feat(directory): Phase 1 frontend — Settings tab + PrincipalPicker#407
Open
larsgeorge-db wants to merge 1 commit into
Open
feat(directory): Phase 1 frontend — Settings tab + PrincipalPicker#407larsgeorge-db wants to merge 1 commit into
larsgeorge-db wants to merge 1 commit into
Conversation
10 tasks
Front-end half of the Directory layer (see #406 for the backend). UI pieces: - views/settings-directory.tsx — Settings → Integrations → Directory. Provider Select (Entra ID enabled, Okta/Ping rendered disabled so the abstraction is visible), UC HTTP Connection Select fed from GET /api/directory/uc-http-connections, Save / Test / Clear buttons with toast feedback, and a provider-specific help block for Entra (token URL, base URL, scope, grant type, required Graph scopes). - components/common/principal-picker.tsx — single component that switches between configured-mode type-ahead and unconfigured-mode manual entry from directory-store status. Two-line result rows (display_name + sub_label), tooltip on selected badges exposing sub_label, X-to-remove, optional popup-dialog "Browse directory" variant with type-filter chips. Discriminated `multiple` prop so single-pick gives `string | null`, multi-pick gives `string[]`. - stores/directory-store.ts — Zustand store caching /api/directory/status for the page lifetime and tracking a session-sticky `degraded` flag flipped on the first search failure so subsequent pickers drop straight into manual mode. - types/directory.ts — TS mirrors of the backend Pydantic models. - Assign Owner dialog migrated to PrincipalPicker(accepts=['user']); API payload (user_email + user_name) unchanged. - Sidebar/route wiring in app.tsx and settings-layout.tsx. Tests (19 new, 550 passing total, 0 regressions): - principal-picker.test.tsx (13): - Pre-existing values render as plain badges without re-resolving against the directory. - X-remove emits the remaining ids. - Disabled hides remove buttons. - Unconfigured: Enter / Tab / comma / blur commit the typed value as a badge; empty input and duplicates are no-ops. - Configured: /api/directory/search is called with q= and types= parameters honouring the accepts filter; queries < 2 chars do not fire a request. - Graceful degradation: a failing search flips into manual-entry mode for the rest of the session. - directory-store.test.ts (6): - fetchStatus populates state, dedupes concurrent calls into one in-flight request, and is a no-op once loaded. - Network failure falls back to a not-configured status. - refresh re-fetches and clears the degraded flag; markDegraded is sticky across re-renders. Notes: - The Radix Popover dropdown itself is exercised by Playwright E2E; the existing tag-selector tests in this repo follow the same split for the same reason (Radix Popover hangs in jsdom). - New code lints clean (no errors); only the existing repo-wide `err: any` catch-block warning pattern remains.
This was referenced May 21, 2026
larsgeorge-db
added a commit
that referenced
this pull request
May 21, 2026
…r scope Documents what shipped under PRs #406 / #407 / #412 / #413 / #416 / #417: - Renames the integration's manager / routes / settings keys in the PRD to match the implementation (Directory layer, /api/directory/*, DIRECTORY_* settings, Settings → Directory tab). - Documents the DirectoryProvider interface and the (DirectoryProviderContext, DirectoryProviderConfig) factory signature so future provider plug-ins know what to implement. - Documents the v1 provider set, which expanded during planning from Entra-only to entra + lakebase + file. The Lakebase table schema and CSV format are included so operators have a single reference. - Preserves story content, the disambiguation rule, both picker modes, storage-compatibility guarantees, and graceful-degradation rules from the PRD body unchanged. - Re-confirms the out-of-scope list (Okta/Ping, service principals, OBO, profile photos, manager hierarchy, role/team Select replacement, CSV bulk import) which the abstraction makes cheap to revisit.
larsgeorge-db
added a commit
that referenced
this pull request
May 21, 2026
…r scope Documents what shipped under PRs #406 / #407 / #412 / #413 / #416 / #417: - Renames the integration's manager / routes / settings keys in the PRD to match the implementation (Directory layer, /api/directory/*, DIRECTORY_* settings, Settings → Directory tab). - Documents the DirectoryProvider interface and the (DirectoryProviderContext, DirectoryProviderConfig) factory signature so future provider plug-ins know what to implement. - Documents the v1 provider set, which expanded during planning from Entra-only to entra + lakebase + file. The Lakebase table schema and CSV format are included so operators have a single reference. - Preserves story content, the disambiguation rule, both picker modes, storage-compatibility guarantees, and graceful-degradation rules from the PRD body unchanged. - Re-confirms the out-of-scope list (Okta/Ping, service principals, OBO, profile photos, manager hierarchy, role/team Select replacement, CSV bulk import) which the abstraction makes cheap to revisit.
b2ee317 to
d2f09fa
Compare
398400c to
23fd4f7
Compare
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.
Second of two PRs implementing Phase 1 of the directory-lookup-and-principal-picker plan (#375). Stacked on #406 — base branch is
feat/directory-backend, so the diff here is frontend-only. Will rebase ontomainonce #406 merges.Source PRD: #335
Plan: #375
Backend PR: #406
Summary
/api/directory/uc-http-connections, Save / Test / Clear buttons with success/destructive toast feedback, and a provider-specific help block for Entra with the four UC-connection fields plus required Graph application scopes.PrincipalPicker— single component, both modes (configured / unconfigured) and both UI variants (inline 2-char-debounced type-ahead + popup "Browse directory" dialog with type-filter chips) selected at runtime from the directory store. Two-line result rows (display name + sub_label), tooltip on selected badges exposing the underlying email/UPN/GUID, X-to-remove. Props are discriminated onmultipleso single-pick callers getstring | nulltyping and multi-pick callers getstring[]typing without casts.directory-store(Zustand) — singleton cache for/api/directory/statusso every picker on a page shares one network call, plus a session-stickydegradedflag flipped on the first search failure so subsequent pickers drop straight into manual mode without re-probing.PrincipalPicker(accepts=['user']). API payload (user_email+user_name) is unchanged — the change is purely UI./settings/directoryroute wired up.Architectural notes
str/List[str]) are preserved; no DB migration in v1.directory.statussays configured but a search call fails, the picker logs once (console.warn), flips into manual-entry mode for the rest of the session, anddirectory-store.degradedbecomes sticky so newly-mounted pickers behave the same way.multiple/acceptscombinations — no per-call-site bespoke control.Test plan
yarn type-check(Done in 17.93s)npx eslint ...): 0 errors, only the repo-wideerr: anycatch-block warning pattern remains (matches existing files).npx vitest run→ 550 passed, 6 skipped, 0 failed.principal-picker.test.tsx(13): pre-existing values render as plain badges without re-resolving; X-remove emits remaining ids; disabled hides remove buttons; Enter/Tab/comma/blur commit in unconfigured mode; empty / duplicate inputs are no-ops; configured mode calls/api/directory/searchwithq=andtypes=honouringaccepts; queries < 2 chars do not fire a request; failing search flips into manual-entry mode for the rest of the session.directory-store.test.ts(6):fetchStatuspopulates state, dedupes concurrent calls into one in-flight request, no-ops once loaded, falls back to not-configured on network failure;refreshre-fetches and clearsdegraded;markDegradedis sticky.tag-selectortests in this repo follow the same split for the same reason (Radix Popover hangs in jsdom).What's intentionally not here