@workos-inc/widgets 1.5.0 → 1.5.1
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/CHANGELOG.md +19 -8
- package/dist/cjs/admin-portal-domain-verification.client.cjs +2 -3
- package/dist/cjs/admin-portal-domain-verification.client.cjs.map +1 -1
- package/dist/cjs/admin-portal-sso-connection-client.cjs +3 -4
- package/dist/cjs/admin-portal-sso-connection-client.cjs.map +1 -1
- package/dist/cjs/api/api-provider.cjs +27 -19
- package/dist/cjs/api/api-provider.cjs.map +1 -1
- package/dist/cjs/api/api-provider.d.cts +4 -3
- package/dist/cjs/api/utils.cjs +10 -0
- package/dist/cjs/api/utils.cjs.map +1 -1
- package/dist/cjs/api/utils.d.cts +7 -2
- package/dist/cjs/api/widgets-api-client.cjs +11 -5
- package/dist/cjs/api/widgets-api-client.cjs.map +1 -1
- package/dist/cjs/api-keys-client.cjs +3 -8
- package/dist/cjs/api-keys-client.cjs.map +1 -1
- package/dist/cjs/lib/add-mfa-dialog.cjs +1 -1
- package/dist/cjs/lib/add-mfa-dialog.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-domain-verification.cjs +25 -18
- package/dist/cjs/lib/admin-portal-domain-verification.cjs.map +1 -1
- package/dist/cjs/lib/admin-portal-sso-connection.cjs +5 -27
- package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
- package/dist/cjs/lib/card-list.cjs.map +1 -0
- package/dist/cjs/lib/errors.cjs +1 -1
- package/dist/cjs/lib/errors.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.cjs +27 -38
- package/dist/cjs/lib/generic-error.cjs.map +1 -1
- package/dist/cjs/lib/generic-error.d.cts +5 -1
- package/dist/cjs/lib/use-permissions.cjs +7 -14
- package/dist/cjs/lib/use-permissions.cjs.map +1 -1
- package/dist/cjs/lib/use-permissions.d.cts +1 -1
- package/dist/cjs/lib/user-security.cjs +1 -1
- package/dist/cjs/lib/user-security.cjs.map +1 -1
- package/dist/cjs/lib/user-sessions.cjs +1 -1
- package/dist/cjs/lib/user-sessions.cjs.map +1 -1
- package/dist/cjs/organization-switcher.client.cjs +2 -4
- package/dist/cjs/organization-switcher.client.cjs.map +1 -1
- package/dist/cjs/user-profile.client.cjs +2 -6
- package/dist/cjs/user-profile.client.cjs.map +1 -1
- package/dist/cjs/user-security.client.cjs +5 -4
- package/dist/cjs/user-security.client.cjs.map +1 -1
- package/dist/cjs/user-sessions.client.cjs +8 -12
- package/dist/cjs/user-sessions.client.cjs.map +1 -1
- package/dist/cjs/users-management.client.cjs +3 -9
- package/dist/cjs/users-management.client.cjs.map +1 -1
- package/dist/esm/admin-portal-domain-verification.client.js +3 -4
- package/dist/esm/admin-portal-domain-verification.client.js.map +1 -1
- package/dist/esm/admin-portal-sso-connection-client.js +4 -5
- package/dist/esm/admin-portal-sso-connection-client.js.map +1 -1
- package/dist/esm/api/api-provider.d.ts +4 -3
- package/dist/esm/api/api-provider.js +26 -19
- package/dist/esm/api/api-provider.js.map +1 -1
- package/dist/esm/api/utils.d.ts +7 -2
- package/dist/esm/api/utils.js +9 -0
- package/dist/esm/api/utils.js.map +1 -1
- package/dist/esm/api/widgets-api-client.js +11 -5
- package/dist/esm/api/widgets-api-client.js.map +1 -1
- package/dist/esm/api-keys-client.js +4 -9
- package/dist/esm/api-keys-client.js.map +1 -1
- package/dist/esm/lib/add-mfa-dialog.js +1 -1
- package/dist/esm/lib/add-mfa-dialog.js.map +1 -1
- package/dist/esm/lib/admin-portal-domain-verification.js +25 -18
- package/dist/esm/lib/admin-portal-domain-verification.js.map +1 -1
- package/dist/esm/lib/admin-portal-sso-connection.js +5 -27
- package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
- package/dist/esm/lib/card-list.js.map +1 -0
- package/dist/esm/lib/errors.js +1 -1
- package/dist/esm/lib/errors.js.map +1 -1
- package/dist/esm/lib/generic-error.d.ts +5 -1
- package/dist/esm/lib/generic-error.js +27 -40
- package/dist/esm/lib/generic-error.js.map +1 -1
- package/dist/esm/lib/use-permissions.d.ts +1 -1
- package/dist/esm/lib/use-permissions.js +8 -15
- package/dist/esm/lib/use-permissions.js.map +1 -1
- package/dist/esm/lib/user-security.js +1 -1
- package/dist/esm/lib/user-security.js.map +1 -1
- package/dist/esm/lib/user-sessions.js +1 -1
- package/dist/esm/lib/user-sessions.js.map +1 -1
- package/dist/esm/organization-switcher.client.js +3 -5
- package/dist/esm/organization-switcher.client.js.map +1 -1
- package/dist/esm/user-profile.client.js +3 -7
- package/dist/esm/user-profile.client.js.map +1 -1
- package/dist/esm/user-security.client.js +6 -5
- package/dist/esm/user-security.client.js.map +1 -1
- package/dist/esm/user-sessions.client.js +10 -14
- package/dist/esm/user-sessions.client.js.map +1 -1
- package/dist/esm/users-management.client.js +4 -10
- package/dist/esm/users-management.client.js.map +1 -1
- package/package.json +4 -1
- package/dist/cjs/card-list.cjs.map +0 -1
- package/dist/esm/card-list.js.map +0 -1
- /package/dist/cjs/{card-list.cjs → lib/card-list.cjs} +0 -0
- /package/dist/cjs/{card-list.d.cts → lib/card-list.d.cts} +0 -0
- /package/dist/esm/{card-list.d.ts → lib/card-list.d.ts} +0 -0
- /package/dist/esm/{card-list.js → lib/card-list.js} +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
3
|
import * as React from "react";
|
|
4
|
+
import { useIsHydrated } from "../lib/use-is-hydrated.js";
|
|
5
|
+
import { getClaims } from "./utils.js";
|
|
3
6
|
const ApiContext = React.createContext(void 0);
|
|
4
7
|
const ApiProvider = ({
|
|
5
8
|
authToken,
|
|
@@ -7,7 +10,20 @@ const ApiProvider = ({
|
|
|
7
10
|
children,
|
|
8
11
|
widgetType
|
|
9
12
|
}) => {
|
|
10
|
-
const
|
|
13
|
+
const authTokenQuery = useQuery({
|
|
14
|
+
initialData: typeof authToken === "string" ? {
|
|
15
|
+
authToken,
|
|
16
|
+
permissions: getClaims(authToken).permissions
|
|
17
|
+
} : void 0,
|
|
18
|
+
queryFn: async () => {
|
|
19
|
+
const resolvedToken = typeof authToken === "string" ? authToken : await authToken();
|
|
20
|
+
return {
|
|
21
|
+
authToken: resolvedToken,
|
|
22
|
+
permissions: getClaims(resolvedToken).permissions
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
queryKey: ["authToken"]
|
|
26
|
+
});
|
|
11
27
|
const [elevatedAccess, setElevatedAccess] = React.useState();
|
|
12
28
|
const elevatedAccessTimeout = React.useRef(void 0);
|
|
13
29
|
React.useEffect(() => {
|
|
@@ -31,15 +47,15 @@ const ApiProvider = ({
|
|
|
31
47
|
}, [elevatedAccess]);
|
|
32
48
|
const value = React.useMemo(
|
|
33
49
|
() => ({
|
|
34
|
-
authToken:
|
|
35
|
-
|
|
50
|
+
authToken: authTokenQuery.data?.authToken,
|
|
51
|
+
permissions: authTokenQuery.data?.permissions,
|
|
36
52
|
baseUrl,
|
|
37
53
|
elevatedAccess,
|
|
38
54
|
setElevatedAccess,
|
|
39
55
|
widgetType
|
|
40
56
|
}),
|
|
41
57
|
[
|
|
42
|
-
|
|
58
|
+
authTokenQuery.data,
|
|
43
59
|
baseUrl,
|
|
44
60
|
elevatedAccess,
|
|
45
61
|
setElevatedAccess,
|
|
@@ -59,24 +75,15 @@ const useElevatedAccessToken = () => {
|
|
|
59
75
|
const { elevatedAccess, setElevatedAccess } = useApi();
|
|
60
76
|
return { elevatedAccess, setElevatedAccess };
|
|
61
77
|
};
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const authTokenPromise = authTokenPromiseOrString;
|
|
68
|
-
const promiseKey = PromiseKey.get(authTokenPromise);
|
|
69
|
-
if (!promiseKey) {
|
|
70
|
-
const newPromiseKey = `${Math.random()}`;
|
|
71
|
-
PromiseKey.set(authTokenPromise, newPromiseKey);
|
|
72
|
-
return newPromiseKey;
|
|
73
|
-
} else {
|
|
74
|
-
return promiseKey;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
78
|
+
const useApiReady = () => {
|
|
79
|
+
const { authToken } = useApi();
|
|
80
|
+
const isHydrated = useIsHydrated();
|
|
81
|
+
return isHydrated && authToken !== void 0;
|
|
82
|
+
};
|
|
77
83
|
export {
|
|
78
84
|
ApiProvider,
|
|
79
85
|
useApi,
|
|
86
|
+
useApiReady,
|
|
80
87
|
useElevatedAccessToken
|
|
81
88
|
};
|
|
82
89
|
//# sourceMappingURL=api-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/api/api-provider.tsx"],"sourcesContent":["import * as React from \"react\";\n\nexport type WidgetType =\n | \"admin-portal-domain-verification\"\n | \"user-management\"\n | \"organization-switcher\"\n | \"user-sessions\"\n | \"user-security\"\n | \"user-profile\"\n | \"admin-portal-sso-connection\"\n | \"api-keys\";\n\nexport type AuthToken = string | (() => Promise<string>);\n\ninterface ElevatedAccess {\n token: string;\n expiresAt: string;\n}\n\ninterface ApiConfig {\n authToken:
|
|
1
|
+
{"version":3,"sources":["../../../src/api/api-provider.tsx"],"sourcesContent":["import { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\nimport { useIsHydrated } from \"../lib/use-is-hydrated.js\";\nimport { getClaims } from \"./utils.js\";\n\nexport type WidgetType =\n | \"admin-portal-domain-verification\"\n | \"user-management\"\n | \"organization-switcher\"\n | \"user-sessions\"\n | \"user-security\"\n | \"user-profile\"\n | \"admin-portal-sso-connection\"\n | \"api-keys\";\n\nexport type AuthToken = string | (() => Promise<string>);\n\ninterface ElevatedAccess {\n token: string;\n expiresAt: string;\n}\n\ninterface ApiConfig {\n authToken: string | undefined;\n permissions: string[] | undefined;\n baseUrl: string;\n widgetType: WidgetType;\n elevatedAccess?: ElevatedAccess;\n setElevatedAccess: (elevatedAccess?: ElevatedAccess) => void;\n}\n\nconst ApiContext = React.createContext<ApiConfig | undefined>(undefined);\n\ninterface ApiProviderProps {\n authToken: AuthToken;\n baseUrl: string;\n children: React.ReactNode;\n widgetType: WidgetType;\n}\n\nexport const ApiProvider = ({\n authToken,\n baseUrl,\n children,\n widgetType,\n}: ApiProviderProps) => {\n const authTokenQuery = useQuery({\n initialData:\n typeof authToken === \"string\"\n ? {\n authToken,\n permissions: getClaims(authToken).permissions,\n }\n : undefined,\n queryFn: async () => {\n const resolvedToken =\n typeof authToken === \"string\" ? authToken : await authToken();\n\n return {\n authToken: resolvedToken,\n permissions: getClaims(resolvedToken).permissions,\n };\n },\n queryKey: [\"authToken\"],\n });\n\n const [elevatedAccess, setElevatedAccess] = React.useState<ElevatedAccess>();\n const elevatedAccessTimeout = React.useRef<number | undefined>(undefined);\n\n // This effect manages the expiration of elevated access tokens\n // When an elevated access token is present, it checks every 30 seconds if the token has expired\n // If the token has expired (current time > expiration time), it clears the elevated access\n React.useEffect(() => {\n if (elevatedAccessTimeout.current) {\n window.clearInterval(elevatedAccessTimeout.current);\n }\n\n if (elevatedAccess) {\n elevatedAccessTimeout.current = window.setInterval(() => {\n const now = new Date();\n const expiresAtDate = new Date(elevatedAccess.expiresAt);\n\n // Reset the elevated access if it has expired\n if (now > expiresAtDate) {\n setElevatedAccess(undefined);\n }\n }, 30_000); // every 30 seconds\n }\n\n return () => {\n if (elevatedAccessTimeout.current) {\n window.clearInterval(elevatedAccessTimeout.current);\n }\n };\n }, [elevatedAccess]);\n\n const value = React.useMemo(\n () => ({\n authToken: authTokenQuery.data?.authToken,\n permissions: authTokenQuery.data?.permissions,\n baseUrl,\n elevatedAccess,\n setElevatedAccess,\n widgetType,\n }),\n [\n authTokenQuery.data,\n baseUrl,\n elevatedAccess,\n setElevatedAccess,\n widgetType,\n ],\n );\n\n return <ApiContext.Provider value={value}>{children}</ApiContext.Provider>;\n};\n\nexport const useApi = () => {\n const context = React.useContext(ApiContext);\n\n if (context === undefined) {\n throw new Error(\"useApi must be used within an ApiProvider\");\n }\n\n return context;\n};\n\nexport const useElevatedAccessToken = () => {\n const { elevatedAccess, setElevatedAccess } = useApi();\n\n return { elevatedAccess, setElevatedAccess };\n};\n\nexport const useApiReady = () => {\n const { authToken } = useApi();\n const isHydrated = useIsHydrated();\n\n return isHydrated && authToken !== undefined;\n};\n"],"mappings":"AAkHS;AAlHT,SAAS,gBAAgB;AACzB,YAAY,WAAW;AACvB,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AA4B1B,MAAM,aAAa,MAAM,cAAqC,MAAS;AAShE,MAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAwB;AACtB,QAAM,iBAAiB,SAAS;AAAA,IAC9B,aACE,OAAO,cAAc,WACjB;AAAA,MACE;AAAA,MACA,aAAa,UAAU,SAAS,EAAE;AAAA,IACpC,IACA;AAAA,IACN,SAAS,YAAY;AACnB,YAAM,gBACJ,OAAO,cAAc,WAAW,YAAY,MAAM,UAAU;AAE9D,aAAO;AAAA,QACL,WAAW;AAAA,QACX,aAAa,UAAU,aAAa,EAAE;AAAA,MACxC;AAAA,IACF;AAAA,IACA,UAAU,CAAC,WAAW;AAAA,EACxB,CAAC;AAED,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAyB;AAC3E,QAAM,wBAAwB,MAAM,OAA2B,MAAS;AAKxE,QAAM,UAAU,MAAM;AACpB,QAAI,sBAAsB,SAAS;AACjC,aAAO,cAAc,sBAAsB,OAAO;AAAA,IACpD;AAEA,QAAI,gBAAgB;AAClB,4BAAsB,UAAU,OAAO,YAAY,MAAM;AACvD,cAAM,MAAM,oBAAI,KAAK;AACrB,cAAM,gBAAgB,IAAI,KAAK,eAAe,SAAS;AAGvD,YAAI,MAAM,eAAe;AACvB,4BAAkB,MAAS;AAAA,QAC7B;AAAA,MACF,GAAG,GAAM;AAAA,IACX;AAEA,WAAO,MAAM;AACX,UAAI,sBAAsB,SAAS;AACjC,eAAO,cAAc,sBAAsB,OAAO;AAAA,MACpD;AAAA,IACF;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB,QAAM,QAAQ,MAAM;AAAA,IAClB,OAAO;AAAA,MACL,WAAW,eAAe,MAAM;AAAA,MAChC,aAAa,eAAe,MAAM;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,MACE,eAAe;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO,oBAAC,WAAW,UAAX,EAAoB,OAAe,UAAS;AACtD;AAEO,MAAM,SAAS,MAAM;AAC1B,QAAM,UAAU,MAAM,WAAW,UAAU;AAE3C,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,SAAO;AACT;AAEO,MAAM,yBAAyB,MAAM;AAC1C,QAAM,EAAE,gBAAgB,kBAAkB,IAAI,OAAO;AAErD,SAAO,EAAE,gBAAgB,kBAAkB;AAC7C;AAEO,MAAM,cAAc,MAAM;AAC/B,QAAM,EAAE,UAAU,IAAI,OAAO;AAC7B,QAAM,aAAa,cAAc;AAEjC,SAAO,cAAc,cAAc;AACrC;","names":[]}
|
package/dist/esm/api/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare function getAuthHeaders(authToken
|
|
1
|
+
declare function getAuthHeaders(authToken?: string): HeadersInit;
|
|
2
2
|
declare function isObjectLike(value: unknown): value is Record<string, unknown>;
|
|
3
3
|
declare function isErrorLike(value: unknown): value is Record<string, unknown> & {
|
|
4
4
|
message: string;
|
|
@@ -7,5 +7,10 @@ declare function parseErrorResponse(response: Response): Promise<{
|
|
|
7
7
|
message: string;
|
|
8
8
|
status: number;
|
|
9
9
|
}>;
|
|
10
|
+
type Claims = {
|
|
11
|
+
sid: string;
|
|
12
|
+
permissions?: string[];
|
|
13
|
+
};
|
|
14
|
+
declare function getClaims(accessToken: string): Claims;
|
|
10
15
|
|
|
11
|
-
export { getAuthHeaders, isErrorLike, isObjectLike, parseErrorResponse };
|
|
16
|
+
export { getAuthHeaders, getClaims, isErrorLike, isObjectLike, parseErrorResponse };
|
package/dist/esm/api/utils.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { WIDGETS_API_VERSION } from "./constants.js";
|
|
2
2
|
function getAuthHeaders(authToken) {
|
|
3
|
+
if (!authToken) {
|
|
4
|
+
return {
|
|
5
|
+
"WorkOS-Widgets-Version": WIDGETS_API_VERSION
|
|
6
|
+
};
|
|
7
|
+
}
|
|
3
8
|
return {
|
|
4
9
|
Authorization: `Bearer ${authToken}`,
|
|
5
10
|
"WorkOS-Widgets-Version": WIDGETS_API_VERSION
|
|
@@ -32,8 +37,12 @@ async function parseErrorResponse(response) {
|
|
|
32
37
|
};
|
|
33
38
|
}
|
|
34
39
|
}
|
|
40
|
+
function getClaims(accessToken) {
|
|
41
|
+
return JSON.parse(atob(accessToken.split(".")[1]));
|
|
42
|
+
}
|
|
35
43
|
export {
|
|
36
44
|
getAuthHeaders,
|
|
45
|
+
getClaims,
|
|
37
46
|
isErrorLike,
|
|
38
47
|
isObjectLike,
|
|
39
48
|
parseErrorResponse
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/api/utils.ts"],"sourcesContent":["import { WIDGETS_API_VERSION } from \"./constants.js\";\n\nexport function getAuthHeaders(authToken
|
|
1
|
+
{"version":3,"sources":["../../../src/api/utils.ts"],"sourcesContent":["import { WIDGETS_API_VERSION } from \"./constants.js\";\n\nexport function getAuthHeaders(authToken?: string): HeadersInit {\n if (!authToken) {\n return {\n \"WorkOS-Widgets-Version\": WIDGETS_API_VERSION,\n };\n }\n\n return {\n Authorization: `Bearer ${authToken}`,\n \"WorkOS-Widgets-Version\": WIDGETS_API_VERSION,\n };\n}\n\nexport function isObjectLike(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function isErrorLike(\n value: unknown,\n): value is Record<string, unknown> & { message: string } {\n return isObjectLike(value) && typeof value.message === \"string\";\n}\n\nexport async function parseErrorResponse(\n response: Response,\n): Promise<{ message: string; status: number }> {\n try {\n const json = await response.json();\n if (!isObjectLike(json) || typeof json.message !== \"string\") {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n return {\n ...json,\n status: response.status,\n message: json.message || response.statusText,\n };\n } catch {\n return {\n status: response.status,\n message: response.statusText,\n };\n }\n}\n\ntype Claims = {\n sid: string;\n permissions?: string[];\n};\n\nexport function getClaims(accessToken: string): Claims {\n return JSON.parse(atob(accessToken.split(\".\")[1]));\n}\n"],"mappings":"AAAA,SAAS,2BAA2B;AAE7B,SAAS,eAAe,WAAiC;AAC9D,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,0BAA0B;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe,UAAU,SAAS;AAAA,IAClC,0BAA0B;AAAA,EAC5B;AACF;AAEO,SAAS,aAAa,OAAkD;AAC7E,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEO,SAAS,YACd,OACwD;AACxD,SAAO,aAAa,KAAK,KAAK,OAAO,MAAM,YAAY;AACzD;AAEA,eAAsB,mBACpB,UAC8C;AAC9C,MAAI;AACF,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI,CAAC,aAAa,IAAI,KAAK,OAAO,KAAK,YAAY,UAAU;AAC3D,aAAO;AAAA,QACL,QAAQ,SAAS;AAAA,QACjB,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AACA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,SAAS;AAAA,MACjB,SAAS,KAAK,WAAW,SAAS;AAAA,IACpC;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS;AAAA,IACpB;AAAA,EACF;AACF;AAOO,SAAS,UAAU,aAA6B;AACrD,SAAO,KAAK,MAAM,KAAK,YAAY,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AACnD;","names":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useApi } from "./api-provider.js";
|
|
2
2
|
import { ApiError, FetchError } from "./errors.js";
|
|
3
3
|
import { getAuthHeaders, parseErrorResponse } from "./utils.js";
|
|
4
|
+
import { IncorrectPermissionsError } from "../lib/errors.js";
|
|
4
5
|
const useWidgetsApiClient = () => {
|
|
5
6
|
const { authToken, baseUrl, elevatedAccess, widgetType } = useApi();
|
|
6
7
|
return async ({ url: pathname, method, params, data }) => {
|
|
@@ -14,7 +15,7 @@ const useWidgetsApiClient = () => {
|
|
|
14
15
|
}
|
|
15
16
|
const queryType = method.toLowerCase() === "get" ? "query" : "mutation";
|
|
16
17
|
const headers = {
|
|
17
|
-
...getAuthHeaders(
|
|
18
|
+
...getAuthHeaders(authToken),
|
|
18
19
|
...elevatedAccess && queryType === "mutation" ? { "x-elevated-access-token": elevatedAccess.token } : {},
|
|
19
20
|
"WorkOS-Widgets-Type": widgetType,
|
|
20
21
|
"Content-Type": "application/json"
|
|
@@ -33,21 +34,26 @@ const useWidgetsApiClient = () => {
|
|
|
33
34
|
});
|
|
34
35
|
if (!response.ok) {
|
|
35
36
|
const { message, status } = await parseErrorResponse(response);
|
|
36
|
-
|
|
37
|
+
const ctx = {
|
|
37
38
|
message,
|
|
38
39
|
status,
|
|
39
40
|
queryType: method.toLowerCase() === "get" ? "query" : "mutation"
|
|
40
|
-
}
|
|
41
|
+
};
|
|
42
|
+
if (status === 403) {
|
|
43
|
+
throw new IncorrectPermissionsError({ context: ctx });
|
|
44
|
+
}
|
|
45
|
+
throw new ApiError(ctx);
|
|
41
46
|
}
|
|
42
47
|
return response.json();
|
|
43
48
|
};
|
|
44
49
|
};
|
|
45
50
|
const useWidgetsApiQueryOptions = (queryOptions) => {
|
|
46
|
-
const {
|
|
51
|
+
const { permissions, baseUrl } = useApi();
|
|
47
52
|
const queryKey = [
|
|
48
53
|
// initial query key needs to go first to allow invalidation of the query name to work
|
|
49
54
|
...queryOptions.queryKey,
|
|
50
|
-
|
|
55
|
+
permissions,
|
|
56
|
+
baseUrl
|
|
51
57
|
];
|
|
52
58
|
return {
|
|
53
59
|
...queryOptions,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/api/widgets-api-client.ts"],"sourcesContent":["import { QueryKey } from \"@tanstack/react-query\";\nimport { useApi } from \"./api-provider.js\";\nimport { ApiError, FetchError } from \"./errors.js\";\nimport { getAuthHeaders, parseErrorResponse } from \"./utils.js\";\n\ntype WidgetsApiClient<T> = (data: {\n url: string;\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n params?: Record<string, any>;\n headers?: Record<string, any>;\n data?: BodyType<unknown>;\n signal?: AbortSignal;\n}) => Promise<T>;\n\nexport const useWidgetsApiClient = <T>(): WidgetsApiClient<T> => {\n const { authToken, baseUrl, elevatedAccess, widgetType } = useApi();\n\n return async ({ url: pathname, method, params, data }) => {\n const url = new URL(baseUrl);\n url.pathname = pathname;\n\n if (params) {\n const cleanParams = Object.fromEntries(\n Object.entries(params).filter(([_, value]) => value !== undefined),\n );\n url.search = new URLSearchParams(cleanParams).toString();\n }\n\n const queryType = method.toLowerCase() === \"get\" ? \"query\" : \"mutation\";\n const headers = {\n ...getAuthHeaders(
|
|
1
|
+
{"version":3,"sources":["../../../src/api/widgets-api-client.ts"],"sourcesContent":["import { QueryKey } from \"@tanstack/react-query\";\nimport { useApi } from \"./api-provider.js\";\nimport { ApiError, FetchError } from \"./errors.js\";\nimport { getAuthHeaders, parseErrorResponse } from \"./utils.js\";\nimport { IncorrectPermissionsError } from \"../lib/errors.js\";\n\ntype WidgetsApiClient<T> = (data: {\n url: string;\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n params?: Record<string, any>;\n headers?: Record<string, any>;\n data?: BodyType<unknown>;\n signal?: AbortSignal;\n}) => Promise<T>;\n\nexport const useWidgetsApiClient = <T>(): WidgetsApiClient<T> => {\n const { authToken, baseUrl, elevatedAccess, widgetType } = useApi();\n\n return async ({ url: pathname, method, params, data }) => {\n const url = new URL(baseUrl);\n url.pathname = pathname;\n\n if (params) {\n const cleanParams = Object.fromEntries(\n Object.entries(params).filter(([_, value]) => value !== undefined),\n );\n url.search = new URLSearchParams(cleanParams).toString();\n }\n\n const queryType = method.toLowerCase() === \"get\" ? \"query\" : \"mutation\";\n const headers = {\n ...getAuthHeaders(authToken),\n ...(elevatedAccess && queryType === \"mutation\"\n ? { \"x-elevated-access-token\": elevatedAccess.token }\n : {}),\n \"WorkOS-Widgets-Type\": widgetType,\n \"Content-Type\": \"application/json\",\n };\n\n const response = await fetch(url, {\n method,\n cache: \"no-store\",\n headers,\n ...(data ? { body: JSON.stringify(data) } : {}),\n }).catch((error) => {\n throw new FetchError({\n message: `Failed to ${method} ${url.toString()}`,\n queryType,\n context: { error },\n });\n });\n\n if (!response.ok) {\n const { message, status } = await parseErrorResponse(response);\n const ctx = {\n message,\n status,\n queryType: method.toLowerCase() === \"get\" ? \"query\" : \"mutation\",\n } as const;\n\n if (status === 403) {\n throw new IncorrectPermissionsError({ context: ctx });\n }\n\n throw new ApiError(ctx);\n }\n\n return response.json();\n };\n};\n\nexport type ErrorType<ErrorData> = ErrorData;\n\nexport type BodyType<BodyData> = BodyData & { headers?: any };\n\nexport const useWidgetsApiQueryOptions = <\n QueryOptions extends { queryKey: QK },\n QK extends QueryKey,\n>(\n queryOptions: QueryOptions,\n) => {\n const { permissions, baseUrl } = useApi();\n const queryKey = [\n // initial query key needs to go first to allow invalidation of the query name to work\n ...queryOptions.queryKey,\n permissions,\n baseUrl,\n ] as unknown as QK;\n\n return {\n ...queryOptions,\n queryKey: queryKey as QK,\n };\n};\n"],"mappings":"AACA,SAAS,cAAc;AACvB,SAAS,UAAU,kBAAkB;AACrC,SAAS,gBAAgB,0BAA0B;AACnD,SAAS,iCAAiC;AAWnC,MAAM,sBAAsB,MAA8B;AAC/D,QAAM,EAAE,WAAW,SAAS,gBAAgB,WAAW,IAAI,OAAO;AAElE,SAAO,OAAO,EAAE,KAAK,UAAU,QAAQ,QAAQ,KAAK,MAAM;AACxD,UAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAI,WAAW;AAEf,QAAI,QAAQ;AACV,YAAM,cAAc,OAAO;AAAA,QACzB,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,MAAM,UAAU,MAAS;AAAA,MACnE;AACA,UAAI,SAAS,IAAI,gBAAgB,WAAW,EAAE,SAAS;AAAA,IACzD;AAEA,UAAM,YAAY,OAAO,YAAY,MAAM,QAAQ,UAAU;AAC7D,UAAM,UAAU;AAAA,MACd,GAAG,eAAe,SAAS;AAAA,MAC3B,GAAI,kBAAkB,cAAc,aAChC,EAAE,2BAA2B,eAAe,MAAM,IAClD,CAAC;AAAA,MACL,uBAAuB;AAAA,MACvB,gBAAgB;AAAA,IAClB;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,GAAI,OAAO,EAAE,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,CAAC;AAAA,IAC/C,CAAC,EAAE,MAAM,CAAC,UAAU;AAClB,YAAM,IAAI,WAAW;AAAA,QACnB,SAAS,aAAa,MAAM,IAAI,IAAI,SAAS,CAAC;AAAA,QAC9C;AAAA,QACA,SAAS,EAAE,MAAM;AAAA,MACnB,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,EAAE,SAAS,OAAO,IAAI,MAAM,mBAAmB,QAAQ;AAC7D,YAAM,MAAM;AAAA,QACV;AAAA,QACA;AAAA,QACA,WAAW,OAAO,YAAY,MAAM,QAAQ,UAAU;AAAA,MACxD;AAEA,UAAI,WAAW,KAAK;AAClB,cAAM,IAAI,0BAA0B,EAAE,SAAS,IAAI,CAAC;AAAA,MACtD;AAEA,YAAM,IAAI,SAAS,GAAG;AAAA,IACxB;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;AAMO,MAAM,4BAA4B,CAIvC,iBACG;AACH,QAAM,EAAE,aAAa,QAAQ,IAAI,OAAO;AACxC,QAAM,WAAW;AAAA;AAAA,IAEf,GAAG,aAAa;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { ApiProvider,
|
|
3
|
+
import { ApiProvider, useApiReady } from "./api/api-provider.js";
|
|
4
4
|
import { ApiKeysTable } from "./lib/api-keys/api-keys-table.js";
|
|
5
5
|
import { useWorkOsApiUrl } from "./lib/widgets-context.js";
|
|
6
|
-
import { useIsHydrated } from "./lib/use-is-hydrated.js";
|
|
7
6
|
import {
|
|
8
7
|
ApiKeysEmptyState,
|
|
9
8
|
ApiKeysLoading,
|
|
@@ -36,16 +35,12 @@ const ApiKeys = ({ authToken }) => {
|
|
|
36
35
|
) });
|
|
37
36
|
};
|
|
38
37
|
const ApiKeysContent = () => {
|
|
39
|
-
const
|
|
38
|
+
const isApiReady = useApiReady();
|
|
40
39
|
const apiKeys = useApiKeys();
|
|
41
|
-
const context = useApi();
|
|
42
40
|
const { state } = useApiKeysContext();
|
|
43
41
|
useListOrganizationApiKeyPermissions({ limit: 100 });
|
|
44
|
-
const permissionsQuery = usePermissions(
|
|
45
|
-
|
|
46
|
-
context.authToken
|
|
47
|
-
);
|
|
48
|
-
if (!isHydrated || apiKeys.isLoading || permissionsQuery.isLoading) {
|
|
42
|
+
const permissionsQuery = usePermissions("widgets:api-keys:manage");
|
|
43
|
+
if (!isApiReady || apiKeys.isLoading || permissionsQuery.isLoading) {
|
|
49
44
|
return /* @__PURE__ */ jsx(ApiKeysLoading, {});
|
|
50
45
|
}
|
|
51
46
|
if (permissionsQuery.isError || apiKeys.isError) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/api-keys-client.tsx"],"sourcesContent":["\"use client\";\nimport { ApiProvider, AuthToken,
|
|
1
|
+
{"version":3,"sources":["../../src/api-keys-client.tsx"],"sourcesContent":["\"use client\";\nimport { ApiProvider, AuthToken, useApiReady } from \"./api/api-provider.js\";\nimport { ApiKeysTable } from \"./lib/api-keys/api-keys-table.js\";\nimport { useWorkOsApiUrl } from \"./lib/widgets-context.js\";\nimport {\n ApiKeysEmptyState,\n ApiKeysLoading,\n ApiKeysRoot,\n} from \"./lib/api-keys/api-keys.js\";\nimport { useListOrganizationApiKeyPermissions } from \"./api/endpoint.js\";\nimport * as React from \"react\";\nimport { GenericError } from \"./lib/generic-error.js\";\nimport { ErrorBoundary } from \"./lib/error-boundary.js\";\nimport { usePermissions } from \"./lib/use-permissions.js\";\nimport {\n ApiKeysContextProvider,\n useApiKeysContext,\n} from \"./lib/api-keys/api-keys-context.js\";\nimport { useApiKeys } from \"./lib/api/api-key.js\";\nimport { ApiKeysSearchProvider } from \"./lib/api-keys/api-keys-search-provider.js\";\nimport { CreateApiKeyDialog } from \"./lib/api-keys/create-api-key.js\";\n\nexport interface ApiKeysProps {\n authToken: AuthToken;\n}\n\nexport const ApiKeys: React.FC<ApiKeysProps> = ({ authToken }) => {\n const baseUrl = useWorkOsApiUrl();\n\n return (\n <ErrorBoundary FallbackComponent={GenericError}>\n <ApiProvider\n widgetType=\"api-keys\"\n authToken={authToken}\n baseUrl={baseUrl}\n >\n <ApiKeysContextProvider>\n <CreateApiKeyDialog />\n <ApiKeysRoot>\n <ApiKeysContent />\n </ApiKeysRoot>\n </ApiKeysContextProvider>\n </ApiProvider>\n </ErrorBoundary>\n );\n};\n\nconst ApiKeysContent = () => {\n const isApiReady = useApiReady();\n const apiKeys = useApiKeys();\n const { state } = useApiKeysContext();\n useListOrganizationApiKeyPermissions({ limit: 100 });\n const permissionsQuery = usePermissions(\"widgets:api-keys:manage\");\n\n if (!isApiReady || apiKeys.isLoading || permissionsQuery.isLoading) {\n return <ApiKeysLoading />;\n }\n\n if (permissionsQuery.isError || apiKeys.isError) {\n return <GenericError error={permissionsQuery.error || apiKeys.error} />;\n }\n\n if (apiKeys.isSuccess) {\n if (apiKeys.data.data.length === 0 && !state.searchQuery) {\n return <ApiKeysEmptyState />;\n }\n\n return (\n <ApiKeysSearchProvider>\n <ApiKeysTable apiKeys={apiKeys.data} />\n </ApiKeysSearchProvider>\n );\n }\n\n return <GenericError error={apiKeys.error} />;\n};\n"],"mappings":";AAoCQ,SACE,KADF;AAnCR,SAAS,aAAwB,mBAAmB;AACpD,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,4CAA4C;AAErD,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,6BAA6B;AACtC,SAAS,0BAA0B;AAM5B,MAAM,UAAkC,CAAC,EAAE,UAAU,MAAM;AAChE,QAAM,UAAU,gBAAgB;AAEhC,SACE,oBAAC,iBAAc,mBAAmB,cAChC;AAAA,IAAC;AAAA;AAAA,MACC,YAAW;AAAA,MACX;AAAA,MACA;AAAA,MAEA,+BAAC,0BACC;AAAA,4BAAC,sBAAmB;AAAA,QACpB,oBAAC,eACC,8BAAC,kBAAe,GAClB;AAAA,SACF;AAAA;AAAA,EACF,GACF;AAEJ;AAEA,MAAM,iBAAiB,MAAM;AAC3B,QAAM,aAAa,YAAY;AAC/B,QAAM,UAAU,WAAW;AAC3B,QAAM,EAAE,MAAM,IAAI,kBAAkB;AACpC,uCAAqC,EAAE,OAAO,IAAI,CAAC;AACnD,QAAM,mBAAmB,eAAe,yBAAyB;AAEjE,MAAI,CAAC,cAAc,QAAQ,aAAa,iBAAiB,WAAW;AAClE,WAAO,oBAAC,kBAAe;AAAA,EACzB;AAEA,MAAI,iBAAiB,WAAW,QAAQ,SAAS;AAC/C,WAAO,oBAAC,gBAAa,OAAO,iBAAiB,SAAS,QAAQ,OAAO;AAAA,EACvE;AAEA,MAAI,QAAQ,WAAW;AACrB,QAAI,QAAQ,KAAK,KAAK,WAAW,KAAK,CAAC,MAAM,aAAa;AACxD,aAAO,oBAAC,qBAAkB;AAAA,IAC5B;AAEA,WACE,oBAAC,yBACC,8BAAC,gBAAa,SAAS,QAAQ,MAAM,GACvC;AAAA,EAEJ;AAEA,SAAO,oBAAC,gBAAa,OAAO,QAAQ,OAAO;AAC7C;","names":[]}
|
|
@@ -273,7 +273,7 @@ function SecretDialog({ children, setupKey }) {
|
|
|
273
273
|
return /* @__PURE__ */ jsxs(Dialog.Root, { children: [
|
|
274
274
|
/* @__PURE__ */ jsx(Dialog.Trigger, { children }),
|
|
275
275
|
/* @__PURE__ */ jsxs(
|
|
276
|
-
|
|
276
|
+
DialogContent,
|
|
277
277
|
{
|
|
278
278
|
maxWidth: "90vw",
|
|
279
279
|
size: { initial: "3", sm: "4" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/add-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Box,\n Code,\n Dialog,\n Flex,\n Grid,\n Link,\n Separator,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport * as Otp from \"./otp-input.js\";\nimport { DialogContent, PrimaryButton, SecondaryButton } from \"./elements.js\";\nimport {\n CreateTotpFactorResponse,\n CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf,\n useCreateTotpFactor,\n useVerifyTotpFactor,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { Marker } from \"./marker.js\";\nimport { CopyButton } from \"./copy-button.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface AddMfaDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n onSuccess?: () => void;\n}\n\nexport function AddMfaDialog({\n children,\n onSuccess,\n ...props\n}: AddMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n const [manuallyTriggered, setManuallyTriggered] = React.useState(false);\n const { elevatedAccess } = useElevatedAccessToken();\n const createAuthFactor = useCreateTotpFactor();\n\n const handleVerified = async () => {\n await createAuthFactor.mutateAsync(undefined);\n };\n\n const onTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (elevatedAccess && !createAuthFactor.data) {\n event.preventDefault();\n setManuallyTriggered(true);\n createAuthFactor.mutate(undefined, {\n onSuccess: () => {\n setOpen(true);\n },\n });\n } else {\n setManuallyTriggered(false);\n }\n };\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root\n {...props}\n open={props.open || open}\n onOpenChange={props.onOpenChange || setOpen}\n >\n <Dialog.Trigger\n onClick={onTriggerClick}\n // @ts-ignore I've to find a way to pass the loading state to the trigger\n loading={manuallyTriggered && createAuthFactor.isPending}\n >\n {children}\n </Dialog.Trigger>\n\n <DialogContent maxWidth=\"480px\">\n <ElevatedAccess onVerified={handleVerified}>\n <Content onClose={handleClose} totpFactor={createAuthFactor.data} />\n </ElevatedAccess>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n totpFactor?: CreateTotpFactorResponse;\n onClose?: () => void;\n}\n\nfunction Content({ onClose, totpFactor }: ContentProps) {\n const securitySettings = useSecuritySettings();\n\n const [customError, setCustomError] = React.useState<string | null>(null);\n const totp = hasQrCode(totpFactor)\n ? totpFactor.authenticationFactor.totp\n : undefined;\n\n const verifyTotp = useVerifyTotpFactor({\n mutation: {\n onSuccess: ({ success }) => {\n if (!success) {\n setCustomError(\"Invalid passcode\");\n }\n },\n },\n });\n\n const serverError = verifyTotp.error || customError;\n const isSuccess = verifyTotp.isSuccess && !serverError;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setCustomError(null);\n\n const formData = new FormData(event.currentTarget);\n const otpCode = formData.get(\"otp-code\")?.toString();\n\n verifyTotp.mutate({\n data: {\n authenticationChallengeId: totpFactor?.authenticationChallenge.id ?? \"\",\n code: otpCode ?? \"\",\n },\n });\n };\n\n useDialogClose(isSuccess, () => {\n securitySettings.update(\"Mfa\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">Set up an authenticator app</Dialog.Title>\n\n <Form.Root onSubmit={handleSubmit}>\n <Grid columns=\"auto 1fr\" rows=\"repeat(4, auto)\" gapX=\"3\" gapY=\"1\">\n <Grid\n rows=\"subgrid\"\n gridRow=\"span 4\"\n style={{ placeItems: \"center\" }}\n >\n <Marker>1</Marker>\n <Separator\n orientation=\"vertical\"\n size=\"4\"\n style={{ width: \"2px\" }}\n />\n <Marker>2</Marker>\n <div />\n </Grid>\n\n <Grid rows=\"subgrid\" gridRow=\"span 4\">\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Scan the QR code\n </Text>\n <Flex direction=\"column\" gap=\"1\">\n <Text as=\"p\" size=\"2\">\n Use an authenticator app like{\" \"}\n <Link\n href=\"https://1password.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n 1Password\n </Link>\n ,{\" \"}\n <Link\n href=\"https://apps.apple.com/us/app/google-authenticator/id388497605\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Google Authenticator\n </Link>\n ,{\" \"}\n <Link\n href=\"https://authy.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Authy\n </Link>\n , or{\" \"}\n <Link\n href=\"https://www.microsoft.com/en-gb/security/mobile-authenticator-app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Microsoft Authenticator\n </Link>{\" \"}\n to scan the QR code below.\n </Text>\n <Flex align=\"center\" gap=\"5\" my=\"5\">\n <Grid\n position=\"relative\"\n width=\"160px\"\n height=\"160px\"\n p=\"2\"\n style={{\n border: \"1px solid var(--gray-7)\",\n borderRadius: \"var(--radius-4)\",\n background: \"var(--gray-2)\",\n overflow: \"hidden\",\n }}\n >\n {totp?.qr_code && (\n <Box asChild width=\"100%\" height=\"auto\">\n <img\n alt=\"Scan this QR code to enroll\"\n aria-describedby=\"secret-note\"\n height=\"160\"\n src={totp.qr_code}\n style={{ userSelect: \"none\", background: \"white\" }}\n width=\"160\"\n />\n </Box>\n )}\n </Grid>\n\n <Flex direction=\"column\" gap=\"1\" align=\"start\">\n <Text color=\"gray\" id=\"secret-note\" size=\"2\">\n Can‘t scan the code?{\" \"}\n </Text>\n\n <SecretDialog setupKey={totp?.secret ?? \"\"}>\n <SecondaryButton\n size=\"1\"\n disabled={verifyTotp.isPending || isSuccess}\n >\n View setup key\n </SecondaryButton>\n </SecretDialog>\n </Flex>\n </Flex>\n </Flex>\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Get verification passcode\n </Text>\n <Flex direction=\"column\" gap=\"4\">\n <Text as=\"p\" size=\"2\">\n Enter the 6-digit passcode from your authenticator app.\n </Text>\n\n <Flex direction=\"column\" gap=\"2\">\n <Otp.Root\n autoSubmit\n gap=\"3\"\n justify=\"start\"\n name=\"otp-code\"\n rows=\"48px\"\n columns=\"repeat(6, 48px)\"\n readOnly={verifyTotp.isPending || isSuccess}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {serverError && (\n <Text size=\"2\" color=\"red\">\n {getMutationErrorMessage(serverError)}\n </Text>\n )}\n </Flex>\n </Flex>\n </Grid>\n </Grid>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <SecondaryButton disabled={verifyTotp.isPending || isSuccess}>\n Cancel\n </SecondaryButton>\n </Dialog.Close>\n\n <SaveButton\n asChild\n loading={verifyTotp.isPending}\n done={isSuccess}\n onDone={onClose}\n >\n <PrimaryButton type=\"submit\">Confirm</PrimaryButton>\n </SaveButton>\n </Flex>\n </Form.Root>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(serverError)}\n </section>\n </VisuallyHidden>\n </>\n );\n}\n\ninterface SecretDialogProps extends React.PropsWithChildren {\n setupKey: string;\n}\n\nfunction SecretDialog({ children, setupKey }: SecretDialogProps) {\n return (\n <Dialog.Root>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n <Dialog.Content\n maxWidth=\"90vw\"\n size={{ initial: \"3\", sm: \"4\" }}\n minWidth=\"300px\"\n width=\"fit-content\"\n >\n <Dialog.Title size=\"2\" weight=\"regular\">\n Your setup key\n </Dialog.Title>\n <Dialog.Description>\n <Text size=\"6\">\n <Code variant=\"ghost\" style={{ letterSpacing: \"0.15rem\" }}>\n {setupKey}\n </Code>\n </Text>\n </Dialog.Description>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton asChild value={setupKey}>\n <PrimaryButton>Copy and close</PrimaryButton>\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = \"Something went wrong, please try again\";\n\n if (typeof error === \"string\") {\n message = error;\n }\n\n if (error instanceof Error) {\n message = error.message;\n }\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n message = error.message;\n }\n\n if (message === \"Invalid passcode\") {\n message = \"Invalid passcode, please try again\";\n }\n\n return message;\n}\n\nfunction hasQrCode(\n response?: CreateTotpFactorResponse,\n): response is CreateTotpFactorResponse & {\n authenticationFactor: {\n totp: NonNullable<CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf>;\n };\n} {\n const totp = response?.authenticationFactor.totp;\n return totp != null && \"qr_code\" in totp;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/add-mfa-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Box,\n Code,\n Dialog,\n Flex,\n Grid,\n Link,\n Separator,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { type ReactNode } from \"react\";\nimport * as Otp from \"./otp-input.js\";\nimport { DialogContent, PrimaryButton, SecondaryButton } from \"./elements.js\";\nimport {\n CreateTotpFactorResponse,\n CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf,\n useCreateTotpFactor,\n useVerifyTotpFactor,\n} from \"../api/endpoint.js\";\nimport { useElevatedAccessToken } from \"../api/api-provider.js\";\nimport * as Form from \"@radix-ui/react-form\";\nimport { Marker } from \"./marker.js\";\nimport { CopyButton } from \"./copy-button.js\";\nimport { useSecuritySettings } from \"./use-security-settings.js\";\nimport { ElevatedAccess } from \"./elevated-access.js\";\nimport { SaveButton } from \"./save-button.js\";\nimport { useDialogClose } from \"./use-dialog-close.js\";\n\ninterface AddMfaDialogProps extends Dialog.RootProps {\n children?: ReactNode;\n onSuccess?: () => void;\n}\n\nexport function AddMfaDialog({\n children,\n onSuccess,\n ...props\n}: AddMfaDialogProps) {\n const [open, setOpen] = React.useState(false);\n const [manuallyTriggered, setManuallyTriggered] = React.useState(false);\n const { elevatedAccess } = useElevatedAccessToken();\n const createAuthFactor = useCreateTotpFactor();\n\n const handleVerified = async () => {\n await createAuthFactor.mutateAsync(undefined);\n };\n\n const onTriggerClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (elevatedAccess && !createAuthFactor.data) {\n event.preventDefault();\n setManuallyTriggered(true);\n createAuthFactor.mutate(undefined, {\n onSuccess: () => {\n setOpen(true);\n },\n });\n } else {\n setManuallyTriggered(false);\n }\n };\n\n const handleClose = React.useCallback(() => {\n setOpen(false);\n }, []);\n\n return (\n <Dialog.Root\n {...props}\n open={props.open || open}\n onOpenChange={props.onOpenChange || setOpen}\n >\n <Dialog.Trigger\n onClick={onTriggerClick}\n // @ts-ignore I've to find a way to pass the loading state to the trigger\n loading={manuallyTriggered && createAuthFactor.isPending}\n >\n {children}\n </Dialog.Trigger>\n\n <DialogContent maxWidth=\"480px\">\n <ElevatedAccess onVerified={handleVerified}>\n <Content onClose={handleClose} totpFactor={createAuthFactor.data} />\n </ElevatedAccess>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\ninterface ContentProps {\n totpFactor?: CreateTotpFactorResponse;\n onClose?: () => void;\n}\n\nfunction Content({ onClose, totpFactor }: ContentProps) {\n const securitySettings = useSecuritySettings();\n\n const [customError, setCustomError] = React.useState<string | null>(null);\n const totp = hasQrCode(totpFactor)\n ? totpFactor.authenticationFactor.totp\n : undefined;\n\n const verifyTotp = useVerifyTotpFactor({\n mutation: {\n onSuccess: ({ success }) => {\n if (!success) {\n setCustomError(\"Invalid passcode\");\n }\n },\n },\n });\n\n const serverError = verifyTotp.error || customError;\n const isSuccess = verifyTotp.isSuccess && !serverError;\n\n const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setCustomError(null);\n\n const formData = new FormData(event.currentTarget);\n const otpCode = formData.get(\"otp-code\")?.toString();\n\n verifyTotp.mutate({\n data: {\n authenticationChallengeId: totpFactor?.authenticationChallenge.id ?? \"\",\n code: otpCode ?? \"\",\n },\n });\n };\n\n useDialogClose(isSuccess, () => {\n securitySettings.update(\"Mfa\", true);\n });\n\n return (\n <>\n <Dialog.Title mb=\"5\">Set up an authenticator app</Dialog.Title>\n\n <Form.Root onSubmit={handleSubmit}>\n <Grid columns=\"auto 1fr\" rows=\"repeat(4, auto)\" gapX=\"3\" gapY=\"1\">\n <Grid\n rows=\"subgrid\"\n gridRow=\"span 4\"\n style={{ placeItems: \"center\" }}\n >\n <Marker>1</Marker>\n <Separator\n orientation=\"vertical\"\n size=\"4\"\n style={{ width: \"2px\" }}\n />\n <Marker>2</Marker>\n <div />\n </Grid>\n\n <Grid rows=\"subgrid\" gridRow=\"span 4\">\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Scan the QR code\n </Text>\n <Flex direction=\"column\" gap=\"1\">\n <Text as=\"p\" size=\"2\">\n Use an authenticator app like{\" \"}\n <Link\n href=\"https://1password.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n 1Password\n </Link>\n ,{\" \"}\n <Link\n href=\"https://apps.apple.com/us/app/google-authenticator/id388497605\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Google Authenticator\n </Link>\n ,{\" \"}\n <Link\n href=\"https://authy.com/\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Authy\n </Link>\n , or{\" \"}\n <Link\n href=\"https://www.microsoft.com/en-gb/security/mobile-authenticator-app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Microsoft Authenticator\n </Link>{\" \"}\n to scan the QR code below.\n </Text>\n <Flex align=\"center\" gap=\"5\" my=\"5\">\n <Grid\n position=\"relative\"\n width=\"160px\"\n height=\"160px\"\n p=\"2\"\n style={{\n border: \"1px solid var(--gray-7)\",\n borderRadius: \"var(--radius-4)\",\n background: \"var(--gray-2)\",\n overflow: \"hidden\",\n }}\n >\n {totp?.qr_code && (\n <Box asChild width=\"100%\" height=\"auto\">\n <img\n alt=\"Scan this QR code to enroll\"\n aria-describedby=\"secret-note\"\n height=\"160\"\n src={totp.qr_code}\n style={{ userSelect: \"none\", background: \"white\" }}\n width=\"160\"\n />\n </Box>\n )}\n </Grid>\n\n <Flex direction=\"column\" gap=\"1\" align=\"start\">\n <Text color=\"gray\" id=\"secret-note\" size=\"2\">\n Can‘t scan the code?{\" \"}\n </Text>\n\n <SecretDialog setupKey={totp?.secret ?? \"\"}>\n <SecondaryButton\n size=\"1\"\n disabled={verifyTotp.isPending || isSuccess}\n >\n View setup key\n </SecondaryButton>\n </SecretDialog>\n </Flex>\n </Flex>\n </Flex>\n <Text as=\"p\" size=\"3\" weight=\"bold\">\n Get verification passcode\n </Text>\n <Flex direction=\"column\" gap=\"4\">\n <Text as=\"p\" size=\"2\">\n Enter the 6-digit passcode from your authenticator app.\n </Text>\n\n <Flex direction=\"column\" gap=\"2\">\n <Otp.Root\n autoSubmit\n gap=\"3\"\n justify=\"start\"\n name=\"otp-code\"\n rows=\"48px\"\n columns=\"repeat(6, 48px)\"\n readOnly={verifyTotp.isPending || isSuccess}\n >\n <Otp.Input required autoFocus autoComplete=\"off\" />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n <Otp.Input required />\n </Otp.Root>\n\n {serverError && (\n <Text size=\"2\" color=\"red\">\n {getMutationErrorMessage(serverError)}\n </Text>\n )}\n </Flex>\n </Flex>\n </Grid>\n </Grid>\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <SecondaryButton disabled={verifyTotp.isPending || isSuccess}>\n Cancel\n </SecondaryButton>\n </Dialog.Close>\n\n <SaveButton\n asChild\n loading={verifyTotp.isPending}\n done={isSuccess}\n onDone={onClose}\n >\n <PrimaryButton type=\"submit\">Confirm</PrimaryButton>\n </SaveButton>\n </Flex>\n </Form.Root>\n\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">\n {getMutationErrorMessage(serverError)}\n </section>\n </VisuallyHidden>\n </>\n );\n}\n\ninterface SecretDialogProps extends React.PropsWithChildren {\n setupKey: string;\n}\n\nfunction SecretDialog({ children, setupKey }: SecretDialogProps) {\n return (\n <Dialog.Root>\n <Dialog.Trigger>{children}</Dialog.Trigger>\n <DialogContent\n maxWidth=\"90vw\"\n size={{ initial: \"3\", sm: \"4\" }}\n minWidth=\"300px\"\n width=\"fit-content\"\n >\n <Dialog.Title size=\"2\" weight=\"regular\">\n Your setup key\n </Dialog.Title>\n <Dialog.Description>\n <Text size=\"6\">\n <Code variant=\"ghost\" style={{ letterSpacing: \"0.15rem\" }}>\n {setupKey}\n </Code>\n </Text>\n </Dialog.Description>\n\n <Flex align=\"center\" gap=\"3\" justify=\"end\" mt=\"5\">\n <Dialog.Close>\n <CopyButton asChild value={setupKey}>\n <PrimaryButton>Copy and close</PrimaryButton>\n </CopyButton>\n </Dialog.Close>\n </Flex>\n </DialogContent>\n </Dialog.Root>\n );\n}\n\nfunction getMutationErrorMessage(error: unknown) {\n let message = \"Something went wrong, please try again\";\n\n if (typeof error === \"string\") {\n message = error;\n }\n\n if (error instanceof Error) {\n message = error.message;\n }\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n message = error.message;\n }\n\n if (message === \"Invalid passcode\") {\n message = \"Invalid passcode, please try again\";\n }\n\n return message;\n}\n\nfunction hasQrCode(\n response?: CreateTotpFactorResponse,\n): response is CreateTotpFactorResponse & {\n authenticationFactor: {\n totp: NonNullable<CreateTotpFactorResponseAuthenticationFactorAllOfTotpAnyOf>;\n };\n} {\n const totp = response?.authenticationFactor.totp;\n return totp != null && \"qr_code\" in totp;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -5,7 +5,7 @@ import { Skeleton } from "./elements.js";
|
|
|
5
5
|
import { IconPanel } from "./icon-panel.js";
|
|
6
6
|
import { GenericError } from "./generic-error.js";
|
|
7
7
|
import { ExternalLinkIcon } from "@radix-ui/react-icons";
|
|
8
|
-
import * as CardList from "
|
|
8
|
+
import * as CardList from "./card-list.js";
|
|
9
9
|
import { DomainItem } from "./domain-item.js";
|
|
10
10
|
import clsx from "clsx";
|
|
11
11
|
const AdminPortalDomainVerification = ({
|
|
@@ -16,23 +16,30 @@ const AdminPortalDomainVerification = ({
|
|
|
16
16
|
isPending = false
|
|
17
17
|
}) => {
|
|
18
18
|
if (organizationDomains.length === 0) {
|
|
19
|
-
return /* @__PURE__ */ jsx(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
color: "gray",
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
return /* @__PURE__ */ jsx(
|
|
20
|
+
Card,
|
|
21
|
+
{
|
|
22
|
+
size: "2",
|
|
23
|
+
"data-woswidgets-widget-id": "admin-portal-domain-verification",
|
|
24
|
+
children: /* @__PURE__ */ jsxs(Flex, { direction: "row", justify: "between", align: "center", children: [
|
|
25
|
+
/* @__PURE__ */ jsx(Text, { size: "2", color: "gray", children: "You haven't added any verified domains yet." }),
|
|
26
|
+
/* @__PURE__ */ jsxs(
|
|
27
|
+
Button,
|
|
28
|
+
{
|
|
29
|
+
variant: "outline",
|
|
30
|
+
color: "gray",
|
|
31
|
+
loading: isPending,
|
|
32
|
+
disabled: isPending,
|
|
33
|
+
onClick: onAddDomain,
|
|
34
|
+
children: [
|
|
35
|
+
"Add domain ",
|
|
36
|
+
/* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
] })
|
|
41
|
+
}
|
|
42
|
+
);
|
|
36
43
|
}
|
|
37
44
|
return /* @__PURE__ */ jsxs(
|
|
38
45
|
Flex,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/admin-portal-domain-verification.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { ExternalLinkIcon } from \"@radix-ui/react-icons\";\nimport * as CardList from \"
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/admin-portal-domain-verification.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Box, Button, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { Skeleton } from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { GenericError } from \"./generic-error.js\";\nimport { ExternalLinkIcon } from \"@radix-ui/react-icons\";\nimport * as CardList from \"./card-list.js\";\nimport { OrganizationDomain } from \"../api/endpoint.js\";\nimport { DomainItem } from \"./domain-item.js\";\n\nimport clsx from \"clsx\";\n\ninterface AdminPortalDomainVerificationProps {\n organizationDomains: OrganizationDomain[];\n onAddDomain: () => void;\n onDeleteDomain: (domainId: string) => void;\n onReverifyDomain: (domainId: string) => void;\n isPending?: boolean;\n}\n\nexport const AdminPortalDomainVerification = ({\n organizationDomains,\n onAddDomain,\n onDeleteDomain,\n onReverifyDomain,\n isPending = false,\n}: AdminPortalDomainVerificationProps) => {\n if (organizationDomains.length === 0) {\n return (\n <Card\n size=\"2\"\n data-woswidgets-widget-id=\"admin-portal-domain-verification\"\n >\n <Flex direction=\"row\" justify=\"between\" align=\"center\">\n <Text size=\"2\" color=\"gray\">\n You haven't added any verified domains yet.\n </Text>\n <Button\n variant=\"outline\"\n color=\"gray\"\n loading={isPending}\n disabled={isPending}\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Flex>\n </Card>\n );\n }\n\n return (\n <Flex\n direction=\"column\"\n gap=\"4\"\n className={clsx(\"woswidgets-widget\")}\n data-woswidgets-widget-id=\"admin-portal-domain-verification\"\n >\n <CardList.Root>\n {organizationDomains.map((domain) => (\n <CardList.Item key={domain.id}>\n <DomainItem\n domain={domain}\n onDeleteDomain={onDeleteDomain}\n onReverifyDomain={onReverifyDomain}\n />\n </CardList.Item>\n ))}\n </CardList.Root>\n\n <Box>\n <Button\n loading={isPending}\n disabled={isPending}\n color=\"gray\"\n variant=\"outline\"\n onClick={onAddDomain}\n >\n Add domain <ExternalLinkIcon />\n </Button>\n </Box>\n </Flex>\n );\n};\n\nexport const AdminPortalDomainVerificationLoading: React.FC = () => {\n return (\n <Card size=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel />\n </Skeleton>\n\n <Flex direction=\"column\">\n <Text size=\"2\" highContrast weight=\"bold\" as=\"p\" mb=\"-2px\">\n <Skeleton>Domain name</Skeleton>\n </Text>\n\n <Text size=\"2\" color=\"gray\" as=\"p\">\n <Skeleton>Added recently</Skeleton>\n </Text>\n </Flex>\n </Flex>\n </Card>\n );\n};\n\nexport function AdminPortalDomainVerificationError({\n error,\n}: {\n error: unknown;\n}) {\n return (\n <Card size=\"2\">\n <GenericError error={error} />\n </Card>\n );\n}\n"],"mappings":";AAoCU,cAGA,YAHA;AAjCV,SAAS,KAAK,QAAQ,MAAM,MAAM,YAAY;AAC9C,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,YAAY,cAAc;AAE1B,SAAS,kBAAkB;AAE3B,OAAO,UAAU;AAUV,MAAM,gCAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,MAA0C;AACxC,MAAI,oBAAoB,WAAW,GAAG;AACpC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,6BAA0B;AAAA,QAE1B,+BAAC,QAAK,WAAU,OAAM,SAAQ,WAAU,OAAM,UAC5C;AAAA,8BAAC,QAAK,MAAK,KAAI,OAAM,QAAO,yDAE5B;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,SAAS;AAAA,cACT,UAAU;AAAA,cACV,SAAS;AAAA,cACV;AAAA;AAAA,gBACY,oBAAC,oBAAiB;AAAA;AAAA;AAAA,UAC/B;AAAA,WACF;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,KAAI;AAAA,MACJ,WAAW,KAAK,mBAAmB;AAAA,MACnC,6BAA0B;AAAA,MAE1B;AAAA,4BAAC,SAAS,MAAT,EACE,8BAAoB,IAAI,CAAC,WACxB,oBAAC,SAAS,MAAT,EACC;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF,KALkB,OAAO,EAM3B,CACD,GACH;AAAA,QAEA,oBAAC,OACC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,UAAU;AAAA,YACV,OAAM;AAAA,YACN,SAAQ;AAAA,YACR,SAAS;AAAA,YACV;AAAA;AAAA,cACY,oBAAC,oBAAiB;AAAA;AAAA;AAAA,QAC/B,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,MAAM,uCAAiD,MAAM;AAClE,SACE,oBAAC,QAAK,MAAK,KACT,+BAAC,QAAK,KAAI,KAAI,OAAM,UAClB;AAAA,wBAAC,YACC,8BAAC,aAAU,GACb;AAAA,IAEA,qBAAC,QAAK,WAAU,UACd;AAAA,0BAAC,QAAK,MAAK,KAAI,cAAY,MAAC,QAAO,QAAO,IAAG,KAAI,IAAG,QAClD,8BAAC,YAAS,yBAAW,GACvB;AAAA,MAEA,oBAAC,QAAK,MAAK,KAAI,OAAM,QAAO,IAAG,KAC7B,8BAAC,YAAS,4BAAc,GAC1B;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEO,SAAS,mCAAmC;AAAA,EACjD;AACF,GAEG;AACD,SACE,oBAAC,QAAK,MAAK,KACT,8BAAC,gBAAa,OAAc,GAC9B;AAEJ;","names":[]}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
InfoCircledIcon,
|
|
10
10
|
Cross2Icon
|
|
11
11
|
} from "@radix-ui/react-icons";
|
|
12
|
-
import * as CardList from "
|
|
12
|
+
import * as CardList from "./card-list.js";
|
|
13
13
|
import { ProviderIcon } from "./provider-icon.js";
|
|
14
14
|
import {
|
|
15
15
|
getIdentityProviderName
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { Status } from "./status.js";
|
|
18
18
|
import { unreachable } from "./utils.js";
|
|
19
19
|
import clsx from "clsx";
|
|
20
|
-
import {
|
|
20
|
+
import { getErrorMessage } from "./generic-error.js";
|
|
21
21
|
const AdminPortalSsoConnectionContext = React.createContext(null);
|
|
22
22
|
AdminPortalSsoConnectionContext.displayName = "AdminPortalSsoConnectionContext";
|
|
23
23
|
function useAdminPortalSsoConnectionContext() {
|
|
@@ -219,30 +219,7 @@ function AdminPortalSsoConnectionError({ error }) {
|
|
|
219
219
|
React.useEffect(() => {
|
|
220
220
|
console.error(error);
|
|
221
221
|
}, [error]);
|
|
222
|
-
const { heading, message } = (
|
|
223
|
-
if (error instanceof FetchError) {
|
|
224
|
-
return {
|
|
225
|
-
heading: "Error fetching data",
|
|
226
|
-
message: "An error occurred. You may need to configure CORS in the WorkOS Dashboard. Contact your organization admin for support."
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
if (error instanceof NoAuthTokenError) {
|
|
230
|
-
return {
|
|
231
|
-
heading: "Error fetching data",
|
|
232
|
-
message: "Authorization error. You likely forgot to provide an authorization token to the Users Management Widget."
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
if (error instanceof ApiError && error.status === 404) {
|
|
236
|
-
return {
|
|
237
|
-
heading: "Error fetching data",
|
|
238
|
-
message: "Authorization error. Contact your organization admin for support."
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
return {
|
|
242
|
-
heading: "Unknown error",
|
|
243
|
-
message: "An unexpected error occurred. Please try refreshing the page, or contact your organization admin for support."
|
|
244
|
-
};
|
|
245
|
-
})();
|
|
222
|
+
const { heading, message } = getErrorMessage(error);
|
|
246
223
|
return /* @__PURE__ */ jsx(Card, { size: "2", children: /* @__PURE__ */ jsx(Flex, { direction: "row", justify: "between", align: "center", gap: "2", children: /* @__PURE__ */ jsxs(Flex, { gap: "4", align: "center", children: [
|
|
247
224
|
/* @__PURE__ */ jsx(
|
|
248
225
|
Flex,
|
|
@@ -254,7 +231,8 @@ function AdminPortalSsoConnectionError({ error }) {
|
|
|
254
231
|
style: {
|
|
255
232
|
borderRadius: "9999px",
|
|
256
233
|
backgroundColor: "var(--red-a4)",
|
|
257
|
-
color: "var(--red-a11)"
|
|
234
|
+
color: "var(--red-a11)",
|
|
235
|
+
flexShrink: 0
|
|
258
236
|
},
|
|
259
237
|
children: /* @__PURE__ */ jsx(Cross2Icon, { width: "18px", height: "18px" })
|
|
260
238
|
}
|