diff --git a/.changeset/configure-sso-select-provider-step.md b/.changeset/configure-sso-select-provider-step.md new file mode 100644 index 00000000000..947e8f08fb1 --- /dev/null +++ b/.changeset/configure-sso-select-provider-step.md @@ -0,0 +1,10 @@ +--- +'@clerk/localizations': patch +'@clerk/clerk-js': patch +'@clerk/shared': patch +'@clerk/ui': patch +--- + +Implement the provider selection step of `<__experimental_ConfigureSSO />`. Renders the two SAML provider tiles (Okta Workforce and Custom SAML Provider) with real icons sourced from `img.clerk.com`, tracks the picked provider in local state, and gates `Step.Footer.Continue` on a selection. Includes a warning callout about provider lock-in and a minor `Step.Header` alignment tweak. All user-visible strings are wired through `@clerk/localizations`, with translations for every supported locale. + +Also extends the flow context with `provider`, `setProvider`, `clearProvider`, and an idempotent `createConnection`, adds the `deriveInitialStep` helper, and wires the wizard's `initialStepId` so the configure flow remounts on the right step after a reload. Continue on Select Provider now creates the enterprise connection and advances to the next step. diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index 1650fbf5f7d..9a8f56746d5 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -186,6 +186,20 @@ export const arSA: LocalizationResource = { navbar: { title: 'تكوين تسجيل الدخول الموحد (SSO)', }, + selectProviderStep: { + title: 'اختر المزود', + subtitle: 'اختر المزود الذي ستقوم بإعداد تسجيل الدخول الموحد (SSO) له.', + body: { + title: 'اختر مزود الهوية الخاص بك', + description: 'سنرشدك خلال عملية الإعداد التفصيلية بعد ذلك.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'مزود SAML مخصص', + }, + warning: 'بمجرد اختيار المزود لا يمكنك التغيير مرة أخرى حتى انتهاء التكوين', + }, }, createOrganization: { formButtonSubmit: 'أنشاء منظمة', diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index 5a1724ed188..7cf5e19b921 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -187,6 +187,20 @@ export const beBY: LocalizationResource = { navbar: { title: 'Налада адзінага ўваходу (SSO)', }, + selectProviderStep: { + title: 'Выберыце правайдэра', + subtitle: 'Выберыце правайдэра, для якога вы будзеце наладжваць SSO.', + body: { + title: 'Выберыце вашага правайдэра ідэнтыфікацыі', + description: 'Мы правядзём вас праз падрабязны працэс налады далей.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Карыстальніцкі правайдэр SAML', + }, + warning: 'Пасля выбару правайдэра вы не зможаце змяніць яго, пакуль не скончыце канфігурацыю', + }, }, createOrganization: { formButtonSubmit: 'Стварыць арганізацыю', diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index 855f8bd4241..32959e88977 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -188,6 +188,20 @@ export const bgBG: LocalizationResource = { navbar: { title: 'Конфигуриране на единен вход (SSO)', }, + selectProviderStep: { + title: 'Изберете доставчик', + subtitle: 'Изберете доставчика, за който ще конфигурирате SSO.', + body: { + title: 'Изберете вашия доставчик на идентичност', + description: 'Ще ви преведем през подробния процес на настройка след това.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Персонализиран SAML доставчик', + }, + warning: 'След като изберете доставчик, не можете да го промените, докато конфигурацията не приключи', + }, }, createOrganization: { formButtonSubmit: 'Създаване на организация', diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index f928a614942..c4255b1df3e 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -186,6 +186,20 @@ export const bnIN: LocalizationResource = { navbar: { title: 'একক সাইন-অন (SSO) কনফিগার করুন', }, + selectProviderStep: { + title: 'Select provider', + subtitle: 'Select the provider you are going to setup SSO for.', + body: { + title: 'Select your identity provider', + description: "We'll guide you through the detailed setup process next.", + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Custom SAML Provider', + }, + warning: 'Once a provider is selected you cannot change again until the configuration is over', + }, }, createOrganization: { formButtonSubmit: 'সংগঠন তৈরি করুন', diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index 43c23922c45..57a46e03989 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -194,6 +194,20 @@ export const caES: LocalizationResource = { navbar: { title: "Configura l'inici de sessió únic (SSO)", }, + selectProviderStep: { + title: 'Seleccioneu un proveïdor', + subtitle: 'Seleccioneu el proveïdor per al qual configurareu SSO.', + body: { + title: "Seleccioneu el vostre proveïdor d'identitat", + description: 'Us guiarem pel procés de configuració detallat a continuació.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Proveïdor SAML personalitzat', + }, + warning: 'Un cop seleccionat un proveïdor no podreu canviar-lo fins que la configuració hagi finalitzat', + }, }, createOrganization: { formButtonSubmit: 'Crea organització', diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index 7723881510c..78e9a97f0a9 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -190,6 +190,20 @@ export const csCZ: LocalizationResource = { navbar: { title: 'Nastavit jednotné přihlášení (SSO)', }, + selectProviderStep: { + title: 'Vyberte poskytovatele', + subtitle: 'Vyberte poskytovatele, pro kterého budete nastavovat SSO.', + body: { + title: 'Vyberte svého poskytovatele identity', + description: 'Provedeme vás dále podrobným procesem nastavení.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Vlastní poskytovatel SAML', + }, + warning: 'Jakmile vyberete poskytovatele, nelze ho změnit, dokud nebude konfigurace dokončena', + }, }, createOrganization: { formButtonSubmit: 'Vytvořit organizaci', diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index fe5673f9627..53ec3670568 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -187,6 +187,20 @@ export const daDK: LocalizationResource = { navbar: { title: 'Konfigurer single sign-on (SSO)', }, + selectProviderStep: { + title: 'Vælg udbyder', + subtitle: 'Vælg den udbyder, du vil opsætte SSO for.', + body: { + title: 'Vælg din identitetsudbyder', + description: 'Vi guider dig gennem den detaljerede opsætningsproces næste gang.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Brugerdefineret SAML-udbyder', + }, + warning: 'Når en udbyder er valgt, kan du ikke ændre den, før konfigurationen er færdig', + }, }, createOrganization: { formButtonSubmit: 'Opret organisation', diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index 2c2ff5f0fdb..252976e567e 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -193,6 +193,21 @@ export const deDE: LocalizationResource = { navbar: { title: 'Single Sign-On (SSO) konfigurieren', }, + selectProviderStep: { + title: 'Anbieter auswählen', + subtitle: 'Wählen Sie den Anbieter, für den Sie SSO einrichten möchten.', + body: { + title: 'Wählen Sie Ihren Identitätsanbieter', + description: 'Wir führen Sie als nächstes durch den detaillierten Einrichtungsprozess.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Benutzerdefinierter SAML-Anbieter', + }, + warning: + 'Sobald ein Anbieter ausgewählt ist, können Sie ihn nicht mehr ändern, bis die Konfiguration abgeschlossen ist', + }, }, createOrganization: { formButtonSubmit: 'Organisation erstellen', diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index ad532677f9f..39624bd453d 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -187,6 +187,20 @@ export const elGR: LocalizationResource = { navbar: { title: 'Διαμόρφωση Ενιαίας Σύνδεσης (SSO)', }, + selectProviderStep: { + title: 'Επιλέξτε πάροχο', + subtitle: 'Επιλέξτε τον πάροχο για τον οποίο θα ρυθμίσετε SSO.', + body: { + title: 'Επιλέξτε τον πάροχο ταυτότητάς σας', + description: 'Θα σας καθοδηγήσουμε στη λεπτομερή διαδικασία ρύθμισης στη συνέχεια.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Προσαρμοσμένος πάροχος SAML', + }, + warning: 'Μόλις επιλεγεί ένας πάροχος δεν μπορείτε να τον αλλάξετε μέχρι να ολοκληρωθεί η ρύθμιση', + }, }, createOrganization: { formButtonSubmit: 'Δημιουργία οργανισμού', diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 5f21f029a6c..1c9901553f9 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -187,6 +187,20 @@ export const enGB: LocalizationResource = { navbar: { title: 'Configure Single Sign-On (SSO)', }, + selectProviderStep: { + title: 'Select provider', + subtitle: 'Select the provider you are going to set up SSO for.', + body: { + title: 'Select your identity provider', + description: "We'll guide you through the detailed setup process next.", + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Custom SAML Provider', + }, + warning: 'Once a provider is selected you cannot change again until the configuration is over', + }, }, createOrganization: { formButtonSubmit: 'Create organisation', diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index c99ba13395a..407aa6f5634 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -209,6 +209,20 @@ export const enUS: LocalizationResource = { navbar: { title: 'Configure Single Sign-On (SSO)', }, + selectProviderStep: { + title: 'Select provider', + subtitle: 'Select the provider you are going to setup SSO for.', + body: { + title: 'Select your identity provider', + description: "We'll guide you through the detailed setup process next.", + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Custom SAML Provider', + }, + warning: 'Once a provider is selected you cannot change again until the configuration is over', + }, }, createOrganization: { formButtonSubmit: 'Create organization', diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index a96ef5b91d5..474ae291590 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -187,6 +187,20 @@ export const esCR: LocalizationResource = { navbar: { title: 'Configurar inicio de sesión único (SSO)', }, + selectProviderStep: { + title: 'Seleccionar proveedor', + subtitle: 'Selecciona el proveedor para el que vas a configurar SSO.', + body: { + title: 'Selecciona tu proveedor de identidad', + description: 'Te guiaremos a través del proceso de configuración detallado a continuación.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Proveedor SAML personalizado', + }, + warning: 'Una vez que se selecciona un proveedor no puedes cambiarlo hasta que termine la configuración', + }, }, createOrganization: { formButtonSubmit: 'Crear organización', diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index 0985e81031f..05f48007dbf 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -193,6 +193,20 @@ export const esES: LocalizationResource = { navbar: { title: 'Configurar inicio de sesión único (SSO)', }, + selectProviderStep: { + title: 'Seleccionar proveedor', + subtitle: 'Selecciona el proveedor para el que vas a configurar SSO.', + body: { + title: 'Selecciona tu proveedor de identidad', + description: 'Te guiaremos a través del proceso de configuración detallado a continuación.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Proveedor SAML personalizado', + }, + warning: 'Una vez seleccionado un proveedor no podrás cambiarlo hasta que finalice la configuración', + }, }, createOrganization: { formButtonSubmit: 'Crear organización', diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index a3bc81d7bb7..a1237b5b991 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -188,6 +188,20 @@ export const esMX: LocalizationResource = { navbar: { title: 'Configurar inicio de sesión único (SSO)', }, + selectProviderStep: { + title: 'Seleccionar proveedor', + subtitle: 'Selecciona el proveedor para el que vas a configurar SSO.', + body: { + title: 'Selecciona tu proveedor de identidad', + description: 'Te guiaremos a través del proceso de configuración detallado a continuación.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Proveedor SAML personalizado', + }, + warning: 'Una vez que se selecciona un proveedor no puedes cambiarlo hasta que termine la configuración', + }, }, createOrganization: { formButtonSubmit: 'Crear organización', diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index 557ceb5ca23..a14f205e2cb 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -187,6 +187,20 @@ export const esUY: LocalizationResource = { navbar: { title: 'Configurar inicio de sesión único (SSO)', }, + selectProviderStep: { + title: 'Seleccionar proveedor', + subtitle: 'Seleccioná el proveedor para el que vas a configurar SSO.', + body: { + title: 'Seleccioná tu proveedor de identidad', + description: 'Te guiaremos a través del proceso de configuración detallado a continuación.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Proveedor SAML personalizado', + }, + warning: 'Una vez que se selecciona un proveedor no podés cambiarlo hasta que termine la configuración', + }, }, createOrganization: { formButtonSubmit: 'Crear organización', diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index 0bd64d2c2f0..4b6ae0fb9f0 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -191,6 +191,20 @@ export const faIR: LocalizationResource = { navbar: { title: 'پیکربندی ورود یکپارچه (SSO)', }, + selectProviderStep: { + title: 'ارائه‌دهنده را انتخاب کنید', + subtitle: 'ارائه‌دهنده‌ای را که می‌خواهید SSO را برای آن راه‌اندازی کنید، انتخاب کنید.', + body: { + title: 'ارائه‌دهنده هویت خود را انتخاب کنید', + description: 'در ادامه شما را در فرآیند راه‌اندازی دقیق راهنمایی خواهیم کرد.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'ارائه‌دهنده SAML سفارشی', + }, + warning: 'پس از انتخاب یک ارائه‌دهنده، نمی‌توانید آن را تا پایان پیکربندی تغییر دهید', + }, }, createOrganization: { formButtonSubmit: 'ایجاد سازمان', diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index 46317d84fac..d18b6b84fbd 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -214,6 +214,20 @@ export const fiFI: LocalizationResource = { navbar: { title: 'Määritä kertakirjautuminen (SSO)', }, + selectProviderStep: { + title: 'Valitse palveluntarjoaja', + subtitle: 'Valitse palveluntarjoaja, jolle määrität SSO:n.', + body: { + title: 'Valitse henkilöllisyyden tarjoaja', + description: 'Opastamme sinut yksityiskohtaisen määritysprosessin läpi seuraavaksi.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Mukautettu SAML-palveluntarjoaja', + }, + warning: 'Kun palveluntarjoaja on valittu, et voi vaihtaa sitä ennen kuin määritys on valmis', + }, }, createOrganization: { formButtonSubmit: 'Luo organisaatio', diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index 97d225f024a..21fc3385dc7 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -195,6 +195,21 @@ export const frFR: LocalizationResource = { navbar: { title: "Configurer l'authentification unique (SSO)", }, + selectProviderStep: { + title: 'Sélectionner un fournisseur', + subtitle: 'Sélectionnez le fournisseur pour lequel vous allez configurer le SSO.', + body: { + title: "Sélectionnez votre fournisseur d'identité", + description: 'Nous vous guiderons ensuite à travers le processus de configuration détaillé.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Fournisseur SAML personnalisé', + }, + warning: + "Une fois un fournisseur sélectionné, vous ne pourrez plus en changer jusqu'à la fin de la configuration", + }, }, createOrganization: { formButtonSubmit: 'Créer l’organisation', diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index b5510e08b09..18d7b8eb0f7 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -186,6 +186,20 @@ export const heIL: LocalizationResource = { navbar: { title: 'הגדרת כניסה אחידה (SSO)', }, + selectProviderStep: { + title: 'בחר ספק', + subtitle: 'בחר את הספק שעבורו תגדיר SSO.', + body: { + title: 'בחר את ספק הזהות שלך', + description: 'נדריך אותך בתהליך ההגדרה המפורט בהמשך.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'ספק SAML מותאם אישית', + }, + warning: 'לאחר בחירת ספק לא ניתן לשנות אותו עד לסיום ההגדרה', + }, }, createOrganization: { formButtonSubmit: 'צור ארגון', diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index 64ce08e7a27..6330b9d65a6 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -187,6 +187,20 @@ export const hiIN: LocalizationResource = { navbar: { title: 'सिंगल साइन-ऑन (SSO) कॉन्फ़िगर करें', }, + selectProviderStep: { + title: 'प्रदाता चुनें', + subtitle: 'उस प्रदाता का चयन करें जिसके लिए आप SSO सेट अप कर रहे हैं।', + body: { + title: 'अपना पहचान प्रदाता चुनें', + description: 'हम आपको आगे विस्तृत सेटअप प्रक्रिया के माध्यम से मार्गदर्शन करेंगे।', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'कस्टम SAML प्रदाता', + }, + warning: 'एक बार प्रदाता का चयन करने के बाद आप कॉन्फ़िगरेशन समाप्त होने तक इसे बदल नहीं सकते', + }, }, createOrganization: { formButtonSubmit: 'संगठन बनाएँ', diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index 32f5b1dee3b..040a502b202 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -216,6 +216,20 @@ export const hrHR: LocalizationResource = { navbar: { title: 'Konfiguriraj jedinstvenu prijavu (SSO)', }, + selectProviderStep: { + title: 'Odaberite pružatelja', + subtitle: 'Odaberite pružatelja za kojeg ćete postaviti SSO.', + body: { + title: 'Odaberite svog pružatelja identiteta', + description: 'Vodit ćemo vas kroz detaljan proces postavljanja u nastavku.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Prilagođeni SAML pružatelj', + }, + warning: 'Nakon odabira pružatelja ne možete ga ponovno mijenjati dok konfiguracija ne završi', + }, }, createOrganization: { formButtonSubmit: 'kreiraj organizaciju', diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index 2fcc3f83bf0..74781b8451e 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -216,6 +216,20 @@ export const huHU: LocalizationResource = { navbar: { title: 'Egyszeri bejelentkezés (SSO) beállítása', }, + selectProviderStep: { + title: 'Szolgáltató kiválasztása', + subtitle: 'Válassza ki azt a szolgáltatót, amelyhez beállítja az SSO-t.', + body: { + title: 'Válassza ki az identitásszolgáltatóját', + description: 'Ezután végigvezetjük a részletes beállítási folyamaton.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Egyéni SAML szolgáltató', + }, + warning: 'Miután kiválasztotta a szolgáltatót, nem módosíthatja, amíg a konfiguráció be nem fejeződik', + }, }, createOrganization: { formButtonSubmit: 'Szervezet létrehozása', diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index bd47bf1828e..4687d0c20f4 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -186,6 +186,20 @@ export const idID: LocalizationResource = { navbar: { title: 'Konfigurasi Single Sign-On (SSO)', }, + selectProviderStep: { + title: 'Pilih penyedia', + subtitle: 'Pilih penyedia yang akan Anda atur untuk SSO.', + body: { + title: 'Pilih penyedia identitas Anda', + description: 'Kami akan memandu Anda melalui proses penyiapan terperinci berikutnya.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Penyedia SAML Khusus', + }, + warning: 'Setelah penyedia dipilih, Anda tidak dapat mengubahnya lagi sampai konfigurasi selesai', + }, }, createOrganization: { formButtonSubmit: 'Buat organisasi', diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index a6346dce68d..10922d82a63 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -215,6 +215,20 @@ export const isIS: LocalizationResource = { navbar: { title: 'Stilla einnar innskráningar (SSO)', }, + selectProviderStep: { + title: 'Veldu þjónustuaðila', + subtitle: 'Veldu þjónustuaðilann sem þú ætlar að setja upp SSO fyrir.', + body: { + title: 'Veldu auðkennisþjónustuaðila þinn', + description: 'Við munum leiðbeina þér í gegnum ítarlegt uppsetningarferli næst.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Sérsniðinn SAML þjónustuaðili', + }, + warning: 'Þegar þjónustuaðili hefur verið valinn er ekki hægt að breyta aftur fyrr en stillingu er lokið', + }, }, createOrganization: { formButtonSubmit: 'Stofna samtök', diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index f5042de6356..db7e9ffb520 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -193,6 +193,20 @@ export const itIT: LocalizationResource = { navbar: { title: 'Configura Single Sign-On (SSO)', }, + selectProviderStep: { + title: 'Seleziona provider', + subtitle: "Seleziona il provider per cui configurerai l'SSO.", + body: { + title: 'Seleziona il tuo provider di identità', + description: 'Ti guideremo nel processo di configurazione dettagliato successivamente.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Provider SAML personalizzato', + }, + warning: 'Una volta selezionato un provider non potrai cambiarlo fino al termine della configurazione', + }, }, createOrganization: { formButtonSubmit: 'Crea organizzazione', diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index 3deb569032b..e41bbe41d32 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -197,6 +197,20 @@ export const jaJP: LocalizationResource = { navbar: { title: 'シングルサインオン(SSO)を設定', }, + selectProviderStep: { + title: 'プロバイダーを選択', + subtitle: 'SSOを設定するプロバイダーを選択してください。', + body: { + title: 'IDプロバイダーを選択してください', + description: '次に、詳細な設定プロセスをご案内します。', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'カスタムSAMLプロバイダー', + }, + warning: 'プロバイダーを選択すると、設定が完了するまで変更できません', + }, }, createOrganization: { formButtonSubmit: '組織を作成する', diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index f53f6a36f42..28edb9b4ecc 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -186,6 +186,20 @@ export const kkKZ: LocalizationResource = { navbar: { title: 'Бірыңғай кіруді конфигурациялау (SSO)', }, + selectProviderStep: { + title: 'Select provider', + subtitle: 'Select the provider you are going to setup SSO for.', + body: { + title: 'Select your identity provider', + description: "We'll guide you through the detailed setup process next.", + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Custom SAML Provider', + }, + warning: 'Once a provider is selected you cannot change again until the configuration is over', + }, }, createOrganization: { formButtonSubmit: 'Ұйым құру', diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index 1fa3e1e370b..cd516070e7e 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -193,6 +193,20 @@ export const koKR: LocalizationResource = { navbar: { title: '싱글 사인온(SSO) 구성', }, + selectProviderStep: { + title: '공급자 선택', + subtitle: 'SSO를 설정할 공급자를 선택하세요.', + body: { + title: 'ID 공급자를 선택하세요', + description: '다음 단계에서 자세한 설정 프로세스를 안내해 드립니다.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: '사용자 지정 SAML 공급자', + }, + warning: '공급자를 선택하면 구성이 완료될 때까지 다시 변경할 수 없습니다', + }, }, createOrganization: { formButtonSubmit: '조직 만들기', diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index 198e7d1fd28..71c024d546c 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -186,6 +186,20 @@ export const mnMN: LocalizationResource = { navbar: { title: 'Нэгдсэн нэвтрэлт (SSO) тохируулах', }, + selectProviderStep: { + title: 'Select provider', + subtitle: 'Select the provider you are going to setup SSO for.', + body: { + title: 'Select your identity provider', + description: "We'll guide you through the detailed setup process next.", + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Custom SAML Provider', + }, + warning: 'Once a provider is selected you cannot change again until the configuration is over', + }, }, createOrganization: { formButtonSubmit: 'Байгуулга үүсгэх', diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index be7b1af309e..cabe9aa4f73 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -186,6 +186,20 @@ export const msMY: LocalizationResource = { navbar: { title: 'Konfigurasi Log Masuk Tunggal (SSO)', }, + selectProviderStep: { + title: 'Pilih pembekal', + subtitle: 'Pilih pembekal yang anda akan sediakan SSO untuknya.', + body: { + title: 'Pilih pembekal identiti anda', + description: 'Kami akan membimbing anda melalui proses persediaan terperinci seterusnya.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Pembekal SAML Tersuai', + }, + warning: 'Setelah pembekal dipilih anda tidak boleh menukar lagi sehingga konfigurasi selesai', + }, }, createOrganization: { formButtonSubmit: 'Cipta organisasi', diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index bcb8abaf78b..d90e4aac8bd 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -215,6 +215,20 @@ export const nbNO: LocalizationResource = { navbar: { title: 'Konfigurer enkeltpålogging (SSO)', }, + selectProviderStep: { + title: 'Velg leverandør', + subtitle: 'Velg leverandøren du skal konfigurere SSO for.', + body: { + title: 'Velg din identitetsleverandør', + description: 'Vi veileder deg gjennom den detaljerte konfigurasjonsprosessen neste gang.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Egendefinert SAML-leverandør', + }, + warning: 'Når en leverandør er valgt, kan du ikke endre igjen før konfigurasjonen er ferdig', + }, }, createOrganization: { formButtonSubmit: 'Opprett organisasjon', diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index 3131fcd5baa..403b97e6a74 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -187,6 +187,20 @@ export const nlBE: LocalizationResource = { navbar: { title: 'Single sign-on (SSO) configureren', }, + selectProviderStep: { + title: 'Provider selecteren', + subtitle: 'Selecteer de provider waarvoor je SSO gaat instellen.', + body: { + title: 'Selecteer je identiteitsprovider', + description: 'We begeleiden je hierna door het gedetailleerde installatieproces.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Aangepaste SAML-provider', + }, + warning: 'Zodra een provider is geselecteerd, kun je deze niet meer wijzigen totdat de configuratie is voltooid', + }, }, createOrganization: { formButtonSubmit: 'Creëer organisatie', diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index ce89575b35d..57f8eeee2e3 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -187,6 +187,20 @@ export const nlNL: LocalizationResource = { navbar: { title: 'Single sign-on (SSO) configureren', }, + selectProviderStep: { + title: 'Provider selecteren', + subtitle: 'Selecteer de provider waarvoor je SSO gaat instellen.', + body: { + title: 'Selecteer je identiteitsprovider', + description: 'We begeleiden je hierna door het gedetailleerde installatieproces.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Aangepaste SAML-provider', + }, + warning: 'Zodra een provider is geselecteerd, kun je deze niet meer wijzigen totdat de configuratie is voltooid', + }, }, createOrganization: { formButtonSubmit: 'Creëer organisatie', diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index e5227729e6f..2d4d700c5ab 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -187,6 +187,20 @@ export const plPL: LocalizationResource = { navbar: { title: 'Skonfiguruj logowanie jednokrotne (SSO)', }, + selectProviderStep: { + title: 'Wybierz dostawcę', + subtitle: 'Wybierz dostawcę, dla którego skonfigurujesz SSO.', + body: { + title: 'Wybierz swojego dostawcę tożsamości', + description: 'Następnie przeprowadzimy Cię przez szczegółowy proces konfiguracji.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Niestandardowy dostawca SAML', + }, + warning: 'Po wybraniu dostawcy nie można go ponownie zmienić aż do zakończenia konfiguracji', + }, }, createOrganization: { formButtonSubmit: 'Utwórz organizację', diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index 108c4f29d9f..347be74c3e3 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -193,6 +193,21 @@ export const ptBR: LocalizationResource = { navbar: { title: 'Configurar logon único (SSO)', }, + selectProviderStep: { + title: 'Selecionar provedor', + subtitle: 'Selecione o provedor para o qual você vai configurar o SSO.', + body: { + title: 'Selecione seu provedor de identidade', + description: 'Iremos guiá-lo pelo processo de configuração detalhado em seguida.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Provedor SAML personalizado', + }, + warning: + 'Depois que um provedor for selecionado, você não poderá alterá-lo até que a configuração seja concluída', + }, }, createOrganization: { formButtonSubmit: 'Criar organização', diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index adf07011b44..2f510f7eb4c 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -194,6 +194,20 @@ export const ptPT: LocalizationResource = { navbar: { title: 'Configurar autenticação única (SSO)', }, + selectProviderStep: { + title: 'Selecionar fornecedor', + subtitle: 'Selecione o fornecedor para o qual vai configurar o SSO.', + body: { + title: 'Selecione o seu fornecedor de identidade', + description: 'Iremos guiá-lo pelo processo de configuração detalhado a seguir.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Fornecedor SAML personalizado', + }, + warning: 'Depois de um fornecedor ser selecionado não pode ser alterado até que a configuração esteja terminada', + }, }, createOrganization: { formButtonSubmit: 'Criar organização', diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index 9008441998f..33a6feff6f7 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -193,6 +193,20 @@ export const roRO: LocalizationResource = { navbar: { title: 'Configurați autentificarea unică (SSO)', }, + selectProviderStep: { + title: 'Selectați furnizorul', + subtitle: 'Selectați furnizorul pentru care veți configura SSO.', + body: { + title: 'Selectați furnizorul de identitate', + description: 'Vă vom ghida în continuare prin procesul de configurare detaliat.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Furnizor SAML personalizat', + }, + warning: 'Odată ce un furnizor este selectat, nu îl puteți schimba până când configurația nu este finalizată', + }, }, createOrganization: { formButtonSubmit: 'Creează organizație', diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index baafba1fdab..b22daf13e66 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -187,6 +187,20 @@ export const ruRU: LocalizationResource = { navbar: { title: 'Настроить единый вход (SSO)', }, + selectProviderStep: { + title: 'Выберите поставщика', + subtitle: 'Выберите поставщика, для которого вы будете настраивать SSO.', + body: { + title: 'Выберите вашего поставщика идентификации', + description: 'Далее мы проведём вас через подробный процесс настройки.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Пользовательский поставщик SAML', + }, + warning: 'После выбора поставщика вы не сможете изменить его до завершения настройки', + }, }, createOrganization: { formButtonSubmit: 'Создать организацию', diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index a74f99a230c..a06c6e62aaf 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -187,6 +187,20 @@ export const skSK: LocalizationResource = { navbar: { title: 'Nastaviť jednotné prihlasovanie (SSO)', }, + selectProviderStep: { + title: 'Vyberte poskytovateľa', + subtitle: 'Vyberte poskytovateľa, pre ktorého budete nastavovať SSO.', + body: { + title: 'Vyberte si svojho poskytovateľa identity', + description: 'Následne vás prevedieme podrobným procesom nastavenia.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Vlastný poskytovateľ SAML', + }, + warning: 'Po výbere poskytovateľa ho nemôžete zmeniť, kým sa konfigurácia neukončí', + }, }, createOrganization: { formButtonSubmit: 'Vytvoriť organizáciu', diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index 1c40e71dd13..cb0ce3b6911 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -187,6 +187,20 @@ export const srRS: LocalizationResource = { navbar: { title: 'Konfiguriši jedinstvenu prijavu (SSO)', }, + selectProviderStep: { + title: 'Izaberite provajdera', + subtitle: 'Izaberite provajdera za koga ćete podesiti SSO.', + body: { + title: 'Izaberite svog provajdera identiteta', + description: 'Vodićemo vas kroz detaljan proces podešavanja u nastavku.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Prilagođeni SAML provajder', + }, + warning: 'Kada se provajder izabere, ne možete ga ponovo menjati dok se konfiguracija ne završi', + }, }, createOrganization: { formButtonSubmit: 'Kreiraj organizaciju', diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index fe20fe42180..da9fe31287a 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -186,6 +186,20 @@ export const svSE: LocalizationResource = { navbar: { title: 'Konfigurera enkel inloggning (SSO)', }, + selectProviderStep: { + title: 'Välj leverantör', + subtitle: 'Välj den leverantör du ska konfigurera SSO för.', + body: { + title: 'Välj din identitetsleverantör', + description: 'Vi guidar dig sedan genom den detaljerade konfigurationsprocessen.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Anpassad SAML-leverantör', + }, + warning: 'När en leverantör har valts kan du inte ändra igen förrän konfigurationen är klar', + }, }, createOrganization: { formButtonSubmit: 'Skapa organisation', diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index 33d46b0155a..41be7ab83c0 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -186,6 +186,20 @@ export const taIN: LocalizationResource = { navbar: { title: 'ஒற்றை உள்நுழைவை (SSO) உள்ளமை', }, + selectProviderStep: { + title: 'Select provider', + subtitle: 'Select the provider you are going to setup SSO for.', + body: { + title: 'Select your identity provider', + description: "We'll guide you through the detailed setup process next.", + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Custom SAML Provider', + }, + warning: 'Once a provider is selected you cannot change again until the configuration is over', + }, }, createOrganization: { formButtonSubmit: 'நிறுவனத்தை உருவாக்கு', diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index a70186c3873..6553c0e90b6 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -186,6 +186,20 @@ export const teIN: LocalizationResource = { navbar: { title: 'సింగిల్ సైన్-ఆన్ (SSO) కాన్ఫిగర్ చేయండి', }, + selectProviderStep: { + title: 'Select provider', + subtitle: 'Select the provider you are going to setup SSO for.', + body: { + title: 'Select your identity provider', + description: "We'll guide you through the detailed setup process next.", + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Custom SAML Provider', + }, + warning: 'Once a provider is selected you cannot change again until the configuration is over', + }, }, createOrganization: { formButtonSubmit: 'సంస్థను సృష్టించండి', diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index 98926b01cb4..9d2d342c010 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -190,6 +190,20 @@ export const thTH: LocalizationResource = { navbar: { title: 'กำหนดค่าการลงชื่อเข้าใช้แบบครั้งเดียว (SSO)', }, + selectProviderStep: { + title: 'เลือกผู้ให้บริการ', + subtitle: 'เลือกผู้ให้บริการที่คุณจะตั้งค่า SSO ให้', + body: { + title: 'เลือกผู้ให้บริการข้อมูลประจำตัวของคุณ', + description: 'เราจะแนะนำคุณตลอดกระบวนการตั้งค่าโดยละเอียดในขั้นตอนถัดไป', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'ผู้ให้บริการ SAML แบบกำหนดเอง', + }, + warning: 'เมื่อเลือกผู้ให้บริการแล้วคุณไม่สามารถเปลี่ยนได้อีกจนกว่าการกำหนดค่าจะเสร็จสิ้น', + }, }, createOrganization: { formButtonSubmit: 'สร้างองค์กร', diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index f9ec3b6f23c..e3dbea0e756 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -186,6 +186,20 @@ export const trTR: LocalizationResource = { navbar: { title: 'Tek Oturum Açmayı (SSO) Yapılandır', }, + selectProviderStep: { + title: 'Sağlayıcıyı seçin', + subtitle: "SSO'yu ayarlayacağınız sağlayıcıyı seçin.", + body: { + title: 'Kimlik sağlayıcınızı seçin', + description: 'Bir sonraki adımda sizi ayrıntılı kurulum sürecinde yönlendireceğiz.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Özel SAML Sağlayıcısı', + }, + warning: 'Bir sağlayıcı seçildikten sonra yapılandırma bitene kadar tekrar değiştiremezsiniz', + }, }, createOrganization: { formButtonSubmit: 'Oluştur', diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index 4a13fb2776e..a4e61bdcdd3 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -187,6 +187,20 @@ export const ukUA: LocalizationResource = { navbar: { title: 'Налаштувати єдиний вхід (SSO)', }, + selectProviderStep: { + title: 'Виберіть постачальника', + subtitle: 'Виберіть постачальника, для якого ви налаштовуватимете SSO.', + body: { + title: 'Виберіть вашого постачальника ідентифікації', + description: 'Далі ми проведемо вас через детальний процес налаштування.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Користувацький постачальник SAML', + }, + warning: 'Після вибору постачальника ви не зможете змінити його, доки не буде завершено налаштування', + }, }, createOrganization: { formButtonSubmit: 'Створити організацію', diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index 6bedf43ee58..6f922bb3ea9 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -190,6 +190,20 @@ export const viVN: LocalizationResource = { navbar: { title: 'Cấu hình đăng nhập một lần (SSO)', }, + selectProviderStep: { + title: 'Chọn nhà cung cấp', + subtitle: 'Chọn nhà cung cấp mà bạn sẽ thiết lập SSO cho.', + body: { + title: 'Chọn nhà cung cấp danh tính của bạn', + description: 'Chúng tôi sẽ hướng dẫn bạn qua quy trình thiết lập chi tiết tiếp theo.', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: 'Nhà cung cấp SAML tùy chỉnh', + }, + warning: 'Khi đã chọn nhà cung cấp, bạn không thể thay đổi cho đến khi cấu hình hoàn tất', + }, }, createOrganization: { formButtonSubmit: 'Tạo tổ chức', diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index f70f9fe53d6..67d4fc6553e 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -186,6 +186,20 @@ export const zhCN: LocalizationResource = { navbar: { title: '配置单点登录 (SSO)', }, + selectProviderStep: { + title: '选择提供商', + subtitle: '选择您要为其设置 SSO 的提供商。', + body: { + title: '选择您的身份提供商', + description: '接下来我们将引导您完成详细的设置过程。', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: '自定义 SAML 提供商', + }, + warning: '选择提供商后,在配置完成之前无法再次更改', + }, }, createOrganization: { formButtonSubmit: '创建组织', diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index 3cdb738b844..ea4adf9a991 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -192,6 +192,20 @@ export const zhTW: LocalizationResource = { navbar: { title: '設定單一登入 (SSO)', }, + selectProviderStep: { + title: '選擇提供者', + subtitle: '選擇您要為其設定 SSO 的提供者。', + body: { + title: '選擇您的身分提供者', + description: '接下來我們將引導您完成詳細的設定流程。', + }, + saml: { + groupLabel: 'SAML', + okta: 'Okta Workforce', + customSaml: '自訂 SAML 提供者', + }, + warning: '選擇提供者後,在設定完成之前無法再次變更', + }, }, createOrganization: { formButtonSubmit: '創建組織', diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index b7479311b84..1123b6e88fb 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -1293,12 +1293,26 @@ export type __internal_LocalizationResource = { }; }; configureSSO: { + missingManageEnterpriseConnectionsPermission: { + title: LocalizationValue; + subtitle: LocalizationValue; + }; navbar: { title: LocalizationValue; }; - missingManageEnterpriseConnectionsPermission: { + selectProviderStep: { title: LocalizationValue; subtitle: LocalizationValue; + body: { + title: LocalizationValue; + description: LocalizationValue; + }; + saml: { + groupLabel: LocalizationValue; + okta: LocalizationValue; + customSaml: LocalizationValue; + }; + warning: LocalizationValue; }; }; apiKeys: { diff --git a/packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx b/packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx index 4ab8dcccb3d..9be9db0a9ea 100644 --- a/packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx +++ b/packages/ui/src/components/ConfigureSSO/ConfigureSSO.tsx @@ -10,7 +10,7 @@ import { ProfileCard } from '@/elements/ProfileCard'; import { ExclamationTriangle } from '@/icons'; import { Route, Switch } from '@/router'; -import { ConfigureSSOFlowProvider } from './ConfigureSSOContext'; +import { ConfigureSSOProvider, useConfigureSSO } from './ConfigureSSOContext'; import { ConfigureSSOHeader } from './ConfigureSSOHeader'; import { ConfigureSSONavbar } from './ConfigureSSONavbar'; import { ConfigureSSOSkeleton } from './ConfigureSSOSkeleton'; @@ -64,7 +64,11 @@ const AuthenticatedContent = withCoreUserGuard(() => { }); const ConfigureSSOCardContent = () => { - const { data: enterpriseConnections, isLoading } = __internal_useUserEnterpriseConnections({ enabled: true }); + const { + data: enterpriseConnections, + isLoading, + createEnterpriseConnection, + } = __internal_useUserEnterpriseConnections({ enabled: true }); // Currently FAPI only supports one enterprise connection per user const enterpriseConnection = enterpriseConnections?.[0]; @@ -74,43 +78,54 @@ const ConfigureSSOCardContent = () => { } return ( - - - + + + + ); +}; - - - +const ConfigureSSOSteps = () => { + const { initialStepId } = useConfigureSSO(); - - - + return ( + + - - - + + + - - - + + + - - - - - + + + + + + + + + + + + ); }; diff --git a/packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx b/packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx index 9513ca41a5e..42a3b2f67c7 100644 --- a/packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx +++ b/packages/ui/src/components/ConfigureSSO/ConfigureSSOContext.tsx @@ -1,41 +1,102 @@ -import type { EnterpriseConnectionResource } from '@clerk/shared/types'; +import { useReverification, useSession, useUser } from '@clerk/shared/react'; +import type { CreateMeEnterpriseConnectionParams, EnterpriseConnectionResource } from '@clerk/shared/types'; import React, { type PropsWithChildren } from 'react'; +import { deriveInitialStep } from './deriveInitialStep'; +import type { ProviderType, WizardStepId } from './types'; + /** * Shared form state for the ConfigureSSO wizard, persisted across steps */ export interface ConfigureSSOData { + initialStepId: WizardStepId; /** * The enterprise connection from the user's primary email address domain */ enterpriseConnection: EnterpriseConnectionResource | undefined; + /** + * The provider selected for this configuration. Reads from the existing + * enterprise connection when present, falling back to the local selection + * made on the Select Provider step. + */ + provider: ProviderType | undefined; + /** + * Sets the local provider selection used by Select Provider before a + * connection has been created. + */ + setProvider: (provider: ProviderType) => void; + /** + * Creates the enterprise connection for the supplied provider, the user's + * primary email domain, and the session's active organization. No-ops when + * an enterprise connection already exists so callers can safely re-trigger. + */ + createConnection: (provider: ProviderType) => Promise; } -interface ConfigureSSOFlowProviderProps { +interface ConfigureSSOProviderProps { enterpriseConnection: EnterpriseConnectionResource | undefined; + createEnterpriseConnection: ( + params: CreateMeEnterpriseConnectionParams, + ) => Promise; } -const ConfigureSSOFlowContext = React.createContext(null); -ConfigureSSOFlowContext.displayName = 'ConfigureSSOFlowContext'; +const ConfigureSSOContext = React.createContext(null); +ConfigureSSOContext.displayName = 'ConfigureSSOContext'; -export const ConfigureSSOFlowProvider = ({ +export const ConfigureSSOProvider = ({ enterpriseConnection, + createEnterpriseConnection, children, -}: PropsWithChildren): JSX.Element => { +}: PropsWithChildren): JSX.Element => { + const { user } = useUser(); + const { session } = useSession(); + const [provider, setProvider] = React.useState( + enterpriseConnection?.provider as ProviderType, + ); + + const initialStepId = deriveInitialStep(enterpriseConnection); + + const createConnectionFetcher = React.useCallback( + async (selectedProvider: ProviderType) => { + if (enterpriseConnection) { + return; + } + if (!user?.primaryEmailAddress) { + throw new Error('Primary email required'); + } + + const emailDomain = user.primaryEmailAddress.emailAddress.split('@')[1]; + const organizationId = session?.lastActiveOrganizationId ?? null; + + await createEnterpriseConnection({ + provider: selectedProvider, + name: emailDomain, + organizationId, + }); + }, + [enterpriseConnection, user, session, createEnterpriseConnection], + ); + + const createConnection = useReverification(createConnectionFetcher); + const value = React.useMemo( () => ({ + initialStepId, enterpriseConnection, + provider, + setProvider, + createConnection, }), - [enterpriseConnection], + [initialStepId, enterpriseConnection, provider, createConnection], ); - return {children}; + return {children}; }; -export const useConfigureSSOFlow = (): ConfigureSSOData => { - const ctx = React.useContext(ConfigureSSOFlowContext); +export const useConfigureSSO = (): ConfigureSSOData => { + const ctx = React.useContext(ConfigureSSOContext); if (!ctx) { - throw new Error('useConfigureSSOFlow called outside .'); + throw new Error('useConfigureSSO called outside .'); } return ctx; }; diff --git a/packages/ui/src/components/ConfigureSSO/__tests__/deriveInitialStep.test.ts b/packages/ui/src/components/ConfigureSSO/__tests__/deriveInitialStep.test.ts new file mode 100644 index 00000000000..2f67bbcc603 --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/__tests__/deriveInitialStep.test.ts @@ -0,0 +1,89 @@ +import type { EnterpriseConnectionResource } from '@clerk/shared/types'; +import { describe, expect, it } from 'vitest'; + +import { deriveInitialStep } from '../deriveInitialStep'; +import type { WizardStepId } from '../types'; + +const makeConnection = (overrides: Partial = {}): EnterpriseConnectionResource => + ({ + id: 'enc_1', + name: 'acme.com', + active: false, + provider: 'saml_okta', + logoPublicUrl: null, + domains: ['acme.com'], + organizationId: null, + syncUserAttributes: false, + disableAdditionalIdentifications: false, + allowOrganizationAccountLinking: false, + customAttributes: [], + oauthConfig: null, + samlConnection: null, + createdAt: null, + updatedAt: null, + __internal_toSnapshot: () => ({}) as any, + ...overrides, + }) as EnterpriseConnectionResource; + +describe('deriveInitialStep', () => { + const cases: Array<{ name: string; input: EnterpriseConnectionResource | undefined; expected: WizardStepId }> = [ + { + name: 'no connection → select-provider', + input: undefined, + expected: 'select-provider', + }, + { + name: 'connection without samlConnection → configure', + input: makeConnection({ samlConnection: null }), + expected: 'configure', + }, + { + name: 'connection with empty samlConnection.idpSsoUrl → configure', + input: makeConnection({ + samlConnection: { + id: 'saml_1', + name: 'acme.com', + active: false, + idpEntityId: '', + idpSsoUrl: '', + idpCertificate: '', + idpMetadataUrl: '', + idpMetadata: '', + acsUrl: 'https://clerk.example.com/acs', + spEntityId: 'https://clerk.example.com', + spMetadataUrl: 'https://clerk.example.com/sp-metadata', + allowSubdomains: false, + allowIdpInitiated: false, + forceAuthn: false, + }, + }), + expected: 'configure', + }, + { + name: 'connection with samlConnection.idpSsoUrl populated → confirmation', + input: makeConnection({ + samlConnection: { + id: 'saml_1', + name: 'acme.com', + active: true, + idpEntityId: 'https://idp.example.com/entity', + idpSsoUrl: 'https://idp.example.com/sso', + idpCertificate: 'CERT', + idpMetadataUrl: 'https://idp.example.com/metadata', + idpMetadata: '', + acsUrl: 'https://clerk.example.com/acs', + spEntityId: 'https://clerk.example.com', + spMetadataUrl: 'https://clerk.example.com/sp-metadata', + allowSubdomains: false, + allowIdpInitiated: false, + forceAuthn: false, + }, + }), + expected: 'confirmation', + }, + ]; + + it.each(cases)('$name', ({ input, expected }) => { + expect(deriveInitialStep(input)).toBe(expected); + }); +}); diff --git a/packages/ui/src/components/ConfigureSSO/deriveInitialStep.ts b/packages/ui/src/components/ConfigureSSO/deriveInitialStep.ts new file mode 100644 index 00000000000..fb19fee3138 --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/deriveInitialStep.ts @@ -0,0 +1,25 @@ +import type { EnterpriseConnectionResource } from '@clerk/shared/types'; + +import type { WizardStepId } from './types'; + +/** + * Decides where the ConfigureSSO wizard should mount on (re)load based on + * the current state of the user's enterprise connection. + * + * No connection → `select-provider` + * Connection without SAML IdP metadata → `configure` + * Connection with SAML IdP metadata → `confirmation` + * + * The `test` step is intentionally absent — we can't derive a "last test + * passed" signal synchronously from the resource. Users can re-test from + * Confirmation. + */ +export const deriveInitialStep = (connection: EnterpriseConnectionResource | undefined): WizardStepId => { + if (!connection) { + return 'select-provider'; + } + if (!connection.samlConnection?.idpSsoUrl) { + return 'configure'; + } + return 'confirmation'; +}; diff --git a/packages/ui/src/components/ConfigureSSO/elements/Step.tsx b/packages/ui/src/components/ConfigureSSO/elements/Step.tsx index a3fc56adebd..10d39a377d1 100644 --- a/packages/ui/src/components/ConfigureSSO/elements/Step.tsx +++ b/packages/ui/src/components/ConfigureSSO/elements/Step.tsx @@ -54,11 +54,11 @@ const Header = ({ title, description, children }: StepHeaderProps): JSX.Element })} > ({ gap: theme.space.$4 })} > - ({ gap: theme.space.$1x5, minWidth: 0 })}> + ({ gap: theme.space.$2, minWidth: 0 })}> ({ color: theme.colors.$colorForeground, fontSize: theme.fontSizes.$lg })} diff --git a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx index 5b19dbb43c9..af420302c57 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/ConfigureStep.tsx @@ -1,10 +1,12 @@ -import { descriptors, Flow, Text } from '@/customizables'; +import { descriptors, Flow } from '@/customizables'; +import { useConfigureSSO } from '../ConfigureSSOContext'; import { Step } from '../elements/Step'; import { useWizard } from '../elements/Wizard'; export const ConfigureStep = (): JSX.Element => { const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); + const { enterpriseConnection } = useConfigureSSO(); return ( @@ -18,9 +20,7 @@ export const ConfigureStep = (): JSX.Element => { /> - - UI goes here - + Single sign-on URL: {enterpriseConnection?.samlConnection?.acsUrl} diff --git a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx index f27de65c496..2d0bdb79e98 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/SelectProviderStep.tsx @@ -1,10 +1,71 @@ -import { descriptors, Flow, Text } from '@/customizables'; +import { iconImageUrl } from '@clerk/shared/constants'; +import React from 'react'; +import type { LocalizationKey } from '@/customizables'; +import { + Col, + descriptors, + Flow, + Grid, + localizationKeys, + SimpleButton, + Span, + Text, + useLocalizations, +} from '@/customizables'; +import { useCardState } from '@/elements/contexts'; +import { mqu } from '@/styledSystem'; +import { Alert } from '@/ui/elements/Alert'; +import { handleError } from '@/utils/errorHandler'; + +import { useConfigureSSO } from '../ConfigureSSOContext'; import { Step } from '../elements/Step'; import { useWizard } from '../elements/Wizard'; +import type { ProviderType } from '../types'; + +const PROVIDER_GROUPS: ReadonlyArray<{ + id: 'saml'; + label: LocalizationKey; + options: ReadonlyArray<{ id: ProviderType; label: LocalizationKey; iconId: string }>; +}> = [ + { + id: 'saml', + label: localizationKeys('configureSSO.selectProviderStep.saml.groupLabel'), + options: [ + { id: 'saml_okta', label: localizationKeys('configureSSO.selectProviderStep.saml.okta'), iconId: 'okta' }, + { + id: 'saml_custom', + label: localizationKeys('configureSSO.selectProviderStep.saml.customSaml'), + iconId: 'saml', + }, + ], + }, +]; export const SelectProviderStep = (): JSX.Element => { - const { goNext, goPrev, isFirstStep, isLastStep } = useWizard(); + const card = useCardState(); + const { goNext } = useWizard(); + const { setProvider, createConnection } = useConfigureSSO(); + const [selected, setSelected] = React.useState(null); + + const handleContinue = async () => { + if (!selected) { + return; + } + + setProvider(selected); + card.setError(undefined); + card.setLoading(); + + try { + await createConnection(selected); + void goNext(); + } catch (err) { + handleError(err as Error, [], card.setError); + } finally { + card.setIdle(); + } + }; return ( @@ -13,27 +74,144 @@ export const SelectProviderStep = (): JSX.Element => { elementId={descriptors.configureSSOStep.setId('select-provider')} > - - UI goes here + ({ gap: theme.space.$5 })}> + ({ gap: theme.space.$1x5 })}> + ({ color: theme.colors.$colorForeground })} + localizationKey={localizationKeys('configureSSO.selectProviderStep.body.title')} + /> + + ({ color: theme.colors.$colorMutedForeground })} + localizationKey={localizationKeys('configureSSO.selectProviderStep.body.description')} + /> + + + {PROVIDER_GROUPS.map(group => ( + ({ gap: theme.space.$3 })} + > + ({ color: theme.colors.$colorForeground })} + localizationKey={group.label} + /> + + + {group.options.map(option => ( + setSelected(option.id)} + /> + ))} + + + ))} + + + + {card.error ? ( + ({ color: theme.colors.$danger500, fontSize: theme.fontSizes.$sm })} + > + {card.error} + + ) : null} - goPrev()} - isDisabled={isFirstStep} - /> + + goNext()} - isDisabled={isLastStep} + onClick={handleContinue} + isLoading={card.isLoading} + isDisabled={!selected || card.isLoading} /> ); }; + +type ProviderCardProps = { + iconId: string; + label: LocalizationKey; + isSelected?: boolean; + onClick?: () => void; +}; + +const ProviderCard = ({ iconId, label, isSelected, onClick }: ProviderCardProps): JSX.Element => { + const { t } = useLocalizations(); + const labelText = t(label); + + return ( + ({ + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + gap: theme.space.$2, + height: theme.sizes.$32, + padding: theme.space.$1x5, + backgroundColor: theme.colors.$colorBackground, + ...(isSelected + ? { + boxShadow: `0 0 0 4px ${theme.colors.$colorRing}`, + } + : {}), + })} + > + ({ + width: theme.sizes.$8, + height: theme.sizes.$8, + backgroundImage: `url(${iconImageUrl(iconId)})`, + backgroundSize: 'contain', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + })} + /> + + ({ color: theme.colors.$colorForeground })} + > + {labelText} + + + ); +}; diff --git a/packages/ui/src/components/ConfigureSSO/steps/__tests__/SelectProviderStep.test.tsx b/packages/ui/src/components/ConfigureSSO/steps/__tests__/SelectProviderStep.test.tsx new file mode 100644 index 00000000000..115c6b6efd3 --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/steps/__tests__/SelectProviderStep.test.tsx @@ -0,0 +1,248 @@ +import { ClerkRuntimeError } from '@clerk/shared/error'; +import type { ReactElement } from 'react'; +import { describe, expect, it, vi } from 'vitest'; + +import { bindCreateFixtures } from '@/test/create-fixtures'; +import { render, screen, waitFor } from '@/test/utils'; +import { CardStateProvider } from '@/ui/elements/contexts'; + +const goNext = vi.fn(); +const goPrev = vi.fn(); + +vi.mock('../../elements/Wizard', () => ({ + useWizard: () => ({ + activeSteps: [], + currentStep: undefined, + currentIndex: -1, + totalSteps: 0, + isFirstStep: true, + isLastStep: false, + isNested: false, + goNext, + goPrev, + goToStep: vi.fn(), + registerStep: vi.fn(), + unregisterStep: vi.fn(), + }), +})); + +const setProvider = vi.fn(); +const clearProvider = vi.fn(); +const createConnection = vi.fn(); + +vi.mock('../../ConfigureSSOContext', () => ({ + useConfigureSSO: () => ({ + enterpriseConnection: undefined, + provider: undefined, + setProvider, + clearProvider, + createConnection, + }), +})); + +import { SelectProviderStep } from '../SelectProviderStep'; + +const { createFixtures } = bindCreateFixtures('ConfigureSSO'); + +const renderStep = ( + wrapper: React.ComponentType<{ children?: React.ReactNode }>, + ui: ReactElement = , +) => { + return render({ui}, { wrapper }); +}; + +const resetMocks = () => { + goNext.mockReset(); + goPrev.mockReset(); + setProvider.mockReset(); + clearProvider.mockReset(); + createConnection.mockReset(); + createConnection.mockResolvedValue(undefined); +}; + +describe('SelectProviderStep', () => { + it('mounts and renders the step header', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + renderStep(wrapper); + + expect(screen.getByRole('heading', { name: 'Select provider' })).toBeInTheDocument(); + expect(screen.getByText('Select your identity provider')).toBeInTheDocument(); + }); + + it('renders both SAML provider tiles with their labels', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + renderStep(wrapper); + + expect(screen.getByRole('button', { name: 'Okta Workforce' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Custom SAML Provider' })).toBeInTheDocument(); + }); + + it('loads each tile icon from img.clerk.com', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + const { container } = renderStep(wrapper); + + // Emotion serializes sx into stylesheets, so we check both inline + the document's collected styles + const iconSpans = Array.from(container.querySelectorAll('button span[aria-hidden]')); + expect(iconSpans).toHaveLength(2); + + const collectedStyles = [ + ...Array.from(document.head.querySelectorAll('style')).map(s => s.textContent ?? ''), + ...iconSpans.map(el => (el as HTMLElement).style.backgroundImage ?? ''), + ].join('\n'); + + expect(collectedStyles).toMatch(/img\.clerk\.com\/static\/okta\.svg/); + expect(collectedStyles).toMatch(/img\.clerk\.com\/static\/saml\.svg/); + }); + + it('disables Continue when no provider is selected', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + renderStep(wrapper); + + expect(screen.getByRole('button', { name: /Continue/i })).toBeDisabled(); + }); + + it('marks the clicked tile as pressed and enables Continue', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + const { userEvent } = renderStep(wrapper); + + const oktaTile = screen.getByRole('button', { name: 'Okta Workforce' }); + expect(oktaTile).toHaveAttribute('aria-pressed', 'false'); + + await userEvent.click(oktaTile); + + expect(oktaTile).toHaveAttribute('aria-pressed', 'true'); + expect(screen.getByRole('button', { name: /Continue/i })).toBeEnabled(); + }); + + it('flips selection when a different tile is clicked', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + const { userEvent } = renderStep(wrapper); + + const oktaTile = screen.getByRole('button', { name: 'Okta Workforce' }); + const customSamlTile = screen.getByRole('button', { name: 'Custom SAML Provider' }); + + await userEvent.click(oktaTile); + expect(oktaTile).toHaveAttribute('aria-pressed', 'true'); + expect(customSamlTile).toHaveAttribute('aria-pressed', 'false'); + + await userEvent.click(customSamlTile); + expect(oktaTile).toHaveAttribute('aria-pressed', 'false'); + expect(customSamlTile).toHaveAttribute('aria-pressed', 'true'); + }); + + it('calls setProvider, createConnection, then goNext when Continue is clicked', async () => { + resetMocks(); + const callOrder: string[] = []; + setProvider.mockImplementation(() => { + callOrder.push('setProvider'); + }); + createConnection.mockImplementation(() => { + callOrder.push('createConnection'); + return Promise.resolve(); + }); + goNext.mockImplementation(() => { + callOrder.push('goNext'); + }); + + const { wrapper } = await createFixtures(); + const { userEvent } = renderStep(wrapper); + + await userEvent.click(screen.getByRole('button', { name: 'Okta Workforce' })); + await userEvent.click(screen.getByRole('button', { name: /Continue/i })); + + await waitFor(() => { + expect(goNext).toHaveBeenCalledTimes(1); + }); + + expect(setProvider).toHaveBeenCalledWith('saml_okta'); + expect(createConnection).toHaveBeenCalledTimes(1); + expect(createConnection).toHaveBeenCalledWith('saml_okta'); + expect(callOrder).toEqual(['setProvider', 'createConnection', 'goNext']); + }); + + it('forwards the Custom SAML backend provider id when selected', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + const { userEvent } = renderStep(wrapper); + + await userEvent.click(screen.getByRole('button', { name: 'Custom SAML Provider' })); + await userEvent.click(screen.getByRole('button', { name: /Continue/i })); + + await waitFor(() => { + expect(goNext).toHaveBeenCalledTimes(1); + }); + + expect(setProvider).toHaveBeenCalledWith('saml_custom'); + expect(createConnection).toHaveBeenCalledTimes(1); + expect(createConnection).toHaveBeenCalledWith('saml_custom'); + }); + + it('shows loading state while createConnection is pending', async () => { + resetMocks(); + let resolveCreate: () => void = () => undefined; + createConnection.mockImplementation( + () => + new Promise(resolve => { + resolveCreate = resolve; + }), + ); + + const { wrapper } = await createFixtures(); + const { userEvent } = renderStep(wrapper); + + await userEvent.click(screen.getByRole('button', { name: 'Okta Workforce' })); + const continueButton = screen.getByRole('button', { name: /Continue/i }); + await userEvent.click(continueButton); + + // While create is pending, Continue stays disabled and goNext hasn't fired. + // The button's accessible name flips to the spinner's "Loading" label while pending. + await waitFor(() => { + expect(createConnection).toHaveBeenCalledTimes(1); + }); + expect(continueButton).toBeDisabled(); + expect(goNext).not.toHaveBeenCalled(); + + resolveCreate(); + + await waitFor(() => { + expect(goNext).toHaveBeenCalledTimes(1); + }); + }); + + it('does not advance and surfaces the error when createConnection rejects', async () => { + resetMocks(); + createConnection.mockRejectedValue(new ClerkRuntimeError('Backend unavailable', { code: 'create_failed' })); + + const { wrapper } = await createFixtures(); + const { userEvent, container } = renderStep(wrapper); + + await userEvent.click(screen.getByRole('button', { name: 'Okta Workforce' })); + await userEvent.click(screen.getByRole('button', { name: /Continue/i })); + + await waitFor(() => { + expect(createConnection).toHaveBeenCalledTimes(1); + }); + + expect(goNext).not.toHaveBeenCalled(); + expect(setProvider).toHaveBeenCalledWith('saml_okta'); + // Allow microtasks to flush so the rejection -> handleError -> setError chain settles + await waitFor(() => { + const text = container.textContent ?? ''; + expect(text).toContain('Backend unavailable'); + }); + }); + + it('disables Previous on the first step', async () => { + resetMocks(); + const { wrapper } = await createFixtures(); + renderStep(wrapper); + + expect(screen.getByRole('button', { name: /Previous/i })).toBeDisabled(); + }); +}); diff --git a/packages/ui/src/components/ConfigureSSO/types.ts b/packages/ui/src/components/ConfigureSSO/types.ts new file mode 100644 index 00000000000..f138ef38387 --- /dev/null +++ b/packages/ui/src/components/ConfigureSSO/types.ts @@ -0,0 +1,3 @@ +export type ProviderType = 'saml_okta' | 'saml_custom'; + +export type WizardStepId = 'select-provider' | 'verify-domain' | 'configure' | 'test' | 'confirmation';