mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 14:56:59 +08:00
fix: circular dependencies (#4307)
This commit is contained in:
@@ -6,7 +6,7 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
|||||||
import { ArrowRightSmallIcon } from '@blocksuite/icons';
|
import { ArrowRightSmallIcon } from '@blocksuite/icons';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import type { WorkspaceSettingDetailProps } from '../index';
|
import type { WorkspaceSettingDetailProps } from '../types';
|
||||||
import { WorkspaceDeleteModal } from './delete';
|
import { WorkspaceDeleteModal } from './delete';
|
||||||
|
|
||||||
export interface DeleteLeaveWorkspaceProps extends WorkspaceSettingDetailProps {
|
export interface DeleteLeaveWorkspaceProps extends WorkspaceSettingDetailProps {
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ import {
|
|||||||
SettingRow,
|
SettingRow,
|
||||||
SettingWrapper,
|
SettingWrapper,
|
||||||
} from '@affine/component/setting-components';
|
} from '@affine/component/setting-components';
|
||||||
import type {
|
|
||||||
WorkspaceFlavour,
|
|
||||||
WorkspaceRegistry,
|
|
||||||
} from '@affine/env/workspace';
|
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
@@ -19,22 +15,7 @@ import { MembersPanel } from './members';
|
|||||||
import { ProfilePanel } from './profile';
|
import { ProfilePanel } from './profile';
|
||||||
import { PublishPanel } from './publish';
|
import { PublishPanel } from './publish';
|
||||||
import { StoragePanel } from './storage';
|
import { StoragePanel } from './storage';
|
||||||
|
import type { WorkspaceSettingDetailProps } from './types';
|
||||||
export interface WorkspaceSettingDetailProps {
|
|
||||||
workspaceId: string;
|
|
||||||
isOwner: boolean;
|
|
||||||
onDeleteLocalWorkspace: () => void;
|
|
||||||
onDeleteCloudWorkspace: () => void;
|
|
||||||
onLeaveWorkspace: () => void;
|
|
||||||
onTransferWorkspace: <
|
|
||||||
From extends WorkspaceFlavour,
|
|
||||||
To extends WorkspaceFlavour,
|
|
||||||
>(
|
|
||||||
from: From,
|
|
||||||
to: To,
|
|
||||||
workspace: WorkspaceRegistry[From]
|
|
||||||
) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => {
|
export const WorkspaceSettingDetail = (props: WorkspaceSettingDetailProps) => {
|
||||||
const { workspaceId } = props;
|
const { workspaceId } = props;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { AffineOfficialWorkspace } from '@affine/env/workspace';
|
import type { AffineOfficialWorkspace } from '@affine/env/workspace';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { type WorkspaceSettingDetailProps } from './index';
|
|
||||||
import * as style from './style.css';
|
import * as style from './style.css';
|
||||||
|
import type { WorkspaceSettingDetailProps } from './types';
|
||||||
|
|
||||||
export interface LabelsPanelProps extends WorkspaceSettingDetailProps {
|
export interface LabelsPanelProps extends WorkspaceSettingDetailProps {
|
||||||
workspace: AffineOfficialWorkspace;
|
workspace: AffineOfficialWorkspace;
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import { useInviteMember } from '../../../hooks/affine/use-invite-member';
|
|||||||
import { type Member, useMembers } from '../../../hooks/affine/use-members';
|
import { type Member, useMembers } from '../../../hooks/affine/use-members';
|
||||||
import { useRevokeMemberPermission } from '../../../hooks/affine/use-revoke-member-permission';
|
import { useRevokeMemberPermission } from '../../../hooks/affine/use-revoke-member-permission';
|
||||||
import { AnyErrorBoundary } from '../any-error-boundary';
|
import { AnyErrorBoundary } from '../any-error-boundary';
|
||||||
import { type WorkspaceSettingDetailProps } from './index';
|
|
||||||
import * as style from './style.css';
|
import * as style from './style.css';
|
||||||
|
import type { WorkspaceSettingDetailProps } from './types';
|
||||||
|
|
||||||
export interface MembersPanelProps extends WorkspaceSettingDetailProps {
|
export interface MembersPanelProps extends WorkspaceSettingDetailProps {
|
||||||
workspace: AffineOfficialWorkspace;
|
workspace: AffineOfficialWorkspace;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import { Upload } from '../../pure/file-upload';
|
import { Upload } from '../../pure/file-upload';
|
||||||
import { type WorkspaceSettingDetailProps } from './index';
|
|
||||||
import * as style from './style.css';
|
import * as style from './style.css';
|
||||||
|
import type { WorkspaceSettingDetailProps } from './types';
|
||||||
|
|
||||||
export interface ProfilePanelProps extends WorkspaceSettingDetailProps {
|
export interface ProfilePanelProps extends WorkspaceSettingDetailProps {
|
||||||
workspace: AffineOfficialWorkspace;
|
workspace: AffineOfficialWorkspace;
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { toast } from '../../../utils';
|
import { toast } from '../../../utils';
|
||||||
import { EnableAffineCloudModal } from '../enable-affine-cloud-modal';
|
import { EnableAffineCloudModal } from '../enable-affine-cloud-modal';
|
||||||
import { TmpDisableAffineCloudModal } from '../tmp-disable-affine-cloud-modal';
|
import { TmpDisableAffineCloudModal } from '../tmp-disable-affine-cloud-modal';
|
||||||
import type { WorkspaceSettingDetailProps } from './index';
|
|
||||||
import * as style from './style.css';
|
import * as style from './style.css';
|
||||||
|
import type { WorkspaceSettingDetailProps } from './types';
|
||||||
|
|
||||||
export interface PublishPanelProps
|
export interface PublishPanelProps
|
||||||
extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
|
extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import type {
|
||||||
|
WorkspaceFlavour,
|
||||||
|
WorkspaceRegistry,
|
||||||
|
} from '@affine/env/workspace';
|
||||||
|
|
||||||
|
export interface WorkspaceSettingDetailProps {
|
||||||
|
workspaceId: string;
|
||||||
|
isOwner: boolean;
|
||||||
|
onDeleteLocalWorkspace: () => void;
|
||||||
|
onDeleteCloudWorkspace: () => void;
|
||||||
|
onLeaveWorkspace: () => void;
|
||||||
|
onTransferWorkspace: <
|
||||||
|
From extends WorkspaceFlavour,
|
||||||
|
To extends WorkspaceFlavour,
|
||||||
|
>(
|
||||||
|
from: From,
|
||||||
|
to: To,
|
||||||
|
workspace: WorkspaceRegistry[From]
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
@@ -25,7 +25,8 @@ import {
|
|||||||
} from 'rxjs/operators';
|
} from 'rxjs/operators';
|
||||||
|
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import { getWorkspaceMeta, workspaceSubjects } from '../workspace';
|
import { getWorkspaceMeta } from '../workspace/meta';
|
||||||
|
import { workspaceSubjects } from '../workspace/subjects';
|
||||||
import { SecondaryWorkspaceSQLiteDB } from './secondary-db';
|
import { SecondaryWorkspaceSQLiteDB } from './secondary-db';
|
||||||
import type { WorkspaceSQLiteDB } from './workspace-db-adapter';
|
import type { WorkspaceSQLiteDB } from './workspace-db-adapter';
|
||||||
import { openWorkspaceDatabase } from './workspace-db-adapter';
|
import { openWorkspaceDatabase } from './workspace-db-adapter';
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { applyUpdate, Doc as YDoc } from 'yjs';
|
|||||||
|
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import type { YOrigin } from '../type';
|
import type { YOrigin } from '../type';
|
||||||
import { getWorkspaceMeta } from '../workspace';
|
import { getWorkspaceMeta } from '../workspace/meta';
|
||||||
import { BaseSQLiteAdapter } from './base-db-adapter';
|
import { BaseSQLiteAdapter } from './base-db-adapter';
|
||||||
import type { WorkspaceSQLiteDB } from './workspace-db-adapter';
|
import type { WorkspaceSQLiteDB } from './workspace-db-adapter';
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { applyUpdate, Doc as YDoc, encodeStateAsUpdate } from 'yjs';
|
|||||||
|
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import type { YOrigin } from '../type';
|
import type { YOrigin } from '../type';
|
||||||
import { getWorkspaceMeta } from '../workspace';
|
import { getWorkspaceMeta } from '../workspace/meta';
|
||||||
import { BaseSQLiteAdapter } from './base-db-adapter';
|
import { BaseSQLiteAdapter } from './base-db-adapter';
|
||||||
import { dbSubjects } from './subjects';
|
import { dbSubjects } from './subjects';
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,12 @@ import {
|
|||||||
import type { WorkspaceSQLiteDB } from '../db/workspace-db-adapter';
|
import type { WorkspaceSQLiteDB } from '../db/workspace-db-adapter';
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import { mainRPC } from '../main-rpc';
|
import { mainRPC } from '../main-rpc';
|
||||||
|
import { listWorkspaces, storeWorkspaceMeta } from '../workspace';
|
||||||
import {
|
import {
|
||||||
getWorkspaceDBPath,
|
getWorkspaceDBPath,
|
||||||
getWorkspaceMeta,
|
getWorkspaceMeta,
|
||||||
getWorkspacesBasePath,
|
getWorkspacesBasePath,
|
||||||
listWorkspaces,
|
} from '../workspace/meta';
|
||||||
storeWorkspaceMeta,
|
|
||||||
} from '../workspace';
|
|
||||||
|
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// we are using native dialogs because HTML dialogs do not give full file paths
|
// we are using native dialogs because HTML dialogs do not give full file paths
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type {
|
|||||||
|
|
||||||
import { dbEvents, dbHandlers } from './db';
|
import { dbEvents, dbHandlers } from './db';
|
||||||
import { dialogHandlers } from './dialog';
|
import { dialogHandlers } from './dialog';
|
||||||
|
import { provideExposed } from './provide';
|
||||||
import { workspaceEvents, workspaceHandlers } from './workspace';
|
import { workspaceEvents, workspaceHandlers } from './workspace';
|
||||||
|
|
||||||
type AllHandlers = {
|
type AllHandlers = {
|
||||||
@@ -25,7 +26,7 @@ export const events = {
|
|||||||
workspace: workspaceEvents,
|
workspace: workspaceEvents,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getExposedMeta = () => {
|
const getExposedMeta = () => {
|
||||||
const handlersMeta = Object.entries(handlers).map(
|
const handlersMeta = Object.entries(handlers).map(
|
||||||
([namespace, namespaceHandlers]) => {
|
([namespace, namespaceHandlers]) => {
|
||||||
return [namespace, Object.keys(namespaceHandlers)] as [string, string[]];
|
return [namespace, Object.keys(namespaceHandlers)] as [string, string[]];
|
||||||
@@ -43,3 +44,5 @@ export const getExposedMeta = () => {
|
|||||||
events: eventsMeta,
|
events: eventsMeta,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
provideExposed(getExposedMeta());
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
|
import { assertExists } from '@blocksuite/global/utils';
|
||||||
import type {
|
import type {
|
||||||
HelperToMain,
|
HelperToMain,
|
||||||
MainToHelper,
|
MainToHelper,
|
||||||
} from '@toeverything/infra/preload/electron';
|
} from '@toeverything/infra/preload/electron';
|
||||||
import { AsyncCall } from 'async-call-rpc';
|
import { AsyncCall } from 'async-call-rpc';
|
||||||
|
|
||||||
import { getExposedMeta } from './exposed';
|
import { exposed } from './provide';
|
||||||
|
|
||||||
const helperToMainServer: HelperToMain = {
|
const helperToMainServer: HelperToMain = {
|
||||||
getMeta: () => getExposedMeta(),
|
getMeta: () => {
|
||||||
|
assertExists(exposed);
|
||||||
|
return exposed;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mainRPC = AsyncCall<MainToHelper>(helperToMainServer, {
|
export const mainRPC = AsyncCall<MainToHelper>(helperToMainServer, {
|
||||||
|
|||||||
11
apps/electron/src/helper/provide.ts
Normal file
11
apps/electron/src/helper/provide.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import type { ExposedMeta } from '@toeverything/infra/preload/electron';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A naive DI implementation to get rid of circular dependency.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export let exposed: ExposedMeta | undefined;
|
||||||
|
|
||||||
|
export const provideExposed = (exposedMeta: ExposedMeta) => {
|
||||||
|
exposed = exposedMeta;
|
||||||
|
};
|
||||||
@@ -74,7 +74,7 @@ describe('delete workspace', () => {
|
|||||||
|
|
||||||
describe('getWorkspaceMeta', () => {
|
describe('getWorkspaceMeta', () => {
|
||||||
test('can get meta', async () => {
|
test('can get meta', async () => {
|
||||||
const { getWorkspaceMeta } = await import('../handlers');
|
const { getWorkspaceMeta } = await import('../meta');
|
||||||
const workspaceId = v4();
|
const workspaceId = v4();
|
||||||
const workspacePath = path.join(appDataPath, 'workspaces', workspaceId);
|
const workspacePath = path.join(appDataPath, 'workspaces', workspaceId);
|
||||||
const meta = {
|
const meta = {
|
||||||
@@ -86,7 +86,7 @@ describe('getWorkspaceMeta', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('can create meta if not exists', async () => {
|
test('can create meta if not exists', async () => {
|
||||||
const { getWorkspaceMeta } = await import('../handlers');
|
const { getWorkspaceMeta } = await import('../meta');
|
||||||
const workspaceId = v4();
|
const workspaceId = v4();
|
||||||
const workspacePath = path.join(appDataPath, 'workspaces', workspaceId);
|
const workspacePath = path.join(appDataPath, 'workspaces', workspaceId);
|
||||||
await fs.ensureDir(workspacePath);
|
await fs.ensureDir(workspacePath);
|
||||||
@@ -100,7 +100,7 @@ describe('getWorkspaceMeta', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('can migrate meta if db file is a link', async () => {
|
test('can migrate meta if db file is a link', async () => {
|
||||||
const { getWorkspaceMeta } = await import('../handlers');
|
const { getWorkspaceMeta } = await import('../meta');
|
||||||
const workspaceId = v4();
|
const workspaceId = v4();
|
||||||
const workspacePath = path.join(appDataPath, 'workspaces', workspaceId);
|
const workspacePath = path.join(appDataPath, 'workspaces', workspaceId);
|
||||||
await fs.ensureDir(workspacePath);
|
await fs.ensureDir(workspacePath);
|
||||||
|
|||||||
@@ -4,20 +4,15 @@ import fs from 'fs-extra';
|
|||||||
|
|
||||||
import { ensureSQLiteDB } from '../db/ensure-db';
|
import { ensureSQLiteDB } from '../db/ensure-db';
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
import { mainRPC } from '../main-rpc';
|
|
||||||
import type { WorkspaceMeta } from '../type';
|
import type { WorkspaceMeta } from '../type';
|
||||||
|
import {
|
||||||
|
getDeletedWorkspacesBasePath,
|
||||||
|
getWorkspaceBasePath,
|
||||||
|
getWorkspaceMeta,
|
||||||
|
getWorkspacesBasePath,
|
||||||
|
} from './meta';
|
||||||
import { workspaceSubjects } from './subjects';
|
import { workspaceSubjects } from './subjects';
|
||||||
|
|
||||||
let _appDataPath = '';
|
|
||||||
|
|
||||||
async function getAppDataPath() {
|
|
||||||
if (_appDataPath) {
|
|
||||||
return _appDataPath;
|
|
||||||
}
|
|
||||||
_appDataPath = await mainRPC.getPath('sessionData');
|
|
||||||
return _appDataPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listWorkspaces(): Promise<
|
export async function listWorkspaces(): Promise<
|
||||||
[workspaceId: string, meta: WorkspaceMeta][]
|
[workspaceId: string, meta: WorkspaceMeta][]
|
||||||
> {
|
> {
|
||||||
@@ -58,67 +53,6 @@ export async function deleteWorkspace(id: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getWorkspacesBasePath() {
|
|
||||||
return path.join(await getAppDataPath(), 'workspaces');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWorkspaceBasePath(workspaceId: string) {
|
|
||||||
return path.join(await getAppDataPath(), 'workspaces', workspaceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getDeletedWorkspacesBasePath() {
|
|
||||||
return path.join(await getAppDataPath(), 'deleted-workspaces');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWorkspaceDBPath(workspaceId: string) {
|
|
||||||
return path.join(await getWorkspaceBasePath(workspaceId), 'storage.db');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getWorkspaceMetaPath(workspaceId: string) {
|
|
||||||
return path.join(await getWorkspaceBasePath(workspaceId), 'meta.json');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get workspace meta, create one if not exists
|
|
||||||
* This function will also migrate the workspace if needed
|
|
||||||
*/
|
|
||||||
export async function getWorkspaceMeta(
|
|
||||||
workspaceId: string
|
|
||||||
): Promise<WorkspaceMeta> {
|
|
||||||
try {
|
|
||||||
const basePath = await getWorkspaceBasePath(workspaceId);
|
|
||||||
const metaPath = await getWorkspaceMetaPath(workspaceId);
|
|
||||||
if (!(await fs.exists(metaPath))) {
|
|
||||||
// since not meta is found, we will migrate symlinked db file if needed
|
|
||||||
await fs.ensureDir(basePath);
|
|
||||||
const dbPath = await getWorkspaceDBPath(workspaceId);
|
|
||||||
|
|
||||||
// todo: remove this after migration (in stable version)
|
|
||||||
const realDBPath = (await fs.exists(dbPath))
|
|
||||||
? await fs.realpath(dbPath)
|
|
||||||
: dbPath;
|
|
||||||
const isLink = realDBPath !== dbPath;
|
|
||||||
if (isLink) {
|
|
||||||
await fs.copy(realDBPath, dbPath);
|
|
||||||
}
|
|
||||||
// create one if not exists
|
|
||||||
const meta = {
|
|
||||||
id: workspaceId,
|
|
||||||
mainDBPath: dbPath,
|
|
||||||
secondaryDBPath: isLink ? realDBPath : undefined,
|
|
||||||
};
|
|
||||||
await fs.writeJSON(metaPath, meta);
|
|
||||||
return meta;
|
|
||||||
} else {
|
|
||||||
const meta = await fs.readJSON(metaPath);
|
|
||||||
return meta;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
logger.error('getWorkspaceMeta failed', err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function storeWorkspaceMeta(
|
export async function storeWorkspaceMeta(
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
meta: Partial<WorkspaceMeta>
|
meta: Partial<WorkspaceMeta>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { MainEventRegister, WorkspaceMeta } from '../type';
|
import type { MainEventRegister, WorkspaceMeta } from '../type';
|
||||||
import { deleteWorkspace, getWorkspaceMeta, listWorkspaces } from './handlers';
|
import { deleteWorkspace, listWorkspaces } from './handlers';
|
||||||
|
import { getWorkspaceMeta } from './meta';
|
||||||
import { workspaceSubjects } from './subjects';
|
import { workspaceSubjects } from './subjects';
|
||||||
|
|
||||||
export * from './handlers';
|
export * from './handlers';
|
||||||
|
|||||||
78
apps/electron/src/helper/workspace/meta.ts
Normal file
78
apps/electron/src/helper/workspace/meta.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
|
||||||
|
import { logger } from '../logger';
|
||||||
|
import { mainRPC } from '../main-rpc';
|
||||||
|
import type { WorkspaceMeta } from '../type';
|
||||||
|
|
||||||
|
let _appDataPath = '';
|
||||||
|
|
||||||
|
export async function getAppDataPath() {
|
||||||
|
if (_appDataPath) {
|
||||||
|
return _appDataPath;
|
||||||
|
}
|
||||||
|
_appDataPath = await mainRPC.getPath('sessionData');
|
||||||
|
return _appDataPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWorkspacesBasePath() {
|
||||||
|
return path.join(await getAppDataPath(), 'workspaces');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWorkspaceBasePath(workspaceId: string) {
|
||||||
|
return path.join(await getAppDataPath(), 'workspaces', workspaceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDeletedWorkspacesBasePath() {
|
||||||
|
return path.join(await getAppDataPath(), 'deleted-workspaces');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWorkspaceDBPath(workspaceId: string) {
|
||||||
|
return path.join(await getWorkspaceBasePath(workspaceId), 'storage.db');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getWorkspaceMetaPath(workspaceId: string) {
|
||||||
|
return path.join(await getWorkspaceBasePath(workspaceId), 'meta.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get workspace meta, create one if not exists
|
||||||
|
* This function will also migrate the workspace if needed
|
||||||
|
*/
|
||||||
|
export async function getWorkspaceMeta(
|
||||||
|
workspaceId: string
|
||||||
|
): Promise<WorkspaceMeta> {
|
||||||
|
try {
|
||||||
|
const basePath = await getWorkspaceBasePath(workspaceId);
|
||||||
|
const metaPath = await getWorkspaceMetaPath(workspaceId);
|
||||||
|
if (!(await fs.exists(metaPath))) {
|
||||||
|
// since not meta is found, we will migrate symlinked db file if needed
|
||||||
|
await fs.ensureDir(basePath);
|
||||||
|
const dbPath = await getWorkspaceDBPath(workspaceId);
|
||||||
|
|
||||||
|
// todo: remove this after migration (in stable version)
|
||||||
|
const realDBPath = (await fs.exists(dbPath))
|
||||||
|
? await fs.realpath(dbPath)
|
||||||
|
: dbPath;
|
||||||
|
const isLink = realDBPath !== dbPath;
|
||||||
|
if (isLink) {
|
||||||
|
await fs.copy(realDBPath, dbPath);
|
||||||
|
}
|
||||||
|
// create one if not exists
|
||||||
|
const meta = {
|
||||||
|
id: workspaceId,
|
||||||
|
mainDBPath: dbPath,
|
||||||
|
secondaryDBPath: isLink ? realDBPath : undefined,
|
||||||
|
};
|
||||||
|
await fs.writeJSON(metaPath, meta);
|
||||||
|
return meta;
|
||||||
|
} else {
|
||||||
|
const meta = await fs.readJSON(metaPath);
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('getWorkspaceMeta failed', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
import {
|
|
||||||
CollectionBar,
|
|
||||||
type CollectionsAtom,
|
|
||||||
} from '@affine/component/page-list';
|
|
||||||
import { DEFAULT_SORT_KEY } from '@affine/env/constant';
|
import { DEFAULT_SORT_KEY } from '@affine/env/constant';
|
||||||
import type { PropertiesMeta } from '@affine/env/filter';
|
import type { PropertiesMeta } from '@affine/env/filter';
|
||||||
import type { GetPageInfoById } from '@affine/env/page-info';
|
import type { GetPageInfoById } from '@affine/env/page-info';
|
||||||
@@ -28,8 +24,10 @@ import { AllPageListMobileView, TrashListMobileView } from './mobile';
|
|||||||
import { TrashOperationCell } from './operation-cell';
|
import { TrashOperationCell } from './operation-cell';
|
||||||
import { StyledTableContainer } from './styles';
|
import { StyledTableContainer } from './styles';
|
||||||
import type { ListData, PageListProps, TrashListData } from './type';
|
import type { ListData, PageListProps, TrashListData } from './type';
|
||||||
|
import type { CollectionsAtom } from './use-collection-manager';
|
||||||
import { useSorter } from './use-sorter';
|
import { useSorter } from './use-sorter';
|
||||||
import { formatDate, useIsSmallDevices } from './utils';
|
import { formatDate, useIsSmallDevices } from './utils';
|
||||||
|
import { CollectionBar } from './view/collection-bar';
|
||||||
|
|
||||||
interface AllPagesHeadProps {
|
interface AllPagesHeadProps {
|
||||||
isPublicWorkspace: boolean;
|
isPublicWorkspace: boolean;
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import {
|
|
||||||
type CollectionsAtom,
|
|
||||||
EditCollectionModel,
|
|
||||||
} from '@affine/component/page-list';
|
|
||||||
import type { PropertiesMeta } from '@affine/env/filter';
|
import type { PropertiesMeta } from '@affine/env/filter';
|
||||||
import type { GetPageInfoById } from '@affine/env/page-info';
|
import type { GetPageInfoById } from '@affine/env/page-info';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
@@ -11,8 +7,12 @@ import { Tooltip } from '@toeverything/components/tooltip';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
import { useCollectionManager } from '../use-collection-manager';
|
import {
|
||||||
|
type CollectionsAtom,
|
||||||
|
useCollectionManager,
|
||||||
|
} from '../use-collection-manager';
|
||||||
import * as styles from './collection-bar.css';
|
import * as styles from './collection-bar.css';
|
||||||
|
import { EditCollectionModel } from './create-collection';
|
||||||
import { useActions } from './use-action';
|
import { useActions } from './use-action';
|
||||||
|
|
||||||
interface CollectionBarProps {
|
interface CollectionBarProps {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { FlexWrapper } from '@affine/component';
|
import { FlexWrapper } from '@affine/component';
|
||||||
import { EditCollectionModel } from '@affine/component/page-list';
|
|
||||||
import type { Collection, Filter } from '@affine/env/filter';
|
import type { Collection, Filter } from '@affine/env/filter';
|
||||||
import type { PropertiesMeta } from '@affine/env/filter';
|
import type { PropertiesMeta } from '@affine/env/filter';
|
||||||
import type { GetPageInfoById } from '@affine/env/page-info';
|
import type { GetPageInfoById } from '@affine/env/page-info';
|
||||||
@@ -15,6 +14,7 @@ import { useCallback, useRef, useState } from 'react';
|
|||||||
import { CreateFilterMenu } from '../filter/vars';
|
import { CreateFilterMenu } from '../filter/vars';
|
||||||
import type { useCollectionManager } from '../use-collection-manager';
|
import type { useCollectionManager } from '../use-collection-manager';
|
||||||
import * as styles from './collection-list.css';
|
import * as styles from './collection-list.css';
|
||||||
|
import { EditCollectionModel } from './create-collection';
|
||||||
import { useActions } from './use-action';
|
import { useActions } from './use-action';
|
||||||
|
|
||||||
const CollectionOption = ({
|
const CollectionOption = ({
|
||||||
|
|||||||
Reference in New Issue
Block a user