diff --git a/packages/console/src/pages/Organizations/Guide/CreateOrganization/index.tsx b/packages/console/src/pages/Organizations/Guide/CreateOrganization/index.tsx index 7e736addd..371300f77 100644 --- a/packages/console/src/pages/Organizations/Guide/CreateOrganization/index.tsx +++ b/packages/console/src/pages/Organizations/Guide/CreateOrganization/index.tsx @@ -13,6 +13,7 @@ import OverlayScrollbar from '@/ds-components/OverlayScrollbar'; import TextInput from '@/ds-components/TextInput'; import TextLink from '@/ds-components/TextLink'; import useApi from '@/hooks/use-api'; +import useConfigs from '@/hooks/use-configs'; import useTenantPathname from '@/hooks/use-tenant-pathname'; import useTheme from '@/hooks/use-theme'; import { trySubmitSafe } from '@/utils/form'; @@ -30,6 +31,7 @@ function CreateOrganization() { const Icon = theme === Theme.Light ? OrganizationFeature : OrganizationFeatureDark; const { navigate } = useTenantPathname(); const api = useApi(); + const { updateConfigs } = useConfigs(); const { register, @@ -43,6 +45,7 @@ function CreateOrganization() { const onSubmit = handleSubmit( trySubmitSafe(async (json) => { await api.post(`api/organizations`, { json }); + void updateConfigs({ organizationCreated: true }); navigate(`/organizations`); }) ); diff --git a/packages/console/src/pages/Organizations/index.tsx b/packages/console/src/pages/Organizations/index.tsx index b2a6d5235..66c482094 100644 --- a/packages/console/src/pages/Organizations/index.tsx +++ b/packages/console/src/pages/Organizations/index.tsx @@ -6,6 +6,7 @@ import PageMeta from '@/components/PageMeta'; import Button from '@/ds-components/Button'; import CardTitle from '@/ds-components/CardTitle'; import TabNav, { TabNavItem } from '@/ds-components/TabNav'; +import useConfigs from '@/hooks/use-configs'; import useTenantPathname from '@/hooks/use-tenant-pathname'; import * as pageLayout from '@/scss/page-layout.module.scss'; @@ -16,6 +17,7 @@ import * as styles from './index.module.scss'; const organizationsPathname = '/organizations'; const createPathname = `${organizationsPathname}/create`; +const organizationGuidePathname = '/organization-guide'; const tabs = Object.freeze({ settings: 'settings', @@ -29,6 +31,7 @@ function Organizations({ tab }: Props) { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { navigate, match } = useTenantPathname(); const isCreating = match(createPathname); + const { configs } = useConfigs(); return (
@@ -47,7 +50,7 @@ function Organizations({ tab }: Props) { size="large" title="organizations.create_organization" onClick={() => { - navigate('/organization-guide'); + navigate(configs?.organizationCreated ? createPathname : organizationGuidePathname); }} />
diff --git a/packages/core/src/__mocks__/index.ts b/packages/core/src/__mocks__/index.ts index 3a9847712..56f6f34e4 100644 --- a/packages/core/src/__mocks__/index.ts +++ b/packages/core/src/__mocks__/index.ts @@ -98,6 +98,7 @@ export const mockAdminUserRole3: Role = { export const mockAdminConsoleData: AdminConsoleData = { signInExperienceCustomized: false, + organizationCreated: false, }; export const mockPrivateKeys: OidcConfigKey[] = [ diff --git a/packages/integration-tests/src/tests/api/logto-config.test.ts b/packages/integration-tests/src/tests/api/logto-config.test.ts index 8c6201331..6b5adfa2e 100644 --- a/packages/integration-tests/src/tests/api/logto-config.test.ts +++ b/packages/integration-tests/src/tests/api/logto-config.test.ts @@ -15,6 +15,7 @@ import { expectRejects } from '#src/helpers/index.js'; const defaultAdminConsoleConfig: AdminConsoleData = { signInExperienceCustomized: false, + organizationCreated: false, }; describe('admin console sign-in experience', () => { diff --git a/packages/schemas/alterations/next-1698646271-add-organization-created-flag.ts b/packages/schemas/alterations/next-1698646271-add-organization-created-flag.ts new file mode 100644 index 000000000..80eb5538a --- /dev/null +++ b/packages/schemas/alterations/next-1698646271-add-organization-created-flag.ts @@ -0,0 +1,75 @@ +import type { DatabaseTransactionConnection } from 'slonik'; +import { sql } from 'slonik'; + +import type { AlterationScript } from '../lib/types/alteration.js'; + +const adminConsoleConfigKey = 'adminConsole'; + +type OldAdminConsoleData = { + signInExperienceCustomized: boolean; +} & Record; + +type OldLogtoAdminConsoleConfig = { + tenantId: string; + value: OldAdminConsoleData; +}; + +type NewAdminConsoleData = { + signInExperienceCustomized: boolean; + organizationCreated: boolean; +} & Record; + +type NewLogtoAdminConsoleConfig = { + tenantId: string; + value: NewAdminConsoleData; +}; + +const alterAdminConsoleData = async ( + logtoConfig: OldLogtoAdminConsoleConfig, + pool: DatabaseTransactionConnection +) => { + const { tenantId, value: oldAdminConsoleConfig } = logtoConfig; + + const newAdminConsoleData: NewAdminConsoleData = { + ...oldAdminConsoleConfig, + organizationCreated: false, + }; + + await pool.query( + sql`update logto_configs set value = ${JSON.stringify( + newAdminConsoleData + )} where tenant_id = ${tenantId} and key = ${adminConsoleConfigKey}` + ); +}; + +const rollbackAdminConsoleData = async ( + logtoConfig: NewLogtoAdminConsoleConfig, + pool: DatabaseTransactionConnection +) => { + const { tenantId, value: newAdminConsoleConfig } = logtoConfig; + + const { organizationCreated, ...oldAdminConsoleData } = newAdminConsoleConfig; + + await pool.query( + sql`update logto_configs set value = ${JSON.stringify( + oldAdminConsoleData + )} where tenant_id = ${tenantId} and key = ${adminConsoleConfigKey}` + ); +}; + +const alteration: AlterationScript = { + up: async (pool) => { + const rows = await pool.many( + sql`select * from logto_configs where key = ${adminConsoleConfigKey}` + ); + await Promise.all(rows.map(async (row) => alterAdminConsoleData(row, pool))); + }, + down: async (pool) => { + const rows = await pool.many( + sql`select * from logto_configs where key = ${adminConsoleConfigKey}` + ); + await Promise.all(rows.map(async (row) => rollbackAdminConsoleData(row, pool))); + }, +}; + +export default alteration; diff --git a/packages/schemas/src/seeds/logto-config.ts b/packages/schemas/src/seeds/logto-config.ts index 74477084a..c7f776427 100644 --- a/packages/schemas/src/seeds/logto-config.ts +++ b/packages/schemas/src/seeds/logto-config.ts @@ -16,6 +16,7 @@ export const createDefaultAdminConsoleConfig = ( key: LogtoTenantConfigKey.AdminConsole, value: { signInExperienceCustomized: false, + organizationCreated: false, }, } satisfies CreateLogtoConfig); diff --git a/packages/schemas/src/types/logto-config.ts b/packages/schemas/src/types/logto-config.ts index 939c5e0f0..3b79c1387 100644 --- a/packages/schemas/src/types/logto-config.ts +++ b/packages/schemas/src/types/logto-config.ts @@ -48,6 +48,7 @@ export const logtoOidcConfigGuard: Readonly<{ /* --- Logto tenant configs --- */ export const adminConsoleDataGuard = z.object({ signInExperienceCustomized: z.boolean(), + organizationCreated: z.boolean(), }); export type AdminConsoleData = z.infer;