@workos-inc/widgets 1.20.0-next.1791237372282 → 1.20.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/CHANGELOG.md +3 -1
- package/README.md +44 -0
- package/dist/cjs/api/claims.cjs +4 -0
- package/dist/cjs/api/claims.cjs.map +1 -1
- package/dist/cjs/api/claims.d.cts +6 -1
- package/dist/cjs/lib/pipes-credential-attribution.cjs +33 -0
- package/dist/cjs/lib/pipes-credential-attribution.cjs.map +1 -0
- package/dist/cjs/lib/pipes-credential-attribution.d.cts +8 -0
- package/dist/cjs/lib/pipes.cjs +26 -10
- package/dist/cjs/lib/pipes.cjs.map +1 -1
- package/dist/cjs/pipes-admin.client.cjs +8 -4
- package/dist/cjs/pipes-admin.client.cjs.map +1 -1
- package/dist/cjs/pipes-admin.client.d.cts +8 -0
- package/dist/esm/api/claims.d.ts +6 -1
- package/dist/esm/api/claims.js +4 -1
- package/dist/esm/api/claims.js.map +1 -1
- package/dist/esm/lib/pipes-credential-attribution.d.ts +8 -0
- package/dist/esm/lib/pipes-credential-attribution.js +31 -0
- package/dist/esm/lib/pipes-credential-attribution.js.map +1 -0
- package/dist/esm/lib/pipes.js +26 -10
- package/dist/esm/lib/pipes.js.map +1 -1
- package/dist/esm/pipes-admin.client.d.ts +8 -0
- package/dist/esm/pipes-admin.client.js +8 -4
- package/dist/esm/pipes-admin.client.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.20.0
|
|
3
|
+
## 1.20.0
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
7
7
|
- Prepare the sectioned `<Pipes>` and `<PipesAdmin>` experiences (`enableSharedConnections`) for multiple connections per provider. Nothing changes until multiple connections are enabled for your environment; until then each provider keeps its single connection and looks as it did before. Once enabled, a provider with several connections renders as a group with one row per connection, oldest first, each with its own status and actions. "Add connection" and "Connect another account" add one (asking for an optional name) when the API reports it available, and connections can be renamed. Repairs target the exact connection, and adds are retry-safe.
|
|
8
8
|
|
|
9
|
+
- Add the optional PipesAdmin `userId` prop for attributing shared API-key and client-credentials writes with application credential tokens. User sessions send their authenticated user automatically. Block missing actors and mismatched session actors with configuration guidance instead of actor-entry UI. Application-token hosts must supply an acting WorkOS user before upgrading; publish only after the API accepts attribution.
|
|
10
|
+
|
|
9
11
|
- Surface data integration connection failures in the Pipes widget
|
|
10
12
|
|
|
11
13
|
When an OAuth handoff popup fails or closes without completing, the widget now
|
package/README.md
CHANGED
|
@@ -3,3 +3,47 @@
|
|
|
3
3
|
A suite of React components providing functionality for enterprise app workflows.
|
|
4
4
|
|
|
5
5
|
[Read the documentation](https://workos.com/docs/widgets)
|
|
6
|
+
|
|
7
|
+
## Shared Pipes credentials
|
|
8
|
+
|
|
9
|
+
`PipesAdmin` defaults to provider settings only. Opt in to shared connections
|
|
10
|
+
with `enableSharedConnections`. User-backed widget sessions and AuthKit user
|
|
11
|
+
access tokens attribute shared API-key and client-credentials writes to the
|
|
12
|
+
signed-in user without any new host prop.
|
|
13
|
+
|
|
14
|
+
Hosts using an application credential token must pass the acting person's
|
|
15
|
+
WorkOS user ID programmatically when connecting, rotating, or repairing shared
|
|
16
|
+
credentials:
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
<PipesAdmin
|
|
20
|
+
authToken={applicationCredentialToken}
|
|
21
|
+
enableSharedConnections
|
|
22
|
+
userId={authenticatedWorkOsUser.id}
|
|
23
|
+
/>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Source `authenticatedWorkOsUser.id` from the host's authenticated user context
|
|
27
|
+
or an existing mapping to that WorkOS user (`user_...`), not an arbitrary
|
|
28
|
+
application-local ID or the credential token's subject. `userId` is an optional
|
|
29
|
+
React prop, never a rendered field or member picker. A missing actor blocks
|
|
30
|
+
these shared credential writes with configuration guidance, while reads,
|
|
31
|
+
provider configuration, and OAuth flows remain available. User-session hosts
|
|
32
|
+
should omit the prop; a different ID is rejected. Standalone widget sessions
|
|
33
|
+
cannot supply an actor through this prop.
|
|
34
|
+
|
|
35
|
+
An authorized application caller asserts whom it acts on behalf of. Passing
|
|
36
|
+
`userId` does not authenticate that person or grant write access: the API still
|
|
37
|
+
validates permissions, identity, and active membership of the token-scoped
|
|
38
|
+
organization. If there is no acting person, do not fabricate one; machine-managed
|
|
39
|
+
credentials require separate policy support.
|
|
40
|
+
|
|
41
|
+
### Upgrade and rollout
|
|
42
|
+
|
|
43
|
+
Before upgrading application-token hosts, supply `userId` from their authenticated
|
|
44
|
+
user context for shared credential actions. User-session hosts require no changes.
|
|
45
|
+
Publish this widget change only after the deployed Widgets GraphQL API accepts
|
|
46
|
+
`userId` on both organization credential inputs (PVIT-1079). Subsequent server-side
|
|
47
|
+
required-actor enforcement (PVIT-1081) also requires operator confirmation of the
|
|
48
|
+
affected hosts' upgrade and communication plan; publication alone does not prove
|
|
49
|
+
adoption.
|
package/dist/cjs/api/claims.cjs
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
//#region src/api/claims.ts
|
|
3
|
+
function getAuthenticatedUserId(claims) {
|
|
4
|
+
return (claims.sub_profile === void 0 || claims.sub_profile === "user") && (claims.sub_type === "authkit" || claims.sub_type === void 0 && !!claims.sid && typeof claims.auth_time === "number") && claims.sub?.startsWith("user_") ? claims.sub : void 0;
|
|
5
|
+
}
|
|
3
6
|
function getClaims(accessToken) {
|
|
4
7
|
return JSON.parse(atob(accessToken.split(".")[1]));
|
|
5
8
|
}
|
|
6
9
|
//#endregion
|
|
10
|
+
exports.getAuthenticatedUserId = getAuthenticatedUserId;
|
|
7
11
|
exports.getClaims = getClaims;
|
|
8
12
|
|
|
9
13
|
//# sourceMappingURL=claims.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claims.cjs","names":[],"sources":["../../../src/api/claims.ts"],"sourcesContent":["interface Claims {\n sid
|
|
1
|
+
{"version":3,"file":"claims.cjs","names":[],"sources":["../../../src/api/claims.ts"],"sourcesContent":["interface Claims {\n sid?: string;\n sub?: string;\n sub_type?: string;\n sub_profile?: string;\n auth_time?: number;\n permissions?: string[];\n exp?: number;\n}\n\nexport function getAuthenticatedUserId(claims: Claims): string | undefined {\n const isUserSession =\n (claims.sub_profile === undefined || claims.sub_profile === \"user\") &&\n (claims.sub_type === \"authkit\" ||\n (claims.sub_type === undefined &&\n !!claims.sid &&\n typeof claims.auth_time === \"number\"));\n\n return isUserSession && claims.sub?.startsWith(\"user_\")\n ? claims.sub\n : undefined;\n}\n\nexport function getClaims(accessToken: string): Claims {\n return JSON.parse(atob(accessToken.split(\".\")[1]));\n}\n"],"mappings":";;AAUA,SAAgB,uBAAuB,QAAoC;CAQzE,QANG,OAAO,gBAAgB,UAAa,OAAO,gBAAgB,YAC3D,OAAO,aAAa,aAClB,OAAO,aAAa,UACnB,CAAC,CAAC,OAAO,OACT,OAAO,OAAO,cAAc,aAEV,OAAO,KAAK,WAAW,OAAO,IAClD,OAAO,MACP;AACN;AAEA,SAAgB,UAAU,aAA6B;CACrD,OAAO,KAAK,MAAM,KAAK,YAAY,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;AACnD"}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
//#region src/api/claims.d.ts
|
|
2
2
|
interface Claims {
|
|
3
|
-
sid
|
|
3
|
+
sid?: string;
|
|
4
|
+
sub?: string;
|
|
5
|
+
sub_type?: string;
|
|
6
|
+
sub_profile?: string;
|
|
7
|
+
auth_time?: number;
|
|
4
8
|
permissions?: string[];
|
|
5
9
|
exp?: number;
|
|
6
10
|
}
|
|
11
|
+
export declare function getAuthenticatedUserId(claims: Claims): string | undefined;
|
|
7
12
|
export declare function getClaims(accessToken: string): Claims;
|
|
8
13
|
//#endregion
|
|
9
14
|
//# sourceMappingURL=claims.d.cts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const require_lib_i18n_use_translation = require("./i18n/use-translation.cjs");
|
|
4
|
+
const require_api_claims = require("../api/claims.cjs");
|
|
5
|
+
const require_api_api_provider = require("../api/api-provider.cjs");
|
|
6
|
+
let react = require("react");
|
|
7
|
+
//#region src/lib/pipes-credential-attribution.tsx
|
|
8
|
+
const PipesCredentialUserIdContext = (0, react.createContext)(void 0);
|
|
9
|
+
function usePipesCredentialAttribution() {
|
|
10
|
+
const hostUserId = (0, react.useContext)(PipesCredentialUserIdContext)?.trim();
|
|
11
|
+
const { authToken } = require_api_api_provider.useApi();
|
|
12
|
+
const translate = require_lib_i18n_use_translation.useTranslation();
|
|
13
|
+
const claims = authToken ? require_api_claims.getClaims(authToken) : void 0;
|
|
14
|
+
const sessionUserId = claims && require_api_claims.getAuthenticatedUserId(claims);
|
|
15
|
+
const userId = sessionUserId ?? (claims?.sub_type === "client_api_credential" && hostUserId?.startsWith("user_") ? hostUserId : void 0);
|
|
16
|
+
return {
|
|
17
|
+
userId,
|
|
18
|
+
error: sessionUserId && hostUserId && hostUserId !== sessionUserId ? translate({
|
|
19
|
+
defaultMessage: "Shared credentials must be attributed to the signed-in user. The application must omit PipesAdmin's userId prop or pass the signed-in user's WorkOS user ID.",
|
|
20
|
+
description: "Configuration error when the host-supplied PipesAdmin user ID differs from the authenticated user",
|
|
21
|
+
id: "pipesCredentialUserMismatch"
|
|
22
|
+
}) : !userId ? translate({
|
|
23
|
+
defaultMessage: "Shared credentials require an acting WorkOS user. The application must use a user-backed session or supply the acting person's WorkOS user ID through PipesAdmin's userId prop when using an application credential token.",
|
|
24
|
+
description: "Configuration guidance for shared credential writes without an acting user; no user ID entry is requested",
|
|
25
|
+
id: "pipesCredentialUserRequired"
|
|
26
|
+
}) : void 0
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
exports.PipesCredentialUserIdContext = PipesCredentialUserIdContext;
|
|
31
|
+
exports.usePipesCredentialAttribution = usePipesCredentialAttribution;
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=pipes-credential-attribution.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipes-credential-attribution.cjs","names":["createContext","useContext","useApi","useTranslation","getClaims","getAuthenticatedUserId"],"sources":["../../../src/lib/pipes-credential-attribution.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { useApi } from \"../api/api-provider.js\";\nimport { getAuthenticatedUserId, getClaims } from \"../api/claims.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\n\nexport const PipesCredentialUserIdContext = createContext<string | undefined>(\n undefined,\n);\n\nexport function usePipesCredentialAttribution() {\n const hostUserId = useContext(PipesCredentialUserIdContext)?.trim();\n const { authToken } = useApi();\n const translate = useTranslation();\n const claims = authToken ? getClaims(authToken) : undefined;\n const sessionUserId = claims && getAuthenticatedUserId(claims);\n const userId =\n sessionUserId ??\n (claims?.sub_type === \"client_api_credential\" &&\n hostUserId?.startsWith(\"user_\")\n ? hostUserId\n : undefined);\n\n const error =\n sessionUserId && hostUserId && hostUserId !== sessionUserId\n ? translate({\n defaultMessage:\n \"Shared credentials must be attributed to the signed-in user. The application must omit PipesAdmin's userId prop or pass the signed-in user's WorkOS user ID.\",\n description:\n \"Configuration error when the host-supplied PipesAdmin user ID differs from the authenticated user\",\n id: \"pipesCredentialUserMismatch\",\n })\n : !userId\n ? translate({\n defaultMessage:\n \"Shared credentials require an acting WorkOS user. The application must use a user-backed session or supply the acting person's WorkOS user ID through PipesAdmin's userId prop when using an application credential token.\",\n description:\n \"Configuration guidance for shared credential writes without an acting user; no user ID entry is requested\",\n id: \"pipesCredentialUserRequired\",\n })\n : undefined;\n\n return { userId, error };\n}\n"],"mappings":";;;;;;;AAOA,MAAa,gCAAA,GAA+BA,MAAAA,cAAAA,CAC1C,MACF;AAEA,SAAgB,gCAAgC;CAC9C,MAAM,cAAA,GAAaC,MAAAA,WAAAA,CAAW,4BAA4B,CAAC,EAAE,KAAK;CAClE,MAAM,EAAE,cAAcC,yBAAAA,OAAO;CAC7B,MAAM,YAAYC,iCAAAA,eAAe;CACjC,MAAM,SAAS,YAAYC,mBAAAA,UAAU,SAAS,IAAI;CAClD,MAAM,gBAAgB,UAAUC,mBAAAA,uBAAuB,MAAM;CAC7D,MAAM,SACJ,kBACC,QAAQ,aAAa,2BACtB,YAAY,WAAW,OAAO,IAC1B,aACA;CAqBN,OAAO;EAAE;EAAQ,OAlBf,iBAAiB,cAAc,eAAe,gBAC1C,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD,CAAC,SACC,UAAU;GACR,gBACE;GACF,aACE;GACF,IAAI;EACN,CAAC,IACD;CAEe;AACzB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/lib/pipes-credential-attribution.d.ts
|
|
2
|
+
export declare const PipesCredentialUserIdContext: import("react").Context<string | undefined>;
|
|
3
|
+
export declare function usePipesCredentialAttribution(): {
|
|
4
|
+
userId: string | undefined;
|
|
5
|
+
error: string | undefined;
|
|
6
|
+
};
|
|
7
|
+
//#endregion
|
|
8
|
+
//# sourceMappingURL=pipes-credential-attribution.d.cts.map
|
package/dist/cjs/lib/pipes.cjs
CHANGED
|
@@ -19,6 +19,7 @@ const require_lib_data_integration_icon = require("./data-integration-icon.cjs")
|
|
|
19
19
|
const require_lib_api_pipes = require("./api/pipes.cjs");
|
|
20
20
|
const require_lib_pipes_connections = require("./pipes-connections.cjs");
|
|
21
21
|
const require_lib_redacted_secret = require("./redacted-secret.cjs");
|
|
22
|
+
const require_lib_pipes_credential_attribution = require("./pipes-credential-attribution.cjs");
|
|
22
23
|
let react = require("react");
|
|
23
24
|
let _radix_ui_themes = require("@radix-ui/themes");
|
|
24
25
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -748,6 +749,8 @@ const API_KEY_REDACTED_PREFIX = "••••";
|
|
|
748
749
|
*/
|
|
749
750
|
function ApiKeyDialog({ integration, installation = integration.installation, owner = "user", target = require_lib_pipes_connections.getConnectionTarget(installation), open, onOpenChange, onSuccess, collectName = false }) {
|
|
750
751
|
const invalidateConnections = require_lib_api_pipes.useInvalidateConnections(owner);
|
|
752
|
+
const attribution = require_lib_pipes_credential_attribution.usePipesCredentialAttribution();
|
|
753
|
+
const attributionError = owner === "organization" ? attribution.error : void 0;
|
|
751
754
|
const [name, setName] = (0, react.useState)("");
|
|
752
755
|
const isRotation = installation?.auth_method === "api_key" && installation.state === "connected";
|
|
753
756
|
const last4 = installation?.api_key_last_4;
|
|
@@ -779,8 +782,13 @@ function ApiKeyDialog({ integration, installation = integration.installation, ow
|
|
|
779
782
|
...require_lib_pipes_connections.toCreationTargetInput(target),
|
|
780
783
|
...collectName ? require_lib_pipes_connections.toAccountDisplayNameInput(name) : {}
|
|
781
784
|
};
|
|
782
|
-
if (owner === "organization")
|
|
783
|
-
|
|
785
|
+
if (owner === "organization") {
|
|
786
|
+
if (attributionError || !attribution.userId) return;
|
|
787
|
+
organizationUpsert.mutate({
|
|
788
|
+
...input,
|
|
789
|
+
userId: attribution.userId
|
|
790
|
+
});
|
|
791
|
+
} else userUpsert.mutate(input);
|
|
784
792
|
};
|
|
785
793
|
(0, react.useEffect)(() => {
|
|
786
794
|
reset();
|
|
@@ -816,11 +824,11 @@ function ApiKeyDialog({ integration, installation = integration.installation, ow
|
|
|
816
824
|
mt: "1",
|
|
817
825
|
children: integration.description
|
|
818
826
|
}),
|
|
819
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Root, {
|
|
827
|
+
(attributionError || error) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Root, {
|
|
820
828
|
my: "3",
|
|
821
829
|
color: "red",
|
|
822
830
|
role: "alert",
|
|
823
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Text, { children: errorMessage ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_i18n_translation.Translation, {
|
|
831
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Text, { children: attributionError ?? errorMessage ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_i18n_translation.Translation, {
|
|
824
832
|
defaultMessage: "An error occurred. Please check the value and try again.",
|
|
825
833
|
id: "bYLbLL",
|
|
826
834
|
description: "Generic error message for API key submission failure"
|
|
@@ -882,7 +890,7 @@ function ApiKeyDialog({ integration, installation = integration.installation, ow
|
|
|
882
890
|
})
|
|
883
891
|
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_elements.Button, {
|
|
884
892
|
type: "button",
|
|
885
|
-
disabled: isPending || !secret.trim(),
|
|
893
|
+
disabled: !!attributionError || isPending || !secret.trim(),
|
|
886
894
|
loading: isPending,
|
|
887
895
|
onClick: () => upsertApiKey(secret.trim()),
|
|
888
896
|
children: isRotation ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_i18n_translation.Translation, {
|
|
@@ -933,6 +941,8 @@ function ApiKeyConnectButton({ integration }) {
|
|
|
933
941
|
*/
|
|
934
942
|
function ClientCredentialsDialog({ integration, installation = integration.installation, owner = "user", target = require_lib_pipes_connections.getConnectionTarget(installation), fields, open, onOpenChange, onSuccess, collectName = false }) {
|
|
935
943
|
const invalidateConnections = require_lib_api_pipes.useInvalidateConnections(owner);
|
|
944
|
+
const attribution = require_lib_pipes_credential_attribution.usePipesCredentialAttribution();
|
|
945
|
+
const attributionError = owner === "organization" ? attribution.error : void 0;
|
|
936
946
|
const [name, setName] = (0, react.useState)("");
|
|
937
947
|
const isUpdate = installation?.auth_method === "client_credentials";
|
|
938
948
|
const storedConfig = (0, react.useMemo)(() => isUpdate ? installation?.config ?? {} : {}, [isUpdate, installation?.config]);
|
|
@@ -975,6 +985,7 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
|
|
|
975
985
|
const { error, isPending } = owner === "organization" ? organizationUpsert : userUpsert;
|
|
976
986
|
const errorMessage = error instanceof require_api_errors.ApiError && error.message ? error.message : null;
|
|
977
987
|
const handleSubmit = () => {
|
|
988
|
+
if (attributionError) return;
|
|
978
989
|
if (!configForm.validate()) return;
|
|
979
990
|
const config = configForm.isDirty ? configForm.buildConfigPayload(storedConfig) : void 0;
|
|
980
991
|
const input = {
|
|
@@ -985,8 +996,13 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
|
|
|
985
996
|
...require_lib_pipes_connections.toCreationTargetInput(target),
|
|
986
997
|
...collectName ? require_lib_pipes_connections.toAccountDisplayNameInput(name) : {}
|
|
987
998
|
};
|
|
988
|
-
if (owner === "organization")
|
|
989
|
-
|
|
999
|
+
if (owner === "organization") {
|
|
1000
|
+
if (!attribution.userId) return;
|
|
1001
|
+
organizationUpsert.mutate({
|
|
1002
|
+
...input,
|
|
1003
|
+
userId: attribution.userId
|
|
1004
|
+
});
|
|
1005
|
+
} else userUpsert.mutate(input);
|
|
990
1006
|
};
|
|
991
1007
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes_components_dialog.Root, {
|
|
992
1008
|
open,
|
|
@@ -1009,11 +1025,11 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
|
|
|
1009
1025
|
values: { integrationName: integration.name }
|
|
1010
1026
|
})
|
|
1011
1027
|
}),
|
|
1012
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Root, {
|
|
1028
|
+
(attributionError || error) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Root, {
|
|
1013
1029
|
my: "3",
|
|
1014
1030
|
color: "red",
|
|
1015
1031
|
role: "alert",
|
|
1016
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Text, { children: errorMessage ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_i18n_translation.Translation, {
|
|
1032
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_themes.Callout.Text, { children: attributionError ?? errorMessage ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_i18n_translation.Translation, {
|
|
1017
1033
|
defaultMessage: "An error occurred. Please check the value and try again.",
|
|
1018
1034
|
id: "bYLbLL",
|
|
1019
1035
|
description: "Generic error message for API key submission failure"
|
|
@@ -1109,7 +1125,7 @@ function ClientCredentialsDialog({ integration, installation = integration.insta
|
|
|
1109
1125
|
})
|
|
1110
1126
|
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_elements.Button, {
|
|
1111
1127
|
type: "button",
|
|
1112
|
-
disabled: isPending || !clientId.trim() || secretMissing || configForm.hasMissingRequired,
|
|
1128
|
+
disabled: !!attributionError || isPending || !clientId.trim() || secretMissing || configForm.hasMissingRequired,
|
|
1113
1129
|
loading: isPending,
|
|
1114
1130
|
onClick: handleSubmit,
|
|
1115
1131
|
children: isUpdate ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_lib_i18n_translation.Translation, {
|