diff --git a/.changeset/sso-bypass-allowlist-by-role.md b/.changeset/sso-bypass-allowlist-by-role.md new file mode 100644 index 00000000000..61f654eaaf2 --- /dev/null +++ b/.changeset/sso-bypass-allowlist-by-role.md @@ -0,0 +1,16 @@ +--- +'@clerk/localizations': minor +'@clerk/clerk-js': minor +'@clerk/shared': minor +'@clerk/ui': minor +--- + +The "Add members" card on the SSO allow list page of `` now offers two ways to add people: by email address, or every member with a given role at once. Members whose email address is not served by one of the organization's enterprise connections are skipped. When nothing could be added the card stays open and says why, and when some were added it moves to a success step that reports how many were skipped. + +For custom flows, `organization.ssoBypassAllowlist` gains `addUsers({ userIds })`, which calls the new bulk endpoint in batches of 100 and returns the added entries together with the users that could not be added and why. + +Inputs marked to be ignored by password managers now also carry the Bitwarden, LastPass and Dashlane opt-out attributes, so those extensions stop offering to fill fields such as the allow list email address. + +The member picker that the "Add member" card shipped with in 4.18.0 is gone, and so are its localization keys under `organizationProfile.securityPage.ssoBypassPage.addForm`: `memberLabel`, `memberPlaceholder`, `changeButton` and `noResults`. The feature was never enabled on any instance, so no application depends on them. + +New customization handles: the `organizationProfileSecuritySsoBypassEmailInput`, `organizationProfileSecuritySsoBypassRoleWarning`, `organizationProfileSecuritySsoBypassFailure` and `organizationProfileSecuritySsoBypassBulkResult` appearance elements. diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index 3b53161aab2..3840cf8113d 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -2,8 +2,8 @@ "files": [ { "path": "./dist/clerk.js", "maxSize": "554KB" }, { "path": "./dist/clerk.browser.js", "maxSize": "81KB" }, - { "path": "./dist/clerk.legacy.browser.js", "maxSize": "122.5KB" }, - { "path": "./dist/clerk.no-rhc.js", "maxSize": "320KB" }, + { "path": "./dist/clerk.legacy.browser.js", "maxSize": "124KB" }, + { "path": "./dist/clerk.no-rhc.js", "maxSize": "322KB" }, { "path": "./dist/clerk.native.js", "maxSize": "80KB" }, { "path": "./dist/vendors*.js", "maxSize": "7KB" }, { "path": "./dist/coinbase*.js", "maxSize": "36KB" }, diff --git a/packages/clerk-js/src/core/resources/SSOBypassAllowlist.ts b/packages/clerk-js/src/core/resources/SSOBypassAllowlist.ts index 4addb975e7a..5d4ee065340 100644 --- a/packages/clerk-js/src/core/resources/SSOBypassAllowlist.ts +++ b/packages/clerk-js/src/core/resources/SSOBypassAllowlist.ts @@ -1,7 +1,10 @@ import type { AddSSOBypassAllowlistUserParams, + AddSSOBypassAllowlistUsersParams, DeletedObjectJSON, DeletedObjectResource, + SSOBypassAllowlistBulkCreateJSON, + SSOBypassAllowlistBulkCreateResult, SSOBypassAllowlistResource, SSOBypassAllowlistUserJSON, SSOBypassAllowlistUserResource, @@ -11,6 +14,8 @@ import { BaseResource } from './Base'; import { DeletedObject } from './DeletedObject'; import { SSOBypassAllowlistUser } from './SSOBypassAllowlistUser'; +const BULK_SIZE = 100; + export class SSOBypassAllowlist implements SSOBypassAllowlistResource { declare private readonly organization: { id: string }; @@ -45,6 +50,25 @@ export class SSOBypassAllowlist implements SSOBypassAllowlistResource { return new SSOBypassAllowlistUser(json); }; + addUsers = async (params: AddSSOBypassAllowlistUsersParams): Promise => { + const result: SSOBypassAllowlistBulkCreateResult = { data: [], errors: [] }; + + for (let start = 0; start < params.userIds.length; start += BULK_SIZE) { + const json = ( + await BaseResource._fetch({ + path: `${this.path}/bulk`, + method: 'POST', + body: { user_id: params.userIds.slice(start, start + BULK_SIZE) } as any, + }) + )?.response as unknown as SSOBypassAllowlistBulkCreateJSON; + + result.data.push(...(json?.data ?? []).map(entry => new SSOBypassAllowlistUser(entry))); + result.errors.push(...(json?.errors ?? []).map(error => ({ userId: error.user_id, code: error.code }))); + } + + return result; + }; + removeUser = async (userId: string): Promise => { const json = ( await BaseResource._fetch({ diff --git a/packages/clerk-js/src/core/resources/__tests__/Organization.test.ts b/packages/clerk-js/src/core/resources/__tests__/Organization.test.ts index 674fba28e18..a1f253af1a3 100644 --- a/packages/clerk-js/src/core/resources/__tests__/Organization.test.ts +++ b/packages/clerk-js/src/core/resources/__tests__/Organization.test.ts @@ -468,6 +468,49 @@ describe('Organization', () => { expect(entry.userId).toBe('user_1'); }); + it('adds users in chunks of 100 and merges the partial results', async () => { + const userIds = Array.from({ length: 150 }, (_, i) => `user_${i}`); + const fetchMock = vi + .fn() + .mockResolvedValueOnce({ + response: { data: [entryJSON], errors: [{ user_id: 'user_5', code: 'sso_bypass_domain_not_served' }] }, + }) + .mockResolvedValueOnce({ + response: { data: [{ ...entryJSON, user_id: 'user_120' }], errors: [] }, + }); + // @ts-ignore + BaseResource._fetch = fetchMock; + + const organization = createOrganization(); + const result = await organization.ssoBypassAllowlist.addUsers({ userIds }); + + expect(fetchMock).toHaveBeenCalledTimes(2); + expect(fetchMock).toHaveBeenNthCalledWith(1, { + method: 'POST', + path: `${ALLOWLIST_PATH}/bulk`, + body: { user_id: userIds.slice(0, 100) }, + }); + expect(fetchMock).toHaveBeenNthCalledWith(2, { + method: 'POST', + path: `${ALLOWLIST_PATH}/bulk`, + body: { user_id: userIds.slice(100) }, + }); + expect(result.data.map(entry => entry.userId)).toEqual(['user_1', 'user_120']); + expect(result.errors).toEqual([{ userId: 'user_5', code: 'sso_bypass_domain_not_served' }]); + }); + + it('sends nothing for an empty batch', async () => { + // @ts-ignore + BaseResource._fetch = vi.fn(); + + const organization = createOrganization(); + const result = await organization.ssoBypassAllowlist.addUsers({ userIds: [] }); + + // @ts-ignore + expect(BaseResource._fetch).not.toHaveBeenCalled(); + expect(result).toEqual({ data: [], errors: [] }); + }); + it('removes a user by id', async () => { // @ts-ignore BaseResource._fetch = vi diff --git a/packages/localizations/src/ar-SA.ts b/packages/localizations/src/ar-SA.ts index bb22bba765c..b170384b18e 100644 --- a/packages/localizations/src/ar-SA.ts +++ b/packages/localizations/src/ar-SA.ts @@ -1379,14 +1379,30 @@ export const arSA: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2049,6 +2065,7 @@ export const arSA: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'لقد قمت بتسجيل الدخول بالفعل', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/be-BY.ts b/packages/localizations/src/be-BY.ts index 1f8c02d1b06..a487e4c1a91 100644 --- a/packages/localizations/src/be-BY.ts +++ b/packages/localizations/src/be-BY.ts @@ -1382,14 +1382,30 @@ export const beBY: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2060,6 +2076,7 @@ export const beBY: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Вы ўжо ўвайшлі.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/bg-BG.ts b/packages/localizations/src/bg-BG.ts index e930180c2b9..5667ae5a7b5 100644 --- a/packages/localizations/src/bg-BG.ts +++ b/packages/localizations/src/bg-BG.ts @@ -1382,14 +1382,30 @@ export const bgBG: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2053,6 +2069,7 @@ export const bgBG: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Вече сте влезнали.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/bn-IN.ts b/packages/localizations/src/bn-IN.ts index d4943caadb8..709c93aaebe 100644 --- a/packages/localizations/src/bn-IN.ts +++ b/packages/localizations/src/bn-IN.ts @@ -1389,14 +1389,30 @@ export const bnIN: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2078,6 +2094,7 @@ export const bnIN: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'একটি Web3 ওয়ালেট এক্সটেনশন পাওয়া যায়নি। চালিয়ে যেতে দয়া করে একটি ইনস্টল করুন।', diff --git a/packages/localizations/src/ca-ES.ts b/packages/localizations/src/ca-ES.ts index b9631e0e7cb..cb05017c14f 100644 --- a/packages/localizations/src/ca-ES.ts +++ b/packages/localizations/src/ca-ES.ts @@ -1389,14 +1389,30 @@ export const caES: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2066,6 +2082,7 @@ export const caES: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Ja estàs connectat.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/cs-CZ.ts b/packages/localizations/src/cs-CZ.ts index d06b5ac9101..b996c0ce0fc 100644 --- a/packages/localizations/src/cs-CZ.ts +++ b/packages/localizations/src/cs-CZ.ts @@ -1387,14 +1387,30 @@ export const csCZ: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2065,6 +2081,7 @@ export const csCZ: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Jste již přihlášen.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Rozšíření peněženky Web3 nebylo nalezeno. Pro pokračování prosím nainstalujte jednu.', diff --git a/packages/localizations/src/da-DK.ts b/packages/localizations/src/da-DK.ts index c943ea9c802..29e042758f5 100644 --- a/packages/localizations/src/da-DK.ts +++ b/packages/localizations/src/da-DK.ts @@ -1380,14 +1380,30 @@ export const daDK: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2050,6 +2066,7 @@ export const daDK: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Du er allerede logget ind.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/de-DE.ts b/packages/localizations/src/de-DE.ts index efe77c56715..b44f723fb29 100644 --- a/packages/localizations/src/de-DE.ts +++ b/packages/localizations/src/de-DE.ts @@ -1395,14 +1395,30 @@ export const deDE: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2083,6 +2099,7 @@ export const deDE: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Sie sind bereits angemeldet.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: diff --git a/packages/localizations/src/el-GR.ts b/packages/localizations/src/el-GR.ts index 973ca52f5c5..3c2456d3edd 100644 --- a/packages/localizations/src/el-GR.ts +++ b/packages/localizations/src/el-GR.ts @@ -1385,14 +1385,30 @@ export const elGR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2074,6 +2090,7 @@ export const elGR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Έχετε ήδη συνδεθεί.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Δεν εντοπίστηκε αναγνωριστικό Web3. Παρακαλώ δοκιμάστε ξανά.', diff --git a/packages/localizations/src/en-GB.ts b/packages/localizations/src/en-GB.ts index 07bd9d181d5..c35c73fb1fd 100644 --- a/packages/localizations/src/en-GB.ts +++ b/packages/localizations/src/en-GB.ts @@ -1381,14 +1381,30 @@ export const enGB: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2057,6 +2073,7 @@ export const enGB: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: "You're already signed in.", + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts index 39f6f9746dc..359bc594a5f 100644 --- a/packages/localizations/src/en-US.ts +++ b/packages/localizations/src/en-US.ts @@ -1418,13 +1418,31 @@ export const enUS: LocalizationResource = { action__add: 'Add', action__search: 'Search users', addForm: { - changeButton: 'Change', - memberLabel: 'Member', - memberPlaceholder: 'Search members', - noResults: 'No members found', - submitButton: 'Add', + emailPlaceholder: "Enter the member's email address", + error__allAlreadyAdded: 'Everyone with that role is already on the allow list.', + error__alreadyAdded: 'This member is already on the allow list.', + error__memberNotFound: 'No member of this organization has that email address.', + modeLabel: 'Add by', + mode__email: 'Email', + mode__role: 'Role', + roleOption: '{{role}} ({{count}})', + roleWarning: 'This list does not sync, members are managed manually.', + submitButton: 'Add members', subtitle: 'Members on this list can sign in with an email code when SSO is unavailable.', - title: 'Add member', + title: 'Add members', + }, + bulkResult: { + added: 'Added {{count}} members', + addedMember: 'Added member successfully', + added__one: 'Added 1 member', + domainNotServed: + '{{count}} members could not be added because their email address is not served by a connection.', + domainNotServed__one: + '1 member could not be added because their email address is not served by a connection.', + notMember: '{{count}} members could not be added because they are no longer in the organization.', + notMember__one: '1 member could not be added because they are no longer in the organization.', + unknown: '{{count}} members could not be added.', + unknown__one: '1 member could not be added.', }, table: { emptyState: 'No members on the allow list', @@ -1433,11 +1451,11 @@ export const enUS: LocalizationResource = { header__user: 'User', menuAction__remove: 'Remove', }, - title: 'SSO allow list', + title: 'SSO bypass', }, ssoBypassSection: { - allowlistCount: '{{count}} users', - allowlistCount__one: '1 user', + allowlistCount: '{{count}} members', + allowlistCount__one: '1 member', allowlistLabel: 'Allow list:', description: 'Members on this list can sign in with an email code when SSO is unavailable.', error__load: 'Could not load the SSO allow list', @@ -2106,6 +2124,8 @@ export const enUS: LocalizationResource = { protect_check_unsupported_environment: "Verification isn't supported in this environment. Please continue in a standard browser or contact support.", session_exists: undefined, + sso_bypass_domain_not_served: + 'This member could not be added because their email address is not served by a connection.', ticket_expired_code: 'This link has expired. Please start again or request a new link.', ticket_invalid_code: 'This link is no longer valid or has already been used. Please start again or request a new link.', diff --git a/packages/localizations/src/es-CR.ts b/packages/localizations/src/es-CR.ts index 0915ceebb4a..206c578c1d8 100644 --- a/packages/localizations/src/es-CR.ts +++ b/packages/localizations/src/es-CR.ts @@ -1385,14 +1385,30 @@ export const esCR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2065,6 +2081,7 @@ export const esCR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'No se puede encontrar la extension de la billetera Web3. Instala una para continuar', diff --git a/packages/localizations/src/es-ES.ts b/packages/localizations/src/es-ES.ts index ea8efcf406e..4cf19bd234f 100644 --- a/packages/localizations/src/es-ES.ts +++ b/packages/localizations/src/es-ES.ts @@ -1390,14 +1390,30 @@ export const esES: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2066,6 +2082,7 @@ export const esES: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Ya has iniciado sesión', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/es-MX.ts b/packages/localizations/src/es-MX.ts index a7d9e1d7aa4..f70472db2a7 100644 --- a/packages/localizations/src/es-MX.ts +++ b/packages/localizations/src/es-MX.ts @@ -1386,14 +1386,30 @@ export const esMX: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2066,6 +2082,7 @@ export const esMX: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Ya has iniciado sesión', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'No se puede encontrar la extension de la billetera Web3. Instala una para continuar', diff --git a/packages/localizations/src/es-UY.ts b/packages/localizations/src/es-UY.ts index 432c849c485..f9dd35007b5 100644 --- a/packages/localizations/src/es-UY.ts +++ b/packages/localizations/src/es-UY.ts @@ -1384,14 +1384,30 @@ export const esUY: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2067,6 +2083,7 @@ export const esUY: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Ya has iniciado sesión', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'No se encontró una extensión de cartera Web3. Por favor, instalá una para continuar.', diff --git a/packages/localizations/src/fa-IR.ts b/packages/localizations/src/fa-IR.ts index 8daa142f9ad..7922218161c 100644 --- a/packages/localizations/src/fa-IR.ts +++ b/packages/localizations/src/fa-IR.ts @@ -1389,14 +1389,30 @@ export const faIR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2064,6 +2080,7 @@ export const faIR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'جلسه از قبل وجود دارد.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'افزونه‌ی کیف پول وب۳ پیدا نشد. برای ادامه، لطفاً یکی نصب کنید.', diff --git a/packages/localizations/src/fi-FI.ts b/packages/localizations/src/fi-FI.ts index 360a30cf3f3..4cf9bc33f64 100644 --- a/packages/localizations/src/fi-FI.ts +++ b/packages/localizations/src/fi-FI.ts @@ -1390,14 +1390,30 @@ export const fiFI: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2082,6 +2098,7 @@ export const fiFI: LocalizationResource = { protect_check_unsupported_environment: 'Tarkistusta ei tueta tässä ympäristössä. Jatka tavallisella selaimella tai ota yhteyttä tukeen.', session_exists: 'Olet jo kirjautunut sisään.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3-lompakkoa ei löytynyt. Asenna sellainen jatkaaksesi.', diff --git a/packages/localizations/src/fr-FR.ts b/packages/localizations/src/fr-FR.ts index aada099130c..da5192566a5 100644 --- a/packages/localizations/src/fr-FR.ts +++ b/packages/localizations/src/fr-FR.ts @@ -1395,14 +1395,30 @@ export const frFR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2075,6 +2091,7 @@ export const frFR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Vous êtes déjà connecté.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Aucune extension de portefeuille Web3 trouvée. Veuillez en installer une pour continuer.', diff --git a/packages/localizations/src/he-IL.ts b/packages/localizations/src/he-IL.ts index b9babea27b7..93e2b829ee1 100644 --- a/packages/localizations/src/he-IL.ts +++ b/packages/localizations/src/he-IL.ts @@ -1376,14 +1376,30 @@ export const heIL: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2041,6 +2057,7 @@ export const heIL: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'אתה כבר מחובר לחשבון.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/hi-IN.ts b/packages/localizations/src/hi-IN.ts index 7c6c2ad0582..b916ac42fcd 100644 --- a/packages/localizations/src/hi-IN.ts +++ b/packages/localizations/src/hi-IN.ts @@ -1389,14 +1389,30 @@ export const hiIN: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2079,6 +2095,7 @@ export const hiIN: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3 वॉलेट एक्सटेंशन नहीं मिल सका। जारी रखने के लिए कृपया एक इंस्टॉल करें।', diff --git a/packages/localizations/src/hr-HR.ts b/packages/localizations/src/hr-HR.ts index 4ae52b41ae4..724ffa36afd 100644 --- a/packages/localizations/src/hr-HR.ts +++ b/packages/localizations/src/hr-HR.ts @@ -1390,14 +1390,30 @@ export const hrHR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2084,6 +2100,7 @@ export const hrHR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Već ste prijavljeni.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Nije pronađeno proširenje za Web3 novčanik. Molimo instalirajte jedno za nastavak.', diff --git a/packages/localizations/src/hu-HU.ts b/packages/localizations/src/hu-HU.ts index f1b222ba5d5..1a706959464 100644 --- a/packages/localizations/src/hu-HU.ts +++ b/packages/localizations/src/hu-HU.ts @@ -1391,14 +1391,30 @@ export const huHU: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2083,6 +2099,7 @@ export const huHU: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Már be vagy jelentkezve.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Nem található Web3 tárca bővítmény. Kérlek telepíts egyet a folytatáshoz.', diff --git a/packages/localizations/src/id-ID.ts b/packages/localizations/src/id-ID.ts index 617a66f9613..95e2115583f 100644 --- a/packages/localizations/src/id-ID.ts +++ b/packages/localizations/src/id-ID.ts @@ -1383,14 +1383,30 @@ export const idID: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2063,6 +2079,7 @@ export const idID: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Anda sudah masuk.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/is-IS.ts b/packages/localizations/src/is-IS.ts index b27d7cd37b1..acdb6e234ec 100644 --- a/packages/localizations/src/is-IS.ts +++ b/packages/localizations/src/is-IS.ts @@ -1390,14 +1390,30 @@ export const isIS: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2081,6 +2097,7 @@ export const isIS: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Þú ert nú þegar innskráður.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Ekki fannst Web3 veskisviðbót. Vinsamlegast settu upp eina til að halda áfram.', diff --git a/packages/localizations/src/it-IT.ts b/packages/localizations/src/it-IT.ts index b5dd28eda07..93fb06cc64a 100644 --- a/packages/localizations/src/it-IT.ts +++ b/packages/localizations/src/it-IT.ts @@ -1390,14 +1390,30 @@ export const itIT: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2062,6 +2078,7 @@ export const itIT: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Sei già loggato.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/ja-JP.ts b/packages/localizations/src/ja-JP.ts index 1ef8f68d012..c9064dccb59 100644 --- a/packages/localizations/src/ja-JP.ts +++ b/packages/localizations/src/ja-JP.ts @@ -1389,14 +1389,30 @@ export const jaJP: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2077,6 +2093,7 @@ export const jaJP: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: '既にサインインしています。', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3ウォレット拡張機能が見つかりません。続行するにはインストールしてください。', diff --git a/packages/localizations/src/kk-KZ.ts b/packages/localizations/src/kk-KZ.ts index feee430ad7d..f6bfd105eff 100644 --- a/packages/localizations/src/kk-KZ.ts +++ b/packages/localizations/src/kk-KZ.ts @@ -1376,14 +1376,30 @@ export const kkKZ: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2043,6 +2059,7 @@ export const kkKZ: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3 Wallet кеңейтуі табылмады. Орнатыңыз.', diff --git a/packages/localizations/src/ko-KR.ts b/packages/localizations/src/ko-KR.ts index 0e630fb6fd8..8f897540d61 100644 --- a/packages/localizations/src/ko-KR.ts +++ b/packages/localizations/src/ko-KR.ts @@ -1381,14 +1381,30 @@ export const koKR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2050,6 +2066,7 @@ export const koKR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: '이미 로그인 중이에요.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3 지갑 확장 프로그램을 찾을 수 없어요. 계속하려면 설치해 주세요.', diff --git a/packages/localizations/src/mn-MN.ts b/packages/localizations/src/mn-MN.ts index 053cf26b29d..22628699d22 100644 --- a/packages/localizations/src/mn-MN.ts +++ b/packages/localizations/src/mn-MN.ts @@ -1383,14 +1383,30 @@ export const mnMN: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2055,6 +2071,7 @@ export const mnMN: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Та аль хэдийн нэвтэрсэн байна.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/ms-MY.ts b/packages/localizations/src/ms-MY.ts index e3ca6913a1e..9e6f2196d2c 100644 --- a/packages/localizations/src/ms-MY.ts +++ b/packages/localizations/src/ms-MY.ts @@ -1392,14 +1392,30 @@ export const msMY: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2088,6 +2104,7 @@ export const msMY: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Sambungan Dompet Web3 tidak dapat dijumpai. Sila pasang satu untuk meneruskan.', diff --git a/packages/localizations/src/nb-NO.ts b/packages/localizations/src/nb-NO.ts index 3300cb8456f..656d86c9abd 100644 --- a/packages/localizations/src/nb-NO.ts +++ b/packages/localizations/src/nb-NO.ts @@ -1391,14 +1391,30 @@ export const nbNO: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2081,6 +2097,7 @@ export const nbNO: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Du er allerede logget inn.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'En Web3-lommebokutvidelse ble ikke funnet. Installer en for å fortsette.', diff --git a/packages/localizations/src/nl-BE.ts b/packages/localizations/src/nl-BE.ts index 5635c4bdae0..058d0566e3f 100644 --- a/packages/localizations/src/nl-BE.ts +++ b/packages/localizations/src/nl-BE.ts @@ -1383,14 +1383,30 @@ export const nlBE: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2054,6 +2070,7 @@ export const nlBE: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Je bent al ingelogd.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/nl-NL.ts b/packages/localizations/src/nl-NL.ts index 683c087722b..a51c1995653 100644 --- a/packages/localizations/src/nl-NL.ts +++ b/packages/localizations/src/nl-NL.ts @@ -1383,14 +1383,30 @@ export const nlNL: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2054,6 +2070,7 @@ export const nlNL: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Je bent al ingelogd.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/pl-PL.ts b/packages/localizations/src/pl-PL.ts index bd2ce40f06c..24c93f5909b 100644 --- a/packages/localizations/src/pl-PL.ts +++ b/packages/localizations/src/pl-PL.ts @@ -1381,14 +1381,30 @@ export const plPL: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2062,6 +2078,7 @@ export const plPL: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Jesteś już zalogowany.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Nie można znaleźć rozszerzenia Web3 Wallet. Zainstaluj je, aby kontynuować.', diff --git a/packages/localizations/src/pt-BR.ts b/packages/localizations/src/pt-BR.ts index f060558f508..ff44fd059d6 100644 --- a/packages/localizations/src/pt-BR.ts +++ b/packages/localizations/src/pt-BR.ts @@ -1391,14 +1391,30 @@ export const ptBR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2072,6 +2088,7 @@ export const ptBR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Você já está conectado.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: diff --git a/packages/localizations/src/pt-PT.ts b/packages/localizations/src/pt-PT.ts index 8a6cd1a348a..d9b75a842ac 100644 --- a/packages/localizations/src/pt-PT.ts +++ b/packages/localizations/src/pt-PT.ts @@ -1391,14 +1391,30 @@ export const ptPT: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2078,6 +2094,7 @@ export const ptPT: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Já está conectado.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Falta um identificador Web3. Tente novamente.', diff --git a/packages/localizations/src/ro-RO.ts b/packages/localizations/src/ro-RO.ts index 859280e7e38..3af154f9b57 100644 --- a/packages/localizations/src/ro-RO.ts +++ b/packages/localizations/src/ro-RO.ts @@ -1391,14 +1391,30 @@ export const roRO: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2073,6 +2089,7 @@ export const roRO: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Nu am găsit o extensie pentru portofel Web3. Te rugăm instalează una pentru a continua.', diff --git a/packages/localizations/src/ru-RU.ts b/packages/localizations/src/ru-RU.ts index e8b1b84144d..2e8589012b4 100644 --- a/packages/localizations/src/ru-RU.ts +++ b/packages/localizations/src/ru-RU.ts @@ -1385,14 +1385,30 @@ export const ruRU: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2070,6 +2086,7 @@ export const ruRU: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Вы уже вошли в систему.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/sk-SK.ts b/packages/localizations/src/sk-SK.ts index d2eafb0a578..8a7fa661be9 100644 --- a/packages/localizations/src/sk-SK.ts +++ b/packages/localizations/src/sk-SK.ts @@ -1381,14 +1381,30 @@ export const skSK: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2061,6 +2077,7 @@ export const skSK: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Jste už přihlášen.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Rozšírenie Web3 Peňaženky nebolo nájdené. Je potrebné ho nainštalovať.', diff --git a/packages/localizations/src/sr-RS.ts b/packages/localizations/src/sr-RS.ts index acd705324c5..3cb05958a6f 100644 --- a/packages/localizations/src/sr-RS.ts +++ b/packages/localizations/src/sr-RS.ts @@ -1381,14 +1381,30 @@ export const srRS: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2053,6 +2069,7 @@ export const srRS: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Već ste prijavljeni.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/sv-SE.ts b/packages/localizations/src/sv-SE.ts index 881a4a4df2a..d30a15de531 100644 --- a/packages/localizations/src/sv-SE.ts +++ b/packages/localizations/src/sv-SE.ts @@ -1381,14 +1381,30 @@ export const svSE: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2056,6 +2072,7 @@ export const svSE: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Du är redan inloggad.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/ta-IN.ts b/packages/localizations/src/ta-IN.ts index cb706cc5fc5..b8c369c0280 100644 --- a/packages/localizations/src/ta-IN.ts +++ b/packages/localizations/src/ta-IN.ts @@ -1394,14 +1394,30 @@ export const taIN: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2089,6 +2105,7 @@ export const taIN: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3 வாலட் நீட்டிப்பு காணப்படவில்லை. தொடர ஒன்றை நிறுவவும்.', diff --git a/packages/localizations/src/te-IN.ts b/packages/localizations/src/te-IN.ts index 9db00b0f6b5..cf3e3b183ec 100644 --- a/packages/localizations/src/te-IN.ts +++ b/packages/localizations/src/te-IN.ts @@ -1391,14 +1391,30 @@ export const teIN: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2083,6 +2099,7 @@ export const teIN: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3 వాలెట్ పొడిగింపు కనుగొనబడలేదు. కొనసాగించడానికి దయచేసి ఒకదాన్ని ఇన్‌స్టాల్ చేయండి.', diff --git a/packages/localizations/src/th-TH.ts b/packages/localizations/src/th-TH.ts index b9abd92700a..83b15833bb5 100644 --- a/packages/localizations/src/th-TH.ts +++ b/packages/localizations/src/th-TH.ts @@ -1382,14 +1382,30 @@ export const thTH: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2051,6 +2067,7 @@ export const thTH: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'ไม่พบส่วนขยาย Web3 Wallet โปรดติดตั้งเพื่อดำเนินการต่อ', diff --git a/packages/localizations/src/tr-TR.ts b/packages/localizations/src/tr-TR.ts index 31f6d97069a..a09e323e061 100644 --- a/packages/localizations/src/tr-TR.ts +++ b/packages/localizations/src/tr-TR.ts @@ -1381,14 +1381,30 @@ export const trTR: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2057,6 +2073,7 @@ export const trTR: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Zaten giriş yapmışsınız.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Web3 için tanımlayıcı eksik.', diff --git a/packages/localizations/src/uk-UA.ts b/packages/localizations/src/uk-UA.ts index a6f282ae4e8..5b5283e1b6c 100644 --- a/packages/localizations/src/uk-UA.ts +++ b/packages/localizations/src/uk-UA.ts @@ -1381,14 +1381,30 @@ export const ukUA: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2051,6 +2067,7 @@ export const ukUA: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: 'Ви вже увійшли в систему.', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/vi-VN.ts b/packages/localizations/src/vi-VN.ts index 89603486018..028d41cf23d 100644 --- a/packages/localizations/src/vi-VN.ts +++ b/packages/localizations/src/vi-VN.ts @@ -1389,14 +1389,30 @@ export const viVN: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2074,6 +2090,7 @@ export const viVN: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: undefined, + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: 'Không tìm thấy phần mở rộng Web3 Wallet. Vui lòng cài đặt một phần mở rộng để tiếp tục.', diff --git a/packages/localizations/src/zh-CN.ts b/packages/localizations/src/zh-CN.ts index ee9112eadc8..2c3ee135aa3 100644 --- a/packages/localizations/src/zh-CN.ts +++ b/packages/localizations/src/zh-CN.ts @@ -1374,14 +1374,30 @@ export const zhCN: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2034,6 +2050,7 @@ export const zhCN: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: '您已登录。', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: undefined, diff --git a/packages/localizations/src/zh-TW.ts b/packages/localizations/src/zh-TW.ts index ed85fe52c0c..7cbca618cb1 100644 --- a/packages/localizations/src/zh-TW.ts +++ b/packages/localizations/src/zh-TW.ts @@ -1377,14 +1377,30 @@ export const zhTW: LocalizationResource = { action__add: undefined, action__search: undefined, addForm: { - changeButton: undefined, - memberLabel: undefined, - memberPlaceholder: undefined, - noResults: undefined, + emailPlaceholder: undefined, + error__allAlreadyAdded: undefined, + error__alreadyAdded: undefined, + error__memberNotFound: undefined, + modeLabel: undefined, + mode__email: undefined, + mode__role: undefined, + roleOption: undefined, + roleWarning: undefined, submitButton: undefined, subtitle: undefined, title: undefined, }, + bulkResult: { + added: undefined, + addedMember: undefined, + added__one: undefined, + domainNotServed: undefined, + domainNotServed__one: undefined, + notMember: undefined, + notMember__one: undefined, + unknown: undefined, + unknown__one: undefined, + }, table: { emptyState: undefined, emptyState__search: undefined, @@ -2039,6 +2055,7 @@ export const zhTW: LocalizationResource = { protect_check_timed_out: undefined, protect_check_unsupported_environment: undefined, session_exists: '您已經登錄。', + sso_bypass_domain_not_served: undefined, ticket_expired_code: undefined, ticket_invalid_code: undefined, web3_missing_identifier: '找不到 Web3 錢包擴充功能。請安裝以繼續。', diff --git a/packages/shared/src/react/hooks/__tests__/useOrganizationSSOBypassAllowlist.spec.tsx b/packages/shared/src/react/hooks/__tests__/useOrganizationSSOBypassAllowlist.spec.tsx index 0b9c5c34d54..739a0fcf6a4 100644 --- a/packages/shared/src/react/hooks/__tests__/useOrganizationSSOBypassAllowlist.spec.tsx +++ b/packages/shared/src/react/hooks/__tests__/useOrganizationSSOBypassAllowlist.spec.tsx @@ -9,6 +9,7 @@ const entry = (userId: string) => ({ id: userId, userId, publicUserData: { ident const getSpy = vi.fn(() => Promise.resolve([entry('user_1')])); const addSpy = vi.fn(() => Promise.resolve(entry('user_2'))); +const addManySpy = vi.fn(() => Promise.resolve({ data: [entry('user_2'), entry('user_3')], errors: [] })); const removeSpy = vi.fn(() => Promise.resolve({ id: 'user_1', deleted: true })); const defaultQueryClient = createMockQueryClient(); @@ -20,7 +21,7 @@ const mockClerk = createMockClerk({ session: null, organization: { id: 'org_1', - ssoBypassAllowlist: { getUsers: getSpy, addUser: addSpy, removeUser: removeSpy }, + ssoBypassAllowlist: { getUsers: getSpy, addUser: addSpy, addUsers: addManySpy, removeUser: removeSpy }, }, client: null, }, @@ -70,6 +71,27 @@ describe('useOrganizationSSOBypassAllowlist', () => { await waitFor(() => expect(getSpy).toHaveBeenCalledTimes(2)); }); + it('adds several users and refetches the list before resolving', async () => { + const { result } = renderAllowlist(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); + + const added = await result.current.addUsers({ userIds: ['user_2', 'user_3'] }); + + expect(addManySpy).toHaveBeenCalledWith({ userIds: ['user_2', 'user_3'] }); + expect(added).toEqual({ data: [entry('user_2'), entry('user_3')], errors: [] }); + await waitFor(() => expect(getSpy).toHaveBeenCalledTimes(2)); + }); + + it('refetches the list even when a bulk add fails part way', async () => { + addManySpy.mockRejectedValueOnce(new Error('network')); + const { result } = renderAllowlist(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); + + await expect(result.current.addUsers({ userIds: ['user_2', 'user_3'] })).rejects.toThrow('network'); + + await waitFor(() => expect(getSpy).toHaveBeenCalledTimes(2)); + }); + it('removes a user and refetches the list before resolving', async () => { const { result } = renderAllowlist(); await waitFor(() => expect(result.current.isLoading).toBe(false)); diff --git a/packages/shared/src/react/hooks/useOrganizationSSOBypassAllowlist.tsx b/packages/shared/src/react/hooks/useOrganizationSSOBypassAllowlist.tsx index c8114205aee..7041fee7993 100644 --- a/packages/shared/src/react/hooks/useOrganizationSSOBypassAllowlist.tsx +++ b/packages/shared/src/react/hooks/useOrganizationSSOBypassAllowlist.tsx @@ -1,7 +1,12 @@ import { useCallback } from 'react'; import type { DeletedObjectResource } from '../../types/deletedObject'; -import type { AddSSOBypassAllowlistUserParams, SSOBypassAllowlistUserResource } from '../../types/ssoBypassAllowlist'; +import type { + AddSSOBypassAllowlistUserParams, + AddSSOBypassAllowlistUsersParams, + SSOBypassAllowlistBulkCreateResult, + SSOBypassAllowlistUserResource, +} from '../../types/ssoBypassAllowlist'; import { useClerkInstanceContext } from '../contexts'; import { defineKeepPreviousDataFn } from '../query/keep-previous-data'; import { useClerkQueryClient } from '../query/use-clerk-query-client'; @@ -21,6 +26,7 @@ export type UseOrganizationSSOBypassAllowlistReturn = { isLoading: boolean; isFetching: boolean; addUser: (params: AddSSOBypassAllowlistUserParams) => Promise; + addUsers: (params: AddSSOBypassAllowlistUsersParams) => Promise; removeUser: (userId: string) => Promise; revalidate: () => Promise; }; @@ -71,6 +77,17 @@ function useOrganizationSSOBypassAllowlist( [organization, revalidate], ); + const addUsers = useCallback( + async (addParams: AddSSOBypassAllowlistUsersParams) => { + try { + return await organization?.ssoBypassAllowlist.addUsers(addParams); + } finally { + await revalidate(); + } + }, + [organization, revalidate], + ); + const removeUser = useCallback( async (userId: string) => { const removed = await organization?.ssoBypassAllowlist.removeUser(userId); @@ -86,6 +103,7 @@ function useOrganizationSSOBypassAllowlist( isLoading: query.isLoading, isFetching: query.isFetching, addUser, + addUsers, removeUser, revalidate, }; diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts index 48bba0d2a2d..16c2296d41f 100644 --- a/packages/shared/src/types/localization.ts +++ b/packages/shared/src/types/localization.ts @@ -1218,11 +1218,16 @@ export type __internal_LocalizationResource = { addForm: { title: LocalizationValue; subtitle: LocalizationValue; - memberLabel: LocalizationValue; - changeButton: LocalizationValue; - memberPlaceholder: LocalizationValue; - noResults: LocalizationValue; + modeLabel: LocalizationValue; + mode__email: LocalizationValue; + mode__role: LocalizationValue; + emailPlaceholder: LocalizationValue; + roleOption: LocalizationValue<'role' | 'count'>; + roleWarning: LocalizationValue; submitButton: LocalizationValue; + error__memberNotFound: LocalizationValue; + error__alreadyAdded: LocalizationValue; + error__allAlreadyAdded: LocalizationValue; }; table: { header__user: LocalizationValue; @@ -1231,6 +1236,17 @@ export type __internal_LocalizationResource = { emptyState__search: LocalizationValue; menuAction__remove: LocalizationValue; }; + bulkResult: { + added: LocalizationValue<'count'>; + added__one: LocalizationValue; + addedMember: LocalizationValue; + domainNotServed: LocalizationValue<'count'>; + domainNotServed__one: LocalizationValue; + notMember: LocalizationValue<'count'>; + notMember__one: LocalizationValue; + unknown: LocalizationValue<'count'>; + unknown__one: LocalizationValue; + }; }; ssoSection: { title: LocalizationValue; @@ -2449,6 +2465,7 @@ type UnstableErrors = WithParamName<{ requireSpecialCharacter: LocalizationValue; }; session_exists: LocalizationValue; + sso_bypass_domain_not_served: LocalizationValue; ticket_expired_code: LocalizationValue; ticket_invalid_code: LocalizationValue; zxcvbn: { diff --git a/packages/shared/src/types/ssoBypassAllowlist.ts b/packages/shared/src/types/ssoBypassAllowlist.ts index ecc177a140d..26e908a6bec 100644 --- a/packages/shared/src/types/ssoBypassAllowlist.ts +++ b/packages/shared/src/types/ssoBypassAllowlist.ts @@ -25,6 +25,30 @@ export type AddSSOBypassAllowlistUserParams = { userId: string; }; +export type AddSSOBypassAllowlistUsersParams = { + userIds: string[]; +}; + +export interface SSOBypassAllowlistBulkCreateErrorJSON { + user_id: string; + code: string; +} + +export interface SSOBypassAllowlistBulkCreateJSON { + data: SSOBypassAllowlistUserJSON[]; + errors: SSOBypassAllowlistBulkCreateErrorJSON[]; +} + +export interface SSOBypassAllowlistBulkCreateError { + userId: string; + code: string; +} + +export interface SSOBypassAllowlistBulkCreateResult { + data: SSOBypassAllowlistUserResource[]; + errors: SSOBypassAllowlistBulkCreateError[]; +} + export interface SSOBypassAllowlistResource { /** * Lists the members who may sign in with an email code when the organization's enterprise SSO is unavailable. @@ -36,6 +60,11 @@ export interface SSOBypassAllowlistResource { * organization's enterprise connections. */ addUser: (params: AddSSOBypassAllowlistUserParams) => Promise; + /** + * Adds several members to the allowlist, one request per 100 ids. Members who cannot be added are reported in + * `errors` with the same code `addUser` returns for them, and do not fail the batch. + */ + addUsers: (params: AddSSOBypassAllowlistUsersParams) => Promise; /** * Removes a member from the allowlist. */ diff --git a/packages/ui/src/components/OrganizationProfile/MemberListTable.tsx b/packages/ui/src/components/OrganizationProfile/MemberListTable.tsx index d7b5c022ede..491d58bd881 100644 --- a/packages/ui/src/components/OrganizationProfile/MemberListTable.tsx +++ b/packages/ui/src/components/OrganizationProfile/MemberListTable.tsx @@ -155,8 +155,19 @@ export const RoleSelect = (props: { triggerSx?: ThemableCssProp; optionListSx?: ThemableCssProp; prefixLocalizationKey?: LocalizationKey | string; + formatLabel?: (label: string, role: { label: string; value: string }) => string; }) => { - const { value, fallbackLabel, roles, onChange, isDisabled, triggerSx, optionListSx, prefixLocalizationKey } = props; + const { + value, + fallbackLabel, + roles, + onChange, + isDisabled, + triggerSx, + optionListSx, + prefixLocalizationKey, + formatLabel = label => label, + } = props; const { localizeCustomRole } = useLocalizeCustomRoles(); @@ -169,9 +180,9 @@ export const RoleSelect = (props: { () => fetchedRoles.map(role => ({ value: role.value, - label: localizeCustomRole(role.value) || role.label, + label: formatLabel(localizeCustomRole(role.value) || role.label, role), })), - [fetchedRoles, localizeCustomRole], + [fetchedRoles, localizeCustomRole, formatLabel], ); return ( @@ -221,7 +232,7 @@ export const RoleSelect = (props: { as='span' colorScheme='body' > - {localizeCustomRole(selectedRole?.value) || selectedRole?.label} + {selectedRole && formatLabel(localizeCustomRole(selectedRole.value) || selectedRole.label, selectedRole)} ) : fallbackLabel ? ( diff --git a/packages/ui/src/components/OrganizationProfile/SSOBypassAllowlistPage.tsx b/packages/ui/src/components/OrganizationProfile/SSOBypassAllowlistPage.tsx index 3f2b9597840..3fec3a16743 100644 --- a/packages/ui/src/components/OrganizationProfile/SSOBypassAllowlistPage.tsx +++ b/packages/ui/src/components/OrganizationProfile/SSOBypassAllowlistPage.tsx @@ -1,11 +1,15 @@ import { __internal_useOrganizationSSOBypassAllowlist, useOrganization, useUser } from '@clerk/shared/react'; import type { AddSSOBypassAllowlistUserParams, - OrganizationMembershipResource, + AddSSOBypassAllowlistUsersParams, + OrganizationCustomRoleKey, + OrganizationResource, + SSOBypassAllowlistBulkCreateResult, SSOBypassAllowlistUserResource, } from '@clerk/shared/types'; -import React, { useMemo, useRef, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; +import { ExclamationTriangle, InformationCircle, UserPlus } from '@/icons'; import { Action } from '@/ui/elements/Action'; import { useActionContext } from '@/ui/elements/Action/ActionRoot'; import { Alert } from '@/ui/elements/Alert'; @@ -17,32 +21,153 @@ import { Form } from '@/ui/elements/Form'; import { FormButtons } from '@/ui/elements/FormButtons'; import { FormContainer } from '@/ui/elements/FormContainer'; import { Header } from '@/ui/elements/Header'; +import { IconCircle } from '@/ui/elements/IconCircle'; import { ProfileCard } from '@/ui/elements/ProfileCard'; import { SearchInput } from '@/ui/elements/SearchInput'; +import { SegmentedControl } from '@/ui/elements/SegmentedControl'; +import { SuccessPage } from '@/ui/elements/SuccessPage'; import { ThreeDotsMenu } from '@/ui/elements/ThreeDotsMenu'; import { UserPreview } from '@/ui/elements/UserPreview'; import { handleError } from '@/ui/utils/errorHandler'; +import { useFormControl } from '@/ui/utils/useFormControl'; +import { useWizard, Wizard } from '../../common'; +import type { LocalizationKey } from '../../customizables'; import { Badge, Button, Col, descriptors, Flex, + Icon, localizationKeys, Td, Text, useLocalizations, } from '../../customizables'; +import { useFetch } from '../../hooks/useFetch'; +import { useFetchRoles } from '../../hooks/useFetchRoles'; import { mqu } from '../../styledSystem'; +import { RoleSelect } from './MemberListTable'; import { SecurityBackControl } from './SecurityBackControl'; type SSOBypassAllowlistPageProps = { onBack: () => void; }; -const MEMBER_SEARCH_DEBOUNCE_MS = 500; -const MEMBER_SEARCH_PAGE_SIZE = 10; +const MEMBER_LOOKUP_PAGE_SIZE = 10; +const ROLE_MEMBERS_PAGE_SIZE = 100; + +type BulkResult = { mode: AddMode; added: number; skipped: number; skippedCode: string | null }; +type AddMode = 'email' | 'role'; +type FormMessage = LocalizationKey | string; + +const DOMAIN_NOT_SERVED = 'sso_bypass_domain_not_served'; +const NOT_A_MEMBER = 'resource_not_found'; +type RoleOption = { value: string; label: string }; + +const findMemberByEmail = async (organization: OrganizationResource, email: string) => { + const wanted = email.toLowerCase(); + let fetched = 0; + for (let page = 1; ; page++) { + const { data, total_count } = await organization.getMemberships({ + query: email, + pageSize: MEMBER_LOOKUP_PAGE_SIZE, + initialPage: page, + }); + const match = data.find(membership => membership.publicUserData?.identifier?.toLowerCase() === wanted); + fetched += data.length; + if (match || data.length === 0 || fetched >= total_count) { + return match; + } + } +}; + +const useRoleMemberCounts = (roles: RoleOption[] | undefined, enabled: boolean): Record => { + const { organization } = useOrganization(); + const roleKeys = (roles ?? []).map(role => role.value); + + const fetchCounts = async ({ keys }: { keys: string[] }) => { + if (!organization) { + return {}; + } + const entries = await Promise.all( + keys.map(async role => { + const { total_count } = await organization.getMemberships({ role: [role], pageSize: 1 }); + return [role, total_count] as const; + }), + ); + return Object.fromEntries(entries) as Record; + }; + + const shouldFetch = enabled && Boolean(organization?.id) && roleKeys.length > 0; + const { data } = useFetch(shouldFetch ? fetchCounts : undefined, { + keys: roleKeys, + orgId: organization?.id, + enabled: shouldFetch, + }); + + return data ?? {}; +}; + +const collectUserIdsByRole = async (organization: OrganizationResource, role: OrganizationCustomRoleKey) => { + const userIds: string[] = []; + let fetched = 0; + for (let page = 1; ; page++) { + const { data, total_count } = await organization.getMemberships({ + role: [role], + pageSize: ROLE_MEMBERS_PAGE_SIZE, + initialPage: page, + }); + fetched += data.length; + data.forEach(membership => { + const userId = membership.publicUserData?.userId; + if (userId) { + userIds.push(userId); + } + }); + if (data.length === 0 || fetched >= total_count) { + return userIds; + } + } +}; + +const sharedCode = (codes: string[]): string | null => + codes.length > 0 && codes.every(code => code === codes[0]) ? codes[0] : null; + +const skippedText = (skipped: number, code: string | null): LocalizationKey => { + const reason = code === DOMAIN_NOT_SERVED ? 'domainNotServed' : code === NOT_A_MEMBER ? 'notMember' : 'unknown'; + return skipped === 1 + ? localizationKeys(`organizationProfile.securityPage.ssoBypassPage.bulkResult.${reason}__one` as const) + : localizationKeys(`organizationProfile.securityPage.ssoBypassPage.bulkResult.${reason}` as const, { + count: String(skipped), + }); +}; + +const InlineMessage = (props: { + icon: React.ComponentType; + text: FormMessage; + elementDescriptor?: (typeof descriptors)[keyof typeof descriptors]; +}): JSX.Element => ( + + + + +); const matchesSearch = (entry: SSOBypassAllowlistUserResource, term: string): boolean => { const { firstName, lastName, identifier, username } = entry.publicUserData; @@ -54,7 +179,7 @@ export const SSOBypassAllowlistPage = withCardStateProvider(({ onBack }: SSOBypa const card = useCardState(); const { t } = useLocalizations(); const { user } = useUser(); - const { data, isLoading, error, addUser, removeUser } = __internal_useOrganizationSSOBypassAllowlist(); + const { data, isLoading, error, addUser, addUsers, removeUser } = __internal_useOrganizationSSOBypassAllowlist(); const [search, setSearch] = useState(''); const term = search.trim().toLowerCase(); @@ -128,6 +253,7 @@ export const SSOBypassAllowlistPage = withCardStateProvider(({ onBack }: SSOBypa @@ -220,17 +346,62 @@ const AllowlistRow = ({ entry, isCurrentUser, onRemove }: AllowlistRowProps): JS type AddMemberProps = { allowlistedUserIds: Set; addUser: (params: AddSSOBypassAllowlistUserParams) => Promise; + addUsers: (params: AddSSOBypassAllowlistUsersParams) => Promise; +}; + +const addedText = (result: BulkResult | null): LocalizationKey => { + if (result?.mode === 'email') { + return localizationKeys('organizationProfile.securityPage.ssoBypassPage.bulkResult.addedMember'); + } + return result?.added === 1 + ? localizationKeys('organizationProfile.securityPage.ssoBypassPage.bulkResult.added__one') + : localizationKeys('organizationProfile.securityPage.ssoBypassPage.bulkResult.added', { + count: String(result?.added ?? 0), + }); }; const AddMemberScreen = (props: AddMemberProps): JSX.Element => { const { close } = useActionContext(); + const wizard = useWizard(); + const [bulkResult, setBulkResult] = useState(null); return ( - + + { + setBulkResult(result); + wizard.nextStep(); + }} + /> + + + + + + {bulkResult && bulkResult.skipped > 0 && ( + + )} + + } + onFinish={close} + /> + ); }; @@ -238,178 +409,180 @@ const AddMemberForm = withCardStateProvider( ({ allowlistedUserIds, addUser, - onSuccess, + addUsers, + onResult, onReset, - }: AddMemberProps & { onSuccess: () => void; onReset: () => void }): JSX.Element => { + }: AddMemberProps & { + onReset: () => void; + onResult: (result: BulkResult) => void; + }): JSX.Element => { const card = useCardState(); - const { t } = useLocalizations(); - const [search, setSearch] = useState(''); - const [query, setQuery] = useState(''); - const [selected, setSelected] = useState(null); - const debounceTimer = useRef | null>(null); - - const { memberships } = useOrganization({ - memberships: { - keepPreviousData: true, - pageSize: MEMBER_SEARCH_PAGE_SIZE, - query: query || undefined, - }, + const { t, translateError } = useLocalizations(); + const [mode, setMode] = useState('email'); + const [role, setRole] = useState(''); + const [failure, setFailure] = useState(null); + const { organization } = useOrganization(); + const { options: roles } = useFetchRoles(); + const roleCounts = useRoleMemberCounts(roles, mode === 'role'); + + const emailField = useFormControl('emailAddress', '', { + type: 'email', + label: localizationKeys('formFieldLabel__emailAddress'), + placeholder: localizationKeys('organizationProfile.securityPage.ssoBypassPage.addForm.emailPlaceholder'), + isRequired: true, }); - const options = (memberships?.data ?? []).filter(membership => { - const userId = membership.publicUserData?.userId; - return Boolean(userId) && !allowlistedUserIds.has(userId as string); - }); + const formatRoleLabel = useCallback( + (label: string, role: RoleOption) => { + const count = roleCounts[role.value]; + return count === undefined + ? label + : t( + localizationKeys('organizationProfile.securityPage.ssoBypassPage.addForm.roleOption', { + role: label, + count: String(count), + }), + ); + }, + [roleCounts, t], + ); + + const email = emailField.value.trim(); + const canSubmit = !card.isLoading && (mode === 'email' ? email !== '' : Boolean(role)); + + const changeMode = (next: AddMode) => { + setFailure(null); + setMode(next); + }; - const handleSearchChange = (value: string) => { - setSearch(value); - if (debounceTimer.current) { - clearTimeout(debounceTimer.current); + const addByEmail = async (): Promise => { + if (!organization) { + return; + } + const member = await findMemberByEmail(organization, email); + const userId = member?.publicUserData?.userId; + if (!userId) { + setFailure(localizationKeys('organizationProfile.securityPage.ssoBypassPage.addForm.error__memberNotFound')); + return; } - if (value.trim() === '') { - setQuery(''); + if (allowlistedUserIds.has(userId)) { + setFailure(localizationKeys('organizationProfile.securityPage.ssoBypassPage.addForm.error__alreadyAdded')); return; } - debounceTimer.current = setTimeout(() => setQuery(value.trim()), MEMBER_SEARCH_DEBOUNCE_MS); + await addUser({ userId }); + return { mode: 'email' as const, added: 1, skipped: 0, skippedCode: null }; }; - const handleClear = () => { - if (debounceTimer.current) { - clearTimeout(debounceTimer.current); + const addByRole = async (): Promise => { + if (!organization) { + return; } - setSearch(''); - setQuery(''); + const userIds = (await collectUserIdsByRole(organization, role)).filter( + userId => !allowlistedUserIds.has(userId), + ); + if (userIds.length === 0) { + setFailure(localizationKeys('organizationProfile.securityPage.ssoBypassPage.addForm.error__allAlreadyAdded')); + return; + } + const result = await addUsers({ userIds }); + const added = result?.data.length ?? 0; + const skipped = result?.errors ?? []; + const skippedCode = sharedCode(skipped.map(error => error.code)); + if (added === 0) { + setFailure(skippedText(skipped.length, skippedCode)); + return; + } + return { mode: 'role' as const, added, skipped: skipped.length, skippedCode }; }; - const selectedUserId = selected?.publicUserData?.userId; - const canSubmit = Boolean(selectedUserId) && !card.isLoading; - const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!selectedUserId || card.isLoading) { + if (!canSubmit) { return; } + setFailure(null); + try { - await card.runAsync(() => addUser({ userId: selectedUserId })); - onSuccess(); + const result = await card.runAsync(mode === 'email' ? addByEmail : addByRole); + if (result) { + onResult(result); + } } catch (err) { - handleError(err as Error, [], card.setError); + handleError(err as Error, [emailField], error => setFailure(translateError(error))); } }; return ( - - - + changeMode(next as AddMode)} + size='lg' + sx={{ alignSelf: 'flex-start' }} + > + + + - {selected ? ( - ({ - padding: `${t.space.$2} ${t.space.$3}`, - borderRadius: t.radii.$md, - borderWidth: t.borderWidths.$normal, - borderStyle: t.borderStyles.$solid, - borderColor: t.colors.$borderAlpha150, - })} - > - + + - - ))} - - {options.length === 0 && !memberships?.isLoading && ( - - )} - - - )} - + )} + + + )} - + {isLoading ? ( + + ) : error ? ( + + ) : ( + + + + + )} - {isLoading ? ( - - - - ) : error ? ( - - ) : ( - - - - - )} + ); diff --git a/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx b/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx index 565acfd6e0e..cd0e9e1fcc4 100644 --- a/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx +++ b/packages/ui/src/components/OrganizationProfile/__tests__/SSOBypassAllowlist.test.tsx @@ -1,5 +1,6 @@ -import { describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { clearFetchCache } from '@/hooks/useFetch'; import { bindCreateFixtures } from '@/test/create-fixtures'; import { act, render, screen, waitFor } from '@/test/utils'; import { VirtualRouter } from '@/ui/router'; @@ -78,6 +79,10 @@ const renderPage = (wrapper: React.ComponentType<{ children?: React.ReactNode }> render(, { wrapper }); describe('SSO bypass allowlist', () => { + beforeEach(() => { + clearFetchCache(); + }); + describe('security overview section', () => { it('is hidden when the member lacks the SSO bypass permission', async () => { const { wrapper, fixtures } = await createFixtures( @@ -126,7 +131,7 @@ describe('SSO bypass allowlist', () => { expect(await screen.findByText('SSO bypass')).toBeInTheDocument(); expect(screen.getByText(BYPASS_DESCRIPTION)).toBeInTheDocument(); - expect(await screen.findByText('2 users')).toBeInTheDocument(); + expect(await screen.findByText('2 members')).toBeInTheDocument(); expect(screen.getByText('Allow list:')).toBeInTheDocument(); }); @@ -145,12 +150,12 @@ describe('SSO bypass allowlist', () => { const { userEvent } = renderPage(wrapper); - expect(await screen.findByText('1 user')).toBeInTheDocument(); + expect(await screen.findByText('1 member')).toBeInTheDocument(); await userEvent.click(screen.getByRole('button', { name: /open menu/i })); await userEvent.click(await screen.findByRole('menuitem', { name: 'Manage' })); - expect(await screen.findByRole('heading', { name: 'SSO allow list' })).toBeInTheDocument(); + expect(await screen.findByRole('heading', { name: 'SSO bypass' })).toBeInTheDocument(); expect(screen.getByText('Cameron Walker')).toBeInTheDocument(); expect(screen.getByText('cameron@clerk.com')).toBeInTheDocument(); expect(screen.getByText('You')).toBeInTheDocument(); @@ -184,7 +189,7 @@ describe('SSO bypass allowlist', () => { await screen.findByText('SSO bypass'); await userEvent.click(screen.getByRole('button', { name: /open menu/i })); await userEvent.click(await screen.findByRole('menuitem', { name: 'Manage' })); - await screen.findByRole('heading', { name: 'SSO allow list' }); + await screen.findByRole('heading', { name: 'SSO bypass' }); }; it('filters the list by name or email', async () => { @@ -210,13 +215,13 @@ describe('SSO bypass allowlist', () => { expect(await screen.findByText('No members match your search')).toBeInTheDocument(); }); - it('adds a member picked from the organization members', async () => { + it('adds a member by email address', async () => { const { wrapper, fixtures } = await createFixtures( withSecurityPage({ permissions: ['org:sys_entconns:manage', 'org:sys_entconns_sso_bypass:manage'] }), ); fixtures.clerk.organization?.getMemberships.mockResolvedValue({ - data: [membership('user_1', 'Cameron', 'cameron@clerk.com'), membership('user_9', 'Yukio', 'yukio@clerk.com')], - total_count: 2, + data: [membership('user_9', 'Yukio', 'yukio@clerk.com')], + total_count: 1, } as any); fixtures.clerk.organization?.ssoBypassAllowlist.addUser.mockResolvedValue( allowlistEntry('user_9', 'Yukio', 'yukio@clerk.com'), @@ -228,27 +233,61 @@ describe('SSO bypass allowlist', () => { await userEvent.click(screen.getByRole('button', { name: 'Add' })); - expect(await screen.findByRole('heading', { name: 'Add member' })).toBeInTheDocument(); - const submitButton = () => screen.getAllByRole('button', { name: 'Add' })[1]; - expect(submitButton()).toBeDisabled(); + expect(await screen.findByRole('heading', { name: 'Add members' })).toBeInTheDocument(); + expect(screen.getByRole('radio', { name: 'Email' })).toBeChecked(); + expect(screen.getByRole('button', { name: 'Add members' })).toBeDisabled(); - const options = await screen.findAllByRole('option'); - expect(options).toHaveLength(1); - expect(options[0]).toHaveTextContent('Yukio Yamamoto'); + await userEvent.type(screen.getByLabelText('Email address'), 'Yukio@clerk.com'); + await userEvent.click(screen.getByRole('button', { name: 'Add members' })); + + await waitFor(() => + expect(fixtures.clerk.organization?.getMemberships).toHaveBeenCalledWith( + expect.objectContaining({ query: 'Yukio@clerk.com' }), + ), + ); + await waitFor(() => + expect(fixtures.clerk.organization?.ssoBypassAllowlist.addUser).toHaveBeenCalledWith({ userId: 'user_9' }), + ); + expect(await screen.findByText('Added member successfully')).toBeInTheDocument(); + + await userEvent.click(await screen.findByRole('button', { name: 'Finish' })); + await waitFor(() => expect(screen.queryByRole('heading', { name: 'Add members' })).not.toBeInTheDocument()); + }); + + it('keeps looking past the first page of search results for the email address', async () => { + const { wrapper, fixtures } = await createFixtures( + withSecurityPage({ permissions: ['org:sys_entconns:manage', 'org:sys_entconns_sso_bypass:manage'] }), + ); + const lookalikes = Array.from({ length: 10 }, (_, i) => + membership(`user_${i + 20}`, `Near${i}`, `near${i}yukio@clerk.com`), + ); + fixtures.clerk.organization?.getMemberships + .mockResolvedValueOnce({ data: lookalikes, total_count: 11 } as any) + .mockResolvedValueOnce({ + data: [membership('user_9', 'Yukio', 'yukio@clerk.com')], + total_count: 11, + } as any); + fixtures.clerk.organization?.ssoBypassAllowlist.addUser.mockResolvedValue( + allowlistEntry('user_9', 'Yukio', 'yukio@clerk.com'), + ); - await userEvent.click(options[0]); - expect(screen.queryByRole('option')).not.toBeInTheDocument(); - expect(screen.getByRole('button', { name: 'Change' })).toBeInTheDocument(); + const { userEvent } = await openAllowlistPage(wrapper, fixtures, []); - await userEvent.click(submitButton()); + await userEvent.click(screen.getByRole('button', { name: 'Add' })); + await userEvent.type(await screen.findByLabelText('Email address'), 'yukio@clerk.com'); + await userEvent.click(screen.getByRole('button', { name: 'Add members' })); + await waitFor(() => + expect(fixtures.clerk.organization?.getMemberships).toHaveBeenCalledWith( + expect.objectContaining({ query: 'yukio@clerk.com', initialPage: 2 }), + ), + ); await waitFor(() => expect(fixtures.clerk.organization?.ssoBypassAllowlist.addUser).toHaveBeenCalledWith({ userId: 'user_9' }), ); - await waitFor(() => expect(screen.queryByRole('heading', { name: 'Add member' })).not.toBeInTheDocument()); }); - it('searches members through the organization membership query', async () => { + it('explains when no member has the email address', async () => { const { wrapper, fixtures } = await createFixtures( withSecurityPage({ permissions: ['org:sys_entconns:manage', 'org:sys_entconns_sso_bypass:manage'] }), ); @@ -257,23 +296,145 @@ describe('SSO bypass allowlist', () => { total_count: 1, } as any); - vi.useFakeTimers({ shouldAdvanceTime: true }); - try { - const { userEvent } = await openAllowlistPage(wrapper, fixtures, []); + const { userEvent } = await openAllowlistPage(wrapper, fixtures, []); + + await userEvent.click(screen.getByRole('button', { name: 'Add' })); + await userEvent.type(await screen.findByLabelText('Email address'), 'nobody@clerk.com'); + await userEvent.click(screen.getByRole('button', { name: 'Add members' })); + + expect(await screen.findByText('No member of this organization has that email address.')).toBeInTheDocument(); + expect(fixtures.clerk.organization?.ssoBypassAllowlist.addUser).not.toHaveBeenCalled(); + expect(screen.getByRole('heading', { name: 'Add members' })).toBeInTheDocument(); + }); + + it('adds every member with the selected role and reports the skipped ones', async () => { + const { wrapper, fixtures } = await createFixtures( + withSecurityPage({ + permissions: ['org:sys_entconns:manage', 'org:sys_entconns_sso_bypass:manage', 'org:sys_memberships:read'], + }), + ); + fixtures.clerk.organization?.getRoles.mockResolvedValue({ + data: [ + { id: 'role_admin', key: 'org:admin', name: 'Admin' }, + { id: 'role_member', key: 'org:member', name: 'Member' }, + ], + total_count: 2, + } as any); + fixtures.clerk.organization?.getMemberships.mockResolvedValue({ + data: [ + membership('user_1', 'Cameron', 'cameron@clerk.com'), + membership('user_9', 'Yukio', 'yukio@clerk.com'), + membership('user_10', 'Dana', 'dana@personal.com'), + ], + total_count: 3, + } as any); + fixtures.clerk.organization?.ssoBypassAllowlist.addUsers.mockResolvedValue({ + data: [allowlistEntry('user_9', 'Yukio', 'yukio@clerk.com')], + errors: [{ userId: 'user_10', code: 'sso_bypass_domain_not_served' }], + }); + + const { userEvent } = await openAllowlistPage(wrapper, fixtures, [ + allowlistEntry('user_1', 'Cameron', 'cameron@clerk.com'), + ]); + + await userEvent.click(screen.getByRole('button', { name: 'Add' })); + expect(await screen.findByRole('heading', { name: 'Add members' })).toBeInTheDocument(); + + await userEvent.click(screen.getByRole('radio', { name: 'Role' })); + expect(screen.getByText('This list does not sync, members are managed manually.')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Add members' })).toBeDisabled(); + + await userEvent.click(screen.getByRole('button', { name: /select role/i })); + await userEvent.click(await screen.findByText('Admin (3)')); + await userEvent.click(screen.getByRole('button', { name: 'Add members' })); + + await waitFor(() => + expect(fixtures.clerk.organization?.getMemberships).toHaveBeenCalledWith( + expect.objectContaining({ role: ['org:admin'], initialPage: 1 }), + ), + ); + await waitFor(() => + expect(fixtures.clerk.organization?.ssoBypassAllowlist.addUsers).toHaveBeenCalledWith({ + userIds: ['user_9', 'user_10'], + }), + ); + + expect(await screen.findByText('Added 1 member')).toBeInTheDocument(); + expect( + screen.getByText('1 member could not be added because their email address is not served by a connection.'), + ).toBeInTheDocument(); + expect(screen.getAllByRole('heading', { name: 'Add members' }).length).toBeGreaterThan(0); + + await userEvent.click(await screen.findByRole('button', { name: 'Finish' })); + await waitFor(() => expect(screen.queryByRole('heading', { name: 'Add members' })).not.toBeInTheDocument()); + }); + + it('keeps the form open when no member with the role could be added', async () => { + const { wrapper, fixtures } = await createFixtures( + withSecurityPage({ + permissions: ['org:sys_entconns:manage', 'org:sys_entconns_sso_bypass:manage', 'org:sys_memberships:read'], + }), + ); + fixtures.clerk.organization?.getRoles.mockResolvedValue({ + data: [{ id: 'role_admin', key: 'org:admin', name: 'Admin' }], + total_count: 1, + } as any); + fixtures.clerk.organization?.getMemberships.mockResolvedValue({ + data: [membership('user_9', 'Yukio', 'yukio@clerk.com'), membership('user_10', 'Dana', 'dana@personal.com')], + total_count: 2, + } as any); + fixtures.clerk.organization?.ssoBypassAllowlist.addUsers.mockResolvedValue({ + data: [], + errors: [ + { userId: 'user_9', code: 'sso_bypass_domain_not_served' }, + { userId: 'user_10', code: 'sso_bypass_domain_not_served' }, + ], + }); + + const { userEvent } = await openAllowlistPage(wrapper, fixtures, []); - await userEvent.click(screen.getByRole('button', { name: 'Add' })); - await userEvent.type(await screen.findByRole('searchbox', { name: 'Search members' }), 'yukio'); + await userEvent.click(screen.getByRole('button', { name: 'Add' })); + await userEvent.click(await screen.findByRole('radio', { name: 'Role' })); + await userEvent.click(screen.getByRole('button', { name: /select role/i })); + await userEvent.click(await screen.findByText('Admin (2)')); + await userEvent.click(screen.getByRole('button', { name: 'Add members' })); + + expect( + await screen.findByText( + '2 members could not be added because their email address is not served by a connection.', + ), + ).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Add members' })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Finish' })).not.toBeInTheDocument(); + }); - await vi.advanceTimersByTimeAsync(600); + it('keeps the form open when everyone with the role is already on the list', async () => { + const { wrapper, fixtures } = await createFixtures( + withSecurityPage({ + permissions: ['org:sys_entconns:manage', 'org:sys_entconns_sso_bypass:manage', 'org:sys_memberships:read'], + }), + ); + fixtures.clerk.organization?.getRoles.mockResolvedValue({ + data: [{ id: 'role_admin', key: 'org:admin', name: 'Admin' }], + total_count: 1, + } as any); + fixtures.clerk.organization?.getMemberships.mockResolvedValue({ + data: [membership('user_1', 'Cameron', 'cameron@clerk.com')], + total_count: 1, + } as any); + + const { userEvent } = await openAllowlistPage(wrapper, fixtures, [ + allowlistEntry('user_1', 'Cameron', 'cameron@clerk.com'), + ]); + + await userEvent.click(screen.getByRole('button', { name: 'Add' })); + await userEvent.click(await screen.findByRole('radio', { name: 'Role' })); + await userEvent.click(screen.getByRole('button', { name: /select role/i })); + await userEvent.click(await screen.findByText('Admin (1)')); + await userEvent.click(screen.getByRole('button', { name: 'Add members' })); - await waitFor(() => - expect(fixtures.clerk.organization?.getMemberships).toHaveBeenCalledWith( - expect.objectContaining({ query: 'yukio' }), - ), - ); - } finally { - vi.useRealTimers(); - } + expect(await screen.findByText('Everyone with that role is already on the allow list.')).toBeInTheDocument(); + expect(fixtures.clerk.organization?.ssoBypassAllowlist.addUsers).not.toHaveBeenCalled(); }); it('removes a member from the row menu', async () => { @@ -309,7 +470,7 @@ describe('SSO bypass allowlist', () => { renderPage(wrapper); expect(await screen.findByText('SSO bypass')).toBeInTheDocument(); - expect(await screen.findByText('0 users')).toBeInTheDocument(); + expect(await screen.findByText('0 members')).toBeInTheDocument(); expect(screen.getByText(SSO_DESCRIPTION)).toBeInTheDocument(); expect(screen.getByText('Active')).toBeInTheDocument(); diff --git a/packages/ui/src/customizables/elementDescriptors.ts b/packages/ui/src/customizables/elementDescriptors.ts index 810301c4f0f..c7301b05d2e 100644 --- a/packages/ui/src/customizables/elementDescriptors.ts +++ b/packages/ui/src/customizables/elementDescriptors.ts @@ -249,10 +249,10 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([ 'organizationProfileSecuritySsoBypassSearchInput', 'organizationProfileSecuritySsoBypassSearchInputIcon', 'organizationProfileSecuritySsoBypassAddButton', - 'organizationProfileSecuritySsoBypassMemberSearchInput', - 'organizationProfileSecuritySsoBypassMemberSearchInputIcon', - 'organizationProfileSecuritySsoBypassMemberOptions', - 'organizationProfileSecuritySsoBypassMemberOption', + 'organizationProfileSecuritySsoBypassEmailInput', + 'organizationProfileSecuritySsoBypassRoleWarning', + 'organizationProfileSecuritySsoBypassFailure', + 'organizationProfileSecuritySsoBypassBulkResult', 'organizationListPreviewItems', 'organizationListPreviewItem', diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts index bbd9306f598..f0959e25fd4 100644 --- a/packages/ui/src/icons/index.ts +++ b/packages/ui/src/icons/index.ts @@ -66,4 +66,5 @@ export { default as Spinner } from './spinner.svg'; export { default as ThreeDots } from './three-dots.svg'; export { default as TriangleRight } from './triangle-right.svg'; export { default as UserCircle } from './user-circle.svg'; +export { default as UserPlus } from './user-plus.svg'; export { default as Users } from './users.svg'; diff --git a/packages/ui/src/icons/user-plus.svg b/packages/ui/src/icons/user-plus.svg new file mode 100644 index 00000000000..e55f0f83ca2 --- /dev/null +++ b/packages/ui/src/icons/user-plus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/ui/src/internal/appearance.ts b/packages/ui/src/internal/appearance.ts index e49f6115fd8..93a617d45a2 100644 --- a/packages/ui/src/internal/appearance.ts +++ b/packages/ui/src/internal/appearance.ts @@ -389,10 +389,10 @@ export type ElementsConfig = { organizationProfileSecuritySsoBypassSearchInput: WithOptions; organizationProfileSecuritySsoBypassSearchInputIcon: WithOptions; organizationProfileSecuritySsoBypassAddButton: WithOptions; - organizationProfileSecuritySsoBypassMemberSearchInput: WithOptions; - organizationProfileSecuritySsoBypassMemberSearchInputIcon: WithOptions; - organizationProfileSecuritySsoBypassMemberOptions: WithOptions; - organizationProfileSecuritySsoBypassMemberOption: WithOptions; + organizationProfileSecuritySsoBypassEmailInput: WithOptions; + organizationProfileSecuritySsoBypassRoleWarning: WithOptions; + organizationProfileSecuritySsoBypassFailure: WithOptions; + organizationProfileSecuritySsoBypassBulkResult: WithOptions; organizationListPreviewItems: WithOptions; organizationListPreviewItem: WithOptions; diff --git a/packages/ui/src/primitives/Input.tsx b/packages/ui/src/primitives/Input.tsx index 258c43ceac7..9eab715f428 100644 --- a/packages/ui/src/primitives/Input.tsx +++ b/packages/ui/src/primitives/Input.tsx @@ -135,6 +135,9 @@ export const Input = React.forwardRef((props, ref) const passwordManagerProps = ignorePasswordManager ? { 'data-1p-ignore': true, + 'data-bwignore': true, + 'data-lpignore': true, + 'data-form-type': 'other', } : undefined;