mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-11-22 09:13:18 +03:00
refactor: init package @affine/workspace
(#1661)
This commit is contained in:
parent
84d27e939d
commit
69721f2a61
@ -15,6 +15,7 @@
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/i18n": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"@affine/workspace": "workspace:*",
|
||||
"@blocksuite/blocks": "0.5.0-20230323085636-3110abb",
|
||||
"@blocksuite/editor": "0.5.0-20230323085636-3110abb",
|
||||
"@blocksuite/icons": "2.0.23",
|
||||
|
@ -1,3 +1,4 @@
|
||||
import type { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
@ -6,7 +7,7 @@ import { atomWithStorage } from 'jotai/utils';
|
||||
import { unstable_batchedUpdates } from 'react-dom';
|
||||
|
||||
import { WorkspacePlugins } from '../plugins';
|
||||
import type { RemWorkspace, RemWorkspaceFlavour } from '../shared';
|
||||
import type { RemWorkspace } from '../shared';
|
||||
// workspace necessary atoms
|
||||
export const currentWorkspaceIdAtom = atom<string | null>(null);
|
||||
export const currentPageIdAtom = atom<string | null>(null);
|
||||
@ -37,7 +38,7 @@ export const jotaiStore = createStore();
|
||||
|
||||
type JotaiWorkspace = {
|
||||
id: string;
|
||||
flavour: RemWorkspaceFlavour;
|
||||
flavour: WorkspaceFlavour;
|
||||
};
|
||||
|
||||
export const jotaiWorkspacesAtom = atomWithStorage<JotaiWorkspace[]>(
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { atom } from 'jotai/index';
|
||||
|
||||
import { BlockSuiteWorkspace } from '../../shared';
|
||||
import { apis } from '../../shared/apis';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
||||
|
||||
export const publicWorkspaceIdAtom = atom<string | null>(null);
|
||||
export const publicBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
|
||||
|
@ -1,11 +1,11 @@
|
||||
'use client';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { Generator } from '@blocksuite/store';
|
||||
import type React from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import { createEmptyBlockSuiteWorkspace } from '../../../utils';
|
||||
import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
|
||||
|
||||
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
||||
|
@ -3,6 +3,7 @@
|
||||
*/
|
||||
import 'fake-indexeddb/auto';
|
||||
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import { render, renderHook } from '@testing-library/react';
|
||||
import { createStore, getDefaultStore, Provider } from 'jotai';
|
||||
@ -20,7 +21,7 @@ import {
|
||||
import { useBlockSuiteWorkspaceHelper } from '../../hooks/use-blocksuite-workspace-helper';
|
||||
import { useWorkspacesHelper } from '../../hooks/use-workspaces';
|
||||
import { ThemeProvider } from '../../providers/ThemeProvider';
|
||||
import { pathGenerator, RemWorkspaceFlavour } from '../../shared';
|
||||
import { pathGenerator } from '../../shared';
|
||||
import { WorkSpaceSliderBar } from '../pure/workspace-slider-bar';
|
||||
|
||||
vi.mock('../blocksuite/header/editor-mode-switch/CustomLottie', () => ({
|
||||
@ -92,7 +93,7 @@ describe('WorkSpaceSliderBar', () => {
|
||||
currentWorkspaceHook.result.current[1](id);
|
||||
const currentWorkspace = await store.get(currentWorkspaceAtom);
|
||||
expect(currentWorkspace).toBeDefined();
|
||||
expect(currentWorkspace?.flavour).toBe(RemWorkspaceFlavour.LOCAL);
|
||||
expect(currentWorkspace?.flavour).toBe(WorkspaceFlavour.LOCAL);
|
||||
expect(currentWorkspace?.id).toBe(id);
|
||||
const app = render(<App />);
|
||||
const card = await app.findByTestId('current-workspace');
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import type { SettingPanel, WorkspaceRegistry } from '@affine/workspace/type';
|
||||
import { settingPanel, WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type { MouseEvent } from 'react';
|
||||
import type React from 'react';
|
||||
import { Suspense, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
@ -6,12 +8,7 @@ import { preload } from 'swr';
|
||||
|
||||
import { useIsWorkspaceOwner } from '../../../hooks/affine/use-is-workspace-owner';
|
||||
import { fetcher, QueryKey } from '../../../plugins/affine/fetcher';
|
||||
import type {
|
||||
AffineOfficialWorkspace,
|
||||
FlavourToWorkspace,
|
||||
SettingPanel,
|
||||
} from '../../../shared';
|
||||
import { RemWorkspaceFlavour, settingPanel } from '../../../shared';
|
||||
import type { AffineOfficialWorkspace } from '../../../shared';
|
||||
import { CollaborationPanel } from './panel/collaboration';
|
||||
import { ExportPanel } from './panel/export';
|
||||
import { GeneralPanel } from './panel/general';
|
||||
@ -31,12 +28,12 @@ export type WorkspaceSettingDetailProps = {
|
||||
onChangeTab: (tab: SettingPanel) => void;
|
||||
onDeleteWorkspace: () => void;
|
||||
onTransferWorkspace: <
|
||||
From extends RemWorkspaceFlavour,
|
||||
To extends RemWorkspaceFlavour
|
||||
From extends WorkspaceFlavour,
|
||||
To extends WorkspaceFlavour
|
||||
>(
|
||||
from: From,
|
||||
to: To,
|
||||
workspace: FlavourToWorkspace[From]
|
||||
workspace: WorkspaceRegistry[From]
|
||||
) => void;
|
||||
};
|
||||
|
||||
@ -49,8 +46,7 @@ const panelMap = {
|
||||
},
|
||||
[settingPanel.Sync]: {
|
||||
name: 'Sync',
|
||||
enable: (flavour: RemWorkspaceFlavour) =>
|
||||
flavour === RemWorkspaceFlavour.AFFINE,
|
||||
enable: (flavour: WorkspaceFlavour) => flavour === WorkspaceFlavour.AFFINE,
|
||||
ui: SyncPanel,
|
||||
},
|
||||
[settingPanel.Collaboration]: {
|
||||
@ -68,7 +64,7 @@ const panelMap = {
|
||||
} satisfies {
|
||||
[Key in SettingPanel]: {
|
||||
name: string;
|
||||
enable?: (flavour: RemWorkspaceFlavour) => boolean;
|
||||
enable?: (flavour: WorkspaceFlavour) => boolean;
|
||||
ui: React.FC<PanelProps>;
|
||||
};
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
} from '@affine/component';
|
||||
import { PermissionType } from '@affine/datacenter';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import {
|
||||
DeleteTemporarilyIcon,
|
||||
EmailIcon,
|
||||
@ -18,7 +19,6 @@ import { useCallback, useState } from 'react';
|
||||
|
||||
import { useMembers } from '../../../../../hooks/affine/use-members';
|
||||
import type { AffineWorkspace, LocalWorkspace } from '../../../../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../../../../shared';
|
||||
import { Unreachable } from '../../../affine-error-eoundary';
|
||||
import { TransformWorkspaceToAffineModal } from '../../../transform-workspace-to-affine-modal';
|
||||
import type { PanelProps } from '../../index';
|
||||
@ -194,8 +194,8 @@ const LocalCollaborationPanel: React.FC<
|
||||
}}
|
||||
onConform={() => {
|
||||
onTransferWorkspace(
|
||||
RemWorkspaceFlavour.LOCAL,
|
||||
RemWorkspaceFlavour.AFFINE,
|
||||
WorkspaceFlavour.LOCAL,
|
||||
WorkspaceFlavour.AFFINE,
|
||||
workspace
|
||||
);
|
||||
setOpen(false);
|
||||
@ -207,13 +207,13 @@ const LocalCollaborationPanel: React.FC<
|
||||
|
||||
export const CollaborationPanel: React.FC<PanelProps> = props => {
|
||||
switch (props.workspace.flavour) {
|
||||
case RemWorkspaceFlavour.AFFINE: {
|
||||
case WorkspaceFlavour.AFFINE: {
|
||||
const workspace = props.workspace as AffineWorkspace;
|
||||
return (
|
||||
<AffineRemoteCollaborationPanel {...props} workspace={workspace} />
|
||||
);
|
||||
}
|
||||
case RemWorkspaceFlavour.LOCAL: {
|
||||
case WorkspaceFlavour.LOCAL: {
|
||||
const workspace = props.workspace as LocalWorkspace;
|
||||
return <LocalCollaborationPanel {...props} workspace={workspace} />;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Button, Input, Modal, ModalCloseButton } from '@affine/component';
|
||||
import { Trans, useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { useBlockSuiteWorkspaceName } from '../../../../../../hooks/use-blocksuite-workspace-name';
|
||||
import type { AffineOfficialWorkspace } from '../../../../../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../../../../../shared';
|
||||
import {
|
||||
StyledButtonContent,
|
||||
StyledInputContent,
|
||||
@ -43,7 +43,7 @@ export const WorkspaceDeleteModal = ({
|
||||
<StyledModalWrapper>
|
||||
<ModalCloseButton onClick={onClose} />
|
||||
<StyledModalHeader>{t('Delete Workspace')}?</StyledModalHeader>
|
||||
{workspace.flavour === RemWorkspaceFlavour.LOCAL ? (
|
||||
{workspace.flavour === WorkspaceFlavour.LOCAL ? (
|
||||
<StyledTextContent>
|
||||
<Trans i18nKey="Delete Workspace Description">
|
||||
Deleting (
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Button, FlexWrapper, MuiFade } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type React from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useIsWorkspaceOwner } from '../../../../../hooks/affine/use-is-workspace-owner';
|
||||
import { useBlockSuiteWorkspaceAvatarUrl } from '../../../../../hooks/use-blocksuite-workspace-avatar-url';
|
||||
import { useBlockSuiteWorkspaceName } from '../../../../../hooks/use-blocksuite-workspace-name';
|
||||
import { RemWorkspaceFlavour } from '../../../../../shared';
|
||||
import { Upload } from '../../../../pure/file-upload';
|
||||
import {
|
||||
CloudWorkspaceIcon,
|
||||
@ -161,7 +161,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
|
||||
<StyledRow>
|
||||
<StyledSettingKey>{t('Workspace Type')}</StyledSettingKey>
|
||||
{isOwner ? (
|
||||
workspace.flavour === RemWorkspaceFlavour.LOCAL ? (
|
||||
workspace.flavour === WorkspaceFlavour.LOCAL ? (
|
||||
<StyledWorkspaceInfo>
|
||||
<LocalWorkspaceIcon />
|
||||
<span>{t('Local Workspace')}</span>
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
Wrapper,
|
||||
} from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { Box } from '@mui/material';
|
||||
import type React from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
@ -17,7 +18,6 @@ import type {
|
||||
AffineWorkspace,
|
||||
LocalWorkspace,
|
||||
} from '../../../../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../../../../shared';
|
||||
import { Unreachable } from '../../../affine-error-eoundary';
|
||||
import { EnableAffineCloudModal } from '../../../enable-affine-cloud-modal';
|
||||
import type { WorkspaceSettingDetailProps } from '../../index';
|
||||
@ -133,8 +133,8 @@ const PublishPanelLocal: React.FC<PublishPanelLocalProps> = ({
|
||||
}}
|
||||
onConfirm={() => {
|
||||
onTransferWorkspace(
|
||||
RemWorkspaceFlavour.LOCAL,
|
||||
RemWorkspaceFlavour.AFFINE,
|
||||
WorkspaceFlavour.LOCAL,
|
||||
WorkspaceFlavour.AFFINE,
|
||||
workspace
|
||||
);
|
||||
setOpen(false);
|
||||
@ -145,9 +145,9 @@ const PublishPanelLocal: React.FC<PublishPanelLocalProps> = ({
|
||||
};
|
||||
|
||||
export const PublishPanel: React.FC<PublishPanelProps> = props => {
|
||||
if (props.workspace.flavour === RemWorkspaceFlavour.AFFINE) {
|
||||
if (props.workspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
return <PublishPanelAffine {...props} workspace={props.workspace} />;
|
||||
} else if (props.workspace.flavour === RemWorkspaceFlavour.LOCAL) {
|
||||
} else if (props.workspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
return <PublishPanelLocal {...props} workspace={props.workspace} />;
|
||||
}
|
||||
throw new Unreachable();
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Content, FlexWrapper, styled } from '@affine/component';
|
||||
import { Trans, useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type React from 'react';
|
||||
|
||||
import { useCurrentUser } from '../../../../../hooks/current/use-current-user';
|
||||
import { useBlockSuiteWorkspaceAvatarUrl } from '../../../../../hooks/use-blocksuite-workspace-avatar-url';
|
||||
import { useBlockSuiteWorkspaceName } from '../../../../../hooks/use-blocksuite-workspace-name';
|
||||
import { RemWorkspaceFlavour } from '../../../../../shared';
|
||||
import { WorkspaceAvatar } from '../../../../pure/footer';
|
||||
import type { PanelProps } from '../../index';
|
||||
|
||||
@ -17,7 +17,7 @@ export const StyledWorkspaceName = styled('span')(({ theme }) => {
|
||||
});
|
||||
|
||||
export const SyncPanel: React.FC<PanelProps> = ({ workspace }) => {
|
||||
if (workspace.flavour !== RemWorkspaceFlavour.AFFINE) {
|
||||
if (workspace.flavour !== WorkspaceFlavour.AFFINE) {
|
||||
throw new TypeError('SyncPanel can only be used with Affine workspace');
|
||||
}
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { displayFlex, IconButton, styled, Tooltip } from '@affine/component';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import {
|
||||
CloudWorkspaceIcon,
|
||||
LocalWorkspaceIcon,
|
||||
@ -15,7 +16,6 @@ import type {
|
||||
AffineOfficialWorkspace,
|
||||
LocalWorkspace,
|
||||
} from '../../../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../../../shared';
|
||||
import { apis } from '../../../../shared/apis';
|
||||
import { TransformWorkspaceToAffineModal } from '../../../affine/transform-workspace-to-affine-modal';
|
||||
|
||||
@ -117,10 +117,10 @@ export const SyncUser = () => {
|
||||
router.reload();
|
||||
return;
|
||||
}
|
||||
assertEquals(workspace.flavour, RemWorkspaceFlavour.LOCAL);
|
||||
assertEquals(workspace.flavour, WorkspaceFlavour.LOCAL);
|
||||
const id = await transformWorkspace(
|
||||
RemWorkspaceFlavour.LOCAL,
|
||||
RemWorkspaceFlavour.AFFINE,
|
||||
WorkspaceFlavour.LOCAL,
|
||||
WorkspaceFlavour.AFFINE,
|
||||
workspace as LocalWorkspace
|
||||
);
|
||||
// fixme(himself65): refactor this
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { PermissionType } from '@affine/datacenter';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useBlockSuiteWorkspaceName } from '../../../hooks/use-blocksuite-workspace-name';
|
||||
import type { RemWorkspace } from '../../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../../shared';
|
||||
import {
|
||||
CloudWorkspaceIcon,
|
||||
JoinedWorkspaceIcon,
|
||||
@ -28,13 +28,13 @@ export type WorkspaceTypeProps = {
|
||||
const WorkspaceType: React.FC<WorkspaceTypeProps> = ({ workspace }) => {
|
||||
const { t } = useTranslation();
|
||||
let isOwner = true;
|
||||
if (workspace.flavour === RemWorkspaceFlavour.AFFINE) {
|
||||
if (workspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
isOwner = workspace.permission === PermissionType.Owner;
|
||||
} else if (workspace.flavour === RemWorkspaceFlavour.LOCAL) {
|
||||
} else if (workspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
isOwner = true;
|
||||
}
|
||||
|
||||
if (workspace.flavour === RemWorkspaceFlavour.LOCAL) {
|
||||
if (workspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
return (
|
||||
<p title={t('Local Workspace')}>
|
||||
<LocalWorkspaceIcon />
|
||||
@ -85,19 +85,18 @@ export const WorkspaceCard: React.FC<WorkspaceCardProps> = ({
|
||||
<StyleWorkspaceInfo>
|
||||
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle>
|
||||
<WorkspaceType workspace={workspace} />
|
||||
{workspace.flavour === RemWorkspaceFlavour.LOCAL && (
|
||||
{workspace.flavour === WorkspaceFlavour.LOCAL && (
|
||||
<p title={t('Available Offline')}>
|
||||
<LocalDataIcon />
|
||||
<span>{t('Available Offline')}</span>
|
||||
</p>
|
||||
)}
|
||||
{workspace.flavour === RemWorkspaceFlavour.AFFINE &&
|
||||
workspace.public && (
|
||||
<p title={t('Published to Web')}>
|
||||
<PublishIcon />
|
||||
<span>{t('Published to Web')}</span>
|
||||
</p>
|
||||
)}
|
||||
{workspace.flavour === WorkspaceFlavour.AFFINE && workspace.public && (
|
||||
<p title={t('Published to Web')}>
|
||||
<PublishIcon />
|
||||
<span>{t('Published to Web')}</span>
|
||||
</p>
|
||||
)}
|
||||
</StyleWorkspaceInfo>
|
||||
<StyledSettingLink
|
||||
className="setting-entry"
|
||||
|
@ -5,6 +5,7 @@ import 'fake-indexeddb/auto';
|
||||
|
||||
import assert from 'node:assert';
|
||||
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
@ -23,7 +24,7 @@ import {
|
||||
} from '../../atoms';
|
||||
import { LocalPlugin } from '../../plugins/local';
|
||||
import type { LocalWorkspace } from '../../shared';
|
||||
import { BlockSuiteWorkspace, RemWorkspaceFlavour } from '../../shared';
|
||||
import { BlockSuiteWorkspace } from '../../shared';
|
||||
import { useIsFirstLoad, useOpenTips } from '../affine/use-is-first-load';
|
||||
import {
|
||||
useRecentlyViewed,
|
||||
@ -181,7 +182,7 @@ describe('useWorkspaces', () => {
|
||||
expect(result2.current.length).toEqual(1);
|
||||
const firstWorkspace = result2.current[0];
|
||||
expect(firstWorkspace.flavour).toBe('local');
|
||||
assert(firstWorkspace.flavour === RemWorkspaceFlavour.LOCAL);
|
||||
assert(firstWorkspace.flavour === WorkspaceFlavour.LOCAL);
|
||||
expect(firstWorkspace.blockSuiteWorkspace.meta.name).toBe('test');
|
||||
});
|
||||
});
|
||||
@ -266,12 +267,12 @@ describe('useRecentlyViewed', () => {
|
||||
store.set(jotaiWorkspacesAtom, [
|
||||
{
|
||||
id: workspaceId,
|
||||
flavour: RemWorkspaceFlavour.LOCAL,
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
},
|
||||
]);
|
||||
LocalPlugin.CRUD.get = vi.fn().mockResolvedValue({
|
||||
id: workspaceId,
|
||||
flavour: RemWorkspaceFlavour.LOCAL,
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
blockSuiteWorkspace,
|
||||
providers: [],
|
||||
} satisfies LocalWorkspace);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { DEFAULT_WORKSPACE_NAME } from '@affine/env';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { assertEquals, assertExists, nanoid } from '@blocksuite/store';
|
||||
import { useAtom } from 'jotai/index';
|
||||
import { useAtom } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { jotaiWorkspacesAtom } from '../atoms';
|
||||
import { LocalPlugin } from '../plugins/local';
|
||||
import { RemWorkspaceFlavour } from '../shared';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../utils';
|
||||
|
||||
export function useCreateFirstWorkspace() {
|
||||
const [jotaiWorkspaces, set] = useAtom(jotaiWorkspacesAtom);
|
||||
@ -29,7 +29,7 @@ export function useCreateFirstWorkspace() {
|
||||
set([
|
||||
{
|
||||
id: workspace.id,
|
||||
flavour: RemWorkspaceFlavour.LOCAL,
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type { NextRouter } from 'next/router';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { currentPageIdAtom, jotaiStore } from '../atoms';
|
||||
import type { RemWorkspace } from '../shared';
|
||||
import { RemWorkspaceFlavour } from '../shared';
|
||||
import { useCurrentPageId } from './current/use-current-page-id';
|
||||
import { useCurrentWorkspace } from './current/use-current-workspace';
|
||||
import { useWorkspaces } from './use-workspaces';
|
||||
@ -13,7 +13,7 @@ export function findSuitablePageId(
|
||||
targetId: string
|
||||
): string | null {
|
||||
switch (workspace.flavour) {
|
||||
case RemWorkspaceFlavour.AFFINE: {
|
||||
case WorkspaceFlavour.AFFINE: {
|
||||
return (
|
||||
workspace.blockSuiteWorkspace.meta.pageMetas.find(
|
||||
page => page.id === targetId
|
||||
@ -22,7 +22,7 @@ export function findSuitablePageId(
|
||||
null
|
||||
);
|
||||
}
|
||||
case RemWorkspaceFlavour.LOCAL: {
|
||||
case WorkspaceFlavour.LOCAL: {
|
||||
return (
|
||||
workspace.blockSuiteWorkspace.meta.pageMetas.find(
|
||||
page => page.id === targetId
|
||||
|
@ -1,9 +1,10 @@
|
||||
import type { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import type { WorkspaceRegistry } from '@affine/workspace/type';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { jotaiWorkspacesAtom } from '../atoms';
|
||||
import { WorkspacePlugins } from '../plugins';
|
||||
import type { FlavourToWorkspace, RemWorkspaceFlavour } from '../shared';
|
||||
|
||||
/**
|
||||
* Transform workspace from one flavour to another
|
||||
@ -13,10 +14,10 @@ import type { FlavourToWorkspace, RemWorkspaceFlavour } from '../shared';
|
||||
export function useTransformWorkspace() {
|
||||
const set = useSetAtom(jotaiWorkspacesAtom);
|
||||
return useCallback(
|
||||
async <From extends RemWorkspaceFlavour, To extends RemWorkspaceFlavour>(
|
||||
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
|
||||
from: From,
|
||||
to: To,
|
||||
workspace: FlavourToWorkspace[From]
|
||||
workspace: WorkspaceRegistry[From]
|
||||
): Promise<string> => {
|
||||
await WorkspacePlugins[from].CRUD.delete(workspace as any);
|
||||
const newId = await WorkspacePlugins[to].CRUD.create(
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
@ -6,8 +8,6 @@ import { jotaiWorkspacesAtom, workspacesAtom } from '../atoms';
|
||||
import { WorkspacePlugins } from '../plugins';
|
||||
import { LocalPlugin } from '../plugins/local';
|
||||
import type { LocalWorkspace, RemWorkspace } from '../shared';
|
||||
import { RemWorkspaceFlavour } from '../shared';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../utils';
|
||||
|
||||
export function useWorkspaces(): RemWorkspace[] {
|
||||
return useAtomValue(workspacesAtom);
|
||||
@ -43,7 +43,7 @@ export function useWorkspacesHelper() {
|
||||
...workspaces,
|
||||
{
|
||||
id,
|
||||
flavour: RemWorkspaceFlavour.LOCAL,
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
},
|
||||
]);
|
||||
return id;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Button, toast } from '@affine/component';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import { Typography } from '@mui/material';
|
||||
import type React from 'react';
|
||||
@ -9,7 +10,6 @@ import { createBroadCastChannelProvider } from '../../blocksuite/providers';
|
||||
import PageList from '../../components/blocksuite/block-suite-page-list/page-list';
|
||||
import { StyledPage, StyledWrapper } from '../../layouts/styles';
|
||||
import type { BroadCastChannelProvider } from '../../shared';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
||||
|
||||
const logger = new DebugLogger('broadcast');
|
||||
|
||||
|
78
apps/web/src/pages/_debug/login.dev.tsx
Normal file
78
apps/web/src/pages/_debug/login.dev.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import { Button, toast } from '@affine/component';
|
||||
import { currentAffineUserAtom } from '@affine/workspace/affine/atom';
|
||||
import {
|
||||
clearLoginStorage,
|
||||
createAffineAuth,
|
||||
getLoginStorage,
|
||||
isExpired,
|
||||
parseIdToken,
|
||||
setLoginStorage,
|
||||
SignMethod,
|
||||
} from '@affine/workspace/affine/login';
|
||||
import { useAtom } from 'jotai';
|
||||
import type { NextPage } from 'next';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { StyledPage, StyledWrapper } from '../../layouts/styles';
|
||||
|
||||
const LoginDevPage: NextPage = () => {
|
||||
const [user, setUser] = useAtom(currentAffineUserAtom);
|
||||
const auth = useMemo(() => createAffineAuth(), []);
|
||||
return (
|
||||
<StyledPage>
|
||||
<StyledWrapper>
|
||||
<h1>LoginDevPage</h1>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
const storage = getLoginStorage();
|
||||
if (storage) {
|
||||
const user = parseIdToken(storage.token);
|
||||
if (isExpired(user)) {
|
||||
await auth.refreshToken(storage);
|
||||
}
|
||||
}
|
||||
const response = await auth.generateToken(SignMethod.Google);
|
||||
if (response) {
|
||||
setLoginStorage(response);
|
||||
const user = parseIdToken(response.token);
|
||||
setUser(user);
|
||||
} else {
|
||||
toast('Login failed');
|
||||
}
|
||||
}}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
const storage = getLoginStorage();
|
||||
if (!storage) {
|
||||
throw new Error('No storage');
|
||||
}
|
||||
const response = await auth.refreshToken(storage);
|
||||
if (response) {
|
||||
setLoginStorage(response);
|
||||
const user = parseIdToken(response.token);
|
||||
setUser(user);
|
||||
} else {
|
||||
toast('Login failed');
|
||||
}
|
||||
}}
|
||||
>
|
||||
Refresh Token
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
clearLoginStorage();
|
||||
setUser(null);
|
||||
}}
|
||||
>
|
||||
Reset Storage
|
||||
</Button>
|
||||
{user && JSON.stringify(user)}
|
||||
</StyledWrapper>
|
||||
</StyledPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginDevPage;
|
@ -1,3 +1,4 @@
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { ContentParser } from '@blocksuite/blocks/content-parser';
|
||||
import type {
|
||||
GetStaticPaths,
|
||||
@ -16,7 +17,6 @@ import {
|
||||
StyledWrapper,
|
||||
} from '../../layouts/styles';
|
||||
import type { BlockSuiteWorkspace } from '../../shared';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
||||
|
||||
export type PreviewPageProps = {
|
||||
text: string;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { useRouter } from 'next/router';
|
||||
import type React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
@ -11,7 +12,6 @@ import { useSyncRouterWithCurrentWorkspaceAndPage } from '../../../hooks/use-syn
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { WorkspacePlugins } from '../../../plugins';
|
||||
import type { BlockSuiteWorkspace, NextPageWithLayout } from '../../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../../shared';
|
||||
|
||||
function enableFullFlags(blockSuiteWorkspace: BlockSuiteWorkspace) {
|
||||
blockSuiteWorkspace.awarenessStore.setFlag('enable_set_remote_flag', false);
|
||||
@ -38,12 +38,12 @@ const WorkspaceDetail: React.FC = () => {
|
||||
if (!pageId) {
|
||||
return <PageLoading />;
|
||||
}
|
||||
if (currentWorkspace.flavour === RemWorkspaceFlavour.AFFINE) {
|
||||
if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
const PageDetail = WorkspacePlugins[currentWorkspace.flavour].UI.PageDetail;
|
||||
return (
|
||||
<PageDetail currentWorkspace={currentWorkspace} currentPageId={pageId} />
|
||||
);
|
||||
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.LOCAL) {
|
||||
} else if (currentWorkspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
const PageDetail = WorkspacePlugins[currentWorkspace.flavour].UI.PageDetail;
|
||||
return (
|
||||
<PageDetail currentWorkspace={currentWorkspace} currentPageId={pageId} />
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { FolderIcon } from '@blocksuite/icons';
|
||||
import { assertEquals, assertExists, nanoid } from '@blocksuite/store';
|
||||
import Head from 'next/head';
|
||||
@ -20,7 +21,6 @@ import type {
|
||||
LocalIndexedDBProvider,
|
||||
NextPageWithLayout,
|
||||
} from '../../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../../shared';
|
||||
|
||||
const AllPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
@ -78,7 +78,7 @@ const AllPage: NextPageWithLayout = () => {
|
||||
if (currentWorkspace === null) {
|
||||
return <PageLoading />;
|
||||
}
|
||||
if (currentWorkspace.flavour === RemWorkspaceFlavour.AFFINE) {
|
||||
if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
const PageList = WorkspacePlugins[currentWorkspace.flavour].UI.PageList;
|
||||
return (
|
||||
<>
|
||||
@ -92,7 +92,7 @@ const AllPage: NextPageWithLayout = () => {
|
||||
/>
|
||||
</>
|
||||
);
|
||||
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.LOCAL) {
|
||||
} else if (currentWorkspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
const PageList = WorkspacePlugins[currentWorkspace.flavour].UI.PageList;
|
||||
return (
|
||||
<>
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import type { SettingPanel, WorkspaceRegistry } from '@affine/workspace/type';
|
||||
import {
|
||||
settingPanel,
|
||||
settingPanelValues,
|
||||
WorkspaceFlavour,
|
||||
} from '@affine/workspace/type';
|
||||
import { SettingsIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import { useAtom } from 'jotai';
|
||||
@ -16,16 +22,7 @@ import { useTransformWorkspace } from '../../../hooks/use-transform-workspace';
|
||||
import { useWorkspacesHelper } from '../../../hooks/use-workspaces';
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { WorkspacePlugins } from '../../../plugins';
|
||||
import type {
|
||||
FlavourToWorkspace,
|
||||
NextPageWithLayout,
|
||||
SettingPanel,
|
||||
} from '../../../shared';
|
||||
import {
|
||||
RemWorkspaceFlavour,
|
||||
settingPanel,
|
||||
settingPanelValues,
|
||||
} from '../../../shared';
|
||||
import type { NextPageWithLayout } from '../../../shared';
|
||||
import { apis } from '../../../shared/apis';
|
||||
|
||||
const settingPanelAtom = atomWithStorage<SettingPanel>(
|
||||
@ -105,13 +102,12 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
}, [currentWorkspace, helper]);
|
||||
const transformWorkspace = useTransformWorkspace();
|
||||
const onTransformWorkspace = useCallback(
|
||||
async <From extends RemWorkspaceFlavour, To extends RemWorkspaceFlavour>(
|
||||
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
|
||||
from: From,
|
||||
to: To,
|
||||
workspace: FlavourToWorkspace[From]
|
||||
workspace: WorkspaceRegistry[From]
|
||||
): Promise<void> => {
|
||||
const needRefresh =
|
||||
to === RemWorkspaceFlavour.AFFINE && !apis.auth.isLogin;
|
||||
const needRefresh = to === WorkspaceFlavour.AFFINE && !apis.auth.isLogin;
|
||||
if (needRefresh) {
|
||||
await apis.signInWithGoogle();
|
||||
}
|
||||
@ -135,7 +131,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
return <PageLoading />;
|
||||
} else if (settingPanelValues.indexOf(currentTab as SettingPanel) === -1) {
|
||||
return <PageLoading />;
|
||||
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.AFFINE) {
|
||||
} else if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
const Setting =
|
||||
WorkspacePlugins[currentWorkspace.flavour].UI.SettingsDetail;
|
||||
return (
|
||||
@ -155,7 +151,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
/>
|
||||
</>
|
||||
);
|
||||
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.LOCAL) {
|
||||
} else if (currentWorkspace.flavour === WorkspaceFlavour.LOCAL) {
|
||||
const Setting =
|
||||
WorkspacePlugins[currentWorkspace.flavour].UI.SettingsDetail;
|
||||
return (
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
|
||||
import { jotaiStore, workspacesAtom } from '../../atoms';
|
||||
import { createAffineProviders } from '../../blocksuite';
|
||||
import { Unreachable } from '../../components/affine/affine-error-eoundary';
|
||||
import type { AffineWorkspace } from '../../shared';
|
||||
import { RemWorkspaceFlavour } from '../../shared';
|
||||
import { apis } from '../../shared/apis';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
||||
|
||||
type Query = (typeof QueryKey)[keyof typeof QueryKey];
|
||||
|
||||
@ -73,7 +73,7 @@ export const fetcher = async (
|
||||
);
|
||||
const remWorkspace: AffineWorkspace = {
|
||||
...workspace,
|
||||
flavour: RemWorkspaceFlavour.AFFINE,
|
||||
flavour: WorkspaceFlavour.AFFINE,
|
||||
blockSuiteWorkspace,
|
||||
providers: [...createAffineProviders(blockSuiteWorkspace)],
|
||||
};
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { LoadPriority, WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { createJSONStorage } from 'jotai/utils';
|
||||
import React from 'react';
|
||||
import { mutate } from 'swr';
|
||||
@ -9,13 +11,8 @@ import { WorkspaceSettingDetail } from '../../components/affine/workspace-settin
|
||||
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
|
||||
import { PageDetailEditor } from '../../components/page-detail-editor';
|
||||
import type { AffineWorkspace } from '../../shared';
|
||||
import {
|
||||
BlockSuiteWorkspace,
|
||||
LoadPriority,
|
||||
RemWorkspaceFlavour,
|
||||
} from '../../shared';
|
||||
import { BlockSuiteWorkspace } from '../../shared';
|
||||
import { apis, clientAuth } from '../../shared/apis';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
||||
import { initPage } from '../../utils/blocksuite';
|
||||
import type { WorkspacePlugin } from '..';
|
||||
import { QueryKey } from './fetcher';
|
||||
@ -46,7 +43,7 @@ const getPersistenceAllWorkspace = () => {
|
||||
);
|
||||
const affineWorkspace: AffineWorkspace = {
|
||||
...item,
|
||||
flavour: RemWorkspaceFlavour.AFFINE,
|
||||
flavour: WorkspaceFlavour.AFFINE,
|
||||
blockSuiteWorkspace,
|
||||
providers: [...createAffineProviders(blockSuiteWorkspace)],
|
||||
};
|
||||
@ -57,8 +54,8 @@ const getPersistenceAllWorkspace = () => {
|
||||
return allWorkspaces;
|
||||
};
|
||||
|
||||
export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
|
||||
flavour: RemWorkspaceFlavour.AFFINE,
|
||||
export const AffinePlugin: WorkspacePlugin<WorkspaceFlavour.AFFINE> = {
|
||||
flavour: WorkspaceFlavour.AFFINE,
|
||||
loadPriority: LoadPriority.HIGH,
|
||||
cleanup: () => {
|
||||
storage.removeItem(kAffineLocal);
|
||||
@ -167,7 +164,7 @@ export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
|
||||
|
||||
const affineWorkspace: AffineWorkspace = {
|
||||
...workspace,
|
||||
flavour: RemWorkspaceFlavour.AFFINE,
|
||||
flavour: WorkspaceFlavour.AFFINE,
|
||||
blockSuiteWorkspace,
|
||||
providers: [...createAffineProviders(blockSuiteWorkspace)],
|
||||
};
|
||||
|
@ -1,74 +1,35 @@
|
||||
import type React from 'react';
|
||||
|
||||
import type {
|
||||
BlockSuiteWorkspace,
|
||||
FlavourToWorkspace,
|
||||
LoadPriority,
|
||||
SettingPanel,
|
||||
} from '../shared';
|
||||
import { RemWorkspaceFlavour } from '../shared';
|
||||
WorkspaceCRUD,
|
||||
WorkspaceUISchema,
|
||||
} from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
|
||||
import type { AffineWorkspace, LocalWorkspace } from '../shared';
|
||||
import { AffinePlugin } from './affine';
|
||||
import { LocalPlugin } from './local';
|
||||
|
||||
type UIBaseProps<Flavour extends RemWorkspaceFlavour> = {
|
||||
currentWorkspace: FlavourToWorkspace[Flavour];
|
||||
};
|
||||
declare module '@affine/workspace/type' {
|
||||
interface WorkspaceRegistry {
|
||||
[WorkspaceFlavour.AFFINE]: AffineWorkspace;
|
||||
[WorkspaceFlavour.LOCAL]: LocalWorkspace;
|
||||
}
|
||||
}
|
||||
|
||||
type SettingProps<Flavour extends RemWorkspaceFlavour> =
|
||||
UIBaseProps<Flavour> & {
|
||||
currentTab: SettingPanel;
|
||||
onChangeTab: (tab: SettingPanel) => void;
|
||||
onDeleteWorkspace: () => void;
|
||||
onTransformWorkspace: <
|
||||
From extends RemWorkspaceFlavour,
|
||||
To extends RemWorkspaceFlavour
|
||||
>(
|
||||
from: From,
|
||||
to: To,
|
||||
workspace: FlavourToWorkspace[From]
|
||||
) => void;
|
||||
};
|
||||
|
||||
type PageDetailProps<Flavour extends RemWorkspaceFlavour> =
|
||||
UIBaseProps<Flavour> & {
|
||||
currentPageId: string;
|
||||
};
|
||||
|
||||
type PageListProps<Flavour extends RemWorkspaceFlavour> = {
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
onOpenPage: (pageId: string, newTab?: boolean) => void;
|
||||
};
|
||||
|
||||
type SideBarMenuProps<Flavour extends RemWorkspaceFlavour> =
|
||||
UIBaseProps<Flavour> & {
|
||||
setSideBarOpen: (open: boolean) => void;
|
||||
};
|
||||
|
||||
export interface WorkspacePlugin<Flavour extends RemWorkspaceFlavour> {
|
||||
export interface WorkspacePlugin<Flavour extends WorkspaceFlavour> {
|
||||
flavour: Flavour;
|
||||
// Plugin will be loaded according to the priority
|
||||
loadPriority: LoadPriority;
|
||||
// fixme: this is a hack
|
||||
cleanup?: () => void;
|
||||
// Fetch necessary data for the first render
|
||||
CRUD: {
|
||||
create: (blockSuiteWorkspace: BlockSuiteWorkspace) => Promise<string>;
|
||||
delete: (workspace: FlavourToWorkspace[Flavour]) => Promise<void>;
|
||||
get: (workspaceId: string) => Promise<FlavourToWorkspace[Flavour] | null>;
|
||||
// not supported yet
|
||||
// update: (workspace: FlavourToWorkspace[Flavour]) => Promise<void>;
|
||||
list: () => Promise<FlavourToWorkspace[Flavour][]>;
|
||||
};
|
||||
UI: {
|
||||
PageDetail: React.FC<PageDetailProps<Flavour>>;
|
||||
PageList: React.FC<PageListProps<Flavour>>;
|
||||
SettingsDetail: React.FC<SettingProps<Flavour>>;
|
||||
};
|
||||
CRUD: WorkspaceCRUD<Flavour>;
|
||||
UI: WorkspaceUISchema<Flavour>;
|
||||
}
|
||||
|
||||
export const WorkspacePlugins = {
|
||||
[RemWorkspaceFlavour.AFFINE]: AffinePlugin,
|
||||
[RemWorkspaceFlavour.LOCAL]: LocalPlugin,
|
||||
[WorkspaceFlavour.AFFINE]: AffinePlugin,
|
||||
[WorkspaceFlavour.LOCAL]: LocalPlugin,
|
||||
} satisfies {
|
||||
[Key in RemWorkspaceFlavour]: WorkspacePlugin<Key>;
|
||||
[Key in WorkspaceFlavour]: WorkspacePlugin<Key>;
|
||||
};
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { DEFAULT_WORKSPACE_NAME } from '@affine/env';
|
||||
import { LoadPriority, WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import { createJSONStorage } from 'jotai/utils';
|
||||
import React from 'react';
|
||||
@ -11,12 +13,7 @@ import { WorkspaceSettingDetail } from '../../components/affine/workspace-settin
|
||||
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
|
||||
import { PageDetailEditor } from '../../components/page-detail-editor';
|
||||
import type { LocalWorkspace } from '../../shared';
|
||||
import {
|
||||
BlockSuiteWorkspace,
|
||||
LoadPriority,
|
||||
RemWorkspaceFlavour,
|
||||
} from '../../shared';
|
||||
import { createEmptyBlockSuiteWorkspace } from '../../utils';
|
||||
import { BlockSuiteWorkspace } from '../../shared';
|
||||
import { initPage } from '../../utils/blocksuite';
|
||||
import type { WorkspacePlugin } from '..';
|
||||
|
||||
@ -25,8 +22,8 @@ const getStorage = () => createJSONStorage(() => localStorage);
|
||||
export const kStoreKey = 'affine-local-workspace';
|
||||
const schema = z.array(z.string());
|
||||
|
||||
export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
|
||||
flavour: RemWorkspaceFlavour.LOCAL,
|
||||
export const LocalPlugin: WorkspacePlugin<WorkspaceFlavour.LOCAL> = {
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
loadPriority: LoadPriority.LOW,
|
||||
CRUD: {
|
||||
get: async workspaceId => {
|
||||
@ -44,7 +41,7 @@ export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
|
||||
);
|
||||
const workspace: LocalWorkspace = {
|
||||
id,
|
||||
flavour: RemWorkspaceFlavour.LOCAL,
|
||||
flavour: WorkspaceFlavour.LOCAL,
|
||||
blockSuiteWorkspace: blockSuiteWorkspace,
|
||||
providers: [...createLocalProviders(blockSuiteWorkspace)],
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ let prefixUrl = '/';
|
||||
if (typeof window === 'undefined') {
|
||||
// SSR
|
||||
const serverAPI = config.serverAPI;
|
||||
if (isValidIPAddress(serverAPI)) {
|
||||
if (isValidIPAddress(serverAPI.split(':')[0])) {
|
||||
// This is for Server side rendering support
|
||||
prefixUrl = new URL('http://' + config.serverAPI + '/').origin;
|
||||
} else {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { Workspace as RemoteWorkspace } from '@affine/datacenter';
|
||||
import type { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||
import type { NextPage } from 'next';
|
||||
import type { ReactElement, ReactNode } from 'react';
|
||||
@ -11,25 +12,15 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
export const enum RemWorkspaceFlavour {
|
||||
AFFINE = 'affine',
|
||||
LOCAL = 'local',
|
||||
}
|
||||
|
||||
export interface FlavourToWorkspace {
|
||||
[RemWorkspaceFlavour.AFFINE]: AffineWorkspace;
|
||||
[RemWorkspaceFlavour.LOCAL]: LocalWorkspace;
|
||||
}
|
||||
|
||||
export interface AffineWorkspace extends RemoteWorkspace {
|
||||
flavour: RemWorkspaceFlavour.AFFINE;
|
||||
flavour: WorkspaceFlavour.AFFINE;
|
||||
// empty
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
providers: Provider[];
|
||||
}
|
||||
|
||||
export interface LocalWorkspace {
|
||||
flavour: RemWorkspaceFlavour.LOCAL;
|
||||
flavour: WorkspaceFlavour.LOCAL;
|
||||
id: string;
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
providers: Provider[];
|
||||
@ -89,16 +80,6 @@ export const enum WorkspaceSubPath {
|
||||
TRASH = 'trash',
|
||||
}
|
||||
|
||||
export const settingPanel = {
|
||||
General: 'general',
|
||||
Collaboration: 'collaboration',
|
||||
Publish: 'publish',
|
||||
Export: 'export',
|
||||
Sync: 'sync',
|
||||
} as const;
|
||||
export const settingPanelValues = [...Object.values(settingPanel)] as const;
|
||||
export type SettingPanel = (typeof settingPanel)[keyof typeof settingPanel];
|
||||
|
||||
export const WorkspaceSubPathName = {
|
||||
[WorkspaceSubPath.ALL]: 'All Pages',
|
||||
[WorkspaceSubPath.FAVORITE]: 'Favorites',
|
||||
@ -125,9 +106,3 @@ export const publicPathGenerator = {
|
||||
} satisfies {
|
||||
[Path in WorkspaceSubPath]: (workspaceId: string) => string;
|
||||
};
|
||||
|
||||
export const enum LoadPriority {
|
||||
HIGH = 1,
|
||||
MEDIUM = 2,
|
||||
LOW = 3,
|
||||
}
|
||||
|
@ -1,8 +1,3 @@
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import type { BlobOptionsGetter, Generator } from '@blocksuite/store';
|
||||
|
||||
import { BlockSuiteWorkspace } from '../shared';
|
||||
|
||||
export function stringToColour(str: string) {
|
||||
str = str || 'affine';
|
||||
let colour = '#';
|
||||
@ -23,24 +18,3 @@ export function stringToColour(str: string) {
|
||||
|
||||
return colour;
|
||||
}
|
||||
|
||||
const hashMap = new Map<string, BlockSuiteWorkspace>();
|
||||
export const createEmptyBlockSuiteWorkspace = (
|
||||
id: string,
|
||||
blobOptionsGetter?: BlobOptionsGetter,
|
||||
idGenerator?: Generator
|
||||
): BlockSuiteWorkspace => {
|
||||
if (hashMap.has(id)) {
|
||||
return hashMap.get(id) as BlockSuiteWorkspace;
|
||||
}
|
||||
const workspace = new BlockSuiteWorkspace({
|
||||
id,
|
||||
isSSR: typeof window === 'undefined',
|
||||
blobOptionsGetter,
|
||||
idGenerator,
|
||||
})
|
||||
.register(AffineSchemas)
|
||||
.register(__unstableSchemas);
|
||||
hashMap.set(id, workspace);
|
||||
return workspace;
|
||||
};
|
||||
|
@ -57,6 +57,7 @@
|
||||
"happy-dom": "^8.9.0",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^13.2.0",
|
||||
"msw": "^1.2.0",
|
||||
"nanoid": "^4.0.1",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.8.5",
|
||||
|
5
packages/env/package.json
vendored
5
packages/env/package.json
vendored
@ -2,12 +2,17 @@
|
||||
"name": "@affine/env",
|
||||
"private": true,
|
||||
"main": "./src/index.ts",
|
||||
"module": "./src/index.ts",
|
||||
"devDependencies": {
|
||||
"next": "=13.2.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./constant": "./src/constant.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blocksuite/global": "0.5.0-20230323085636-3110abb",
|
||||
"lit": "^2.6.1"
|
||||
|
66
packages/env/src/constant.ts
vendored
66
packages/env/src/constant.ts
vendored
@ -1,2 +1,68 @@
|
||||
export const DEFAULT_WORKSPACE_NAME = 'Demo Workspace';
|
||||
export const UNTITLED_WORKSPACE_NAME = 'Untitled';
|
||||
|
||||
export const enum MessageCode {
|
||||
loginError,
|
||||
noPermission,
|
||||
loadListFailed,
|
||||
getDetailFailed,
|
||||
createWorkspaceFailed,
|
||||
getMembersFailed,
|
||||
updateWorkspaceFailed,
|
||||
deleteWorkspaceFailed,
|
||||
inviteMemberFailed,
|
||||
removeMemberFailed,
|
||||
acceptInvitingFailed,
|
||||
getBlobFailed,
|
||||
leaveWorkspaceFailed,
|
||||
downloadWorkspaceFailed,
|
||||
refreshTokenError,
|
||||
}
|
||||
|
||||
export const Messages = {
|
||||
[MessageCode.loginError]: {
|
||||
message: 'Login failed',
|
||||
},
|
||||
[MessageCode.noPermission]: {
|
||||
message: 'No permission',
|
||||
},
|
||||
[MessageCode.loadListFailed]: {
|
||||
message: 'Load list failed',
|
||||
},
|
||||
[MessageCode.getDetailFailed]: {
|
||||
message: 'Get detail failed',
|
||||
},
|
||||
[MessageCode.createWorkspaceFailed]: {
|
||||
message: 'Create workspace failed',
|
||||
},
|
||||
[MessageCode.getMembersFailed]: {
|
||||
message: 'Get members failed',
|
||||
},
|
||||
[MessageCode.updateWorkspaceFailed]: {
|
||||
message: 'Update workspace failed',
|
||||
},
|
||||
[MessageCode.deleteWorkspaceFailed]: {
|
||||
message: 'Delete workspace failed',
|
||||
},
|
||||
[MessageCode.inviteMemberFailed]: {
|
||||
message: 'Invite member failed',
|
||||
},
|
||||
[MessageCode.removeMemberFailed]: {
|
||||
message: 'Remove member failed',
|
||||
},
|
||||
[MessageCode.acceptInvitingFailed]: {
|
||||
message: 'Accept inviting failed',
|
||||
},
|
||||
[MessageCode.getBlobFailed]: {
|
||||
message: 'Get blob failed',
|
||||
},
|
||||
[MessageCode.leaveWorkspaceFailed]: {
|
||||
message: 'Leave workspace failed',
|
||||
},
|
||||
[MessageCode.downloadWorkspaceFailed]: {
|
||||
message: 'Download workspace failed',
|
||||
},
|
||||
[MessageCode.refreshTokenError]: {
|
||||
message: 'Refresh token failed',
|
||||
},
|
||||
} as const;
|
||||
|
22
packages/workspace/package.json
Normal file
22
packages/workspace/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@affine/workspace",
|
||||
"private": true,
|
||||
"exports": {
|
||||
"./utils": "./src/utils.ts",
|
||||
"./type": "./src/type.ts",
|
||||
"./affine/*": "./src/affine/*.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
"@affine/debug": "workspace:*",
|
||||
"@affine/env": "workspace:*",
|
||||
"@blocksuite/blocks": "0.5.0-20230323085636-3110abb",
|
||||
"@blocksuite/store": "0.5.0-20230323085636-3110abb",
|
||||
"firebase": "^9.18.0",
|
||||
"jotai": "^2.0.3",
|
||||
"js-base64": "^3.7.5",
|
||||
"ky": "^0.33.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
}
|
20
packages/workspace/src/affine/__tests__/atom.spec.ts
Normal file
20
packages/workspace/src/affine/__tests__/atom.spec.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { getDefaultStore } from 'jotai';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { currentAffineUserAtom } from '../atom';
|
||||
|
||||
describe('atom', () => {
|
||||
test('currentAffineUserAtom', () => {
|
||||
const store = getDefaultStore();
|
||||
const mock = {
|
||||
created_at: 0,
|
||||
exp: 0,
|
||||
email: '',
|
||||
id: '',
|
||||
name: '',
|
||||
avatar_url: '',
|
||||
};
|
||||
store.set(currentAffineUserAtom, mock);
|
||||
expect(store.get(currentAffineUserAtom)).toEqual(mock);
|
||||
});
|
||||
});
|
42
packages/workspace/src/affine/__tests__/login.spec.ts
Normal file
42
packages/workspace/src/affine/__tests__/login.spec.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import type { AccessTokenMessage } from '@affine/workspace/affine/login';
|
||||
import {
|
||||
getLoginStorage,
|
||||
isExpired,
|
||||
setLoginStorage,
|
||||
STORAGE_KEY,
|
||||
} from '@affine/workspace/affine/login';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
describe('storage', () => {
|
||||
test('should work', () => {
|
||||
setLoginStorage({
|
||||
token: '1',
|
||||
refresh: '2',
|
||||
});
|
||||
const data = localStorage.getItem(STORAGE_KEY);
|
||||
expect(data).toBe('{"token":"1","refresh":"2"}');
|
||||
const login = getLoginStorage();
|
||||
expect(login).toEqual({
|
||||
token: '1',
|
||||
refresh: '2',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('utils', () => {
|
||||
test('isExpired', async () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
expect(isExpired({ exp: now + 1 } as AccessTokenMessage)).toBeFalsy();
|
||||
const promise = new Promise<void>(resolve => {
|
||||
setTimeout(() => {
|
||||
expect(isExpired({ exp: now + 1 } as AccessTokenMessage)).toBeTruthy();
|
||||
resolve();
|
||||
}, 2000);
|
||||
});
|
||||
expect(isExpired({ exp: now - 1 } as AccessTokenMessage)).toBeTruthy();
|
||||
await promise;
|
||||
});
|
||||
});
|
4
packages/workspace/src/affine/atom.ts
Normal file
4
packages/workspace/src/affine/atom.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import type { AccessTokenMessage } from '@affine/workspace/affine/login';
|
||||
import { atom } from 'jotai';
|
||||
|
||||
export const currentAffineUserAtom = atom<AccessTokenMessage | null>(null);
|
175
packages/workspace/src/affine/login.ts
Normal file
175
packages/workspace/src/affine/login.ts
Normal file
@ -0,0 +1,175 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { initializeApp } from 'firebase/app';
|
||||
import type { AuthProvider } from 'firebase/auth';
|
||||
import {
|
||||
type Auth as FirebaseAuth,
|
||||
connectAuthEmulator,
|
||||
getAuth as getFirebaseAuth,
|
||||
GithubAuthProvider,
|
||||
GoogleAuthProvider,
|
||||
signInWithPopup,
|
||||
} from 'firebase/auth';
|
||||
import { decode } from 'js-base64';
|
||||
// Connect emulators based on env vars
|
||||
const envConnectEmulators = process.env.REACT_APP_FIREBASE_EMULATORS === 'true';
|
||||
|
||||
export type AccessTokenMessage = {
|
||||
created_at: number;
|
||||
exp: number;
|
||||
email: string;
|
||||
id: string;
|
||||
name: string;
|
||||
avatar_url: string;
|
||||
};
|
||||
|
||||
export type LoginParams = {
|
||||
type: 'Google' | 'Refresh';
|
||||
token: string;
|
||||
};
|
||||
|
||||
export type LoginResponse = {
|
||||
// access token, expires in a very short time
|
||||
token: string;
|
||||
// Refresh token
|
||||
refresh: string;
|
||||
};
|
||||
|
||||
const logger = new DebugLogger('token');
|
||||
|
||||
export const STORAGE_KEY = 'affine-login-v2';
|
||||
|
||||
export function parseIdToken(token: string): AccessTokenMessage {
|
||||
return JSON.parse(decode(token.split('.')[1]));
|
||||
}
|
||||
|
||||
export const isExpired = (token: AccessTokenMessage): boolean => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
return token.exp < now;
|
||||
};
|
||||
|
||||
export const setLoginStorage = (login: LoginResponse) => {
|
||||
localStorage.setItem(
|
||||
STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
token: login.token,
|
||||
refresh: login.refresh,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export const clearLoginStorage = () => {
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
};
|
||||
|
||||
export const getLoginStorage = (): LoginResponse | null => {
|
||||
const login = localStorage.getItem(STORAGE_KEY);
|
||||
if (login) {
|
||||
try {
|
||||
return JSON.parse(login);
|
||||
} catch (error) {
|
||||
logger.error('Failed to parse login', error);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const enum SignMethod {
|
||||
Google = 'Google',
|
||||
GitHub = 'GitHub',
|
||||
// Twitter = 'Twitter',
|
||||
}
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var firebaseAuthEmulatorStarted: boolean | undefined;
|
||||
}
|
||||
|
||||
export function createAffineAuth() {
|
||||
let _firebaseAuth: FirebaseAuth | null = null;
|
||||
const getAuth = (): FirebaseAuth | null => {
|
||||
try {
|
||||
if (!_firebaseAuth) {
|
||||
const app = initializeApp({
|
||||
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
|
||||
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
|
||||
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
|
||||
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId:
|
||||
process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
|
||||
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
|
||||
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
|
||||
});
|
||||
_firebaseAuth = getFirebaseAuth(app);
|
||||
}
|
||||
if (envConnectEmulators && !globalThis.firebaseAuthEmulatorStarted) {
|
||||
connectAuthEmulator(_firebaseAuth, 'http://localhost:9099', {
|
||||
disableWarnings: true,
|
||||
});
|
||||
globalThis.firebaseAuthEmulatorStarted = true;
|
||||
}
|
||||
return _firebaseAuth;
|
||||
} catch (error) {
|
||||
logger.error('Failed to initialize firebase', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
generateToken: async (
|
||||
method: SignMethod
|
||||
): Promise<LoginResponse | null> => {
|
||||
const auth = getAuth();
|
||||
if (!auth) {
|
||||
throw new Error('Failed to initialize firebase');
|
||||
}
|
||||
let provider: AuthProvider;
|
||||
switch (method) {
|
||||
case SignMethod.Google:
|
||||
provider = new GoogleAuthProvider();
|
||||
break;
|
||||
case SignMethod.GitHub:
|
||||
provider = new GithubAuthProvider();
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unsupported sign method');
|
||||
}
|
||||
try {
|
||||
const response = await signInWithPopup(auth, provider);
|
||||
const idToken = await response.user.getIdToken();
|
||||
logger.debug(idToken);
|
||||
return fetch('/api/user/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'Google',
|
||||
token: idToken,
|
||||
}),
|
||||
}).then(r => r.json()) as Promise<LoginResponse>;
|
||||
} catch (error) {
|
||||
if (error instanceof Error && 'code' in error) {
|
||||
if (error.code === 'auth/popup-closed-by-user') {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
logger.error('Failed to sign in', error);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
refreshToken: async (
|
||||
loginResponse: LoginResponse
|
||||
): Promise<LoginResponse | null> => {
|
||||
return fetch('/api/user/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'Refresh',
|
||||
token: loginResponse.refresh,
|
||||
}),
|
||||
}).then(r => r.json()) as Promise<LoginResponse>;
|
||||
},
|
||||
} as const;
|
||||
}
|
74
packages/workspace/src/type.ts
Normal file
74
packages/workspace/src/type.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import type { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||
import type { FC } from 'react';
|
||||
|
||||
export const enum LoadPriority {
|
||||
HIGH = 1,
|
||||
MEDIUM = 2,
|
||||
LOW = 3,
|
||||
}
|
||||
|
||||
export const enum WorkspaceFlavour {
|
||||
AFFINE = 'affine',
|
||||
LOCAL = 'local',
|
||||
}
|
||||
export const settingPanel = {
|
||||
General: 'general',
|
||||
Collaboration: 'collaboration',
|
||||
Publish: 'publish',
|
||||
Export: 'export',
|
||||
Sync: 'sync',
|
||||
} as const;
|
||||
export const settingPanelValues = [...Object.values(settingPanel)] as const;
|
||||
export type SettingPanel = (typeof settingPanel)[keyof typeof settingPanel];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface WorkspaceRegistry {}
|
||||
|
||||
export interface WorkspaceCRUD<Flavour extends keyof WorkspaceRegistry> {
|
||||
create: (blockSuiteWorkspace: BlockSuiteWorkspace) => Promise<string>;
|
||||
delete: (workspace: WorkspaceRegistry[Flavour]) => Promise<void>;
|
||||
get: (workspaceId: string) => Promise<WorkspaceRegistry[Flavour] | null>;
|
||||
// not supported yet
|
||||
// update: (workspace: FlavourToWorkspace[Flavour]) => Promise<void>;
|
||||
list: () => Promise<WorkspaceRegistry[Flavour][]>;
|
||||
}
|
||||
|
||||
type UIBaseProps<Flavour extends keyof WorkspaceRegistry> = {
|
||||
currentWorkspace: WorkspaceRegistry[Flavour];
|
||||
};
|
||||
|
||||
type SettingProps<Flavour extends keyof WorkspaceRegistry> =
|
||||
UIBaseProps<Flavour> & {
|
||||
currentTab: SettingPanel;
|
||||
onChangeTab: (tab: SettingPanel) => void;
|
||||
onDeleteWorkspace: () => void;
|
||||
onTransformWorkspace: <
|
||||
From extends keyof WorkspaceRegistry,
|
||||
To extends keyof WorkspaceRegistry
|
||||
>(
|
||||
from: From,
|
||||
to: To,
|
||||
workspace: WorkspaceRegistry[From]
|
||||
) => void;
|
||||
};
|
||||
|
||||
type PageDetailProps<Flavour extends keyof WorkspaceRegistry> =
|
||||
UIBaseProps<Flavour> & {
|
||||
currentPageId: string;
|
||||
};
|
||||
|
||||
type PageListProps<Flavour extends keyof WorkspaceRegistry> = {
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
onOpenPage: (pageId: string, newTab?: boolean) => void;
|
||||
};
|
||||
|
||||
type SideBarMenuProps<Flavour extends keyof WorkspaceRegistry> =
|
||||
UIBaseProps<Flavour> & {
|
||||
setSideBarOpen: (open: boolean) => void;
|
||||
};
|
||||
|
||||
export interface WorkspaceUISchema<Flavour extends keyof WorkspaceRegistry> {
|
||||
PageDetail: FC<PageDetailProps<Flavour>>;
|
||||
PageList: FC<PageListProps<Flavour>>;
|
||||
SettingsDetail: FC<SettingProps<Flavour>>;
|
||||
}
|
24
packages/workspace/src/utils.ts
Normal file
24
packages/workspace/src/utils.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import type { BlobOptionsGetter, Generator } from '@blocksuite/store';
|
||||
import { Workspace } from '@blocksuite/store';
|
||||
|
||||
const hashMap = new Map<string, Workspace>();
|
||||
export const createEmptyBlockSuiteWorkspace = (
|
||||
id: string,
|
||||
blobOptionsGetter?: BlobOptionsGetter,
|
||||
idGenerator?: Generator
|
||||
): Workspace => {
|
||||
if (hashMap.has(id)) {
|
||||
return hashMap.get(id) as Workspace;
|
||||
}
|
||||
const workspace = new Workspace({
|
||||
id,
|
||||
isSSR: typeof window === 'undefined',
|
||||
blobOptionsGetter,
|
||||
idGenerator,
|
||||
})
|
||||
.register(AffineSchemas)
|
||||
.register(__unstableSchemas);
|
||||
hashMap.set(id, workspace);
|
||||
return workspace;
|
||||
};
|
4
packages/workspace/tsconfig.json
Normal file
4
packages/workspace/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["./src"]
|
||||
}
|
@ -26,7 +26,9 @@
|
||||
"@affine/i18n": ["./packages/i18n/src"],
|
||||
"@affine/debug": ["./packages/debug"],
|
||||
"@affine/env": ["./packages/env"],
|
||||
"@affine/utils": ["./packages/utils"]
|
||||
"@affine/env/*": ["./packages/env/src/*"],
|
||||
"@affine/utils": ["./packages/utils"],
|
||||
"@affine/workspace/*": ["./packages/workspace/src/*"]
|
||||
}
|
||||
},
|
||||
"references": [
|
||||
@ -55,7 +57,7 @@
|
||||
"path": "./packages/debug"
|
||||
},
|
||||
{
|
||||
"path": "./packages/cli"
|
||||
"path": "./packages/workspace"
|
||||
}
|
||||
],
|
||||
"files": [],
|
||||
|
317
yarn.lock
317
yarn.lock
@ -22,6 +22,7 @@ __metadata:
|
||||
"@affine/env": "workspace:*"
|
||||
"@affine/i18n": "workspace:*"
|
||||
"@affine/templates": "workspace:*"
|
||||
"@affine/workspace": "workspace:*"
|
||||
"@blocksuite/blocks": 0.5.0-20230323085636-3110abb
|
||||
"@blocksuite/editor": 0.5.0-20230323085636-3110abb
|
||||
"@blocksuite/icons": 2.0.23
|
||||
@ -251,6 +252,24 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@affine/workspace@workspace:*, @affine/workspace@workspace:packages/workspace":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@affine/workspace@workspace:packages/workspace"
|
||||
dependencies:
|
||||
"@affine/component": "workspace:*"
|
||||
"@affine/debug": "workspace:*"
|
||||
"@affine/env": "workspace:*"
|
||||
"@blocksuite/blocks": 0.5.0-20230323085636-3110abb
|
||||
"@blocksuite/store": 0.5.0-20230323085636-3110abb
|
||||
firebase: ^9.18.0
|
||||
jotai: ^2.0.3
|
||||
js-base64: ^3.7.5
|
||||
ky: ^0.33.3
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@ampproject/remapping@npm:^2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "@ampproject/remapping@npm:2.2.0"
|
||||
@ -3856,6 +3875,32 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mswjs/cookies@npm:^0.2.2":
|
||||
version: 0.2.2
|
||||
resolution: "@mswjs/cookies@npm:0.2.2"
|
||||
dependencies:
|
||||
"@types/set-cookie-parser": ^2.4.0
|
||||
set-cookie-parser: ^2.4.6
|
||||
checksum: 23b1ef56d57efcc1b44600076f531a1fb703855af342a31e01bad4adaf0dab51f6d3b5595a95a7988c3f612ba075835f9a06c52833205284d101eb9a51dd72b0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mswjs/interceptors@npm:^0.17.5":
|
||||
version: 0.17.9
|
||||
resolution: "@mswjs/interceptors@npm:0.17.9"
|
||||
dependencies:
|
||||
"@open-draft/until": ^1.0.3
|
||||
"@types/debug": ^4.1.7
|
||||
"@xmldom/xmldom": ^0.8.3
|
||||
debug: ^4.3.3
|
||||
headers-polyfill: ^3.1.0
|
||||
outvariant: ^1.2.1
|
||||
strict-event-emitter: ^0.2.4
|
||||
web-encoding: ^1.1.5
|
||||
checksum: 4df726cbee93d8baa54ead1ecb11e98124468659f51eb659ef8ead4aca7d6375198baf412ea17d4810fa5f1ee4fa53994702cb3b0b4f6f427a2f0fb890020192
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mui/base@npm:5.0.0-alpha.121":
|
||||
version: 5.0.0-alpha.121
|
||||
resolution: "@mui/base@npm:5.0.0-alpha.121"
|
||||
@ -4193,6 +4238,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@open-draft/until@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "@open-draft/until@npm:1.0.3"
|
||||
checksum: 323e92ebef0150ed0f8caedc7d219b68cdc50784fa4eba0377eef93533d3f46514eb2400ced83dda8c51bddc3d2c7b8e9cf95e5ec85ab7f62dfc015d174f62f2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@perfsee/bundle-analyzer@npm:1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "@perfsee/bundle-analyzer@npm:1.4.0"
|
||||
@ -6475,6 +6527,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/cookie@npm:^0.4.1":
|
||||
version: 0.4.1
|
||||
resolution: "@types/cookie@npm:0.4.1"
|
||||
checksum: 3275534ed69a76c68eb1a77d547d75f99fedc80befb75a3d1d03662fb08d697e6f8b1274e12af1a74c6896071b11510631ba891f64d30c78528d0ec45a9c1a18
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/debug@npm:^4.1.7":
|
||||
version: 4.1.7
|
||||
resolution: "@types/debug@npm:4.1.7"
|
||||
@ -6680,6 +6739,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/js-levenshtein@npm:^1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "@types/js-levenshtein@npm:1.1.1"
|
||||
checksum: 1d1ff1ee2ad551909e47f3ce19fcf85b64dc5146d3b531c8d26fc775492d36e380b32cf5ef68ff301e812c3b00282f37aac579ebb44498b94baff0ace7509769
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.11, @types/json-schema@npm:^7.0.6, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9":
|
||||
version: 7.0.11
|
||||
resolution: "@types/json-schema@npm:7.0.11"
|
||||
@ -6949,6 +7015,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/set-cookie-parser@npm:^2.4.0":
|
||||
version: 2.4.2
|
||||
resolution: "@types/set-cookie-parser@npm:2.4.2"
|
||||
dependencies:
|
||||
"@types/node": "*"
|
||||
checksum: c31bf04eb9620829dc3c91bced74ac934ad039d20d20893fb5acac0f08769cbd4eef3bf7502a0289c7be59c3e9cfa456147b4e88bff47dd1b9efb4995ba5d5a3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/stack-utils@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "@types/stack-utils@npm:2.0.1"
|
||||
@ -7395,6 +7470,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@xmldom/xmldom@npm:^0.8.3":
|
||||
version: 0.8.6
|
||||
resolution: "@xmldom/xmldom@npm:0.8.6"
|
||||
checksum: f17ac6d99a971a6aeb831fcfc5cfa86f367664e45815046548814b2deb17ccc421fef4e0d5ba29e66179d112b552f6caa5680064f8e7bd8a389b788a60404c8e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@xtuc/ieee754@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "@xtuc/ieee754@npm:1.2.0"
|
||||
@ -7420,6 +7502,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@zxing/text-encoding@npm:0.9.0":
|
||||
version: 0.9.0
|
||||
resolution: "@zxing/text-encoding@npm:0.9.0"
|
||||
checksum: c23b12aee7639382e4949961304a1294776afaffa40f579e09ffecd0e5e68cf26ef3edd75009de46da8a536e571448755ca68b3e2ea707d53793c0edb2e2c34a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"AFFiNE@workspace:.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "AFFiNE@workspace:."
|
||||
@ -7447,6 +7536,7 @@ __metadata:
|
||||
happy-dom: ^8.9.0
|
||||
husky: ^8.0.3
|
||||
lint-staged: ^13.2.0
|
||||
msw: ^1.2.0
|
||||
nanoid: ^4.0.1
|
||||
nyc: ^15.1.0
|
||||
prettier: ^2.8.5
|
||||
@ -8665,6 +8755,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:4.1.1":
|
||||
version: 4.1.1
|
||||
resolution: "chalk@npm:4.1.1"
|
||||
dependencies:
|
||||
ansi-styles: ^4.1.0
|
||||
supports-color: ^7.1.0
|
||||
checksum: 036e973e665ba1a32c975e291d5f3d549bceeb7b1b983320d4598fb75d70fe20c5db5d62971ec0fe76cdbce83985a00ee42372416abfc3a5584465005a7855ed
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:5.2.0, chalk@npm:^5.2.0":
|
||||
version: 5.2.0
|
||||
resolution: "chalk@npm:5.2.0"
|
||||
@ -8693,7 +8793,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.2":
|
||||
"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "chalk@npm:4.1.2"
|
||||
dependencies:
|
||||
@ -8717,6 +8817,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chardet@npm:^0.7.0":
|
||||
version: 0.7.0
|
||||
resolution: "chardet@npm:0.7.0"
|
||||
checksum: 6fd5da1f5d18ff5712c1e0aed41da200d7c51c28f11b36ee3c7b483f3696dabc08927fc6b227735eb8f0e1215c9a8abd8154637f3eff8cada5959df7f58b024d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"check-error@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "check-error@npm:1.0.2"
|
||||
@ -8724,7 +8831,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chokidar@npm:^3.5.3":
|
||||
"chokidar@npm:^3.4.2, chokidar@npm:^3.5.3":
|
||||
version: 3.5.3
|
||||
resolution: "chokidar@npm:3.5.3"
|
||||
dependencies:
|
||||
@ -8861,6 +8968,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cli-width@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "cli-width@npm:3.0.0"
|
||||
checksum: 4c94af3769367a70e11ed69aa6095f1c600c0ff510f3921ab4045af961820d57c0233acfa8b6396037391f31b4c397e1f614d234294f979ff61430a6c166c3f6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"client-only@npm:0.0.1":
|
||||
version: 0.0.1
|
||||
resolution: "client-only@npm:0.0.1"
|
||||
@ -9219,6 +9333,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cookie@npm:^0.4.2":
|
||||
version: 0.4.2
|
||||
resolution: "cookie@npm:0.4.2"
|
||||
checksum: a00833c998bedf8e787b4c342defe5fa419abd96b32f4464f718b91022586b8f1bafbddd499288e75c037642493c83083da426c6a9080d309e3bd90fd11baa9b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"core-js-compat@npm:^3.25.1":
|
||||
version: 3.29.1
|
||||
resolution: "core-js-compat@npm:3.29.1"
|
||||
@ -11028,7 +11149,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"events@npm:^3.2.0":
|
||||
"events@npm:^3.2.0, events@npm:^3.3.0":
|
||||
version: 3.3.0
|
||||
resolution: "events@npm:3.3.0"
|
||||
checksum: f6f487ad2198aa41d878fa31452f1a3c00958f46e9019286ff4787c84aac329332ab45c9cdc8c445928fc6d7ded294b9e005a7fce9426488518017831b272780
|
||||
@ -11197,6 +11318,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"external-editor@npm:^3.0.3":
|
||||
version: 3.1.0
|
||||
resolution: "external-editor@npm:3.1.0"
|
||||
dependencies:
|
||||
chardet: ^0.7.0
|
||||
iconv-lite: ^0.4.24
|
||||
tmp: ^0.0.33
|
||||
checksum: 1c2a616a73f1b3435ce04030261bed0e22d4737e14b090bb48e58865da92529c9f2b05b893de650738d55e692d071819b45e1669259b2b354bc3154d27a698c7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"extract-zip@npm:^1.6.6":
|
||||
version: 1.7.0
|
||||
resolution: "extract-zip@npm:1.7.0"
|
||||
@ -11331,6 +11463,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"figures@npm:^3.0.0":
|
||||
version: 3.2.0
|
||||
resolution: "figures@npm:3.2.0"
|
||||
dependencies:
|
||||
escape-string-regexp: ^1.0.5
|
||||
checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"file-entry-cache@npm:^6.0.1":
|
||||
version: 6.0.1
|
||||
resolution: "file-entry-cache@npm:6.0.1"
|
||||
@ -12392,7 +12533,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql@npm:^16.0.0":
|
||||
"graphql@npm:^15.0.0 || ^16.0.0, graphql@npm:^16.0.0":
|
||||
version: 16.6.0
|
||||
resolution: "graphql@npm:16.6.0"
|
||||
checksum: bf1d9e3c1938ce3c1a81e909bd3ead1ae4707c577f91cff1ca2eca474bfbc7873d5d7b942e1e9777ff5a8304421dba57a4b76d7a29eb19de8711cb70e3c2415e
|
||||
@ -12536,6 +12677,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"headers-polyfill@npm:^3.1.0":
|
||||
version: 3.1.2
|
||||
resolution: "headers-polyfill@npm:3.1.2"
|
||||
checksum: 510ca9637ef652404dbd432e680418f8d418ba18094ef2f64c3d8de955ebf6e68d553c7f0aeaa5fc937d130b139c1e2d7c2066cd4cf0f740a4627924eaaee9db
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
|
||||
version: 3.3.2
|
||||
resolution: "hoist-non-react-statics@npm:3.3.2"
|
||||
@ -12751,7 +12899,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:0.4.24":
|
||||
"iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.24":
|
||||
version: 0.4.24
|
||||
resolution: "iconv-lite@npm:0.4.24"
|
||||
dependencies:
|
||||
@ -12889,6 +13037,29 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inquirer@npm:^8.2.0":
|
||||
version: 8.2.5
|
||||
resolution: "inquirer@npm:8.2.5"
|
||||
dependencies:
|
||||
ansi-escapes: ^4.2.1
|
||||
chalk: ^4.1.1
|
||||
cli-cursor: ^3.1.0
|
||||
cli-width: ^3.0.0
|
||||
external-editor: ^3.0.3
|
||||
figures: ^3.0.0
|
||||
lodash: ^4.17.21
|
||||
mute-stream: 0.0.8
|
||||
ora: ^5.4.1
|
||||
run-async: ^2.4.0
|
||||
rxjs: ^7.5.5
|
||||
string-width: ^4.1.0
|
||||
strip-ansi: ^6.0.0
|
||||
through: ^2.3.6
|
||||
wrap-ansi: ^7.0.0
|
||||
checksum: f13ee4c444187786fb393609dedf6b30870115a57b603f2e6424f29a99abc13446fd45ee22461c33c9c40a92a60a8df62d0d6b25d74fc6676fa4cb211de55b55
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.5":
|
||||
version: 1.0.5
|
||||
resolution: "internal-slot@npm:1.0.5"
|
||||
@ -13159,6 +13330,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-node-process@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "is-node-process@npm:1.0.1"
|
||||
checksum: 3ddb8a892a00f6eb9c2aea7e7e1426b8683512d9419933d95114f4f64b5455e26601c23a31c0682463890032136dd98a326988a770ab6b4eed54a43ade8bed50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-number-object@npm:^1.0.4":
|
||||
version: 1.0.7
|
||||
resolution: "is-number-object@npm:1.0.7"
|
||||
@ -14239,6 +14417,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"js-levenshtein@npm:^1.1.6":
|
||||
version: 1.1.6
|
||||
resolution: "js-levenshtein@npm:1.1.6"
|
||||
checksum: 409f052a7f1141be4058d97da7860e08efd97fc588b7a4c5cfa0548bc04f6d576644dae65ab630266dff685d56fb90d494e03d4d79cb484c287746b4f1bf0694
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"js-sdsl@npm:^4.1.4":
|
||||
version: 4.3.0
|
||||
resolution: "js-sdsl@npm:4.3.0"
|
||||
@ -15469,6 +15654,40 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"msw@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "msw@npm:1.2.0"
|
||||
dependencies:
|
||||
"@mswjs/cookies": ^0.2.2
|
||||
"@mswjs/interceptors": ^0.17.5
|
||||
"@open-draft/until": ^1.0.3
|
||||
"@types/cookie": ^0.4.1
|
||||
"@types/js-levenshtein": ^1.1.1
|
||||
chalk: 4.1.1
|
||||
chokidar: ^3.4.2
|
||||
cookie: ^0.4.2
|
||||
graphql: ^15.0.0 || ^16.0.0
|
||||
headers-polyfill: ^3.1.0
|
||||
inquirer: ^8.2.0
|
||||
is-node-process: ^1.0.1
|
||||
js-levenshtein: ^1.1.6
|
||||
node-fetch: ^2.6.7
|
||||
outvariant: ^1.3.0
|
||||
path-to-regexp: ^6.2.0
|
||||
strict-event-emitter: ^0.4.3
|
||||
type-fest: ^2.19.0
|
||||
yargs: ^17.3.1
|
||||
peerDependencies:
|
||||
typescript: ">= 4.4.x <= 5.0.x"
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
bin:
|
||||
msw: cli/index.js
|
||||
checksum: 2cea7fe0f2ebb59b11534896cbaa91dca65f4fb2272402549079cc4190847fc42f5367f331c552d576d59a3521f498da0384d53cf4960beaebd6165bbc44593b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"multipipe@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "multipipe@npm:1.0.2"
|
||||
@ -15490,6 +15709,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mute-stream@npm:0.0.8":
|
||||
version: 0.0.8
|
||||
resolution: "mute-stream@npm:0.0.8"
|
||||
checksum: ff48d251fc3f827e5b1206cda0ffdaec885e56057ee86a3155e1951bc940fd5f33531774b1cc8414d7668c10a8907f863f6561875ee6e8768931a62121a531a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mz@npm:^2.7.0":
|
||||
version: 2.7.0
|
||||
resolution: "mz@npm:2.7.0"
|
||||
@ -16150,7 +16376,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ora@npm:^5.1.0":
|
||||
"ora@npm:^5.1.0, ora@npm:^5.4.1":
|
||||
version: 5.4.1
|
||||
resolution: "ora@npm:5.4.1"
|
||||
dependencies:
|
||||
@ -16174,6 +16400,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"os-tmpdir@npm:~1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "os-tmpdir@npm:1.0.2"
|
||||
checksum: 5666560f7b9f10182548bf7013883265be33620b1c1b4a4d405c25be2636f970c5488ff3e6c48de75b55d02bde037249fe5dbfbb4c0fb7714953d56aed062e6d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"outvariant@npm:^1.2.1, outvariant@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "outvariant@npm:1.3.0"
|
||||
checksum: ac76ca375c1c642989e1c74f0e9ebac84c05bc9fdc8f28be949c16fae1658e9f1f2fb1133fe3cc1e98afabef78fe4298fe9360b5734baf8e6ad440c182680848
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-cancelable@npm:^2.0.0":
|
||||
version: 2.1.1
|
||||
resolution: "p-cancelable@npm:2.1.1"
|
||||
@ -16477,6 +16717,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-to-regexp@npm:^6.2.0":
|
||||
version: 6.2.1
|
||||
resolution: "path-to-regexp@npm:6.2.1"
|
||||
checksum: f0227af8284ea13300f4293ba111e3635142f976d4197f14d5ad1f124aebd9118783dd2e5f1fe16f7273743cc3dbeddfb7493f237bb27c10fdae07020cc9b698
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-type@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "path-type@npm:2.0.0"
|
||||
@ -17848,6 +18095,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"run-async@npm:^2.4.0":
|
||||
version: 2.4.1
|
||||
resolution: "run-async@npm:2.4.1"
|
||||
checksum: a2c88aa15df176f091a2878eb840e68d0bdee319d8d97bbb89112223259cebecb94bc0defd735662b83c2f7a30bed8cddb7d1674eb48ae7322dc602b22d03797
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"run-parallel@npm:^1.1.9":
|
||||
version: 1.2.0
|
||||
resolution: "run-parallel@npm:1.2.0"
|
||||
@ -17866,7 +18120,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rxjs@npm:^7.8.0":
|
||||
"rxjs@npm:^7.5.5, rxjs@npm:^7.8.0":
|
||||
version: 7.8.0
|
||||
resolution: "rxjs@npm:7.8.0"
|
||||
dependencies:
|
||||
@ -18057,6 +18311,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"set-cookie-parser@npm:^2.4.6":
|
||||
version: 2.6.0
|
||||
resolution: "set-cookie-parser@npm:2.6.0"
|
||||
checksum: bf11ebc594c53d84588f1b4c04f1b8ce14e0498b1c011b3d76b5c6d5aac481bbc3f7c5260ec4ce99bdc1d9aed19f9fc315e73166a36ca74d0f12349a73f6bdc9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"setprototypeof@npm:1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "setprototypeof@npm:1.2.0"
|
||||
@ -18541,6 +18802,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strict-event-emitter@npm:^0.2.4":
|
||||
version: 0.2.8
|
||||
resolution: "strict-event-emitter@npm:0.2.8"
|
||||
dependencies:
|
||||
events: ^3.3.0
|
||||
checksum: 6ac06fe72a6ee6ae64d20f1dd42838ea67342f1b5f32b03b3050d73ee6ecee44b4d5c4ed2965a7154b47991e215f373d4e789e2b2be2769cd80e356126c2ca53
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strict-event-emitter@npm:^0.4.3":
|
||||
version: 0.4.6
|
||||
resolution: "strict-event-emitter@npm:0.4.6"
|
||||
checksum: 4f4f2909613e7811de789991c06bfb770d6d6987e2ec5c66fa7485d0f07cc4e7e32eba0dcf26cee6d86af6c92946d7f4acdfaff57d0c4114df2cfa1bf0e3c091
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"strict-uri-encode@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "strict-uri-encode@npm:2.0.0"
|
||||
@ -19101,7 +19378,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"through@npm:2, through@npm:^2.3.8, through@npm:~2.3, through@npm:~2.3.1":
|
||||
"through@npm:2, through@npm:^2.3.6, through@npm:^2.3.8, through@npm:~2.3, through@npm:~2.3.1":
|
||||
version: 2.3.8
|
||||
resolution: "through@npm:2.3.8"
|
||||
checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd
|
||||
@ -19165,6 +19442,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tmp@npm:^0.0.33":
|
||||
version: 0.0.33
|
||||
resolution: "tmp@npm:0.0.33"
|
||||
dependencies:
|
||||
os-tmpdir: ~1.0.2
|
||||
checksum: 902d7aceb74453ea02abbf58c203f4a8fc1cead89b60b31e354f74ed5b3fb09ea817f94fb310f884a5d16987dd9fa5a735412a7c2dd088dd3d415aa819ae3a28
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tmp@npm:^0.2.0":
|
||||
version: 0.2.1
|
||||
resolution: "tmp@npm:0.2.1"
|
||||
@ -19817,7 +20103,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"util@npm:^0.12.0, util@npm:^0.12.4":
|
||||
"util@npm:^0.12.0, util@npm:^0.12.3, util@npm:^0.12.4":
|
||||
version: 0.12.5
|
||||
resolution: "util@npm:0.12.5"
|
||||
dependencies:
|
||||
@ -20090,6 +20376,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"web-encoding@npm:^1.1.5":
|
||||
version: 1.1.5
|
||||
resolution: "web-encoding@npm:1.1.5"
|
||||
dependencies:
|
||||
"@zxing/text-encoding": 0.9.0
|
||||
util: ^0.12.3
|
||||
dependenciesMeta:
|
||||
"@zxing/text-encoding":
|
||||
optional: true
|
||||
checksum: 2234a2b122f41006ce07859b3c0bf2e18f46144fda2907d5db0b571b76aa5c26977c646100ad9c00d2f8a4f6f2b848bc02147845d8c447ab365ec4eff376338d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"web-streams-polyfill@npm:^3.0.3":
|
||||
version: 3.2.1
|
||||
resolution: "web-streams-polyfill@npm:3.2.1"
|
||||
|
Loading…
Reference in New Issue
Block a user