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

![CleanShot 2025-03-13 at 13 02 25@2x](https://github.com/user-attachments/assets/82f50a5b-f079-4c64-a3fa-6554735bea82)
This commit is contained in:
JimmFly
2025-03-13 10:46:26 +00:00
parent 7df06ea98b
commit 0c9591f08e
5 changed files with 81 additions and 22 deletions
@@ -14,7 +14,7 @@ import {
} from '@affine/core/modules/dialogs';
import { useI18n } from '@affine/i18n';
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 { cssVar } from '@toeverything/theme';
import { assignInlineVars } from '@vanilla-extract/dynamic';
@@ -27,6 +27,7 @@ import {
ServerService,
SubscriptionService,
UserCopilotQuotaService,
UserFeatureService,
UserQuotaService,
} from '../../modules/cloud';
import { UserPlanButton } from '../affine/auth/user-plan-button';
@@ -80,6 +81,9 @@ const UnauthorizedUserInfo = () => {
const AccountMenu = () => {
const workspaceDialogService = useService(WorkspaceDialogService);
const openSignOutModal = useSignOut();
const serverService = useService(ServerService);
const userFeatureService = useService(UserFeatureService);
const isAdmin = useLiveData(userFeatureService.userFeature.isAdmin$);
const onOpenAccountSetting = useCallback(() => {
track.$.navigationPanel.profileAndBadge.openSettings({ to: 'account' });
@@ -88,8 +92,16 @@ const AccountMenu = () => {
});
}, [workspaceDialogService]);
const onOpenAdminPanel = useCallback(() => {
window.open(`${serverService.server.baseUrl}/admin`, '_blank');
}, [serverService.server.baseUrl]);
const t = useI18n();
useEffect(() => {
userFeatureService.userFeature.revalidate();
}, [userFeatureService]);
return (
<>
<MenuItem
@@ -99,6 +111,15 @@ const AccountMenu = () => {
>
{t['com.affine.workspace.cloud.account.settings']()}
</MenuItem>
{isAdmin ? (
<MenuItem
prefixIcon={<AdminIcon />}
data-testid="workspace-modal-account-admin-option"
onClick={onOpenAdminPanel}
>
{t['com.affine.workspace.cloud.account.admin']()}
</MenuItem>
) : null}
<MenuItem
prefixIcon={<SignOutIcon />}
data-testid="workspace-modal-sign-out-option"
@@ -18,6 +18,11 @@ import type { UserFeatureStore } from '../stores/user-feature';
export class UserFeature extends Entity {
// undefined means no user, null means loading
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 =>
features === null
? null
@@ -14,7 +14,7 @@
"it-IT": 99,
"it": 1,
"ja": 99,
"ko": 63,
"ko": 62,
"pl": 99,
"pt-BR": 99,
"ru": 99,
+48 -17
View File
@@ -5404,8 +5404,8 @@ export function useAFFiNEI18N(): {
*/
["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;
/**
* `Enables Embed Iframe Block.`
@@ -6465,6 +6465,10 @@ export function useAFFiNEI18N(): {
* `Account settings`
*/
["com.affine.workspace.cloud.account.settings"](): string;
/**
* `Admin panel`
*/
["com.affine.workspace.cloud.account.admin"](): string;
/**
* `Sign up/ Sign in`
*/
@@ -6549,6 +6553,18 @@ export function useAFFiNEI18N(): {
* `Yesterday`
*/
["com.affine.yesterday"](): string;
/**
* `Inactive`
*/
["com.affine.inactive"](): string;
/**
* `Inactive member`
*/
["com.affine.inactive-member"](): string;
/**
* `Inactive workspace`
*/
["com.affine.inactive-workspace"](): string;
/**
* `core`
*/
@@ -6992,12 +7008,9 @@ export function useAFFiNEI18N(): {
*/
["com.affine.notification.unsupported"](): string;
/**
* `{{username}} mentioned you in {{docTitle}}`
* `No new notifications`
*/
["com.affine.notification.mention"](options: Readonly<{
username: string;
docTitle: string;
}>): string;
["com.affine.notification.empty"](): string;
/**
* `Tips`
*/
@@ -7006,6 +7019,10 @@ export function useAFFiNEI18N(): {
* `Template`
*/
Template(): string;
/**
* `Delete Template`
*/
["com.affine.template-list.delete"](): string;
/**
* `No template`
*/
@@ -7119,6 +7136,12 @@ export function useAFFiNEI18N(): {
["error.QUERY_TOO_LONG"](options: {
readonly max: string;
}): string;
/**
* `Validation error, errors: {{errors}}`
*/
["error.VALIDATION_ERROR"](options: {
readonly errors: string;
}): string;
/**
* `User not found.`
*/
@@ -7162,6 +7185,10 @@ export function useAFFiNEI18N(): {
status: string;
body: string;
}>): string;
/**
* `Invalid auth state. You might start the auth progress from another device.`
*/
["error.INVALID_AUTH_STATE"](): string;
/**
* `Missing query parameter `{{name}}`.`
*/
@@ -7622,21 +7649,15 @@ export function useAFFiNEI18N(): {
*/
["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: {
readonly spaceId: string;
["error.MENTION_USER_DOC_ACCESS_DENIED"](options: {
readonly docId: string;
}): string;
/**
* `You cannot mention yourself.`
* `You can not mention yourself.`
*/
["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]); }
function createComponent(i18nKey: string) {
return (props) => createElement(Trans, { i18nKey, shouldUnescape: true, ...props });
@@ -8061,6 +8082,16 @@ export const TypedTrans: {
}, {
["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.`
*/
+5 -3
View File
@@ -1610,6 +1610,7 @@
"com.affine.workspace.cloud": "Cloud workspaces",
"com.affine.workspace.cloud.account.logout": "Sign out",
"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.description": "Sync with AFFiNE Cloud",
"com.affine.workspace.cloud.join": "Join workspace",
@@ -1774,6 +1775,7 @@
"error.BAD_REQUEST": "Bad request.",
"error.GRAPHQL_BAD_REQUEST": "GraphQL bad request, code: {{code}}, {{message}}",
"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_AVATAR_NOT_FOUND": "User avatar not found.",
"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.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_AUTH_STATE": "Invalid auth state. You might start the auth progress from another device.",
"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.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.UNSUPPORTED_CLIENT_VERSION": "Unsupported client with version [{{clientVersion}}], required version is [{{requiredVersion}}].",
"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_ONESELF_DENIED": "You cannot mention yourself.",
"error.NOTIFICATION_ACCESS_DENIED": "You do not have permission to access notification {{notificationId}}."
"error.MENTION_USER_DOC_ACCESS_DENIED": "Mentioned user can not access doc {{docId}}.",
"error.MENTION_USER_ONESELF_DENIED": "You can not mention yourself."
}