Skip to content

Port the Azure scope tree to ElevateCore - #195

Merged
FrodeHus merged 4 commits into
mainfrom
azure-scope-hierarchy-macos
Sep 19, 2026
Merged

FrodeHus merged 4 commits into
mainfrom
azure-scope-hierarchy-macos

Conversation

@FrodeHus

@FrodeHus FrodeHus commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

Part of #186; the SwiftUI work is tracked in #194.

Built and tested on a Mac. swift build and swift test are clean — 437 ElevateCore tests pass, including the new ArmScopeTests and ScopeTreeTests — and the ElevateApp Xcode target builds and passes its tests on top of the changed PanelFilter (Swift 6.4 / Xcode 26).

#193 has merged, so this now targets main and has been brought up to date with it; the diff is macOS-only.

What is here

ArmScope and ScopeTree in ElevateCore, transliterated from the C# added in #193 together with their tests, so the two Cores do not drift. PanelFilter now searches the whole ARM path on this side too — the one behaviour change, and the only thing here a user could notice: a row shows only the scope's caption, but "prod" should find an eligibility whose subscription is named in the path alone.

The Azure tab itself is untouched and still lists flat.

The tests mirror the C# suite case for case, including the two that pin the decisions worth not re-litigating: management groups sit beside subscriptions rather than above them, and a pass-through scope is folded into the node below it.

Not here

Everything in #194: the AppModel state and accessors, the ScopeRow view, TenantRoles walking flatten, and the macOS docs. Landing this on its own keeps the logic and its tests reviewable separately from the view, and means whoever picks up the SwiftUI has a green Core underneath them.

🤖 Generated with Claude Code

FrodeHus and others added 2 commits September 19, 2026 01:48
ArmScope and ScopeTree, transliterated from the C# added for #186 along
with their tests, so the macOS Azure tab has the same tree to draw from and
the two Cores do not drift. PanelFilter now searches the whole ARM path on
this side too, which is the one behaviour change here: a row shows only the
scope's caption, but "prod" should find an eligibility whose subscription is
named in the path alone.

The Azure tab itself is unchanged and still lists flat. This is the logic
layer only — see the follow-up issue for the SwiftUI work.

NOT COMPILED. Written on a Windows machine with no Swift toolchain, so
'swift test' has never run against it. The tests mirror the C# suite case
for case and are the fastest way to find whatever this got wrong.

Refs #186

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The search box reaching an Azure role's whole scope path is live on macOS
the moment this merges, so it belongs under Unreleased rather than waiting
for the tab's tree. CI caught the omission.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Base automatically changed from azure-scope-hierarchy to main September 19, 2026 00:17
@FrodeHus
FrodeHus marked this pull request as ready for review September 19, 2026 00:17
@FrodeHus
FrodeHus merged commit ba87be5 into main Sep 19, 2026
13 checks passed
@FrodeHus
FrodeHus deleted the azure-scope-hierarchy-macos branch September 19, 2026 11:27
FrodeHus added a commit that referenced this pull request Sep 19, 2026
The Azure tab listed its eligibilities flat, which does not scale: a platform
engineer eligible for Contributor on sixty subscriptions read sixty sibling
rows and clicked sixty times before the single activation Elevate promised.
Windows and the CLI got the tree in #186; the logic and its tests came across
to ElevateCore in #195. This is the SwiftUI layer that draws it.

AppModel gains the Azure tab's tree and the state around it, mirroring
AppModel.Panel.cs: azureTree(for:) builds from the already-filtered rows, so a
search narrows the tree rather than sitting beside it; collapsedScopes is keyed
per tenant, because two accounts can reach the same scope; and isScopeCollapsed
answers false while filtering, so a match is never hidden behind a node closed
earlier. The subtree checkbox carries its own canSelect, stricter than
canActivate: the rule for "is this row's checkbox enabled" lived in the view,
and without it a scope checkbox would select rows whose own checkbox is off. A
partly chosen subtree fills up rather than emptying — the checkbox is offering
the rest.

TenantRoles walks ScopeTree.flatten on the Azure tab and emits a ScopeRow or a
RoleRow per entry. The two foldings the Core already performs are what keep the
tree from costing more rows than it saves, so the view only has to respect
them: a scope that just passes through is drawn as a dimmed "Alpha /" ahead of
the title it was folded into, and a scope leading to a single role gets no
header at all. Indent is 12 pt a step and stops after three; the panel is 380 pt
wide and a management group path is longer than that, and the header's own path
says where you are. Management groups sit beside the subscriptions, not above
them, for the reason ArmScope documents.

Verified on a Mac: 444 ElevateCore tests and 158 ElevateApp tests pass, and the
app builds with no new warnings. The twelve new AppModelScopeTreeTests mirror
the C# suite case for case and were watched failing first. The panel was also
rendered offscreen in light and dark, with and without select mode, to check
the folding, the elision and the three-state checkbox against real scopes.

Closes #194

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant