feat(core): add an entry for admin panel (#10813)

This commit is contained in:
@@ -14,7 +14,7 @@ import {
|
|||||||
} from '@affine/core/modules/dialogs';
|
} from '@affine/core/modules/dialogs';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import { AccountIcon, SignOutIcon } from '@blocksuite/icons/rc';
|
import { AccountIcon, AdminIcon, SignOutIcon } from '@blocksuite/icons/rc';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
ServerService,
|
ServerService,
|
||||||
SubscriptionService,
|
SubscriptionService,
|
||||||
UserCopilotQuotaService,
|
UserCopilotQuotaService,
|
||||||
|
UserFeatureService,
|
||||||
UserQuotaService,
|
UserQuotaService,
|
||||||
} from '../../modules/cloud';
|
} from '../../modules/cloud';
|
||||||
import { UserPlanButton } from '../affine/auth/user-plan-button';
|
import { UserPlanButton } from '../affine/auth/user-plan-button';
|
||||||
@@ -80,6 +81,9 @@ const UnauthorizedUserInfo = () => {
|
|||||||
const AccountMenu = () => {
|
const AccountMenu = () => {
|
||||||
const workspaceDialogService = useService(WorkspaceDialogService);
|
const workspaceDialogService = useService(WorkspaceDialogService);
|
||||||
const openSignOutModal = useSignOut();
|
const openSignOutModal = useSignOut();
|
||||||
|
const serverService = useService(ServerService);
|
||||||
|
const userFeatureService = useService(UserFeatureService);
|
||||||
|
const isAdmin = useLiveData(userFeatureService.userFeature.isAdmin$);
|
||||||
|
|
||||||
const onOpenAccountSetting = useCallback(() => {
|
const onOpenAccountSetting = useCallback(() => {
|
||||||
track.$.navigationPanel.profileAndBadge.openSettings({ to: 'account' });
|
track.$.navigationPanel.profileAndBadge.openSettings({ to: 'account' });
|
||||||
@@ -88,8 +92,16 @@ const AccountMenu = () => {
|
|||||||
});
|
});
|
||||||
}, [workspaceDialogService]);
|
}, [workspaceDialogService]);
|
||||||
|
|
||||||
|
const onOpenAdminPanel = useCallback(() => {
|
||||||
|
window.open(`${serverService.server.baseUrl}/admin`, '_blank');
|
||||||
|
}, [serverService.server.baseUrl]);
|
||||||
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
userFeatureService.userFeature.revalidate();
|
||||||
|
}, [userFeatureService]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@@ -99,6 +111,15 @@ const AccountMenu = () => {
|
|||||||
>
|
>
|
||||||
{t['com.affine.workspace.cloud.account.settings']()}
|
{t['com.affine.workspace.cloud.account.settings']()}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
{isAdmin ? (
|
||||||
|
<MenuItem
|
||||||
|
prefixIcon={<AdminIcon />}
|
||||||
|
data-testid="workspace-modal-account-admin-option"
|
||||||
|
onClick={onOpenAdminPanel}
|
||||||
|
>
|
||||||
|
{t['com.affine.workspace.cloud.account.admin']()}
|
||||||
|
</MenuItem>
|
||||||
|
) : null}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
prefixIcon={<SignOutIcon />}
|
prefixIcon={<SignOutIcon />}
|
||||||
data-testid="workspace-modal-sign-out-option"
|
data-testid="workspace-modal-sign-out-option"
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ import type { UserFeatureStore } from '../stores/user-feature';
|
|||||||
export class UserFeature extends Entity {
|
export class UserFeature extends Entity {
|
||||||
// undefined means no user, null means loading
|
// undefined means no user, null means loading
|
||||||
features$ = new LiveData<FeatureType[] | null | undefined>(null);
|
features$ = new LiveData<FeatureType[] | null | undefined>(null);
|
||||||
|
|
||||||
|
isAdmin$ = this.features$.map(features =>
|
||||||
|
features === null ? null : features?.some(f => f === FeatureType.Admin)
|
||||||
|
);
|
||||||
|
|
||||||
isEarlyAccess$ = this.features$.map(features =>
|
isEarlyAccess$ = this.features$.map(features =>
|
||||||
features === null
|
features === null
|
||||||
? null
|
? null
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"it-IT": 99,
|
"it-IT": 99,
|
||||||
"it": 1,
|
"it": 1,
|
||||||
"ja": 99,
|
"ja": 99,
|
||||||
"ko": 63,
|
"ko": 62,
|
||||||
"pl": 99,
|
"pl": 99,
|
||||||
"pt-BR": 99,
|
"pt-BR": 99,
|
||||||
"ru": 99,
|
"ru": 99,
|
||||||
|
|||||||
@@ -5404,7 +5404,7 @@ export function useAFFiNEI18N(): {
|
|||||||
*/
|
*/
|
||||||
["com.affine.settings.workspace.experimental-features.enable-callout.description"](): string;
|
["com.affine.settings.workspace.experimental-features.enable-callout.description"](): string;
|
||||||
/**
|
/**
|
||||||
* Embed Iframe Block
|
* `Embed Iframe Block`
|
||||||
*/
|
*/
|
||||||
["com.affine.settings.workspace.experimental-features.enable-embed-iframe-block.name"](): string;
|
["com.affine.settings.workspace.experimental-features.enable-embed-iframe-block.name"](): string;
|
||||||
/**
|
/**
|
||||||
@@ -6465,6 +6465,10 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Account settings`
|
* `Account settings`
|
||||||
*/
|
*/
|
||||||
["com.affine.workspace.cloud.account.settings"](): string;
|
["com.affine.workspace.cloud.account.settings"](): string;
|
||||||
|
/**
|
||||||
|
* `Admin panel`
|
||||||
|
*/
|
||||||
|
["com.affine.workspace.cloud.account.admin"](): string;
|
||||||
/**
|
/**
|
||||||
* `Sign up/ Sign in`
|
* `Sign up/ Sign in`
|
||||||
*/
|
*/
|
||||||
@@ -6549,6 +6553,18 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Yesterday`
|
* `Yesterday`
|
||||||
*/
|
*/
|
||||||
["com.affine.yesterday"](): string;
|
["com.affine.yesterday"](): string;
|
||||||
|
/**
|
||||||
|
* `Inactive`
|
||||||
|
*/
|
||||||
|
["com.affine.inactive"](): string;
|
||||||
|
/**
|
||||||
|
* `Inactive member`
|
||||||
|
*/
|
||||||
|
["com.affine.inactive-member"](): string;
|
||||||
|
/**
|
||||||
|
* `Inactive workspace`
|
||||||
|
*/
|
||||||
|
["com.affine.inactive-workspace"](): string;
|
||||||
/**
|
/**
|
||||||
* `core`
|
* `core`
|
||||||
*/
|
*/
|
||||||
@@ -6992,12 +7008,9 @@ export function useAFFiNEI18N(): {
|
|||||||
*/
|
*/
|
||||||
["com.affine.notification.unsupported"](): string;
|
["com.affine.notification.unsupported"](): string;
|
||||||
/**
|
/**
|
||||||
* `{{username}} mentioned you in {{docTitle}}`
|
* `No new notifications`
|
||||||
*/
|
*/
|
||||||
["com.affine.notification.mention"](options: Readonly<{
|
["com.affine.notification.empty"](): string;
|
||||||
username: string;
|
|
||||||
docTitle: string;
|
|
||||||
}>): string;
|
|
||||||
/**
|
/**
|
||||||
* `Tips`
|
* `Tips`
|
||||||
*/
|
*/
|
||||||
@@ -7006,6 +7019,10 @@ export function useAFFiNEI18N(): {
|
|||||||
* `Template`
|
* `Template`
|
||||||
*/
|
*/
|
||||||
Template(): string;
|
Template(): string;
|
||||||
|
/**
|
||||||
|
* `Delete Template`
|
||||||
|
*/
|
||||||
|
["com.affine.template-list.delete"](): string;
|
||||||
/**
|
/**
|
||||||
* `No template`
|
* `No template`
|
||||||
*/
|
*/
|
||||||
@@ -7119,6 +7136,12 @@ export function useAFFiNEI18N(): {
|
|||||||
["error.QUERY_TOO_LONG"](options: {
|
["error.QUERY_TOO_LONG"](options: {
|
||||||
readonly max: string;
|
readonly max: string;
|
||||||
}): string;
|
}): string;
|
||||||
|
/**
|
||||||
|
* `Validation error, errors: {{errors}}`
|
||||||
|
*/
|
||||||
|
["error.VALIDATION_ERROR"](options: {
|
||||||
|
readonly errors: string;
|
||||||
|
}): string;
|
||||||
/**
|
/**
|
||||||
* `User not found.`
|
* `User not found.`
|
||||||
*/
|
*/
|
||||||
@@ -7162,6 +7185,10 @@ export function useAFFiNEI18N(): {
|
|||||||
status: string;
|
status: string;
|
||||||
body: string;
|
body: string;
|
||||||
}>): string;
|
}>): string;
|
||||||
|
/**
|
||||||
|
* `Invalid auth state. You might start the auth progress from another device.`
|
||||||
|
*/
|
||||||
|
["error.INVALID_AUTH_STATE"](): string;
|
||||||
/**
|
/**
|
||||||
* `Missing query parameter `{{name}}`.`
|
* `Missing query parameter `{{name}}`.`
|
||||||
*/
|
*/
|
||||||
@@ -7622,21 +7649,15 @@ export function useAFFiNEI18N(): {
|
|||||||
*/
|
*/
|
||||||
["error.NOTIFICATION_NOT_FOUND"](): string;
|
["error.NOTIFICATION_NOT_FOUND"](): string;
|
||||||
/**
|
/**
|
||||||
* `Mention user do not have permission to access space {{spaceId}}.`
|
* `Mentioned user can not access doc {{docId}}.`
|
||||||
*/
|
*/
|
||||||
["error.MENTION_USER_SPACE_ACCESS_DENIED"](options: {
|
["error.MENTION_USER_DOC_ACCESS_DENIED"](options: {
|
||||||
readonly spaceId: string;
|
readonly docId: string;
|
||||||
}): string;
|
}): string;
|
||||||
/**
|
/**
|
||||||
* `You can not mention yourself.`
|
* `You can not mention yourself.`
|
||||||
*/
|
*/
|
||||||
["error.MENTION_USER_ONESELF_DENIED"](): string;
|
["error.MENTION_USER_ONESELF_DENIED"](): string;
|
||||||
/**
|
|
||||||
* `You do not have permission to access notification {{notificationId}}.`
|
|
||||||
*/
|
|
||||||
["error.NOTIFICATION_ACCESS_DENIED"](options: {
|
|
||||||
readonly notificationId: string;
|
|
||||||
}): string;
|
|
||||||
} { const { t } = useTranslation(); return useMemo(() => createProxy((key) => t.bind(null, key)), [t]); }
|
} { const { t } = useTranslation(); return useMemo(() => createProxy((key) => t.bind(null, key)), [t]); }
|
||||||
function createComponent(i18nKey: string) {
|
function createComponent(i18nKey: string) {
|
||||||
return (props) => createElement(Trans, { i18nKey, shouldUnescape: true, ...props });
|
return (props) => createElement(Trans, { i18nKey, shouldUnescape: true, ...props });
|
||||||
@@ -8061,6 +8082,16 @@ export const TypedTrans: {
|
|||||||
}, {
|
}, {
|
||||||
["1"]: JSX.Element;
|
["1"]: JSX.Element;
|
||||||
}>>;
|
}>>;
|
||||||
|
/**
|
||||||
|
* `<1>{{username}}</1> mentioned you in <2>{{docTitle}}</2>`
|
||||||
|
*/
|
||||||
|
["com.affine.notification.mention"]: ComponentType<TypedTransProps<Readonly<{
|
||||||
|
username: string;
|
||||||
|
docTitle: string;
|
||||||
|
}>, {
|
||||||
|
["1"]: JSX.Element;
|
||||||
|
["2"]: JSX.Element;
|
||||||
|
}>>;
|
||||||
/**
|
/**
|
||||||
* `Unable to join <1/> <2>{{workspaceName}}</2> due to insufficient seats available.`
|
* `Unable to join <1/> <2>{{workspaceName}}</2> due to insufficient seats available.`
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1610,6 +1610,7 @@
|
|||||||
"com.affine.workspace.cloud": "Cloud workspaces",
|
"com.affine.workspace.cloud": "Cloud workspaces",
|
||||||
"com.affine.workspace.cloud.account.logout": "Sign out",
|
"com.affine.workspace.cloud.account.logout": "Sign out",
|
||||||
"com.affine.workspace.cloud.account.settings": "Account settings",
|
"com.affine.workspace.cloud.account.settings": "Account settings",
|
||||||
|
"com.affine.workspace.cloud.account.admin": "Admin panel",
|
||||||
"com.affine.workspace.cloud.auth": "Sign up/ Sign in",
|
"com.affine.workspace.cloud.auth": "Sign up/ Sign in",
|
||||||
"com.affine.workspace.cloud.description": "Sync with AFFiNE Cloud",
|
"com.affine.workspace.cloud.description": "Sync with AFFiNE Cloud",
|
||||||
"com.affine.workspace.cloud.join": "Join workspace",
|
"com.affine.workspace.cloud.join": "Join workspace",
|
||||||
@@ -1774,6 +1775,7 @@
|
|||||||
"error.BAD_REQUEST": "Bad request.",
|
"error.BAD_REQUEST": "Bad request.",
|
||||||
"error.GRAPHQL_BAD_REQUEST": "GraphQL bad request, code: {{code}}, {{message}}",
|
"error.GRAPHQL_BAD_REQUEST": "GraphQL bad request, code: {{code}}, {{message}}",
|
||||||
"error.QUERY_TOO_LONG": "Query is too long, max length is {{max}}.",
|
"error.QUERY_TOO_LONG": "Query is too long, max length is {{max}}.",
|
||||||
|
"error.VALIDATION_ERROR": "Validation error, errors: {{errors}}",
|
||||||
"error.USER_NOT_FOUND": "User not found.",
|
"error.USER_NOT_FOUND": "User not found.",
|
||||||
"error.USER_AVATAR_NOT_FOUND": "User avatar not found.",
|
"error.USER_AVATAR_NOT_FOUND": "User avatar not found.",
|
||||||
"error.EMAIL_ALREADY_USED": "This email has already been registered.",
|
"error.EMAIL_ALREADY_USED": "This email has already been registered.",
|
||||||
@@ -1783,6 +1785,7 @@
|
|||||||
"error.OAUTH_STATE_EXPIRED": "OAuth state expired, please try again.",
|
"error.OAUTH_STATE_EXPIRED": "OAuth state expired, please try again.",
|
||||||
"error.INVALID_OAUTH_CALLBACK_STATE": "Invalid callback state parameter.",
|
"error.INVALID_OAUTH_CALLBACK_STATE": "Invalid callback state parameter.",
|
||||||
"error.INVALID_OAUTH_CALLBACK_CODE": "Invalid callback code parameter, provider response status: {{status}} and body: {{body}}.",
|
"error.INVALID_OAUTH_CALLBACK_CODE": "Invalid callback code parameter, provider response status: {{status}} and body: {{body}}.",
|
||||||
|
"error.INVALID_AUTH_STATE": "Invalid auth state. You might start the auth progress from another device.",
|
||||||
"error.MISSING_OAUTH_QUERY_PARAMETER": "Missing query parameter `{{name}}`.",
|
"error.MISSING_OAUTH_QUERY_PARAMETER": "Missing query parameter `{{name}}`.",
|
||||||
"error.OAUTH_ACCOUNT_ALREADY_CONNECTED": "The third-party account has already been connected to another user.",
|
"error.OAUTH_ACCOUNT_ALREADY_CONNECTED": "The third-party account has already been connected to another user.",
|
||||||
"error.INVALID_EMAIL": "An invalid email provided: {{email}}",
|
"error.INVALID_EMAIL": "An invalid email provided: {{email}}",
|
||||||
@@ -1875,7 +1878,6 @@
|
|||||||
"error.WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE": "You cannot downgrade the workspace from team workspace because there are more than {{limit}} members that are currently active.",
|
"error.WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE": "You cannot downgrade the workspace from team workspace because there are more than {{limit}} members that are currently active.",
|
||||||
"error.UNSUPPORTED_CLIENT_VERSION": "Unsupported client with version [{{clientVersion}}], required version is [{{requiredVersion}}].",
|
"error.UNSUPPORTED_CLIENT_VERSION": "Unsupported client with version [{{clientVersion}}], required version is [{{requiredVersion}}].",
|
||||||
"error.NOTIFICATION_NOT_FOUND": "Notification not found.",
|
"error.NOTIFICATION_NOT_FOUND": "Notification not found.",
|
||||||
"error.MENTION_USER_SPACE_ACCESS_DENIED": "Mention user do not have permission to access space {{spaceId}}.",
|
"error.MENTION_USER_DOC_ACCESS_DENIED": "Mentioned user can not access doc {{docId}}.",
|
||||||
"error.MENTION_USER_ONESELF_DENIED": "You cannot mention yourself.",
|
"error.MENTION_USER_ONESELF_DENIED": "You can not mention yourself."
|
||||||
"error.NOTIFICATION_ACCESS_DENIED": "You do not have permission to access notification {{notificationId}}."
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user