diff --git a/packages/frontend/core/src/desktop/pages/workspace/index.tsx b/packages/frontend/core/src/desktop/pages/workspace/index.tsx
index 4e2effc92e..bfe0cf6311 100644
--- a/packages/frontend/core/src/desktop/pages/workspace/index.tsx
+++ b/packages/frontend/core/src/desktop/pages/workspace/index.tsx
@@ -4,8 +4,8 @@ import { workbenchRoutes } from '@affine/core/desktop/workbench-router';
import {
DefaultServerService,
ServersService,
- WorkspaceServerService,
} from '@affine/core/modules/cloud';
+import { GlobalDialogService } from '@affine/core/modules/dialogs';
import { DndService } from '@affine/core/modules/dnd/services';
import { GlobalContextService } from '@affine/core/modules/global-context';
import {
@@ -33,7 +33,6 @@ import { AffineErrorBoundary } from '../../../components/affine/affine-error-bou
import { WorkbenchRoot } from '../../../modules/workbench';
import { AppContainer } from '../../components/app-container';
import { PageNotFound } from '../404';
-import { SignIn } from '../auth/sign-in';
import { WorkspaceLayout } from './layouts/workspace-layout';
import { SharePage } from './share/share-page';
@@ -53,8 +52,18 @@ declare global {
}
export const Component = (): ReactElement => {
- const { workspacesService } = useServices({
+ const {
+ workspacesService,
+ globalDialogService,
+ serversService,
+ defaultServerService,
+ globalContextService,
+ } = useServices({
WorkspacesService,
+ GlobalDialogService,
+ ServersService,
+ DefaultServerService,
+ GlobalContextService,
});
const params = useParams();
@@ -88,11 +97,6 @@ export const Component = (): ReactElement => {
const [workspaceNotFound, setWorkspaceNotFound] = useState(false);
const listLoading = useLiveData(workspacesService.list.isRevalidating$);
const workspaces = useLiveData(workspacesService.list.workspaces$);
- const serversService = useService(ServersService);
- const serverFromSearchParams = searchParams.get('server');
- const serverNotFound = serverFromSearchParams
- ? serversService.getServerByBaseUrl(serverFromSearchParams)
- : null;
const meta = useMemo(() => {
return workspaces.find(({ id }) => id === params.workspaceId);
}, [workspaces, params.workspaceId]);
@@ -125,36 +129,87 @@ export const Component = (): ReactElement => {
return;
}, [listLoading, meta, workspaceNotFound, workspacesService]);
- if (workspaceNotFound) {
- if (BUILD_CONFIG.isElectron && serverNotFound) {
- const url = new URL(window.location.href);
- url.searchParams.delete('server');
- const redirectUrl = url.toString().replace(window.location.origin, '');
- return (
-
-
-
- );
+ // server search params
+ const serverFromSearchParams = useLiveData(
+ searchParams.has('server')
+ ? serversService.serverByBaseUrl$(searchParams.get('server') as string)
+ : undefined
+ );
+ // server from workspace
+ const serverFromWorkspace = useLiveData(
+ meta?.flavour && meta.flavour !== 'local'
+ ? serversService.server$(meta?.flavour)
+ : undefined
+ );
+ const server = serverFromWorkspace ?? serverFromSearchParams;
+
+ useEffect(() => {
+ if (server) {
+ globalContextService.globalContext.serverId.set(server.id);
+ return () => {
+ globalContextService.globalContext.serverId.set(
+ defaultServerService.server.id
+ );
+ };
}
+ return;
+ }, [
+ defaultServerService.server.id,
+ globalContextService.globalContext.serverId,
+ server,
+ ]);
+
+ // if server is not found, and we have server in search params, we should show add selfhosted dialog
+ const needAddSelfhosted = server === undefined && searchParams.has('server');
+ // use ref to avoid useEffect trigger twice
+ const addSelfhostedDialogOpened = useRef(false);
+
+ useEffect(() => {
+ if (addSelfhostedDialogOpened.current) {
+ return;
+ }
+ addSelfhostedDialogOpened.current = true;
+ if (BUILD_CONFIG.isElectron && needAddSelfhosted) {
+ globalDialogService.open('sign-in', {
+ server: searchParams.get('server') as string,
+ });
+ }
+ return;
+ }, [
+ globalDialogService,
+ needAddSelfhosted,
+ searchParams,
+ serverFromSearchParams,
+ ]);
+
+ if (workspaceNotFound) {
if (detailDocRoute) {
return (
-
+
+
+
);
}
return (
-
-
-
+
+
+
+
+
);
}
if (!meta) {
return ;
}
- return ;
+ return (
+
+
+
+ );
};
const DNDContextProvider = ({ children }: PropsWithChildren) => {
@@ -171,15 +226,12 @@ const DNDContextProvider = ({ children }: PropsWithChildren) => {
};
const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
- const { workspacesService, globalContextService, defaultServerService } =
- useServices({
- WorkspacesService,
- GlobalContextService,
- DefaultServerService,
- });
+ const { workspacesService, globalContextService } = useServices({
+ WorkspacesService,
+ GlobalContextService,
+ });
const [workspace, setWorkspace] = useState(null);
- const workspaceServer = workspace?.scope.get(WorkspaceServerService).server;
useLayoutEffect(() => {
const ref = workspacesService.open({ metadata: meta });
@@ -238,30 +290,17 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
};
localStorage.setItem('last_workspace_id', workspace.id);
globalContextService.globalContext.workspaceId.set(workspace.id);
- if (workspaceServer) {
- globalContextService.globalContext.serverId.set(workspaceServer.id);
- }
globalContextService.globalContext.workspaceFlavour.set(
workspace.flavour
);
return () => {
window.currentWorkspace = undefined;
globalContextService.globalContext.workspaceId.set(null);
- if (workspaceServer) {
- globalContextService.globalContext.serverId.set(
- defaultServerService.server.id
- );
- }
globalContextService.globalContext.workspaceFlavour.set(null);
};
}
return;
- }, [
- defaultServerService.server.id,
- globalContextService,
- workspace,
- workspaceServer,
- ]);
+ }, [globalContextService, workspace]);
if (!workspace) {
return null; // skip this, workspace will be set in layout effect
@@ -269,27 +308,23 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
if (!isRootDocReady) {
return (
-
-
-
-
-
-
+
+
+
+
);
}
return (
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
};
diff --git a/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx b/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx
index c53adc0873..b695ac67c8 100644
--- a/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx
+++ b/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx
@@ -9,6 +9,7 @@ import {
AuthService,
FetchService,
GraphQLService,
+ ServerService,
} from '@affine/core/modules/cloud';
import { type Doc, DocsService } from '@affine/core/modules/doc';
import {
@@ -64,8 +65,9 @@ export const SharePage = ({
workspaceId: string;
docId: string;
}) => {
- const { shareReaderService } = useServices({
+ const { shareReaderService, serverService } = useServices({
ShareReaderService,
+ ServerService,
});
const isLoading = useLiveData(shareReaderService.reader.isLoading$);
@@ -104,8 +106,12 @@ export const SharePage = ({
}, [location.search]);
useEffect(() => {
- shareReaderService.reader.loadShare({ workspaceId, docId });
- }, [shareReaderService, docId, workspaceId]);
+ shareReaderService.reader.loadShare({
+ serverId: serverService.server.id,
+ workspaceId,
+ docId,
+ });
+ }, [shareReaderService, docId, workspaceId, serverService.server.id]);
let element: ReactNode = null;
if (isLoading) {
diff --git a/packages/frontend/core/src/modules/cloud/services/servers.ts b/packages/frontend/core/src/modules/cloud/services/servers.ts
index e0e3084947..9fcbd5c172 100644
--- a/packages/frontend/core/src/modules/cloud/services/servers.ts
+++ b/packages/frontend/core/src/modules/cloud/services/servers.ts
@@ -55,6 +55,12 @@ export class ServersService extends Service {
);
}
+ serverByBaseUrl$(url: string) {
+ return this.servers$.map(servers =>
+ servers.find(server => server.baseUrl === url)
+ );
+ }
+
private readonly serverPool = new ObjectPool({
onDelete(obj) {
obj.dispose();
diff --git a/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts b/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts
index 82c94db320..b9740e4cb0 100644
--- a/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts
+++ b/packages/frontend/core/src/modules/share-doc/entities/share-reader.ts
@@ -31,8 +31,18 @@ export class ShareReader extends Entity {
loadShare = effect(
switchMap(
- ({ workspaceId, docId }: { workspaceId: string; docId: string }) => {
- return fromPromise(this.store.loadShare(workspaceId, docId)).pipe(
+ ({
+ serverId,
+ workspaceId,
+ docId,
+ }: {
+ serverId: string;
+ workspaceId: string;
+ docId: string;
+ }) => {
+ return fromPromise(
+ this.store.loadShare(serverId, workspaceId, docId)
+ ).pipe(
mergeMap(data => {
if (!data) {
this.data$.next(null);
diff --git a/packages/frontend/core/src/modules/share-doc/index.ts b/packages/frontend/core/src/modules/share-doc/index.ts
index c1a06f4bbc..816c6a8c4e 100644
--- a/packages/frontend/core/src/modules/share-doc/index.ts
+++ b/packages/frontend/core/src/modules/share-doc/index.ts
@@ -5,7 +5,7 @@ export { ShareReaderService } from './services/share-reader';
import { type Framework } from '@toeverything/infra';
-import { RawFetchProvider, WorkspaceServerService } from '../cloud';
+import { ServersService, WorkspaceServerService } from '../cloud';
import { DocScope, DocService } from '../doc';
import {
WorkspaceLocalCache,
@@ -26,7 +26,7 @@ export function configureShareDocsModule(framework: Framework) {
framework
.service(ShareReaderService)
.entity(ShareReader, [ShareReaderStore])
- .store(ShareReaderStore, [RawFetchProvider])
+ .store(ShareReaderStore, [ServersService])
.scope(WorkspaceScope)
.service(ShareDocsListService, [WorkspaceService])
.store(ShareDocsStore, [WorkspaceServerService])
diff --git a/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts b/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts
index ca8b6a3147..3159d4cef4 100644
--- a/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts
+++ b/packages/frontend/core/src/modules/share-doc/stores/share-reader.ts
@@ -2,36 +2,31 @@ import { ErrorNames, UserFriendlyError } from '@affine/graphql';
import type { DocMode } from '@blocksuite/affine/blocks';
import { Store } from '@toeverything/infra';
-import type { RawFetchProvider } from '../../cloud';
+import type { ServersService } from '../../cloud';
import { isBackendError } from '../../cloud';
export class ShareReaderStore extends Store {
- constructor(private readonly rawFetch?: RawFetchProvider) {
+ constructor(private readonly serversService: ServersService) {
super();
}
- async loadShare(workspaceId: string, docId: string) {
- if (!this.rawFetch) {
- throw new Error('No Fetch Service');
+ async loadShare(serverId: string, workspaceId: string, docId: string) {
+ const server = this.serversService.server$(serverId).value;
+ if (!server) {
+ throw new Error(`Server ${serverId} not found`);
}
try {
- const docResponse = await this.rawFetch.fetch(
+ const docResponse = await server.fetch(
`/api/workspaces/${workspaceId}/docs/${docId}`
);
- if (docResponse.status !== 200) {
- throw new Error('Failed to fetch workspace');
- }
const publishMode = docResponse.headers.get(
'publish-mode'
) as DocMode | null;
const docBinary = await docResponse.arrayBuffer();
- const workspaceResponse = await this.rawFetch.fetch(
+ const workspaceResponse = await server.fetch(
`/api/workspaces/${workspaceId}/docs/${workspaceId}`
);
- if (workspaceResponse.status !== 200) {
- throw new Error('Failed to fetch workspace');
- }
const workspaceBinary = await workspaceResponse.arrayBuffer();
return {