Stage E: split the mixed System Settings card, add the app role roster - #1316
Merged
Paul Lizer (paullizer) merged 2 commits intoAug 19, 2026
Merged
Conversation
One tab carried the entire backup, migration, restore, Cosmos editing and job history surface: 1,622 lines in a single scroll. Backup readiness, backup, schedule, storage, encryption Migrate migration workflow Restore backup inventory and restore Cosmos Editor direct database editor Jobs job history Navigation is now 14 groups / 44 tabs / 88 sections. Stage D is done, from an original 17 flat tabs. Three problems the existing tools could not handle The migration card is a <section>, not a <div>, so every div balancing helper walked straight past it and the tools reported five top level cards where there were six. Its boundaries were found by balancing <section> instead, and the split was driven from explicit ranges with a check that every one of the 1,183 lines lands in exactly one output. Eleven dialogs, six of them opened from JavaScript rather than a button, serving what became five different tabs. A dialog inside a tab pane cannot appear while another tab is showing, so all eleven moved outside the panes. Checked first that none carried a name= attribute: the pane's twelve form fields are all radio groups inside the migration card, which stayed put. One save button, one status line and one operational warning serve all five tabs. Group-shared regions Shared controls cannot be copied into each pane, because that repeats element ids and the JavaScript module would bind to the wrong one, and cannot live in one pane, because an inactive pane is hidden and the other four tabs would lose the save button. They now sit outside the panes marked data-admin-group-shared="backup-recovery" and are revealed only while that group is active, synced from every path that activates a tab including Bootstrap's own shown.bs.tab event. syncAdminGroupSharedRegions resolves the owning group from either navigation. Reading only the top tab strip was a real bug: that strip is not rendered at all in the sidebar layout, so the save button would have been hidden permanently. Verified against a simulated DOM in both layouts. Verified field contract 462 names / 110 card ids, unchanged regression set 32 failures, identical to baseline jinja compile 46/46 admin templates xss sinks pass element ids all 1,608 ids in the composed template are unique modal placement every dialog reachable from its trigger Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
system-settings-section mixed five unrelated concerns under one
heading. Each moved to the tab that owns it, with the field markup
carried across byte for byte.
max_file_size_mb -> Workspaces / Files & Sharing
conversation_history_limit -> Chat / Chat Experience
default_system_prompt -> Chat / Chat Experience
access_denied_message -> Security / Access & Roles
idle timeout (4 fields) stays in Security / Session, and the card
is renamed idle-timeout-section for what
it now holds
Splitting a card changes card ids but not field names, which is why
the field contract passed unchanged. Card ids are structural; field
names are the breaking surface, and the contract test tracks only
those, deliberately.
App Role Requirements roster
Ten settings across seven tabs can each require an Entra app role,
so the overall access policy could not be read without hunting
through the whole of Admin Settings. Access & Roles now lists every
one of them.
The roster is built at runtime from
input[name^="require_member_of_"] rather than from a list, so a new
role requirement added anywhere appears automatically and this can
never fall out of step.
Each row is a mirror carrying no name attribute, following the
existing proxy convention, so the setting is still posted exactly
once. Sync is two way: the mirror drives the canonical input and
dispatches a change event, and the canonical input updates the
mirror when changed on its own tab. Verified against a simulated
DOM.
A structural guard worth keeping
test_every_pane_partial_is_balanced checks <div> and <section>
balance in every pane. An unbalanced pane does not fail to render,
it silently nests the panes that follow it, so the failure surfaces
somewhere unrelated. Found the hard way here: a stray </div> in
access-roles.html made a Send Feedback test fail. The new test names
the offending file directly, and is verified against a deliberately
broken pane.
The parity test also caught the new roster being listed in the nav map
in a different order from the markup. Nav order must match pane order.
Navigation is now 14 groups / 44 tabs / 93 sections.
Verified
field contract 462 names, unchanged
regression set 32 failures, identical to baseline
jinja compile 46/46 admin templates
pane balance all panes balanced
xss sinks pass
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
merged commit Aug 19, 2026
6750ca5
into
feature/admin-settings-ia
11 checks passed
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.
Stage E, the last content change in the Admin Settings rework. Splits the mixed System Settings card and adds the app role roster.
Base:
feature/admin-settings-ia. Stacked on #1315.The mixed card is gone
system-settings-sectionput five unrelated concerns under one heading. Each moved to the tab that owns it, with the field markup carried across byte-for-byte:max_file_size_mbconversation_history_limitdefault_system_promptaccess_denied_messageWhat remains in Session is only the idle timeout, so the card is renamed
idle-timeout-sectionfor what it actually holds. Security → Session was an interim home from #1311; it is now honest.Splitting a card changes card ids but not field names, which is why the field contract passed unchanged. Card ids are structural and move freely during this work; field names are the breaking surface, and the contract test tracks only those — deliberately.
App Role Requirements roster
Ten settings across seven tabs can each require an Entra app role. You could not read the overall access policy without hunting through the whole of Admin Settings.
Security → Access & Roles now lists every one, with a switch and a link back to the setting in its own tab.
Two things make this safe and durable:
input[name^="require_member_of_"]at runtime, so a new role requirement added anywhere appears automatically and this can never fall out of step.nameattribute, following the existing proxy convention, so each setting is still posted exactly once. Sync is two-way — the mirror drives the canonical input and dispatches achangeevent, and the canonical input updates the mirror when changed on its own tab.Verified against a simulated DOM:
A structural guard worth keeping
test_every_pane_partial_is_balancedchecks<div>and<section>balance in every pane.An unbalanced pane does not fail to render. It silently nests the panes that follow it, so they get hidden and the failure surfaces somewhere completely unrelated. That happened here: a stray
</div>inaccess-roles.htmlmade a Send Feedback test fail. The new test names the offending file directly:Verified against a deliberately broken pane.
The parity test also earned its keep, catching the new roster listed in the nav map in a different order from the markup. Nav order must match pane order.
Result
Navigation is now 14 groups / 44 tabs / 93 sections, from 17 flat tabs.
Next
Only cleanup remains: revert the six CI branch filters added so staging PRs would run the gates, then open the staging →
DevelopmentPR.