diff --git a/packages/console/src/pages/ConnectorDetails/index.tsx b/packages/console/src/pages/ConnectorDetails/index.tsx index 760df8381..29ac6cdc0 100644 --- a/packages/console/src/pages/ConnectorDetails/index.tsx +++ b/packages/console/src/pages/ConnectorDetails/index.tsx @@ -3,7 +3,7 @@ import { AppearanceMode, ConnectorType } from '@logto/schemas'; import classNames from 'classnames'; import { useState } from 'react'; import { toast } from 'react-hot-toast'; -import { useTranslation } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import { useNavigate, useParams } from 'react-router-dom'; import useSWR, { useSWRConfig } from 'swr'; @@ -14,6 +14,7 @@ import Reset from '@/assets/images/reset.svg'; import ActionMenu, { ActionMenuItem } from '@/components/ActionMenu'; import Button from '@/components/Button'; import Card from '@/components/Card'; +import ConfirmModal from '@/components/ConfirmModal'; import CopyToClipboard from '@/components/CopyToClipboard'; import DetailsSkeleton from '@/components/DetailsSkeleton'; import Drawer from '@/components/Drawer'; @@ -49,6 +50,18 @@ const ConnectorDetails = () => { const api = useApi(); const navigate = useNavigate(); const theme = useTheme(); + const isSocial = data?.type === ConnectorType.Social; + const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); + + const onDeleteClick = async () => { + if (!isSocial || !inUse) { + await handleDelete(); + + return; + } + + setIsDeleteAlertOpen(true); + }; const handleDelete = async () => { if (!connectorId) { @@ -65,7 +78,7 @@ const ConnectorDetails = () => { await mutateGlobal('/api/connectors'); setIsDeleted(true); - if (data?.type === ConnectorType.Social) { + if (isSocial) { navigate(`/connectors/social`, { replace: true }); } else { navigate(`/connectors`, { replace: true }); @@ -75,16 +88,14 @@ const ConnectorDetails = () => { return (
} title="connector_details.back_to_connectors" className={styles.backLink} /> {isLoading && } {!data && error &&
{`error occurred: ${error.body?.message ?? error.message}`}
} - {data?.type === ConnectorType.Social && ( - - )} + {isSocial && } {data && (
@@ -137,7 +148,7 @@ const ConnectorDetails = () => { buttonProps={{ icon: , size: 'large' }} title={t('general.more_options')} > - {data.type !== ConnectorType.Social && ( + {!isSocial && ( } iconClassName={styles.resetIcon} @@ -152,7 +163,7 @@ const ConnectorDetails = () => { )} )} - } type="danger" onClick={handleDelete}> + } type="danger" onClick={onDeleteClick}> {t('general.delete')} @@ -183,6 +194,22 @@ const ConnectorDetails = () => { /> )} + {data && ( + { + setIsDeleteAlertOpen(false); + }} + onConfirm={handleDelete} + > + }} + /> + + )}
); }; diff --git a/packages/core/src/__mocks__/connector-base-data.ts b/packages/core/src/__mocks__/connector-base-data.ts new file mode 100644 index 000000000..71e294abd --- /dev/null +++ b/packages/core/src/__mocks__/connector-base-data.ts @@ -0,0 +1,125 @@ +import type { ConnectorMetadata } from '@logto/connector-kit'; +import { ConnectorPlatform } from '@logto/connector-kit'; +import type { Connector } from '@logto/schemas'; + +export const mockMetadata: ConnectorMetadata = { + id: 'id', + target: 'connector', + platform: null, + name: { + en: 'Connector', + 'pt-PT': 'Conector', + 'zh-CN': '连接器', + 'tr-TR': 'Connector', + ko: 'Connector', + }, + logo: './logo.png', + logoDark: './logo-dark.png', + description: { + en: 'Connector', + 'pt-PT': 'Conector', + 'zh-CN': '连接器', + 'tr-TR': 'Connector', + ko: 'Connector', + }, + readme: 'README.md', + configTemplate: 'config-template.json', +}; + +export const mockMetadata0: ConnectorMetadata = { + ...mockMetadata, + id: 'id0', + target: 'connector_0', + platform: ConnectorPlatform.Universal, +}; + +export const mockMetadata1: ConnectorMetadata = { + ...mockMetadata, + id: 'id1', + target: 'connector_1', + platform: ConnectorPlatform.Universal, +}; + +export const mockMetadata2: ConnectorMetadata = { + ...mockMetadata, + id: 'id2', + target: 'connector_2', + platform: ConnectorPlatform.Universal, +}; + +export const mockMetadata3: ConnectorMetadata = { + ...mockMetadata, + id: 'id3', + target: 'connector_3', + platform: ConnectorPlatform.Universal, +}; + +export const mockMetadata4: ConnectorMetadata = { + ...mockMetadata, + id: 'id4', + target: 'connector_4', + platform: ConnectorPlatform.Universal, +}; + +export const mockMetadata5: ConnectorMetadata = { + ...mockMetadata, + id: 'id5', + target: 'connector_5', + platform: ConnectorPlatform.Universal, +}; + +export const mockMetadata6: ConnectorMetadata = { + ...mockMetadata, + id: 'id6', + target: 'connector_6', + platform: ConnectorPlatform.Universal, +}; + +export const mockConnector0: Connector = { + id: 'id0', + enabled: true, + config: {}, + createdAt: 1_234_567_890_123, +}; + +export const mockConnector1: Connector = { + id: 'id1', + enabled: true, + config: {}, + createdAt: 1_234_567_890_234, +}; + +export const mockConnector2: Connector = { + id: 'id2', + enabled: true, + config: {}, + createdAt: 1_234_567_890_345, +}; + +export const mockConnector3: Connector = { + id: 'id3', + enabled: true, + config: {}, + createdAt: 1_234_567_890_456, +}; + +export const mockConnector4: Connector = { + id: 'id4', + enabled: true, + config: {}, + createdAt: 1_234_567_890_567, +}; + +export const mockConnector5: Connector = { + id: 'id5', + enabled: true, + config: {}, + createdAt: 1_234_567_890_567, +}; + +export const mockConnector6: Connector = { + id: 'id6', + enabled: true, + config: {}, + createdAt: 1_234_567_890_567, +}; diff --git a/packages/core/src/__mocks__/connector.ts b/packages/core/src/__mocks__/connector.ts index 69e6c99c2..84181b3f9 100644 --- a/packages/core/src/__mocks__/connector.ts +++ b/packages/core/src/__mocks__/connector.ts @@ -1,33 +1,29 @@ import { ConnectorPlatform } from '@logto/connector-kit'; -import type { Connector, ConnectorMetadata } from '@logto/schemas'; +import type { Connector } from '@logto/schemas'; import { ConnectorType } from '@logto/schemas'; import { any } from 'zod'; import type { LogtoConnector } from '@/connectors/types'; -export const mockMetadata: ConnectorMetadata = { - id: 'id', - target: 'connector', - platform: null, - name: { - en: 'Connector', - 'pt-PT': 'Conector', - 'zh-CN': '连接器', - 'tr-TR': 'Connector', - ko: 'Connector', - }, - logo: './logo.png', - logoDark: './logo-dark.png', - description: { - en: 'Connector', - 'pt-PT': 'Conector', - 'zh-CN': '连接器', - 'tr-TR': 'Connector', - ko: 'Connector', - }, - readme: 'README.md', - configTemplate: 'config-template.json', -}; +import { + mockConnector0, + mockConnector1, + mockConnector2, + mockConnector3, + mockConnector4, + mockConnector5, + mockConnector6, + mockMetadata, + mockMetadata0, + mockMetadata1, + mockMetadata2, + mockMetadata3, + mockMetadata4, + mockMetadata5, + mockMetadata6, +} from './connector-base-data'; + +export { mockMetadata } from './connector-base-data'; export const mockConnector: Connector = { id: 'id', @@ -44,104 +40,6 @@ export const mockLogtoConnector = { configGuard: any(), }; -const mockMetadata0: ConnectorMetadata = { - ...mockMetadata, - id: 'id0', - target: 'connector_0', - platform: ConnectorPlatform.Universal, -}; - -const mockMetadata1: ConnectorMetadata = { - ...mockMetadata, - id: 'id1', - target: 'connector_1', - platform: ConnectorPlatform.Universal, -}; - -const mockMetadata2: ConnectorMetadata = { - ...mockMetadata, - id: 'id2', - target: 'connector_2', - platform: ConnectorPlatform.Universal, -}; - -const mockMetadata3: ConnectorMetadata = { - ...mockMetadata, - id: 'id3', - target: 'connector_3', - platform: ConnectorPlatform.Universal, -}; - -const mockMetadata4: ConnectorMetadata = { - ...mockMetadata, - id: 'id4', - target: 'connector_4', - platform: ConnectorPlatform.Universal, -}; - -const mockMetadata5: ConnectorMetadata = { - ...mockMetadata, - id: 'id5', - target: 'connector_5', - platform: ConnectorPlatform.Universal, -}; - -const mockMetadata6: ConnectorMetadata = { - ...mockMetadata, - id: 'id6', - target: 'connector_6', - platform: ConnectorPlatform.Universal, -}; - -const mockConnector0: Connector = { - id: 'id0', - enabled: true, - config: {}, - createdAt: 1_234_567_890_123, -}; - -const mockConnector1: Connector = { - id: 'id1', - enabled: true, - config: {}, - createdAt: 1_234_567_890_234, -}; - -const mockConnector2: Connector = { - id: 'id2', - enabled: true, - config: {}, - createdAt: 1_234_567_890_345, -}; - -const mockConnector3: Connector = { - id: 'id3', - enabled: true, - config: {}, - createdAt: 1_234_567_890_456, -}; - -const mockConnector4: Connector = { - id: 'id4', - enabled: true, - config: {}, - createdAt: 1_234_567_890_567, -}; - -const mockConnector5: Connector = { - id: 'id5', - enabled: true, - config: {}, - createdAt: 1_234_567_890_567, -}; - -const mockConnector6: Connector = { - id: 'id6', - enabled: true, - config: {}, - createdAt: 1_234_567_890_567, -}; - export const mockConnectorList: Connector[] = [ mockConnector0, mockConnector1, @@ -312,3 +210,52 @@ export const mockLogtoConnectors = [ mockWechatConnector, mockWechatNativeConnector, ]; + +export const disabledSocialTarget01 = 'disableSocialTarget-id01'; +export const disabledSocialTarget02 = 'disableSocialTarget-id02'; +export const enabledSocialTarget01 = 'enabledSocialTarget-id01'; + +export const mockSocialConnectors: LogtoConnector[] = [ + { + dbEntry: { + id: 'id0', + enabled: false, + config: {}, + createdAt: 1_234_567_890_123, + }, + metadata: { + ...mockMetadata, + target: disabledSocialTarget01, + }, + type: ConnectorType.Social, + ...mockLogtoConnector, + }, + { + dbEntry: { + id: 'id1', + enabled: true, + config: {}, + createdAt: 1_234_567_890_123, + }, + metadata: { + ...mockMetadata, + target: enabledSocialTarget01, + }, + type: ConnectorType.Social, + ...mockLogtoConnector, + }, + { + dbEntry: { + id: 'id2', + enabled: false, + config: {}, + createdAt: 1_234_567_890_123, + }, + metadata: { + ...mockMetadata, + target: disabledSocialTarget02, + }, + type: ConnectorType.Social, + ...mockLogtoConnector, + }, +]; diff --git a/packages/core/src/lib/sign-in-experience/index.test.ts b/packages/core/src/lib/sign-in-experience/index.test.ts index 068ebd525..b871a0469 100644 --- a/packages/core/src/lib/sign-in-experience/index.test.ts +++ b/packages/core/src/lib/sign-in-experience/index.test.ts @@ -1,22 +1,53 @@ import type { LanguageTag } from '@logto/language-kit'; import { builtInLanguages } from '@logto/phrases-ui'; +import type { CreateSignInExperience, SignInExperience } from '@logto/schemas'; import { BrandingStyle } from '@logto/schemas'; -import { mockBranding } from '@/__mocks__'; +import { + disabledSocialTarget01, + disabledSocialTarget02, + enabledSocialTarget01, + mockBranding, + mockSignInExperience, + mockSocialConnectors, +} from '@/__mocks__'; +import type { LogtoConnector } from '@/connectors/types'; import RequestError from '@/errors/RequestError'; import { validateBranding, validateTermsOfUse, validateLanguageInfo, + removeUnavailableSocialConnectorTargets, } from '@/lib/sign-in-experience'; +import { updateDefaultSignInExperience } from '@/queries/sign-in-experience'; const allCustomLanguageTags: LanguageTag[] = []; const findAllCustomLanguageTags = jest.fn(async () => allCustomLanguageTags); +const getLogtoConnectorsPlaceHolder = jest.fn() as jest.MockedFunction< + () => Promise +>; +const findDefaultSignInExperience = jest.fn() as jest.MockedFunction< + () => Promise +>; jest.mock('@/queries/custom-phrase', () => ({ findAllCustomLanguageTags: async () => findAllCustomLanguageTags(), })); +jest.mock('@/connectors', () => ({ + getLogtoConnectors: async () => getLogtoConnectorsPlaceHolder(), +})); + +jest.mock('@/queries/sign-in-experience', () => ({ + findDefaultSignInExperience: async () => findDefaultSignInExperience(), + updateDefaultSignInExperience: jest.fn( + async (data: Partial): Promise => ({ + ...mockSignInExperience, + ...data, + }) + ), +})); + beforeEach(() => { jest.clearAllMocks(); }); @@ -123,3 +154,25 @@ describe('validate terms of use', () => { }).toMatchError(new RequestError('sign_in_experiences.empty_content_url_of_terms_of_use')); }); }); + +describe('remove unavailable social connector targets', () => { + test('should remove unavailable social connector targets in sign-in experience', async () => { + const mockSocialConnectorTargets = mockSocialConnectors.map( + ({ metadata: { target } }) => target + ); + findDefaultSignInExperience.mockResolvedValueOnce({ + ...mockSignInExperience, + socialSignInConnectorTargets: mockSocialConnectorTargets, + }); + getLogtoConnectorsPlaceHolder.mockResolvedValueOnce(mockSocialConnectors); + expect(mockSocialConnectorTargets).toEqual([ + disabledSocialTarget01, + enabledSocialTarget01, + disabledSocialTarget02, + ]); + await removeUnavailableSocialConnectorTargets(); + expect(updateDefaultSignInExperience).toBeCalledWith({ + socialSignInConnectorTargets: [enabledSocialTarget01], + }); + }); +}); diff --git a/packages/core/src/lib/sign-in-experience/index.ts b/packages/core/src/lib/sign-in-experience/index.ts index 81d522bde..304544434 100644 --- a/packages/core/src/lib/sign-in-experience/index.ts +++ b/packages/core/src/lib/sign-in-experience/index.ts @@ -1,9 +1,14 @@ import { builtInLanguages } from '@logto/phrases-ui'; import type { Branding, LanguageInfo, TermsOfUse } from '@logto/schemas'; -import { BrandingStyle } from '@logto/schemas'; +import { ConnectorType, BrandingStyle } from '@logto/schemas'; +import { getLogtoConnectors } from '@/connectors'; import RequestError from '@/errors/RequestError'; import { findAllCustomLanguageTags } from '@/queries/custom-phrase'; +import { + findDefaultSignInExperience, + updateDefaultSignInExperience, +} from '@/queries/sign-in-experience'; import assertThat from '@/utils/assert-that'; export * from './sign-up'; @@ -35,3 +40,19 @@ export const validateTermsOfUse = (termsOfUse: TermsOfUse) => { 'sign_in_experiences.empty_content_url_of_terms_of_use' ); }; + +export const removeUnavailableSocialConnectorTargets = async () => { + const connectors = await getLogtoConnectors(); + const availableSocialConnectorTargets = new Set( + connectors + .filter(({ type, dbEntry: { enabled } }) => enabled && type === ConnectorType.Social) + .map(({ metadata: { target } }) => target) + ); + + const { socialSignInConnectorTargets } = await findDefaultSignInExperience(); + await updateDefaultSignInExperience({ + socialSignInConnectorTargets: socialSignInConnectorTargets.filter((target) => + availableSocialConnectorTargets.has(target) + ), + }); +}; diff --git a/packages/core/src/routes/connector.ts b/packages/core/src/routes/connector.ts index 0663ed4f6..c03e25fbb 100644 --- a/packages/core/src/routes/connector.ts +++ b/packages/core/src/routes/connector.ts @@ -7,6 +7,7 @@ import { object, string } from 'zod'; import { getLogtoConnectorById, getLogtoConnectors } from '@/connectors'; import type { LogtoConnector } from '@/connectors/types'; import RequestError from '@/errors/RequestError'; +import { removeUnavailableSocialConnectorTargets } from '@/lib/sign-in-experience'; import koaGuard from '@/middleware/koa-guard'; import { updateConnector } from '@/queries/connector'; import assertThat from '@/utils/assert-that'; @@ -115,6 +116,12 @@ export default function connectorRoutes(router: T) { where: { id }, jsonbMode: 'merge', }); + + // Delete the social connector in the sign-in experience if it is disabled. + if (!enabled && type === ConnectorType.Social) { + await removeUnavailableSocialConnectorTargets(); + } + ctx.body = { ...connector, metadata, type }; return next(); diff --git a/packages/core/src/routes/connector.update.test.ts b/packages/core/src/routes/connector.update.test.ts index 2bd028b16..3e9eb3094 100644 --- a/packages/core/src/routes/connector.update.test.ts +++ b/packages/core/src/routes/connector.update.test.ts @@ -46,6 +46,10 @@ jest.mock('@/connectors', () => ({ getLogtoConnectorById: async (connectorId: string) => getLogtoConnectorByIdPlaceholder(connectorId), })); +jest.mock('@/lib/sign-in-experience', () => ({ + // eslint-disable-next-line @typescript-eslint/no-empty-function + removeUnavailableSocialConnectorTargets: async () => {}, +})); describe('connector PATCH routes', () => { const connectorRequest = createRequester({ authedRoutes: connectorRoutes }); diff --git a/packages/core/src/routes/session/continue.test.ts b/packages/core/src/routes/session/continue.test.ts index 3d2af5dea..76d4456fe 100644 --- a/packages/core/src/routes/session/continue.test.ts +++ b/packages/core/src/routes/session/continue.test.ts @@ -1,3 +1,4 @@ +import { PasscodeType } from '@logto/schemas'; import { addDays, subSeconds } from 'date-fns'; import { Provider } from 'oidc-provider'; @@ -138,6 +139,7 @@ describe('session -> continueRoutes', () => { continueSignIn: { userId: mockUser.id, expiresAt: getTomorrowIsoString(), + type: PasscodeType.Continue, }, }, }); @@ -169,6 +171,7 @@ describe('session -> continueRoutes', () => { continueSignIn: { userId: mockUser.id, expiresAt: getTomorrowIsoString(), + type: PasscodeType.Continue, }, }, }); diff --git a/packages/core/src/routes/session/continue.ts b/packages/core/src/routes/session/continue.ts index a37738fd5..83d42d851 100644 --- a/packages/core/src/routes/session/continue.ts +++ b/packages/core/src/routes/session/continue.ts @@ -17,7 +17,7 @@ import { import assertThat from '@/utils/assert-that'; import type { AnonymousRouter } from '../types'; -import { emailSessionResultGuard, smsSessionResultGuard } from './types'; +import { continueEmailSessionResultGuard, continueSmsSessionResultGuard } from './types'; import { checkRequiredProfile, getContinueSignInResult, @@ -104,7 +104,7 @@ export default function continueRoutes(router: T, pro const { email } = await getVerificationStorageFromInteraction( ctx, provider, - emailSessionResultGuard + continueEmailSessionResultGuard ); const user = await findUserById(userId); @@ -138,7 +138,7 @@ export default function continueRoutes(router: T, pro const { phone } = await getVerificationStorageFromInteraction( ctx, provider, - smsSessionResultGuard + continueSmsSessionResultGuard ); const user = await findUserById(userId); diff --git a/packages/core/src/routes/session/passwordless.ts b/packages/core/src/routes/session/passwordless.ts index c038f560d..e2f1686c0 100644 --- a/packages/core/src/routes/session/passwordless.ts +++ b/packages/core/src/routes/session/passwordless.ts @@ -117,13 +117,21 @@ export default function passwordlessRoutes( return next(); } - await assignVerificationResult(ctx, provider, { flow, phone }); - if (flow === PasscodeType.SignIn) { + await assignVerificationResult(ctx, provider, { flow, phone }); + return smsSignInAction(provider)(ctx, next); } - return smsRegisterAction(provider)(ctx, next); + if (flow === PasscodeType.Register) { + await assignVerificationResult(ctx, provider, { flow, phone }); + + return smsRegisterAction(provider)(ctx, next); + } + + await assignVerificationResult(ctx, provider, { flow, phone }); + + return next(); } ); @@ -161,13 +169,21 @@ export default function passwordlessRoutes( return next(); } - await assignVerificationResult(ctx, provider, { flow, email }); - if (flow === PasscodeType.SignIn) { + await assignVerificationResult(ctx, provider, { flow, email }); + return emailSignInAction(provider)(ctx, next); } - return emailRegisterAction(provider)(ctx, next); + if (flow === PasscodeType.Register) { + await assignVerificationResult(ctx, provider, { flow, email }); + + return emailRegisterAction(provider)(ctx, next); + } + + await assignVerificationResult(ctx, provider, { flow, email }); + + return next(); } ); diff --git a/packages/core/src/routes/session/types.ts b/packages/core/src/routes/session/types.ts index 098b6bd0c..82469b79d 100644 --- a/packages/core/src/routes/session/types.ts +++ b/packages/core/src/routes/session/types.ts @@ -45,10 +45,36 @@ export const forgotPasswordSessionResultGuard = z.object({ verification: forgotPasswordSessionStorageGuard, }); +const continueEmailSessionStorageGuard = z.object({ + flow: z.literal(PasscodeType.Continue), + expiresAt: z.string(), + email: z.string(), +}); + +export type ContinueEmailSessionStorage = z.infer; + +export const continueEmailSessionResultGuard = z.object({ + verification: continueEmailSessionStorageGuard, +}); + +const continueSmsSessionStorageGuard = z.object({ + flow: z.literal(PasscodeType.Continue), + expiresAt: z.string(), + phone: z.string(), +}); + +export type ContinueSmsSessionStorage = z.infer; + +export const continueSmsSessionResultGuard = z.object({ + verification: continueSmsSessionStorageGuard, +}); + export type VerificationStorage = | SmsSessionStorage | EmailSessionStorage - | ForgotPasswordSessionStorage; + | ForgotPasswordSessionStorage + | ContinueEmailSessionStorage + | ContinueSmsSessionStorage; export type VerificationResult = { verification: T }; diff --git a/packages/phrases/src/locales/de/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/de/translation/admin-console/connector-details.ts index 4a67369ad..23f210699 100644 --- a/packages/phrases/src/locales/de/translation/admin-console/connector-details.ts +++ b/packages/phrases/src/locales/de/translation/admin-console/connector-details.ts @@ -17,6 +17,8 @@ const connector_details = { type_email: 'E-Mail connector', type_sms: 'SMS connector', type_social: 'Social connector', + in_use_deletion_description: + 'This connector is in use in your sign in experience. By deleting, sign in experience will be deleted in sign in experience settings.', // UNTRANSLATED }; export default connector_details; diff --git a/packages/phrases/src/locales/en/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/en/translation/admin-console/connector-details.ts index d009e9bc1..abef0e54e 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/connector-details.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/connector-details.ts @@ -17,6 +17,8 @@ const connector_details = { type_email: 'Email connector', type_sms: 'SMS connector', type_social: 'Social connector', + in_use_deletion_description: + 'This connector is in use in your sign in experience. By deleting, sign in experience will be deleted in sign in experience settings.', }; export default connector_details; diff --git a/packages/phrases/src/locales/fr/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/fr/translation/admin-console/connector-details.ts index 4e77dea47..f11ada084 100644 --- a/packages/phrases/src/locales/fr/translation/admin-console/connector-details.ts +++ b/packages/phrases/src/locales/fr/translation/admin-console/connector-details.ts @@ -17,6 +17,8 @@ const connector_details = { type_email: 'Connecteur Email', type_sms: 'Connecteur SMS', type_social: 'Connecteur Social', + in_use_deletion_description: + 'This connector is in use in your sign in experience. By deleting, sign in experience will be deleted in sign in experience settings.', // UNTRANSLATED }; export default connector_details; diff --git a/packages/phrases/src/locales/ko/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/ko/translation/admin-console/connector-details.ts index 5ea485c8e..0d0f07949 100644 --- a/packages/phrases/src/locales/ko/translation/admin-console/connector-details.ts +++ b/packages/phrases/src/locales/ko/translation/admin-console/connector-details.ts @@ -17,6 +17,8 @@ const connector_details = { type_email: '이메일 연동', type_sms: 'SMS 연동', type_social: '소셜 연동', + in_use_deletion_description: + 'This connector is in use in your sign in experience. By deleting, sign in experience will be deleted in sign in experience settings.', // UNTRANSLATED }; export default connector_details; diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/connector-details.ts index 3933d3f3c..2c081c494 100644 --- a/packages/phrases/src/locales/pt-pt/translation/admin-console/connector-details.ts +++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/connector-details.ts @@ -17,6 +17,8 @@ const connector_details = { type_email: 'Conector de Email', type_sms: 'Conector de SMS', type_social: 'Conector Social', + in_use_deletion_description: + 'This connector is in use in your sign in experience. By deleting, sign in experience will be deleted in sign in experience settings.', // UNTRANSLATED }; export default connector_details; diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/connector-details.ts index b61ac449a..1730766b1 100644 --- a/packages/phrases/src/locales/tr-tr/translation/admin-console/connector-details.ts +++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/connector-details.ts @@ -17,6 +17,8 @@ const connector_details = { type_email: 'Eposta connectorı', type_sms: 'SMS connectorı', type_social: 'Social connector', + in_use_deletion_description: + 'This connector is in use in your sign in experience. By deleting, sign in experience will be deleted in sign in experience settings.', // UNTRANSLATED }; export default connector_details; diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/connector-details.ts index b491d749b..2721849d8 100644 --- a/packages/phrases/src/locales/zh-cn/translation/admin-console/connector-details.ts +++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/connector-details.ts @@ -17,6 +17,8 @@ const connector_details = { type_email: '邮件连接器', type_sms: '短信连接器', type_social: '社交连接器', + in_use_deletion_description: + 'This connector is in use in your sign in experience. By deleting, sign in experience will be deleted in sign in experience settings.', // UNTRANSLATED }; export default connector_details; diff --git a/packages/schemas/alterations/next-1667900481-add-passcode-type-continue.ts b/packages/schemas/alterations/next-1667900481-add-passcode-type-continue.ts new file mode 100644 index 000000000..1aa07480c --- /dev/null +++ b/packages/schemas/alterations/next-1667900481-add-passcode-type-continue.ts @@ -0,0 +1,19 @@ +import { sql } from 'slonik'; + +import type { AlterationScript } from '../lib/types/alteration'; + +const alteration: AlterationScript = { + up: async (pool) => { + await pool.query(sql` + alter type passcode_type add value 'Continue' + `); + }, + down: async (pool) => { + await pool.query(sql` + drop type passcode_type + create type passcode_type as enum ('SignIn', 'Register', 'ForgotPassword'); + `); + }, +}; + +export default alteration; diff --git a/packages/schemas/tables/passcodes.sql b/packages/schemas/tables/passcodes.sql index 300f5fd98..d596747d8 100644 --- a/packages/schemas/tables/passcodes.sql +++ b/packages/schemas/tables/passcodes.sql @@ -1,4 +1,4 @@ -create type passcode_type as enum ('SignIn', 'Register', 'ForgotPassword'); +create type passcode_type as enum ('SignIn', 'Register', 'ForgotPassword', 'Continue'); create table passcodes ( id varchar(21) not null,