0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(console): update get-started tasks (#3439)

This commit is contained in:
Xiao Yijun 2023-03-17 14:19:29 +08:00 committed by GitHub
parent 30ed6ff998
commit 3404684a61
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 305 additions and 76 deletions

View file

@ -0,0 +1,26 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1820_100266)">
<rect width="48" height="48" rx="8" fill="#3A3B59"/>
<rect x="5" y="5" width="30.8" height="30.8" rx="8" fill="url(#paint0_linear_1820_100266)" fill-opacity="0.8"/>
<circle cx="20.3998" cy="15.7811" r="4.62" fill="#F5EEFF"/>
<rect x="15.0098" y="14.2409" width="6.16" height="0.77" rx="0.385" fill="#2D2C61"/>
<rect x="22.7095" y="14.2409" width="3.08" height="0.77" rx="0.385" fill="#2D2C61"/>
<path d="M13.4697 26.5609C13.4697 24.0094 15.5382 21.9409 18.0897 21.9409H22.7097C25.2613 21.9409 27.3297 24.0094 27.3297 26.5609V28.1009C27.3297 28.9514 26.6402 29.6409 25.7897 29.6409H15.0097C14.1592 29.6409 13.4697 28.9514 13.4697 28.1009V26.5609Z" fill="#FAABFF"/>
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M34.7198 26.6343C34.7198 26.209 35.0646 25.8643 35.4898 25.8643H37.0298C37.4551 25.8643 37.7998 26.209 37.7998 26.6343V28.1743H34.7198V26.6343ZM34.7198 44.3444C34.7198 44.7696 35.0645 45.1144 35.4898 45.1144H37.0298C37.4551 45.1144 37.7998 44.7696 37.7998 44.3444V42.8044H34.7198V44.3444ZM27.4048 37.0302C26.9795 37.0302 26.6348 36.6854 26.6348 36.2602V34.7202C26.6348 34.2949 26.9795 33.9502 27.4048 33.9502H28.9448V37.0302H27.4048ZM45.1148 37.0302C45.54 37.0302 45.8848 36.6854 45.8848 36.2602V34.7202C45.8848 34.2949 45.54 33.9502 45.1148 33.9502H43.5748V37.0302H45.1148Z" fill="#CABEFF"/>
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M28.9096 30.3166C28.6089 30.0159 28.6089 29.5283 28.9096 29.2276L29.9985 28.1387C30.2992 27.838 30.7867 27.838 31.0875 28.1387L32.1764 29.2276L29.9985 31.4055L28.9096 30.3166ZM41.4323 42.8395C41.733 43.1402 42.2206 43.1402 42.5213 42.8395L43.6102 41.7506C43.9109 41.4499 43.9109 40.9624 43.6102 40.6617L42.5213 39.5727L40.3434 41.7506L41.4323 42.8395ZM31.0877 42.8401C30.787 43.1408 30.2995 43.1408 29.9988 42.8401L28.9098 41.7511C28.6091 41.4504 28.6091 40.9629 28.9098 40.6622L29.9987 39.5732L32.1766 41.7511L31.0877 42.8401ZM43.6104 30.317C43.9111 30.0163 43.9111 29.5288 43.6104 29.2281L42.5214 28.1391C42.2207 27.8384 41.7332 27.8384 41.4325 28.1391L40.3436 29.2281L42.5215 31.406L43.6104 30.317Z" fill="#CABEFF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.2596 43.191C40.5122 43.191 43.9596 39.7436 43.9596 35.491C43.9596 31.2384 40.5122 27.791 36.2596 27.791C32.007 27.791 28.5596 31.2384 28.5596 35.491C28.5596 39.7436 32.007 43.191 36.2596 43.191ZM36.2595 38.5712C37.9606 38.5712 39.3395 37.1923 39.3395 35.4912C39.3395 33.7902 37.9606 32.4112 36.2595 32.4112C34.5585 32.4112 33.1795 33.7902 33.1795 35.4912C33.1795 37.1923 34.5585 38.5712 36.2595 38.5712Z" fill="url(#paint1_linear_1820_100266)"/>
</g>
<defs>
<linearGradient id="paint0_linear_1820_100266" x1="32.5" y1="7" x2="4" y2="40.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#5E35F3"/>
<stop offset="1" stop-color="#F5A7FF"/>
</linearGradient>
<linearGradient id="paint1_linear_1820_100266" x1="27.811" y1="42.091" x2="42.7546" y2="30.0127" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF06A"/>
<stop offset="1" stop-color="#E54AFE"/>
</linearGradient>
<clipPath id="clip0_1820_100266">
<rect width="48" height="48" rx="8" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,26 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1724_99135)">
<rect width="48" height="48" rx="8" fill="#F3EFFA"/>
<rect x="5" y="5" width="30.8" height="30.8" rx="8" fill="url(#paint0_linear_1724_99135)" fill-opacity="0.8"/>
<circle cx="20.3998" cy="15.7811" r="4.62" fill="#F5EEFF"/>
<rect x="15.0098" y="14.2409" width="6.16" height="0.77" rx="0.385" fill="#2D2C61"/>
<rect x="22.7095" y="14.2409" width="3.08" height="0.77" rx="0.385" fill="#2D2C61"/>
<path d="M13.4697 26.5609C13.4697 24.0094 15.5382 21.9409 18.0897 21.9409H22.7097C25.2613 21.9409 27.3297 24.0094 27.3297 26.5609V28.1009C27.3297 28.9514 26.6402 29.6409 25.7897 29.6409H15.0097C14.1592 29.6409 13.4697 28.9514 13.4697 28.1009V26.5609Z" fill="#FAABFF"/>
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M34.7198 26.6343C34.7198 26.209 35.0646 25.8643 35.4898 25.8643H37.0298C37.4551 25.8643 37.7998 26.209 37.7998 26.6343V28.1743H34.7198V26.6343ZM34.7198 44.3444C34.7198 44.7696 35.0645 45.1144 35.4898 45.1144H37.0298C37.4551 45.1144 37.7998 44.7696 37.7998 44.3444V42.8044H34.7198V44.3444ZM27.4048 37.0302C26.9795 37.0302 26.6348 36.6854 26.6348 36.2602V34.7202C26.6348 34.2949 26.9795 33.9502 27.4048 33.9502H28.9448V37.0302H27.4048ZM45.1148 37.0302C45.54 37.0302 45.8848 36.6854 45.8848 36.2602V34.7202C45.8848 34.2949 45.54 33.9502 45.1148 33.9502H43.5748V37.0302H45.1148Z" fill="#7958FF"/>
<path opacity="0.7" fill-rule="evenodd" clip-rule="evenodd" d="M28.9096 30.3166C28.6089 30.0159 28.6089 29.5283 28.9096 29.2276L29.9985 28.1387C30.2992 27.838 30.7867 27.838 31.0875 28.1387L32.1764 29.2276L29.9985 31.4055L28.9096 30.3166ZM41.4323 42.8395C41.733 43.1402 42.2206 43.1402 42.5213 42.8395L43.6102 41.7506C43.9109 41.4499 43.9109 40.9624 43.6102 40.6617L42.5213 39.5727L40.3434 41.7506L41.4323 42.8395ZM31.0877 42.8401C30.787 43.1408 30.2995 43.1408 29.9988 42.8401L28.9098 41.7511C28.6091 41.4504 28.6091 40.9629 28.9098 40.6622L29.9987 39.5732L32.1766 41.7511L31.0877 42.8401ZM43.6104 30.317C43.9111 30.0163 43.9111 29.5288 43.6104 29.2281L42.5214 28.1391C42.2207 27.8384 41.7332 27.8384 41.4325 28.1391L40.3436 29.2281L42.5215 31.406L43.6104 30.317Z" fill="#7958FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.2596 43.191C40.5122 43.191 43.9596 39.7436 43.9596 35.491C43.9596 31.2384 40.5122 27.791 36.2596 27.791C32.007 27.791 28.5596 31.2384 28.5596 35.491C28.5596 39.7436 32.007 43.191 36.2596 43.191ZM36.2595 38.5712C37.9606 38.5712 39.3395 37.1923 39.3395 35.4912C39.3395 33.7902 37.9606 32.4112 36.2595 32.4112C34.5585 32.4112 33.1795 33.7902 33.1795 35.4912C33.1795 37.1923 34.5585 38.5712 36.2595 38.5712Z" fill="url(#paint1_linear_1724_99135)"/>
</g>
<defs>
<linearGradient id="paint0_linear_1724_99135" x1="32.5" y1="7" x2="4" y2="40.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#5E35F3"/>
<stop offset="1" stop-color="#F5A7FF"/>
</linearGradient>
<linearGradient id="paint1_linear_1724_99135" x1="27.811" y1="42.091" x2="42.7546" y2="30.0127" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF06A"/>
<stop offset="1" stop-color="#E54AFE"/>
</linearGradient>
<clipPath id="clip0_1724_99135">
<rect width="48" height="48" rx="8" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -1,10 +1,11 @@
import { useCallback, useMemo } from 'react';
import { z } from 'zod';
import { isCloud } from '@/consts/cloud';
import useMeCustomData from '@/hooks/use-me-custom-data';
import type { UserOnboardingData } from '../types';
import { userOnboardingDataGuard } from '../types';
import { Project, userOnboardingDataGuard } from '../types';
const userOnboardingDataKey = 'onboarding';
@ -17,6 +18,10 @@ const useUserOnboardingData = () => {
return parsed.success ? parsed.data[userOnboardingDataKey] : {};
}, [data]);
const isBusinessPlan = useMemo(() => {
return isCloud && userOnboardingData.questionnaire?.project === Project.Company;
}, [userOnboardingData]);
const update = useCallback(
async (data: Partial<UserOnboardingData>) => {
await updateMeCustomData({
@ -29,7 +34,7 @@ const useUserOnboardingData = () => {
[updateMeCustomData, userOnboardingData]
);
return { data: userOnboardingData, error, isLoading, isLoaded, update };
return { data: userOnboardingData, error, isLoading, isLoaded, isBusinessPlan, update };
};
export default useUserOnboardingData;

View file

@ -15,7 +15,7 @@ import * as pageLayout from '@/onboarding/scss/layout.module.scss';
import ActionBar from '../../components/ActionBar';
import { CardSelector, MultiCardSelector } from '../../components/CardSelector';
import type { Questionnaire } from '../../types';
import { Project, OnboardingPage } from '../../types';
import { OnboardingPage } from '../../types';
import { getOnboardingPage } from '../../utils';
import * as styles from './index.module.scss';
import { titleOptions, companySizeOptions, reasonOptions } from './options';
@ -26,11 +26,10 @@ const About = () => {
const {
data: { questionnaire },
isBusinessPlan,
update,
} = useUserOnboardingData();
const isCompanyProject = questionnaire?.project === Project.Company;
const { control, register, handleSubmit, reset } = useForm<Questionnaire>({
mode: 'onChange',
});
@ -60,7 +59,7 @@ const About = () => {
<div className={styles.title}>{t('cloud.about.title')}</div>
<div className={styles.description}>{t('cloud.about.description')}</div>
<form className={styles.form}>
{isCompanyProject && (
{isBusinessPlan && (
<>
<FormField
isMultiple

View file

@ -7,22 +7,25 @@ import CheckPreviewDark from '@/assets/images/check-demo-dark.svg';
import CheckPreview from '@/assets/images/check-demo.svg';
import CreateAppDark from '@/assets/images/create-app-dark.svg';
import CreateApp from '@/assets/images/create-app.svg';
import CreateRoleDark from '@/assets/images/create-role-dark.svg';
import CreateRole from '@/assets/images/create-role.svg';
import CustomizeDark from '@/assets/images/customize-dark.svg';
import Customize from '@/assets/images/customize.svg';
import DiscordDark from '@/assets/images/discord-dark.svg';
import Discord from '@/assets/images/discord.svg';
import GithubDark from '@/assets/images/github-dark.svg';
import Github from '@/assets/images/github.svg';
import FurtherReadingsDark from '@/assets/images/further-readings-dark.svg';
import FurtherReadings from '@/assets/images/further-readings.svg';
import MachineToMachineDark from '@/assets/images/machine-to-machine-dark.svg';
import MachineToMachine from '@/assets/images/machine-to-machine.svg';
import PasswordlessDark from '@/assets/images/passwordless-dark.svg';
import Passwordless from '@/assets/images/passwordless.svg';
import { discordLink, githubLink } from '@/consts';
import { isCloud } from '@/consts/cloud';
import { discordLink } from '@/consts';
import { ConnectorsTabs } from '@/consts/page-tabs';
import { AppEndpointsContext } from '@/contexts/AppEndpointsProvider';
import useConfigs from '@/hooks/use-configs';
import useDocumentationUrl from '@/hooks/use-documentation-url';
import useTheme from '@/hooks/use-theme';
import useUserOnboardingData from '@/onboarding/hooks/use-user-onboarding-data';
type GetStartedMetadata = {
id: string;
@ -41,9 +44,11 @@ const useGetStartedMetadata = () => {
const theme = useTheme();
const isLightMode = theme === Theme.Light;
const navigate = useNavigate();
const { isBusinessPlan } = useUserOnboardingData();
const { getDocumentationUrl } = useDocumentationUrl();
const data = useMemo(() => {
const metadataItems: GetStartedMetadata[] = [
const basicMetadata: GetStartedMetadata[] = useMemo(
() => [
{
id: 'checkLivePreview',
title: 'get_started.check_preview_title',
@ -89,30 +94,21 @@ const useGetStartedMetadata = () => {
navigate('/sign-in-experience');
},
},
isCloud
? {
id: 'interactWithManagementAPI',
title: 'get_started.management_api_title',
subtitle: 'get_started.management_api_subtitle',
icon: isLightMode ? MachineToMachine : MachineToMachineDark,
buttonText: 'general.create',
isComplete: configs?.m2mApplicationCreated,
onClick: () => {
navigate('/applications/create');
},
}
: {
id: 'checkOutSelfHostingOptions',
title: 'get_started.self_hosting_title',
subtitle: 'get_started.self_hosting_subtitle',
icon: isLightMode ? Github : GithubDark,
buttonText: 'general.visit',
isComplete: configs?.selfHostingChecked,
onClick: () => {
void updateConfigs({ selfHostingChecked: true });
window.open(githubLink, '_blank');
},
},
],
[
configs?.applicationCreated,
configs?.livePreviewChecked,
configs?.passwordlessConfigured,
configs?.signInExperienceCustomized,
isLightMode,
navigate,
updateConfigs,
userEndpoint,
]
);
const personalPlanMetadata: GetStartedMetadata[] = useMemo(
() => [
{
id: 'joinCommunity',
title: 'get_started.community_title',
@ -125,22 +121,67 @@ const useGetStartedMetadata = () => {
window.open(discordLink, '_blank');
},
},
{
id: 'checkOutFurtherReadings',
title: 'get_started.further_readings_title',
subtitle: 'get_started.further_readings_subtitle',
icon: isLightMode ? FurtherReadings : FurtherReadingsDark,
buttonText: 'general.check_out',
isComplete: configs?.furtherReadingsChecked,
onClick: () => {
void updateConfigs({ furtherReadingsChecked: true });
window.open(
getDocumentationUrl('/docs/tutorials/get-started/further-readings'),
'_blank'
);
},
},
],
[
configs?.communityChecked,
configs?.furtherReadingsChecked,
getDocumentationUrl,
isLightMode,
updateConfigs,
]
);
const businessPlanMetadata: GetStartedMetadata[] = useMemo(
() => [
{
id: 'interactWithManagementAPI',
title: 'get_started.management_api_title',
subtitle: 'get_started.management_api_subtitle',
icon: isLightMode ? MachineToMachine : MachineToMachineDark,
buttonText: 'general.create',
isComplete: configs?.m2mApplicationCreated,
onClick: () => {
navigate('/applications/create');
},
},
{
id: 'addRbac',
title: 'get_started.add_rbac_title',
subtitle: 'get_started.add_rbac_subtitle',
icon: isLightMode ? CreateRole : CreateRoleDark,
buttonText: 'general.create',
isComplete: configs?.roleCreated,
onClick: () => {
navigate('/roles/create');
},
},
],
[configs?.m2mApplicationCreated, configs?.roleCreated, isLightMode, navigate]
);
const data = useMemo(() => {
const metadataItems: GetStartedMetadata[] = [
...basicMetadata,
...(isBusinessPlan ? businessPlanMetadata : personalPlanMetadata),
];
return metadataItems.filter(({ isHidden }) => !isHidden);
}, [
isLightMode,
configs?.livePreviewChecked,
configs?.applicationCreated,
configs?.passwordlessConfigured,
configs?.signInExperienceCustomized,
configs?.m2mApplicationCreated,
configs?.selfHostingChecked,
configs?.communityChecked,
updateConfigs,
userEndpoint,
navigate,
]);
}, [basicMetadata, isBusinessPlan, businessPlanMetadata, personalPlanMetadata]);
return {
data,

View file

@ -10,6 +10,7 @@ import ModalLayout from '@/components/ModalLayout';
import RoleScopesTransfer from '@/components/RoleScopesTransfer';
import TextInput from '@/components/TextInput';
import useApi from '@/hooks/use-api';
import useConfigs from '@/hooks/use-configs';
export type Props = {
onClose: (createdRole?: Role) => void;
@ -33,6 +34,7 @@ const CreateRoleForm = ({ onClose }: Props) => {
} = useForm<CreateRoleFormData>();
const api = useApi();
const { updateConfigs } = useConfigs();
const onSubmit = handleSubmit(async ({ name, description, scopes }) => {
if (isSubmitting) {
@ -46,6 +48,7 @@ const CreateRoleForm = ({ onClose }: Props) => {
};
const createdRole = await api.post('api/roles', { json: payload }).json<Role>();
await updateConfigs({ roleCreated: true });
onClose(createdRole);
});

View file

@ -85,7 +85,8 @@ export const mockAdminConsoleData: AdminConsoleData = {
applicationCreated: false,
signInExperienceCustomized: false,
passwordlessConfigured: false,
selfHostingChecked: false,
furtherReadingsChecked: false,
roleCreated: false,
communityChecked: false,
m2mApplicationCreated: false,
};

View file

@ -18,14 +18,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors', // UNTRANSLATED
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer', // UNTRANSLATED
self_hosting_title: 'Check Github for self-hosting options', // UNTRANSLATED
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes', // UNTRANSLATED
community_title: 'Join our discord community', // UNTRANSLATED
community_subtitle: 'Join our public channel to chat with other developers', // UNTRANSLATED
management_api_title: 'Interact with Management API', // UNTRANSLATED
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup', // UNTRANSLATED
further_readings_title: 'Further readings', // UNTRANSLATED
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts', // UNTRANSLATED
add_rbac_title: 'Add role-based access control to protect your resources', // UNTRANSLATED
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.', // UNTRANSLATED
};
export default get_started;

View file

@ -16,14 +16,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors',
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer',
self_hosting_title: 'Check Github for self-hosting options',
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes',
community_title: 'Join our discord community',
community_subtitle: 'Join our public channel to chat with other developers',
management_api_title: 'Interact with Management API',
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup',
further_readings_title: 'Further readings',
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts',
add_rbac_title: 'Add role-based access control to protect your resources',
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.',
};
export default get_started;

View file

@ -19,14 +19,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors', // UNTRANSLATED
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer', // UNTRANSLATED
self_hosting_title: 'Check Github for self-hosting options', // UNTRANSLATED
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes', // UNTRANSLATED
community_title: 'Join our discord community', // UNTRANSLATED
community_subtitle: 'Join our public channel to chat with other developers', // UNTRANSLATED
management_api_title: 'Interact with Management API', // UNTRANSLATED
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup', // UNTRANSLATED
further_readings_title: 'Further readings', // UNTRANSLATED
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts', // UNTRANSLATED
add_rbac_title: 'Add role-based access control to protect your resources', // UNTRANSLATED
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.', // UNTRANSLATED
};
export default get_started;

View file

@ -16,14 +16,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors', // UNTRANSLATED
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer', // UNTRANSLATED
self_hosting_title: 'Check Github for self-hosting options', // UNTRANSLATED
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes', // UNTRANSLATED
community_title: 'Join our discord community', // UNTRANSLATED
community_subtitle: 'Join our public channel to chat with other developers', // UNTRANSLATED
management_api_title: 'Interact with Management API', // UNTRANSLATED
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup', // UNTRANSLATED
further_readings_title: 'Further readings', // UNTRANSLATED
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts', // UNTRANSLATED
add_rbac_title: 'Add role-based access control to protect your resources', // UNTRANSLATED
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.', // UNTRANSLATED
};
export default get_started;

View file

@ -17,14 +17,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors', // UNTRANSLATED
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer', // UNTRANSLATED
self_hosting_title: 'Check Github for self-hosting options', // UNTRANSLATED
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes', // UNTRANSLATED
community_title: 'Join our discord community', // UNTRANSLATED
community_subtitle: 'Join our public channel to chat with other developers', // UNTRANSLATED
management_api_title: 'Interact with Management API', // UNTRANSLATED
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup', // UNTRANSLATED
further_readings_title: 'Further readings', // UNTRANSLATED
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts', // UNTRANSLATED
add_rbac_title: 'Add role-based access control to protect your resources', // UNTRANSLATED
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.', // UNTRANSLATED
};
export default get_started;

View file

@ -17,14 +17,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors', // UNTRANSLATED
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer', // UNTRANSLATED
self_hosting_title: 'Check Github for self-hosting options', // UNTRANSLATED
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes', // UNTRANSLATED
community_title: 'Join our discord community', // UNTRANSLATED
community_subtitle: 'Join our public channel to chat with other developers', // UNTRANSLATED
management_api_title: 'Interact with Management API', // UNTRANSLATED
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup', // UNTRANSLATED
further_readings_title: 'Further readings', // UNTRANSLATED
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts', // UNTRANSLATED
add_rbac_title: 'Add role-based access control to protect your resources', // UNTRANSLATED
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.', // UNTRANSLATED
};
export default get_started;

View file

@ -17,14 +17,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors', // UNTRANSLATED
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer', // UNTRANSLATED
self_hosting_title: 'Check Github for self-hosting options', // UNTRANSLATED
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes', // UNTRANSLATED
community_title: 'Join our discord community', // UNTRANSLATED
community_subtitle: 'Join our public channel to chat with other developers', // UNTRANSLATED
management_api_title: 'Interact with Management API', // UNTRANSLATED
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup', // UNTRANSLATED
further_readings_title: 'Further readings', // UNTRANSLATED
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts', // UNTRANSLATED
add_rbac_title: 'Add role-based access control to protect your resources', // UNTRANSLATED
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.', // UNTRANSLATED
};
export default get_started;

View file

@ -16,14 +16,17 @@ const get_started = {
passwordless_title: 'Scale passwordless sign in by adding your own connectors', // UNTRANSLATED
passwordless_subtitle:
'Try passwordless sign in and enable a secure and frictionless experience for your customer', // UNTRANSLATED
self_hosting_title: 'Check Github for self-hosting options', // UNTRANSLATED
self_hosting_subtitle:
'Efficiently deploy by visiting the Github homepage in a matter of minutes', // UNTRANSLATED
community_title: 'Join our discord community', // UNTRANSLATED
community_subtitle: 'Join our public channel to chat with other developers', // UNTRANSLATED
management_api_title: 'Interact with Management API', // UNTRANSLATED
management_api_subtitle:
'Build a machine to machine app for API access and your product tech infrastructure setup', // UNTRANSLATED
further_readings_title: 'Further readings', // UNTRANSLATED
further_readings_subtitle:
'Check out our step-by-step, scenario-based docs without tedious concepts', // UNTRANSLATED
add_rbac_title: 'Add role-based access control to protect your resources', // UNTRANSLATED
add_rbac_subtitle:
'Control your resource through scalable role authorization for diverse use cases.', // UNTRANSLATED
};
export default get_started;

View file

@ -0,0 +1,102 @@
import type { DatabaseTransactionConnection } from 'slonik';
import { sql } from 'slonik';
import type { AlterationScript } from '../lib/types/alteration.js';
const adminConsoleConfigKey = 'adminConsole';
type OldAdminConsoleData = {
livePreviewChecked: boolean;
applicationCreated: boolean;
signInExperienceCustomized: boolean;
passwordlessConfigured: boolean;
selfHostingChecked: boolean;
communityChecked: boolean;
m2mApplicationCreated: boolean;
} & Record<string, unknown>;
type OldLogtoAdminConsoleConfig = {
tenantId: string;
value: OldAdminConsoleData;
};
type NewAdminConsoleData = {
livePreviewChecked: boolean;
applicationCreated: boolean;
signInExperienceCustomized: boolean;
passwordlessConfigured: boolean;
furtherReadingsChecked: boolean;
roleCreated: boolean;
communityChecked: boolean;
m2mApplicationCreated: boolean;
} & Record<string, unknown>;
type NewLogtoAdminConsoleConfig = {
tenantId: string;
value: NewAdminConsoleData;
};
const alterAdminConsoleData = async (
logtoConfig: OldLogtoAdminConsoleConfig,
pool: DatabaseTransactionConnection
) => {
const { tenantId, value: oldAdminConsoleConfig } = logtoConfig;
const {
selfHostingChecked, // Extract to remove from config
...others
} = oldAdminConsoleConfig;
const newAdminConsoleData: NewAdminConsoleData = {
...others,
furtherReadingsChecked: false,
roleCreated: 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 {
furtherReadingsChecked, // Extract to remove from config
roleCreated, // Extract to remove from config
...others
} = newAdminConsoleConfig;
const oldAdminConsoleData: OldAdminConsoleData = {
...others,
selfHostingChecked: false,
};
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<OldLogtoAdminConsoleConfig>(
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<NewLogtoAdminConsoleConfig>(
sql`select * from logto_configs where key = ${adminConsoleConfigKey}`
);
await Promise.all(rows.map(async (row) => rollbackAdminConsoleData(row, pool)));
},
};
export default alteration;

View file

@ -17,7 +17,8 @@ export const createDefaultAdminConsoleConfig = (
applicationCreated: false,
signInExperienceCustomized: false,
passwordlessConfigured: false,
selfHostingChecked: false,
furtherReadingsChecked: false,
roleCreated: false,
communityChecked: false,
m2mApplicationCreated: false,
},

View file

@ -26,8 +26,9 @@ export const adminConsoleDataGuard = z.object({
applicationCreated: z.boolean(),
signInExperienceCustomized: z.boolean(),
passwordlessConfigured: z.boolean(),
selfHostingChecked: z.boolean(),
communityChecked: z.boolean(),
furtherReadingsChecked: z.boolean(),
roleCreated: z.boolean(),
m2mApplicationCreated: z.boolean(),
});