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

feat(console,phrases): add organizations paywall (#4939)

This commit is contained in:
Charles Zhao 2023-11-22 14:40:01 +08:00 committed by GitHub
parent 0e334ecdb1
commit fbf6d89d9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 249 additions and 153 deletions

View file

@ -49,6 +49,6 @@
"access": "public"
},
"devDependencies": {
"@logto/cloud": "0.2.5-d434baa"
"@logto/cloud": "0.2.5-9257c0d"
}
}

View file

@ -26,7 +26,7 @@
"@fontsource/roboto-mono": "^5.0.0",
"@jest/types": "^29.5.0",
"@logto/app-insights": "workspace:^1.3.1",
"@logto/cloud": "0.2.5-d434baa",
"@logto/cloud": "0.2.5-9257c0d",
"@logto/connector-kit": "workspace:^2.0.0",
"@logto/core-kit": "workspace:^2.1.2",
"@logto/language-kit": "workspace:^1.0.0",

View file

@ -26,7 +26,7 @@ const featuredQuotaKeys: Array<keyof SubscriptionPlanQuota> = [
'scopesPerRoleLimit',
'mfaEnabled',
'ssoEnabled',
'organizationEnabled',
'organizationsEnabled',
'auditLogsRetentionDays',
];

View file

@ -77,12 +77,6 @@ export const ticketSupportResponseTimeMap: Record<string, number | undefined> =
[ReservedPlanId.Pro]: 48,
};
export const organizationEnabledMap: EnabledFeatureMap = {
[ReservedPlanId.Free]: false,
[ReservedPlanId.Hobby]: true,
[ReservedPlanId.Pro]: true,
};
export const ssoEnabledMap: EnabledFeatureMap = {
[ReservedPlanId.Free]: false,
[ReservedPlanId.Hobby]: true,
@ -123,7 +117,7 @@ const enterprisePlanTable: SubscriptionPlanTable = {
hooksLimit: undefined,
communitySupportEnabled: true,
ticketSupportResponseTime: undefined,
organizationEnabled: true,
organizationsEnabled: true,
ssoEnabled: true,
};
@ -163,7 +157,7 @@ export const planTableGroupKeyMap: SubscriptionPlanTableGroupKeyMap = Object.fre
'rolesLimit',
'scopesPerRoleLimit',
],
[SubscriptionPlanTableGroupKey.organization]: ['organizationEnabled'],
[SubscriptionPlanTableGroupKey.organizations]: ['organizationsEnabled'],
[SubscriptionPlanTableGroupKey.auditLogs]: ['auditLogsRetentionDays'],
[SubscriptionPlanTableGroupKey.hooks]: ['hooksLimit'],
[SubscriptionPlanTableGroupKey.support]: ['communitySupportEnabled', 'ticketSupportResponseTime'],

View file

@ -22,7 +22,7 @@ export const quotaItemPhrasesMap: Record<
communitySupportEnabled: 'community_support_enabled.name',
ticketSupportResponseTime: 'customer_ticket_support.name',
mfaEnabled: 'mfa_enabled.name',
organizationEnabled: 'organization_enabled.name',
organizationsEnabled: 'organizations_enabled.name',
ssoEnabled: 'sso_enabled.name',
};
@ -46,7 +46,7 @@ export const quotaItemUnlimitedPhrasesMap: Record<
communitySupportEnabled: 'community_support_enabled.unlimited',
ticketSupportResponseTime: 'customer_ticket_support.unlimited',
mfaEnabled: 'mfa_enabled.unlimited',
organizationEnabled: 'organization_enabled.unlimited',
organizationsEnabled: 'organizations_enabled.unlimited',
ssoEnabled: 'sso_enabled.unlimited',
};
@ -70,7 +70,7 @@ export const quotaItemLimitedPhrasesMap: Record<
communitySupportEnabled: 'community_support_enabled.limited',
ticketSupportResponseTime: 'customer_ticket_support.limited',
mfaEnabled: 'mfa_enabled.limited',
organizationEnabled: 'organization_enabled.limited',
organizationsEnabled: 'organizations_enabled.limited',
ssoEnabled: 'sso_enabled.limited',
};
@ -94,6 +94,6 @@ export const quotaItemNotEligiblePhrasesMap: Record<
communitySupportEnabled: 'community_support_enabled.not_eligible',
ticketSupportResponseTime: 'customer_ticket_support.not_eligible',
mfaEnabled: 'mfa_enabled.not_eligible',
organizationEnabled: 'organization_enabled.not_eligible',
organizationsEnabled: 'organizations_enabled.not_eligible',
ssoEnabled: 'sso_enabled.not_eligible',
};

