@shipfox/client-shell 10.0.1 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/user-menu.d.ts.map +1 -1
- package/dist/components/user-menu.js +26 -0
- package/dist/components/user-menu.js.map +1 -1
- package/dist/core/session.d.ts +1 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js.map +1 -1
- package/dist/hooks/api/session-auth.d.ts.map +1 -1
- package/dist/hooks/api/session-auth.js +2 -1
- package/dist/hooks/api/session-auth.js.map +1 -1
- package/dist/runtime/anchors.d.ts.map +1 -1
- package/dist/runtime/anchors.js +6 -3
- package/dist/runtime/anchors.js.map +1 -1
- package/dist/runtime/chrome-context.d.ts +6 -0
- package/dist/runtime/chrome-context.d.ts.map +1 -1
- package/dist/runtime/chrome-context.js.map +1 -1
- package/dist/runtime/workspace-setup.d.ts +4 -0
- package/dist/runtime/workspace-setup.d.ts.map +1 -1
- package/dist/runtime/workspace-setup.js +23 -0
- package/dist/runtime/workspace-setup.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-menu.d.ts","sourceRoot":"","sources":["../../src/components/user-menu.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"user-menu.d.ts","sourceRoot":"","sources":["../../src/components/user-menu.tsx"],"names":[],"mappings":"AA0CA,wBAAgB,QAAQ,gCA2CvB"}
|
|
@@ -3,7 +3,9 @@ import { Avatar } from '@shipfox/react-ui/avatar';
|
|
|
3
3
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@shipfox/react-ui/dropdown-menu';
|
|
4
4
|
import { useTheme } from '@shipfox/react-ui/hooks';
|
|
5
5
|
import { Link } from '@tanstack/react-router';
|
|
6
|
+
import { Component } from 'react';
|
|
6
7
|
import { useAuthState } from '#runtime/auth.js';
|
|
8
|
+
import { useChrome } from '#runtime/chrome-context.js';
|
|
7
9
|
const themeOptions = [
|
|
8
10
|
{
|
|
9
11
|
value: 'light',
|
|
@@ -18,8 +20,29 @@ const themeOptions = [
|
|
|
18
20
|
label: 'System'
|
|
19
21
|
}
|
|
20
22
|
];
|
|
23
|
+
let AccountMenuEntryBoundary = class AccountMenuEntryBoundary extends Component {
|
|
24
|
+
static getDerivedStateFromError() {
|
|
25
|
+
return {
|
|
26
|
+
hasError: true
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
componentDidCatch(error) {
|
|
30
|
+
globalThis.reportError?.(new Error('Failed to render account menu entry.', {
|
|
31
|
+
cause: error
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
render() {
|
|
35
|
+
return this.state.hasError ? null : this.props.children;
|
|
36
|
+
}
|
|
37
|
+
constructor(...args){
|
|
38
|
+
super(...args), this.state = {
|
|
39
|
+
hasError: false
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
};
|
|
21
43
|
export function UserMenu() {
|
|
22
44
|
const { user } = useAuthState();
|
|
45
|
+
const { AccountMenuEntry } = useChrome();
|
|
23
46
|
const { theme, setTheme } = useTheme();
|
|
24
47
|
const email = user?.email ?? '';
|
|
25
48
|
return /*#__PURE__*/ _jsxs(DropdownMenu, {
|
|
@@ -59,6 +82,9 @@ export function UserMenu() {
|
|
|
59
82
|
children: option.label
|
|
60
83
|
}, option.value))
|
|
61
84
|
}),
|
|
85
|
+
AccountMenuEntry ? /*#__PURE__*/ _jsx(AccountMenuEntryBoundary, {
|
|
86
|
+
children: /*#__PURE__*/ _jsx(AccountMenuEntry, {})
|
|
87
|
+
}) : undefined,
|
|
62
88
|
/*#__PURE__*/ _jsx(DropdownMenuSeparator, {}),
|
|
63
89
|
/*#__PURE__*/ _jsx(DropdownMenuItem, {
|
|
64
90
|
asChild: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/user-menu.tsx"],"sourcesContent":["import {Avatar} from '@shipfox/react-ui/avatar';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {useTheme} from '@shipfox/react-ui/hooks';\nimport type {Theme} from '@shipfox/react-ui/theme';\nimport {Link} from '@tanstack/react-router';\nimport {useAuthState} from '#runtime/auth.js';\n\nconst themeOptions: Array<{value: Theme; label: string}> = [\n {value: 'light', label: 'Light'},\n {value: 'dark', label: 'Dark'},\n {value: 'system', label: 'System'},\n];\nexport function UserMenu() {\n const {user} = useAuthState();\n const {theme, setTheme} = useTheme();\n const email = user?.email ?? '';\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"User menu\"\n className=\"rounded-full focus-visible:outline-none focus-visible:shadow-button-neutral-focus\"\n >\n <Avatar size=\"sm\" content=\"letters\" fallback={email} />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-[220px]\">\n <DropdownMenuLabel className=\"text-xs text-foreground-neutral-muted truncate\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuLabel className=\"text-xs text-foreground-neutral-muted\">\n Theme\n </DropdownMenuLabel>\n <DropdownMenuRadioGroup value={theme} onValueChange={(value) => setTheme(value as Theme)}>\n {themeOptions.map((option) => (\n <DropdownMenuRadioItem key={option.value} value={option.value}>\n {option.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n <DropdownMenuSeparator />\n <DropdownMenuItem asChild>\n <Link to={'/auth/logout' as never}>Logout</Link>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"names":["Avatar","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuLabel","DropdownMenuRadioGroup","DropdownMenuRadioItem","DropdownMenuSeparator","DropdownMenuTrigger","useTheme","Link","useAuthState","themeOptions","value","label","UserMenu","user","theme","setTheme","email","asChild","button","type","aria-label","className","size","content","fallback","align","sideOffset","onValueChange","map","option","to"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SACEC,YAAY,EACZC,mBAAmB,EACnBC,gBAAgB,EAChBC,iBAAiB,EACjBC,sBAAsB,EACtBC,qBAAqB,EACrBC,qBAAqB,EACrBC,mBAAmB,QACd,kCAAkC;AACzC,SAAQC,QAAQ,QAAO,0BAA0B;AAEjD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,YAAY,QAAO,mBAAmB;
|
|
1
|
+
{"version":3,"sources":["../../src/components/user-menu.tsx"],"sourcesContent":["import {Avatar} from '@shipfox/react-ui/avatar';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {useTheme} from '@shipfox/react-ui/hooks';\nimport type {Theme} from '@shipfox/react-ui/theme';\nimport {Link} from '@tanstack/react-router';\nimport {Component, type PropsWithChildren} from 'react';\nimport {useAuthState} from '#runtime/auth.js';\nimport {useChrome} from '#runtime/chrome-context.js';\n\nconst themeOptions: Array<{value: Theme; label: string}> = [\n {value: 'light', label: 'Light'},\n {value: 'dark', label: 'Dark'},\n {value: 'system', label: 'System'},\n];\n\ntype AccountMenuEntryBoundaryState = {hasError: boolean};\n\nclass AccountMenuEntryBoundary extends Component<PropsWithChildren, AccountMenuEntryBoundaryState> {\n override state: AccountMenuEntryBoundaryState = {hasError: false};\n\n static getDerivedStateFromError(): AccountMenuEntryBoundaryState {\n return {hasError: true};\n }\n\n override componentDidCatch(error: unknown): void {\n globalThis.reportError?.(new Error('Failed to render account menu entry.', {cause: error}));\n }\n\n override render() {\n return this.state.hasError ? null : this.props.children;\n }\n}\n\nexport function UserMenu() {\n const {user} = useAuthState();\n const {AccountMenuEntry} = useChrome();\n const {theme, setTheme} = useTheme();\n const email = user?.email ?? '';\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"User menu\"\n className=\"rounded-full focus-visible:outline-none focus-visible:shadow-button-neutral-focus\"\n >\n <Avatar size=\"sm\" content=\"letters\" fallback={email} />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-[220px]\">\n <DropdownMenuLabel className=\"text-xs text-foreground-neutral-muted truncate\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuLabel className=\"text-xs text-foreground-neutral-muted\">\n Theme\n </DropdownMenuLabel>\n <DropdownMenuRadioGroup value={theme} onValueChange={(value) => setTheme(value as Theme)}>\n {themeOptions.map((option) => (\n <DropdownMenuRadioItem key={option.value} value={option.value}>\n {option.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n {AccountMenuEntry ? (\n <AccountMenuEntryBoundary>\n <AccountMenuEntry />\n </AccountMenuEntryBoundary>\n ) : undefined}\n <DropdownMenuSeparator />\n <DropdownMenuItem asChild>\n <Link to={'/auth/logout' as never}>Logout</Link>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"names":["Avatar","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuLabel","DropdownMenuRadioGroup","DropdownMenuRadioItem","DropdownMenuSeparator","DropdownMenuTrigger","useTheme","Link","Component","useAuthState","useChrome","themeOptions","value","label","AccountMenuEntryBoundary","getDerivedStateFromError","hasError","componentDidCatch","error","globalThis","reportError","Error","cause","render","state","props","children","UserMenu","user","AccountMenuEntry","theme","setTheme","email","asChild","button","type","aria-label","className","size","content","fallback","align","sideOffset","onValueChange","map","option","undefined","to"],"mappings":";AAAA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SACEC,YAAY,EACZC,mBAAmB,EACnBC,gBAAgB,EAChBC,iBAAiB,EACjBC,sBAAsB,EACtBC,qBAAqB,EACrBC,qBAAqB,EACrBC,mBAAmB,QACd,kCAAkC;AACzC,SAAQC,QAAQ,QAAO,0BAA0B;AAEjD,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,SAAS,QAA+B,QAAQ;AACxD,SAAQC,YAAY,QAAO,mBAAmB;AAC9C,SAAQC,SAAS,QAAO,6BAA6B;AAErD,MAAMC,eAAqD;IACzD;QAACC,OAAO;QAASC,OAAO;IAAO;IAC/B;QAACD,OAAO;QAAQC,OAAO;IAAM;IAC7B;QAACD,OAAO;QAAUC,OAAO;IAAQ;CAClC;AAID,IAAA,AAAMC,2BAAN,MAAMA,iCAAiCN;IAGrC,OAAOO,2BAA0D;QAC/D,OAAO;YAACC,UAAU;QAAI;IACxB;IAESC,kBAAkBC,KAAc,EAAQ;QAC/CC,WAAWC,WAAW,GAAG,IAAIC,MAAM,wCAAwC;YAACC,OAAOJ;QAAK;IAC1F;IAESK,SAAS;QAChB,OAAO,IAAI,CAACC,KAAK,CAACR,QAAQ,GAAG,OAAO,IAAI,CAACS,KAAK,CAACC,QAAQ;IACzD;;QAbF,qBACWF,QAAuC;YAACR,UAAU;QAAK;;AAalE;AAEA,OAAO,SAASW;IACd,MAAM,EAACC,IAAI,EAAC,GAAGnB;IACf,MAAM,EAACoB,gBAAgB,EAAC,GAAGnB;IAC3B,MAAM,EAACoB,KAAK,EAAEC,QAAQ,EAAC,GAAGzB;IAC1B,MAAM0B,QAAQJ,MAAMI,SAAS;IAC7B,qBACE,MAAClC;;0BACC,KAACO;gBAAoB4B,OAAO;0BAC1B,cAAA,KAACC;oBACCC,MAAK;oBACLC,cAAW;oBACXC,WAAU;8BAEV,cAAA,KAACxC;wBAAOyC,MAAK;wBAAKC,SAAQ;wBAAUC,UAAUR;;;;0BAGlD,MAACjC;gBAAoB0C,OAAM;gBAAMC,YAAY;gBAAGL,WAAU;;kCACxD,KAACpC;wBAAkBoC,WAAU;kCAC1BL;;kCAEH,KAAC5B;kCACD,KAACH;wBAAkBoC,WAAU;kCAAwC;;kCAGrE,KAACnC;wBAAuBU,OAAOkB;wBAAOa,eAAe,CAAC/B,QAAUmB,SAASnB;kCACtED,aAAaiC,GAAG,CAAC,CAACC,uBACjB,KAAC1C;gCAAyCS,OAAOiC,OAAOjC,KAAK;0CAC1DiC,OAAOhC,KAAK;+BADagC,OAAOjC,KAAK;;oBAK3CiB,iCACC,KAACf;kCACC,cAAA,KAACe;yBAEDiB;kCACJ,KAAC1C;kCACD,KAACJ;wBAAiBiC,OAAO;kCACvB,cAAA,KAAC1B;4BAAKwC,IAAI;sCAAyB;;;;;;;AAK7C"}
|
package/dist/core/session.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;CAC7C"}
|
package/dist/core/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/session.ts"],"sourcesContent":["export type AdminRole = 'admin-observer' | 'admin-operator' | 'admin-owner';\n\nexport interface UserIdentity {\n id: string;\n email: string;\n name?: string;\n emailVerifiedAt?: string;\n adminRole?: AdminRole;\n}\n\nexport interface AuthenticatedSession {\n accessToken: string;\n user: UserIdentity;\n}\n\nexport interface WorkspaceMembership {\n id: string;\n workspaceId: string;\n}\n\nexport interface WorkspaceSummary {\n id: string;\n name: string;\n membershipId: string;\n}\n"],"names":[],"mappings":"AAoBA,
|
|
1
|
+
{"version":3,"sources":["../../src/core/session.ts"],"sourcesContent":["export type AdminRole = 'admin-observer' | 'admin-operator' | 'admin-owner';\n\nexport interface UserIdentity {\n id: string;\n email: string;\n name?: string;\n emailVerifiedAt?: string;\n adminRole?: AdminRole;\n}\n\nexport interface AuthenticatedSession {\n accessToken: string;\n user: UserIdentity;\n}\n\nexport interface WorkspaceMembership {\n id: string;\n workspaceId: string;\n}\n\nexport interface WorkspaceSummary {\n id: string;\n name: string;\n membershipId: string;\n status?: 'active' | 'suspended' | 'deleted';\n}\n"],"names":[],"mappings":"AAoBA,WAKC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/session-auth.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,iBAAiB,EAAe,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAC,oBAAoB,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAG7E,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAED,eAAO,MAAM,mBAAmB,8BAA+B,CAAC;AAChE,eAAO,MAAM,sBAAsB,iCAAkC,CAAC;AAEtE,KAAK,uBAAuB,GAAG,iBAAiB,CAC9C,oBAAoB,EACpB,KAAK,EACL,oBAAoB,EACpB,OAAO,mBAAmB,CAC3B,CAAC;AAEF,KAAK,0BAA0B,GAAG,iBAAiB,CACjD,cAAc,EACd,KAAK,EACL,cAAc,EACd,OAAO,sBAAsB,CAC9B,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"session-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/session-auth.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,iBAAiB,EAAe,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAC,oBAAoB,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAG7E,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAED,eAAO,MAAM,mBAAmB,8BAA+B,CAAC;AAChE,eAAO,MAAM,sBAAsB,iCAAkC,CAAC;AAEtE,KAAK,uBAAuB,GAAG,iBAAiB,CAC9C,oBAAoB,EACpB,KAAK,EACL,oBAAoB,EACpB,OAAO,mBAAmB,CAC3B,CAAC;AAEF,KAAK,0BAA0B,GAAG,iBAAiB,CACjD,cAAc,EACd,KAAK,EACL,cAAc,EACd,OAAO,sBAAsB,CAC9B,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,KAAK,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CAczB;AAED,wBAAgB,uBAAuB,IAAI,uBAAuB,CAOjE;AAED,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,0BAA0B,CAOrF;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,oBAAoB,CAAC,CAM/B"}
|
|
@@ -24,7 +24,8 @@ export async function listUserWorkspaces(token, signal) {
|
|
|
24
24
|
memberships: response.memberships.map((membership)=>({
|
|
25
25
|
id: membership.workspace_id,
|
|
26
26
|
name: membership.workspace_name,
|
|
27
|
-
membershipId: membership.id
|
|
27
|
+
membershipId: membership.id,
|
|
28
|
+
status: membership.workspace_status
|
|
28
29
|
}))
|
|
29
30
|
};
|
|
30
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/api/session-auth.ts"],"sourcesContent":["import {loginResponseSchema} from '@shipfox/api-auth-dto';\nimport {listUserWorkspacesResponseSchema} from '@shipfox/api-workspaces-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {type FetchQueryOptions, queryOptions} from '@tanstack/react-query';\nimport type {AuthenticatedSession, WorkspaceSummary} from '#core/session.js';\nimport {toAuthenticatedSession} from './session-mapper.js';\n\nexport interface UserWorkspaces {\n memberships: WorkspaceSummary[];\n}\n\nexport const authRefreshQueryKey = ['auth', 'refresh'] as const;\nexport const userWorkspacesQueryKey = ['workspaces', 'mine'] as const;\n\ntype AuthRefreshQueryOptions = FetchQueryOptions<\n AuthenticatedSession,\n Error,\n AuthenticatedSession,\n typeof authRefreshQueryKey\n>;\n\ntype UserWorkspacesQueryOptions = FetchQueryOptions<\n UserWorkspaces,\n Error,\n UserWorkspaces,\n typeof userWorkspacesQueryKey\n>;\n\nexport async function listUserWorkspaces(\n token?: string,\n signal?: AbortSignal,\n): Promise<UserWorkspaces> {\n const response = await checkedApiRequest(\n listUserWorkspacesResponseSchema,\n '/workspaces',\n token ? {headers: {authorization: `Bearer ${token}`}, signal} : {signal},\n );\n return {\n memberships: response.memberships.map((membership) => ({\n id: membership.workspace_id,\n name: membership.workspace_name,\n membershipId: membership.id,\n })),\n };\n}\n\nexport function authRefreshQueryOptions(): AuthRefreshQueryOptions {\n return queryOptions({\n queryKey: authRefreshQueryKey,\n queryFn: ({signal}) => refreshAuthenticatedSession(signal),\n retry: false,\n staleTime: 0,\n });\n}\n\nexport function userWorkspacesQueryOptions(token?: string): UserWorkspacesQueryOptions {\n return queryOptions({\n queryKey: userWorkspacesQueryKey,\n queryFn: ({signal}) => listUserWorkspaces(token, signal),\n retry: false,\n staleTime: 0,\n });\n}\n\nexport async function refreshAuthenticatedSession(\n signal?: AbortSignal,\n): Promise<AuthenticatedSession> {\n const response = await checkedApiRequest(loginResponseSchema, '/auth/refresh', {\n method: 'POST',\n signal,\n });\n return toAuthenticatedSession(response);\n}\n"],"names":["loginResponseSchema","listUserWorkspacesResponseSchema","checkedApiRequest","queryOptions","toAuthenticatedSession","authRefreshQueryKey","userWorkspacesQueryKey","listUserWorkspaces","token","signal","response","headers","authorization","memberships","map","membership","id","workspace_id","name","workspace_name","membershipId","authRefreshQueryOptions","queryKey","queryFn","refreshAuthenticatedSession","retry","staleTime","userWorkspacesQueryOptions","method"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAC1D,SAAQC,gCAAgC,QAAO,8BAA8B;AAC7E,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAgCC,YAAY,QAAO,wBAAwB;AAE3E,SAAQC,sBAAsB,QAAO,sBAAsB;AAM3D,OAAO,MAAMC,sBAAsB;IAAC;IAAQ;CAAU,CAAU;AAChE,OAAO,MAAMC,yBAAyB;IAAC;IAAc;CAAO,CAAU;AAgBtE,OAAO,eAAeC,mBACpBC,KAAc,EACdC,MAAoB;IAEpB,MAAMC,WAAW,MAAMR,kBACrBD,kCACA,eACAO,QAAQ;QAACG,SAAS;YAACC,eAAe,CAAC,OAAO,EAAEJ,OAAO;QAAA;QAAGC;IAAM,IAAI;QAACA;IAAM;IAEzE,OAAO;QACLI,aAAaH,SAASG,WAAW,CAACC,GAAG,CAAC,CAACC,aAAgB,CAAA;gBACrDC,IAAID,WAAWE,YAAY;gBAC3BC,MAAMH,WAAWI,cAAc;gBAC/BC,cAAcL,WAAWC,EAAE;
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/api/session-auth.ts"],"sourcesContent":["import {loginResponseSchema} from '@shipfox/api-auth-dto';\nimport {listUserWorkspacesResponseSchema} from '@shipfox/api-workspaces-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {type FetchQueryOptions, queryOptions} from '@tanstack/react-query';\nimport type {AuthenticatedSession, WorkspaceSummary} from '#core/session.js';\nimport {toAuthenticatedSession} from './session-mapper.js';\n\nexport interface UserWorkspaces {\n memberships: WorkspaceSummary[];\n}\n\nexport const authRefreshQueryKey = ['auth', 'refresh'] as const;\nexport const userWorkspacesQueryKey = ['workspaces', 'mine'] as const;\n\ntype AuthRefreshQueryOptions = FetchQueryOptions<\n AuthenticatedSession,\n Error,\n AuthenticatedSession,\n typeof authRefreshQueryKey\n>;\n\ntype UserWorkspacesQueryOptions = FetchQueryOptions<\n UserWorkspaces,\n Error,\n UserWorkspaces,\n typeof userWorkspacesQueryKey\n>;\n\nexport async function listUserWorkspaces(\n token?: string,\n signal?: AbortSignal,\n): Promise<UserWorkspaces> {\n const response = await checkedApiRequest(\n listUserWorkspacesResponseSchema,\n '/workspaces',\n token ? {headers: {authorization: `Bearer ${token}`}, signal} : {signal},\n );\n return {\n memberships: response.memberships.map((membership) => ({\n id: membership.workspace_id,\n name: membership.workspace_name,\n membershipId: membership.id,\n status: membership.workspace_status,\n })),\n };\n}\n\nexport function authRefreshQueryOptions(): AuthRefreshQueryOptions {\n return queryOptions({\n queryKey: authRefreshQueryKey,\n queryFn: ({signal}) => refreshAuthenticatedSession(signal),\n retry: false,\n staleTime: 0,\n });\n}\n\nexport function userWorkspacesQueryOptions(token?: string): UserWorkspacesQueryOptions {\n return queryOptions({\n queryKey: userWorkspacesQueryKey,\n queryFn: ({signal}) => listUserWorkspaces(token, signal),\n retry: false,\n staleTime: 0,\n });\n}\n\nexport async function refreshAuthenticatedSession(\n signal?: AbortSignal,\n): Promise<AuthenticatedSession> {\n const response = await checkedApiRequest(loginResponseSchema, '/auth/refresh', {\n method: 'POST',\n signal,\n });\n return toAuthenticatedSession(response);\n}\n"],"names":["loginResponseSchema","listUserWorkspacesResponseSchema","checkedApiRequest","queryOptions","toAuthenticatedSession","authRefreshQueryKey","userWorkspacesQueryKey","listUserWorkspaces","token","signal","response","headers","authorization","memberships","map","membership","id","workspace_id","name","workspace_name","membershipId","status","workspace_status","authRefreshQueryOptions","queryKey","queryFn","refreshAuthenticatedSession","retry","staleTime","userWorkspacesQueryOptions","method"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAC1D,SAAQC,gCAAgC,QAAO,8BAA8B;AAC7E,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAgCC,YAAY,QAAO,wBAAwB;AAE3E,SAAQC,sBAAsB,QAAO,sBAAsB;AAM3D,OAAO,MAAMC,sBAAsB;IAAC;IAAQ;CAAU,CAAU;AAChE,OAAO,MAAMC,yBAAyB;IAAC;IAAc;CAAO,CAAU;AAgBtE,OAAO,eAAeC,mBACpBC,KAAc,EACdC,MAAoB;IAEpB,MAAMC,WAAW,MAAMR,kBACrBD,kCACA,eACAO,QAAQ;QAACG,SAAS;YAACC,eAAe,CAAC,OAAO,EAAEJ,OAAO;QAAA;QAAGC;IAAM,IAAI;QAACA;IAAM;IAEzE,OAAO;QACLI,aAAaH,SAASG,WAAW,CAACC,GAAG,CAAC,CAACC,aAAgB,CAAA;gBACrDC,IAAID,WAAWE,YAAY;gBAC3BC,MAAMH,WAAWI,cAAc;gBAC/BC,cAAcL,WAAWC,EAAE;gBAC3BK,QAAQN,WAAWO,gBAAgB;YACrC,CAAA;IACF;AACF;AAEA,OAAO,SAASC;IACd,OAAOpB,aAAa;QAClBqB,UAAUnB;QACVoB,SAAS,CAAC,EAAChB,MAAM,EAAC,GAAKiB,4BAA4BjB;QACnDkB,OAAO;QACPC,WAAW;IACb;AACF;AAEA,OAAO,SAASC,2BAA2BrB,KAAc;IACvD,OAAOL,aAAa;QAClBqB,UAAUlB;QACVmB,SAAS,CAAC,EAAChB,MAAM,EAAC,GAAKF,mBAAmBC,OAAOC;QACjDkB,OAAO;QACPC,WAAW;IACb;AACF;AAEA,OAAO,eAAeF,4BACpBjB,MAAoB;IAEpB,MAAMC,WAAW,MAAMR,kBAAkBF,qBAAqB,iBAAiB;QAC7E8B,QAAQ;QACRrB;IACF;IACA,OAAOL,uBAAuBM;AAChC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anchors.d.ts","sourceRoot":"","sources":["../../src/runtime/anchors.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,cAAc,CAAC;AAKpE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"anchors.d.ts","sourceRoot":"","sources":["../../src/runtime/anchors.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,cAAc,CAAC;AAKpE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAOvD,OAAO,EAAC,kBAAkB,EAAC,MAAM,mBAAmB,CAAC;AAErD,wBAAgB,mBAAmB,CAAC,EAClC,UAAU,EACV,gBAAgB,GACjB,EAAE;IACD,UAAU,EAAE,SAAS,WAAW,EAAE,CAAC;IACnC,gBAAgB,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACnD;;;;;;;;;;;EAyFA"}
|
package/dist/runtime/anchors.js
CHANGED
|
@@ -5,11 +5,11 @@ import { createRootRouteWithContext, createRoute, Outlet, redirect } from '@tans
|
|
|
5
5
|
import { MainLayout } from '#components/main-layout.js';
|
|
6
6
|
import { NotFoundPage } from '#components/not-found-page.js';
|
|
7
7
|
import { SettingsNav } from '#components/settings-nav.js';
|
|
8
|
-
import { useActiveWorkspace } from './active-workspace.js';
|
|
8
|
+
import { useActiveWorkspace, useMaybeActiveWorkspace } from './active-workspace.js';
|
|
9
9
|
import { anchorPaths } from './anchor-paths.js';
|
|
10
10
|
import { useChrome } from './chrome-context.js';
|
|
11
11
|
import { rememberLastWorkspaceId } from './last-workspace.js';
|
|
12
|
-
import { WorkspaceLayoutErrorRoute, WorkspaceSetupPending } from './workspace-setup.js';
|
|
12
|
+
import { WorkspaceLayoutErrorRoute, WorkspaceSetupPending, WorkspaceUnavailablePage } from './workspace-setup.js';
|
|
13
13
|
export { routePathForAnchor } from './anchor-paths.js';
|
|
14
14
|
export function buildAnchorSkeleton({ navigation, settingsSections }) {
|
|
15
15
|
const rootRoute = createRootRouteWithContext()({
|
|
@@ -55,7 +55,10 @@ export function buildAnchorSkeleton({ navigation, settingsSections }) {
|
|
|
55
55
|
errorComponent: WorkspaceLayoutErrorRoute,
|
|
56
56
|
component: ()=>{
|
|
57
57
|
const setupState = workspaceLayout.useRouteContext();
|
|
58
|
-
|
|
58
|
+
const workspace = useMaybeActiveWorkspace();
|
|
59
|
+
return setupState.hideProjectNavigation === undefined ? /*#__PURE__*/ _jsx(WorkspaceSetupPending, {}) : setupState.unavailable ? /*#__PURE__*/ _jsx(WorkspaceUnavailablePage, {
|
|
60
|
+
workspaceName: workspace?.name
|
|
61
|
+
}) : /*#__PURE__*/ _jsx(MainLayout, {
|
|
59
62
|
navigation: navigation,
|
|
60
63
|
hideProjectNavigation: setupState.hideProjectNavigation
|
|
61
64
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/anchors.tsx"],"sourcesContent":["import {ShipfoxLoader} from '@shipfox/react-ui/loader';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {createRootRouteWithContext, createRoute, Outlet, redirect} from '@tanstack/react-router';\nimport {MainLayout} from '#components/main-layout.js';\nimport {NotFoundPage} from '#components/not-found-page.js';\nimport {SettingsNav} from '#components/settings-nav.js';\nimport type {NavTabEntry, SettingsSectionEntry} from '#contract.js';\nimport {useActiveWorkspace} from './active-workspace.js';\nimport {anchorPaths} from './anchor-paths.js';\nimport {useChrome} from './chrome-context.js';\nimport {rememberLastWorkspaceId} from './last-workspace.js';\nimport type {RouterContext} from './router-context.js';\nimport {WorkspaceLayoutErrorRoute
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/anchors.tsx"],"sourcesContent":["import {ShipfoxLoader} from '@shipfox/react-ui/loader';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {createRootRouteWithContext, createRoute, Outlet, redirect} from '@tanstack/react-router';\nimport {MainLayout} from '#components/main-layout.js';\nimport {NotFoundPage} from '#components/not-found-page.js';\nimport {SettingsNav} from '#components/settings-nav.js';\nimport type {NavTabEntry, SettingsSectionEntry} from '#contract.js';\nimport {useActiveWorkspace, useMaybeActiveWorkspace} from './active-workspace.js';\nimport {anchorPaths} from './anchor-paths.js';\nimport {useChrome} from './chrome-context.js';\nimport {rememberLastWorkspaceId} from './last-workspace.js';\nimport type {RouterContext} from './router-context.js';\nimport {\n WorkspaceLayoutErrorRoute,\n WorkspaceSetupPending,\n WorkspaceUnavailablePage,\n} from './workspace-setup.js';\n\nexport {routePathForAnchor} from './anchor-paths.js';\n\nexport function buildAnchorSkeleton({\n navigation,\n settingsSections,\n}: {\n navigation: readonly NavTabEntry[];\n settingsSections: readonly SettingsSectionEntry[];\n}) {\n const rootRoute = createRootRouteWithContext<RouterContext>()({\n component: Outlet,\n notFoundComponent: NotFoundPage,\n });\n const workspaceLayout = createRoute({\n getParentRoute: () => rootRoute,\n path: anchorPaths.workspaceLayout,\n beforeLoad: async ({context, params, location}) => {\n const auth = context.auth;\n if (!auth || auth.isLoading || !context.queryClient) return;\n if (!auth.isAuthenticated)\n throw redirect({to: '/auth/login' as never, search: {redirect: location.href} as never});\n if (!auth.workspaces.some((workspace) => workspace.id === params.wid))\n throw redirect({to: '/'});\n try {\n if (auth.user?.id) rememberLastWorkspaceId(auth.user.id, params.wid);\n } catch {\n // Local storage is best effort.\n }\n if (!context.workspaceSetup)\n throw new Error('Client composition includes workspace routes but no workspaceSetup gate.');\n return await context.workspaceSetup({\n queryClient: context.queryClient,\n workspaceId: params.wid,\n pathname: location.pathname,\n });\n },\n pendingComponent: () => (\n <div className=\"flex h-screen items-center justify-center\">\n <ShipfoxLoader size={64} animation=\"circular\" color=\"orange\" background=\"dark\" />\n </div>\n ),\n errorComponent: WorkspaceLayoutErrorRoute,\n component: () => {\n const setupState = workspaceLayout.useRouteContext() as {\n hideProjectNavigation?: boolean;\n unavailable?: boolean;\n };\n const workspace = useMaybeActiveWorkspace();\n return setupState.hideProjectNavigation === undefined ? (\n <WorkspaceSetupPending />\n ) : setupState.unavailable ? (\n <WorkspaceUnavailablePage workspaceName={workspace?.name} />\n ) : (\n <MainLayout\n navigation={navigation}\n hideProjectNavigation={setupState.hideProjectNavigation}\n />\n );\n },\n });\n const projectLayout = createRoute({\n getParentRoute: () => workspaceLayout,\n path: '/projects/$pid',\n component: () => {\n const {ProjectLayoutGuard} = useChrome();\n return <ProjectLayoutGuard />;\n },\n });\n const workspaceSettings = createRoute({\n getParentRoute: () => workspaceLayout,\n path: '/settings',\n component: () => {\n const workspace = useActiveWorkspace();\n return (\n <div className=\"flex w-full flex-col gap-24\">\n <header className=\"flex flex-col gap-6\">\n <Header variant=\"h2\">Workspace settings</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Configure {workspace.name}.\n </Text>\n </header>\n\n <div className=\"grid grid-cols-[180px_minmax(0,1fr)] gap-32 max-[760px]:grid-cols-1\">\n <SettingsNav entries={settingsSections} />\n <Outlet />\n </div>\n </div>\n );\n },\n });\n return {\n anchors: {root: rootRoute, workspaceLayout, projectLayout, workspaceSettings},\n rootRoute,\n workspaceLayout,\n projectLayout,\n workspaceSettings,\n };\n}\n"],"names":["ShipfoxLoader","Header","Text","createRootRouteWithContext","createRoute","Outlet","redirect","MainLayout","NotFoundPage","SettingsNav","useActiveWorkspace","useMaybeActiveWorkspace","anchorPaths","useChrome","rememberLastWorkspaceId","WorkspaceLayoutErrorRoute","WorkspaceSetupPending","WorkspaceUnavailablePage","routePathForAnchor","buildAnchorSkeleton","navigation","settingsSections","rootRoute","component","notFoundComponent","workspaceLayout","getParentRoute","path","beforeLoad","context","params","location","auth","isLoading","queryClient","isAuthenticated","to","search","href","workspaces","some","workspace","id","wid","user","workspaceSetup","Error","workspaceId","pathname","pendingComponent","div","className","size","animation","color","background","errorComponent","setupState","useRouteContext","hideProjectNavigation","undefined","unavailable","workspaceName","name","projectLayout","ProjectLayoutGuard","workspaceSettings","header","variant","entries","anchors","root"],"mappings":"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"}
|
|
@@ -2,6 +2,12 @@ import type { ComponentType, PropsWithChildren } from 'react';
|
|
|
2
2
|
export interface ChromeSlots {
|
|
3
3
|
ProjectBreadcrumb: ComponentType;
|
|
4
4
|
ProjectLayoutGuard: ComponentType;
|
|
5
|
+
/**
|
|
6
|
+
* Optional content rendered in the account menu before the shell-owned logout
|
|
7
|
+
* action. The composing component must render one DropdownMenuItem or return
|
|
8
|
+
* null, and owns whether this content renders from the current session.
|
|
9
|
+
*/
|
|
10
|
+
AccountMenuEntry?: ComponentType;
|
|
5
11
|
}
|
|
6
12
|
export declare function ChromeProvider({ chrome, children, }: PropsWithChildren<{
|
|
7
13
|
chrome: ChromeSlots | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chrome-context.d.ts","sourceRoot":"","sources":["../../src/runtime/chrome-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAE,iBAAiB,EAAC,MAAM,OAAO,CAAC;AAG5D,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,aAAa,CAAC;IACjC,kBAAkB,EAAE,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"chrome-context.d.ts","sourceRoot":"","sources":["../../src/runtime/chrome-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAE,iBAAiB,EAAC,MAAM,OAAO,CAAC;AAG5D,MAAM,WAAW,WAAW;IAC1B,iBAAiB,EAAE,aAAa,CAAC;IACjC,kBAAkB,EAAE,aAAa,CAAC;IAClC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,aAAa,CAAC;CAClC;AAID,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,GACT,EAAE,iBAAiB,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAA;CAAC,CAAC,+BAEtD;AAED,wBAAgB,SAAS,IAAI,WAAW,CAIvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/chrome-context.tsx"],"sourcesContent":["import type {ComponentType, PropsWithChildren} from 'react';\nimport {createContext, useContext} from 'react';\n\nexport interface ChromeSlots {\n ProjectBreadcrumb: ComponentType;\n ProjectLayoutGuard: ComponentType;\n}\n\nconst ChromeContext = createContext<ChromeSlots | undefined>(undefined);\n\nexport function ChromeProvider({\n chrome,\n children,\n}: PropsWithChildren<{chrome: ChromeSlots | undefined}>) {\n return <ChromeContext.Provider value={chrome}>{children}</ChromeContext.Provider>;\n}\n\nexport function useChrome(): ChromeSlots {\n const chrome = useContext(ChromeContext);\n if (!chrome) throw new Error('Client composition must provide browser chrome slots.');\n return chrome;\n}\n"],"names":["createContext","useContext","ChromeContext","undefined","ChromeProvider","chrome","children","Provider","value","useChrome","Error"],"mappings":";AACA,SAAQA,aAAa,EAAEC,UAAU,QAAO,QAAQ;
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/chrome-context.tsx"],"sourcesContent":["import type {ComponentType, PropsWithChildren} from 'react';\nimport {createContext, useContext} from 'react';\n\nexport interface ChromeSlots {\n ProjectBreadcrumb: ComponentType;\n ProjectLayoutGuard: ComponentType;\n /**\n * Optional content rendered in the account menu before the shell-owned logout\n * action. The composing component must render one DropdownMenuItem or return\n * null, and owns whether this content renders from the current session.\n */\n AccountMenuEntry?: ComponentType;\n}\n\nconst ChromeContext = createContext<ChromeSlots | undefined>(undefined);\n\nexport function ChromeProvider({\n chrome,\n children,\n}: PropsWithChildren<{chrome: ChromeSlots | undefined}>) {\n return <ChromeContext.Provider value={chrome}>{children}</ChromeContext.Provider>;\n}\n\nexport function useChrome(): ChromeSlots {\n const chrome = useContext(ChromeContext);\n if (!chrome) throw new Error('Client composition must provide browser chrome slots.');\n return chrome;\n}\n"],"names":["createContext","useContext","ChromeContext","undefined","ChromeProvider","chrome","children","Provider","value","useChrome","Error"],"mappings":";AACA,SAAQA,aAAa,EAAEC,UAAU,QAAO,QAAQ;AAahD,MAAMC,8BAAgBF,cAAuCG;AAE7D,OAAO,SAASC,eAAe,EAC7BC,MAAM,EACNC,QAAQ,EAC6C;IACrD,qBAAO,KAACJ,cAAcK,QAAQ;QAACC,OAAOH;kBAASC;;AACjD;AAEA,OAAO,SAASG;IACd,MAAMJ,SAASJ,WAAWC;IAC1B,IAAI,CAACG,QAAQ,MAAM,IAAIK,MAAM;IAC7B,OAAOL;AACT"}
|
|
@@ -2,6 +2,7 @@ import type { QueryClient } from '@tanstack/react-query';
|
|
|
2
2
|
import { type ErrorComponentProps } from '@tanstack/react-router';
|
|
3
3
|
export interface WorkspaceSetupState {
|
|
4
4
|
hideProjectNavigation: boolean;
|
|
5
|
+
unavailable?: boolean;
|
|
5
6
|
}
|
|
6
7
|
export interface WorkspaceSetupRouteOptions {
|
|
7
8
|
queryClient: QueryClient;
|
|
@@ -14,5 +15,8 @@ export declare class WorkspaceSetupLoadError extends Error {
|
|
|
14
15
|
constructor(cause: unknown);
|
|
15
16
|
}
|
|
16
17
|
export declare function WorkspaceSetupPending(): import("react").JSX.Element;
|
|
18
|
+
export declare function WorkspaceUnavailablePage({ workspaceName }: {
|
|
19
|
+
workspaceName?: string | undefined;
|
|
20
|
+
}): import("react").JSX.Element;
|
|
17
21
|
export declare function WorkspaceLayoutErrorRoute({ error, reset }: ErrorComponentProps): import("react").JSX.Element;
|
|
18
22
|
//# sourceMappingURL=workspace-setup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-setup.d.ts","sourceRoot":"","sources":["../../src/runtime/workspace-setup.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAC,KAAK,mBAAmB,EAAY,MAAM,wBAAwB,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,qBAAqB,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-setup.d.ts","sourceRoot":"","sources":["../../src/runtime/workspace-setup.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAC,KAAK,mBAAmB,EAAY,MAAM,wBAAwB,CAAC;AAE3E,MAAM,WAAW,mBAAmB;IAClC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AACD,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,0BAA0B,KAChC,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAElC,qBAAa,uBAAwB,SAAQ,KAAK;aACX,KAAK,EAAE,OAAO;gBAAd,KAAK,EAAE,OAAO;CAIpD;AACD,wBAAgB,qBAAqB,gCAEpC;AAED,wBAAgB,wBAAwB,CAAC,EAAC,aAAa,EAAC,EAAE;IAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAC,+BAc7F;AACD,wBAAgB,yBAAyB,CAAC,EAAC,KAAK,EAAE,KAAK,EAAC,EAAE,mBAAmB,+BA+B5E"}
|
|
@@ -14,6 +14,29 @@ export class WorkspaceSetupLoadError extends Error {
|
|
|
14
14
|
export function WorkspaceSetupPending() {
|
|
15
15
|
return /*#__PURE__*/ _jsx(FullPageLoader, {});
|
|
16
16
|
}
|
|
17
|
+
export function WorkspaceUnavailablePage({ workspaceName }) {
|
|
18
|
+
return /*#__PURE__*/ _jsx("main", {
|
|
19
|
+
className: "min-h-screen bg-background-subtle-base px-24 py-32 max-[520px]:px-16",
|
|
20
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
21
|
+
className: "mx-auto flex w-full max-w-[640px] flex-col gap-12",
|
|
22
|
+
children: [
|
|
23
|
+
/*#__PURE__*/ _jsx(Header, {
|
|
24
|
+
variant: "h1",
|
|
25
|
+
children: "Workspace unavailable"
|
|
26
|
+
}),
|
|
27
|
+
/*#__PURE__*/ _jsxs(Text, {
|
|
28
|
+
size: "md",
|
|
29
|
+
className: "text-foreground-neutral-muted",
|
|
30
|
+
children: [
|
|
31
|
+
workspaceName ? `${workspaceName} is currently unavailable.` : 'This workspace is currently unavailable.',
|
|
32
|
+
' ',
|
|
33
|
+
"Please contact your configured support contact if you need help."
|
|
34
|
+
]
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
}
|
|
17
40
|
export function WorkspaceLayoutErrorRoute({ error, reset }) {
|
|
18
41
|
const router = useRouter();
|
|
19
42
|
const retry = ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/workspace-setup.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport type {QueryClient} from '@tanstack/react-query';\nimport {type ErrorComponentProps, useRouter} from '@tanstack/react-router';\n\nexport interface WorkspaceSetupState {\n hideProjectNavigation: boolean;\n}\nexport interface WorkspaceSetupRouteOptions {\n queryClient: QueryClient;\n workspaceId: string;\n pathname: string;\n}\nexport type WorkspaceSetupGate = (\n options: WorkspaceSetupRouteOptions,\n) => Promise<WorkspaceSetupState>;\n\nexport class WorkspaceSetupLoadError extends Error {\n constructor(public override readonly cause: unknown) {\n super(cause instanceof Error ? cause.message : 'Workspace setup load failed');\n this.name = 'WorkspaceSetupLoadError';\n }\n}\nexport function WorkspaceSetupPending() {\n return <FullPageLoader />;\n}\nexport function WorkspaceLayoutErrorRoute({error, reset}: ErrorComponentProps) {\n const router = useRouter();\n const retry = () => {\n reset();\n void router.invalidate();\n };\n const setupError = error instanceof WorkspaceSetupLoadError;\n const message =\n error instanceof ApiError\n ? error.message\n : setupError && error.cause instanceof ApiError\n ? error.cause.message\n : 'Try again in a moment.';\n return (\n <main className=\"min-h-screen bg-background-subtle-base px-24 py-32 max-[520px]:px-16\">\n <div className=\"mx-auto flex w-full max-w-[640px] flex-col gap-24\">\n <Header variant=\"h1\">{setupError ? 'Workspace setup' : 'Workspace'}</Header>\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-8\">\n <Text size=\"sm\" bold>\n {setupError ? 'Could not load workspace setup' : 'Could not load workspace'}\n </Text>\n <Text size=\"sm\">{message}</Text>\n <Button size=\"sm\" variant=\"secondary\" onClick={retry} className=\"w-fit\">\n Retry\n </Button>\n </div>\n </Callout>\n </div>\n </main>\n );\n}\n"],"names":["ApiError","Button","Callout","FullPageLoader","Header","Text","useRouter","WorkspaceSetupLoadError","Error","cause","message","name","WorkspaceSetupPending","
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/workspace-setup.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport type {QueryClient} from '@tanstack/react-query';\nimport {type ErrorComponentProps, useRouter} from '@tanstack/react-router';\n\nexport interface WorkspaceSetupState {\n hideProjectNavigation: boolean;\n unavailable?: boolean;\n}\nexport interface WorkspaceSetupRouteOptions {\n queryClient: QueryClient;\n workspaceId: string;\n pathname: string;\n}\nexport type WorkspaceSetupGate = (\n options: WorkspaceSetupRouteOptions,\n) => Promise<WorkspaceSetupState>;\n\nexport class WorkspaceSetupLoadError extends Error {\n constructor(public override readonly cause: unknown) {\n super(cause instanceof Error ? cause.message : 'Workspace setup load failed');\n this.name = 'WorkspaceSetupLoadError';\n }\n}\nexport function WorkspaceSetupPending() {\n return <FullPageLoader />;\n}\n\nexport function WorkspaceUnavailablePage({workspaceName}: {workspaceName?: string | undefined}) {\n return (\n <main className=\"min-h-screen bg-background-subtle-base px-24 py-32 max-[520px]:px-16\">\n <div className=\"mx-auto flex w-full max-w-[640px] flex-col gap-12\">\n <Header variant=\"h1\">Workspace unavailable</Header>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n {workspaceName\n ? `${workspaceName} is currently unavailable.`\n : 'This workspace is currently unavailable.'}{' '}\n Please contact your configured support contact if you need help.\n </Text>\n </div>\n </main>\n );\n}\nexport function WorkspaceLayoutErrorRoute({error, reset}: ErrorComponentProps) {\n const router = useRouter();\n const retry = () => {\n reset();\n void router.invalidate();\n };\n const setupError = error instanceof WorkspaceSetupLoadError;\n const message =\n error instanceof ApiError\n ? error.message\n : setupError && error.cause instanceof ApiError\n ? error.cause.message\n : 'Try again in a moment.';\n return (\n <main className=\"min-h-screen bg-background-subtle-base px-24 py-32 max-[520px]:px-16\">\n <div className=\"mx-auto flex w-full max-w-[640px] flex-col gap-24\">\n <Header variant=\"h1\">{setupError ? 'Workspace setup' : 'Workspace'}</Header>\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-8\">\n <Text size=\"sm\" bold>\n {setupError ? 'Could not load workspace setup' : 'Could not load workspace'}\n </Text>\n <Text size=\"sm\">{message}</Text>\n <Button size=\"sm\" variant=\"secondary\" onClick={retry} className=\"w-fit\">\n Retry\n </Button>\n </div>\n </Callout>\n </div>\n </main>\n );\n}\n"],"names":["ApiError","Button","Callout","FullPageLoader","Header","Text","useRouter","WorkspaceSetupLoadError","Error","cause","message","name","WorkspaceSetupPending","WorkspaceUnavailablePage","workspaceName","main","className","div","variant","size","WorkspaceLayoutErrorRoute","error","reset","router","retry","invalidate","setupError","role","type","bold","onClick"],"mappings":";AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAC7C,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,cAAc,QAAO,2BAA2B;AACxD,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAE1D,SAAkCC,SAAS,QAAO,yBAAyB;AAe3E,OAAO,MAAMC,gCAAgCC;IAC3C,YAAY,AAAyBC,KAAc,CAAE;QACnD,KAAK,CAACA,iBAAiBD,QAAQC,MAAMC,OAAO,GAAG,qCADZD,QAAAA;QAEnC,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AACA,OAAO,SAASC;IACd,qBAAO,KAACT;AACV;AAEA,OAAO,SAASU,yBAAyB,EAACC,aAAa,EAAuC;IAC5F,qBACE,KAACC;QAAKC,WAAU;kBACd,cAAA,MAACC;YAAID,WAAU;;8BACb,KAACZ;oBAAOc,SAAQ;8BAAK;;8BACrB,MAACb;oBAAKc,MAAK;oBAAKH,WAAU;;wBACvBF,gBACG,GAAGA,cAAc,0BAA0B,CAAC,GAC5C;wBAA4C;wBAAI;;;;;;AAM9D;AACA,OAAO,SAASM,0BAA0B,EAACC,KAAK,EAAEC,KAAK,EAAsB;IAC3E,MAAMC,SAASjB;IACf,MAAMkB,QAAQ;QACZF;QACA,KAAKC,OAAOE,UAAU;IACxB;IACA,MAAMC,aAAaL,iBAAiBd;IACpC,MAAMG,UACJW,iBAAiBrB,WACbqB,MAAMX,OAAO,GACbgB,cAAcL,MAAMZ,KAAK,YAAYT,WACnCqB,MAAMZ,KAAK,CAACC,OAAO,GACnB;IACR,qBACE,KAACK;QAAKC,WAAU;kBACd,cAAA,MAACC;YAAID,WAAU;;8BACb,KAACZ;oBAAOc,SAAQ;8BAAMQ,aAAa,oBAAoB;;8BACvD,KAACxB;oBAAQyB,MAAK;oBAAQC,MAAK;8BACzB,cAAA,MAACX;wBAAID,WAAU;;0CACb,KAACX;gCAAKc,MAAK;gCAAKU,IAAI;0CACjBH,aAAa,mCAAmC;;0CAEnD,KAACrB;gCAAKc,MAAK;0CAAMT;;0CACjB,KAACT;gCAAOkB,MAAK;gCAAKD,SAAQ;gCAAYY,SAASN;gCAAOR,WAAU;0CAAQ;;;;;;;;AAQpF"}
|