Repository navigation
fix(admin): backport upstream mods-list + groups select-all polish - #41
Merged
Merged
Conversation
…pty state Port of upstream sbpp#1552, continuing our earlier feat/mods-list-compact-actions (#14) port before upstream's own follow-up review passes landed. - Mod name/folder/icon path are stored entity-encoded, but the template rendered them with Smarty's default auto-escape on top, so a mod whose name contains e.g. an ampersand painted the literal `&` in the admin list instead of `&`. Add `|unescape:'html'` at every text and attribute sink (desktop table, mobile cards, edit/delete aria-labels and data-name attributes) to decode once before Smarty's own escape reapplies it safely. - Replace the ad-hoc "No mods configured yet." paragraph with the shared `.empty-state` pattern (icon + title + body + permission- gated CTA) per the "Empty states" convention in AGENTS.md, and add the missing `$permission_addmods` property so the CTA can gate on it. - `$mod_count` counted mid=0 (the reserved "Web" pseudo-mod every install carries) even though `$mod_list` always excludes it, so a fresh install with zero real mods configured showed an empty table instead of the empty state. Scope the COUNT query to `mid > 0` to match. - Mobile cards: give the modfolder line `truncate` + a `title` attribute and move the SU badge to a `flex-shrink:0` sibling instead of letting a long folder name push it off narrow screens. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Port of upstream sbpp#1573's tri-state "select all" checkbox for the web-group permission flag grid, adapted to this fork's existing two-button shape (sbpp#1436) instead of swapping in a single <input type="checkbox">. A straight swap to upstream's checkbox would have thrown away the explicit Select-all/Select-none affordance and forced re-proving two things the sbpp#1436 spec (admin-groups-select-all-flags.spec.ts) already locks in against the button pair: the unsigned bit-31 OR-fold guard (sbpp#1272, SbppFoldFlags' `>>> 0`) and the dirty-tracker-arming contract in SbppGroupsToggleAllFlags. Neither is exercised for free by a native checkbox's indeterminate state. Instead, both buttons now reflect the grid's current state via aria-disabled + a dimmed style once nothing is left to do — not the native `disabled` attribute, because SbppGroupsToggleAllFlags is already a safe no-op on a fully-selected grid and the existing spec deliberately re-clicks "Select all" in that state as an idempotency check; a truly disabled button can't be clicked at all. SbppGroupsRefreshSelectAllButtons() is wired into the three places the grid's checked state can change: the existing `change` listener (manual clicks and the bulk toggle's own dispatched event), the master-detail paintGroup() repaint (which sets .checked directly with no change event), and a bootstrap call for the SSR-rendered initial state. Extends the existing E2E spec (rather than adding a new file) with aria-disabled assertions at each state transition, including after a fresh page reload to prove the state is re-derived from the SSR- checked grid rather than carried in JS memory. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3 tasks
Collaborator
|
Let's fix tests before merging |
SbppGroupsToggleAllFlags dispatches its synthetic change event on the flag grid itself, which the grid listener filters out (it only reacts to input[name="flags[]"] targets). The Select all / Select none aria-disabled state was therefore never refreshed after a bulk toggle, failing admin-groups-select-all-flags.spec.ts. Refresh explicitly.
Once every flag is checked the button carries aria-disabled="true", which Playwright's actionability check treats as disabled, so the plain click() hung until the 30s timeout. Force the click (a mouse user can still press it, it has no native disabled) and correct the template docblock that claimed aria-disabled kept it clickable for Playwright.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Backports the non-dependabot admin-UI fixes from upstream
sbpp/sourcebans-ppthat were still missing after comparingmainagainst upstream — this covers items 5 and 4 from that audit (item 6, the Add Admin server-access grid CSS fix, turned out not applicable to this fork; see "Not included" below).fix(admin-mods): decode entity-encoded mod metadata and add proper empty state
Port of upstream sbpp#1552, continuing our earlier
feat/mods-list-compact-actions(#14) port before upstream's own follow-up review passes landed.&in the admin list instead of&. Added|unescape:'html'at every text/attribute sink (desktop table, mobile cards, edit/delete aria-labels and data-name attributes)..empty-statepattern (icon + title + body + permission-gated CTA) per the "Empty states" convention in AGENTS.md, adding the missing$permission_addmodsproperty.$mod_countcountedmid=0(the reserved "Web" pseudo-mod every install carries) even though$mod_listalways excludes it, so a fresh install with zero real mods configured showed an empty table instead of the empty state. Scoped theCOUNTquery tomid > 0to match.truncate+titleon the modfolder line so a long folder name can't push the SU badge off narrow screens.feat(admin-groups): reflect exhausted select-all/select-none state
Port of upstream sbpp#1573's tri-state "select all" checkbox for the web-group permission flag grid — adapted to this fork's existing two-button shape (sbpp#1436) instead of swapping in a single
<input type="checkbox">.A straight swap to upstream's checkbox would have thrown away the explicit Select-all/Select-none affordance and forced re-proving two things the existing
admin-groups-select-all-flags.spec.tsspec already locks in against the button pair: the unsigned bit-31 OR-fold guard (sbpp#1272) and the dirty-tracker-arming contract inSbppGroupsToggleAllFlags. Neither comes for free from a native checkbox'sindeterminatestate.Instead, both buttons now reflect the grid's current state via
aria-disabled+ a dimmed style once nothing is left to do — not the nativedisabledattribute, becauseSbppGroupsToggleAllFlagsis already a safe no-op on a fully-selected grid and the existing spec deliberately re-clicks "Select all" in that state as an idempotency check; a trulydisabledbutton can't be clicked at all (Playwright would hang on actionability). Wired into the three places the grid's checked state can change without a manual checkbox click: thechangelistener, the master-detailpaintGroup()repaint, and a bootstrap call for the SSR-rendered initial state.Extended the existing E2E spec with
aria-disabledassertions at each state transition, including after a page reload to prove the state re-derives from the SSR-checked grid rather than JS memory.Not included: item 6 (Add Admin server-access grid, upstream sbpp#1491)
Upstream's fix caps a checkbox-tile grid (
.admin-server-access-grid+[data-testid="server-tile"]cards) at two columns so long hostnames wrap instead of being clipped. This fork's Add Admin "Individual servers" picker was already migrated off that pattern onto a themeddata-multiselect<select multiple>(hostname hydration viaoption[data-server-host], same shape as the admin-search box) — there is zero trace of.admin-server-access-grid/[data-testid="server-tile"]left inpage_admin_admins_add.tplortheme.css. The column-width problem the upstream CSS fixes doesn't exist in a scrollable dropdown, so there's nothing to backport here.Verification
phpstan analyse(DBA plugin disabled, matching the documented offline recipe): clean — the only reported item is the known unrelatedinstall/pages/page.6.phpbaseline artifact from running without DBA.phpunit --filter "ModsDeleteDialogTest|RoutingTest|AdminPagesQueryCountTest|WebGroupsCatalogTest|ButtonClassChainTest|DeadJsCallSitesTest": all green.page_admin_groups_list.tplsyntax-checked withnode -cafter extracting the{literal}block.admin-groups-select-all-flags.spec.ts,mods-add-form.spec.ts,mod-delete-confirm.spec.ts) not run in this environment (no Playwright browser install here) — CI'se2e.ymlgate covers it; the modified spec only adds assertions to an existing passing flow, no existing assertions were changed.Test plan
?p=admin&c=mods§ion=listwith zero configured mods on a fresh-ish install and confirm the new empty-state card (icon + "Add mod" CTA) renders instead of an empty table.&or<and confirm it renders correctly (not as&) in both the desktop table and the mobile card.?p=admin&c=groups§ion=list, select a group, click "Select all", confirm the button visibly dims and a second click is still possible (idempotent) but a screen reader announces it as unavailable (aria-disabled="true").🤖 Generated with Claude Code