diff --git a/apps/web/src/components/message-center-handler/index.tsx b/apps/web/src/components/message-center-handler/index.tsx
new file mode 100644
index 0000000000..a724bd88e3
--- /dev/null
+++ b/apps/web/src/components/message-center-handler/index.tsx
@@ -0,0 +1,35 @@
+import { toast } from '@affine/component';
+import { getApis, MessageCenter } from '@affine/datacenter';
+import { useRouter } from 'next/router';
+import { useEffect } from 'react';
+
+export function MessageCenterHandler({
+ children,
+}: {
+ children?: React.ReactNode;
+}) {
+ const router = useRouter();
+ useEffect(() => {
+ const instance = MessageCenter.getInstance();
+ if (instance) {
+ return instance.onMessage(async message => {
+ if (message.code === MessageCenter.messageCode.noPermission) {
+ // todo: translate message
+ // todo: more specific message for accessing different resources
+ // todo: error toast style
+ toast('You have no permission to access this workspace');
+ getApis().auth.clear();
+ // the status of the app right now is unknown, and it won't help if we let
+ // the app continue and let the user auth the app.
+ // that's why so we need to reload the page for now.
+ //
+ // fix: a better option is to keep loading the app, and prompt the user to login
+ // or perhaps displaying page 401?
+ router.reload();
+ }
+ });
+ }
+ }, [router]);
+
+ return <>{children}>;
+}
diff --git a/apps/web/src/hooks/use-members.ts b/apps/web/src/hooks/use-members.ts
index 96304aeb21..804849917d 100644
--- a/apps/web/src/hooks/use-members.ts
+++ b/apps/web/src/hooks/use-members.ts
@@ -11,7 +11,7 @@ export const useMembers = () => {
const refreshMembers = useCallback(async () => {
if (!currentWorkspace || !dataCenter) return;
const members = await dataCenter.getMembers(currentWorkspace.id);
- setMembers(members);
+ setMembers(members ?? []);
}, [dataCenter, currentWorkspace]);
useEffect(() => {
diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx
index 4165770602..0d9eee6c2b 100644
--- a/apps/web/src/pages/_app.tsx
+++ b/apps/web/src/pages/_app.tsx
@@ -24,6 +24,7 @@ import { useTranslation } from '@affine/i18n';
import React from 'react';
import { GlobalAppProvider } from '@/store/app';
import { DataCenterPreloader } from '@/store/app/datacenter';
+import { MessageCenterHandler } from '@/components/message-center-handler';
const ThemeProvider = dynamic(() => import('@/providers/ThemeProvider'), {
ssr: false,
@@ -77,17 +78,19 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
,
]}
>
- {NoNeedAppStatePageList.includes(router.route) ? (
- getLayout()
- ) : (
- }>
-
-
- {getLayout()}
-
-
-
- )}
+
+ {NoNeedAppStatePageList.includes(router.route) ? (
+ getLayout()
+ ) : (
+ }>
+
+
+ {getLayout()}
+
+
+
+ )}
+
>
diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts
index 92118bcaab..83ee50dc23 100644
--- a/packages/data-center/src/datacenter.ts
+++ b/packages/data-center/src/datacenter.ts
@@ -6,23 +6,25 @@ import type {
CreateWorkspaceInfoParams,
UpdateWorkspaceMetaParams,
} from './provider/base';
-import { LocalProvider } from './provider/local/local';
+import { LocalProvider } from './provider/local';
import { AffineProvider } from './provider';
import type { Message } from './types';
import assert from 'assert';
import { getLogger } from './logger';
-import { createBlocksuiteWorkspace } from './utils/index';
+import { createBlocksuiteWorkspace } from './utils';
import { MessageCenter } from './message';
import { WorkspaceUnit } from './workspace-unit';
/**
* @class DataCenter
* @classdesc Data center is made for managing different providers for business
*/
+
export class DataCenter {
private readonly _workspaceUnitCollection = new WorkspaceUnitCollection();
private readonly _logger = getLogger('dc');
private _workspaceInstances: Map = new Map();
private _messageCenter = MessageCenter.getInstance();
+
/**
* A mainProvider must exist as the only data trustworthy source.
*/
@@ -304,7 +306,6 @@ export class DataCenter {
/**
* remove the new member to the workspace
- * @param {number} permissionId permission id
*/
public async removeMember(workspaceId: string, permissionId: number) {
const workspaceInfo = this._workspaceUnitCollection.find(workspaceId);
diff --git a/packages/data-center/src/message/message.ts b/packages/data-center/src/message/message.ts
index 93b75de777..aedfcefa2d 100644
--- a/packages/data-center/src/message/message.ts
+++ b/packages/data-center/src/message/message.ts
@@ -32,5 +32,8 @@ export class MessageCenter extends Observable {
public onMessage(callback: (message: Message) => void) {
this.on('message', callback);
+ return () => {
+ this.off('message', callback);
+ };
}
}
diff --git a/packages/data-center/src/provider/affine/apis/auth.ts b/packages/data-center/src/provider/affine/apis/auth.ts
index 22a256dde4..9eac8cc22f 100644
--- a/packages/data-center/src/provider/affine/apis/auth.ts
+++ b/packages/data-center/src/provider/affine/apis/auth.ts
@@ -105,17 +105,21 @@ export class Auth {
type: 'Refresh',
token: refreshToken || this._refreshToken,
});
- this._padding.finally(() => {
- // clear on settled
- this._padding = undefined;
- });
this._refreshToken = refreshToken || this._refreshToken;
}
- const res = await this._padding;
- if (!refreshToken || refreshToken !== this._refreshToken) {
- this.setLogin(res);
+ try {
+ const res = await this._padding;
+ if (res && (!refreshToken || refreshToken !== this._refreshToken)) {
+ this.setLogin(res);
+ }
+ return true;
+ } catch {
+ this._logger('Failed to refresh token');
+ } finally {
+ // clear on settled
+ this._padding = undefined;
}
- return true;
+ return false;
}
get user() {
diff --git a/packages/data-center/src/provider/affine/apis/request.ts b/packages/data-center/src/provider/affine/apis/request.ts
index 91b3ccbab3..21512b612d 100644
--- a/packages/data-center/src/provider/affine/apis/request.ts
+++ b/packages/data-center/src/provider/affine/apis/request.ts
@@ -14,19 +14,15 @@ export const bareClient: KyInstance = ky.extend({
// todo: report timeout error
timeout: 60000,
hooks: {
- // afterResponse: [
- // async (_request, _options, response) => {
- // if (response.status === 200) {
- // const data = await response.json();
- // if (data.error) {
- // return new Response(data.error.message, {
- // status: data.error.code,
- // });
- // }
- // }
- // return response;
- // },
- // ],
+ beforeError: [
+ error => {
+ const { response } = error;
+ if (response.status === 401) {
+ _sendMessage(MessageCenter.messageCode.noPermission);
+ }
+ return error;
+ },
+ ],
},
});
@@ -59,15 +55,5 @@ export const client: KyInstance = bareClient.extend({
request.headers.set('Authorization', auth.token);
},
],
-
- beforeError: [
- error => {
- const { response } = error;
- if (response.status === 401) {
- _sendMessage(MessageCenter.messageCode.noPermission);
- }
- return error;
- },
- ],
},
});