diff --git a/.changeset/security-page-redesign.md b/.changeset/security-page-redesign.md
new file mode 100644
index 00000000000..3beac907ce8
--- /dev/null
+++ b/.changeset/security-page-redesign.md
@@ -0,0 +1,9 @@
+---
+'@clerk/localizations': minor
+'@clerk/shared': minor
+'@clerk/ui': minor
+---
+
+Update the SSO and Directory Sync sections of the `` Security page to the latest designs. Both sections now show a "Configure" button until something is set up (SSO then shows "Add connection"), and SSO connection rows show the identity provider's logo and an actions menu (Edit, Continue configuration, Activate/Deactivate, Remove). These actions have been removed from the SSO connection page, and status badges are no longer color-coded. Okta logos now follow the theme's foreground color, so they stay visible in dark mode, including on the enterprise connection chooser and in ``.
+
+The SSO button uses the new `ssoSection.primaryButton__configure` localization key; `ssoSection.primaryButton__startConfiguration` is deprecated and no longer used. In `directorySyncSection`, `primaryButton__startConfiguration` is renamed to `primaryButton__configure` and `badge__unconfigured` is removed.
diff --git a/integration/tests/composed-components.test.ts b/integration/tests/composed-components.test.ts
index 439a79d344f..515993a8eb5 100644
--- a/integration/tests/composed-components.test.ts
+++ b/integration/tests/composed-components.test.ts
@@ -463,6 +463,6 @@ test.describe('composed OrganizationProfile exports @generic', () => {
// the composed counterpart to the security tab (there are no composable sub-sections here).
await expect(u.page.getByRole('heading', { name: /^security$/i })).toBeVisible();
await expect(u.page.getByText(/^SSO$/)).toBeVisible();
- await expect(u.page.getByRole('button', { name: /start configuration/i })).toBeVisible();
+ await expect(u.page.locator('.cl-profileSection__sso').getByRole('button', { name: /^configure$/i })).toBeVisible();
});
});
diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts
index 7ab7fe9f682..51eb8049416 100644
--- a/packages/localizations/src/ar-SA.ts
+++ b/packages/localizations/src/ar-SA.ts
@@ -1386,14 +1386,13 @@ export const arSA: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1465,6 +1464,7 @@ export const arSA: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts
index 2ca6811c35c..2d3047732f7 100644
--- a/packages/localizations/src/be-BY.ts
+++ b/packages/localizations/src/be-BY.ts
@@ -1389,14 +1389,13 @@ export const beBY: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1468,6 +1467,7 @@ export const beBY: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts
index 4b46d8928c5..97e0dea7866 100644
--- a/packages/localizations/src/bg-BG.ts
+++ b/packages/localizations/src/bg-BG.ts
@@ -1389,14 +1389,13 @@ export const bgBG: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1468,6 +1467,7 @@ export const bgBG: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts
index 18778b578c7..e4903dd4680 100644
--- a/packages/localizations/src/bn-IN.ts
+++ b/packages/localizations/src/bn-IN.ts
@@ -1396,14 +1396,13 @@ export const bnIN: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1475,6 +1474,7 @@ export const bnIN: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts
index 6a182d97bf4..415dfb5651c 100644
--- a/packages/localizations/src/ca-ES.ts
+++ b/packages/localizations/src/ca-ES.ts
@@ -1396,14 +1396,13 @@ export const caES: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1475,6 +1474,7 @@ export const caES: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts
index 2c136eeed54..be7ddf037c6 100644
--- a/packages/localizations/src/cs-CZ.ts
+++ b/packages/localizations/src/cs-CZ.ts
@@ -1394,14 +1394,13 @@ export const csCZ: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1473,6 +1472,7 @@ export const csCZ: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts
index e6a3452295e..e9b3b4facda 100644
--- a/packages/localizations/src/da-DK.ts
+++ b/packages/localizations/src/da-DK.ts
@@ -1387,14 +1387,13 @@ export const daDK: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1466,6 +1465,7 @@ export const daDK: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts
index a790bf6e48a..85211a28986 100644
--- a/packages/localizations/src/de-DE.ts
+++ b/packages/localizations/src/de-DE.ts
@@ -1402,14 +1402,13 @@ export const deDE: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1481,6 +1480,7 @@ export const deDE: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts
index a81d77042e9..0467f20fb50 100644
--- a/packages/localizations/src/el-GR.ts
+++ b/packages/localizations/src/el-GR.ts
@@ -1392,14 +1392,13 @@ export const elGR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1471,6 +1470,7 @@ export const elGR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts
index c8f21c414d8..e028cff9e6f 100644
--- a/packages/localizations/src/en-GB.ts
+++ b/packages/localizations/src/en-GB.ts
@@ -1388,14 +1388,13 @@ export const enGB: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const enGB: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts
index 58523350769..abbcb744c3f 100644
--- a/packages/localizations/src/en-US.ts
+++ b/packages/localizations/src/en-US.ts
@@ -1425,16 +1425,14 @@ export const enUS: LocalizationResource = {
directorySyncSection: {
badge__active: 'Active',
badge__inactive: 'Inactive',
- badge__ssoRequired: 'SSO Required',
- badge__unconfigured: 'Unconfigured',
- description:
- "Automatically add, update, and remove organization members from your identity provider's directory. Requires an SSO connection.",
+ badge__ssoRequired: 'SSO required',
+ description: 'Keep organization members synced with your identity provider. Requires an SSO connection.',
error__load: 'Could not load Directory Sync',
menuAction__activate: 'Activate',
menuAction__deactivate: 'Deactivate',
menuAction__edit: 'Edit',
menuAction__remove: 'Remove',
- primaryButton__startConfiguration: 'Start configuration',
+ primaryButton__configure: 'Configure',
removeDialog: {
confirmButton: 'Remove Directory Sync',
subtitle:
@@ -1510,6 +1508,7 @@ export const enUS: LocalizationResource = {
menuAction__edit: 'Edit',
menuAction__remove: 'Remove',
primaryButton__addConnection: 'Add connection',
+ primaryButton__configure: 'Configure',
primaryButton__continueConfiguration: 'Continue configuration',
primaryButton__startConfiguration: 'Start configuration',
title: 'SSO',
diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts
index 20fde8d7627..f13e61b1055 100644
--- a/packages/localizations/src/es-CR.ts
+++ b/packages/localizations/src/es-CR.ts
@@ -1392,14 +1392,13 @@ export const esCR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1471,6 +1470,7 @@ export const esCR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts
index 8a3e3b077c0..175e88c7ef6 100644
--- a/packages/localizations/src/es-ES.ts
+++ b/packages/localizations/src/es-ES.ts
@@ -1397,14 +1397,13 @@ export const esES: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1476,6 +1475,7 @@ export const esES: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts
index 9fbd1657c41..35a9eab3747 100644
--- a/packages/localizations/src/es-MX.ts
+++ b/packages/localizations/src/es-MX.ts
@@ -1393,14 +1393,13 @@ export const esMX: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1472,6 +1471,7 @@ export const esMX: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts
index 4642d64e309..5f03cd55126 100644
--- a/packages/localizations/src/es-UY.ts
+++ b/packages/localizations/src/es-UY.ts
@@ -1391,14 +1391,13 @@ export const esUY: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1470,6 +1469,7 @@ export const esUY: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts
index c5394488e72..72e0ee3f716 100644
--- a/packages/localizations/src/fa-IR.ts
+++ b/packages/localizations/src/fa-IR.ts
@@ -1396,14 +1396,13 @@ export const faIR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1475,6 +1474,7 @@ export const faIR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts
index acf81048405..c3b07cb926e 100644
--- a/packages/localizations/src/fi-FI.ts
+++ b/packages/localizations/src/fi-FI.ts
@@ -1397,14 +1397,13 @@ export const fiFI: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1476,6 +1475,7 @@ export const fiFI: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts
index b53badd7457..31685940074 100644
--- a/packages/localizations/src/fr-FR.ts
+++ b/packages/localizations/src/fr-FR.ts
@@ -1402,14 +1402,13 @@ export const frFR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1481,6 +1480,7 @@ export const frFR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts
index 0feb281e01f..0c49ef326f3 100644
--- a/packages/localizations/src/he-IL.ts
+++ b/packages/localizations/src/he-IL.ts
@@ -1383,14 +1383,13 @@ export const heIL: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1462,6 +1461,7 @@ export const heIL: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts
index eb8921f1811..3b2df157c4a 100644
--- a/packages/localizations/src/hi-IN.ts
+++ b/packages/localizations/src/hi-IN.ts
@@ -1396,14 +1396,13 @@ export const hiIN: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1475,6 +1474,7 @@ export const hiIN: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts
index 0e6b43d4eee..40c4423cc1c 100644
--- a/packages/localizations/src/hr-HR.ts
+++ b/packages/localizations/src/hr-HR.ts
@@ -1397,14 +1397,13 @@ export const hrHR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1476,6 +1475,7 @@ export const hrHR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts
index 2df3cf0f335..bd0aeb00fc0 100644
--- a/packages/localizations/src/hu-HU.ts
+++ b/packages/localizations/src/hu-HU.ts
@@ -1398,14 +1398,13 @@ export const huHU: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1477,6 +1476,7 @@ export const huHU: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts
index 8506ee752a1..bb8f7a58b70 100644
--- a/packages/localizations/src/id-ID.ts
+++ b/packages/localizations/src/id-ID.ts
@@ -1390,14 +1390,13 @@ export const idID: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1469,6 +1468,7 @@ export const idID: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts
index 2725cb0ec66..f53f4d6cff5 100644
--- a/packages/localizations/src/is-IS.ts
+++ b/packages/localizations/src/is-IS.ts
@@ -1397,14 +1397,13 @@ export const isIS: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1476,6 +1475,7 @@ export const isIS: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts
index 818aa2c99c8..826889a94b4 100644
--- a/packages/localizations/src/it-IT.ts
+++ b/packages/localizations/src/it-IT.ts
@@ -1397,14 +1397,13 @@ export const itIT: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1476,6 +1475,7 @@ export const itIT: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts
index 4a5a0fe7001..c2cdb2926ad 100644
--- a/packages/localizations/src/ja-JP.ts
+++ b/packages/localizations/src/ja-JP.ts
@@ -1396,14 +1396,13 @@ export const jaJP: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1475,6 +1474,7 @@ export const jaJP: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts
index 7134dfb7483..306bd58ce3c 100644
--- a/packages/localizations/src/kk-KZ.ts
+++ b/packages/localizations/src/kk-KZ.ts
@@ -1383,14 +1383,13 @@ export const kkKZ: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1462,6 +1461,7 @@ export const kkKZ: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts
index 24de87d4e9d..8b76029443a 100644
--- a/packages/localizations/src/ko-KR.ts
+++ b/packages/localizations/src/ko-KR.ts
@@ -1388,14 +1388,13 @@ export const koKR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const koKR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts
index 108ba8014de..375c45efd4a 100644
--- a/packages/localizations/src/mn-MN.ts
+++ b/packages/localizations/src/mn-MN.ts
@@ -1390,14 +1390,13 @@ export const mnMN: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1469,6 +1468,7 @@ export const mnMN: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts
index fda67db9c75..ed21fbaef48 100644
--- a/packages/localizations/src/ms-MY.ts
+++ b/packages/localizations/src/ms-MY.ts
@@ -1399,14 +1399,13 @@ export const msMY: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1478,6 +1477,7 @@ export const msMY: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts
index 58ee9d09a6d..9e42aac4b76 100644
--- a/packages/localizations/src/nb-NO.ts
+++ b/packages/localizations/src/nb-NO.ts
@@ -1398,14 +1398,13 @@ export const nbNO: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1477,6 +1476,7 @@ export const nbNO: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts
index 03c02cecc3d..ddd60976415 100644
--- a/packages/localizations/src/nl-BE.ts
+++ b/packages/localizations/src/nl-BE.ts
@@ -1390,14 +1390,13 @@ export const nlBE: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1469,6 +1468,7 @@ export const nlBE: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts
index 8896e27a07b..e2a1969b441 100644
--- a/packages/localizations/src/nl-NL.ts
+++ b/packages/localizations/src/nl-NL.ts
@@ -1390,14 +1390,13 @@ export const nlNL: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1469,6 +1468,7 @@ export const nlNL: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts
index aa8adc2a60c..76d3adc7ea9 100644
--- a/packages/localizations/src/pl-PL.ts
+++ b/packages/localizations/src/pl-PL.ts
@@ -1388,14 +1388,13 @@ export const plPL: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const plPL: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts
index df49686106b..0d9ac6023a7 100644
--- a/packages/localizations/src/pt-BR.ts
+++ b/packages/localizations/src/pt-BR.ts
@@ -1398,14 +1398,13 @@ export const ptBR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1477,6 +1476,7 @@ export const ptBR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts
index b6538ce7947..4440c052473 100644
--- a/packages/localizations/src/pt-PT.ts
+++ b/packages/localizations/src/pt-PT.ts
@@ -1398,14 +1398,13 @@ export const ptPT: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1477,6 +1476,7 @@ export const ptPT: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts
index 20d5a8a8107..b372cf79c68 100644
--- a/packages/localizations/src/ro-RO.ts
+++ b/packages/localizations/src/ro-RO.ts
@@ -1398,14 +1398,13 @@ export const roRO: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1477,6 +1476,7 @@ export const roRO: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts
index 216d06bd8f0..07d081dd992 100644
--- a/packages/localizations/src/ru-RU.ts
+++ b/packages/localizations/src/ru-RU.ts
@@ -1392,14 +1392,13 @@ export const ruRU: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1471,6 +1470,7 @@ export const ruRU: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts
index 857dd72424f..fc9169d88d2 100644
--- a/packages/localizations/src/sk-SK.ts
+++ b/packages/localizations/src/sk-SK.ts
@@ -1388,14 +1388,13 @@ export const skSK: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const skSK: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts
index 1e36e637efa..cc7fbb83dfb 100644
--- a/packages/localizations/src/sr-RS.ts
+++ b/packages/localizations/src/sr-RS.ts
@@ -1388,14 +1388,13 @@ export const srRS: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const srRS: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts
index be7b87b178a..4277bb57a62 100644
--- a/packages/localizations/src/sv-SE.ts
+++ b/packages/localizations/src/sv-SE.ts
@@ -1388,14 +1388,13 @@ export const svSE: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const svSE: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts
index 73272043e6e..8f8ee372d62 100644
--- a/packages/localizations/src/ta-IN.ts
+++ b/packages/localizations/src/ta-IN.ts
@@ -1401,14 +1401,13 @@ export const taIN: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1480,6 +1479,7 @@ export const taIN: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts
index 1256ecff435..957f053751c 100644
--- a/packages/localizations/src/te-IN.ts
+++ b/packages/localizations/src/te-IN.ts
@@ -1398,14 +1398,13 @@ export const teIN: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1477,6 +1476,7 @@ export const teIN: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts
index 5a002a7b01b..c98233dba9f 100644
--- a/packages/localizations/src/th-TH.ts
+++ b/packages/localizations/src/th-TH.ts
@@ -1389,14 +1389,13 @@ export const thTH: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1468,6 +1467,7 @@ export const thTH: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts
index f1736ecb0e4..fe69dcdc525 100644
--- a/packages/localizations/src/tr-TR.ts
+++ b/packages/localizations/src/tr-TR.ts
@@ -1388,14 +1388,13 @@ export const trTR: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const trTR: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts
index 73699280b51..e3a16b8ea27 100644
--- a/packages/localizations/src/uk-UA.ts
+++ b/packages/localizations/src/uk-UA.ts
@@ -1388,14 +1388,13 @@ export const ukUA: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1467,6 +1466,7 @@ export const ukUA: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts
index 1fae7626221..8c543c1e108 100644
--- a/packages/localizations/src/vi-VN.ts
+++ b/packages/localizations/src/vi-VN.ts
@@ -1396,14 +1396,13 @@ export const viVN: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1475,6 +1474,7 @@ export const viVN: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts
index a3ac19925ce..2537e98bae0 100644
--- a/packages/localizations/src/zh-CN.ts
+++ b/packages/localizations/src/zh-CN.ts
@@ -1381,14 +1381,13 @@ export const zhCN: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1460,6 +1459,7 @@ export const zhCN: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts
index 54c411d38c2..a8db934fa49 100644
--- a/packages/localizations/src/zh-TW.ts
+++ b/packages/localizations/src/zh-TW.ts
@@ -1384,14 +1384,13 @@ export const zhTW: LocalizationResource = {
badge__active: undefined,
badge__inactive: undefined,
badge__ssoRequired: undefined,
- badge__unconfigured: undefined,
description: undefined,
error__load: undefined,
menuAction__activate: undefined,
menuAction__deactivate: undefined,
menuAction__edit: undefined,
menuAction__remove: undefined,
- primaryButton__startConfiguration: undefined,
+ primaryButton__configure: undefined,
removeDialog: {
confirmButton: undefined,
subtitle: undefined,
@@ -1463,6 +1462,7 @@ export const zhTW: LocalizationResource = {
menuAction__edit: undefined,
menuAction__remove: undefined,
primaryButton__addConnection: undefined,
+ primaryButton__configure: undefined,
primaryButton__continueConfiguration: undefined,
primaryButton__startConfiguration: undefined,
title: undefined,
diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts
index cd015a831ff..588bd91a29f 100644
--- a/packages/shared/src/types/localization.ts
+++ b/packages/shared/src/types/localization.ts
@@ -1255,7 +1255,11 @@ export type __internal_LocalizationResource = {
badge__active: LocalizationValue;
badge__inactive: LocalizationValue;
descriptionLine1: LocalizationValue;
+ /**
+ * @deprecated Use `primaryButton__configure` instead.
+ */
primaryButton__startConfiguration: LocalizationValue;
+ primaryButton__configure: LocalizationValue;
primaryButton__continueConfiguration: LocalizationValue;
primaryButton__addConnection: LocalizationValue;
domainLabel: LocalizationValue;
@@ -1332,13 +1336,12 @@ export type __internal_LocalizationResource = {
};
directorySyncSection: {
title: LocalizationValue;
- badge__unconfigured: LocalizationValue;
badge__ssoRequired: LocalizationValue;
badge__active: LocalizationValue;
badge__inactive: LocalizationValue;
description: LocalizationValue;
error__load: LocalizationValue;
- primaryButton__startConfiguration: LocalizationValue;
+ primaryButton__configure: LocalizationValue;
menuAction__edit: LocalizationValue;
menuAction__activate: LocalizationValue;
menuAction__deactivate: LocalizationValue;
diff --git a/packages/ui/src/common/ProviderIcon.tsx b/packages/ui/src/common/ProviderIcon.tsx
index 36c29883435..05f77e0d05f 100644
--- a/packages/ui/src/common/ProviderIcon.tsx
+++ b/packages/ui/src/common/ProviderIcon.tsx
@@ -7,7 +7,7 @@ import { ProviderInitialIcon } from './ProviderInitialIcon';
type ProviderId = OAuthProvider | Web3Provider | PhoneCodeChannel;
-export const SUPPORTS_MASK_IMAGE = ['agentid', 'apple', 'github', 'okx_wallet', 'vercel', 'x'] as const;
+export const SUPPORTS_MASK_IMAGE = ['agentid', 'apple', 'github', 'okta', 'okx_wallet', 'vercel', 'x'] as const;
export const getEnterpriseProviderIconId = (provider: string) =>
provider.replace(/(oauth_|saml_)/, '').trim() as OAuthProvider;
diff --git a/packages/ui/src/components/ConfigureDirectorySync/SecurityDirectorySyncSection.tsx b/packages/ui/src/components/ConfigureDirectorySync/SecurityDirectorySyncSection.tsx
index 32e333957d2..7d76899ece4 100644
--- a/packages/ui/src/components/ConfigureDirectorySync/SecurityDirectorySyncSection.tsx
+++ b/packages/ui/src/components/ConfigureDirectorySync/SecurityDirectorySyncSection.tsx
@@ -9,10 +9,11 @@ import { Card } from '@/ui/elements/Card';
import { CardStateProvider, useCardState } from '@/ui/elements/contexts';
import { ProfileSection } from '@/ui/elements/Section';
import { ThreeDotsMenu } from '@/ui/elements/ThreeDotsMenu';
+import type { ThemableCssProp } from '@/ui/styledSystem';
import { handleError } from '@/utils/errorHandler';
import type { LocalizationKey } from '../../customizables';
-import { Badge, Button, Col, descriptors, Flex, localizationKeys, Spinner, Text } from '../../customizables';
+import { Badge, Col, descriptors, Flex, localizationKeys, Spinner, Text } from '../../customizables';
import { sortEnterpriseConnections } from '../ConfigureSSO/domain/organizationEnterpriseConnection';
import { ResetConnectionDialog } from '../ConfigureSSO/ResetConnectionDialog';
@@ -25,19 +26,15 @@ type SecurityDirectorySyncSectionProps = {
type DirectorySyncStatus = 'unconfigured' | 'active' | 'inactive';
const STATUS_BADGES: Record<
- DirectorySyncStatus,
+ Exclude,
{ colorScheme: 'primary' | 'success' | 'warning'; label: LocalizationKey }
> = {
- unconfigured: {
- colorScheme: 'primary',
- label: localizationKeys('organizationProfile.securityPage.directorySyncSection.badge__unconfigured'),
- },
active: {
- colorScheme: 'success',
+ colorScheme: 'primary',
label: localizationKeys('organizationProfile.securityPage.directorySyncSection.badge__active'),
},
inactive: {
- colorScheme: 'warning',
+ colorScheme: 'primary',
label: localizationKeys('organizationProfile.securityPage.directorySyncSection.badge__inactive'),
},
};
@@ -71,24 +68,14 @@ export const SecurityDirectorySyncSection = ({
// The hook maps a 404 (no directory yet) to `data: null`, so any error here is unexpected.
const isLoading = isLoadingConnections || (Boolean(connection) && isLoadingDirectory);
const error = connectionsError ?? directoryError;
- const isSettled = !isLoading && !error;
const status: DirectorySyncStatus = directory ? (directory.enabled ? 'active' : 'inactive') : 'unconfigured';
- const badge = STATUS_BADGES[status];
return (
- ) : undefined
- }
>
{isLoading ? (
-
-
-
+ )}
+
+
- {!hasSsoConnection && (
-
- )}
-
+ ({ paddingInlineStart: `calc(${t.space.$2x5} + ${t.sizes.$4} + ${t.space.$2})` })} />
+
) : (
@@ -191,14 +173,19 @@ const ConfiguredContent = ({
}
};
+ const badge = STATUS_BADGES[isActive ? 'active' : 'inactive'];
+
return (
-
+
(
+const Description = ({ sx }: { sx?: ThemableCssProp }): JSX.Element => (
);
diff --git a/packages/ui/src/components/ConfigureSSO/domain/providers.ts b/packages/ui/src/components/ConfigureSSO/domain/providers.ts
index c1e2bedb13e..1619b2a3008 100644
--- a/packages/ui/src/components/ConfigureSSO/domain/providers.ts
+++ b/packages/ui/src/components/ConfigureSSO/domain/providers.ts
@@ -55,6 +55,9 @@ export const PROVIDER_GROUPS: ReadonlyArray = [
export const providerLabel = (provider: ProviderType): LocalizationKey | undefined =>
PROVIDER_GROUPS.flatMap(group => group.options).find(option => option.id === provider)?.label;
+export const providerIconId = (provider: ProviderType): string | undefined =>
+ PROVIDER_GROUPS.flatMap(group => group.options).find(option => option.id === provider)?.iconId;
+
/** Every OIDC variant is presented as the single OIDC card. */
export const toProviderCard = (provider: EnterpriseConnectionProviderType): ProviderType =>
isOidcProvider(provider) ? 'oidc_custom' : provider;
diff --git a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx
index 2462c7fc37b..48a61878dfb 100644
--- a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx
+++ b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx
@@ -1,6 +1,8 @@
import { iconImageUrl } from '@clerk/shared/constants';
+import type { OAuthProvider } from '@clerk/shared/types';
import React from 'react';
+import { ProviderIcon } from '@/common';
import type { LocalizationKey } from '@/customizables';
import {
Box,
@@ -10,7 +12,6 @@ import {
Grid,
localizationKeys,
RadioInput,
- Span,
Text,
useLocalizations,
} from '@/customizables';
@@ -26,8 +27,6 @@ import { Step } from '../elements/Step';
import { useWizard } from '../elements/Wizard';
import type { ProviderType } from '../types';
-const MONOCHROMATIC_PROVIDER_ICONS: ReadonlySet = new Set(['okta']);
-
export const SelectProviderStep = (): JSX.Element => {
const {
organizationEnterpriseConnection: c,
@@ -274,31 +273,14 @@ const ProviderCard = ({ name, value, iconId, label, checked, onChange }: Provide
sx={common.visuallyHidden()}
/>
- {
- const isMonochromatic = MONOCHROMATIC_PROVIDER_ICONS.has(iconId);
- const baseSize = { width: theme.sizes.$8, height: theme.sizes.$8 };
- if (isMonochromatic) {
- return {
- ...baseSize,
- backgroundColor: theme.colors.$colorForeground,
- maskImage: `url(${iconImageUrl(iconId)})`,
- maskSize: 'contain',
- maskPosition: 'center',
- maskRepeat: 'no-repeat',
- };
- }
- return {
- ...baseSize,
- backgroundImage: `url(${iconImageUrl(iconId)})`,
- backgroundSize: 'contain',
- backgroundPosition: 'center',
- backgroundRepeat: 'no-repeat',
- };
- }}
/>
{
+ const iconId = providerIconId(toProviderCard(connection.provider as EnterpriseConnectionProviderType));
+ const iconUrl = iconId ? iconImageUrl(iconId) : connection.logoPublicUrl?.trim();
+
+ return (
+
+ );
+};
diff --git a/packages/ui/src/components/OrganizationProfile/EnterpriseConnectionPage/DangerZoneSection.tsx b/packages/ui/src/components/OrganizationProfile/EnterpriseConnectionPage/DangerZoneSection.tsx
deleted file mode 100644
index 901e9d40b2d..00000000000
--- a/packages/ui/src/components/OrganizationProfile/EnterpriseConnectionPage/DangerZoneSection.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import type { EnterpriseConnectionResource } from '@clerk/shared/types';
-import { useState } from 'react';
-
-import { Card } from '@/elements/Card';
-import { CardStateProvider, useCardState } from '@/elements/contexts';
-import { ProfileSection } from '@/elements/Section';
-import { handleError } from '@/utils/errorHandler';
-
-import { localizationKeys } from '../../../customizables';
-import type { ThemableCssProp } from '../../../styledSystem';
-import type { EnterpriseConnectionMutations } from '../../ConfigureSSO/hooks/useOrganizationEnterpriseConnection';
-import { ResetConnectionDialog } from '../../ConfigureSSO/ResetConnectionDialog';
-
-type DangerZoneSectionProps = {
- connection: EnterpriseConnectionResource;
- enterpriseConnectionMutations: EnterpriseConnectionMutations;
- organizationName: string;
- contentRef: React.RefObject;
- onBack: () => void;
-};
-
-export const DangerZoneSection = (props: DangerZoneSectionProps): JSX.Element => (
-
- {/* Own card state so a failed deactivation reports here instead of in the page header. */}
-
-
-
-
-);
-
-const itemSx: ThemableCssProp = t => ({
- paddingTop: 0,
- paddingBottom: 0,
- paddingInlineStart: t.space.$1,
-});
-
-const DangerZoneActions = ({
- connection,
- enterpriseConnectionMutations: { setConnectionActive, deleteConnection },
- organizationName,
- contentRef,
- onBack,
-}: DangerZoneSectionProps): JSX.Element => {
- const card = useCardState();
- const [isDialogOpen, setIsDialogOpen] = useState(false);
-
- const onDeactivate = async () => {
- if (card.isLoading) {
- return;
- }
-
- card.setError(undefined);
- card.setLoading();
-
- try {
- await setConnectionActive(connection.id, false);
- } catch (err) {
- handleError(err as Error, [], card.setError);
- } finally {
- card.setIdle();
- }
- };
-
- return (
- <>
-
- {connection.active && (
-
- void onDeactivate()}
- localizationKey={localizationKeys(
- 'organizationProfile.securityPage.connectionPage.dangerZone.deactivateButton',
- )}
- />
-
- )}
-
-
- setIsDialogOpen(true)}
- localizationKey={localizationKeys(
- 'organizationProfile.securityPage.connectionPage.dangerZone.removeButton',
- )}
- />
-
-
-
- {card.error}
-
- setIsDialogOpen(false)}
- confirmationValue={organizationName}
- title={localizationKeys('organizationProfile.securityPage.removeDialog.title')}
- subtitle={localizationKeys('organizationProfile.securityPage.removeDialog.subtitle', {
- name: connection.name,
- })}
- confirmButtonLabel={localizationKeys('organizationProfile.securityPage.removeDialog.confirmButton')}
- onDelete={async () => {
- await deleteConnection(connection.id);
- onBack();
- }}
- contentRef={contentRef}
- />
- >
- );
-};
diff --git a/packages/ui/src/components/OrganizationProfile/EnterpriseConnectionPage/index.tsx b/packages/ui/src/components/OrganizationProfile/EnterpriseConnectionPage/index.tsx
index 8915ab99820..b7b8a686fdb 100644
--- a/packages/ui/src/components/OrganizationProfile/EnterpriseConnectionPage/index.tsx
+++ b/packages/ui/src/components/OrganizationProfile/EnterpriseConnectionPage/index.tsx
@@ -1,21 +1,17 @@
import type { EnterpriseConnectionResource } from '@clerk/shared/types';
-import { Card } from '@/elements/Card';
-import { useCardState, withCardStateProvider } from '@/elements/contexts';
import { Header } from '@/elements/Header';
import { ProfileCard } from '@/elements/ProfileCard';
-import { handleError } from '@/utils/errorHandler';
-import { getEnterpriseProviderIconId, ProviderIcon } from '../../../common';
-import { Badge, Button, Col, descriptors, Flex, localizationKeys, Text } from '../../../customizables';
+import { Badge, Col, descriptors, Flex, Text } from '../../../customizables';
import { isOidcProvider } from '../../ConfigureSSO/domain/organizationEnterpriseConnection';
import { providerLabel, toProviderCard } from '../../ConfigureSSO/domain/providers';
import type { EnterpriseConnectionMutations } from '../../ConfigureSSO/hooks/useOrganizationEnterpriseConnection';
import { useOrganizationEnterpriseConnectionStatus } from '../../ConfigureSSO/hooks/useOrganizationEnterpriseConnectionStatus';
import type { EnterpriseConnectionProviderType } from '../../ConfigureSSO/types';
+import { EnterpriseConnectionIcon } from '../EnterpriseConnectionIcon';
import { STATUS_BADGES } from '../enterpriseConnectionStatusBadges';
import { SecurityBackControl } from '../SecurityBackControl';
-import { DangerZoneSection } from './DangerZoneSection';
import { DomainsSection } from './DomainsSection';
import { IdentityProviderSection } from './IdentityProviderSection';
import { NameSection } from './NameSection';
@@ -25,115 +21,68 @@ import { SettingsSection } from './SettingsSection';
export type EnterpriseConnectionPageProps = {
connection: EnterpriseConnectionResource;
enterpriseConnectionMutations: EnterpriseConnectionMutations;
- organizationName: string;
- contentRef: React.RefObject;
onBack: () => void;
- /** Opens the wizard scoped to this connection, resuming at its furthest-reachable step. */
- onOpenWizard: () => void;
};
-export const EnterpriseConnectionPage = withCardStateProvider(
- ({
- connection,
- enterpriseConnectionMutations,
- organizationName,
- contentRef,
- onBack,
- onOpenWizard,
- }: EnterpriseConnectionPageProps): JSX.Element => {
- const { updateConnection } = enterpriseConnectionMutations;
- const isOidc = isOidcProvider(connection.provider);
-
- return (
-
+export const EnterpriseConnectionPage = ({
+ connection,
+ enterpriseConnectionMutations: { updateConnection },
+ onBack,
+}: EnterpriseConnectionPageProps): JSX.Element => {
+ const isOidc = isOidcProvider(connection.provider);
+
+ return (
+
+ ({ gap: t.space.$8 })}
+ >
({ gap: t.space.$8 })}
+ elementDescriptor={descriptors.profilePage}
+ elementId={descriptors.profilePage.setId('organizationSecurity')}
>
-
-
-
-
+
-
+
- {isOidc ? (
-
- ) : (
-
- )}
+
-
+ {isOidc ? (
+
+ ) : (
+
+ )}
-
+
-
-
+
-
- );
- },
-);
+
+
+ );
+};
-type ConnectionHeaderProps = Pick<
- EnterpriseConnectionPageProps,
- 'connection' | 'enterpriseConnectionMutations' | 'onBack' | 'onOpenWizard'
->;
+type ConnectionHeaderProps = Pick;
-const ConnectionHeader = ({
- connection,
- enterpriseConnectionMutations: { setConnectionActive },
- onBack,
- onOpenWizard,
-}: ConnectionHeaderProps): JSX.Element => {
- const card = useCardState();
+const ConnectionHeader = ({ connection, onBack }: ConnectionHeaderProps): JSX.Element => {
const { status } = useOrganizationEnterpriseConnectionStatus(connection);
const badge = STATUS_BADGES[status];
const label = providerLabel(toProviderCard(connection.provider as EnterpriseConnectionProviderType));
- const onActivate = async () => {
- if (card.isLoading) {
- return;
- }
-
- card.setError(undefined);
- card.setLoading();
-
- try {
- // The mutation revalidates before resolving, so the refreshed entity drives the settled UI.
- await setConnectionActive(connection.id, true);
- } catch (err) {
- handleError(err as Error, [], card.setError);
- } finally {
- card.setIdle();
- }
- };
-
return (
({ gap: t.space.$4, marginBottom: t.space.$4 })}>
@@ -145,12 +94,7 @@ const ConnectionHeader = ({
wrap='wrap'
sx={t => ({ gap: t.space.$2 })}
>
-
+
{connection.name}
@@ -169,29 +113,7 @@ const ConnectionHeader = ({
colorScheme={badge.colorScheme}
localizationKey={badge.label}
/>
-
- {status === 'active' ? null : status === 'inactive' ? (
-
-
- {card.error}
);
};
diff --git a/packages/ui/src/components/OrganizationProfile/OrganizationSecurityPage.tsx b/packages/ui/src/components/OrganizationProfile/OrganizationSecurityPage.tsx
index 5c651ce7e1f..ccf3b63e763 100644
--- a/packages/ui/src/components/OrganizationProfile/OrganizationSecurityPage.tsx
+++ b/packages/ui/src/components/OrganizationProfile/OrganizationSecurityPage.tsx
@@ -22,11 +22,9 @@ type OrganizationSecurityPageProps = {
contentRef: React.RefObject;
};
-type WizardReturnTo = { kind: 'overview' } | { kind: 'connection'; id: string };
-
type SecurityPageView =
| { kind: 'overview' }
- | { kind: 'wizard'; forceInitialStep: boolean; returnTo: WizardReturnTo }
+ | { kind: 'wizard'; forceInitialStep: boolean }
| { kind: 'connection'; id: string }
| { kind: 'directorySync' }
| { kind: 'ssoBypass' };
@@ -70,13 +68,9 @@ const OrganizationSecurityPageContent = ({ contentRef }: OrganizationSecurityPag
const exitToOverview = () => setRequestedView({ kind: 'overview' });
- const openWizard = (
- scope: ConnectionScope,
- forceInitialStep = false,
- returnTo: WizardReturnTo = { kind: 'overview' },
- ) => {
+ const openWizard = (scope: ConnectionScope, forceInitialStep = false) => {
selectConnection(scope);
- setRequestedView({ kind: 'wizard', forceInitialStep, returnTo });
+ setRequestedView({ kind: 'wizard', forceInitialStep });
};
const openConnection = (id: string) => setRequestedView({ kind: 'connection', id });
@@ -133,28 +127,12 @@ const OrganizationSecurityPageContent = ({ contentRef }: OrganizationSecurityPag
- openWizard({ kind: 'existing', id: openedConnection.id }, false, {
- kind: 'connection',
- id: openedConnection.id,
- })
- }
/>
);
}
if (view.kind === 'wizard') {
- const { returnTo } = view;
- const exitWizard = () =>
- setRequestedView(
- returnTo.kind === 'connection' && enterpriseConnections.some(connection => connection.id === returnTo.id)
- ? returnTo
- : { kind: 'overview' },
- );
-
return (
}
- onExit={exitWizard}
+ title={}
+ onExit={exitToOverview}
/>
);
}
@@ -178,6 +156,9 @@ const OrganizationSecurityPageContent = ({ contentRef }: OrganizationSecurityPag
diff --git a/packages/ui/src/components/OrganizationProfile/SecuritySsoSection.tsx b/packages/ui/src/components/OrganizationProfile/SecuritySsoSection.tsx
index 184e6fc22fd..717ee7a9295 100644
--- a/packages/ui/src/components/OrganizationProfile/SecuritySsoSection.tsx
+++ b/packages/ui/src/components/OrganizationProfile/SecuritySsoSection.tsx
@@ -1,13 +1,17 @@
import type { EnterpriseConnectionResource } from '@clerk/shared/types';
+import { useState } from 'react';
+import { Card } from '@/ui/elements/Card';
+import { CardStateProvider, useCardState } from '@/ui/elements/contexts';
import { ProfileSection } from '@/ui/elements/Section';
+import { ThreeDotsMenu } from '@/ui/elements/ThreeDotsMenu';
import { Tooltip } from '@/ui/elements/Tooltip';
+import type { ThemableCssProp } from '@/ui/styledSystem';
+import { handleError } from '@/utils/errorHandler';
-import { getEnterpriseProviderIconId, ProviderIcon } from '../../common';
import { useEnvironment } from '../../contexts';
import {
Badge,
- Box,
Button,
Col,
descriptors,
@@ -18,21 +22,30 @@ import {
useLocalizations,
} from '../../customizables';
import { useFetchRoles, useLocalizeCustomRoles } from '../../hooks/useFetchRoles';
-import { ChevronRight, InformationCircle } from '../../icons';
+import { InformationCircle } from '../../icons';
import type { ConnectionScope } from '../ConfigureSSO/domain/connectionScope';
import { providerLabel, toProviderCard } from '../ConfigureSSO/domain/providers';
+import type { EnterpriseConnectionMutations } from '../ConfigureSSO/hooks/useOrganizationEnterpriseConnection';
import { useOrganizationEnterpriseConnectionStatus } from '../ConfigureSSO/hooks/useOrganizationEnterpriseConnectionStatus';
+import { ResetConnectionDialog } from '../ConfigureSSO/ResetConnectionDialog';
import type { EnterpriseConnectionProviderType } from '../ConfigureSSO/types';
+import { EnterpriseConnectionIcon } from './EnterpriseConnectionIcon';
import { STATUS_BADGES } from './enterpriseConnectionStatusBadges';
type SecuritySsoSectionProps = {
enterpriseConnections: EnterpriseConnectionResource[];
+ enterpriseConnectionMutations: EnterpriseConnectionMutations;
+ organizationName: string;
+ contentRef: React.RefObject;
onConfigure?: (scope: ConnectionScope, forceInitialStep?: boolean) => void;
onOpenConnection?: (id: string) => void;
};
export const SecuritySsoSection = ({
enterpriseConnections,
+ enterpriseConnectionMutations,
+ organizationName,
+ contentRef,
onConfigure,
onOpenConnection,
}: SecuritySsoSectionProps): JSX.Element => {
@@ -41,189 +54,233 @@ export const SecuritySsoSection = ({
title={localizationKeys('organizationProfile.securityPage.ssoSection.title')}
id='sso'
centered={false}
- badge={
-
-
- {enterpriseConnections.length === 0 ? (
-
- ) : undefined}
-
- }
+ badge={}
>
- {enterpriseConnections.length === 0 ? (
-
-
-
- {onConfigure && (
- onConfigure({ kind: 'new' }, true)}
- localizationKey={localizationKeys(
- 'organizationProfile.securityPage.ssoSection.primaryButton__startConfiguration',
- )}
- />
- )}
-
- ) : (
-
-
-
+
+ {enterpriseConnections.length > 0 && (
{enterpriseConnections.map(connection => (
-
+
+
+
))}
+ )}
+
{onConfigure && (
onConfigure({ kind: 'new' }, true)}
/>
)}
+ ({ paddingInlineStart: `calc(${t.space.$2x5} + ${t.sizes.$4} + ${t.space.$2})` })
+ : undefined
+ }
+ />
- )}
+
);
};
-type ConnectionRowProps = {
+type ConnectionRowProps = Omit & {
connection: EnterpriseConnectionResource;
- onOpenConnection?: (id: string) => void;
};
-const ConnectionRow = ({ connection, onOpenConnection }: ConnectionRowProps): JSX.Element => {
+const ConnectionRow = ({
+ connection,
+ enterpriseConnectionMutations: { setConnectionActive, deleteConnection },
+ organizationName,
+ contentRef,
+ onConfigure,
+ onOpenConnection,
+}: ConnectionRowProps): JSX.Element => {
+ const card = useCardState();
+ const [isRemoveDialogOpen, setIsRemoveDialogOpen] = useState(false);
const { status } = useOrganizationEnterpriseConnectionStatus(connection, { probe: false });
const badge = STATUS_BADGES[status];
const label = providerLabel(toProviderCard(connection.provider as EnterpriseConnectionProviderType));
- const item = (
-
- ({ minWidth: 0, flex: 1, gap: t.space.$2 })}
- >
-
+ const onSetActive = async (active: boolean) => {
+ if (card.isLoading) {
+ return;
+ }
-
- {connection.name}
- {label && (
-
- )}
-
+ card.setError(undefined);
+ card.setLoading();
+
+ try {
+ await setConnectionActive(connection.id, active);
+ } catch (err) {
+ handleError(err as Error, [], card.setError);
+ } finally {
+ card.setIdle();
+ }
+ };
- {connection.domains.length > 0 && (
+ const actions =
+ onConfigure && onOpenConnection
+ ? [
+ {
+ label: localizationKeys('organizationProfile.securityPage.ssoSection.menuAction__edit'),
+ onClick: () => onOpenConnection(connection.id),
+ },
+ ...(status === 'in_progress'
+ ? [
+ {
+ label: localizationKeys('organizationProfile.securityPage.ssoSection.menuAction__continue'),
+ onClick: () => onConfigure({ kind: 'existing', id: connection.id }),
+ },
+ ]
+ : []),
+ ...(status === 'active'
+ ? [
+ {
+ label: localizationKeys('organizationProfile.securityPage.ssoSection.menuAction__deactivate'),
+ isDisabled: card.isLoading,
+ onClick: () => void onSetActive(false),
+ },
+ ]
+ : []),
+ ...(status === 'inactive'
+ ? [
+ {
+ label: localizationKeys('organizationProfile.securityPage.ssoSection.menuAction__activate'),
+ isDisabled: card.isLoading,
+ onClick: () => void onSetActive(true),
+ },
+ ]
+ : []),
+ {
+ label: localizationKeys('organizationProfile.securityPage.ssoSection.menuAction__remove'),
+ isDestructive: true,
+ onClick: () => setIsRemoveDialogOpen(true),
+ },
+ ]
+ : undefined;
+
+ return (
+
+
+ ({ minWidth: 0, flex: 1, gap: t.space.$3 })}
+ >
({ minWidth: 0, gap: t.space.$1x5 })}
+ justify='center'
+ sx={t => ({
+ flexShrink: 0,
+ width: t.sizes.$10,
+ height: t.sizes.$10,
+ borderRadius: t.radii.$md,
+ borderWidth: t.borderWidths.$normal,
+ borderStyle: t.borderStyles.$solid,
+ borderColor: t.colors.$borderAlpha150,
+ backgroundColor: t.colors.$colorBackground,
+ })}
>
- {connection.domains.map(domain => (
-
- {domain}
-
- ))}
+
- )}
-
- ({ gap: t.space.$2 })}
- >
-
+
+ {connection.name}
+ {connection.domains.length > 0 ? (
+
+ {connection.domains.join(', ')}
+
+ ) : (
+ label && (
+
+ )
+ )}
+
+
- {onOpenConnection && (
- ({ width: t.sizes.$4, height: t.sizes.$4, color: t.colors.$colorMutedForeground })}
+ ({ gap: t.space.$2 })}
+ >
+
- )}
-
-
- );
- if (!onOpenConnection) {
- return (
-
- {item}
-
- );
- }
+ {actions && (
+
+ )}
+
+
- return (
- onOpenConnection(connection.id)}
- sx={{ display: 'block', width: '100%', height: 'auto', padding: 0, textAlign: 'start' }}
- >
- {item}
-
+ {card.error}
+
+ {actions && (
+ setIsRemoveDialogOpen(false)}
+ confirmationValue={organizationName}
+ title={localizationKeys('organizationProfile.securityPage.removeDialog.title')}
+ subtitle={localizationKeys('organizationProfile.securityPage.removeDialog.subtitle', {
+ name: connection.name,
+ })}
+ confirmButtonLabel={localizationKeys('organizationProfile.securityPage.removeDialog.confirmButton')}
+ onDelete={() => deleteConnection(connection.id)}
+ contentRef={contentRef}
+ />
+ )}
+
);
};
-const SsoDescription = (): JSX.Element => (
+const SsoDescription = ({ sx }: { sx?: ThemableCssProp }): JSX.Element => (
);
diff --git a/packages/ui/src/components/OrganizationProfile/__tests__/EnterpriseConnectionPage.test.tsx b/packages/ui/src/components/OrganizationProfile/__tests__/EnterpriseConnectionPage.test.tsx
index bc5d85c0843..004f1677179 100644
--- a/packages/ui/src/components/OrganizationProfile/__tests__/EnterpriseConnectionPage.test.tsx
+++ b/packages/ui/src/components/OrganizationProfile/__tests__/EnterpriseConnectionPage.test.tsx
@@ -87,16 +87,12 @@ const renderPage = (
fixtures: any,
connection: any,
onBack = vi.fn(),
- onOpenWizard = vi.fn(),
) => {
const page = (next: any) => (
);
@@ -104,7 +100,6 @@ const renderPage = (
return {
onBack,
- onOpenWizard,
...result,
rerenderWith: (next: any) => result.rerender(page(next)),
};
@@ -132,8 +127,8 @@ describe('EnterpriseConnectionPage', () => {
expect(screen.getByText('Service provider')).toBeInTheDocument();
expect(screen.getByText('Identity provider')).toBeInTheDocument();
expect(screen.getByText('Settings')).toBeInTheDocument();
- expect(screen.getByText('Danger zone')).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'Remove connection' })).toBeInTheDocument();
+ expect(screen.queryByText('Danger zone')).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Remove connection' })).not.toBeInTheDocument();
expect(screen.getByDisplayValue('https://accounts.clerk.com/v1/acs')).toBeInTheDocument();
expect(screen.getByDisplayValue('https://accounts.clerk.com/saml/ent_1')).toBeInTheDocument();
@@ -231,97 +226,22 @@ describe('EnterpriseConnectionPage', () => {
});
});
- describe('header actions', () => {
- it('offers no header action for an active connection', async () => {
+ describe('header', () => {
+ it.each([
+ ['active', { active: true }],
+ ['inactive', { active: false }],
+ ['mid-setup', { samlConnection: null, oauthConfig: null }],
+ ])('offers no lifecycle actions for a %s connection', async (_, overrides) => {
const { wrapper, fixtures } = await createFixtures(withPageFixtures);
withNoTestRuns(fixtures);
- renderPage(wrapper, fixtures, samlConnection({ active: true }));
+ renderPage(wrapper, fixtures, samlConnection(overrides));
expect(await screen.findByRole('heading', { name: 'clerk.com' })).toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'Activate' })).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Deactivate' })).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'Continue setup' })).not.toBeInTheDocument();
- });
-
- it('activates an inactive connection', async () => {
- const { wrapper, fixtures } = await createFixtures(withPageFixtures);
- withNoTestRuns(fixtures);
- fixtures.clerk.organization?.getEnterpriseConnectionTestRuns.mockResolvedValue({
- data: [{ id: 'run_1', status: 'success' }],
- total_count: 1,
- } as any);
- fixtures.clerk.organization?.updateEnterpriseConnection.mockResolvedValue({ active: true } as any);
-
- const { userEvent } = renderPage(wrapper, fixtures, samlConnection({ active: false }));
-
- await userEvent.click(await screen.findByRole('button', { name: 'Activate' }));
-
- expect(fixtures.clerk.organization?.updateEnterpriseConnection).toHaveBeenCalledWith('ent_1', { active: true });
- });
-
- it('offers Continue setup for a connection that is still mid-setup', async () => {
- const { wrapper, fixtures } = await createFixtures(withPageFixtures);
- withNoTestRuns(fixtures);
-
- const { userEvent, onOpenWizard } = renderPage(
- wrapper,
- fixtures,
- samlConnection({ samlConnection: null, oauthConfig: null }),
- );
-
- await userEvent.click(await screen.findByRole('button', { name: 'Continue setup' }));
-
- expect(onOpenWizard).toHaveBeenCalled();
- expect(screen.queryByRole('button', { name: 'Open setup wizard' })).not.toBeInTheDocument();
- });
- });
-
- describe('danger zone', () => {
- it('deactivates an active connection', async () => {
- const { wrapper, fixtures } = await createFixtures(withPageFixtures);
- withNoTestRuns(fixtures);
- fixtures.clerk.organization?.updateEnterpriseConnection.mockResolvedValue({ active: false } as any);
-
- const { userEvent } = renderPage(wrapper, fixtures, samlConnection({ active: true }));
-
- await userEvent.click(await screen.findByRole('button', { name: 'Deactivate connection' }));
-
- expect(fixtures.clerk.organization?.updateEnterpriseConnection).toHaveBeenCalledWith('ent_1', { active: false });
- });
-
- it('offers no Deactivate connection button for an inactive connection', async () => {
- const { wrapper, fixtures } = await createFixtures(withPageFixtures);
- withNoTestRuns(fixtures);
-
- renderPage(wrapper, fixtures, samlConnection({ active: false }));
-
- expect(await screen.findByRole('button', { name: 'Remove connection' })).toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'Deactivate connection' })).not.toBeInTheDocument();
- });
-
- it('removes the connection from the danger zone and returns to the overview', async () => {
- const { wrapper, fixtures } = await createFixtures(withPageFixtures);
- withNoTestRuns(fixtures);
- fixtures.clerk.organization?.deleteEnterpriseConnection.mockResolvedValue({} as any);
-
- const { userEvent, onBack } = renderPage(wrapper, fixtures, samlConnection({ active: true }));
-
- expect(await screen.findAllByRole('button', { name: 'Remove connection' })).toHaveLength(1);
- await userEvent.click(screen.getByRole('button', { name: 'Remove connection' }));
-
- const dialog = within(await screen.findByRole('dialog'));
- expect(dialog.getByRole('heading', { name: 'Remove SSO connection' })).toBeInTheDocument();
- expect(dialog.getByText(/Are you sure you want to remove the connection "clerk.com"\?/i)).toBeInTheDocument();
-
- await userEvent.type(dialog.getByLabelText(/below to continue/i), 'Org1');
- await waitFor(() => expect(dialog.getByRole('button', { name: 'Remove connection' })).toBeEnabled());
- await userEvent.click(dialog.getByRole('button', { name: 'Remove connection' }));
-
- await waitFor(() => {
- expect(fixtures.clerk.organization?.deleteEnterpriseConnection).toHaveBeenCalledWith('ent_1');
- });
- expect(onBack).toHaveBeenCalled();
+ expect(screen.queryByRole('button', { name: 'Remove connection' })).not.toBeInTheDocument();
});
});
diff --git a/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationProfile.test.tsx b/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationProfile.test.tsx
index 0027468d9e1..cc8799f07ad 100644
--- a/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationProfile.test.tsx
+++ b/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationProfile.test.tsx
@@ -594,7 +594,7 @@ describe('OrganizationProfile', () => {
renderSecurityRoute(wrapper);
expect(await screen.findByText(SECURITY_DESCRIPTION)).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'Start configuration' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'Configure' })).toBeInTheDocument();
});
it('blocks the security page on the guarded route when the user lacks the manage enterprise connections permission', async () => {
@@ -608,7 +608,7 @@ describe('OrganizationProfile', () => {
expect(fixtures.clerk.organization?.getEnterpriseConnections).not.toHaveBeenCalled();
expect(screen.queryByRole('heading', { name: 'Security' })).not.toBeInTheDocument();
expect(screen.queryByText(SECURITY_DESCRIPTION)).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Start configuration' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Configure' })).not.toBeInTheDocument();
});
});
diff --git a/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationSecurityPage.test.tsx b/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationSecurityPage.test.tsx
index f0f815460e9..ffa51a203a0 100644
--- a/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationSecurityPage.test.tsx
+++ b/packages/ui/src/components/OrganizationProfile/__tests__/OrganizationSecurityPage.test.tsx
@@ -1,4 +1,5 @@
import { ClerkAPIResponseError } from '@clerk/shared/error';
+import { within } from '@testing-library/react';
import { describe, expect, it, vi } from 'vitest';
import { bindCreateFixtures } from '@/test/create-fixtures';
@@ -47,12 +48,37 @@ const configuredConnection = (overrides: Record = {}) =>
...overrides,
}) as any;
+const section = (id: 'sso' | 'directorySync') =>
+ within(document.querySelector(`.cl-profileSection__${id}`) as HTMLElement);
+
+const findMenuButtons = (id: 'sso' | 'directorySync') =>
+ waitFor(() => {
+ const buttons = section(id).getAllByRole('button', { name: /open menu/i });
+ expect(buttons.length).toBeGreaterThan(0);
+ return buttons;
+ });
+
+const openConnectionMenu = async (userEvent: ReturnType['userEvent'], index = 0) => {
+ const buttons = await findMenuButtons('sso');
+ await userEvent.click(buttons[index]);
+};
+
+const openConnectionPage = async (userEvent: ReturnType['userEvent'], index = 0) => {
+ await openConnectionMenu(userEvent, index);
+ await userEvent.click(await screen.findByRole('menuitem', { name: 'Edit' }));
+};
+
+const openDirectorySyncMenu = async (userEvent: ReturnType['userEvent']) => {
+ const [button] = await findMenuButtons('directorySync');
+ await userEvent.click(button);
+};
+
const renderPage = (wrapper: React.ComponentType<{ children?: React.ReactNode }>) =>
render(, { wrapper });
describe('OrganizationSecurityPage', () => {
describe('overview states', () => {
- it('renders the unconfigured state with a Start configuration action', async () => {
+ it('renders the unconfigured state with a Configure action', async () => {
const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([]);
@@ -60,19 +86,19 @@ describe('OrganizationSecurityPage', () => {
renderPage(wrapper);
// The "Security" header now also renders during the loading placeholder, so
- // wait on the settled badge before asserting the page chrome and content.
- expect(await screen.findByText('Unconfigured')).toBeInTheDocument();
+ // wait on the settled action before asserting the page chrome and content.
+ expect(await screen.findByRole('button', { name: 'Configure' })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Security' })).toBeInTheDocument();
expect(screen.getByText('SSO')).toBeInTheDocument();
expect(screen.getByText(DESCRIPTION_LINE_1)).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'Start configuration' })).toBeInTheDocument();
+ expect(screen.queryByText('Unconfigured')).not.toBeInTheDocument();
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
expect(screen.queryByText(/select your identity provider/i)).not.toBeInTheDocument();
});
- it('renders the in-progress state as a clickable row', async () => {
+ it('renders the in-progress state as a row with a menu', async () => {
const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
// A connection without SAML configuration is mid-setup.
@@ -91,8 +117,8 @@ describe('OrganizationSecurityPage', () => {
expect(screen.queryByText(/you have started a configuration/i)).not.toBeInTheDocument();
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
- expect(screen.getByRole('button', { name: /clerk\.com/ })).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: /clerk\.com/ })).not.toBeInTheDocument();
+ expect(screen.getByRole('button', { name: /open menu/i })).toBeInTheDocument();
});
it('renders the active state as a condensed overview with the domains', async () => {
@@ -108,19 +134,21 @@ describe('OrganizationSecurityPage', () => {
expect(await screen.findByText('Active')).toBeInTheDocument();
expect(screen.getByText(DESCRIPTION_LINE_1)).toBeInTheDocument();
+ expect(screen.getByLabelText('clerk.com icon')).toBeInTheDocument();
+ expect(screen.queryByText('C')).not.toBeInTheDocument();
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
expect(screen.queryByText(/^Domains:?$/)).not.toBeInTheDocument();
expect(screen.getAllByText('clerk.com').length).toBeGreaterThan(0);
- expect(screen.getByRole('button', { name: /clerk\.com/ })).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Start configuration' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: /clerk\.com/ })).not.toBeInTheDocument();
+ expect(screen.getByRole('button', { name: /open menu/i })).toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Configure' })).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'Continue configuration' })).not.toBeInTheDocument();
});
- it('renders the inactive state with a chip per domain', async () => {
+ it('renders the inactive state with every domain in the caption', async () => {
const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([
@@ -136,11 +164,9 @@ describe('OrganizationSecurityPage', () => {
expect(await screen.findByText('Inactive')).toBeInTheDocument();
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
+ expect(screen.getByRole('button', { name: /open menu/i })).toBeInTheDocument();
- for (const domain of ['github.com', 'gmail.com', 'maps.com', 'another.com']) {
- expect(screen.getByText(domain)).toBeInTheDocument();
- }
+ expect(screen.getByText('github.com, gmail.com, maps.com, another.com')).toBeInTheDocument();
});
it('renders the full value for long domains', async () => {
@@ -205,7 +231,7 @@ describe('OrganizationSecurityPage', () => {
});
describe('view switching', () => {
- it('opens the wizard at the first step when Start configuration is clicked', async () => {
+ it('opens the wizard at the first step when Configure is clicked', async () => {
const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([]);
@@ -213,43 +239,14 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: 'Start configuration' }));
+ await userEvent.click(await screen.findByRole('button', { name: 'Configure' }));
// Start forces the first step. The fixture domain is already verified, so
// without the forced entry the wizard would skip to select-provider —
// proving Start threads `forceInitialStep`.
expect(await screen.findByRole('heading', { name: /add SSO domains/i })).toBeInTheDocument();
expect(screen.queryByText(/select your identity provider/i)).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Start configuration' })).not.toBeInTheDocument();
- });
-
- it("resumes the wizard at the reachable step from the connection page's Continue setup", async () => {
- const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
-
- // A connection without SAML configuration is mid-setup (in_progress).
- fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([
- configuredConnection({ samlConnection: null }),
- ]);
- fixtures.clerk.organization?.getEnterpriseConnectionTestRuns.mockResolvedValue({
- data: [],
- total_count: 0,
- } as any);
- fixtures.clerk.organization?.getDomains.mockResolvedValue({ data: [verifiedDomain], total_count: 1 } as any);
-
- const { userEvent } = renderPage(wrapper);
-
- await userEvent.click(await screen.findByRole('button', { name: /clerk\.com/ }));
- await userEvent.click(await screen.findByRole('button', { name: 'Continue setup' }));
-
- // The connection page forces no step, so the wizard resumes at the furthest-
- // reachable step for this connection (configure, since a provider connection
- // exists and the domain is verified) rather than the forced first step.
- // Resuming into `configure` (direction 0) falls through to its furthest-
- // reachable sub-step: a provider already exists, so it lands on
- // `configure-provider` rather than re-showing `select-provider`.
- expect(await screen.findByRole('heading', { name: /configure okta workforce/i })).toBeInTheDocument();
- expect(screen.queryByRole('heading', { name: /select your identity provider/i })).not.toBeInTheDocument();
- expect(screen.queryByRole('heading', { name: /add SSO domains/i })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Configure' })).not.toBeInTheDocument();
});
});
@@ -263,44 +260,104 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
// Enter the wizard from the overview.
- await userEvent.click(await screen.findByRole('button', { name: 'Start configuration' }));
+ await userEvent.click(await screen.findByRole('button', { name: 'Configure' }));
const backControl = await screen.findByRole('button', { name: 'Security' });
expect(backControl).toBeInTheDocument();
// The back control exits to the overview (the Start action returns).
await userEvent.click(backControl);
- expect(await screen.findByRole('button', { name: 'Start configuration' })).toBeInTheDocument();
+ expect(await screen.findByRole('button', { name: 'Configure' })).toBeInTheDocument();
expect(screen.queryByRole('heading', { name: /add SSO domains/i })).not.toBeInTheDocument();
});
+ });
- it('returns to the connection page when the wizard was opened from it', async () => {
- const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
-
- fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([
- configuredConnection({ samlConnection: null }),
- ]);
+ describe('connection row menu', () => {
+ const withConnection = (
+ fixtures: any,
+ connection: any,
+ testRuns: unknown[] = [{ id: 'run_1', status: 'success' }],
+ ) => {
+ fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([connection]);
fixtures.clerk.organization?.getEnterpriseConnectionTestRuns.mockResolvedValue({
- data: [],
- total_count: 0,
+ data: testRuns,
+ total_count: testRuns.length,
} as any);
fixtures.clerk.organization?.getDomains.mockResolvedValue({ data: [verifiedDomain], total_count: 1 } as any);
+ };
+
+ it('lists Edit, Deactivate, and Remove for an active connection', async () => {
+ const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
+ withConnection(fixtures, configuredConnection({ active: true }));
+
+ const { userEvent } = renderPage(wrapper);
+
+ await openConnectionMenu(userEvent);
+
+ expect(await screen.findByRole('menuitem', { name: 'Edit' })).toBeInTheDocument();
+ expect(screen.getByRole('menuitem', { name: 'Deactivate' })).toBeInTheDocument();
+ expect(screen.getByRole('menuitem', { name: 'Remove' })).toBeInTheDocument();
+ expect(screen.queryByRole('menuitem', { name: 'Activate' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('menuitem', { name: 'Continue configuration' })).not.toBeInTheDocument();
+ });
+
+ it('activates an inactive connection from the menu', async () => {
+ const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
+ withConnection(fixtures, configuredConnection({ active: false }));
+ fixtures.clerk.organization?.updateEnterpriseConnection.mockResolvedValue({} as any);
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /clerk\.com/ }));
- await userEvent.click(await screen.findByRole('button', { name: 'Continue setup' }));
+ await openConnectionMenu(userEvent);
+ expect(screen.queryByRole('menuitem', { name: 'Deactivate' })).not.toBeInTheDocument();
+ await userEvent.click(await screen.findByRole('menuitem', { name: 'Activate' }));
+
+ await waitFor(() =>
+ expect(fixtures.clerk.organization?.updateEnterpriseConnection).toHaveBeenCalledWith(
+ 'ent_1',
+ expect.objectContaining({ active: true }),
+ ),
+ );
+ });
+
+ it('resumes the wizard from Continue configuration on an in-progress connection', async () => {
+ const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
+ withConnection(fixtures, configuredConnection({ samlConnection: null }), []);
+
+ const { userEvent } = renderPage(wrapper);
+
+ await openConnectionMenu(userEvent);
+ expect(screen.queryByRole('menuitem', { name: 'Activate' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('menuitem', { name: 'Deactivate' })).not.toBeInTheDocument();
+ await userEvent.click(await screen.findByRole('menuitem', { name: 'Continue configuration' }));
+
expect(await screen.findByRole('heading', { name: /configure okta workforce/i })).toBeInTheDocument();
+ });
- await userEvent.click(await screen.findByRole('button', { name: 'Security' }));
+ it('removes a connection through the type-to-confirm dialog', async () => {
+ const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
+ withConnection(fixtures, configuredConnection({ active: true }));
+ fixtures.clerk.organization?.deleteEnterpriseConnection.mockResolvedValue({} as any);
- expect(await screen.findByText('Danger zone')).toBeInTheDocument();
- expect(screen.queryByText(DESCRIPTION_LINE_1)).not.toBeInTheDocument();
+ const { userEvent } = renderPage(wrapper);
+
+ await openConnectionMenu(userEvent);
+ await userEvent.click(await screen.findByRole('menuitem', { name: 'Remove' }));
+
+ const dialog = within(await screen.findByRole('dialog'));
+ await userEvent.type(dialog.getByRole('textbox'), 'Org1');
+ fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([]);
+ await userEvent.click(dialog.getByRole('button', { name: /remove/i }));
+
+ await waitFor(() =>
+ expect(fixtures.clerk.organization?.deleteEnterpriseConnection).toHaveBeenCalledWith('ent_1'),
+ );
+ expect(await screen.findByRole('button', { name: 'Configure' })).toBeInTheDocument();
});
});
describe('connection page', () => {
- it('opens the connection page for the clicked row', async () => {
+ it('opens the connection page from the row menu Edit action', async () => {
const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([configuredConnection({ active: true })]);
@@ -311,7 +368,7 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /clerk\.com/ }));
+ await openConnectionPage(userEvent);
expect(await screen.findByRole('heading', { name: 'clerk.com' })).toBeInTheDocument();
expect(screen.getAllByText('Okta Workforce').length).toBeGreaterThan(0);
@@ -330,7 +387,7 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /clerk\.com/ }));
+ await openConnectionPage(userEvent);
await userEvent.click(await screen.findByRole('button', { name: 'Security' }));
expect(await screen.findByText(DESCRIPTION_LINE_1)).toBeInTheDocument();
@@ -353,11 +410,11 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /clerk\.com/ }));
+ await openConnectionPage(userEvent);
await userEvent.click(await screen.findByRole('checkbox', { name: /Sync user attributes/ }));
await userEvent.click(screen.getByRole('button', { name: 'Save' }));
- expect(await screen.findByRole('button', { name: 'Start configuration' })).toBeInTheDocument();
+ expect(await screen.findByRole('button', { name: 'Configure' })).toBeInTheDocument();
expect(screen.queryByText('Identity provider')).not.toBeInTheDocument();
});
});
@@ -406,13 +463,13 @@ describe('OrganizationSecurityPage', () => {
expect(screen.queryByText('Unconfigured')).not.toBeInTheDocument();
});
- it('opens the connection page of the clicked row', async () => {
+ it('opens the connection page of the row whose menu was used', async () => {
const { wrapper, fixtures } = await createFixtures(withSecurityPageFixtures);
withTwoConnections(fixtures);
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /second\.com/ }));
+ await openConnectionPage(userEvent, 1);
expect(await screen.findByRole('heading', { name: 'second.com' })).toBeInTheDocument();
expect(screen.queryByRole('heading', { name: 'first.com' })).not.toBeInTheDocument();
@@ -471,8 +528,7 @@ describe('OrganizationSecurityPage', () => {
renderPage(wrapper);
- expect(await screen.findByRole('button', { name: /clerk\.com/ })).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
+ expect(await screen.findByText('Active')).toBeInTheDocument();
expect(screen.queryByText('Directory Sync')).not.toBeInTheDocument();
expect(fixtures.clerk.organization?.getDirectorySync).not.toHaveBeenCalled();
});
@@ -486,10 +542,14 @@ describe('OrganizationSecurityPage', () => {
renderPage(wrapper);
- const startButton = await screen.findByRole('button', { name: 'Start configuration' });
- expect(startButton).toBeEnabled();
- expect(screen.queryByText('SSO Required')).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
+ const configureButton = await screen.findByRole('button', { name: 'Configure' });
+ expect(configureButton).toBeEnabled();
+ expect(
+ screen.getByText('Keep organization members synced with your identity provider. Requires an SSO connection.'),
+ ).toBeInTheDocument();
+ expect(screen.queryByText('Unconfigured')).not.toBeInTheDocument();
+ expect(screen.queryByText('SSO required')).not.toBeInTheDocument();
+ expect(section('directorySync').queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
});
it('surfaces a load error when the directory request fails for any other reason', async () => {
@@ -505,8 +565,8 @@ describe('OrganizationSecurityPage', () => {
renderPage(wrapper);
expect(await screen.findByText('Could not load Directory Sync')).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Start configuration' })).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Configure' })).not.toBeInTheDocument();
+ expect(section('directorySync').queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument();
});
it('disables setup and flags SSO as required when no connection exists', async () => {
@@ -516,11 +576,10 @@ describe('OrganizationSecurityPage', () => {
renderPage(wrapper);
- expect(await screen.findByText('SSO Required')).toBeInTheDocument();
- const startButtons = screen.getAllByRole('button', { name: 'Start configuration' });
- expect(startButtons).toHaveLength(2);
- expect(startButtons[0]).toBeEnabled();
- expect(startButtons[1]).toBeDisabled();
+ expect(await screen.findByText('SSO required')).toBeInTheDocument();
+ const [ssoConfigureButton, directorySyncConfigureButton] = screen.getAllByRole('button', { name: 'Configure' });
+ expect(ssoConfigureButton).toBeEnabled();
+ expect(directorySyncConfigureButton).toBeDisabled();
expect(fixtures.clerk.organization?.getDirectorySync).not.toHaveBeenCalled();
});
@@ -538,7 +597,7 @@ describe('OrganizationSecurityPage', () => {
// Google used to be sent to the Clerk Dashboard here, which is the Clerk
// customer's account rather than the admin's, so setup dead-ended.
- expect(await screen.findByRole('button', { name: 'Start configuration' })).toBeEnabled();
+ expect(await screen.findByRole('button', { name: 'Configure' })).toBeEnabled();
expect(
screen.queryByText('Google Workspace connections are not configurable via self-serve'),
).not.toBeInTheDocument();
@@ -551,7 +610,7 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /open menu/i }));
+ await openDirectorySyncMenu(userEvent);
expect(screen.getByRole('menuitem', { name: 'Edit' })).toBeInTheDocument();
expect(screen.getByRole('menuitem', { name: 'Deactivate' })).toBeInTheDocument();
@@ -571,12 +630,12 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /open menu/i }));
+ await openDirectorySyncMenu(userEvent);
await userEvent.click(screen.getByRole('menuitem', { name: 'Deactivate' }));
expect(activeDirectory.update).toHaveBeenCalledWith({ enabled: false });
- await userEvent.click(screen.getByRole('button', { name: /open menu/i }));
+ await openDirectorySyncMenu(userEvent);
await waitFor(() => expect(screen.getByRole('menuitem', { name: 'Activate' })).toBeInTheDocument());
});
@@ -589,7 +648,7 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /open menu/i }));
+ await openDirectorySyncMenu(userEvent);
await userEvent.click(screen.getByRole('menuitem', { name: 'Remove' }));
expect(await screen.findByRole('heading', { name: 'Remove Directory Sync' })).toBeInTheDocument();
@@ -600,7 +659,7 @@ describe('OrganizationSecurityPage', () => {
await userEvent.click(confirmButton);
expect(activeDirectory.delete).toHaveBeenCalledWith();
- await waitFor(() => expect(screen.getByRole('button', { name: 'Start configuration' })).toBeInTheDocument());
+ await waitFor(() => expect(screen.getByRole('button', { name: 'Configure' })).toBeInTheDocument());
// Typing the confirmation and swapping the section back has hit the 5s default on CI.
}, 15_000);
@@ -611,7 +670,7 @@ describe('OrganizationSecurityPage', () => {
const { userEvent } = renderPage(wrapper);
- await userEvent.click(await screen.findByRole('button', { name: /open menu/i }));
+ await openDirectorySyncMenu(userEvent);
await userEvent.click(screen.getByRole('menuitem', { name: 'Edit' }));
await waitFor(() => expect(screen.queryByRole('button', { name: /open menu/i })).not.toBeInTheDocument());
diff --git a/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx b/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx
index cd0e9e1fcc4..639992a9c6a 100644
--- a/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx
+++ b/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx
@@ -1,3 +1,4 @@
+import { within } from '@testing-library/react';
import { beforeEach, describe, expect, it } from 'vitest';
import { clearFetchCache } from '@/hooks/useFetch';
@@ -109,7 +110,7 @@ describe('SSO bypass allowlist', () => {
renderPage(wrapper);
- expect(await screen.findByRole('button', { name: 'Start configuration' })).toBeInTheDocument();
+ expect(await screen.findByRole('button', { name: 'Configure' })).toBeInTheDocument();
expect(screen.queryByText('SSO bypass')).not.toBeInTheDocument();
});
@@ -152,7 +153,11 @@ describe('SSO bypass allowlist', () => {
expect(await screen.findByText('1 member')).toBeInTheDocument();
- await userEvent.click(screen.getByRole('button', { name: /open menu/i }));
+ await userEvent.click(
+ within(document.querySelector('.cl-profileSection__ssoBypass') as HTMLElement).getByRole('button', {
+ name: /open menu/i,
+ }),
+ );
await userEvent.click(await screen.findByRole('menuitem', { name: 'Manage' }));
expect(await screen.findByRole('heading', { name: 'SSO bypass' })).toBeInTheDocument();
@@ -187,7 +192,11 @@ describe('SSO bypass allowlist', () => {
const userEventOpen = async (userEvent: ReturnType['userEvent']) => {
await screen.findByText('SSO bypass');
- await userEvent.click(screen.getByRole('button', { name: /open menu/i }));
+ await userEvent.click(
+ within(document.querySelector('.cl-profileSection__ssoBypass') as HTMLElement).getByRole('button', {
+ name: /open menu/i,
+ }),
+ );
await userEvent.click(await screen.findByRole('menuitem', { name: 'Manage' }));
await screen.findByRole('heading', { name: 'SSO bypass' });
};
@@ -474,9 +483,13 @@ describe('SSO bypass allowlist', () => {
expect(screen.getByText(SSO_DESCRIPTION)).toBeInTheDocument();
expect(screen.getByText('Active')).toBeInTheDocument();
- expect(screen.queryByRole('button', { name: /clerk\.com/ })).not.toBeInTheDocument();
+ expect(
+ within(document.querySelector('.cl-profileSection__sso') as HTMLElement).queryByRole('button', {
+ name: /open menu/i,
+ }),
+ ).not.toBeInTheDocument();
expect(screen.queryByRole('button', { name: 'Add connection' })).not.toBeInTheDocument();
- expect(screen.queryByRole('button', { name: 'Start configuration' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Configure' })).not.toBeInTheDocument();
expect(fixtures.clerk.organization?.getEnterpriseConnectionTestRuns).not.toHaveBeenCalled();
});
diff --git a/packages/ui/src/components/OrganizationProfile/enterpriseConnectionStatusBadges.ts b/packages/ui/src/components/OrganizationProfile/enterpriseConnectionStatusBadges.ts
index 73b43cad2fa..aa17c4c0b6c 100644
--- a/packages/ui/src/components/OrganizationProfile/enterpriseConnectionStatusBadges.ts
+++ b/packages/ui/src/components/OrganizationProfile/enterpriseConnectionStatusBadges.ts
@@ -4,7 +4,7 @@ import type { OrganizationEnterpriseConnectionStatus } from '../ConfigureSSO/dom
export const STATUS_BADGES: Record<
OrganizationEnterpriseConnectionStatus,
- { id: string; colorScheme?: 'primary' | 'danger' | 'warning' | 'success'; label: LocalizationKey }
+ { id: string; colorScheme: 'primary'; label: LocalizationKey }
> = {
unconfigured: {
id: 'unconfigured',
@@ -13,17 +13,17 @@ export const STATUS_BADGES: Record<
},
in_progress: {
id: 'inProgress',
- colorScheme: 'warning',
+ colorScheme: 'primary',
label: localizationKeys('organizationProfile.securityPage.ssoSection.badge__inProgress'),
},
active: {
id: 'active',
- colorScheme: 'success',
+ colorScheme: 'primary',
label: localizationKeys('organizationProfile.securityPage.ssoSection.badge__active'),
},
inactive: {
id: 'inactive',
- colorScheme: 'danger',
+ colorScheme: 'primary',
label: localizationKeys('organizationProfile.securityPage.ssoSection.badge__inactive'),
},
};