Repository navigation
UN-4290 [FEAT] Add the v1 account menu and organisation switcher #2395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
110 commits
Select commit
Hold shift + click to select a range
0c5bacb
feat(frontend): v1 scaffold, strict TypeScript and import boundary (U…
jaseemjaskp 5c55a7c
fix(frontend): close v1 guardrail bypasses found in self-review (UN-4…
jaseemjaskp 87c803c
feat(frontend): run v1 checks in CI and tighten what pages may import…
jaseemjaskp f86de0b
refactor(frontend): address SonarCloud findings on the v1 guardrails …
jaseemjaskp 67be34b
refactor(frontend): split the contract-matrix builder to cut its comp…
jaseemjaskp 81e15b1
fix(frontend): check every glob pattern and v0 -> v1 imports Biome ca…
jaseemjaskp 7e66cc5
UN-4286 [FEAT] Add the v1 plugin manifest, slots and build check
athul-rs 1f426f9
UN-4286 [FEAT] Pass VITE_DISTRIBUTION through the frontend Docker build
athul-rs 7ae6de5
UN-4286 [FEAT] Keep overlaid v1 plugins out of OSS commits
athul-rs cbfd332
UN-4286 [FEAT] Build the plugin registry in plugins/ and hand Slot to…
athul-rs 1babd39
UN-4286 [FIX] Let v1 tests typecheck until the scaffold settles the c…
athul-rs 0bd4a2c
UN-4290 [FEAT] Add the v1 account menu and organisation switcher
athul-rs e7d4b55
UN-4290 [FIX] Show the e-mail as the account menu title when the user…
athul-rs 7e541ab
UN-4299 [MISC] Turn on skipLibCheck for v1: vitest 3.2 and @types/cha…
praveen-formido 6f22f62
UN-4299 [FEAT] Add the v1 theme model: three modes, follow-system and…
praveen-formido 7aa5bf4
UN-4299 [FEAT] Add the v1 portal container and the theme preference s…
praveen-formido 0c85cd6
UN-4299 [FEAT] Add the v1 token source, the generator and tokens.css …
praveen-formido 6393d31
UN-4299 [FIX] Prefix the spacing utilities in the token table so they…
praveen-formido 4a05a26
UN-4299 [FEAT] Add cn() configured for the v1 utility prefix
praveen-formido a9307e7
UN-4299 [FIX] Pin the v1 prefix in cn() with a test that fails withou…
praveen-formido 5a361ae
UN-4299 [FIX] Use "ui" as the v1 utility prefix: Tailwind accepts low…
praveen-formido 0e2b7a0
UN-4299 [FEAT] Add the prefixed v1 Tailwind root with fonts, modes, t…
praveen-formido d737fa8
UN-4299 [FIX] Exclude the generated tokens.css from Biome formatting …
praveen-formido a9acf5e
UN-4299 [FIX] Sort the imports in cn.ts so biome ci passes
praveen-formido 861c7b6
UN-4286 [FIX] Retry a slot's import after a failed load
athul-rs 014249a
UN-4290 [FIX] Check the sign-out redirect, share the sign-out sequenc…
athul-rs 6c31314
UN-4286 [FIX] Reject unknown slots and distributions and load manifes…
athul-rs 1c97ee3
UN-4290 [FIX] Harden the organisation switcher and match its Figma marks
athul-rs b3e8acf
UN-4290 [CHORE] Merge the P0-T07 review fixes
athul-rs 54469cb
UN-4299 [FIX] Make the root compile test fail on unscoped selector li…
praveen-formido 43c9ced
UN-4299 [FEAT] Add ThemeProvider: the v1 root, follow-system binding …
praveen-formido cc6126c
UN-4299 [FIX] Apply the stored theme before first paint with useLayou…
praveen-formido 927f4e0
UN-4286 [FIX] Load esbuild only under Node, so the cloud overlay runs…
athul-rs 52c4f55
UN-4290 [CHORE] Merge the P0-T07 loader fix
athul-rs 0e13d94
UN-4299 [FEAT] Enforce the v1 styling policy: raw colours, pixels, in…
praveen-formido 3b11ca4
UN-4290 [FIX] Follow only an http(s) sign-out redirect
athul-rs c3a703c
UN-4299 [FIX] Scope the styling lint to class strings and cover vh/vw…
praveen-formido a35da5b
UN-4299 [FIX] Keep v0's Tailwind scan out of src/v1, the lint scripts…
praveen-formido d6047e9
UN-4299 [FIX] Teach cn the type roles so a role and a text colour no …
praveen-formido b29503d
UN-4299 [FIX] Reject colour literals outside class strings, named-col…
praveen-formido e064614
UN-4299 [FIX] Keep the focus ring visible in forced-colors mode and s…
praveen-formido 88354e1
UN-4299 [FIX] Create the portal container before the mode changes so …
praveen-formido a41e1ba
UN-4299 [FIX] Document the v0 rules that reach v1, the focus-ring usa…
praveen-formido 8231919
UN-4299 [FIX] Name the theme storage key in the v1 README
praveen-formido d0c1be0
UN-4299 [MISC] Name the three theme modes in the v1 README
praveen-formido f8969a5
Merge remote-tracking branch 'origin/UN-4299-design-tokens-themes' in…
athul-rs d791573
UN-4290 Move the v1 menus onto the ui: prefix and design tokens
athul-rs 664d1cf
fix(frontend): typecheck v1 tests that import vitest; skip cloud plug…
jaseemjaskp 8ede7ec
UN-4286 [FIX] Write the plugin matrix to a file given without --dir, …
athul-rs fbe0e6c
UN-4290 [FIX] Scroll a long organisation list inside a panel capped t…
athul-rs 787bf8b
fix(frontend): close v1 guardrail gaps from team review (UN-4270)
jaseemjaskp b9bed0d
feat(frontend): add an assets/ folder to the v1 taxonomy (UN-4270)
jaseemjaskp 3889a34
fix(frontend): find v1 imports only in executable code, not in string…
jaseemjaskp bef9515
UN-4299 [FEAT] Let a v1 style attribute set CSS custom properties only
praveen-formido 678efbb
UN-4299 [FIX] Make check-v1-styles.mjs executable to match its shebang
praveen-formido 8028a73
UN-4299 [FIX] Type the custom-property keys a v1 style attribute may set
praveen-formido feb8c5f
fix(frontend): don't read JSX apostrophes as strings in the v1 scanne…
jaseemjaskp 5312a6b
Merge remote-tracking branch 'origin/UN-4270-v1-scaffold' into UN-428…
athul-rs 6b2df4d
UN-4286 [FIX] Give the missing-import test a template the v1 guard ca…
athul-rs 5e944c3
Merge branch 'UN-4286-plugin-manifest' into UN-4290-v1-account-menu
athul-rs 3d88fbf
Merge branch 'UN-4290-v1-account-menu' into UN-4290-v1-menus-tokens
athul-rs 982c743
Merge remote-tracking branch 'origin/UN-4299-design-tokens-themes' in…
athul-rs d555e16
UN-4290 [FIX] Check the scroll classes by their ui: names
athul-rs 8510dac
UN-4290 [FIX] Make the space before the new-tab hint explicit
athul-rs 6202e5a
UN-4290 [FIX] Put the menus on the popover colour and match the switc…
athul-rs 7af9264
fix(frontend): read v1 imports from a Babel AST, not a hand-written t…
jaseemjaskp daa1a18
fix(frontend): read v1 import specifiers through TypeScript assertion…
jaseemjaskp 73b9ffa
fix(frontend): close v1 boundary gaps from the daa1a182d review (UN-4…
jaseemjaskp 508e370
UN-4299 [FIX] Close the styling-lint gaps found in review
praveen-formido 6e75882
UN-4299 [FIX] Set color-scheme per mode, bind spacing utilities to th…
praveen-formido 622695f
UN-4299 [FIX] Run the token generator under bun
praveen-formido 7fdcb02
fix(frontend): read CSS image-set() and escaped url()s; allowlist v1 …
jaseemjaskp ee517cb
chore: git-ignore cloud v1 plugins copied into src/v1/plugins/ (UN-4270)
jaseemjaskp e565ae5
UN-4299 [MISC] Merge main into the tokens branch now that the v1 scaf…
praveen-formido c6c0b21
UN-4299 [FIX] Close the S3 separator gap and two lint false positives…
praveen-formido 4667e5d
UN-4299 [MISC] Move the token values to tokens.json and settle the So…
praveen-formido 6fe2322
UN-4286 [MISC] Merge the final v1 scaffold head (#2380, ee517cb4e)
athul-rs 9cdbf7b
UN-4286 [MISC] Merge main after the v1 scaffold landed (#2380)
athul-rs 6f7c439
Merge remote-tracking branch 'origin/UN-4286-plugin-manifest' into UN…
athul-rs ab695c6
Merge remote-tracking branch 'origin/UN-4290-v1-account-menu' into UN…
athul-rs 497c7b6
UN-4290 [MISC] Merge the latest tokens branch (#2399), which has main…
athul-rs f50b148
UN-4290 [FIX] Switch organisation by signing in again when the identi…
athul-rs 6c85e7f
Merge branch 'UN-4290-v1-account-menu' into UN-4290-v1-menus-tokens
athul-rs fa189cf
Merge branch 'main' into UN-4299-design-tokens-themes
muhammad-ali-e 486c2be
Merge branch 'main' into UN-4299-design-tokens-themes
muhammad-ali-e 678ddaf
Merge commit 'refs/tmp/pr2399' into UN-4290-v1-menus-tokens
athul-rs 4e56d2a
Merge remote-tracking branch 'origin/main' into UN-4290-v1-menus-tokens
athul-rs fc7a131
UN-4286 [MISC] Merge main into the plugin manifest branch
athul-rs 4a25e80
UN-4290 [MISC] Merge the updated plugin manifest branch (#2394)
athul-rs 000ae0d
UN-4286 [MISC] Merge main (v1 icons lint) into the plugin manifest br…
athul-rs 779e6aa
UN-4290 [MISC] Merge the updated plugin manifest branch (#2394)
athul-rs 0551930
UN-4290 [FIX] Account menu uses the dropdown-menu shadow
athul-rs 365c924
UN-4286 [FIX] Test the v1 guard in both plugin-import resolvers directly
athul-rs c015c25
Merge remote-tracking branch 'origin/main' into UN-4286-plugin-manifest
athul-rs a29fc09
Merge commit 'c015c2537' into UN-4290-v1-account-menu
athul-rs cacc2e2
UN-4290 [FIX] Address review: restore the plugin README, explain a 41…
athul-rs 8b94e7c
Merge origin/main into UN-4286-plugin-manifest
athul-rs 4c4b9ae
Merge branch 'UN-4286-plugin-manifest' into UN-4290-v1-account-menu
athul-rs b3a667a
UN-4286 [FIX] Address review: check plugin routes against OSS pages, …
athul-rs 9be9d5a
Merge branch 'UN-4286-plugin-manifest' into UN-4290-v1-account-menu
athul-rs f37d0d9
UN-4290 [FEAT] Keep the current organisation's details through a 403 …
athul-rs 5cc28d7
UN-4286 [FEAT] Match plugin routes by overlap and report every render…
athul-rs 85797a2
Merge branch 'UN-4286-plugin-manifest' into UN-4290-v1-account-menu
athul-rs 98623d6
UN-4286 [FEAT] Use a fixed overlap rule in the registry test
athul-rs 8963bc4
Merge branch 'UN-4286-plugin-manifest' into UN-4290-v1-account-menu
athul-rs 7367906
UN-4286 [FIX] Address review: check manifest shape and route patterns…
athul-rs 341df53
Merge branch 'UN-4286-plugin-manifest' into UN-4290-v1-account-menu
athul-rs e05f055
UN-4290 [FIX] Address review: list shape check, typed refusals, panel…
athul-rs 20bd0f8
Merge remote-tracking branch 'origin/main' into UN-4290-v1-account-menu
athul-rs ee29b71
UN-4290 [FIX] Alias the Radix Popover so the v0 shim scan skips it
athul-rs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import axios from "axios"; | ||
|
|
||
| const SAFE_METHODS = new Set(["get", "head", "options"]); | ||
|
|
||
| function cookie(name: string): string | undefined { | ||
| const prefix = `${name}=`; | ||
| const entry = document.cookie | ||
| .split("; ") | ||
| .find((part) => part.startsWith(prefix)); | ||
| if (entry === undefined) { | ||
| return undefined; | ||
| } | ||
| try { | ||
| return decodeURIComponent(entry.slice(prefix.length)); | ||
| } catch { | ||
| // A malformed value is no token: send no header and let the server refuse. | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * The one HTTP client v1 services use. Django's session cookie authenticates; | ||
| * unsafe methods carry the CSRF cookie back as X-CSRFToken. Set here rather | ||
| * than through axios's xsrf options, which only the browser adapter applies. | ||
| * ponytail: no 401 or error-toast handling yet; add it when a page needs it. | ||
| */ | ||
| export const http = axios.create({ withCredentials: true }); | ||
|
|
||
| http.interceptors.request.use((config) => { | ||
| const token = cookie("csrftoken"); | ||
| if ( | ||
| token !== undefined && | ||
| !SAFE_METHODS.has((config.method ?? "get").toLowerCase()) | ||
| ) { | ||
| config.headers.set("X-CSRFToken", token); | ||
| } | ||
| return config; | ||
| }); | ||
|
athul-rs marked this conversation as resolved.
Resolved
|
||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| import { describe, expect, test } from "vitest"; | ||
| import { | ||
| describeOrganization, | ||
| initial, | ||
| initials, | ||
| landingPath, | ||
| organizationInitials, | ||
| roleLabel, | ||
| } from "./organizations"; | ||
|
|
||
| describe("roleLabel", () => { | ||
| test.each([ | ||
| ["admin", "Admin"], | ||
| ["unstract_admin", "Admin"], | ||
| ["user", "Member"], | ||
| ["unstract_user", "Member"], | ||
| ["unstract_supervisor", "Supervisor"], | ||
| ["unstract_reviewer", "Reviewer"], | ||
| ])("%s reads %s", (role, label) => { | ||
| expect(roleLabel(role)).toBe(label); | ||
| }); | ||
|
|
||
| test("an unknown role is not guessed", () => { | ||
| expect(roleLabel("auditor")).toBeUndefined(); | ||
| expect(roleLabel(undefined)).toBeUndefined(); | ||
| }); | ||
| }); | ||
|
|
||
| describe("describeOrganization", () => { | ||
| test("role, member count and region, as frame NEW10 shows", () => { | ||
| expect( | ||
| describeOrganization({ role: "admin", member_count: 40, region: "US" }), | ||
| ).toBe("Admin · 40 members · US"); | ||
| }); | ||
|
|
||
| test("one member is singular", () => { | ||
| expect(describeOrganization({ role: "admin", member_count: 1 })).toBe( | ||
| "Admin · 1 member", | ||
| ); | ||
| }); | ||
|
|
||
| test("absent fields are left out, never guessed (OSS sends no region)", () => { | ||
| expect(describeOrganization({ role: "user" })).toBe("Member"); | ||
| expect(describeOrganization({ member_count: 3 })).toBe("3 members"); | ||
| expect(describeOrganization({})).toBe(""); | ||
| }); | ||
| }); | ||
|
|
||
| describe("initials", () => { | ||
| test.each([ | ||
| ["Zipstack", "Z"], | ||
| ["Tanushree Daga", "TD"], | ||
| ["Tanushree’s organisation", "TO"], | ||
| [" ", "?"], | ||
| ])("%s gives %s", (name, expected) => { | ||
| expect(initials(name)).toBe(expected); | ||
| }); | ||
| }); | ||
|
|
||
| describe("initial", () => { | ||
| test.each([ | ||
| ["Tanushree Daga", "T"], | ||
| ["[email protected]", "A"], | ||
| [" ", "?"], | ||
| ])("%s gives %s", (name, expected) => { | ||
| expect(initial(name)).toBe(expected); | ||
| }); | ||
| }); | ||
|
|
||
| describe("organizationInitials", () => { | ||
| test.each([ | ||
| ["Zipstack", "ZI"], | ||
| ["Tanushree’s organisation", "TO"], | ||
| ["Acme Data Labs", "AD"], | ||
| ["X", "X"], | ||
| [" ", "?"], | ||
| ])("%s gives %s", (name, expected) => { | ||
| expect(organizationInitials(name)).toBe(expected); | ||
| }); | ||
| }); | ||
|
|
||
| describe("landingPath", () => { | ||
| test("keeps the section in the new organisation", () => { | ||
| expect(landingPath("/zipstack/workflows", "zipstack", "tanushree")).toBe( | ||
| "/tanushree/workflows", | ||
| ); | ||
| }); | ||
|
|
||
| test("drops anything under the section: that record may not exist there", () => { | ||
| expect( | ||
| landingPath("/zipstack/tools/123/settings", "zipstack", "tanushree"), | ||
| ).toBe("/tanushree/tools"); | ||
| }); | ||
|
|
||
| test("falls back to the dashboard when the path has no section", () => { | ||
| expect(landingPath("/zipstack", "zipstack", "tanushree")).toBe( | ||
| "/tanushree/dashboard", | ||
| ); | ||
| expect(landingPath("/zipstack/", "zipstack", "tanushree")).toBe( | ||
| "/tanushree/dashboard", | ||
| ); | ||
| }); | ||
|
|
||
| test("falls back to the dashboard outside the current organisation's paths", () => { | ||
| expect(landingPath("/landing", "zipstack", "tanushree")).toBe( | ||
| "/tanushree/dashboard", | ||
| ); | ||
| expect(landingPath("/otherorg/workflows", "zipstack", "tanushree")).toBe( | ||
| "/tanushree/dashboard", | ||
| ); | ||
| }); | ||
|
athul-rs marked this conversation as resolved.
Resolved
|
||
| }); | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /** Wording and navigation rules for the organisation switcher (page 19). */ | ||
|
|
||
| // Stored roles: `admin`/`user` in OSS, `unstract_*` in cloud (account_v2/ReadMe.md). | ||
| const ROLE_LABELS: Record<string, string> = { | ||
| admin: "Admin", | ||
| unstract_admin: "Admin", | ||
| user: "Member", | ||
| unstract_user: "Member", | ||
| unstract_supervisor: "Supervisor", | ||
| unstract_reviewer: "Reviewer", | ||
| }; | ||
|
|
||
| export function roleLabel(role: string | undefined): string | undefined { | ||
| return role === undefined ? undefined : ROLE_LABELS[role]; | ||
| } | ||
|
|
||
| export interface OrganizationDetails { | ||
| role?: string; | ||
| member_count?: number; | ||
| region?: string; | ||
| } | ||
|
|
||
| /** | ||
| * "Admin · 40 members · US". The list leaves a field out when this deployment | ||
| * cannot answer for it (OSS has no regions), so a missing part is skipped. | ||
| * v1 shows the region code as the backend sends it, with no label mapping. | ||
| */ | ||
| export function describeOrganization({ | ||
| role, | ||
| member_count, | ||
| region, | ||
| }: OrganizationDetails): string { | ||
| const members = | ||
| member_count === undefined | ||
| ? undefined | ||
| : `${member_count} member${member_count === 1 ? "" : "s"}`; | ||
|
Check warning on line 36 in frontend/src/v1/lib/organizations.ts
|
||
| return [roleLabel(role), members, region].filter(Boolean).join(" · "); | ||
|
athul-rs marked this conversation as resolved.
Resolved
|
||
| } | ||
|
|
||
| export function initials(name: string): string { | ||
| const words = name.trim().split(/\s+/).filter(Boolean); | ||
| if (words.length === 0) { | ||
| return "?"; | ||
| } | ||
| return words | ||
| .slice(0, 2) | ||
| .map((word) => word[0].toUpperCase()) | ||
| .join(""); | ||
| } | ||
|
|
||
| /** One letter, for the small marks (the account trigger, the organisation pill). */ | ||
| export function initial(name: string): string { | ||
| return name.trim()[0]?.toUpperCase() ?? "?"; | ||
| } | ||
|
|
||
| /** Two letters for an organisation avatar; a one-word name gives its first two. */ | ||
| export function organizationInitials(name: string): string { | ||
| const words = name.trim().split(/\s+/).filter(Boolean); | ||
| if (words.length === 0) { | ||
| return "?"; | ||
| } | ||
| const letters = | ||
| words.length === 1 ? [...words[0]].slice(0, 2) : words.map((w) => w[0]); | ||
| return letters.slice(0, 2).join("").toUpperCase(); | ||
| } | ||
|
|
||
| /** | ||
| * Where the app lands after switching: the same section in the new | ||
| * organisation, else its dashboard. Paths are `/<org name>/<section>/...`. | ||
| * ponytail: keeps only the section, since a record id below it belongs to the | ||
| * old organisation; ask the route registry which sections exist once it does. | ||
| */ | ||
| export function landingPath( | ||
| pathname: string, | ||
| fromOrg: string, | ||
| toOrg: string, | ||
| ): string { | ||
| const [org, section] = pathname.split("/").filter(Boolean); | ||
| return org === fromOrg && section | ||
| ? `/${toOrg}/${section}` | ||
| : `/${toOrg}/dashboard`; | ||
| } | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import { http } from "@v1/lib/http"; | ||
| import type { OrganizationDetails } from "@v1/lib/organizations"; | ||
| import axios from "axios"; | ||
|
|
||
| /** A row of GET /api/v1/organization. role, member_count and region may be absent. */ | ||
| export interface Organization extends OrganizationDetails { | ||
| id: string; | ||
| /** The URL name: paths are /<name>/... */ | ||
| name: string; | ||
| display_name: string; | ||
| } | ||
|
|
||
| /** | ||
| * A refusal the backend gives a meaning to. `session-ended`: the list call | ||
| * answered 412 after logging the session out; `body` may name the cause. | ||
| * `access-removed`: the set call answered 403, so the user left that | ||
| * organisation after the list loaded. Any other failure is thrown as is. | ||
| */ | ||
| export class OrganizationError extends Error { | ||
| readonly kind: "session-ended" | "access-removed"; | ||
| readonly body: unknown; | ||
|
|
||
| constructor(kind: OrganizationError["kind"], body?: unknown) { | ||
| super(`Organisation request refused: ${kind}`); | ||
| this.name = "OrganizationError"; | ||
| this.kind = kind; | ||
| this.body = body; | ||
| } | ||
| } | ||
|
|
||
| function refusal( | ||
| error: unknown, | ||
| status: number, | ||
| kind: OrganizationError["kind"], | ||
| ): unknown { | ||
| return axios.isAxiosError(error) && error.response?.status === status | ||
| ? new OrganizationError(kind, error.response.data) | ||
| : error; | ||
| } | ||
|
|
||
| export async function listOrganizations(): Promise<Organization[]> { | ||
| let data: { organizations?: unknown } | undefined; | ||
| try { | ||
| ({ data } = await http.get<{ organizations?: unknown }>( | ||
| "/api/v1/organization", | ||
| )); | ||
| } catch (error) { | ||
| throw refusal(error, 412, "session-ended"); | ||
| } | ||
| // A proxy or SPA fallback can answer 200 with some other body. | ||
| if (!Array.isArray(data?.organizations)) { | ||
| throw new Error("Organization list reply carried no organizations"); | ||
|
Check warning on line 52 in frontend/src/v1/services/organizations.ts
|
||
| } | ||
| return data.organizations as Organization[]; | ||
| } | ||
|
athul-rs marked this conversation as resolved.
Resolved
|
||
|
|
||
| /** Makes the organisation the session's current one. */ | ||
| export async function switchOrganization(id: string): Promise<void> { | ||
| try { | ||
| await http.post(`/api/v1/organization/${encodeURIComponent(id)}/set`); | ||
| } catch (error) { | ||
| throw refusal(error, 403, "access-removed"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Where to send the browser to switch when the identity provider picked the | ||
| * organisation at login (the session's `org_switch_via_login`): a new login | ||
| * naming it, so the provider records the choice for every product. `prompt=none` | ||
| * shows no screen, since the provider already has a session. | ||
| */ | ||
| export function organizationLoginUrl(id: string): string { | ||
| const query = new URLSearchParams({ organization: id, prompt: "none" }); | ||
| return `/api/v1/login?${query.toString()}`; | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.