View file

@ -4,17 +4,18 @@ import { useTranslation } from 'react-i18next';
import Plus from '@/assets/icons/plus.svg';
import OrganizationEmptyDark from '@/assets/images/organization-empty-dark.svg';
import OrganizationEmpty from '@/assets/images/organization-empty.svg';
import Button from '@/ds-components/Button';
import Button, { type Props as ButtonProps } from '@/ds-components/Button';
import useConfigs from '@/hooks/use-configs';
import useTheme from '@/hooks/use-theme';
import * as styles from './index.module.scss';
type Props = {
onCreate: () => void;
/** Override the default button properties in the placeholder */
buttonProps?: ButtonProps;
};
function EmptyDataPlaceholder({ onCreate }: Props) {
function EmptyDataPlaceholder({ buttonProps }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.organizations' });
const { configs } = useConfigs();
const theme = useTheme();
@ -34,7 +35,7 @@ function EmptyDataPlaceholder({ onCreate }: Props) {
title={
isInitialSetup ? 'organizations.setup_organization' : 'organizations.create_organization'
}
onClick={onCreate}
{...buttonProps}
/>
</div>
);

View file

@ -51,7 +51,11 @@ function OrganizationsTable({ isLoading, onCreate }: Props) {
<Table
className={pageLayout.table}
isLoading={isTableLoading}
placeholder={<EmptyDataPlaceholder onCreate={onCreate} />}
placeholder={
<EmptyDataPlaceholder
buttonProps={{ title: 'organizations.create_organization', onClick: onCreate }}
/>
}
rowGroups={[{ key: 'data', data }]}
rowClickHandler={({ id }) => {
navigate(joinPath(pathname, id));

View file

@ -1,14 +1,18 @@
import { joinPath } from '@silverhand/essentials';
import { useCallback, useState } from 'react';
import { ReservedPlanId } from '@logto/schemas';
import { cond, conditional, joinPath } from '@silverhand/essentials';
import { useCallback, useContext, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Plus from '@/assets/icons/plus.svg';
import PageMeta from '@/components/PageMeta';
import { subscriptionPage } from '@/consts/pages';
import { TenantsContext } from '@/contexts/TenantsProvider';
import Button from '@/ds-components/Button';
import Card from '@/ds-components/Card';
import CardTitle from '@/ds-components/CardTitle';
import TabNav, { TabNavItem } from '@/ds-components/TabNav';
import useConfigs from '@/hooks/use-configs';
import useSubscriptionPlan from '@/hooks/use-subscription-plan';
import useTenantPathname from '@/hooks/use-tenant-pathname';
import * as pageLayout from '@/scss/page-layout.module.scss';
@ -29,10 +33,18 @@ type Props = {
function Organizations({ tab }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const { currentTenantId, isDevTenant } = useContext(TenantsContext);
const { data: currentPlan } = useSubscriptionPlan(currentTenantId);
const { navigate } = useTenantPathname();
const [isCreating, setIsCreating] = useState(false);
const { configs, isLoading: isLoadingConfigs } = useConfigs();
const isInitialSetup = !isLoadingConfigs && !configs?.organizationCreated;
const isOrganizationsDisabled = currentPlan?.id === ReservedPlanId.Free;
const upgradePlan = useCallback(() => {
navigate(subscriptionPage);
}, [navigate]);
const handleCreate = useCallback(() => {
if (isInitialSetup) {
@ -56,7 +68,12 @@ function Organizations({ tab }: Props) {
/>
<PageMeta titleKey="organizations.page_title" />
<div className={pageLayout.headline}>
<CardTitle title="organizations.title" subtitle="organizations.subtitle" />
<CardTitle
isBeta
paywall={cond((isOrganizationsDisabled || isDevTenant) && ReservedPlanId.Hobby)}
title="organizations.title"
subtitle="organizations.subtitle"
/>
{!isInitialSetup && (
<Button
icon={<Plus />}
@ -69,7 +86,15 @@ function Organizations({ tab }: Props) {
</div>
{isInitialSetup && (
<Card className={styles.emptyCardContainer}>
<EmptyDataPlaceholder onCreate={handleCreate} />
<EmptyDataPlaceholder
buttonProps={{
title: isOrganizationsDisabled
? 'upsell.upgrade_plan'
: 'organizations.setup_organization',
onClick: isOrganizationsDisabled ? upgradePlan : handleCreate,
...conditional(isOrganizationsDisabled && { icon: undefined }),
}}
/>
</Card>
)}
{!isInitialSetup && (

View file

@ -16,7 +16,7 @@ const planQuotaGroupKeyPhraseMap: {
[SubscriptionPlanTableGroupKey.userAuthentication]: 'user_authn.title',
[SubscriptionPlanTableGroupKey.roles]: 'user_management.title',
[SubscriptionPlanTableGroupKey.hooks]: 'hooks.title',
[SubscriptionPlanTableGroupKey.organization]: 'organization.title',
[SubscriptionPlanTableGroupKey.organizations]: 'organizations.title',
[SubscriptionPlanTableGroupKey.auditLogs]: 'audit_logs.title',
[SubscriptionPlanTableGroupKey.support]: 'support.title',
};

View file

@ -37,7 +37,7 @@ const planQuotaKeyPhraseMap: {
auditLogsRetentionDays: 'audit_logs.retention',
communitySupportEnabled: 'support.community',
ticketSupportResponseTime: 'support.customer_ticket',
organizationEnabled: 'organization.organization',
organizationsEnabled: 'organizations.organizations',
};
type Props = {

View file

@ -16,8 +16,6 @@ export type SubscriptionPlanQuota = Omit<
// Support
communitySupportEnabled: boolean;
ticketSupportResponseTime: number;
// Organization
organizationEnabled: boolean;
// SSO
ssoEnabled: boolean;
};
@ -63,7 +61,7 @@ export enum SubscriptionPlanTableGroupKey {
roles = 'roles',
auditLogs = 'auditLogs',
hooks = 'hooks',
organization = 'organization',
organizations = 'organizations',
support = 'support',
}

View file

@ -6,7 +6,6 @@ import { tryReadResponseErrorBody } from '@/cloud/hooks/use-cloud-api';
import { type SubscriptionPlanResponse } from '@/cloud/types/router';
import {
communitySupportEnabledMap,
organizationEnabledMap,
ssoEnabledMap,
ticketSupportResponseTimeMap,
} from '@/consts/plan-quotas';
@ -22,7 +21,6 @@ export const addSupportQuotaToPlan = (subscriptionPlanResponse: SubscriptionPlan
...quota,
communitySupportEnabled: communitySupportEnabledMap[id] ?? false, // Fallback to not supported
ticketSupportResponseTime: ticketSupportResponseTimeMap[id] ?? 0, // Fallback to not supported
organizationEnabled: organizationEnabledMap[id] ?? false, // Fallback to not supported
ssoEnabled: ssoEnabledMap[id] ?? false, // Fallback to not supported
},
};

View file

@ -91,7 +91,7 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@logto/cloud": "0.2.5-d434baa",
"@logto/cloud": "0.2.5-9257c0d",
"@silverhand/eslint-config": "4.0.1",
"@silverhand/ts-config": "4.0.0",
"@types/debug": "^4.1.7",

View file

@ -70,6 +70,7 @@ export const createQuotaLibrary = (
},
customDomainEnabled: notNumber,
mfaEnabled: notNumber,
organizationsEnabled: notNumber,
omniSignInEnabled: notNumber, // No limit for now
builtInEmailConnectorEnabled: notNumber, // No limit for now
};

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Unbegrenzte Webhooks',
not_eligible: 'Entferne deine Webhooks',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
not_eligible: 'Entferne deine Organisationen',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Audit-Log-Retention',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: 'Organisation',
organization: 'Organisation',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Support',

View file

@ -1,5 +1,5 @@
const organization = {
const organizations = {
require_membership: 'The user must be a member of the organization to proceed.',
};
export default Object.freeze(organization);
export default Object.freeze(organizations);

View file

@ -1,4 +1,4 @@
const organization = {
const organizations = {
organization: 'Organization',
page_title: 'Organizations',
title: 'Organizations',
@ -89,4 +89,4 @@ const organization = {
},
};
export default Object.freeze(organization);
export default Object.freeze(organizations);

View file

@ -93,10 +93,10 @@ const quota_item = {
unlimited: 'Unlimited webhooks',
not_eligible: 'Remove your webhooks',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
organizations_enabled: {
name: 'Organizations',
limited: 'Organizations',
unlimited: 'Organizations',
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {

View file

@ -51,9 +51,9 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
title: 'Organization',
organization: 'Organization',
organizations: {
title: 'Organizations',
organizations: 'Organizations',
},
support: {
title: 'Support',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Webhooks ilimitados',
not_eligible: 'Elimina tus webhooks',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
not_eligible: 'Elimine su organización',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Conservación de registros de auditoría',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: 'Organización',
organization: 'Organización',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Soporte',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Webhooks illimités',
not_eligible: 'Supprimez vos webhooks',
},
organization_enabled: {
name: 'Organisation',
limited: 'Organisation',
unlimited: 'Organisation',
not_eligible: 'Supprimez vos organisations',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: "Conservation des journaux d'audit",

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: 'Organisation',
organization: 'Organisation',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Support',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Webhook illimitati',
not_eligible: 'Rimuovi i tuoi webhook',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
not_eligible: 'Rimuovi il tuo organisations',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Conservazione log di audit',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: 'Organizzazione',
organization: 'Organizzazione',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Assistenza',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: '無制限のWebhooks',
not_eligible: 'Webhookを削除してください',
},
organization_enabled: {
name: '組織',
limited: '組織',
unlimited: '組織',
not_eligible: '組織を削除してください',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: '監査ログの保持期間',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'ウェブフック',
hooks: 'ウェブフック',
},
organization: {
organizations: {
title: '組織',
organization: '組織',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'サポート',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: '무제한 Webhooks',
not_eligible: '웹훅을 삭제하세요',
},
organization_enabled: {
name: '조직',
limited: '조직',
unlimited: '조직',
not_eligible: '조직을 제거하십시오',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: '감사 로그 보존 기간',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: '조직',
organization: '조직',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: '지원',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Nieograniczona liczba webhooków',
not_eligible: 'Usuń swoje webhooki',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
not_eligible: 'Usuń swoje organizacje',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Przechowywanie dzienników audytowych',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooki',
hooks: 'Webhooki',
},
organization: {
organizations: {
title: 'Organizacja',
organization: 'Organizacja',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Wsparcie',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Webhooks ilimitados',
not_eligible: 'Remova seus webhooks',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
not_eligible: 'Remova suas organizações',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Permanência de registros de auditoria',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: 'Organização',
organization: 'Organização',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Suporte',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Webhooks ilimitados',
not_eligible: 'Remova os seus webhooks',
},
organization_enabled: {
name: 'Organização',
limited: 'Organização',
unlimited: 'Organização',
not_eligible: 'Remover as tuas organizações',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Conservação de registos de auditoria',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Hooks',
hooks: 'Hooks',
},
organization: {
organizations: {
title: 'Organização',
organization: 'Organização',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Suporte',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Неограниченное количество вебхуков',
not_eligible: 'Удалите ваши вебхуки',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
not_eligible: 'Удалите свои организации',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Время хранения аудит-логов',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Вебхуки',
hooks: 'Вебхуки',
},
organization: {
organizations: {
title: 'Организация',
organization: 'Организация',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Поддержка',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: 'Sınırsız webhooklar',
not_eligible: 'Webhooklarınızı kaldırın',
},
organization_enabled: {
name: 'Organization',
limited: 'Organization',
unlimited: 'Organization',
not_eligible: 'Organizasyonlarınızı kaldırın',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: 'Denetim günlükleri saklama süresi',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Web Kancaları',
hooks: 'Web Kancaları',
},
organization: {
organizations: {
title: 'Organizasyon',
organization: 'Organization',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: 'Destek',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: '无限制的 Webhooks',
not_eligible: '移除你的 Webhooks',
},
organization_enabled: {
name: '组织',
limited: '组织',
unlimited: '组织',
not_eligible: '移除你的组织',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: '审计日志保留',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: '组织',
organization: '组织',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: '支持',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: '無限制的 Webhooks',
not_eligible: '移除您的 Webhooks',
},
organization_enabled: {
name: '組織',
limited: '組織',
unlimited: '組織',
not_eligible: '刪除您的組織',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: '審計日誌保留',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: '組織',
organization: '組織',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: '支援',

View file

@ -93,11 +93,15 @@ const quota_item = {
unlimited: '無限制的 Webhooks',
not_eligible: '移除您的 Webhooks',
},
organization_enabled: {
name: '組織',
limited: '組織',
unlimited: '組織',
not_eligible: '移除您的組織',
organizations_enabled: {
/** UNTRANSLATED */
name: 'Organizations',
/** UNTRANSLATED */
limited: 'Organizations',
/** UNTRANSLATED */
unlimited: 'Organizations',
/** UNTRANSLATED */
not_eligible: 'Remove your organizations',
},
audit_logs_retention_days: {
name: '審計記錄保留期限',

View file

@ -51,9 +51,10 @@ const quota_table = {
title: 'Webhooks',
hooks: 'Webhooks',
},
organization: {
organizations: {
title: '組織',
organization: '組織',
/** UNTRANSLATED */
organizations: 'Organizations',
},
support: {
title: '支援',

View file

@ -1322,8 +1322,8 @@ importers:
specifier: ^29.5.0
version: 29.5.0
'@logto/cloud':
specifier: 0.2.5-d434baa
version: 0.2.5-d434baa(zod@3.22.4)
specifier: 0.2.5-9257c0d
version: 0.2.5-9257c0d(zod@3.22.4)
'@rollup/plugin-commonjs':
specifier: ^25.0.0
version: 25.0.7(rollup@4.1.4)
@ -2840,8 +2840,8 @@ importers:
specifier: workspace:^1.3.1
version: link:../app-insights
'@logto/cloud':
specifier: 0.2.5-d434baa
version: 0.2.5-d434baa(zod@3.22.4)
specifier: 0.2.5-9257c0d
version: 0.2.5-9257c0d(zod@3.22.4)
'@logto/connector-kit':
specifier: workspace:^2.0.0
version: link:../toolkit/connector-kit
@ -3318,8 +3318,8 @@ importers:
version: 3.22.4
devDependencies:
'@logto/cloud':
specifier: 0.2.5-d434baa
version: 0.2.5-d434baa(zod@3.22.4)
specifier: 0.2.5-9257c0d
version: 0.2.5-9257c0d(zod@3.22.4)
'@silverhand/eslint-config':
specifier: 4.0.1
version: 4.0.1(eslint@8.44.0)(prettier@3.0.0)(typescript@5.0.2)
@ -7505,7 +7505,7 @@ packages:
resolution: {integrity: sha512-7I2ELo5UWIJsFCYK/gX465l0+QhXTdyYWkgb2CcdPu5KbaPBNpASedm+fEV2NREYe2svbNODFhog6UMA/xGQnQ==}
dependencies:
'@logto/js': 2.1.1
'@silverhand/essentials': 2.8.4
'@silverhand/essentials': 2.8.5
camelcase-keys: 7.0.2
jose: 4.14.4
dev: true
@ -7514,16 +7514,16 @@ packages:
resolution: {integrity: sha512-xq4LhQ6ItbukAHgsMDcgfspTpdpO5sSfSEugpOrGP/nLwzGTfBO78OSUfMdBQEDr5+3SRmONuSjUBBwssOLINA==}
dependencies:
'@logto/js': 2.1.3
'@silverhand/essentials': 2.8.4
'@silverhand/essentials': 2.8.5
camelcase-keys: 7.0.2
jose: 4.14.4
dev: true
/@logto/cloud@0.2.5-d434baa(zod@3.22.4):
resolution: {integrity: sha512-VmWpqFzpWBrzJPQLvfe0bb7/XjF3lxs/rPbLt3zqBjGPtDXM9FAUn1m/gPbTwzXi5PxGOjlbD7jTl+3+1u4/NQ==}
/@logto/cloud@0.2.5-9257c0d(zod@3.22.4):
resolution: {integrity: sha512-tACUnAH8eRVS/InlIFIP50IcQzjlqCCPPa2Oqs4NNe1EkVMW7uplNZDPa1cTqT3fk223OvU9/9f0ydK9gwNZPQ==}
engines: {node: ^18.12.0}
dependencies:
'@silverhand/essentials': 2.8.4
'@silverhand/essentials': 2.8.5
'@withtyped/server': 0.12.9(zod@3.22.4)
transitivePeerDependencies:
- zod
@ -7540,7 +7540,7 @@ packages:
/@logto/js@2.1.3:
resolution: {integrity: sha512-TOuoC5gHx/SfY5gcGSBfw63x5TpM6Lm/9J5y0Jy003Z1DZARUlpz0KbzyCVAIC/+6qIefkmNPHKl1rq9MB/hog==}
dependencies:
'@silverhand/essentials': 2.8.4
'@silverhand/essentials': 2.8.5
camelcase-keys: 7.0.2
jose: 4.14.4
dev: true
@ -9241,6 +9241,11 @@ packages:
resolution: {integrity: sha512-VaI00QyD2trA7n7/wHNcGNGRXoSr8dUGs/hQCu4Rju4Edl3vso7CeCXdfGU2aNDuT2uMs75of6Ph8gqVJhWlYQ==}
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^8.0.0}
/@silverhand/essentials@2.8.5:
resolution: {integrity: sha512-ChOGm1NeETWkEZXkIDD123cf8gxphqeSbtnvgsiqKMmWH2oSMvqORAyVFdngl0MuL9Ef5EdLFII+JrJkdytHrQ==}
engines: {node: ^16.13.0 || ^18.12.0 || ^19.2.0, pnpm: ^8.0.0}
dev: true
/@silverhand/ts-config-react@4.0.0(typescript@5.0.2):
resolution: {integrity: sha512-IkZka1iuIBgw0AUbsknghw1vOIs4zOgUxR8jL38Kuk63hmSj687N4BWBb8KhVMhqaG4U/DYkbSEZuwsyHBe68g==}
engines: {node: ^18.12.0}