feat: support offline mode for affine workspace (#1322)

This commit is contained in:
Himself65
2023-03-05 01:51:08 -06:00
committed by GitHub
parent 3e131603dd
commit bd4977e94e
2 changed files with 128 additions and 42 deletions

View File

@@ -26,9 +26,36 @@ const schema = z.object({
type: z.number(), type: z.number(),
public: z.boolean(), public: z.boolean(),
permission: z.number(), permission: z.number(),
create_at: z.number(),
}); });
const getPersistenceAllWorkspace = () => {
const items = storage.getItem(kAffineLocal);
const allWorkspaces: AffineWorkspace[] = [];
if (
Array.isArray(items) &&
items.every(item => schema.safeParse(item).success)
) {
allWorkspaces.push(
...items.map((item: z.infer<typeof schema>) => {
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
item.id,
(k: string) =>
// fixme: token could be expired
({ api: '/api/workspace', token: apis.auth.token }[k])
);
const affineWorkspace: AffineWorkspace = {
...item,
flavour: RemWorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};
return affineWorkspace;
})
);
}
return allWorkspaces;
};
export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = { export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
flavour: RemWorkspaceFlavour.AFFINE, flavour: RemWorkspaceFlavour.AFFINE,
loadPriority: LoadPriority.HIGH, loadPriority: LoadPriority.HIGH,
@@ -38,57 +65,117 @@ export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
blockSuiteWorkspace.doc blockSuiteWorkspace.doc
); );
const { id } = await apis.createWorkspace(new Blob([binary.buffer])); const { id } = await apis.createWorkspace(new Blob([binary.buffer]));
// refresh the local storage
await AffinePlugin.CRUD.list();
return id; return id;
}, },
delete: async workspace => { delete: async workspace => {
const items = storage.getItem(kAffineLocal);
if (
Array.isArray(items) &&
items.every(item => schema.safeParse(item).success)
) {
storage.setItem(
kAffineLocal,
items.filter(item => item.id !== workspace.id)
);
}
await apis.deleteWorkspace({ await apis.deleteWorkspace({
id: workspace.id, id: workspace.id,
}); });
}, },
get: async workspaceId => { get: async workspaceId => {
const workspaces: AffineWorkspace[] = await preload( try {
QueryKey.getWorkspaces, if (!apis.auth.isLogin) {
fetcher const workspaces = getPersistenceAllWorkspace();
); return (
workspaces.find(workspace => workspace.id === workspaceId) ?? null
const workspace = workspaces.find( );
workspace => workspace.id === workspaceId }
); const workspaces: AffineWorkspace[] = await preload(
const dump = workspaces.map(workspace => { QueryKey.getWorkspaces,
return { fetcher
id: workspace.id, );
type: workspace.type, return (
public: workspace.public, workspaces.find(workspace => workspace.id === workspaceId) ?? null
permission: workspace.permission, );
create_at: workspace.create_at, } catch (e) {
} satisfies z.infer<typeof schema>; const workspaces = getPersistenceAllWorkspace();
}); return (
storage.setItem(kAffineLocal, dump); workspaces.find(workspace => workspace.id === workspaceId) ?? null
if (!workspace) { );
return null;
} }
return workspace;
}, },
list: async () => { list: async () => {
// fixme: refactor auth check const allWorkspaces = getPersistenceAllWorkspace();
if (!apis.auth.isLogin) return []; try {
return await apis.getWorkspaces().then(workspaces => { if (apis.auth.isLogin) {
return workspaces.map(workspace => { const workspaces = await apis.getWorkspaces().then(workspaces => {
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace( return workspaces.map(workspace => {
workspace.id, const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
(k: string) => workspace.id,
// fixme: token could be expired (k: string) =>
({ api: '/api/workspace', token: apis.auth.token }[k]) // fixme: token could be expired
); ({ api: '/api/workspace', token: apis.auth.token }[k])
const affineWorkspace: AffineWorkspace = { );
...workspace, const dump = workspaces.map(workspace => {
flavour: RemWorkspaceFlavour.AFFINE, return {
blockSuiteWorkspace, id: workspace.id,
providers: [...createAffineProviders(blockSuiteWorkspace)], type: workspace.type,
}; public: workspace.public,
return affineWorkspace; permission: workspace.permission,
}); } satisfies z.infer<typeof schema>;
}); });
const old = storage.getItem(kAffineLocal);
if (
Array.isArray(old) &&
old.every(item => schema.safeParse(item).success)
) {
const data = [...dump];
old.forEach((item: z.infer<typeof schema>) => {
const has = dump.find(dump => dump.id === item.id);
if (!has) {
data.push(item);
}
});
storage.setItem(kAffineLocal, [...data]);
}
const affineWorkspace: AffineWorkspace = {
...workspace,
flavour: RemWorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};
return affineWorkspace;
});
});
workspaces.forEach(workspace => {
const idx = allWorkspaces.findIndex(
({ id }) => id === workspace.id
);
if (idx !== -1) {
allWorkspaces.splice(idx, 1, workspace);
} else {
allWorkspaces.push(workspace);
}
});
// only save data when login in
const dump = allWorkspaces.map(workspace => {
return {
id: workspace.id,
type: workspace.type,
public: workspace.public,
permission: workspace.permission,
} satisfies z.infer<typeof schema>;
});
storage.setItem(kAffineLocal, [...dump]);
}
} catch (e) {
console.error('fetch affine workspaces failed', e);
}
return [...allWorkspaces];
}, },
}, },
PageDetail: ({ currentWorkspace, currentPageId }) => { PageDetail: ({ currentWorkspace, currentPageId }) => {

View File

@@ -32,7 +32,6 @@ export interface Workspace {
type: WorkspaceType; type: WorkspaceType;
public: boolean; public: boolean;
permission: PermissionType; permission: PermissionType;
create_at: number;
} }
export interface WorkspaceDetail extends Workspace { export interface WorkspaceDetail extends Workspace {