diff --git a/.changeset/bright-trees-retry.md b/.changeset/bright-trees-retry.md new file mode 100644 index 00000000000..72cfb14b46a --- /dev/null +++ b/.changeset/bright-trees-retry.md @@ -0,0 +1,7 @@ +--- +'@clerk/ui': patch +'@clerk/localizations': patch +'@clerk/shared': patch +--- + +Add a "Re-issue" action to pending self-serve SSO domains, which issues a fresh TXT record when the published one is stale. Each successful re-issue starts a five-minute cooldown, explained on the disabled button. diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index 412c5ad3367..a4eeed877cb 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -729,6 +729,7 @@ export const arSA: LocalizationResource = { }, verifiedAtLabel: "تم التحقق في {{ date | shortDate('en-US') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'إضافة {{domain}}', diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index 6171efa76f1..296d62577bb 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -730,6 +730,7 @@ export const beBY: LocalizationResource = { }, verifiedAtLabel: "Пацверджана {{ date | shortDate('be-BY') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Дадаць {{domain}}', diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index 5c24af73f66..8a526945ee9 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -731,6 +731,7 @@ export const bgBG: LocalizationResource = { }, verifiedAtLabel: "Потвърден на {{ date | shortDate('bg-BG') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Добавяне на {{domain}}', diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index dd477c1dacd..f7d11ea4829 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -736,6 +736,7 @@ export const bnIN: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('bn-IN') }} তারিখে যাচাই করা হয়েছে", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} যোগ করুন', diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index c7a12dcd007..ccdb2689b1f 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -737,6 +737,7 @@ export const caES: LocalizationResource = { }, verifiedAtLabel: "Verificat el {{ date | shortDate('ca-ES') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Afegeix {{domain}}', diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index 794f8c5b0a8..011d2df60f7 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -734,6 +734,7 @@ export const csCZ: LocalizationResource = { }, verifiedAtLabel: "Ověřeno {{ date | shortDate('cs-CZ') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Přidat {{domain}}', diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index 7726dd8f310..15dc0386e96 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -729,6 +729,7 @@ export const daDK: LocalizationResource = { }, verifiedAtLabel: "Bekræftet den {{ date | shortDate('da-DK') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Tilføj {{domain}}', diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index 2d615e35ee0..30802c28b35 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -736,6 +736,7 @@ export const deDE: LocalizationResource = { }, verifiedAtLabel: "Verifiziert am {{ date | shortDate('de-DE') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} hinzufügen', diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index b0f43aabb26..b98af50af82 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -730,6 +730,7 @@ export const elGR: LocalizationResource = { }, verifiedAtLabel: "Επαληθεύτηκε στις {{ date | shortDate('el-GR') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Προσθήκη {{domain}}', diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 6c1415128ad..672cce5fe22 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -729,6 +729,7 @@ export const enGB: LocalizationResource = { }, verifiedAtLabel: "Verified on {{ date | shortDate('en-GB') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Add {{domain}}', diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 4c4e33bcd4c..df1e9126eb0 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -745,7 +745,8 @@ export const enUS: LocalizationResource = { valueLabel: 'Value', }, verifiedAtLabel: "Verified on {{ date | shortDate('en-US') }}", - verifyAgainButton: 'Verify again', + verifyAgainButton: 'Re-issue', + verifyAgainButtonTooltip__throttled: 'A new record was just issued. You can issue another one shortly.', }, domainSuggestion: { formButtonPrimary__add: 'Add {{domain}}', diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index 051c1c8e592..ba1b831dfdb 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -730,6 +730,7 @@ export const esCR: LocalizationResource = { }, verifiedAtLabel: "Verificado el {{ date | shortDate('es-CR') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Agregar {{domain}}', diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index a28358daa7e..84bc4dcadf2 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -736,6 +736,7 @@ export const esES: LocalizationResource = { }, verifiedAtLabel: "Verificado el {{ date | shortDate('es-ES') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Añadir {{domain}}', diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index 43d21afac61..33703106b40 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -731,6 +731,7 @@ export const esMX: LocalizationResource = { }, verifiedAtLabel: "Verificado el {{ date | shortDate('es-MX') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Agregar {{domain}}', diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index 59cf112290f..49bae67373d 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -730,6 +730,7 @@ export const esUY: LocalizationResource = { }, verifiedAtLabel: "Verificado el {{ date | shortDate('es-UY') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Agregar {{domain}}', diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index 8b90baf9f22..d71d9fa0b72 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -735,6 +735,7 @@ export const faIR: LocalizationResource = { }, verifiedAtLabel: "تأیید‌شده در {{ date | shortDate('fa-IR') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'افزودن {{domain}}', diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index c7ee3488ae9..dbfc401f3b7 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -736,6 +736,7 @@ export const fiFI: LocalizationResource = { }, verifiedAtLabel: "Vahvistettu {{ date | shortDate('fi-FI') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Lisää {{domain}}', diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index aa019e5fa48..565f5b129a2 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -738,6 +738,7 @@ export const frFR: LocalizationResource = { }, verifiedAtLabel: "Vérifié le {{ date | shortDate('fr-FR') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Ajouter {{domain}}', diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index a95959d3aab..16a0af7143b 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -729,6 +729,7 @@ export const heIL: LocalizationResource = { }, verifiedAtLabel: "אומת בתאריך {{ date | shortDate('he-IL') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'הוסף {{domain}}', diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index 3331c95b3a3..d0cd1f54b29 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -736,6 +736,7 @@ export const hiIN: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('hi-IN') }} को सत्यापित", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} जोड़ें', diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index 3cd2486c91a..9645fe74204 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -737,6 +737,7 @@ export const hrHR: LocalizationResource = { }, verifiedAtLabel: "Potvrđeno {{ date | shortDate('hr-HR') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Dodaj {{domain}}', diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index ecbc5857b1c..71205a85475 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -737,6 +737,7 @@ export const huHU: LocalizationResource = { }, verifiedAtLabel: "Igazolva: {{ date | shortDate('hu-HU') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} hozzáadása', diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index 890a5432be7..b52d005b444 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -730,6 +730,7 @@ export const idID: LocalizationResource = { }, verifiedAtLabel: "Diverifikasi pada {{ date | shortDate('id-ID') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Tambah {{domain}}', diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index bbea10b5afd..12bc9f56ffc 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -736,6 +736,7 @@ export const isIS: LocalizationResource = { }, verifiedAtLabel: "Staðfest {{ date | shortDate('is-IS') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Bæta við {{domain}}', diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index 0919d7813ef..ac9b79722b0 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -736,6 +736,7 @@ export const itIT: LocalizationResource = { }, verifiedAtLabel: "Verificato il {{ date | shortDate('it-IT') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Aggiungi {{domain}}', diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index 79b739b0e20..41c965b8c0e 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -737,6 +737,7 @@ export const jaJP: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('ja-JP') }} に確認", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} を追加', diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index 5739bb8e83f..ba8406ebf59 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -730,6 +730,7 @@ export const kkKZ: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('kk-KZ') }} күні расталды", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} қосу', diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index 4070b2a7d16..f236577d12c 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -733,6 +733,7 @@ export const koKR: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('ko-KR') }}에 확인됨", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} 추가', diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index 66ad147f594..40dffe38626 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -730,6 +730,7 @@ export const mnMN: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('mn-MN') }}-нд баталгаажсан", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} нэмэх', diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index 28f3b8fa362..1604f3a2309 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -738,6 +738,7 @@ export const msMY: LocalizationResource = { }, verifiedAtLabel: "Disahkan pada {{ date | shortDate('ms-MY') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Tambah {{domain}}', diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index 634d14772cf..eddd40a1dea 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -737,6 +737,7 @@ export const nbNO: LocalizationResource = { }, verifiedAtLabel: "Verifisert den {{ date | shortDate('nb-NO') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Legg til {{domain}}', diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index 7584091ffb9..ed31d02378c 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -730,6 +730,7 @@ export const nlBE: LocalizationResource = { }, verifiedAtLabel: "Geverifieerd op {{ date | shortDate('nl-BE') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} toevoegen', diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index 3bc6bff7ac1..e42798d2b1f 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -730,6 +730,7 @@ export const nlNL: LocalizationResource = { }, verifiedAtLabel: "Geverifieerd op {{ date | shortDate('nl-NL') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} toevoegen', diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index be54a14ff4e..4ecf0d19412 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -730,6 +730,7 @@ export const plPL: LocalizationResource = { }, verifiedAtLabel: "Zweryfikowano {{ date | shortDate('pl-PL') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Dodaj {{domain}}', diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index 42e0c5b08f7..5d34ce28b37 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -736,6 +736,7 @@ export const ptBR: LocalizationResource = { }, verifiedAtLabel: "Verificado em {{ date | shortDate('pt-BR') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Adicionar {{domain}}', diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index d136f7b6fca..08d29400c7f 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -738,6 +738,7 @@ export const ptPT: LocalizationResource = { }, verifiedAtLabel: "Verificado em {{ date | shortDate('pt-PT') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Adicionar {{domain}}', diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index ffb22de2fc2..d197fb3791b 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -736,6 +736,7 @@ export const roRO: LocalizationResource = { }, verifiedAtLabel: "Verificat pe {{ date | shortDate('ro-RO') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Adaugă {{domain}}', diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index a8552a376d7..214e3b26a70 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -730,6 +730,7 @@ export const ruRU: LocalizationResource = { }, verifiedAtLabel: "Подтверждён {{ date | shortDate('ru-RU') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Добавить {{domain}}', diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index 386d4b8e6a2..e8dc2b08b04 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -730,6 +730,7 @@ export const skSK: LocalizationResource = { }, verifiedAtLabel: "Overené {{ date | shortDate('sk-SK') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Pridať {{domain}}', diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index 729042ee9f9..8782ebf5ffc 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -730,6 +730,7 @@ export const srRS: LocalizationResource = { }, verifiedAtLabel: "Potvrđeno {{ date | shortDate('sr-RS') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Dodaj {{domain}}', diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index 12cea3490e5..1b49c1a42b7 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -730,6 +730,7 @@ export const svSE: LocalizationResource = { }, verifiedAtLabel: "Verifierad den {{ date | shortDate('sv-SE') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Lägg till {{domain}}', diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index c4c30019d93..f0f2f508bb7 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -738,6 +738,7 @@ export const taIN: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('ta-IN') }} அன்று சரிபார்க்கப்பட்டது", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} ஐச் சேர்', diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index 3e523d8d58d..b6baf26ade6 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -737,6 +737,7 @@ export const teIN: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('te-IN') }} న ధృవీకరించబడింది", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} జోడించు', diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index b86fd886f32..2abb81e961d 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -733,6 +733,7 @@ export const thTH: LocalizationResource = { }, verifiedAtLabel: "ยืนยันเมื่อ {{ date | shortDate('th-TH') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'เพิ่ม {{domain}}', diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index 34ae01d2949..ad8ebbf56c6 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -730,6 +730,7 @@ export const trTR: LocalizationResource = { }, verifiedAtLabel: "{{ date | shortDate('tr-TR') }} tarihinde doğrulandı", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '{{domain}} ekle', diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index d30dea0a59c..fb408990086 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -730,6 +730,7 @@ export const ukUA: LocalizationResource = { }, verifiedAtLabel: "Підтверджено {{ date | shortDate('uk-UA') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Додати {{domain}}', diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index 266cc6d915e..f953808cc7b 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -736,6 +736,7 @@ export const viVN: LocalizationResource = { }, verifiedAtLabel: "Đã xác minh vào {{ date | shortDate('vi-VN') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: 'Thêm {{domain}}', diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index 56a9b1b385a..34cddcdd6c3 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -729,6 +729,7 @@ export const zhCN: LocalizationResource = { }, verifiedAtLabel: "验证于 {{ date | shortDate('zh-CN') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '添加 {{domain}}', diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index 3b8462c96ea..aa0583b1bd4 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -732,6 +732,7 @@ export const zhTW: LocalizationResource = { }, verifiedAtLabel: "驗證於 {{ date | shortDate('zh-TW') }}", verifyAgainButton: undefined, + verifyAgainButtonTooltip__throttled: undefined, }, domainSuggestion: { formButtonPrimary__add: '新增 {{domain}}', diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index efb96c465cc..9d8f976430d 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -1442,6 +1442,7 @@ export type __internal_LocalizationResource = { expiredAtLabel: LocalizationValue<'date'>; expiredLabel: LocalizationValue; verifyAgainButton: LocalizationValue; + verifyAgainButtonTooltip__throttled: LocalizationValue; removeButtonTooltip__lastVerifiedDomain: LocalizationValue; removeButtonTooltip__lastVerifiedDomainActive: LocalizationValue; txtRecord: { diff --git a/packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx b/packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx index b5309a864c5..6a5e7dcbdaf 100644 --- a/packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx +++ b/packages/ui/src/components/ConfigureSSO/__tests__/ConfigureSSO.test.tsx @@ -1,7 +1,7 @@ -import { describe, expect, it } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { bindCreateFixtures } from '@/test/create-fixtures'; -import { render, waitFor } from '@/test/utils'; +import { act, render, waitFor } from '@/test/utils'; import { ConfigureSSO } from '../ConfigureSSO'; @@ -23,10 +23,19 @@ const unverifiedDomain = { ownershipVerification: { status: 'unverified', strategy: 'txt' }, } as any; +const expiredDomain = { + ...unverifiedDomain, + ownershipVerification: { status: 'expired', strategy: 'txt', expiresAt: new Date('2026-01-01') }, +}; + const mockOrganizationDomains = (fixtures: any, domains: any[]) => fixtures.clerk.organization?.getDomains.mockResolvedValue({ data: domains, total_count: domains.length } as any); describe('ConfigureSSO', () => { + afterEach(() => { + vi.useRealTimers(); + }); + describe('within an organization', () => { it('shows a warning if the active organization membership lacks the manage enterprise connections permission', async () => { const { wrapper, fixtures } = await createFixtures(f => { @@ -158,6 +167,113 @@ describe('ConfigureSSO', () => { expect(queryByText(/select your identity provider/i)).not.toBeInTheDocument(); }); + it('shows the verification retry action while domain ownership verification is pending', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEnterpriseSso({ selfServeSSO: true }); + f.withEmailAddress(); + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.com'], + organization_memberships: [{ name: 'Org1', permissions: ['org:sys_entconns:manage'] }], + }); + }); + + fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([]); + mockOrganizationDomains(fixtures, [unverifiedDomain]); + + const { findByRole } = render(, { wrapper }); + + await findByRole('button', { name: /re-issue/i }); + }); + + it('throttles domain verification retries for five minutes', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEnterpriseSso({ selfServeSSO: true }); + f.withEmailAddress(); + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.com'], + organization_memberships: [{ name: 'Org1', permissions: ['org:sys_entconns:manage'] }], + }); + }); + + fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([]); + mockOrganizationDomains(fixtures, [expiredDomain]); + fixtures.clerk.organization?.prepareOwnershipVerification.mockResolvedValue({ data: [expiredDomain] } as any); + + const { findByRole, getByRole } = render(, { wrapper }); + await findByRole('button', { name: /re-issue/i }); + + vi.useFakeTimers(); + await act(() => { + getByRole('button', { name: /re-issue/i }).click(); + return Promise.resolve(); + }); + + expect(fixtures.clerk.organization?.prepareOwnershipVerification).toHaveBeenCalledWith([expiredDomain.id]); + expect(getByRole('button', { name: /re-issue/i })).toBeDisabled(); + + act(() => { + vi.advanceTimersByTime(5 * 60 * 1000); + }); + + expect(getByRole('button', { name: /re-issue/i })).not.toBeDisabled(); + }); + + it('explains the cooldown while a domain verification retry is throttled', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEnterpriseSso({ selfServeSSO: true }); + f.withEmailAddress(); + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.com'], + organization_memberships: [{ name: 'Org1', permissions: ['org:sys_entconns:manage'] }], + }); + }); + + fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([]); + mockOrganizationDomains(fixtures, [expiredDomain]); + fixtures.clerk.organization?.prepareOwnershipVerification.mockResolvedValue({ data: [expiredDomain] } as any); + + const { findByRole, getByRole, findByText, userEvent } = render(, { wrapper }); + await userEvent.click(await findByRole('button', { name: /re-issue/i })); + + const throttledButton = await waitFor(() => { + const button = getByRole('button', { name: /re-issue/i }); + expect(button).toBeDisabled(); + return button; + }); + + await userEvent.hover(throttledButton.parentElement as HTMLElement); + await findByText(/you can issue another one shortly/i); + }); + + it('does not throttle domain verification retries when the request fails', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withEnterpriseSso({ selfServeSSO: true }); + f.withEmailAddress(); + f.withOrganizations(); + f.withUser({ + email_addresses: ['test@clerk.com'], + organization_memberships: [{ name: 'Org1', permissions: ['org:sys_entconns:manage'] }], + }); + }); + + fixtures.clerk.organization?.getEnterpriseConnections.mockResolvedValue([]); + mockOrganizationDomains(fixtures, [expiredDomain]); + fixtures.clerk.organization?.prepareOwnershipVerification.mockRejectedValue(new Error('nope')); + + const { findByRole, getByRole } = render(, { wrapper }); + await findByRole('button', { name: /re-issue/i }); + + await act(() => { + getByRole('button', { name: /re-issue/i }).click(); + return Promise.resolve(); + }); + + expect(getByRole('button', { name: /re-issue/i })).not.toBeDisabled(); + }); + it('short-circuits to the activate step for an active connection', async () => { const { wrapper, fixtures } = await createFixtures(f => { f.withEnterpriseSso({ selfServeSSO: true }); diff --git a/packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx b/packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx index 8c449089080..1d490563f31 100644 --- a/packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx +++ b/packages/ui/src/components/ConfigureSSO/steps/OrganizationDomainsStep.tsx @@ -36,6 +36,8 @@ import { Step } from '../elements/Step'; import { useWizard } from '../elements/Wizard/WizardContext'; import { RemoveDomainDialog } from '../RemoveDomainDialog'; +const OWNERSHIP_VERIFICATION_RETRY_THROTTLE_MS = 5 * 60 * 1000; + export const OrganizationDomainsStep = (): JSX.Element => { const { t } = useLocalizations(); const { @@ -81,14 +83,16 @@ export const OrganizationDomainsStep = (): JSX.Element => { } }; - const handlePrepareOwnershipVerification = async (domain: OrganizationDomainResource) => { + const handlePrepareOwnershipVerification = async (domain: OrganizationDomainResource): Promise => { card.setError(undefined); try { await prepareOwnershipVerification([domain]); + return true; } catch (err: any) { const apiError = getFieldError(err) ?? getGlobalError(err); card.setError(apiError); + return false; } }; @@ -371,10 +375,23 @@ const DomainCard = ({ }: { domain: OrganizationDomainResource; onRemove: () => void; - onPrepareOwnershipVerification: () => Promise; + onPrepareOwnershipVerification: () => Promise; isRemoveDisabled?: boolean; removeDisabledTooltip?: ReturnType; }): JSX.Element | null => { + const [isVerifying, setIsVerifying] = useState(false); + const [isRetryThrottled, setIsRetryThrottled] = useState(false); + + useEffect(() => { + if (!isRetryThrottled) { + return; + } + + const timeoutId = window.setTimeout(() => setIsRetryThrottled(false), OWNERSHIP_VERIFICATION_RETRY_THROTTLE_MS); + + return () => window.clearTimeout(timeoutId); + }, [isRetryThrottled]); + if (!domain.name) { return null; } @@ -384,6 +401,21 @@ const DomainCard = ({ const isExpired = ownershipVerification?.status === 'expired'; const cardId = ownershipVerification?.status ?? 'unverified'; + const handleVerificationRetry = () => { + setIsVerifying(true); + void onPrepareOwnershipVerification() + .then(setIsRetryThrottled) + .finally(() => setIsVerifying(false)); + }; + + const retryButton = ( + + ); + const removeButton = ( + {retryButton} ); }; +const VerificationRetryButton = ({ + isVerifying, + isThrottled, + onClick, +}: { + isVerifying: boolean; + isThrottled: boolean; + onClick: () => void; +}): JSX.Element => { + const button = ( + + ); + + if (!isThrottled) { + return button; + } + + return ( + + {button} + + + ); +}; + const TxtRecord = ({ ownershipVerification, + retryButton, }: { ownershipVerification: OrganizationDomainResource['ownershipVerification']; + retryButton: JSX.Element; }): JSX.Element => { return ( + + {retryButton} );