From 82b3c0d2640c17f2ba02ef18a5143eef21d42cff Mon Sep 17 00:00:00 2001 From: Richard Lora Date: Sun, 29 Jun 2025 10:17:18 -0400 Subject: [PATCH] feat(core): add allowGuestDemoWorkspace flag to force login (#12779) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/user-attachments/assets/41a659c9-6def-4492-be8e-5910eb148d6f This PR enforces login‑first access (#8716) by disabling or enabling the guest demo workspace via Admin Server Client Page and redirecting unauthenticated users straight to `/sign‑in`. ## Summary by CodeRabbit * **New Features** * Added a configuration option to control whether guest users can create demo workspaces. * Updated server and client interfaces, GraphQL schema, and queries to support the new guest demo workspace flag. * **Bug Fixes** * Improved sign-out behavior to redirect users appropriately based on guest demo workspace permissions. * Enhanced navigation flow to handle guest demo workspace access and user authentication state. * **Tests** * Added tests to verify sign-out logic when guest demo workspaces are enabled or disabled. --------- Co-authored-by: liuyi Co-authored-by: fengmk2 --- .docker/selfhost/schema.json | 10 ++ .../backend/server/src/core/config/config.ts | 5 + .../server/src/core/config/resolver.ts | 1 + .../backend/server/src/core/config/types.ts | 5 + .../backend/server/src/core/version/config.ts | 5 + packages/backend/server/src/schema.gql | 3 + .../src/graphql/admin/admin-server-config.gql | 1 + packages/common/graphql/src/graphql/index.ts | 2 + .../graphql/src/graphql/server-config.gql | 1 + packages/common/graphql/src/schema.ts | 4 + packages/frontend/admin/src/config.json | 8 ++ .../share-header-right-item/user-avatar.tsx | 5 +- .../affine/__tests__/use-sign-out.spec.ts | 92 +++++++++++++++++++ .../components/hooks/affine/use-sign-out.ts | 18 +++- .../add-workspace/index.tsx | 11 ++- .../user-with-workspace-list/index.tsx | 10 +- .../workspace-list/index.tsx | 5 +- .../core/src/desktop/pages/index/index.tsx | 32 ++++++- .../core/src/desktop/pages/invite/index.tsx | 3 +- .../components/workspace-selector/menu.tsx | 3 +- .../core/src/modules/cloud/constant.ts | 6 ++ .../core/src/modules/cloud/entities/server.ts | 1 + .../src/modules/cloud/services/servers.ts | 1 + .../frontend/core/src/modules/cloud/types.ts | 1 + .../core/src/modules/feature-flag/constant.ts | 10 -- 25 files changed, 209 insertions(+), 34 deletions(-) create mode 100644 packages/frontend/core/src/components/hooks/affine/__tests__/use-sign-out.spec.ts diff --git a/.docker/selfhost/schema.json b/.docker/selfhost/schema.json index 889f49fcdf..613186b25e 100644 --- a/.docker/selfhost/schema.json +++ b/.docker/selfhost/schema.json @@ -565,6 +565,11 @@ "type": "boolean", "description": "Only allow users with early access features to access the app\n@default false", "default": false + }, + "allowGuestDemoWorkspace": { + "type": "boolean", + "description": "Whether allow guest users to create demo workspaces.\n@default true", + "default": true } } }, @@ -592,6 +597,11 @@ "type": "string", "description": "Allowed version range of the app that allowed to access the server. Requires 'client/versionControl.enabled' to be true to take effect.\n@default \">=0.20.0\"", "default": ">=0.20.0" + }, + "allowGuestDemoWorkspace": { + "type": "boolean", + "description": "Allow guests to access demo workspace.\n@default true", + "default": true } } }, diff --git a/packages/backend/server/src/core/config/config.ts b/packages/backend/server/src/core/config/config.ts index 3b6bd421b2..8ecdbef687 100644 --- a/packages/backend/server/src/core/config/config.ts +++ b/packages/backend/server/src/core/config/config.ts @@ -4,6 +4,7 @@ import { defineModuleConfig } from '../../base'; export interface ServerFlags { earlyAccessControl: boolean; + allowGuestDemoWorkspace: boolean; } declare global { @@ -75,4 +76,8 @@ defineModuleConfig('flags', { desc: 'Only allow users with early access features to access the app', default: false, }, + allowGuestDemoWorkspace: { + desc: 'Whether allow guest users to create demo workspaces.', + default: true, + }, }); diff --git a/packages/backend/server/src/core/config/resolver.ts b/packages/backend/server/src/core/config/resolver.ts index f16b7012a0..fa07070a95 100644 --- a/packages/backend/server/src/core/config/resolver.ts +++ b/packages/backend/server/src/core/config/resolver.ts @@ -85,6 +85,7 @@ export class ServerConfigResolver { baseUrl: this.url.requestBaseUrl, type: env.DEPLOYMENT_TYPE, features: this.server.features, + allowGuestDemoWorkspace: this.config.flags.allowGuestDemoWorkspace, }; } diff --git a/packages/backend/server/src/core/config/types.ts b/packages/backend/server/src/core/config/types.ts index c0f4aea578..120d39caa1 100644 --- a/packages/backend/server/src/core/config/types.ts +++ b/packages/backend/server/src/core/config/types.ts @@ -38,4 +38,9 @@ export class ServerConfigType { @Field(() => [ServerFeature], { description: 'enabled server features' }) features!: ServerFeature[]; + + @Field(() => Boolean, { + description: 'Whether allow guest users to create demo workspaces.', + }) + allowGuestDemoWorkspace!: boolean; } diff --git a/packages/backend/server/src/core/version/config.ts b/packages/backend/server/src/core/version/config.ts index 62047206e7..2542ce517b 100644 --- a/packages/backend/server/src/core/version/config.ts +++ b/packages/backend/server/src/core/version/config.ts @@ -5,6 +5,7 @@ export interface VersionConfig { enabled: boolean; requiredVersion: string; }; + allowGuestDemoWorkspace?: boolean; } declare global { @@ -28,4 +29,8 @@ defineModuleConfig('client', { desc: "Allowed version range of the app that allowed to access the server. Requires 'client/versionControl.enabled' to be true to take effect.", default: '>=0.20.0', }, + allowGuestDemoWorkspace: { + desc: 'Allow guests to access demo workspace.', + default: true, + }, }); diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index b8ea21d094..aaafc45e8c 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -1585,6 +1585,9 @@ enum SearchTable { } type ServerConfigType { + """Whether allow guest users to create demo workspaces.""" + allowGuestDemoWorkspace: Boolean! + """fetch latest available upgradable release of server""" availableUpgrade: ReleaseVersionType diff --git a/packages/common/graphql/src/graphql/admin/admin-server-config.gql b/packages/common/graphql/src/graphql/admin/admin-server-config.gql index 6873c7bfad..acb59fb7cf 100644 --- a/packages/common/graphql/src/graphql/admin/admin-server-config.gql +++ b/packages/common/graphql/src/graphql/admin/admin-server-config.gql @@ -7,6 +7,7 @@ query adminServerConfig { baseUrl name features + allowGuestDemoWorkspace type initialized credentialsRequirement { diff --git a/packages/common/graphql/src/graphql/index.ts b/packages/common/graphql/src/graphql/index.ts index eabc6c78f0..5e50468a41 100644 --- a/packages/common/graphql/src/graphql/index.ts +++ b/packages/common/graphql/src/graphql/index.ts @@ -32,6 +32,7 @@ export const adminServerConfigQuery = { baseUrl name features + allowGuestDemoWorkspace type initialized credentialsRequirement { @@ -1822,6 +1823,7 @@ export const serverConfigQuery = { baseUrl name features + allowGuestDemoWorkspace type initialized credentialsRequirement { diff --git a/packages/common/graphql/src/graphql/server-config.gql b/packages/common/graphql/src/graphql/server-config.gql index ac84085671..e95a5b2b1e 100644 --- a/packages/common/graphql/src/graphql/server-config.gql +++ b/packages/common/graphql/src/graphql/server-config.gql @@ -7,6 +7,7 @@ query serverConfig { baseUrl name features + allowGuestDemoWorkspace type initialized credentialsRequirement { diff --git a/packages/common/graphql/src/schema.ts b/packages/common/graphql/src/schema.ts index 0b02648abf..274c55c372 100644 --- a/packages/common/graphql/src/schema.ts +++ b/packages/common/graphql/src/schema.ts @@ -2149,6 +2149,8 @@ export enum SearchTable { export interface ServerConfigType { __typename?: 'ServerConfigType'; + /** Whether allow guest users to create demo workspaces. */ + allowGuestDemoWorkspace: Scalars['Boolean']['output']; /** fetch latest available upgradable release of server */ availableUpgrade: Maybe; /** Features for user that can be configured */ @@ -2743,6 +2745,7 @@ export type AdminServerConfigQuery = { baseUrl: string; name: string; features: Array; + allowGuestDemoWorkspace: boolean; type: ServerDeploymentType; initialized: boolean; availableUserFeatures: Array; @@ -4828,6 +4831,7 @@ export type ServerConfigQuery = { baseUrl: string; name: string; features: Array; + allowGuestDemoWorkspace: boolean; type: ServerDeploymentType; initialized: boolean; credentialsRequirement: { diff --git a/packages/frontend/admin/src/config.json b/packages/frontend/admin/src/config.json index ba2d0424bf..70f4f1c6f9 100644 --- a/packages/frontend/admin/src/config.json +++ b/packages/frontend/admin/src/config.json @@ -190,6 +190,10 @@ "earlyAccessControl": { "type": "Boolean", "desc": "Only allow users with early access features to access the app" + }, + "allowGuestDemoWorkspace": { + "type": "Boolean", + "desc": "Whether allow guest users to create demo workspaces." } }, "docService": { @@ -207,6 +211,10 @@ "versionControl.requiredVersion": { "type": "String", "desc": "Allowed version range of the app that allowed to access the server. Requires 'client/versionControl.enabled' to be true to take effect." + }, + "allowGuestDemoWorkspace": { + "type": "Boolean", + "desc": "Allow guests to access demo workspace." } }, "captcha": { diff --git a/packages/frontend/core/src/components/cloud/share-header-right-item/user-avatar.tsx b/packages/frontend/core/src/components/cloud/share-header-right-item/user-avatar.tsx index f293f1ca9e..ab0060fb12 100644 --- a/packages/frontend/core/src/components/cloud/share-header-right-item/user-avatar.tsx +++ b/packages/frontend/core/src/components/cloud/share-header-right-item/user-avatar.tsx @@ -7,6 +7,7 @@ import { useLiveData, useService } from '@toeverything/infra'; import { useEffect, useMemo } from 'react'; import { AuthService, SubscriptionService } from '../../../modules/cloud'; +import { useNavigateHelper } from '../../hooks/use-navigate-helper'; import * as styles from './styles.css'; const UserInfo = () => { @@ -51,9 +52,11 @@ export const PublishPageUserAvatar = () => { const user = useLiveData(authService.session.account$); const t = useI18n(); + const navigateHelper = useNavigateHelper(); const handleSignOut = useAsyncCallback(async () => { await authService.signOut(); - }, [authService]); + navigateHelper.jumpToSignIn(); + }, [authService, navigateHelper]); const menuItem = useMemo(() => { return ( diff --git a/packages/frontend/core/src/components/hooks/affine/__tests__/use-sign-out.spec.ts b/packages/frontend/core/src/components/hooks/affine/__tests__/use-sign-out.spec.ts new file mode 100644 index 0000000000..f95ec760a3 --- /dev/null +++ b/packages/frontend/core/src/components/hooks/affine/__tests__/use-sign-out.spec.ts @@ -0,0 +1,92 @@ +/* eslint-disable rxjs/finnish */ +/** + * @vitest-environment happy-dom + */ +import { renderHook, waitFor } from '@testing-library/react'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +// mocks +const signOutFn = vi.fn(); +const jumpToIndex = vi.fn(); +const jumpToSignIn = vi.fn(); +let allowGuestDemo: boolean | undefined = true; + +vi.mock('@affine/core/modules/cloud', () => ({ + AuthService: class {}, + DefaultServerService: class {}, +})); + +vi.mock('@toeverything/infra', () => { + return { + useService: () => ({ signOut: signOutFn }), + useServices: () => ({ + defaultServerService: { + server: { + config$: { + value: { + get allowGuestDemoWorkspace() { + return allowGuestDemo; + }, + }, + }, + }, + }, + }), + }; +}); + +vi.mock('@affine/component', () => { + return { + useConfirmModal: () => ({ + openConfirmModal: ({ onConfirm }: { onConfirm?: () => unknown }) => { + return Promise.resolve(onConfirm?.()); + }, + }), + notify: { error: vi.fn() }, + }; +}); + +vi.mock('@affine/i18n', () => ({ + useI18n: () => new Proxy({}, { get: () => () => '' }), +})); + +vi.mock('../../use-navigate-helper', () => ({ + useNavigateHelper: () => ({ jumpToIndex, jumpToSignIn }), +})); + +import { useSignOut } from '../use-sign-out'; + +describe('useSignOut', () => { + beforeEach(() => { + signOutFn.mockClear(); + jumpToIndex.mockClear(); + jumpToSignIn.mockClear(); + }); + + test('redirects to index when guest demo allowed', async () => { + allowGuestDemo = true; + const { result } = renderHook(() => useSignOut()); + result.current(); + await waitFor(() => expect(signOutFn).toHaveBeenCalled()); + expect(jumpToIndex).toHaveBeenCalled(); + expect(jumpToSignIn).not.toHaveBeenCalled(); + }); + + test('redirects to index when guest demo config not provided', async () => { + allowGuestDemo = undefined; + const { result } = renderHook(() => useSignOut()); + result.current(); + await waitFor(() => expect(signOutFn).toHaveBeenCalled()); + expect(jumpToIndex).toHaveBeenCalled(); + expect(jumpToSignIn).not.toHaveBeenCalled(); + }); + + test('redirects to sign in when guest demo disabled', async () => { + allowGuestDemo = false; + const { result } = renderHook(() => useSignOut()); + result.current(); + await waitFor(() => expect(signOutFn).toHaveBeenCalled()); + expect(jumpToSignIn).toHaveBeenCalled(); + expect(jumpToIndex).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/frontend/core/src/components/hooks/affine/use-sign-out.ts b/packages/frontend/core/src/components/hooks/affine/use-sign-out.ts index baee5d0077..bb4e0f4983 100644 --- a/packages/frontend/core/src/components/hooks/affine/use-sign-out.ts +++ b/packages/frontend/core/src/components/hooks/affine/use-sign-out.ts @@ -3,10 +3,10 @@ import { notify, useConfirmModal, } from '@affine/component'; -import { AuthService } from '@affine/core/modules/cloud'; +import { AuthService, DefaultServerService } from '@affine/core/modules/cloud'; import { UserFriendlyError } from '@affine/error'; import { useI18n } from '@affine/i18n'; -import { useService } from '@toeverything/infra'; +import { useService, useServices } from '@toeverything/infra'; import { useCallback } from 'react'; import { useNavigateHelper } from '../use-navigate-helper'; @@ -25,21 +25,29 @@ export const useSignOut = ({ }: ConfirmModalProps = {}) => { const t = useI18n(); const { openConfirmModal } = useConfirmModal(); - const { jumpToIndex } = useNavigateHelper(); + const { jumpToSignIn, jumpToIndex } = useNavigateHelper(); const authService = useService(AuthService); + const { defaultServerService } = useServices({ DefaultServerService }); const signOut = useCallback(async () => { onConfirm?.()?.catch(console.error); try { await authService.signOut(); - jumpToIndex(); + if ( + defaultServerService.server.config$.value.allowGuestDemoWorkspace !== + false + ) { + jumpToIndex(); + } else { + jumpToSignIn(); + } } catch (err) { console.error(err); const error = UserFriendlyError.fromAny(err); notify.error(error); } - }, [authService, jumpToIndex, onConfirm]); + }, [authService, jumpToIndex, jumpToSignIn, defaultServerService, onConfirm]); const getDefaultText = useCallback( (key: SignOutConfirmModalI18NKeys) => { diff --git a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/add-workspace/index.tsx b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/add-workspace/index.tsx index 90cea7e20b..8b0f2ff09f 100644 --- a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/add-workspace/index.tsx +++ b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/add-workspace/index.tsx @@ -1,5 +1,5 @@ import { MenuItem } from '@affine/component/ui/menu'; -import { FeatureFlagService } from '@affine/core/modules/feature-flag'; +import { DefaultServerService } from '@affine/core/modules/cloud'; import { useI18n } from '@affine/i18n'; import { ImportIcon, PlusIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; @@ -14,10 +14,11 @@ export const AddWorkspace = ({ onNewWorkspace?: () => void; }) => { const t = useI18n(); - const featureFlagService = useService(FeatureFlagService); - const enableLocalWorkspace = useLiveData( - featureFlagService.flags.enable_local_workspace.$ + const defaultServerService = useService(DefaultServerService); + const allowGuestDemo = useLiveData( + defaultServerService.server.config$.selector(c => c.allowGuestDemoWorkspace) ); + const guestDemoEnabled = allowGuestDemo !== false; return ( <> @@ -44,7 +45,7 @@ export const AddWorkspace = ({ className={styles.ItemContainer} >
- {enableLocalWorkspace + {guestDemoEnabled ? t['com.affine.workspaceList.addWorkspace.create']() : t['com.affine.workspaceList.addWorkspace.create-cloud']()}
diff --git a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx index d8613128b0..990c8f566e 100644 --- a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx +++ b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx @@ -1,8 +1,7 @@ import { ScrollableContainer } from '@affine/component'; import { MenuItem } from '@affine/component/ui/menu'; -import { AuthService } from '@affine/core/modules/cloud'; +import { AuthService, DefaultServerService } from '@affine/core/modules/cloud'; import { GlobalDialogService } from '@affine/core/modules/dialogs'; -import { FeatureFlagService } from '@affine/core/modules/feature-flag'; import { type WorkspaceMetadata } from '@affine/core/modules/workspace'; import { useI18n } from '@affine/i18n'; import { track } from '@affine/track'; @@ -66,7 +65,7 @@ export const UserWithWorkspaceList = ({ }: UserWithWorkspaceListProps) => { const globalDialogService = useService(GlobalDialogService); const session = useLiveData(useService(AuthService).session.session$); - const featureFlagService = useService(FeatureFlagService); + const defaultServerService = useService(DefaultServerService); const isAuthenticated = session.status === 'authenticated'; @@ -77,7 +76,8 @@ export const UserWithWorkspaceList = ({ const onNewWorkspace = useCallback(() => { if ( !isAuthenticated && - !featureFlagService.flags.enable_local_workspace.value + defaultServerService.server.config$.value.allowGuestDemoWorkspace === + false ) { return openSignInModal(); } @@ -90,7 +90,7 @@ export const UserWithWorkspaceList = ({ onEventEnd?.(); }, [ globalDialogService, - featureFlagService, + defaultServerService, isAuthenticated, onCreatedWorkspace, onEventEnd, diff --git a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/workspace-list/index.tsx b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/workspace-list/index.tsx index 17ee897e15..44f589be54 100644 --- a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/workspace-list/index.tsx +++ b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/workspace-list/index.tsx @@ -1,6 +1,7 @@ import { IconButton, Menu, MenuItem } from '@affine/component'; import { Divider } from '@affine/component/ui/divider'; import { useEnableCloud } from '@affine/core/components/hooks/affine/use-enable-cloud'; +import { useSignOut } from '@affine/core/components/hooks/affine/use-sign-out'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper'; import type { AuthAccountInfo, Server } from '@affine/core/modules/cloud'; @@ -161,9 +162,7 @@ const CloudWorkSpaceList = ({ workspaces, ]); - const handleSignOut = useAsyncCallback(async () => { - await authService.signOut(); - }, [authService]); + const handleSignOut = useSignOut(); const handleSignIn = useAsyncCallback(async () => { globalDialogService.open('sign-in', { diff --git a/packages/frontend/core/src/desktop/pages/index/index.tsx b/packages/frontend/core/src/desktop/pages/index/index.tsx index 187c180eb5..5649fb55d5 100644 --- a/packages/frontend/core/src/desktop/pages/index/index.tsx +++ b/packages/frontend/core/src/desktop/pages/index/index.tsx @@ -1,3 +1,4 @@ +import { DefaultServerService } from '@affine/core/modules/cloud'; import { DesktopApiService } from '@affine/core/modules/desktop-api'; import { WorkspacesService } from '@affine/core/modules/workspace'; import { @@ -46,16 +47,23 @@ export const Component = ({ const [navigating, setNavigating] = useState(true); const [creating, setCreating] = useState(false); const authService = useService(AuthService); + const defaultServerService = useService(DefaultServerService); const loggedIn = useLiveData( authService.session.status$.map(s => s === 'authenticated') ); + const allowGuestDemo = + useLiveData( + defaultServerService.server.config$.selector( + c => c.allowGuestDemoWorkspace + ) + ) ?? true; const workspacesService = useService(WorkspacesService); const list = useLiveData(workspacesService.list.workspaces$); const listIsLoading = useLiveData(workspacesService.list.isRevalidating$); - const { openPage, jumpToPage } = useNavigateHelper(); + const { openPage, jumpToPage, jumpToSignIn } = useNavigateHelper(); const [searchParams] = useSearchParams(); const createOnceRef = useRef(false); @@ -84,6 +92,12 @@ export const Component = ({ return; } + if (!allowGuestDemo && !loggedIn) { + localStorage.removeItem('last_workspace_id'); + jumpToSignIn(); + return; + } + // check is user logged in && has cloud workspace if (searchParams.get('initCloud') === 'true') { if (loggedIn) { @@ -111,10 +125,12 @@ export const Component = ({ openPage(openWorkspace.id, defaultIndexRoute, RouteLogic.REPLACE); } }, [ + allowGuestDemo, createCloudWorkspace, list, openPage, searchParams, + jumpToSignIn, listIsLoading, loggedIn, navigating, @@ -128,7 +144,9 @@ export const Component = ({ }, [desktopApi]); useEffect(() => { - setCreating(true); + if (listIsLoading || list.length > 0) { + return; + } createFirstAppData(workspacesService) .then(createdWorkspace => { if (createdWorkspace) { @@ -148,7 +166,15 @@ export const Component = ({ .finally(() => { setCreating(false); }); - }, [jumpToPage, openPage, workspacesService]); + }, [ + jumpToPage, + jumpToSignIn, + openPage, + workspacesService, + loggedIn, + listIsLoading, + list, + ]); if (navigating || creating) { return fallback ?? ; diff --git a/packages/frontend/core/src/desktop/pages/invite/index.tsx b/packages/frontend/core/src/desktop/pages/invite/index.tsx index ad1a9382e4..54f80ec66e 100644 --- a/packages/frontend/core/src/desktop/pages/invite/index.tsx +++ b/packages/frontend/core/src/desktop/pages/invite/index.tsx @@ -83,7 +83,8 @@ const AcceptInvite = ({ inviteId: targetInviteId }: { inviteId: string }) => { const onSignOut = useAsyncCallback(async () => { await authService.signOut(); - }, [authService]); + navigateHelper.jumpToSignIn(); + }, [authService, navigateHelper]); if ((loading && !requestToJoinLoading) || inviteId !== targetInviteId) { return null; diff --git a/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx b/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx index 75d6ec4507..a65b961c7c 100644 --- a/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx +++ b/packages/frontend/core/src/mobile/components/workspace-selector/menu.tsx @@ -228,7 +228,8 @@ const CloudWorkSpaceList = ({ const handleSignOut = useAsyncCallback(async () => { await authService.signOut(); - }, [authService]); + navigateHelper.jumpToSignIn(); + }, [authService, navigateHelper]); const handleSignIn = useAsyncCallback(async () => { globalDialogService.open('sign-in', { diff --git a/packages/frontend/core/src/modules/cloud/constant.ts b/packages/frontend/core/src/modules/cloud/constant.ts index d8b8f9589a..988bb8451c 100644 --- a/packages/frontend/core/src/modules/cloud/constant.ts +++ b/packages/frontend/core/src/modules/cloud/constant.ts @@ -26,6 +26,7 @@ export const BUILD_IN_SERVERS: (ServerMetadata & { config: ServerConfig })[] = maxLength: 32, }, }, + allowGuestDemoWorkspace: true, }, }, ] @@ -56,6 +57,7 @@ export const BUILD_IN_SERVERS: (ServerMetadata & { config: ServerConfig })[] = maxLength: 32, }, }, + allowGuestDemoWorkspace: true, }, }, ] @@ -88,6 +90,7 @@ export const BUILD_IN_SERVERS: (ServerMetadata & { config: ServerConfig })[] = maxLength: 32, }, }, + allowGuestDemoWorkspace: true, }, }, ] @@ -120,6 +123,7 @@ export const BUILD_IN_SERVERS: (ServerMetadata & { config: ServerConfig })[] = maxLength: 32, }, }, + allowGuestDemoWorkspace: true, }, }, ] @@ -148,6 +152,7 @@ export const BUILD_IN_SERVERS: (ServerMetadata & { config: ServerConfig })[] = maxLength: 32, }, }, + allowGuestDemoWorkspace: true, }, }, ] @@ -178,6 +183,7 @@ export const BUILD_IN_SERVERS: (ServerMetadata & { config: ServerConfig })[] = maxLength: 32, }, }, + allowGuestDemoWorkspace: true, }, }, ] diff --git a/packages/frontend/core/src/modules/cloud/entities/server.ts b/packages/frontend/core/src/modules/cloud/entities/server.ts index aa6d425a33..d287d7fcfa 100644 --- a/packages/frontend/core/src/modules/cloud/entities/server.ts +++ b/packages/frontend/core/src/modules/cloud/entities/server.ts @@ -82,6 +82,7 @@ export class Server extends Entity<{ credentialsRequirement: config.credentialsRequirement, features: config.features, oauthProviders: config.oauthProviders, + allowGuestDemoWorkspace: config.allowGuestDemoWorkspace, serverName: config.name, type: config.type, version: config.version, diff --git a/packages/frontend/core/src/modules/cloud/services/servers.ts b/packages/frontend/core/src/modules/cloud/services/servers.ts index 757390d996..8b872bd3e4 100644 --- a/packages/frontend/core/src/modules/cloud/services/servers.ts +++ b/packages/frontend/core/src/modules/cloud/services/servers.ts @@ -82,6 +82,7 @@ export class ServersService extends Service { credentialsRequirement: config.credentialsRequirement, features: config.features, oauthProviders: config.oauthProviders, + allowGuestDemoWorkspace: config.allowGuestDemoWorkspace, serverName: config.name, type: config.type, initialized: config.initialized, diff --git a/packages/frontend/core/src/modules/cloud/types.ts b/packages/frontend/core/src/modules/cloud/types.ts index 4d86deab86..5f2d340809 100644 --- a/packages/frontend/core/src/modules/cloud/types.ts +++ b/packages/frontend/core/src/modules/cloud/types.ts @@ -14,6 +14,7 @@ export interface ServerMetadata { export interface ServerConfig { serverName: string; features: ServerFeature[]; + allowGuestDemoWorkspace: boolean; oauthProviders: OAuthProviderType[]; type: ServerDeploymentType; initialized?: boolean; diff --git a/packages/frontend/core/src/modules/feature-flag/constant.ts b/packages/frontend/core/src/modules/feature-flag/constant.ts index 4e57fe3b88..0efa9c8736 100644 --- a/packages/frontend/core/src/modules/feature-flag/constant.ts +++ b/packages/frontend/core/src/modules/feature-flag/constant.ts @@ -1,7 +1,6 @@ import type { FlagInfo } from './types'; // const isNotStableBuild = BUILD_CONFIG.appBuildType !== 'stable'; -const isDesktopEnvironment = BUILD_CONFIG.isElectron; const isCanaryBuild = BUILD_CONFIG.appBuildType === 'canary'; const isMobile = BUILD_CONFIG.isMobileEdition; @@ -149,15 +148,6 @@ export const AFFINE_FLAGS = { configurable: isCanaryBuild && !isMobile, defaultState: isCanaryBuild, }, - enable_local_workspace: { - category: 'affine', - displayName: - 'com.affine.settings.workspace.experimental-features.enable-local-workspace.name', - description: - 'com.affine.settings.workspace.experimental-features.enable-local-workspace.description', - configurable: isCanaryBuild, - defaultState: isDesktopEnvironment || isCanaryBuild, - }, enable_advanced_block_visibility: { category: 'blocksuite', bsFlag: 'enable_advanced_block_visibility',