From c6657e7a9b8fc5cc588ef2745d2910ae83778def Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Wed, 4 Jan 2023 18:08:11 +0800 Subject: [PATCH 001/298] feat: mock workspace process --- .../src/components/create-workspace/index.tsx | 83 +++++++++++++ .../src/components/workspace-modal/index.tsx | 117 ++++++++++++++++++ .../src/components/workspace-modal/styles.ts | 38 ++++++ packages/app/src/hooks/mock-data/mock.ts | 75 +++++++++++ .../app/src/pages/new-workspace/index.tsx | 47 +++++++ 5 files changed, 360 insertions(+) create mode 100644 packages/app/src/components/create-workspace/index.tsx create mode 100644 packages/app/src/components/workspace-modal/index.tsx create mode 100644 packages/app/src/components/workspace-modal/styles.ts create mode 100644 packages/app/src/hooks/mock-data/mock.ts create mode 100644 packages/app/src/pages/new-workspace/index.tsx diff --git a/packages/app/src/components/create-workspace/index.tsx b/packages/app/src/components/create-workspace/index.tsx new file mode 100644 index 0000000000..1a04d3ce9a --- /dev/null +++ b/packages/app/src/components/create-workspace/index.tsx @@ -0,0 +1,83 @@ +import { styled } from '@/styles'; +import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; +import { Button } from '@/ui/button'; +import { useState } from 'react'; +import { createWorkspace } from '@/hooks/mock-data/mock'; +import Input from '@/ui/input'; + +interface ModalProps { + open: boolean; + onClose: () => void; +} + +export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { + const [workspaceName, setWorkspaceName] = useState(''); + const handleCreateWorkspace = () => { + createWorkspace(workspaceName); + onClose(); + }; + return ( +
+ + +
+ New Workspace + { + onClose(); + }} + /> +
+ +

+ Workspace is your virtual space to capture, create and plan as + just one person or together as a team. +

+ { + setWorkspaceName(value); + }} + > + +
+
+
+
+ ); +}; + +const Header = styled('div')({ + position: 'relative', + height: '44px', +}); + +const Content = styled('div')({ + display: 'flex', + padding: '0 48px', + flexDirection: 'column', + alignItems: 'center', + gap: '16px', +}); + +const ContentTitle = styled('span')({ + fontSize: '20px', + lineHeight: '28px', + fontWeight: 600, + textAlign: 'left', + paddingBottom: '16px', +}); + +const Footer = styled('div')({ + height: '70px', + paddingLeft: '24px', + marginTop: '32px', + textAlign: 'center', +}); diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx new file mode 100644 index 0000000000..84e56dd60d --- /dev/null +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -0,0 +1,117 @@ +import { styled } from '@/styles'; +import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; +import { Button } from '@/ui/button'; +import { useEffect, useState } from 'react'; +import { getWorkspaceList, Workspace } from '@/hooks/mock-data/mock'; +import { CreateWorkspaceModal } from '../create-workspace'; + +interface LoginModalProps { + open: boolean; + onClose: () => void; +} + +export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { + const [workspaceList, setWorkspaceList] = useState([]); + const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false); + + useEffect(() => { + getList(); + }, []); + + const getList = () => { + const data = getWorkspaceList(); + setWorkspaceList(data); + }; + return ( +
+ + +
+ My workspace + { + onClose(); + }} + /> +
+ + + {workspaceList.map(item => { + return ( + + + {item.name} + {item.type === 'local' && local} + {item.type === 'share' && share} + {item.isPublish ? 'public' : 'private'} + {item.isLocal ? 'local' : 'local'} + + ); + })} +
  • + +
  • +
    +
    +
    + +
    + { + setCreateWorkspaceOpen(false); + getList(); + }} + > +
    +
    +
    + ); +}; + +const Header = styled('div')({ + position: 'relative', + height: '44px', +}); + +const Content = styled('div')({ + padding: '0 20px', + flexDirection: 'column', + alignItems: 'center', + gap: '16px', +}); + +const ContentTitle = styled('span')({ + fontSize: '20px', + lineHeight: '28px', + fontWeight: 600, + textAlign: 'left', + paddingBottom: '16px', +}); + +const Footer = styled('div')({ + height: '70px', + paddingLeft: '24px', + marginTop: '32px', + textAlign: 'center', +}); + +const WorkspaceList = styled('div')({ + display: 'grid', + gridRowGap: '10px', + gridColumnGap: '10px', + fontSize: '16px', + gridTemplateColumns: 'repeat(2, 1fr)', +}); + +const WorkspaceItem = styled('div')({ + border: '1px solid #e5e5e5', +}); diff --git a/packages/app/src/components/workspace-modal/styles.ts b/packages/app/src/components/workspace-modal/styles.ts new file mode 100644 index 0000000000..40a8bcc375 --- /dev/null +++ b/packages/app/src/components/workspace-modal/styles.ts @@ -0,0 +1,38 @@ +import { displayFlex, styled } from '@/styles'; + +export const StyledTitle = styled.div(() => { + return { + ...displayFlex('center', 'center'), + fontSize: '20px', + fontWeight: 500, + marginTop: '60px', + lineHeight: 1, + }; +}); + +export const StyledContent = styled.div(() => { + return { + padding: '0 40px', + marginTop: '32px', + fontSize: '18px', + lineHeight: '25px', + 'p:not(last-of-type)': { + marginBottom: '10px', + }, + }; +}); + +export const StyledButton = styled.div(({ theme }) => { + return { + width: '146px', + height: '42px', + background: theme.colors.primaryColor, + color: '#FFFFFF', + fontSize: '18px', + fontWeight: 500, + borderRadius: '21px', + margin: '52px auto 0', + cursor: 'pointer', + ...displayFlex('center', 'center'), + }; +}); diff --git a/packages/app/src/hooks/mock-data/mock.ts b/packages/app/src/hooks/mock-data/mock.ts new file mode 100644 index 0000000000..e484dfcc87 --- /dev/null +++ b/packages/app/src/hooks/mock-data/mock.ts @@ -0,0 +1,75 @@ +export interface Workspace { + name: string; // 名称 + id: string; //唯一标识 + isPublish?: boolean; // 是否公开 + isLocal?: boolean; // 是否全部数据都在本地 + avatar?: string; // 封面 + type: 'local' | 'cloud' | 'share'; // cloud: 云端(本次暂不支持),local: 本地,share: 分享 + workspaceOwner?: User; // 本地工作空间的拥有者 +} + +interface User { + name: string; + id: string; + email: string; + avatar: string; +} + +export function getWorkspaceList(): Workspace[] { + const workspacesMeta = JSON.parse( + localStorage.getItem('affine-workspace') ?? '[]' + ); + return workspacesMeta; +} + +export function getPagesByWorkspaceId(workspaceId: string) { + if (!workspaceId) return []; + const workspacesMeta = []; + for (let i = 0; i < 10; i++) { + workspacesMeta.push({ + id: 'page-' + i, + name: 'page ' + i, + }); + } +} + +export function addWorkSpace(workspaceData: Workspace) { + const workspacesMeta = getWorkspaceList(); + workspacesMeta.push(workspaceData); + localStorage.setItem('affine-workspace', JSON.stringify(workspacesMeta)); +} + +export function deleteWorkspaceById(workspaceId: string) { + const workspacesMeta = getWorkspaceList(); + const newWorkspacesMeta = workspacesMeta.filter(() => { + return workspaceId !== workspaceId; + }); + localStorage.setItem('affine-workspace', JSON.stringify(newWorkspacesMeta)); +} + +export function updateWorkspaceById( + workspaceId: string, + workspaceData: Workspace +) { + const workspacesMeta = getWorkspaceList(); + const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { + if (workspace.id === workspaceId) { + return workspaceData; + } + return workspace; + }); + localStorage.setItem('affine-workspace', JSON.stringify(newWorkspacesMeta)); +} +export function createWorkspace(workspaceName: string) { + const workspaceData = { + name: workspaceName, + id: 'workspace-' + Date.now(), + isPublish: false, + isLocal: true, + avatar: '', + type: 'local', + } as Workspace; + const workspacesMeta = getWorkspaceList(); + workspacesMeta.push(workspaceData); + localStorage.setItem('affine-workspace', JSON.stringify(workspacesMeta)); +} diff --git a/packages/app/src/pages/new-workspace/index.tsx b/packages/app/src/pages/new-workspace/index.tsx new file mode 100644 index 0000000000..b46e99d917 --- /dev/null +++ b/packages/app/src/pages/new-workspace/index.tsx @@ -0,0 +1,47 @@ +import { WorkspaceModal } from '@/components/workspace-modal'; +import { getWorkspaceList } from '@/hooks/mock-data/mock'; +import { useEffect, useState } from 'react'; +import { styled } from '@/styles'; +import Button from '@/ui/button/Button'; + +const Page = () => { + const [open, setOpen] = useState(false); + + useEffect(() => { + const data = getWorkspaceList(); + if (!data.length) { + setOpen(true); + } + }, []); + return ( + +
    workspace
    +
    + +
    + { + setOpen(false); + }} + > +
    + ); +}; +export default Page; + +const Workspace = styled.div(({ theme }) => { + return { + height: '100vh', + background: theme.colors.pageBackground, + color: '#FFFFFF', + fontSize: '18px', + fontWeight: 500, + }; +}); From 5f729464a26ecc704813d082f592e0a45a26f6b6 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Wed, 4 Jan 2023 21:49:56 +0800 Subject: [PATCH 002/298] feat: learn poc --- .../src/components/workspace-modal/index.tsx | 18 ++++++++++++------ packages/app/src/pages/new-workspace/index.tsx | 6 +++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 84e56dd60d..f6a2efdb96 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -27,7 +27,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
    - My workspace + My Workspace List { return ( - {item.name} - {item.type === 'local' && local} - {item.type === 'share' && share} - {item.isPublish ? 'public' : 'private'} - {item.isLocal ? 'local' : 'local'} + {item.name}/ + {item.type === 'local' && local} + {item.type === 'share' && share}/ + {item.isPublish ? 'isPublish' : 'isPrivate'}/ + {item.isLocal ? 'isLocal' : ''}/ ); })}
  • Date: Thu, 5 Jan 2023 16:05:54 +0800 Subject: [PATCH 003/298] feat:mock workspace-setting --- .../src/components/workspace-modal/index.tsx | 20 +++- .../workspace-setting/general/general.tsx | 17 +-- .../workspace-setting/workspace-setting.tsx | 24 ++-- .../SelectorPopperContent.tsx | 18 +-- .../WorkspaceSelector/WorkspaceSelector.tsx | 69 +++++------ .../components/workspace-slider-bar/index.tsx | 16 +++ packages/app/src/hooks/mock-data/mock.ts | 108 ++++++++++++------ .../app/src/pages/new-workspace/index.tsx | 6 +- .../providers/app-state-provider/context.ts | 4 - 9 files changed, 160 insertions(+), 122 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index f6a2efdb96..05b1f6632b 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -2,7 +2,11 @@ import { styled } from '@/styles'; import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Button } from '@/ui/button'; import { useEffect, useState } from 'react'; -import { getWorkspaceList, Workspace } from '@/hooks/mock-data/mock'; +import { + getWorkspaces, + Workspace, + setActiveWorkspace, +} from '@/hooks/mock-data/mock'; import { CreateWorkspaceModal } from '../create-workspace'; interface LoginModalProps { @@ -19,7 +23,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { }, []); const getList = () => { - const data = getWorkspaceList(); + const data = getWorkspaces(); setWorkspaceList(data); }; return ( @@ -40,11 +44,16 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { {workspaceList.map(item => { return ( - - + { + setActiveWorkspace(item); + onClose(); + }} + key={item.id} + > {item.name}/ {item.type === 'local' && local} - {item.type === 'share' && share}/ + {item.type === 'join' && join}/ {item.isPublish ? 'isPublish' : 'isPrivate'}/ {item.isLocal ? 'isLocal' : ''}/ @@ -70,6 +79,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { onClose={() => { setCreateWorkspaceOpen(false); getList(); + onClose(); }} > diff --git a/packages/app/src/components/workspace-setting/general/general.tsx b/packages/app/src/components/workspace-setting/general/general.tsx index cef2daccb7..82389370b3 100644 --- a/packages/app/src/components/workspace-setting/general/general.tsx +++ b/packages/app/src/components/workspace-setting/general/general.tsx @@ -9,25 +9,22 @@ import { StyledSettingH2 } from '../style'; import { useState } from 'react'; import { Button } from '@/ui/button'; import Input from '@/ui/input'; -import { getDataCenter, Workspace, WorkspaceType } from '@affine/datacenter'; +import { getDataCenter } from '@affine/datacenter'; import { useAppState } from '@/providers/app-state-provider'; -import { WorkspaceDetails } from '@/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent'; import { WorkspaceDelete } from './delete'; import { Workspace as StoreWorkspace } from '@blocksuite/store'; import { debounce } from '@/utils'; import { WorkspaceLeave } from './leave'; import { Upload } from '@/components/file-upload'; +import { Workspace } from '@/hooks/mock-data/mock'; export const GeneralPage = ({ workspace, - owner, }: { workspace: Workspace; - owner: WorkspaceDetails[string]['owner']; workspaces: Record; }) => { const { - user, currentWorkspace, workspacesMeta, workspaces, @@ -36,14 +33,11 @@ export const GeneralPage = ({ const [showDelete, setShowDelete] = useState(false); const [showLeave, setShowLeave] = useState(false); const [uploading, setUploading] = useState(false); - const [workspaceName, setWorkspaceName] = useState( - workspaces[workspace.id]?.meta.name || - (workspace.type === WorkspaceType.Private && user ? user.name : '') - ); + const [workspaceName, setWorkspaceName] = useState(''); const debouncedRefreshWorkspacesMeta = debounce(() => { refreshWorkspacesMeta(); }, 100); - const isOwner = user && owner.id === user.id; + const isOwner = true; const handleChangeWorkSpaceName = (newName: string) => { setWorkspaceName(newName); currentWorkspace?.meta.setName(newName); @@ -119,7 +113,6 @@ export const GeneralPage = ({ width={327} value={workspaceName} placeholder="Workspace Name" - disabled={!isOwner} maxLength={14} minLength={1} onChange={handleChangeWorkSpaceName} @@ -130,7 +123,7 @@ export const GeneralPage = ({ diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index c1b07e2441..238ff1f412 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -36,14 +36,14 @@ import { useCallback, useEffect, useState } from 'react'; import { Button, IconButton } from '@/ui/button'; import Input from '@/ui/input'; import { InviteMembers } from '../invite-members/index'; -import { Workspace, Member, getDataCenter } from '@affine/datacenter'; +import { Member, getDataCenter } from '@affine/datacenter'; import { Avatar } from '@mui/material'; import { Menu, MenuItem } from '@/ui/menu'; import { toast } from '@/ui/toast'; import { Empty } from '@/ui/empty'; import { useAppState } from '@/providers/app-state-provider'; -import { WorkspaceDetails } from '../workspace-slider-bar/WorkspaceSelector/SelectorPopperContent'; import { GeneralPage } from './general'; +import { getActiveWorkspace, Workspace } from '@/hooks/mock-data/mock'; enum ActiveTab { 'general' = 'general', @@ -59,8 +59,6 @@ type SettingTabProps = { type WorkspaceSettingProps = { isShow: boolean; onClose?: () => void; - workspace: Workspace; - owner: WorkspaceDetails[string]['owner']; }; const WorkspaceSettingTab = ({ activeTab, onTabChange }: SettingTabProps) => { @@ -106,18 +104,18 @@ const WorkspaceSettingTab = ({ activeTab, onTabChange }: SettingTabProps) => { export const WorkspaceSetting = ({ isShow, onClose, - workspace, - owner, }: WorkspaceSettingProps) => { - const { user, workspaces } = useAppState(); + const { workspaces } = useAppState(); const [activeTab, setActiveTab] = useState(ActiveTab.general); const handleTabChange = (tab: ActiveTab) => { setActiveTab(tab); }; + + const workspace = getActiveWorkspace(); const handleClickClose = () => { onClose && onClose(); }; - const isOwner = user && owner.id === user.id; + const isOwner = true; useEffect(() => { // reset tab when modal is closed if (!isShow) { @@ -125,7 +123,7 @@ export const WorkspaceSetting = ({ } }, [isShow]); return ( - + {isOwner ? ( @@ -141,11 +139,7 @@ export const WorkspaceSetting = ({ ) : null} {activeTab === ActiveTab.general && ( - + )} {activeTab === ActiveTab.members && workspace && ( @@ -295,7 +289,7 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { const PublishPage = ({ workspace }: { workspace: Workspace }) => { const shareUrl = window.location.host + '/workspace/' + workspace.id; const [publicStatus, setPublicStatus] = useState( - workspace.public + workspace.isPublish ?? false ); const togglePublic = (flag: boolean) => { getDataCenter() diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx index 8e101307bb..494fdd495d 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx @@ -130,16 +130,16 @@ export const SelectorPopperContent = ({ {settingWorkspace ? ( ) : null} diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index 4e0299888f..22013ba674 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -1,53 +1,46 @@ -import { Popper } from '@/ui/popper'; import { Avatar, WorkspaceName, SelectorWrapper } from './styles'; -import { SelectorPopperContent } from './SelectorPopperContent'; -import { useState } from 'react'; -import { useAppState } from '@/providers/app-state-provider'; -import { WorkspaceType } from '@affine/datacenter'; +import { useEffect, useState } from 'react'; import { AffineIcon } from '../icons/icons'; +import { WorkspaceModal } from '@/components/workspace-modal'; +import { getActiveWorkspace } from '@/hooks/mock-data/mock'; export const WorkspaceSelector = () => { - const [isShow, setIsShow] = useState(false); - const { currentWorkspace, workspacesMeta, currentWorkspaceId, user } = - useAppState(); - const workspaceMeta = workspacesMeta.find( - meta => String(meta.id) === String(currentWorkspaceId) - ); + const [workspaceListShow, setWorkspaceListShow] = useState(false); + const [workspace, setWorkSpace] = useState(getActiveWorkspace()); + useEffect(() => { + getWorkspace(); + }, [workspaceListShow]); + const getWorkspace = () => { + const workspace = getActiveWorkspace(); + setWorkSpace(workspace); + }; + return ( - } - zIndex={1000} - placement="bottom-start" - trigger="click" - onVisibleChange={setIsShow} - > - + <> + { + setWorkspaceListShow(true); + }} + data-testid="current-workspace" + > - {workspaceMeta?.type === WorkspaceType.Private && user ? ( - user?.name[0] - ) : ( - - )} + - {workspaceMeta?.type === WorkspaceType.Private - ? user - ? user.name - : 'AFFiNE' - : currentWorkspace?.meta.name || 'AFFiNE'} + {workspace?.name ?? 'AFFiNE'} - + { + setWorkspaceListShow(false); + getWorkspace(); + }} + > + ); }; diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index 559e0b983a..63305638a5 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -21,6 +21,7 @@ import { ImportIcon, TrashIcon, AddIcon, + SettingsIcon, } from '@blocksuite/icons'; import Link from 'next/link'; import { Tooltip } from '@/ui/tooltip'; @@ -31,6 +32,7 @@ import { IconButton } from '@/ui/button'; import useLocalStorage from '@/hooks/use-local-storage'; import usePageMetaList from '@/hooks/use-page-meta-list'; import { usePageHelper } from '@/hooks/use-page-helper'; +import { WorkspaceSetting } from '@/components/workspace-setting'; const FavoriteList = ({ showList }: { showList: boolean }) => { const { openPage } = usePageHelper(); @@ -146,6 +148,20 @@ export const WorkSpaceSliderBar = () => { + { + console.log('ttt'); + }} + > + Setting + + + { + console.log(1231231); + }} + /> { diff --git a/packages/app/src/hooks/mock-data/mock.ts b/packages/app/src/hooks/mock-data/mock.ts index e484dfcc87..91fcfaa85f 100644 --- a/packages/app/src/hooks/mock-data/mock.ts +++ b/packages/app/src/hooks/mock-data/mock.ts @@ -4,7 +4,7 @@ export interface Workspace { isPublish?: boolean; // 是否公开 isLocal?: boolean; // 是否全部数据都在本地 avatar?: string; // 封面 - type: 'local' | 'cloud' | 'share'; // cloud: 云端(本次暂不支持),local: 本地,share: 分享 + type: 'local' | 'cloud' | 'join'; // cloud: 云端(本次暂不支持),local: 本地,join : 加入别人的 workspaceOwner?: User; // 本地工作空间的拥有者 } @@ -15,45 +15,15 @@ interface User { avatar: string; } -export function getWorkspaceList(): Workspace[] { - const workspacesMeta = JSON.parse( - localStorage.getItem('affine-workspace') ?? '[]' - ); - return workspacesMeta; -} - -export function getPagesByWorkspaceId(workspaceId: string) { - if (!workspaceId) return []; - const workspacesMeta = []; - for (let i = 0; i < 10; i++) { - workspacesMeta.push({ - id: 'page-' + i, - name: 'page ' + i, - }); - } -} - -export function addWorkSpace(workspaceData: Workspace) { - const workspacesMeta = getWorkspaceList(); - workspacesMeta.push(workspaceData); - localStorage.setItem('affine-workspace', JSON.stringify(workspacesMeta)); -} - -export function deleteWorkspaceById(workspaceId: string) { - const workspacesMeta = getWorkspaceList(); - const newWorkspacesMeta = workspacesMeta.filter(() => { - return workspaceId !== workspaceId; - }); - localStorage.setItem('affine-workspace', JSON.stringify(newWorkspacesMeta)); -} - -export function updateWorkspaceById( +export function updateWorkspaceMeta( workspaceId: string, workspaceData: Workspace ) { - const workspacesMeta = getWorkspaceList(); + const workspacesMeta = getWorkspaces(); const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { if (workspace.id === workspaceId) { + workspaceData.name && (workspace.name = workspaceData.name); + workspaceData.avatar && (workspace.avatar = workspaceData.avatar); return workspaceData; } return workspace; @@ -69,7 +39,73 @@ export function createWorkspace(workspaceName: string) { avatar: '', type: 'local', } as Workspace; - const workspacesMeta = getWorkspaceList(); + const workspacesMeta = getWorkspaces(); workspacesMeta.push(workspaceData); localStorage.setItem('affine-workspace', JSON.stringify(workspacesMeta)); + setActiveWorkspace(workspaceData); +} + +export function getWorkspaces(): Workspace[] { + const workspacesMeta = JSON.parse( + localStorage.getItem('affine-workspace') ?? '[]' + ); + return workspacesMeta; +} + +export function deleteWorkspace(workspaceId: string) { + const workspacesMeta = getWorkspaces(); + const newWorkspacesMeta = workspacesMeta.filter(() => { + return workspaceId !== workspaceId; + }); + localStorage.setItem('affine-workspace', JSON.stringify(newWorkspacesMeta)); +} + +export function getMembers(id: string): User[] { + const memberMap = JSON.parse(localStorage.getItem('affine-member') ?? '{}'); + return memberMap[id] || []; +} + +export function leaveWorkspace(id: string) { + return true; +} + +export function setWorkspacePublish(id: string, isPublish: boolean): boolean { + const workspacesMeta = getWorkspaces(); + const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { + if (workspace.id === id) { + workspace.isPublish = isPublish; + } + return workspace; + }); + localStorage.setItem('affine-workspace', JSON.stringify(newWorkspacesMeta)); + return isPublish; +} + +export function getWorkspaceById(id: string) { + const workspacesMeta = getWorkspaces(); + return workspacesMeta.find((workspace: Workspace) => { + return workspace.id === id; + }); +} + +export function getPagesByWorkspaceId(workspaceId: string) { + if (!workspaceId) return []; + const workspacesMeta = []; + for (let i = 0; i < 10; i++) { + workspacesMeta.push({ + id: 'page-' + i, + name: 'page ' + i, + }); + } +} + +export function getActiveWorkspace(): Workspace { + return JSON.parse(localStorage.getItem('affine-active-workspace') ?? '{}'); +} + +export function setActiveWorkspace(workspaceData: Workspace) { + localStorage.setItem( + 'affine-active-workspace', + JSON.stringify(workspaceData) + ); } diff --git a/packages/app/src/pages/new-workspace/index.tsx b/packages/app/src/pages/new-workspace/index.tsx index 2b04453508..1a1d9e1a44 100644 --- a/packages/app/src/pages/new-workspace/index.tsx +++ b/packages/app/src/pages/new-workspace/index.tsx @@ -1,14 +1,14 @@ import { WorkspaceModal } from '@/components/workspace-modal'; -import { getWorkspaceList } from '@/hooks/mock-data/mock'; +import { getWorkspaces } from '@/hooks/mock-data/mock'; import { useEffect, useState } from 'react'; import { styled } from '@/styles'; import Button from '@/ui/button/Button'; const Page = () => { - const [open, setOpen] = useState(true); + const [open, setOpen] = useState(false); useEffect(() => { - const data = getWorkspaceList(); + const data = getWorkspaces(); if (!data.length) { setOpen(true); } diff --git a/packages/app/src/providers/app-state-provider/context.ts b/packages/app/src/providers/app-state-provider/context.ts index ee6b41d05a..98e535396e 100644 --- a/packages/app/src/providers/app-state-provider/context.ts +++ b/packages/app/src/providers/app-state-provider/context.ts @@ -40,14 +40,10 @@ export interface AppStateContext extends AppStateValue { export const AppState = createContext({ user: null, workspacesMeta: [], - currentWorkspaceId: '', currentWorkspace: null, - currentPage: null, - editor: null, - // eslint-disable-next-line @typescript-eslint/no-empty-function setState: () => {}, createEditor: undefined, From 55dbc8ad3b2ce69b9e32a17f4b542fc92902512e Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Thu, 5 Jan 2023 17:11:24 +0800 Subject: [PATCH 004/298] feat: adjust modal height --- packages/app/src/components/workspace-modal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 05b1f6632b..24d9782c06 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -29,7 +29,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { return (
    - +
    My Workspace List Date: Thu, 5 Jan 2023 17:32:39 +0800 Subject: [PATCH 005/298] feat: mock login --- .../src/components/workspace-modal/index.tsx | 56 +++++++++++++++++-- .../workspace-setting/general/general.tsx | 7 +-- .../workspace-setting/workspace-setting.tsx | 26 ++++----- .../components/workspace-slider-bar/index.tsx | 8 ++- .../components/workspace-slider-bar/style.ts | 1 + packages/app/src/hooks/mock-data/mock.ts | 22 +++++++- packages/app/src/ui/confirm/Confirm.tsx | 4 +- 7 files changed, 95 insertions(+), 29 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 05b1f6632b..479b22c99e 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -6,8 +6,14 @@ import { getWorkspaces, Workspace, setActiveWorkspace, + Login, + User, + getUserInfo, + SignOut, } from '@/hooks/mock-data/mock'; import { CreateWorkspaceModal } from '../create-workspace'; +import { useConfirm } from '@/providers/confirm-provider'; +import { toast } from '@/ui/toast'; interface LoginModalProps { open: boolean; @@ -16,20 +22,30 @@ interface LoginModalProps { export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { const [workspaceList, setWorkspaceList] = useState([]); + const [user, setUser] = useState(); const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false); - + const { confirm } = useConfirm(); useEffect(() => { - getList(); + setList(); + setUserInfo(); }, []); - const getList = () => { + const setList = () => { const data = getWorkspaces(); setWorkspaceList(data); }; + const setUserInfo = () => { + const data = getUserInfo(); + setUser(data); + }; return (
    - +
    My Workspace List {
    - + {!user ? ( + + ) : ( + + )}
    { setCreateWorkspaceOpen(false); - getList(); + setList(); onClose(); + confirm({ + title: 'Enable AFFiNE Cloud?', + content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`, + confirmText: user ? 'Enable' : 'Sign in and Enable', + cancelText: 'Skip', + }).then(confirm => { + confirm && Login(); + }); }} > @@ -98,6 +141,7 @@ const Content = styled('div')({ flexDirection: 'column', alignItems: 'center', gap: '16px', + flex: 1, }); const ContentTitle = styled('span')({ diff --git a/packages/app/src/components/workspace-setting/general/general.tsx b/packages/app/src/components/workspace-setting/general/general.tsx index 82389370b3..fa72178869 100644 --- a/packages/app/src/components/workspace-setting/general/general.tsx +++ b/packages/app/src/components/workspace-setting/general/general.tsx @@ -16,7 +16,7 @@ import { Workspace as StoreWorkspace } from '@blocksuite/store'; import { debounce } from '@/utils'; import { WorkspaceLeave } from './leave'; import { Upload } from '@/components/file-upload'; -import { Workspace } from '@/hooks/mock-data/mock'; +import { getUserInfo, Workspace } from '@/hooks/mock-data/mock'; export const GeneralPage = ({ workspace, @@ -30,6 +30,7 @@ export const GeneralPage = ({ workspaces, refreshWorkspacesMeta, } = useAppState(); + // const user = getUserInfo(); const [showDelete, setShowDelete] = useState(false); const [showLeave, setShowLeave] = useState(false); const [uploading, setUploading] = useState(false); @@ -38,11 +39,9 @@ export const GeneralPage = ({ refreshWorkspacesMeta(); }, 100); const isOwner = true; + const handleChangeWorkSpaceName = (newName: string) => { setWorkspaceName(newName); - currentWorkspace?.meta.setName(newName); - workspaces[workspace.id]?.meta.setName(newName); - debouncedRefreshWorkspacesMeta(); }; const currentWorkspaceIndex = workspacesMeta.findIndex( meta => meta.id === workspace.id diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index 238ff1f412..f1a9256dbf 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -43,7 +43,11 @@ import { toast } from '@/ui/toast'; import { Empty } from '@/ui/empty'; import { useAppState } from '@/providers/app-state-provider'; import { GeneralPage } from './general'; -import { getActiveWorkspace, Workspace } from '@/hooks/mock-data/mock'; +import { + getActiveWorkspace, + setWorkspacePublish, + Workspace, +} from '@/hooks/mock-data/mock'; enum ActiveTab { 'general' = 'general', @@ -112,6 +116,7 @@ export const WorkspaceSetting = ({ }; const workspace = getActiveWorkspace(); + console.log('workspace: ', workspace); const handleClickClose = () => { onClose && onClose(); }; @@ -123,7 +128,7 @@ export const WorkspaceSetting = ({ } }, [isShow]); return ( - + {isOwner ? ( @@ -287,23 +292,16 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { }; const PublishPage = ({ workspace }: { workspace: Workspace }) => { - const shareUrl = window.location.host + '/workspace/' + workspace.id; + const shareUrl = + window.location.host + '/workspace/' + workspace.id + '?share=true'; const [publicStatus, setPublicStatus] = useState( workspace.isPublish ?? false ); const togglePublic = (flag: boolean) => { - getDataCenter() - .then(dc => - dc.apis.updateWorkspace({ - id: workspace.id, - public: flag, - }) - ) - .then(data => { - setPublicStatus(data?.public); - toast('Updated Public Status Success'); - }); + const isPublic = setWorkspacePublish(workspace.id, flag); + setPublicStatus(isPublic); }; + const copyUrl = () => { navigator.clipboard.writeText(shareUrl); toast('Copied url to clipboard'); diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index 63305638a5..b9132fab52 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -76,6 +76,8 @@ export const WorkSpaceSliderBar = () => { const [showTip, setShowTip] = useState(false); const [show, setShow] = useLocalStorage('AFFiNE_SLIDE_BAR', false, true); + const [showWorkspaceSetting, setShowWorkspaceSetting] = useState(false); + const paths = { all: currentWorkspaceId ? `/workspace/${currentWorkspaceId}/all` : '', favorite: currentWorkspaceId @@ -150,16 +152,16 @@ export const WorkSpaceSliderBar = () => { { - console.log('ttt'); + setShowWorkspaceSetting(true); }} > Setting { - console.log(1231231); + setShowWorkspaceSetting(false); }} /> diff --git a/packages/app/src/components/workspace-slider-bar/style.ts b/packages/app/src/components/workspace-slider-bar/style.ts index f29de60a1e..6f380b43e1 100644 --- a/packages/app/src/components/workspace-slider-bar/style.ts +++ b/packages/app/src/components/workspace-slider-bar/style.ts @@ -62,6 +62,7 @@ export const StyledListItem = styled.div<{ color: active ? theme.colors.primaryColor : theme.colors.popoverColor, paddingLeft: '12px', borderRadius: '5px', + cursor: 'pointer', ...displayFlex('flex-start', 'center'), ...(disabled ? { diff --git a/packages/app/src/hooks/mock-data/mock.ts b/packages/app/src/hooks/mock-data/mock.ts index 91fcfaa85f..6f5f5f289c 100644 --- a/packages/app/src/hooks/mock-data/mock.ts +++ b/packages/app/src/hooks/mock-data/mock.ts @@ -8,7 +8,7 @@ export interface Workspace { workspaceOwner?: User; // 本地工作空间的拥有者 } -interface User { +export interface User { name: string; id: string; email: string; @@ -109,3 +109,23 @@ export function setActiveWorkspace(workspaceData: Workspace) { JSON.stringify(workspaceData) ); } + +export function getUserInfo(): User { + return JSON.parse(localStorage.getItem('affine-user') ?? 'null'); +} + +export function Login(): void { + localStorage.setItem( + 'affine-user', + JSON.stringify({ + name: 'Diamond', + id: 'ttt', + email: 'diamond.shx@gmail.com', + avatar: 'string', + }) + ); +} + +export function SignOut(): void { + localStorage.removeItem('affine-user'); +} diff --git a/packages/app/src/ui/confirm/Confirm.tsx b/packages/app/src/ui/confirm/Confirm.tsx index d3de35adb1..7b789c4f89 100644 --- a/packages/app/src/ui/confirm/Confirm.tsx +++ b/packages/app/src/ui/confirm/Confirm.tsx @@ -11,6 +11,7 @@ export type ConfirmProps = { title?: string; content?: string; confirmText?: string; + cancelText?: string; // TODO: Confirm button's color should depend on confirm type confirmType?: 'primary' | 'warning' | 'danger'; onConfirm?: () => void; @@ -24,6 +25,7 @@ export const Confirm = ({ confirmType, onConfirm, onCancel, + cancelText = 'Cancel', }: ConfirmProps) => { const [open, setOpen] = useState(true); return ( @@ -48,7 +50,7 @@ export const Confirm = ({ }} style={{ marginRight: '24px' }} > - Cancel + {cancelText}
  • +

    + Tips:Workspace is your virtual space to capture, create and plan + as just one person or together as a team. +

    Date: Thu, 5 Jan 2023 17:55:00 +0800 Subject: [PATCH 007/298] feat: add icons --- packages/app/src/components/workspace-modal/index.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 46cd1a9182..de0ae36fa3 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -16,10 +16,10 @@ import { CloudUnsyncedIcon, CloudInsyncIcon, UsersIcon, + AddIcon, } from '@blocksuite/icons'; import { useConfirm } from '@/providers/confirm-provider'; import { toast } from '@/ui/toast'; - interface LoginModalProps { open: boolean; onClose: () => void; @@ -76,6 +76,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { style={{ float: 'left', marginTop: '6px', + marginLeft: '10px', marginRight: '10px', }} width="24" @@ -122,6 +123,14 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { setCreateWorkspaceOpen(true); }} > + Create Or Import From 27b7c4e8fb5ecb1e996bd2aab098fa4914668e13 Mon Sep 17 00:00:00 2001 From: QiShaoXuan Date: Thu, 5 Jan 2023 18:33:17 +0800 Subject: [PATCH 008/298] chore: remove useless file & code --- .../providers/app-state-provider/context.ts | 4 +- .../app-state-provider/dynamic-blocksuite.tsx | 22 +------ .../src/providers/app-state-provider/hooks.ts | 51 -------------- .../providers/app-state-provider/provider.tsx | 66 ++++--------------- 4 files changed, 18 insertions(+), 125 deletions(-) delete mode 100644 packages/app/src/providers/app-state-provider/hooks.ts diff --git a/packages/app/src/providers/app-state-provider/context.ts b/packages/app/src/providers/app-state-provider/context.ts index 98e535396e..f907246edf 100644 --- a/packages/app/src/providers/app-state-provider/context.ts +++ b/packages/app/src/providers/app-state-provider/context.ts @@ -5,6 +5,7 @@ import type { Workspace as StoreWorkspace, } from '@blocksuite/store'; import type { EditorContainer } from '@blocksuite/editor'; + export type LoadWorkspaceHandler = ( workspaceId: string, user?: AccessTokenMessage | null @@ -20,7 +21,7 @@ export interface AppStateValue { currentPage: StorePage | null; - workspaces: Record; + // workspaces: Record; editor: EditorContainer | null; synced: boolean; @@ -53,7 +54,6 @@ export const AppState = createContext({ synced: false, // eslint-disable-next-line @typescript-eslint/no-empty-function refreshWorkspacesMeta: () => {}, - workspaces: {}, }); export const useAppState = () => { diff --git a/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx b/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx index 3a8fb7671c..4b7b876545 100644 --- a/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx +++ b/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx @@ -2,31 +2,13 @@ import { useEffect } from 'react'; import type { Page } from '@blocksuite/store'; import '@blocksuite/blocks'; import { EditorContainer } from '@blocksuite/editor'; -import type { LoadWorkspaceHandler, CreateEditorHandler } from './context'; -import { getDataCenter } from '@affine/datacenter'; +import type { CreateEditorHandler } from './context'; interface Props { - setLoadWorkspaceHandler: (handler: LoadWorkspaceHandler) => void; setCreateEditorHandler: (handler: CreateEditorHandler) => void; } -const DynamicBlocksuite = ({ - setLoadWorkspaceHandler, - setCreateEditorHandler, -}: Props) => { - useEffect(() => { - const openWorkspace: LoadWorkspaceHandler = async (workspaceId: string) => { - if (workspaceId) { - const dc = await getDataCenter(); - return dc.load(workspaceId, { providerId: 'affine' }); - } else { - return null; - } - }; - - setLoadWorkspaceHandler(openWorkspace); - }, [setLoadWorkspaceHandler]); - +const DynamicBlocksuite = ({ setCreateEditorHandler }: Props) => { useEffect(() => { const createEditorHandler: CreateEditorHandler = (page: Page) => { const editor = new EditorContainer(); diff --git a/packages/app/src/providers/app-state-provider/hooks.ts b/packages/app/src/providers/app-state-provider/hooks.ts deleted file mode 100644 index 6996bd03ef..0000000000 --- a/packages/app/src/providers/app-state-provider/hooks.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { useEffect } from 'react'; -import { useRouter } from 'next/router'; -import { useAppState } from './context'; -import { usePageHelper } from '@/hooks/use-page-helper'; -export const useLoadWorkspace = () => { - const router = useRouter(); - const { loadWorkspace, currentWorkspace, currentWorkspaceId } = useAppState(); - - const workspaceId = router.query.workspaceId as string; - - useEffect(() => { - loadWorkspace?.(workspaceId); - }, [workspaceId, loadWorkspace]); - - return currentWorkspaceId === workspaceId ? currentWorkspace : null; -}; - -export const useLoadPage = () => { - const router = useRouter(); - const { loadPage, currentPage, currentWorkspaceId } = useAppState(); - const { createPage } = usePageHelper(); - const workspace = useLoadWorkspace(); - - const pageId = router.query.pageId as string; - - useEffect(() => { - if (!workspace) { - return; - } - const page = pageId ? workspace?.getPage(pageId) : null; - if (page) { - loadPage?.(pageId); - return; - } - - const savedPageId = workspace.meta.pageMetas[0]?.id; - if (savedPageId) { - router.push(`/workspace/${currentWorkspaceId}/${savedPageId}`); - return; - } - - createPage().then(async pageId => { - if (!pageId) { - return; - } - router.push(`/workspace/${currentWorkspaceId}/${pageId}`); - }); - }, [workspace, pageId, loadPage, createPage, router, currentWorkspaceId]); - - return currentPage?.id === pageId ? currentPage : null; -}; diff --git a/packages/app/src/providers/app-state-provider/provider.tsx b/packages/app/src/providers/app-state-provider/provider.tsx index daa60ff85e..ce071d8487 100644 --- a/packages/app/src/providers/app-state-provider/provider.tsx +++ b/packages/app/src/providers/app-state-provider/provider.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState, useEffect, useCallback, useRef } from 'react'; +import { useMemo, useState, useCallback, useRef } from 'react'; import type { ReactNode } from 'react'; import dynamic from 'next/dynamic'; import { getDataCenter } from '@affine/datacenter'; @@ -8,12 +8,20 @@ import type { CreateEditorHandler, LoadWorkspaceHandler, } from './context'; -import { Page, Workspace as StoreWorkspace } from '@blocksuite/store'; +import { Page } from '@blocksuite/store'; import { EditorContainer } from '@blocksuite/editor'; const DynamicBlocksuite = dynamic(() => import('./dynamic-blocksuite'), { ssr: false, }); +const loadWorkspaceHandler: LoadWorkspaceHandler = async workspaceId => { + if (workspaceId) { + const dc = await getDataCenter(); + return dc.load(workspaceId, { providerId: 'affine' }); + } else { + return null; + } +}; export const AppStateProvider = ({ children }: { children?: ReactNode }) => { const refreshWorkspacesMeta = async () => { const dc = await getDataCenter(); @@ -30,43 +38,10 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { currentWorkspace: null, currentPage: null, editor: null, - // Synced is used to ensure that the provider has synced with the server, - // So after Synced set to true, the other state is sure to be set. - synced: false, refreshWorkspacesMeta, - workspaces: {}, + synced: true, }); - useEffect(() => { - (async () => { - const workspacesList = await Promise.all( - state.workspacesMeta.map(async ({ id }) => { - const workspace = - (await loadWorkspaceHandler?.(id, state.user)) || null; - return { id, workspace }; - }) - ); - const workspaces: Record = {}; - workspacesList.forEach(({ id, workspace }) => { - workspaces[id] = workspace; - }); - setState(state => ({ - ...state, - workspaces, - })); - })(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [state.workspacesMeta]); - - const [loadWorkspaceHandler, _setLoadWorkspaceHandler] = - useState(); - const setLoadWorkspaceHandler = useCallback( - (handler: LoadWorkspaceHandler) => { - _setLoadWorkspaceHandler(() => handler); - }, - [_setLoadWorkspaceHandler] - ); - const [createEditorHandler, _setCreateEditorHandler] = useState(); @@ -85,7 +60,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { return state.currentWorkspace; } const workspace = - (await loadWorkspaceHandler?.(workspaceId, state.user)) || null; + (await loadWorkspaceHandler(workspaceId, state.user)) || null; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error @@ -103,6 +78,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { })); return workspace; }; + const loadPage = useRef(() => Promise.resolve(null) ); @@ -147,17 +123,6 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { setState(state => ({ ...state, editor })); }; - useEffect(() => { - if (!loadWorkspaceHandler) { - return; - } - setState(state => ({ - ...state, - workspacesMeta: [], - synced: true, - })); - }, [loadWorkspaceHandler]); - const context = useMemo( () => ({ ...state, @@ -172,10 +137,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { return ( - + {children} ); From 955558b0d041de48db76d6b8a16eba84d3525ef9 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Thu, 5 Jan 2023 19:04:16 +0800 Subject: [PATCH 009/298] feat: mock delete --- .../src/components/workspace-modal/index.tsx | 6 +- .../general/delete/delete.tsx | 16 ++++-- .../workspace-setting/general/general.tsx | 56 +++++++++++++++---- .../workspace-setting/general/style.ts | 2 +- .../workspace-setting/workspace-setting.tsx | 1 - .../WorkspaceSelector/WorkspaceSelector.tsx | 6 +- packages/app/src/hooks/mock-data/mock.ts | 6 +- 7 files changed, 71 insertions(+), 22 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 479b22c99e..85fdd461ab 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -121,7 +121,11 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { confirmText: user ? 'Enable' : 'Sign in and Enable', cancelText: 'Skip', }).then(confirm => { - confirm && Login(); + if (user) { + console.log('enable cloud'); + } else { + confirm && Login(); + } }); }} > diff --git a/packages/app/src/components/workspace-setting/general/delete/delete.tsx b/packages/app/src/components/workspace-setting/general/delete/delete.tsx index 7fd14ef818..0f972443d7 100644 --- a/packages/app/src/components/workspace-setting/general/delete/delete.tsx +++ b/packages/app/src/components/workspace-setting/general/delete/delete.tsx @@ -14,6 +14,7 @@ import { Button } from '@/ui/button'; import { getDataCenter } from '@affine/datacenter'; import { useRouter } from 'next/router'; import { useAppState } from '@/providers/app-state-provider'; +import { deleteWorkspace, getWorkspaces } from '@/hooks/mock-data/mock'; interface WorkspaceDeleteProps { open: boolean; @@ -31,7 +32,6 @@ export const WorkspaceDelete = ({ nextWorkSpaceId, }: WorkspaceDeleteProps) => { const [deleteStr, setDeleteStr] = useState(''); - const { refreshWorkspacesMeta } = useAppState(); const router = useRouter(); const handlerInputChange = (workspaceName: string) => { @@ -39,10 +39,16 @@ export const WorkspaceDelete = ({ }; const handleDelete = async () => { - const dc = await getDataCenter(); - await dc.apis.deleteWorkspace({ id: workspaceId }); - router.push(`/workspace/${nextWorkSpaceId}`); - refreshWorkspacesMeta(); + // const dc = await getDataCenter(); + // await dc.apis.deleteWorkspace({ id: workspaceId }); + // router.push(`/workspace/${nextWorkSpaceId}`); + deleteWorkspace(workspaceId); + const workspaceList = getWorkspaces(); + if (workspaceList.length) { + router.push(`/workspace/${workspaceList[0].id}`); + } else { + router.push(`/workspace`); + } onClose(); }; diff --git a/packages/app/src/components/workspace-setting/general/general.tsx b/packages/app/src/components/workspace-setting/general/general.tsx index fa72178869..e36bd7db52 100644 --- a/packages/app/src/components/workspace-setting/general/general.tsx +++ b/packages/app/src/components/workspace-setting/general/general.tsx @@ -6,8 +6,8 @@ import { } from './style'; import { StyledSettingH2 } from '../style'; -import { useState } from 'react'; -import { Button } from '@/ui/button'; +import { useEffect, useState } from 'react'; +import { Button, TextButton } from '@/ui/button'; import Input from '@/ui/input'; import { getDataCenter } from '@affine/datacenter'; import { useAppState } from '@/providers/app-state-provider'; @@ -16,7 +16,12 @@ import { Workspace as StoreWorkspace } from '@blocksuite/store'; import { debounce } from '@/utils'; import { WorkspaceLeave } from './leave'; import { Upload } from '@/components/file-upload'; -import { getUserInfo, Workspace } from '@/hooks/mock-data/mock'; +import { + getUserInfo, + updateWorkspaceMeta, + User, + Workspace, +} from '@/hooks/mock-data/mock'; export const GeneralPage = ({ workspace, @@ -30,8 +35,13 @@ export const GeneralPage = ({ workspaces, refreshWorkspacesMeta, } = useAppState(); - // const user = getUserInfo(); + useEffect(() => { + setWorkspaceName(workspace.name); + const user = getUserInfo(); + setUserInfo(user); + }, []); const [showDelete, setShowDelete] = useState(false); + const [userInfo, setUserInfo] = useState(); const [showLeave, setShowLeave] = useState(false); const [uploading, setUploading] = useState(false); const [workspaceName, setWorkspaceName] = useState(''); @@ -63,6 +73,9 @@ export const GeneralPage = ({ const handleCloseLeave = () => { setShowLeave(false); }; + const handleUpdateWorkspaceName = () => { + updateWorkspaceMeta(workspace.id, { name: workspaceName }); + }; const fileChange = async (file: File) => { setUploading(true); @@ -106,7 +119,7 @@ export const GeneralPage = ({ ) : null} */} {/* */} - Workspace Name + Workspace Name + { + handleUpdateWorkspaceName(); + }} + style={{ marginLeft: '10px' }} + > + ✔️ + - Workspace Owner + {userInfo ? ( +
    + Workspace Owner + + + +
    + ) : ( + '' + )} + + Workspace Type - + {workspace.type} {isOwner ? ( diff --git a/packages/app/src/components/workspace-setting/general/style.ts b/packages/app/src/components/workspace-setting/general/style.ts index e4b505f228..739ec24aec 100644 --- a/packages/app/src/components/workspace-setting/general/style.ts +++ b/packages/app/src/components/workspace-setting/general/style.ts @@ -9,7 +9,7 @@ export const StyledSettingInputContainer = styled('div')(() => { export const StyledDeleteButtonContainer = styled('div')(() => { return { - marginTop: '154px', + marginTop: '30px', }; }); diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index f1a9256dbf..66850cabc7 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -116,7 +116,6 @@ export const WorkspaceSetting = ({ }; const workspace = getActiveWorkspace(); - console.log('workspace: ', workspace); const handleClickClose = () => { onClose && onClose(); }; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index 22013ba674..aa6d532fa3 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -2,7 +2,7 @@ import { Avatar, WorkspaceName, SelectorWrapper } from './styles'; import { useEffect, useState } from 'react'; import { AffineIcon } from '../icons/icons'; import { WorkspaceModal } from '@/components/workspace-modal'; -import { getActiveWorkspace } from '@/hooks/mock-data/mock'; +import { getActiveWorkspace, getWorkspaces } from '@/hooks/mock-data/mock'; export const WorkspaceSelector = () => { const [workspaceListShow, setWorkspaceListShow] = useState(false); @@ -10,6 +10,10 @@ export const WorkspaceSelector = () => { useEffect(() => { getWorkspace(); }, [workspaceListShow]); + const workspaceList = getWorkspaces(); + if (workspaceList.length === 0) { + setWorkspaceListShow(true); + } const getWorkspace = () => { const workspace = getActiveWorkspace(); setWorkSpace(workspace); diff --git a/packages/app/src/hooks/mock-data/mock.ts b/packages/app/src/hooks/mock-data/mock.ts index 6f5f5f289c..c7180fce58 100644 --- a/packages/app/src/hooks/mock-data/mock.ts +++ b/packages/app/src/hooks/mock-data/mock.ts @@ -17,7 +17,7 @@ export interface User { export function updateWorkspaceMeta( workspaceId: string, - workspaceData: Workspace + workspaceData: { name?: string; avatar?: string } ) { const workspacesMeta = getWorkspaces(); const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { @@ -29,6 +29,10 @@ export function updateWorkspaceMeta( return workspace; }); localStorage.setItem('affine-workspace', JSON.stringify(newWorkspacesMeta)); + const activeWorkspace = getActiveWorkspace(); + workspaceData.name && (activeWorkspace.name = workspaceData.name); + workspaceData.avatar && (activeWorkspace.avatar = workspaceData.avatar); + setActiveWorkspace(activeWorkspace); } export function createWorkspace(workspaceName: string) { const workspaceData = { From 2773b3e489a53db121786b8b577ed5a9e4eddd62 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Thu, 5 Jan 2023 19:07:14 +0800 Subject: [PATCH 010/298] fix:delete bugs --- .../WorkspaceSelector/WorkspaceSelector.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index aa6d532fa3..669b927a9e 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -8,13 +8,16 @@ export const WorkspaceSelector = () => { const [workspaceListShow, setWorkspaceListShow] = useState(false); const [workspace, setWorkSpace] = useState(getActiveWorkspace()); useEffect(() => { - getWorkspace(); + setWorkspace(); }, [workspaceListShow]); - const workspaceList = getWorkspaces(); - if (workspaceList.length === 0) { - setWorkspaceListShow(true); - } - const getWorkspace = () => { + useEffect(() => { + const workspaceList = getWorkspaces(); + if (workspaceList.length === 0) { + setWorkspaceListShow(true); + } + }); + + const setWorkspace = () => { const workspace = getActiveWorkspace(); setWorkSpace(workspace); }; @@ -42,7 +45,7 @@ export const WorkspaceSelector = () => { open={workspaceListShow} onClose={() => { setWorkspaceListShow(false); - getWorkspace(); + setWorkspace(); }} > From 9424cfb86521db6f25b399fd03489b856b3ccb2d Mon Sep 17 00:00:00 2001 From: QiShaoXuan Date: Thu, 5 Jan 2023 19:14:41 +0800 Subject: [PATCH 011/298] feat: add useTemporaryHelper --- .../app/src/hooks/use-temporary-helper.ts | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 packages/app/src/hooks/use-temporary-helper.ts diff --git a/packages/app/src/hooks/use-temporary-helper.ts b/packages/app/src/hooks/use-temporary-helper.ts new file mode 100644 index 0000000000..8de0ef88a0 --- /dev/null +++ b/packages/app/src/hooks/use-temporary-helper.ts @@ -0,0 +1,115 @@ +import { useEffect, useState } from 'react'; +import { getWorkspaces, Workspace, User } from './mock-data/mock'; + +export function getActiveWorkspace(): Workspace { + return JSON.parse(localStorage.getItem('affine-active-workspace') ?? '{}'); +} + +export const useTemporaryHelper = () => { + const [workspaceMetaList, setWorkspaceMetaList] = useState( + getWorkspaces() + ); + const [currentWorkspace, setCurrentWorkspace] = useState( + JSON.parse(localStorage.getItem('affine-active-workspace') ?? '{}') + ); + const [user, setUser] = useState(null); + + return { + updateWorkspaceMeta: (workspaceId: string, workspaceData: Workspace) => { + const workspacesMeta = getWorkspaces(); + const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { + if (workspace.id === workspaceId) { + workspaceData.name && (workspace.name = workspaceData.name); + workspaceData.avatar && (workspace.avatar = workspaceData.avatar); + return workspaceData; + } + return workspace; + }); + localStorage.setItem( + 'affine-workspace', + JSON.stringify(newWorkspacesMeta) + ); + setWorkspaceMetaList(newWorkspacesMeta); + if (workspaceId === currentWorkspace?.id) { + setCurrentWorkspace( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + newWorkspacesMeta.find(v => v.id === currentWorkspace.id) + ); + } + }, + createWorkspace: (workspaceName: string) => { + const workspaceData = { + name: workspaceName, + id: 'workspace-' + Date.now(), + isPublish: false, + isLocal: true, + avatar: '', + type: 'local', + } as Workspace; + const workspacesMeta = getWorkspaces(); + workspacesMeta.push(workspaceData); + localStorage.setItem('affine-workspace', JSON.stringify(workspacesMeta)); + setWorkspaceMetaList(workspacesMeta); + }, + deleteWorkspace: (workspaceId: string) => { + const workspacesMeta = getWorkspaces(); + const newWorkspacesMeta = workspacesMeta.filter(() => { + return workspaceId !== workspaceId; + }); + localStorage.setItem( + 'affine-workspace', + JSON.stringify(newWorkspacesMeta) + ); + setWorkspaceMetaList(workspacesMeta); + }, + + setWorkspacePublish: (id: string, isPublish: boolean) => { + const workspacesMeta = getWorkspaces(); + const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { + if (workspace.id === id) { + workspace.isPublish = isPublish; + } + return workspace; + }); + localStorage.setItem( + 'affine-workspace', + JSON.stringify(newWorkspacesMeta) + ); + setWorkspaceMetaList(workspacesMeta); + }, + setActiveWorkspace(workspaceData: Workspace) { + localStorage.setItem( + 'affine-active-workspace', + JSON.stringify(workspaceData) + ); + setCurrentWorkspace(workspaceData); + }, + + login: () => { + const userInfo = { + name: 'Diamond', + id: 'ttt', + email: 'diamond.shx@gmail.com', + avatar: 'string', + }; + localStorage.setItem('affine-user', JSON.stringify(userInfo)); + + setUser(userInfo); + }, + getUserInfo: () => { + return user; + }, + + SignOut(): void { + localStorage.removeItem('affine-user'); + setUser(null); + }, + + workspaceMetaList, + currentWorkspace, + user, + }; +}; + +export default useTemporaryHelper; From b6542b02453a80f5a2bcb1ba6ec6eef5c91888b8 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Thu, 5 Jan 2023 19:21:35 +0800 Subject: [PATCH 012/298] feat: member init --- .../general/delete/delete.tsx | 2 - .../workspace-setting/general/general.tsx | 37 ++------------- .../workspace-setting/general/leave/leave.tsx | 4 +- .../workspace-setting/workspace-setting.tsx | 46 +++++++++++-------- .../WorkspaceSelector/WorkspaceSelector.tsx | 1 - 5 files changed, 32 insertions(+), 58 deletions(-) diff --git a/packages/app/src/components/workspace-setting/general/delete/delete.tsx b/packages/app/src/components/workspace-setting/general/delete/delete.tsx index 0f972443d7..f5b9e1e86c 100644 --- a/packages/app/src/components/workspace-setting/general/delete/delete.tsx +++ b/packages/app/src/components/workspace-setting/general/delete/delete.tsx @@ -21,7 +21,6 @@ interface WorkspaceDeleteProps { onClose: () => void; workspaceName: string; workspaceId: string; - nextWorkSpaceId: string; } export const WorkspaceDelete = ({ @@ -29,7 +28,6 @@ export const WorkspaceDelete = ({ onClose, workspaceId, workspaceName, - nextWorkSpaceId, }: WorkspaceDeleteProps) => { const [deleteStr, setDeleteStr] = useState(''); const router = useRouter(); diff --git a/packages/app/src/components/workspace-setting/general/general.tsx b/packages/app/src/components/workspace-setting/general/general.tsx index e36bd7db52..9142b3854f 100644 --- a/packages/app/src/components/workspace-setting/general/general.tsx +++ b/packages/app/src/components/workspace-setting/general/general.tsx @@ -12,7 +12,6 @@ import Input from '@/ui/input'; import { getDataCenter } from '@affine/datacenter'; import { useAppState } from '@/providers/app-state-provider'; import { WorkspaceDelete } from './delete'; -import { Workspace as StoreWorkspace } from '@blocksuite/store'; import { debounce } from '@/utils'; import { WorkspaceLeave } from './leave'; import { Upload } from '@/components/file-upload'; @@ -23,18 +22,8 @@ import { Workspace, } from '@/hooks/mock-data/mock'; -export const GeneralPage = ({ - workspace, -}: { - workspace: Workspace; - workspaces: Record; -}) => { - const { - currentWorkspace, - workspacesMeta, - workspaces, - refreshWorkspacesMeta, - } = useAppState(); +export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { + const { currentWorkspace, refreshWorkspacesMeta } = useAppState(); useEffect(() => { setWorkspaceName(workspace.name); const user = getUserInfo(); @@ -53,13 +42,6 @@ export const GeneralPage = ({ const handleChangeWorkSpaceName = (newName: string) => { setWorkspaceName(newName); }; - const currentWorkspaceIndex = workspacesMeta.findIndex( - meta => meta.id === workspace.id - ); - const nextWorkSpaceId = - currentWorkspaceIndex === workspacesMeta.length - 1 - ? workspacesMeta[currentWorkspaceIndex - 1]?.id - : workspacesMeta[currentWorkspaceIndex + 1]?.id; const handleClickDelete = () => { setShowDelete(true); }; @@ -87,7 +69,7 @@ export const GeneralPage = ({ }); if (blobId) { currentWorkspace?.meta.setAvatar(blobId); - workspaces[workspace.id]?.meta.setAvatar(blobId); + // workspaces[workspace.id]?.meta.setAvatar(blobId); setUploading(false); debouncedRefreshWorkspacesMeta(); } @@ -97,15 +79,8 @@ export const GeneralPage = ({
    Workspace Avatar - - {workspaces[workspace.id]?.meta.name[0]} + + AFFiNE ) : ( @@ -182,7 +156,6 @@ export const GeneralPage = ({ onClose={handleCloseLeave} workspaceName={workspaceName} workspaceId={workspace.id} - nextWorkSpaceId={nextWorkSpaceId} /> )} diff --git a/packages/app/src/components/workspace-setting/general/leave/leave.tsx b/packages/app/src/components/workspace-setting/general/leave/leave.tsx index 3c2cf8ce22..79cadd6edb 100644 --- a/packages/app/src/components/workspace-setting/general/leave/leave.tsx +++ b/packages/app/src/components/workspace-setting/general/leave/leave.tsx @@ -16,13 +16,11 @@ interface WorkspaceDeleteProps { onClose: () => void; workspaceName: string; workspaceId: string; - nextWorkSpaceId: string; } export const WorkspaceLeave = ({ open, onClose, - nextWorkSpaceId, workspaceId, }: WorkspaceDeleteProps) => { const router = useRouter(); @@ -30,7 +28,7 @@ export const WorkspaceLeave = ({ const handleLeave = async () => { const dc = await getDataCenter(); await dc.apis.leaveWorkspace({ id: workspaceId }); - router.push(`/workspace/${nextWorkSpaceId}`); + // router.push(`/workspace/${nextWorkSpaceId}`); refreshWorkspacesMeta(); onClose(); }; diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index 66850cabc7..7d7855aaca 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -45,7 +45,9 @@ import { useAppState } from '@/providers/app-state-provider'; import { GeneralPage } from './general'; import { getActiveWorkspace, + getUserInfo, setWorkspacePublish, + User, Workspace, } from '@/hooks/mock-data/mock'; @@ -109,7 +111,7 @@ export const WorkspaceSetting = ({ isShow, onClose, }: WorkspaceSettingProps) => { - const { workspaces } = useAppState(); + // const { workspaces } = useAppState(); const [activeTab, setActiveTab] = useState(ActiveTab.general); const handleTabChange = (tab: ActiveTab) => { setActiveTab(tab); @@ -143,7 +145,7 @@ export const WorkspaceSetting = ({ ) : null} {activeTab === ActiveTab.general && ( - + )} {activeTab === ActiveTab.members && workspace && ( @@ -160,23 +162,27 @@ export const WorkspaceSetting = ({ const MembersPage = ({ workspace }: { workspace: Workspace }) => { const [isInviteModalShow, setIsInviteModalShow] = useState(false); const [members, setMembers] = useState([]); - const refreshMembers = useCallback(() => { - getDataCenter() - .then(dc => - dc.apis.getWorkspaceMembers({ - id: workspace.id, - }) - ) - .then(data => { - setMembers(data); - }) - .catch(err => { - console.log(err); - }); - }, [workspace.id]); + const [userInfo, setUserInfo] = useState(); + // const refreshMembers = useCallback(() => { + // getDataCenter() + // .then(dc => + // dc.apis.getWorkspaceMembers({ + // id: workspace.id, + // }) + // ) + // .then(data => { + // setMembers(data); + // }) + // .catch(err => { + // console.log(err); + // }); + // }, [workspace.id]); + useEffect(() => { - refreshMembers(); - }, [refreshMembers]); + const user = getUserInfo(); + user && setUserInfo(user); + // refreshMembers(); + }, []); return (
    @@ -240,7 +246,7 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { .then(() => { // console.log('data: ', data); toast('Moved to Trash'); - refreshMembers(); + // refreshMembers(); }); // }); }} @@ -280,7 +286,7 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { setIsInviteModalShow(false); }} onInviteSuccess={() => { - refreshMembers(); + // refreshMembers(); }} workspaceId={workspace.id} open={isInviteModalShow} diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index 669b927a9e..5ccc9a446b 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -16,7 +16,6 @@ export const WorkspaceSelector = () => { setWorkspaceListShow(true); } }); - const setWorkspace = () => { const workspace = getActiveWorkspace(); setWorkSpace(workspace); From e3c1e6a5da56bd4a543d37b30f1f2e0c838e0291 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Thu, 5 Jan 2023 19:30:16 +0800 Subject: [PATCH 013/298] fix:member init --- .../workspace-setting/workspace-setting.tsx | 247 ++++++++++-------- 1 file changed, 140 insertions(+), 107 deletions(-) diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index 7d7855aaca..a905134f76 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -46,6 +46,7 @@ import { GeneralPage } from './general'; import { getActiveWorkspace, getUserInfo, + Login, setWorkspacePublish, User, Workspace, @@ -179,119 +180,151 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { // }, [workspace.id]); useEffect(() => { - const user = getUserInfo(); - user && setUserInfo(user); + setUser(); // refreshMembers(); }, []); + const setUser = () => { + const user = getUserInfo(); + user && setUserInfo(user); + }; + return (
    - - - Users({members.length}) - - Access level - - - {members.length === 0 && ( - - )} - {members.length ? ( - members.map(member => { - return ( - - - {member.user.type === 'Registered' ? ( - - ) : ( - - - - )} + {userInfo ? ( + <> + + + Users({members.length}) + + Access level + + + {members.length === 0 && ( + + )} + {members.length ? ( + members.map(member => { + return ( + + + {member.user.type === 'Registered' ? ( + + ) : ( + + + + )} - - {member.user.type === 'Registered' ? ( - {member.user.name} - ) : ( - <> - )} - {member.user.email} - - - - {member.accepted - ? member.type !== 99 - ? 'Member' - : 'Workspace Owner' - : 'Pending'} - - - - { - // confirm({ - // title: 'Delete Member?', - // content: `will delete member`, - // confirmText: 'Delete', - // confirmType: 'danger', - // }).then(confirm => { - getDataCenter() - .then(dc => - dc.apis.removeMember({ - permissionId: member.id, - }) - ) - .then(() => { - // console.log('data: ', data); - toast('Moved to Trash'); - // refreshMembers(); - }); - // }); - }} - icon={} - > - Delete - - - } - placement="bottom-end" - disablePortal={true} - > - - - - - - - ); - }) - ) : ( - <> - )} - - - - { - setIsInviteModalShow(false); - }} - onInviteSuccess={() => { - // refreshMembers(); - }} - workspaceId={workspace.id} - open={isInviteModalShow} - > - + + {member.user.type === 'Registered' ? ( + + {member.user.name} + + ) : ( + <> + )} + + {member.user.email} + + + + + {member.accepted + ? member.type !== 99 + ? 'Member' + : 'Workspace Owner' + : 'Pending'} + + + + { + // confirm({ + // title: 'Delete Member?', + // content: `will delete member`, + // confirmText: 'Delete', + // confirmType: 'danger', + // }).then(confirm => { + getDataCenter() + .then(dc => + dc.apis.removeMember({ + permissionId: member.id, + }) + ) + .then(() => { + // console.log('data: ', data); + toast('Moved to Trash'); + // refreshMembers(); + }); + // }); + }} + icon={} + > + Delete + + + } + placement="bottom-end" + disablePortal={true} + > + + + + + + + ); + }) + ) : ( + <> + )} + + + + { + setIsInviteModalShow(false); + }} + onInviteSuccess={() => { + // refreshMembers(); + }} + workspaceId={workspace.id} + open={isInviteModalShow} + > + + + ) : ( + <> +
    + Collaborating with other members requires AFFiNE Cloud service. +
    +
    + +
    + + )}
    ); }; From 46792e5757ac1d03a7bdc936945c66fe8d746017 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 5 Jan 2023 22:20:40 +0800 Subject: [PATCH 014/298] feat: data center business apis --- packages/data-center/src/apis/business.ts | 115 ++++++++++++++++++ packages/data-center/src/apis/index.ts | 10 +- packages/data-center/src/apis/workspace.ts | 2 +- packages/data-center/src/datacenter.ts | 8 +- packages/data-center/src/style/index.ts | 24 ++++ packages/data-center/src/workspaces/index.ts | 1 + .../data-center/src/workspaces/workspaces.ts | 113 +++++++++++++++++ 7 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 packages/data-center/src/apis/business.ts create mode 100644 packages/data-center/src/style/index.ts create mode 100644 packages/data-center/src/workspaces/index.ts create mode 100644 packages/data-center/src/workspaces/workspaces.ts diff --git a/packages/data-center/src/apis/business.ts b/packages/data-center/src/apis/business.ts new file mode 100644 index 0000000000..ab5b258d29 --- /dev/null +++ b/packages/data-center/src/apis/business.ts @@ -0,0 +1,115 @@ +import { uuidv4 } from '@blocksuite/store'; +import { getDataCenter } from 'src'; +import { DataCenter } from 'src/datacenter'; +import { Workspace, WorkspaceMeta, WorkspaceType } from '../style'; +import { token } from './token'; + +export class Business { + private _dc: DataCenter | undefined; + + private async _getDc() { + if (!this._dc) { + this._dc = await getDataCenter(); + } + return this._dc; + } + + async createWorkspace( + name: string + ): Promise> { + let id = ''; + let type = WorkspaceType.local; + if (token.isLogin) { + // TODO: add default avatar + const data = await this._dc?.apis.createWorkspace({ name, avatar: '' }); + id = data?.id || ''; + type = WorkspaceType.cloud; + this._dc?.load(id, { providerId: 'affine' }); + } else { + this._dc?.load(uuidv4(), { providerId: 'local' }); + } + const newWorkspaces = (await this.getWorkspaces()).find(w => w.id === id); + return { + id: newWorkspaces?.id || '', + name, + avatar: '', + type, + }; + } + + // updateWorkspaceMeta( + // id: string, + // meta: { name?: string; avatar: Partial } + // ) {} + + async getWorkspaces(focusUpdated?: boolean): Promise { + const dc = await this._getDc(); + if (focusUpdated) { + await dc.workspacesList.refreshWorkspaceList(); + } + return dc.workspacesList.getWorkspaces(); + } + + async onWorkspaceChange(cb: (workspaces: Workspace[]) => void) { + const dc = await this._getDc(); + dc.workspacesList.on('change', cb); + } + + async deleteWorkspace(id: string) { + const dc = await this._getDc(); + const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); + if (workspace?.type === WorkspaceType.cloud) { + dc.apis.deleteWorkspace({ id }); + } + dc.delete(id); + } + + async leaveWorkspace(id: string) { + const dc = await this._getDc(); + const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); + if (workspace?.type === WorkspaceType.cloud) { + dc.apis.leaveWorkspace({ id }); + dc.delete(id); + } + } + + setWorkspacePublish(id: string, isPublish: boolean): boolean { + return isPublish; + } + + async getWorkspaceById(id: string) { + const dc = await this._getDc(); + const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); + if (workspace?.type === WorkspaceType.cloud) { + return dc.load(id, { providerId: 'affine' }); + } else { + return dc.load(id, { providerId: 'local' }); + } + } + + // getMembers(id: string): any {} + + // inviteMember(id: string, email: string) {} + + async acceptInvitation(invitingCode: string) { + const dc = await this._getDc(); + dc.apis.acceptInviting({ invitingCode }); + } + + // getUserInfo(): any {} + + async login() { + const dc = await this._getDc(); + await dc.auth('affine'); + } + + // logout() {} + + // setWorkspaceSyncType(id: string, type: 'local' | 'cloud') {} + + // importWorkspace(file: File) {} + + // exportWorkspace(id: string) {} + + // enableWorkspaceCloud(id: string) {} +} diff --git a/packages/data-center/src/apis/index.ts b/packages/data-center/src/apis/index.ts index de62a9fcb1..57c003d8fd 100644 --- a/packages/data-center/src/apis/index.ts +++ b/packages/data-center/src/apis/index.ts @@ -4,16 +4,24 @@ export type { Callback } from './token.js'; import { getAuthorizer } from './token.js'; import * as user from './user.js'; import * as workspace from './workspace.js'; +import * as business from './business.js'; export type Apis = typeof user & typeof workspace & { + business: typeof business; signInWithGoogle: ReturnType[0]; onAuthStateChanged: ReturnType[1]; }; export const getApis = (): Apis => { const [signInWithGoogle, onAuthStateChanged] = getAuthorizer(); - return { ...user, ...workspace, signInWithGoogle, onAuthStateChanged }; + return { + ...user, + ...workspace, + business, + signInWithGoogle, + onAuthStateChanged, + }; }; export type { AccessTokenMessage } from './token'; diff --git a/packages/data-center/src/apis/workspace.ts b/packages/data-center/src/apis/workspace.ts index 396aa46f8e..0c145928d5 100644 --- a/packages/data-center/src/apis/workspace.ts +++ b/packages/data-center/src/apis/workspace.ts @@ -84,7 +84,7 @@ export interface CreateWorkspaceParams { export async function createWorkspace( params: CreateWorkspaceParams -): Promise { +): Promise<{ id: string }> { return client.post('api/workspace', { json: params }).json(); } diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 3e31e9f1d8..dd01e7785f 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -7,6 +7,7 @@ import { getApis, Apis } from './apis/index.js'; import { AffineProvider, BaseProvider } from './provider/index.js'; import { LocalProvider } from './provider/index.js'; import { getKVConfigure } from './store.js'; +import { Workspaces } from './workspaces'; // load workspace's config type LoadConfig = { @@ -33,6 +34,7 @@ export class DataCenter { private readonly _workspaces = new Map>(); private readonly _config; private readonly _logger; + public readonly workspacesList = new Workspaces(this); readonly signals = { listAdd: new Signal(), @@ -62,6 +64,7 @@ export class DataCenter { this.signals.listRemove.on(workspace => { this._config.delete(`list:${workspace}`); }); + this.workspacesList.init(); } get apis(): Readonly { @@ -195,10 +198,11 @@ export class DataCenter { * data state is also map, the key is the provider id, and the data exists locally when the value is true, otherwise it does not exist */ async list(): Promise>> { + const listString = 'list:'; const entries: [string, WorkspaceItem][] = await this._config.entries(); return entries.reduce((acc, [k, i]) => { - if (k.startsWith('list:')) { - const key = k.slice(5); + if (k.startsWith(listString)) { + const key = k.slice(listString.length); acc[key] = acc[key] || {}; acc[key][i.provider] = i.locally; } diff --git a/packages/data-center/src/style/index.ts b/packages/data-center/src/style/index.ts new file mode 100644 index 0000000000..522946a099 --- /dev/null +++ b/packages/data-center/src/style/index.ts @@ -0,0 +1,24 @@ +export enum WorkspaceType { + local = 'local', + cloud = 'cloud', +} + +export type Workspace = { + name: string; + id: string; + isPublish?: boolean; + avatar?: string; + type: WorkspaceType; + owner?: User; + isLocal?: boolean; + memberCount: number; +}; + +export type User = { + name: string; + id: string; + email: string; + avatar: string; +}; + +export type WorkspaceMeta = Pick; diff --git a/packages/data-center/src/workspaces/index.ts b/packages/data-center/src/workspaces/index.ts new file mode 100644 index 0000000000..05a26f8e2b --- /dev/null +++ b/packages/data-center/src/workspaces/index.ts @@ -0,0 +1 @@ +export { Workspaces } from './workspaces'; diff --git a/packages/data-center/src/workspaces/workspaces.ts b/packages/data-center/src/workspaces/workspaces.ts new file mode 100644 index 0000000000..2c2211614d --- /dev/null +++ b/packages/data-center/src/workspaces/workspaces.ts @@ -0,0 +1,113 @@ +import { Workspace } from '@blocksuite/store'; +import { Observable } from 'lib0/observable'; +import { WorkspaceDetail } from 'src/apis/workspace'; +import { DataCenter } from 'src/datacenter'; +import { User, Workspace as Wp, WorkspaceType } from 'src/style'; + +function getProvider(providerList: Record) { + return Object.keys(providerList)[0]; +} + +function isCloudWorkspace(provider: string) { + return provider === 'affine'; +} + +export class Workspaces extends Observable { + private _workspaces: Wp[]; + private readonly workspaceInstances: Map = new Map(); + // cache cloud workspace owner + _dc: DataCenter; + + constructor(dataCenter: DataCenter) { + super(); + this._workspaces = []; + this.workspaceInstances = new Map(); + this._dc = dataCenter; + } + + init() { + // IMP: init local providers + this._dc.auth('local'); + // add listener on list change + this._dc.signals.listAdd.on(e => { + this.refreshWorkspaceList(); + }); + this._dc.signals.listRemove.on(e => { + this.refreshWorkspaceList(); + }); + } + + async refreshWorkspaceList() { + const workspaceList = await this._dc.list(); + + const workspaceMap = Object.keys(workspaceList).map(([id]) => { + return this._dc.load(id).then(w => { + return { id, workspace: w, provider: getProvider(workspaceList[id]) }; + }); + }); + + const workspaces = (await Promise.all(workspaceMap)).map(w => { + const { id, workspace, provider } = w; + if (workspace && !this.workspaceInstances.has(id)) { + this.workspaceInstances.set(id, workspace); + } + return { + id, + name: (workspace?.doc?.meta.name as string) || '', + avatar: (workspace?.meta.avatar as string) || '', + type: isCloudWorkspace(provider) + ? WorkspaceType.cloud + : WorkspaceType.local, + isLocal: false, + isPublish: false, + owner: undefined, + memberCount: 1, + } as Wp; + }); + const getDetailList = (await Promise.all(workspaceMap)).map(w => { + const { id, provider } = w; + if (provider === 'workspaces') { + return new Promise<{ id: string; detail: WorkspaceDetail | null }>( + resolve => { + this._dc.apis.getWorkspaceDetail({ id }).then(data => { + resolve({ id, detail: data || null }); + }); + } + ); + } + }); + const ownerList = await Promise.all(getDetailList); + (await Promise.all(ownerList)).forEach(detail => { + if (detail) { + const { id, detail: workspaceDetail } = detail; + if (workspaceDetail) { + const { owner, member_count } = workspaceDetail; + const currentWorkspace = workspaces.find(w => w.id === id); + if (currentWorkspace) { + currentWorkspace.owner = { + id: owner.id, + name: owner.name, + avatar: owner.avatar_url, + email: owner.email, + }; + currentWorkspace.memberCount = member_count; + } + } + } + }); + this._updateWorkspaces(workspaces); + } + + getWorkspaces() { + return this._workspaces; + } + + _updateWorkspaces(workspaces: Wp[]) { + this._workspaces = workspaces; + this.emit('change', this._workspaces); + } + + onWorkspaceChange(cb: (workspace: Wp) => void) { + this.on('change', cb); + } +} From c0c167fea870a20c9f3ac1d7eff841b4f8c95b15 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Thu, 5 Jan 2023 22:32:58 +0800 Subject: [PATCH 015/298] feat: mock invite --- .../src/components/invite-members/index.tsx | 68 +++++++++++-------- .../workspace-setting/workspace-setting.tsx | 63 ++++++++--------- .../SelectorPopperContent.tsx | 11 +-- packages/app/src/hooks/mock-data/mock.ts | 14 ++++ 4 files changed, 87 insertions(+), 69 deletions(-) diff --git a/packages/app/src/components/invite-members/index.tsx b/packages/app/src/components/invite-members/index.tsx index f06674cb6b..44f4f6aaeb 100644 --- a/packages/app/src/components/invite-members/index.tsx +++ b/packages/app/src/components/invite-members/index.tsx @@ -6,6 +6,7 @@ import Input from '@/ui/input'; import { useState } from 'react'; import { getDataCenter } from '@affine/datacenter'; import { Avatar } from '@mui/material'; +import { setMember } from '@/hooks/mock-data/mock'; interface LoginModalProps { open: boolean; onClose: () => void; @@ -54,29 +55,34 @@ export const InviteMembers = ({ // eslint-disable-next-line @typescript-eslint/no-explicit-any const [userData, setUserData] = useState({}); const inputChange = (value: string) => { - setEmail(value); setShowMember(true); if (gmailReg.test(value)) { + setEmail(value); setShowTip(false); - debounce( - () => { - getDataCenter() - .then(dc => - dc.apis.getUserByEmail({ - email: value, - workspace_id: workspaceId, - }) - ) - .then(data => { - if (data?.name) { - setUserData(data); - setShowTip(false); - } - }); - }, - 300, - true - )(); + setUserData({ + name: 'wxl', + avatar: 'https://avatars.githubusercontent.com/u/20501502?v=4', + email: value, + }); + // debounce( + // () => { + // getDataCenter() + // .then(dc => + // dc.apis.getUserByEmail({ + // email: value, + // workspace_id: workspaceId, + // }) + // ) + // .then(data => { + // if (data?.name) { + // setUserData(data); + // setShowTip(false); + // } + // }); + // }, + // 300, + // true + // )(); } else { setShowTip(true); } @@ -134,16 +140,18 @@ export const InviteMembers = ({ shape="circle" type="primary" onClick={() => { - getDataCenter() - .then(dc => dc.apis.inviteMember({ id: workspaceId, email })) - .then(() => { - onClose(); - onInviteSuccess && onInviteSuccess(); - }) - .catch(err => { - // toast('Invite failed'); - console.log(err); - }); + setMember(workspaceId, userData); + onInviteSuccess(); + // getDataCenter() + // .then(dc => dc.apis.inviteMember({ id: workspaceId, email })) + // .then(() => { + // onClose(); + // onInviteSuccess && onInviteSuccess(); + // }) + // .catch(err => { + // // toast('Invite failed'); + // console.log(err); + // }); }} > Invite diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index a905134f76..f22a736739 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -44,7 +44,9 @@ import { Empty } from '@/ui/empty'; import { useAppState } from '@/providers/app-state-provider'; import { GeneralPage } from './general'; import { + deleteMember, getActiveWorkspace, + getMembers, getUserInfo, Login, setWorkspacePublish, @@ -162,7 +164,7 @@ export const WorkspaceSetting = ({ const MembersPage = ({ workspace }: { workspace: Workspace }) => { const [isInviteModalShow, setIsInviteModalShow] = useState(false); - const [members, setMembers] = useState([]); + const [members, setMembers] = useState([]); const [userInfo, setUserInfo] = useState(); // const refreshMembers = useCallback(() => { // getDataCenter() @@ -181,6 +183,7 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { useEffect(() => { setUser(); + setMembersList(); // refreshMembers(); }, []); @@ -188,6 +191,10 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { const user = getUserInfo(); user && setUserInfo(user); }; + const setMembersList = () => { + const members = getMembers(workspace.id); + members && setMembers(members); + }; return (
    @@ -212,33 +219,23 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { return ( - {member.user.type === 'Registered' ? ( - - ) : ( - - - - )} + + + - {member.user.type === 'Registered' ? ( - - {member.user.name} - - ) : ( - <> - )} - - {member.user.email} - + {member.name} + + {member.email} - {member.accepted + {/* {member.accepted ? member.type !== 99 ? 'Member' : 'Workspace Owner' - : 'Pending'} + : 'Pending'} */} + Pending { <> { + deleteMember(workspace.id, 0); + setMembersList(); // confirm({ // title: 'Delete Member?', // content: `will delete member`, // confirmText: 'Delete', // confirmType: 'danger', // }).then(confirm => { - getDataCenter() - .then(dc => - dc.apis.removeMember({ - permissionId: member.id, - }) - ) - .then(() => { - // console.log('data: ', data); - toast('Moved to Trash'); - // refreshMembers(); - }); + // getDataCenter() + // .then(dc => + // dc.apis.removeMember({ + // permissionId: member.id, + // }) + // ) + // .then(() => { + // // console.log('data: ', data); + // toast('Moved to Trash'); + // // refreshMembers(); + // }); // }); }} icon={} @@ -301,6 +300,8 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { setIsInviteModalShow(false); }} onInviteSuccess={() => { + setMembersList(); + setIsInviteModalShow(false); // refreshMembers(); }} workspaceId={workspace.id} diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx index 494fdd495d..db6d4d34f1 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx @@ -27,8 +27,7 @@ type SelectorPopperContentProps = { export const SelectorPopperContent = ({ isShow, }: SelectorPopperContentProps) => { - const { user, workspacesMeta, workspaces, refreshWorkspacesMeta } = - useAppState(); + const { user, workspacesMeta, refreshWorkspacesMeta } = useAppState(); const [settingWorkspaceId, setSettingWorkspaceId] = useState( null ); @@ -115,13 +114,9 @@ export const SelectorPopperContent = ({ type={workspace.type} key={workspace.id} id={workspace.id} - icon={ - (workspaces[workspace.id]?.meta.avatar && - `/api/blob/${workspaces[workspace.id]?.meta.avatar}`) || - `loading...` - } + icon={`loading...`} onClickSetting={handleClickSettingWorkspace} - name={workspaces[workspace.id]?.meta.name || `loading...`} + name={`loading...`} memberCount={workSpaceDetails[workspace.id]?.memberCount || 1} /> ) : null; diff --git a/packages/app/src/hooks/mock-data/mock.ts b/packages/app/src/hooks/mock-data/mock.ts index c7180fce58..24e1427a05 100644 --- a/packages/app/src/hooks/mock-data/mock.ts +++ b/packages/app/src/hooks/mock-data/mock.ts @@ -69,6 +69,20 @@ export function getMembers(id: string): User[] { return memberMap[id] || []; } +export function setMember(workspaceId: string, member: User) { + const memberMap = JSON.parse(localStorage.getItem('affine-member') ?? '{}'); + memberMap[workspaceId] = memberMap[workspaceId] || []; + memberMap[workspaceId].push(member); + localStorage.setItem('affine-member', JSON.stringify(memberMap)); +} + +export function deleteMember(workspaceId: string, index: number) { + const memberMap = JSON.parse(localStorage.getItem('affine-member') ?? '{}'); + const memberList = memberMap[workspaceId]; + memberList.splice(index, 1); + memberMap[workspaceId] = memberList; + localStorage.setItem('affine-member', JSON.stringify(memberMap)); +} export function leaveWorkspace(id: string) { return true; } From 27aaf2de1a6fc391aacfe4777744a87f8396a737 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 5 Jan 2023 22:55:41 +0800 Subject: [PATCH 016/298] feat: add api state --- packages/data-center/src/apis/business.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/data-center/src/apis/business.ts b/packages/data-center/src/apis/business.ts index ab5b258d29..a2586d444c 100644 --- a/packages/data-center/src/apis/business.ts +++ b/packages/data-center/src/apis/business.ts @@ -37,6 +37,7 @@ export class Business { }; } + // not think out a good way to update workspace meta // updateWorkspaceMeta( // id: string, // meta: { name?: string; avatar: Partial } @@ -87,6 +88,7 @@ export class Business { } } + // no time // getMembers(id: string): any {} // inviteMember(id: string, email: string) {} @@ -96,20 +98,27 @@ export class Business { dc.apis.acceptInviting({ invitingCode }); } + // check with dark sky // getUserInfo(): any {} + // TODO check with dark sky async login() { const dc = await this._getDc(); await dc.auth('affine'); } + // just has no time // logout() {} + // need discuss // setWorkspaceSyncType(id: string, type: 'local' | 'cloud') {} + // need discuss // importWorkspace(file: File) {} + // need discuss may be not in apis // exportWorkspace(id: string) {} + // need discuss // enableWorkspaceCloud(id: string) {} } From dd149474d9432c6e868f12b77079f5c6946f33c7 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Thu, 5 Jan 2023 23:33:13 +0800 Subject: [PATCH 017/298] feat: mock sync --- .../src/components/workspace-modal/index.tsx | 5 +- .../workspace-setting/workspace-setting.tsx | 97 ++++++++++++++++++- packages/app/src/hooks/mock-data/mock.ts | 13 ++- 3 files changed, 110 insertions(+), 5 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index d562538ffc..3ee9848f2d 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -37,6 +37,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { const setList = () => { const data = getWorkspaces(); + console.log('data: ', data); setWorkspaceList(data); }; const setUserInfo = () => { @@ -62,14 +63,14 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
    - {workspaceList.map(item => { + {workspaceList.map((item, index) => { return ( { setActiveWorkspace(item); onClose(); }} - key={item.id} + key={index} > { General + + { + onTabChange && onTabChange(ActiveTab.sync); + }} + > + + + + Sync + + { @@ -150,6 +166,7 @@ export const WorkspaceSetting = ({ {activeTab === ActiveTab.general && ( )} + {activeTab === ActiveTab.sync && } {activeTab === ActiveTab.members && workspace && ( )} @@ -215,9 +232,9 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { > )} {members.length ? ( - members.map(member => { + members.map((member, index) => { return ( - + @@ -395,3 +412,79 @@ const PublishPage = ({ workspace }: { workspace: Workspace }) => { ); }; +const SyncPage = ({ workspace }: { workspace: Workspace }) => { + const [workspaceType, setWorkspaceType] = useState('local'); + useEffect(() => { + setType(); + }); + const setType = () => { + const ACTIVEworkspace = getActiveWorkspace(); + console.log('ACTIVEworkspace: ', ACTIVEworkspace); + ACTIVEworkspace && setWorkspaceType(ACTIVEworkspace.type); + }; + return ( +
    + + {workspaceType === 'local' ? ( + <> + + {workspace.name} is Local Workspace. All data is stored on the + current device. You can enable AFFiNE Cloud for this workspace to + keep data in sync with the cloud. + + + + + + + + + ) : ( + + {workspace.name} is Cloud Workspace. All data will be synchronized + and saved to the AFFiNE account +
    + + { + deleteMember(workspace.id, 0); + }} + icon={} + > + Download core data to device + + { + deleteMember(workspace.id, 0); + }} + icon={} + > + Download all data to device + + + } + placement="bottom-end" + disablePortal={true} + > + + +
    +
    + )} +
    +
    + ); +}; diff --git a/packages/app/src/hooks/mock-data/mock.ts b/packages/app/src/hooks/mock-data/mock.ts index 24e1427a05..510b6dca01 100644 --- a/packages/app/src/hooks/mock-data/mock.ts +++ b/packages/app/src/hooks/mock-data/mock.ts @@ -1,3 +1,5 @@ +import { type } from 'os'; + export interface Workspace { name: string; // 名称 id: string; //唯一标识 @@ -17,13 +19,19 @@ export interface User { export function updateWorkspaceMeta( workspaceId: string, - workspaceData: { name?: string; avatar?: string } + workspaceData: { + name?: string; + avatar?: string; + workspaceType?: 'local' | 'cloud' | 'join'; + } ) { const workspacesMeta = getWorkspaces(); const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { if (workspace.id === workspaceId) { workspaceData.name && (workspace.name = workspaceData.name); workspaceData.avatar && (workspace.avatar = workspaceData.avatar); + workspaceData.workspaceType && + (workspace.type = workspaceData.workspaceType); return workspaceData; } return workspace; @@ -32,6 +40,8 @@ export function updateWorkspaceMeta( const activeWorkspace = getActiveWorkspace(); workspaceData.name && (activeWorkspace.name = workspaceData.name); workspaceData.avatar && (activeWorkspace.avatar = workspaceData.avatar); + workspaceData.workspaceType && + (activeWorkspace.type = workspaceData.workspaceType); setActiveWorkspace(activeWorkspace); } export function createWorkspace(workspaceName: string) { @@ -122,6 +132,7 @@ export function getActiveWorkspace(): Workspace { } export function setActiveWorkspace(workspaceData: Workspace) { + console.log('workspaceData: ', workspaceData); localStorage.setItem( 'affine-active-workspace', JSON.stringify(workspaceData) From e2293ffc44357164f11ea3694bac3f1ebc6b88b6 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Thu, 5 Jan 2023 23:58:17 +0800 Subject: [PATCH 018/298] feat: add api names --- packages/data-center/src/apis/business.ts | 90 ++++++++++++++++--- .../data-center/src/workspaces/workspaces.ts | 4 +- 2 files changed, 82 insertions(+), 12 deletions(-) diff --git a/packages/data-center/src/apis/business.ts b/packages/data-center/src/apis/business.ts index a2586d444c..e364f01a60 100644 --- a/packages/data-center/src/apis/business.ts +++ b/packages/data-center/src/apis/business.ts @@ -1,6 +1,6 @@ import { uuidv4 } from '@blocksuite/store'; -import { getDataCenter } from 'src'; -import { DataCenter } from 'src/datacenter'; +import { getDataCenter } from './../index'; +import { DataCenter } from './../datacenter'; import { Workspace, WorkspaceMeta, WorkspaceType } from '../style'; import { token } from './token'; @@ -51,6 +51,18 @@ export class Business { return dc.workspacesList.getWorkspaces(); } + /** + * Get page list by workspace id + * @param {string} id ID of workspace. + */ + getPagesByWorkspaceId(id: string) { + return []; + } + + /** + * Observe the update of the workspace + * @param {function} callback({Workspace[]}). + */ async onWorkspaceChange(cb: (workspaces: Workspace[]) => void) { const dc = await this._getDc(); dc.workspacesList.on('change', cb); @@ -65,6 +77,10 @@ export class Business { dc.delete(id); } + /** + * The member of the workspace go to leave workspace + * @param {string} id ID of workspace. + */ async leaveWorkspace(id: string) { const dc = await this._getDc(); const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); @@ -74,10 +90,19 @@ export class Business { } } + /** + * Let the workspace to be public + * @param {string} id ID of workspace. + * @param {string} isPublish publish flag of workspace. + */ setWorkspacePublish(id: string, isPublish: boolean): boolean { return isPublish; } + /** + * Get workspace by workspace id + * @param {string} id ID of workspace. + */ async getWorkspaceById(id: string) { const dc = await this._getDc(); const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); @@ -89,9 +114,21 @@ export class Business { } // no time - // getMembers(id: string): any {} - - // inviteMember(id: string, email: string) {} + /** + * Get the members of the workspace + * @param {string} id ID of workspace. + */ + getMembers(id: string): any { + void 0; + } + /** + * Add a new member to the workspace + * @param {string} id ID of workspace. + * @param {string} email new member email. + */ + inviteMember(id: string, email: string) { + void 0; + } async acceptInvitation(invitingCode: string) { const dc = await this._getDc(); @@ -99,7 +136,12 @@ export class Business { } // check with dark sky - // getUserInfo(): any {} + /** + * Get login user info + */ + getUserInfo() { + void 0; + } // TODO check with dark sky async login() { @@ -108,17 +150,45 @@ export class Business { } // just has no time - // logout() {} + /** + * Logout and clear login session + */ + logout() { + void 0; + } // need discuss + /** + * Create a connection between local and cloud, sync cloud data to local + * @param {string} id ID of workspace. + * @param {string} id type of workspace. + */ // setWorkspaceSyncType(id: string, type: 'local' | 'cloud') {} // need discuss - // importWorkspace(file: File) {} + /** + * Select a file to import the workspace + * @param {File} file file of workspace. + */ + importWorkspace(file: File) { + void 0; + } // need discuss may be not in apis - // exportWorkspace(id: string) {} + // /** + // * Generate a file ,and export it to local file system + // * @param {string} id ID of workspace. + // */ + exportWorkspace(id: string) { + void 0; + } // need discuss - // enableWorkspaceCloud(id: string) {} + // /** + // * Enable workspace cloud flag + // * @param {string} id ID of workspace. + // */ + enableWorkspaceCloud(id: string) { + void 0; + } } diff --git a/packages/data-center/src/workspaces/workspaces.ts b/packages/data-center/src/workspaces/workspaces.ts index 2c2211614d..72348e79d7 100644 --- a/packages/data-center/src/workspaces/workspaces.ts +++ b/packages/data-center/src/workspaces/workspaces.ts @@ -1,8 +1,8 @@ import { Workspace } from '@blocksuite/store'; import { Observable } from 'lib0/observable'; import { WorkspaceDetail } from 'src/apis/workspace'; -import { DataCenter } from 'src/datacenter'; -import { User, Workspace as Wp, WorkspaceType } from 'src/style'; +import { DataCenter } from './../datacenter'; +import { User, Workspace as Wp, WorkspaceType } from './../style'; function getProvider(providerList: Record) { return Object.keys(providerList)[0]; From 1da129378934c55902bfe8d3a0f5437f1ab3fcea Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 00:18:43 +0800 Subject: [PATCH 019/298] feat: add removeMember api --- packages/data-center/src/apis/business.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/data-center/src/apis/business.ts b/packages/data-center/src/apis/business.ts index e364f01a60..ababd0e28a 100644 --- a/packages/data-center/src/apis/business.ts +++ b/packages/data-center/src/apis/business.ts @@ -130,6 +130,19 @@ export class Business { void 0; } + /** + * remove the new member to the workspace + * @param {string} workspaceId ID of workspace. + * @param {string} memberId ID of member + */ + removeMember(workspaceId: string, memberId: string) { + void 0; + } + + /** + * A new member click the invite link, finish to join the workspace + * @param {string} inviteCode token for invitation. + */ async acceptInvitation(invitingCode: string) { const dc = await this._getDc(); dc.apis.acceptInviting({ invitingCode }); From 8ebed0b92efea329ed9254ba8b5abd35d7a3fc7a Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 00:48:09 +0800 Subject: [PATCH 020/298] feat: more fluent --- .../src/components/create-workspace/index.tsx | 9 ++++--- .../src/components/workspace-modal/index.tsx | 27 +++++++++++++++---- packages/app/src/hooks/mock-data/mock.ts | 6 ++++- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/packages/app/src/components/create-workspace/index.tsx b/packages/app/src/components/create-workspace/index.tsx index 9059d9bec1..2faeb60e97 100644 --- a/packages/app/src/components/create-workspace/index.tsx +++ b/packages/app/src/components/create-workspace/index.tsx @@ -4,16 +4,19 @@ import { Button } from '@/ui/button'; import { useState } from 'react'; import { createWorkspace } from '@/hooks/mock-data/mock'; import Input from '@/ui/input'; +interface ICloseParams { + workspaceId?: string; +} interface ModalProps { open: boolean; - onClose: () => void; + onClose: (opts?: ICloseParams) => void; } export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { const [workspaceName, setWorkspaceName] = useState(''); const handleCreateWorkspace = () => { - createWorkspace(workspaceName); - onClose(); + const { workspaceId } = createWorkspace(workspaceName); + onClose({ workspaceId }); }; return (
    diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 3ee9848f2d..c2f0581516 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -10,6 +10,7 @@ import { User, getUserInfo, SignOut, + updateWorkspaceMeta, } from '@/hooks/mock-data/mock'; import { CreateWorkspaceModal } from '../create-workspace'; import { @@ -102,13 +103,23 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { fill="#6880FF" /> - {item.name} + + + {item.name || ' undefined'} + - - {item.type === 'local' && ( + + {(item.workspaceType === 'local' || + !item.workspaceType) && ( )} - {item.type === 'cloud' && ( + {item.workspaceType === 'cloud' && ( )} {item.isPublish && } @@ -165,7 +176,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { { + onClose={({ workspaceId }) => { setCreateWorkspaceOpen(false); setList(); onClose(); @@ -177,6 +188,12 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { }).then(confirm => { if (user) { console.log('enable cloud'); + workspaceId && + setTimeout(() => { + updateWorkspaceMeta(workspaceId as string, { + workspaceType: 'cloud', + }); + }, 1000); } else { confirm && Login(); } diff --git a/packages/app/src/hooks/mock-data/mock.ts b/packages/app/src/hooks/mock-data/mock.ts index 510b6dca01..1cb4a8cf89 100644 --- a/packages/app/src/hooks/mock-data/mock.ts +++ b/packages/app/src/hooks/mock-data/mock.ts @@ -6,6 +6,7 @@ export interface Workspace { isPublish?: boolean; // 是否公开 isLocal?: boolean; // 是否全部数据都在本地 avatar?: string; // 封面 + workspaceType: 'local' | 'cloud' | 'join'; // cloud: 云端(本次暂不支持),local: 本地,join : 加入别人的 type: 'local' | 'cloud' | 'join'; // cloud: 云端(本次暂不支持),local: 本地,join : 加入别人的 workspaceOwner?: User; // 本地工作空间的拥有者 } @@ -40,14 +41,16 @@ export function updateWorkspaceMeta( const activeWorkspace = getActiveWorkspace(); workspaceData.name && (activeWorkspace.name = workspaceData.name); workspaceData.avatar && (activeWorkspace.avatar = workspaceData.avatar); + workspaceData.workspaceType && (activeWorkspace.type = workspaceData.workspaceType); setActiveWorkspace(activeWorkspace); } export function createWorkspace(workspaceName: string) { + const workspaceId = 'workspace-' + Date.now(); const workspaceData = { name: workspaceName, - id: 'workspace-' + Date.now(), + id: workspaceId, isPublish: false, isLocal: true, avatar: '', @@ -57,6 +60,7 @@ export function createWorkspace(workspaceName: string) { workspacesMeta.push(workspaceData); localStorage.setItem('affine-workspace', JSON.stringify(workspacesMeta)); setActiveWorkspace(workspaceData); + return { workspaceId }; } export function getWorkspaces(): Workspace[] { From 76f75faf6c675a9077fe1dc3bc3538784c0ae703 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 00:49:04 +0800 Subject: [PATCH 021/298] feat: more fluent --- packages/app/src/components/workspace-modal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index c2f0581516..1f332ce904 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -105,7 +105,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { - {item.name || ' undefined'} + {item.name || 'untitled'} Date: Fri, 6 Jan 2023 00:51:43 +0800 Subject: [PATCH 022/298] feat: more fluent --- .../app/src/components/workspace-modal/index.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 1f332ce904..c1d4402f92 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -104,7 +104,17 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { /> - + {item.name || 'untitled'} @@ -112,7 +122,6 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { style={{ position: 'relative', top: '6px', - marginLeft: '100px', }} > {(item.workspaceType === 'local' || From eb2d3d5d40d546751ea41edd0ed5b13caf674f83 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 01:04:52 +0800 Subject: [PATCH 023/298] feat: add letter avatar --- .../src/components/create-workspace/index.tsx | 4 +- .../src/components/workspace-modal/index.tsx | 63 +++++++++++-------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/packages/app/src/components/create-workspace/index.tsx b/packages/app/src/components/create-workspace/index.tsx index 2faeb60e97..3814d2449e 100644 --- a/packages/app/src/components/create-workspace/index.tsx +++ b/packages/app/src/components/create-workspace/index.tsx @@ -9,7 +9,7 @@ interface ICloseParams { } interface ModalProps { open: boolean; - onClose: (opts?: ICloseParams) => void; + onClose: (opts: ICloseParams) => void; } export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { @@ -28,7 +28,7 @@ export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { top={6} right={6} onClick={() => { - onClose(); + onClose({}); }} /> diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index c1d4402f92..affc9492ec 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -45,6 +45,26 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { const data = getUserInfo(); setUser(data); }; + const stringToColour = function (str: string) { + str = str || 'affine'; + let colour = '#'; + let hash = 0; + // str to hash + for ( + let i = 0; + i < str.length; + hash = str.charCodeAt(i++) + ((hash << 5) - hash) + ); + + // int/hash to hex + for ( + let i = 0; + i < 3; + colour += ('00' + ((hash >> (i++ * 8)) & 0xff).toString(16)).slice(-2) + ); + + return colour; + }; return (
    @@ -74,45 +94,37 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { key={index} > - - - - + {(item.name || 'AFFiNE').substring(0, 1)} +
    {item.name || 'untitled'} @@ -121,7 +133,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { {(item.workspaceType === 'local' || @@ -255,7 +267,6 @@ const WorkspaceItem = styled('div')({ cursor: 'pointer', padding: '8px', border: '1px solid #eee', - fontWeight: 'bold', ':hover': { background: '#eee', }, From 40d09357925e3c44ded3f8dd2519d7cf772440cc Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 01:13:02 +0800 Subject: [PATCH 024/298] feat: global avatar --- .../src/components/workspace-modal/index.tsx | 20 +---------------- .../WorkspaceSelector/WorkspaceSelector.tsx | 22 ++++++++++++++++--- packages/app/src/utils/colors.ts | 20 +++++++++++++++++ packages/app/src/utils/index.ts | 2 ++ 4 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 packages/app/src/utils/colors.ts diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index affc9492ec..caaec6d329 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -21,6 +21,7 @@ import { } from '@blocksuite/icons'; import { useConfirm } from '@/providers/confirm-provider'; import { toast } from '@/ui/toast'; +import { stringToColour } from '@/utils'; interface LoginModalProps { open: boolean; onClose: () => void; @@ -45,26 +46,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { const data = getUserInfo(); setUser(data); }; - const stringToColour = function (str: string) { - str = str || 'affine'; - let colour = '#'; - let hash = 0; - // str to hash - for ( - let i = 0; - i < str.length; - hash = str.charCodeAt(i++) + ((hash << 5) - hash) - ); - // int/hash to hex - for ( - let i = 0; - i < 3; - colour += ('00' + ((hash >> (i++ * 8)) & 0xff).toString(16)).slice(-2) - ); - - return colour; - }; return (
    diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index 5ccc9a446b..9004ef72a9 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -1,9 +1,9 @@ import { Avatar, WorkspaceName, SelectorWrapper } from './styles'; import { useEffect, useState } from 'react'; -import { AffineIcon } from '../icons/icons'; +// import { AffineIcon } from '../icons/icons'; import { WorkspaceModal } from '@/components/workspace-modal'; import { getActiveWorkspace, getWorkspaces } from '@/hooks/mock-data/mock'; - +import { stringToColour } from '@/utils'; export const WorkspaceSelector = () => { const [workspaceListShow, setWorkspaceListShow] = useState(false); const [workspace, setWorkSpace] = useState(getActiveWorkspace()); @@ -34,7 +34,23 @@ export const WorkspaceSelector = () => { data-testid="workspace-avatar" src={workspace.avatar} > - +
    + {(workspace?.name ?? 'AFFiNE').substring(0, 1)} +
    {workspace?.name ?? 'AFFiNE'} diff --git a/packages/app/src/utils/colors.ts b/packages/app/src/utils/colors.ts new file mode 100644 index 0000000000..431342fbf1 --- /dev/null +++ b/packages/app/src/utils/colors.ts @@ -0,0 +1,20 @@ +export function stringToColour(str: string) { + str = str || 'affine'; + let colour = '#'; + let hash = 0; + // str to hash + for ( + let i = 0; + i < str.length; + hash = str.charCodeAt(i++) + ((hash << 5) - hash) + ); + + // int/hash to hex + for ( + let i = 0; + i < 3; + colour += ('00' + ((hash >> (i++ * 8)) & 0xff).toString(16)).slice(-2) + ); + + return colour; +} diff --git a/packages/app/src/utils/index.ts b/packages/app/src/utils/index.ts index aeeaed611c..2d05a590cd 100644 --- a/packages/app/src/utils/index.ts +++ b/packages/app/src/utils/index.ts @@ -3,3 +3,5 @@ export { isDev } from './env'; export * from './useragent'; export * from './tools'; + +export * from './colors'; From fb292b5423755a975a2ff7ab894065ee8ac356c0 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 01:13:57 +0800 Subject: [PATCH 025/298] test: skip avatar test --- tests/local-first-workspace.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/local-first-workspace.spec.ts b/tests/local-first-workspace.spec.ts index f3c1ba9e1c..6c4a948cc4 100644 --- a/tests/local-first-workspace.spec.ts +++ b/tests/local-first-workspace.spec.ts @@ -9,7 +9,7 @@ test.describe('Local first default workspace', () => { expect(await workspaceName.textContent()).toBe('AFFiNE'); }); - test('Default workspace avatar', async ({ page }) => { + test.skip('Default workspace avatar', async ({ page }) => { const workspaceAvatar = page.getByTestId('workspace-avatar'); expect(await workspaceAvatar.innerHTML()).toBe( '' From 67ef5099dd28459334cdfa7f7eb4a80b565e8dee Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 01:20:51 +0800 Subject: [PATCH 026/298] feat: ui --- .../app/src/components/workspace-modal/index.tsx | 14 ++++++++------ packages/app/src/hooks/mock-data/mock.ts | 9 +++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index caaec6d329..e2a3b55f4b 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -109,7 +109,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { top: '20px', }} > - {item.name || 'untitled'} + {item.name || 'AFFiNE'} { top: '20px', }} > - {(item.workspaceType === 'local' || - !item.workspaceType) && ( + {(item.type === 'local' || !item.type) && ( )} - {item.workspaceType === 'cloud' && ( + {item.type === 'cloud' && ( )} {item.isPublish && } @@ -133,6 +132,9 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { })}
  • { const { currentWorkspace, refreshWorkspacesMeta } = useAppState(); useEffect(() => { @@ -85,19 +85,11 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => {
    - {(workspace?.name ?? 'AFFiNE').substring(0, 1)} +
    { { - onTabChange && onTabChange(ActiveTab.publish); + onTabChange && onTabChange(ActiveTab.export); }} > diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index affda10fff..2047010e02 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -2,8 +2,8 @@ import { Avatar, WorkspaceName, SelectorWrapper } from './styles'; import { useEffect, useState } from 'react'; // import { AffineIcon } from '../icons/icons'; import { WorkspaceModal } from '@/components/workspace-modal'; +import { WorkspaceAvatar } from '@/components/workspace-avatar'; import { getActiveWorkspace, getWorkspaces } from '@/hooks/mock-data/mock'; -import { stringToColour } from '@/utils'; export const WorkspaceSelector = () => { const [workspaceListShow, setWorkspaceListShow] = useState(false); const [workspace, setWorkSpace] = useState(getActiveWorkspace()); @@ -37,18 +37,9 @@ export const WorkspaceSelector = () => {
    - {(workspace?.name ?? 'AFFiNE').substring(0, 1)} +
    From 7bbf1d28ea32c24ee7c7a30a6eecd0e7329a248f Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 6 Jan 2023 09:51:20 +0800 Subject: [PATCH 032/298] feat: add code tag --- .../app/src/components/workspace-setting/general/general.tsx | 2 +- .../src/components/workspace-setting/workspace-setting.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/app/src/components/workspace-setting/general/general.tsx b/packages/app/src/components/workspace-setting/general/general.tsx index b8ecd6fcd0..5d808d839f 100644 --- a/packages/app/src/components/workspace-setting/general/general.tsx +++ b/packages/app/src/components/workspace-setting/general/general.tsx @@ -140,7 +140,7 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { Workspace Type - {workspace.type} + {workspace.type} {isOwner ? ( diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index f19a60bd6f..13180a5801 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -466,8 +466,8 @@ const SyncPage = ({ workspace }: { workspace: Workspace }) => { ) : ( - {workspace.name} is Cloud Workspace. All data will be synchronized - and saved to the AFFiNE account + {workspace.name} is Cloud Workspace. All data will be + synchronized and saved to the AFFiNE account
    Date: Fri, 6 Jan 2023 14:26:18 +0800 Subject: [PATCH 033/298] feat: mock sync --- .../src/components/workspace-modal/index.tsx | 14 +- .../general/delete/delete.tsx | 33 ++-- .../workspace-setting/general/delete/style.ts | 7 +- .../workspace-setting/general/general.tsx | 16 +- .../src/components/workspace-setting/style.ts | 7 +- .../workspace-setting/workspace-setting.tsx | 175 +++++++++++------- .../app/src/hooks/use-temporary-helper.ts | 13 +- 7 files changed, 156 insertions(+), 109 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 81293efdbc..eb83c1ab04 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -8,7 +8,6 @@ import { setActiveWorkspace, Login, User, - getUserInfo, SignOut, updateWorkspaceMeta, } from '@/hooks/mock-data/mock'; @@ -22,6 +21,7 @@ import { import { useConfirm } from '@/providers/confirm-provider'; import { toast } from '@/ui/toast'; import { WorkspaceAvatar } from '@/components/workspace-avatar'; +import useTemporaryHelper from '@/hooks/use-temporary-helper'; interface LoginModalProps { open: boolean; onClose: () => void; @@ -29,23 +29,17 @@ interface LoginModalProps { export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { const [workspaceList, setWorkspaceList] = useState([]); - const [user, setUser] = useState(); const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false); const { confirm } = useConfirm(); + const { user, login } = useTemporaryHelper(); useEffect(() => { setList(); - setUserInfo(); }, []); const setList = () => { const data = getWorkspaces(); - console.log('data: ', data); setWorkspaceList(data); }; - const setUserInfo = () => { - const data = getUserInfo(); - setUser(data); - }; return (
    @@ -151,9 +145,8 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { {!user ? ( {/* TODO: add upload logic */} - {/* {isOwner ? ( - upload - ) : null} */} - {/* */} Workspace Name @@ -122,7 +115,7 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { ✔️ - {userInfo ? ( + {/* {userInfo ? (
    Workspace Owner @@ -136,7 +129,7 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => {
    ) : ( '' - )} + )} */} Workspace Type @@ -151,8 +144,7 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { ) : ( diff --git a/packages/app/src/components/workspace-setting/style.ts b/packages/app/src/components/workspace-setting/style.ts index f59125a9fd..7cf6ac9fc2 100644 --- a/packages/app/src/components/workspace-setting/style.ts +++ b/packages/app/src/components/workspace-setting/style.ts @@ -199,11 +199,12 @@ export const StyledMoreVerticalButton = styled('button')(() => { export const StyledPublishExplanation = styled('div')(() => { return { - marginTop: '56px', paddingRight: '48px', fontWeight: '500', fontSize: '18px', lineHeight: '26px', + flex: 1, + marginTop: '60px', }; }); @@ -213,7 +214,9 @@ export const StyledPublishCopyContainer = styled('div')(() => { display: 'flex', flexDirection: 'row', alignItems: 'center', + height: '38px', + paddingTop: '20px', }; }); @@ -226,5 +229,7 @@ export const StyledCopyButtonContainer = styled('div')(() => { export const StyledPublishContent = styled('div')(() => { return { height: '494px', + display: 'flex', + flexDirection: 'column', }; }); diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index 13180a5801..7e4ebc7247 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -56,6 +56,8 @@ import { User, Workspace, } from '@/hooks/mock-data/mock'; +import useTemporaryHelper from '@/hooks/use-temporary-helper'; +import { useConfirm } from '@/providers/confirm-provider'; enum ActiveTab { 'general' = 'general', @@ -364,66 +366,108 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { const PublishPage = ({ workspace }: { workspace: Workspace }) => { const shareUrl = window.location.host + '/workspace/' + workspace.id + '?share=true'; - const [publicStatus, setPublicStatus] = useState( - workspace.isPublish ?? false - ); + + const { login, updateWorkspaceMeta, user, currentWorkspace } = + useTemporaryHelper(); + const { confirm } = useConfirm(); + const togglePublic = (flag: boolean) => { - const isPublic = setWorkspacePublish(workspace.id, flag); - setPublicStatus(isPublic); + updateWorkspaceMeta(currentWorkspace.id, { isPublish: flag }); }; const copyUrl = () => { navigator.clipboard.writeText(shareUrl); toast('Copied url to clipboard'); }; + + const enableAffineCloud = () => { + confirm({ + title: 'Enable AFFiNE Cloud?', + content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`, + confirmText: user ? 'Enable' : 'Sign in and Enable', + cancelText: 'Skip', + }).then(confirm => { + if (user) { + updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); + } else { + confirm && login(); + updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); + } + }); + }; return ( -
    - - {publicStatus ? ( + <> + {user ? ( +
    + + {currentWorkspace?.isPublish ? ( + <> + + Publishing to web requires AFFiNE Cloud service . + + + Share with link + + + + + + + + + ) : ( + + After publishing to the web, everyone can view the content of + this workspace through the link. + + )} + + {!currentWorkspace?.isPublish ? ( + + ) : ( + + )} +
    + ) : ( + <> - The current workspace has been published to the web, everyone can - view the contents of this workspace through the link. + Publishing to web requires AFFiNE Cloud service. - Share with link + - - - - + - ) : ( - - After publishing to the web, everyone can view the content of this - workspace through the link. - - )} - - {!publicStatus ? ( - - ) : ( - +
    )} -
    + ); }; const SyncPage = ({ workspace }: { workspace: Workspace }) => { @@ -433,7 +477,6 @@ const SyncPage = ({ workspace }: { workspace: Workspace }) => { }); const setType = () => { const ACTIVEworkspace = getActiveWorkspace(); - console.log('ACTIVEworkspace: ', ACTIVEworkspace); ACTIVEworkspace && setWorkspaceType(ACTIVEworkspace.type); }; return ( @@ -448,27 +491,27 @@ const SyncPage = ({ workspace }: { workspace: Workspace }) => { - - - + ) : ( - - {workspace.name} is Cloud Workspace. All data will be - synchronized and saved to the AFFiNE account -
    + <> + + {workspace.name} is Cloud Workspace. All data will be + synchronized and saved to the AFFiNE + + @@ -495,8 +538,8 @@ const SyncPage = ({ workspace }: { workspace: Workspace }) => { > -
    -
    + + )}
    diff --git a/packages/app/src/hooks/use-temporary-helper.ts b/packages/app/src/hooks/use-temporary-helper.ts index 8de0ef88a0..c2727f1653 100644 --- a/packages/app/src/hooks/use-temporary-helper.ts +++ b/packages/app/src/hooks/use-temporary-helper.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { getWorkspaces, Workspace, User } from './mock-data/mock'; export function getActiveWorkspace(): Workspace { @@ -12,16 +12,19 @@ export const useTemporaryHelper = () => { const [currentWorkspace, setCurrentWorkspace] = useState( JSON.parse(localStorage.getItem('affine-active-workspace') ?? '{}') ); - const [user, setUser] = useState(null); + const [user, setUser] = useState(); return { - updateWorkspaceMeta: (workspaceId: string, workspaceData: Workspace) => { + updateWorkspaceMeta: ( + workspaceId: string, + workspaceData: { name?: string; avatar?: string; isPublish?: boolean } + ) => { const workspacesMeta = getWorkspaces(); const newWorkspacesMeta = workspacesMeta.map((workspace: Workspace) => { if (workspace.id === workspaceId) { workspaceData.name && (workspace.name = workspaceData.name); workspaceData.avatar && (workspace.avatar = workspaceData.avatar); - return workspaceData; + return workspace; } return workspace; }); @@ -94,7 +97,7 @@ export const useTemporaryHelper = () => { avatar: 'string', }; localStorage.setItem('affine-user', JSON.stringify(userInfo)); - + console.log('login'); setUser(userInfo); }, getUserInfo: () => { From 97567e2e1fe54bb561c5ce7e9988e7a540f7d0b7 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Fri, 6 Jan 2023 14:42:19 +0800 Subject: [PATCH 034/298] feat: mock login --- .../workspace-setting/MembersPage.tsx | 198 +++++++++ .../workspace-setting/PublishPage.tsx | 122 ++++++ .../components/workspace-setting/SyncPage.tsx | 91 ++++ .../workspace-setting/workspace-setting.tsx | 397 +----------------- 4 files changed, 415 insertions(+), 393 deletions(-) create mode 100644 packages/app/src/components/workspace-setting/MembersPage.tsx create mode 100644 packages/app/src/components/workspace-setting/PublishPage.tsx create mode 100644 packages/app/src/components/workspace-setting/SyncPage.tsx diff --git a/packages/app/src/components/workspace-setting/MembersPage.tsx b/packages/app/src/components/workspace-setting/MembersPage.tsx new file mode 100644 index 0000000000..7695a43b0c --- /dev/null +++ b/packages/app/src/components/workspace-setting/MembersPage.tsx @@ -0,0 +1,198 @@ +import { + StyledMemberAvatar, + StyledMemberButtonContainer, + StyledMemberEmail, + StyledMemberInfo, + StyledMemberListContainer, + StyledMemberListItem, + StyledMemberName, + StyledMemberNameContainer, + StyledMemberRoleContainer, + StyledMemberTitleContainer, + StyledMoreVerticalButton, +} from './style'; +import { MoreVerticalIcon, EmailIcon, TrashIcon } from '@blocksuite/icons'; +import { useEffect, useState } from 'react'; +import { Button, IconButton } from '@/ui/button'; +import { InviteMembers } from '../invite-members/index'; +// import { Member, getDataCenter } from '@affine/datacenter'; +// import { Avatar } from '@mui/material'; +import { Menu, MenuItem } from '@/ui/menu'; +import { Empty } from '@/ui/empty'; +import { + deleteMember, + getMembers, + getUserInfo, + Login, + User, + Workspace, +} from '@/hooks/mock-data/mock'; + +// import { useAppState } from '@/providers/app-state-provider'; +export const MembersPage = ({ workspace }: { workspace: Workspace }) => { + const [isInviteModalShow, setIsInviteModalShow] = useState(false); + const [members, setMembers] = useState([]); + const [userInfo, setUserInfo] = useState(); + // const refreshMembers = useCallback(() => { + // getDataCenter() + // .then(dc => + // dc.apis.getWorkspaceMembers({ + // id: workspace.id, + // }) + // ) + // .then(data => { + // setMembers(data); + // }) + // .catch(err => { + // console.log(err); + // }); + // }, [workspace.id]); + + useEffect(() => { + setUser(); + setMembersList(); + // refreshMembers(); + }, []); + + const setUser = () => { + const user = getUserInfo(); + user && setUserInfo(user); + }; + const setMembersList = () => { + const members = getMembers(workspace.id); + members && setMembers(members); + }; + + return ( +
    + {userInfo ? ( + <> + + + Users({members.length}) + + Access level + + + {members.length === 0 && ( + + )} + {members.length ? ( + members.map((member, index) => { + return ( + + + + + + + + {member.name} + + {member.email} + + + + {/* {member.accepted + ? member.type !== 99 + ? 'Member' + : 'Workspace Owner' + : 'Pending'} */} + Pending + + + + { + deleteMember(workspace.id, 0); + setMembersList(); + // confirm({ + // title: 'Delete Member?', + // content: `will delete member`, + // confirmText: 'Delete', + // confirmType: 'danger', + // }).then(confirm => { + // getDataCenter() + // .then(dc => + // dc.apis.removeMember({ + // permissionId: member.id, + // }) + // ) + // .then(() => { + // // console.log('data: ', data); + // toast('Moved to Trash'); + // // refreshMembers(); + // }); + // }); + }} + icon={} + > + Delete + + + } + placement="bottom-end" + disablePortal={true} + > + + + + + + + ); + }) + ) : ( + <> + )} + + + + { + setIsInviteModalShow(false); + }} + onInviteSuccess={() => { + setMembersList(); + setIsInviteModalShow(false); + // refreshMembers(); + }} + workspaceId={workspace.id} + open={isInviteModalShow} + > + + + ) : ( + <> +
    + Collaborating with other members requires AFFiNE Cloud service. +
    +
    + +
    + + )} +
    + ); +}; diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx new file mode 100644 index 0000000000..f5136e76bd --- /dev/null +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -0,0 +1,122 @@ +import { + StyledCopyButtonContainer, + StyledPublishContent, + StyledPublishCopyContainer, + StyledPublishExplanation, + StyledSettingH2, +} from './style'; + +import { Button } from '@/ui/button'; +import Input from '@/ui/input'; +import { toast } from '@/ui/toast'; +import { Workspace } from '@/hooks/mock-data/mock'; +import useTemporaryHelper from '@/hooks/use-temporary-helper'; +import { useConfirm } from '@/providers/confirm-provider'; + +export const PublishPage = ({ workspace }: { workspace: Workspace }) => { + const shareUrl = + window.location.host + '/workspace/' + workspace.id + '?share=true'; + + const { login, updateWorkspaceMeta, user, currentWorkspace } = + useTemporaryHelper(); + const { confirm } = useConfirm(); + + const togglePublic = (flag: boolean) => { + updateWorkspaceMeta(currentWorkspace.id, { isPublish: flag }); + }; + + const copyUrl = () => { + navigator.clipboard.writeText(shareUrl); + toast('Copied url to clipboard'); + }; + + const enableAffineCloud = () => { + confirm({ + title: 'Enable AFFiNE Cloud?', + content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`, + confirmText: user ? 'Enable' : 'Sign in and Enable', + cancelText: 'Skip', + }).then(confirm => { + if (user) { + updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); + } else { + confirm && login(); + updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); + } + }); + }; + return ( + <> + {currentWorkspace.type === 'cloud' ? ( +
    + + {currentWorkspace?.isPublish ? ( + <> + + Publishing to web requires AFFiNE Cloud service . + + + Share with link + + + + + + + + + ) : ( + + After publishing to the web, everyone can view the content of + this workspace through the link. + + )} + + {!currentWorkspace?.isPublish ? ( + + ) : ( + + )} +
    + ) : ( + + <> + + Publishing to web requires AFFiNE Cloud service. + + + + + + + + )} + + ); +}; diff --git a/packages/app/src/components/workspace-setting/SyncPage.tsx b/packages/app/src/components/workspace-setting/SyncPage.tsx new file mode 100644 index 0000000000..572a67f775 --- /dev/null +++ b/packages/app/src/components/workspace-setting/SyncPage.tsx @@ -0,0 +1,91 @@ +import { + StyledPublishContent, + StyledPublishCopyContainer, + StyledPublishExplanation, +} from './style'; +import { DownloadIcon } from '@blocksuite/icons'; +import { useEffect, useState } from 'react'; +import { Button } from '@/ui/button'; +import { Menu, MenuItem } from '@/ui/menu'; +import { + deleteMember, + getActiveWorkspace, + updateWorkspaceMeta, + Workspace, +} from '@/hooks/mock-data/mock'; + +export const SyncPage = ({ workspace }: { workspace: Workspace }) => { + const [workspaceType, setWorkspaceType] = useState('local'); + useEffect(() => { + setType(); + }); + const setType = () => { + const ACTIVEworkspace = getActiveWorkspace(); + ACTIVEworkspace && setWorkspaceType(ACTIVEworkspace.type); + }; + return ( +
    + + {workspaceType === 'local' ? ( + <> + + {workspace.name} is Local Workspace. All data is stored on the + current device. You can enable AFFiNE Cloud for this workspace to + keep data in sync with the cloud. + + + + + + + ) : ( + <> + + {workspace.name} is Cloud Workspace. All data will be + synchronized and saved to the AFFiNE + + + + { + deleteMember(workspace.id, 0); + }} + icon={} + > + Download core data to device + + { + deleteMember(workspace.id, 0); + }} + icon={} + > + Download all data to device + + + } + placement="bottom-end" + disablePortal={true} + > + + + + + )} + +
    + ); +}; diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index 7e4ebc7247..7d292c9b98 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -1,23 +1,7 @@ import Modal, { ModalCloseButton } from '@/ui/modal'; import { - StyledCopyButtonContainer, - StyledMemberAvatar, - StyledMemberButtonContainer, - StyledMemberEmail, - StyledMemberInfo, - StyledMemberListContainer, - StyledMemberListItem, - StyledMemberName, - StyledMemberNameContainer, - StyledMemberRoleContainer, - StyledMemberTitleContainer, - StyledMoreVerticalButton, - StyledPublishContent, - StyledPublishCopyContainer, - StyledPublishExplanation, StyledSettingContainer, StyledSettingContent, - StyledSettingH2, StyledSettingSidebar, StyledSettingSidebarHeader, StyledSettingTabContainer, @@ -28,36 +12,14 @@ import { EditIcon, UsersIcon, PublishIcon, - MoreVerticalIcon, - EmailIcon, - TrashIcon, - DownloadIcon, CloudInsyncIcon, } from '@blocksuite/icons'; import { useEffect, useState } from 'react'; -import { Button, IconButton } from '@/ui/button'; -import Input from '@/ui/input'; -import { InviteMembers } from '../invite-members/index'; -// import { Member, getDataCenter } from '@affine/datacenter'; -// import { Avatar } from '@mui/material'; -import { Menu, MenuItem } from '@/ui/menu'; -import { toast } from '@/ui/toast'; -import { Empty } from '@/ui/empty'; -// import { useAppState } from '@/providers/app-state-provider'; import { GeneralPage } from './general'; -import { - deleteMember, - getActiveWorkspace, - getMembers, - getUserInfo, - Login, - setWorkspacePublish, - updateWorkspaceMeta, - User, - Workspace, -} from '@/hooks/mock-data/mock'; -import useTemporaryHelper from '@/hooks/use-temporary-helper'; -import { useConfirm } from '@/providers/confirm-provider'; +import { getActiveWorkspace } from '@/hooks/mock-data/mock'; +import MembersPage from './MembersPage'; +import PublishPage from './PublishPage'; +import SyncPage from './SyncPage'; enum ActiveTab { 'general' = 'general', @@ -194,354 +156,3 @@ export const WorkspaceSetting = ({ ); }; - -const MembersPage = ({ workspace }: { workspace: Workspace }) => { - const [isInviteModalShow, setIsInviteModalShow] = useState(false); - const [members, setMembers] = useState([]); - const [userInfo, setUserInfo] = useState(); - // const refreshMembers = useCallback(() => { - // getDataCenter() - // .then(dc => - // dc.apis.getWorkspaceMembers({ - // id: workspace.id, - // }) - // ) - // .then(data => { - // setMembers(data); - // }) - // .catch(err => { - // console.log(err); - // }); - // }, [workspace.id]); - - useEffect(() => { - setUser(); - setMembersList(); - // refreshMembers(); - }, []); - - const setUser = () => { - const user = getUserInfo(); - user && setUserInfo(user); - }; - const setMembersList = () => { - const members = getMembers(workspace.id); - members && setMembers(members); - }; - - return ( -
    - {userInfo ? ( - <> - - - Users({members.length}) - - Access level - - - {members.length === 0 && ( - - )} - {members.length ? ( - members.map((member, index) => { - return ( - - - - - - - - {member.name} - - {member.email} - - - - {/* {member.accepted - ? member.type !== 99 - ? 'Member' - : 'Workspace Owner' - : 'Pending'} */} - Pending - - - - { - deleteMember(workspace.id, 0); - setMembersList(); - // confirm({ - // title: 'Delete Member?', - // content: `will delete member`, - // confirmText: 'Delete', - // confirmType: 'danger', - // }).then(confirm => { - // getDataCenter() - // .then(dc => - // dc.apis.removeMember({ - // permissionId: member.id, - // }) - // ) - // .then(() => { - // // console.log('data: ', data); - // toast('Moved to Trash'); - // // refreshMembers(); - // }); - // }); - }} - icon={} - > - Delete - - - } - placement="bottom-end" - disablePortal={true} - > - - - - - - - ); - }) - ) : ( - <> - )} - - - - { - setIsInviteModalShow(false); - }} - onInviteSuccess={() => { - setMembersList(); - setIsInviteModalShow(false); - // refreshMembers(); - }} - workspaceId={workspace.id} - open={isInviteModalShow} - > - - - ) : ( - <> -
    - Collaborating with other members requires AFFiNE Cloud service. -
    -
    - -
    - - )} -
    - ); -}; - -const PublishPage = ({ workspace }: { workspace: Workspace }) => { - const shareUrl = - window.location.host + '/workspace/' + workspace.id + '?share=true'; - - const { login, updateWorkspaceMeta, user, currentWorkspace } = - useTemporaryHelper(); - const { confirm } = useConfirm(); - - const togglePublic = (flag: boolean) => { - updateWorkspaceMeta(currentWorkspace.id, { isPublish: flag }); - }; - - const copyUrl = () => { - navigator.clipboard.writeText(shareUrl); - toast('Copied url to clipboard'); - }; - - const enableAffineCloud = () => { - confirm({ - title: 'Enable AFFiNE Cloud?', - content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`, - confirmText: user ? 'Enable' : 'Sign in and Enable', - cancelText: 'Skip', - }).then(confirm => { - if (user) { - updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); - } else { - confirm && login(); - updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); - } - }); - }; - return ( - <> - {user ? ( -
    - - {currentWorkspace?.isPublish ? ( - <> - - Publishing to web requires AFFiNE Cloud service . - - - Share with link - - - - - - - - - ) : ( - - After publishing to the web, everyone can view the content of - this workspace through the link. - - )} - - {!currentWorkspace?.isPublish ? ( - - ) : ( - - )} -
    - ) : ( - - <> - - Publishing to web requires AFFiNE Cloud service. - - - - - - - - )} - - ); -}; -const SyncPage = ({ workspace }: { workspace: Workspace }) => { - const [workspaceType, setWorkspaceType] = useState('local'); - useEffect(() => { - setType(); - }); - const setType = () => { - const ACTIVEworkspace = getActiveWorkspace(); - ACTIVEworkspace && setWorkspaceType(ACTIVEworkspace.type); - }; - return ( -
    - - {workspaceType === 'local' ? ( - <> - - {workspace.name} is Local Workspace. All data is stored on the - current device. You can enable AFFiNE Cloud for this workspace to - keep data in sync with the cloud. - - - - - - - ) : ( - <> - - {workspace.name} is Cloud Workspace. All data will be - synchronized and saved to the AFFiNE - - - - { - deleteMember(workspace.id, 0); - }} - icon={} - > - Download core data to device - - { - deleteMember(workspace.id, 0); - }} - icon={} - > - Download all data to device - - - } - placement="bottom-end" - disablePortal={true} - > - - - - - )} - -
    - ); -}; From 3d5f239e4e84d5c8a9e15d389b35ac6ce2ad4eac Mon Sep 17 00:00:00 2001 From: JimmFly Date: Fri, 6 Jan 2023 15:00:42 +0800 Subject: [PATCH 035/298] feat: add language switch --- .../src/components/workspace-modal/index.tsx | 2 + .../workspace-modal/languageMenu.tsx | 95 +++++++++++++++++++ .../src/components/workspace-modal/styles.ts | 20 ++++ packages/app/src/libs/i18n/resources/bn.json | 23 +---- packages/app/src/libs/i18n/resources/fr.json | 30 +----- packages/app/src/libs/i18n/resources/sr.json | 28 +----- .../app/src/libs/i18n/resources/zh-Hans.json | 88 ++++++++++++----- .../app/src/libs/i18n/resources/zh-Hant.json | 30 +----- packages/app/src/ui/confirm/Confirm.tsx | 2 +- 9 files changed, 184 insertions(+), 134 deletions(-) create mode 100644 packages/app/src/components/workspace-modal/languageMenu.tsx diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 81293efdbc..b86cb67ad6 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -2,6 +2,7 @@ import { styled } from '@/styles'; import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Button } from '@/ui/button'; import { useEffect, useState } from 'react'; +import { LanguageMenu } from './languageMenu'; import { getWorkspaces, Workspace, @@ -56,6 +57,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { >
    My Workspaces + { + const { i18n } = useTranslation(); + const changeLanguage = (event: string) => { + i18n.changeLanguage(event); + }; + const [show, setShow] = useState(false); + const currentLanguage = LOCALES.find(item => item.tag === i18n.language); + const [languageName, setLanguageName] = useState( + currentLanguage?.originalName + ); + return ( + + {LOCALES.map(option => { + return ( + { + changeLanguage(option.tag); + setShow(false); + setLanguageName(option.originalName); + }} + > + {option.originalName} + + ); + })} + + } + open={show} + > + { + setShow(!show); + }} + > + + {languageName} + + + + + ); +}; + +const StyledContainer = styled('div')(() => ({ + display: 'flex', + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', +})); + +const StyledText = styled('span')(({ theme }) => ({ + marginRight: '4px', + marginLeft: '16px', + fontSize: theme.font.sm, + fontWeight: '500', + textTransform: 'capitalize', +})); +const StyledTooltip = styled(({ className, ...props }: TooltipProps) => ( + +))(({ theme }) => ({ + zIndex: theme.zIndex.modal, + '& .MuiTooltip-tooltip': { + backgroundColor: theme.colors.popoverBackground, + boxShadow: theme.shadow.modal, + color: theme.colors.popoverColor, + }, +})); + +const ListItem = styled(Button)(({ theme }) => ({ + display: 'block', + width: '100%', + color: theme.colors.popoverColor, + fontSize: theme.font.sm, + textTransform: 'capitalize', +})); + +const StyledTitleButton = styled(Button)(({ theme }) => ({ + position: 'absolute', + right: '50px', + color: theme.colors.popoverColor, + fontSize: theme.font.sm, +})); diff --git a/packages/app/src/components/workspace-modal/styles.ts b/packages/app/src/components/workspace-modal/styles.ts index 40a8bcc375..a54b191fce 100644 --- a/packages/app/src/components/workspace-modal/styles.ts +++ b/packages/app/src/components/workspace-modal/styles.ts @@ -1,4 +1,7 @@ import { displayFlex, styled } from '@/styles'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import Select from '@mui/material/Select'; export const StyledTitle = styled.div(() => { return { @@ -36,3 +39,20 @@ export const StyledButton = styled.div(({ theme }) => { ...displayFlex('center', 'center'), }; }); +export const StyledFormControl = styled(FormControl)(({ theme }) => { + return { + position: 'absolute', + minWidth: '100px', + right: '50px', + backgroundColor: theme.colors.popoverBackground, + }; +}); +export const StyledSelect = styled(Select)(({ theme }) => { + return { + backgroundColor: theme.colors.popoverBackground, + color: theme.colors.popoverColor, + }; +}); +export const StyledMenuItem = styled(MenuItem)(() => { + return {}; +}); diff --git a/packages/app/src/libs/i18n/resources/bn.json b/packages/app/src/libs/i18n/resources/bn.json index 5eb50f8cdf..0967ef424b 100644 --- a/packages/app/src/libs/i18n/resources/bn.json +++ b/packages/app/src/libs/i18n/resources/bn.json @@ -1,22 +1 @@ -{ - "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "", - "Add A Below Block": "নীচে একটি ব্লক যোগ করুন", - "WarningTips": { - "IsNotfsApiSupported": "অ্যাফাইন ডেমোতে স্বাগতম। পরিবর্তনগুলি সংরক্ষণ করা শুরু করতে আপনি Chrome/Edge এর মতো ক্রোমিয়াম ভিত্তিক ব্রাউজারের সর্বশেষ সংস্করণের মাধ্যমে ডিস্কে ডেটা সিঙ্ক করতে পারেন", - "DoNotStore": "অ্যাফাইন সক্রিয় ডেভেলপমেন্ট এর অধীনে এবং বর্তমান সংস্করণটি অস্থিতিশীল। দয়া করে কোন তথ্য বা ডেটা সঞ্চয় করবেন না" - }, - "Language": "ভাষা", - "Settings": "সেটিংস", - "Share": "শেয়ার করুন", - "Comment": "মন্তব্য", - "Delete": "মুছে ফেলুন", - "Copy Page Link": "পেজ লিংক কপি করুন", - "Duplicate Page": "সদৃশ পৃষ্ঠা তৈরি করুন", - "Logout": "লগআউট", - "Divide Here As A New Group": "একটি নতুন গ্রুপ হিসেবে বিভক্ত করুন", - "ComingSoon": "লেআউট সেটিংস শীঘ্রই আসছে...", - "Clear Workspace": "ওয়ার্কস্পেস পরিষ্কার করুন", - "Layout": "লেআউট", - "Turn into": "রূপান্তর করুন", - "Sync to Disk": "ডিস্ক এ সিঙ্ক করুন" -} +{} diff --git a/packages/app/src/libs/i18n/resources/fr.json b/packages/app/src/libs/i18n/resources/fr.json index d30fdcb133..0967ef424b 100644 --- a/packages/app/src/libs/i18n/resources/fr.json +++ b/packages/app/src/libs/i18n/resources/fr.json @@ -1,29 +1 @@ -{ - "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "", - "ComingSoon": "Bientôt disponible", - "Duplicate Page": "Dupliquer la page", - "Copy Page Link": "Copier le lien de la page", - "Delete": "Supprimer", - "Comment": "Commentaire", - "Export As HTML": "Exporter en HTML", - "Export As Markdown": "Exporter en Markdown", - "Export As PDF (Unsupported)": "exporter en PDF (non supporté)", - "Logout": "Déconnexion", - "Export Workspace": "Exporter l'espace de travail", - "Import Workspace": "Importer l'espace de travail", - "Language": "Langue", - "Last edited by": "Dernière édition par {{name}}", - "Layout": "Mise en forme", - "Settings": "Réglages", - "Share": "Partager", - "Sync to Disk": "Synchroniser sur le disque", - "Turn into": "Transformer en", - "WarningTips": { - "DoNotStore": "Affine est en développement actif ; la version actuelle est INSTABLE. Veuillez NE PAS stocker d'informations ou de données", - "IsNotLocalWorkspace": "Bienvenue sur la démo d'AFFiNE. Pour commencer à sauvegarder vos modifications, vous pouvez SYNCHRONISER SUR LE DISQUE", - "IsNotfsApiSupported": "Bienvenue sur la démo d'AFFiNE. Pour commencer à sauvegarder vos modifications, vous pouvez SYNCHRONISER SUR LE DISQUE\navec la dernière version d'un navigateur basé sur Chromium tel que Chrome ou Edge." - }, - "Add A Below Block": "Ajouter un bloc en-dessous", - "Divide Here As A New Group": "Séparer ici en un nouveau groupe", - "Clear Workspace": "Vider l'espace de travail" -} +{} diff --git a/packages/app/src/libs/i18n/resources/sr.json b/packages/app/src/libs/i18n/resources/sr.json index edc6c32f2c..0967ef424b 100644 --- a/packages/app/src/libs/i18n/resources/sr.json +++ b/packages/app/src/libs/i18n/resources/sr.json @@ -1,27 +1 @@ -{ - "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "", - "Clear Workspace": "Očisti radni prostor", - "ComingSoon": "Podešavanja za izgled dolaze", - "Comment": "Komentar", - "Copy Page Link": "Kopiraj link stranice", - "Delete": "Obriši", - "Duplicate Page": "Dupliraj stranicu", - "Export As HTML": "Izvezi kao HTML", - "Export As Markdown": "Izvezi kao Markdown", - "Export As PDF (Unsupported)": "Izvezi kao PDF (nepodržano)", - "Export Workspace": "Izvezi radnu površinu", - "Import Workspace": "Poboljšaj radnu površinu", - "Language": "Jezik", - "Last edited by": "Zadnju promenu uradio {{ime}}", - "Layout": "Izgled", - "Logout": "Odjava", - "Settings": "Podešavanja", - "Share": "Podeli", - "Sync to Disk": "Sinhroniziraj sa diskom", - "Turn into": "Promeni u", - "WarningTips": { - "DoNotStore": "AFFiNE je u stanju aktivnog razvoja i trenutna verzija je NESTABILNA. Molimo vas, NEMOJTE čuvati informacije ili podatke.", - "IsNotLocalWorkspace": "Dobrodošli u AFFiNE demo. Da bi započeli proces čuvanja promena možete kliknuti SINHRONIZUJ SA DISKOM.", - "IsNotfsApiSupported": "Dobrodošli u AFFiNE demo. Da bi započeli proces čuvanja promena možete SINHRONIZOVATI NA DISK sa poslednjom verzijom pretraživača tipa Chromium, kao što su Chrome/Edge." - } -} +{} diff --git a/packages/app/src/libs/i18n/resources/zh-Hans.json b/packages/app/src/libs/i18n/resources/zh-Hans.json index 14786dcb7e..47095233d9 100644 --- a/packages/app/src/libs/i18n/resources/zh-Hans.json +++ b/packages/app/src/libs/i18n/resources/zh-Hans.json @@ -1,29 +1,65 @@ { - "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "", - "Sync to Disk": "同步到磁盘", - "Share": "分享", - "WarningTips": { - "IsNotfsApiSupported": "欢迎来到AFFiNE 的演示界面。您可以使用最新版本的基于Chrome的浏览器(如Chrome/Edge)将数据同步到磁盘来进行保存", - "IsNotLocalWorkspace": "欢迎来到AFFiNE 的演示界面,您可以同步到磁盘来进行保存操作。", - "DoNotStore": "AFFiNE 正在积极开发中,当前版本不稳定。请不要存储信息或数据。" - }, - "ComingSoon": "布局设置即将到来", - "Layout": "布局", - "Comment": "评论", - "Settings": "设置", - "Duplicate Page": "复制页面", - "Copy Page Link": "复制页面链接", - "Language": "当前语言", - "Clear Workspace": "清空工作区域", - "Export As Markdown": "导出 markdown", - "Export As HTML": "导出 HTML", - "Export As PDF (Unsupported)": "导出 PDF (暂不支持)", - "Import Workspace": "导入 Workspace", - "Export Workspace": "导出 Workspace", - "Last edited by": "最后编辑者为 {{name}}", - "Logout": "退出登录", + "Quick search": "快速搜索", + "All pages": "全部页面", + "Favourites": "收藏夹", + "No item": "没有项目", + "Import": "导入", + "Trash": "回收站", + "New Page": "新建文章", + "New Keyword Page": "新建 '{{query}}' 为标题的文章", + "Find 0 result": "找到 0 个结果", + "Find results": "找到 {{number}} 个结果", + "Collapse sidebar": "关闭侧边栏", + "Expand sidebar": "展开侧边栏", + "Removed from Favourites": "已从收藏中移除", + "Remove from favourites": "从收藏中移除", + "Added to Favourites": "已添加到收藏", + "Add to favourites": "添加到收藏", + "Paper": "文章", + "Edgeless": "无边模式", + "Switch to": "跳转到", + "Convert to ": "转换成 ", + "Page": "文章", + "Export": "导出", + "Export to HTML": "导出到 HTML", + "Export to Markdown": "导出到 Markdown", "Delete": "删除", - "Turn into": "转换为", - "Add A Below Block": "在下方添加一个新块", - "Divide Here As A New Group": "从这里划分一个新组" + "Title": "标题", + "Untitled": "无标题", + "Created": "创建时间", + "Updated": "更新时间", + "Open in new tab": "在新页面打开", + "Favourite": "收藏", + "Favourited": "已收藏", + "Delete page?": "删除文章?", + "Delete permanently?": "永久删除?", + "will be moved to Trash": "{{title}} 将被移动到回收站", + "Once deleted, you can't undo this action.": "一次性删除,无法恢复。", + "Moved to Trash": "已移动到回收站", + "Permanently deleted": "已永久删除", + "restored": "{{title}} 已恢复", + "Cancel": "取消", + "Keyboard Shortcuts": "快捷键", + "Contact Us": "联系我们", + "Official Website": "官网", + "Get in touch!": "Get in touch!", + "AFFiNE Community": "AFFiNE Community", + "How is AFFiNE Alpha different?": "How is AFFiNE Alpha different?", + "Shortcuts": "Shortcuts", + "Undo": "Undo", + "Redo": "Redo", + "Bold": "Bold", + "Italic": "Italic", + "Underline": "Underline", + "Strikethrough": "Strikethrough", + "Inline code": "Inline code", + "Code block": "Code block", + "Link": "Link", + "Body text": "Body text", + "Heading": "Heading {{number}}", + "Increase indent": "Increase indent", + "Reduce indent": "Reduce indent", + "Markdown Syntax": "Markdown Syntax", + "Divider": "Divider", + "404 - Page Not Found": "404 - Page Not Found" } diff --git a/packages/app/src/libs/i18n/resources/zh-Hant.json b/packages/app/src/libs/i18n/resources/zh-Hant.json index 4d0f28c9cd..0967ef424b 100644 --- a/packages/app/src/libs/i18n/resources/zh-Hant.json +++ b/packages/app/src/libs/i18n/resources/zh-Hant.json @@ -1,29 +1 @@ -{ - "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "", - "Add A Below Block": "在下方新添塊", - "Clear Workspace": "清空工作區", - "ComingSoon": "自定義佈局功能即將與您見面", - "Comment": "評論", - "Copy Page Link": "拷貝頁面鏈接", - "Delete": "刪除", - "Divide Here As A New Group": "從此地劃分成新組", - "Duplicate Page": "複製界面", - "Export As HTML": "導出 HTML", - "Export As Markdown": "以 Markdown 導出", - "Export As PDF (Unsupported)": "導出為 PDF(即將可用)", - "Export Workspace": "導出 Workspace", - "Import Workspace": "導入 Workspace", - "Language": "語言", - "Last edited by": "最後編輯者為 {{name}}", - "Layout": "佈局", - "Logout": "退出登錄", - "Settings": "設置", - "Share": "分享", - "Sync to Disk": "同步到磁盤", - "Turn into": "轉換為", - "WarningTips": { - "DoNotStore": "我們正在積極開發 AFFiNE,目前版本尚不穩定,請避免存儲信息或數據。", - "IsNotLocalWorkspace": "歡迎來到 AFFiNE 演示界面。您可以通過「同步到磁盤」來保存更改。", - "IsNotfsApiSupported": "歡迎進入AFFiNE演示!使用最新版本的基於 Chromium 內核的瀏覽器如Chrome/Edge,您可以通過「同步到磁盤」來保存更改" - } -} +{} diff --git a/packages/app/src/ui/confirm/Confirm.tsx b/packages/app/src/ui/confirm/Confirm.tsx index 872a43624e..dee4953812 100644 --- a/packages/app/src/ui/confirm/Confirm.tsx +++ b/packages/app/src/ui/confirm/Confirm.tsx @@ -52,7 +52,7 @@ export const Confirm = ({ }} style={{ marginRight: '24px' }} > - {cancelText} + {cancelText === 'Cancel' ? t('Cancel') : cancelText}
    - {workspaceList.map((item, index) => { + {workspaceMetaList.map((item, index) => { return ( { @@ -165,7 +155,6 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { open={createWorkspaceOpen} onClose={({ workspaceId }) => { setCreateWorkspaceOpen(false); - setList(); onClose(); confirm({ title: 'Enable AFFiNE Cloud?', @@ -182,7 +171,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { }); }, 1000); } else { - confirm && Login(); + confirm && login(); } }); }} diff --git a/packages/app/src/components/workspace-setting/MembersPage.tsx b/packages/app/src/components/workspace-setting/MembersPage.tsx index 7695a43b0c..b69c89b6f1 100644 --- a/packages/app/src/components/workspace-setting/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/MembersPage.tsx @@ -15,24 +15,21 @@ import { MoreVerticalIcon, EmailIcon, TrashIcon } from '@blocksuite/icons'; import { useEffect, useState } from 'react'; import { Button, IconButton } from '@/ui/button'; import { InviteMembers } from '../invite-members/index'; -// import { Member, getDataCenter } from '@affine/datacenter'; -// import { Avatar } from '@mui/material'; import { Menu, MenuItem } from '@/ui/menu'; import { Empty } from '@/ui/empty'; import { deleteMember, getMembers, - getUserInfo, - Login, User, Workspace, } from '@/hooks/mock-data/mock'; +import useTemporaryHelper from '@/hooks/use-temporary-helper'; // import { useAppState } from '@/providers/app-state-provider'; export const MembersPage = ({ workspace }: { workspace: Workspace }) => { const [isInviteModalShow, setIsInviteModalShow] = useState(false); const [members, setMembers] = useState([]); - const [userInfo, setUserInfo] = useState(); + const { user, login } = useTemporaryHelper(); // const refreshMembers = useCallback(() => { // getDataCenter() // .then(dc => @@ -49,15 +46,10 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { // }, [workspace.id]); useEffect(() => { - setUser(); setMembersList(); // refreshMembers(); }, []); - const setUser = () => { - const user = getUserInfo(); - user && setUserInfo(user); - }; const setMembersList = () => { const members = getMembers(workspace.id); members && setMembers(members); @@ -65,7 +57,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { return (
    - {userInfo ? ( + {user ? ( <> @@ -184,8 +176,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => {
    - + )}
    ); diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx index 0e8a9b5cf3..f09cb3e11c 100644 --- a/packages/app/src/components/workspace-setting/PublishPage.tsx +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -14,15 +14,15 @@ import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { useConfirm } from '@/providers/confirm-provider'; export const PublishPage = ({ workspace }: { workspace: Workspace }) => { + console.log('workspace: ', workspace); const shareUrl = window.location.host + '/workspace/' + workspace.id + '?share=true'; - const { login, updateWorkspaceMeta, user, currentWorkspace } = - useTemporaryHelper(); + const { login, updateWorkspaceMeta, user } = useTemporaryHelper(); const { confirm } = useConfirm(); const togglePublic = (flag: boolean) => { - updateWorkspaceMeta(currentWorkspace.id, { isPublish: flag }); + updateWorkspaceMeta(workspace.id, { isPublish: flag }); }; const copyUrl = () => { @@ -37,20 +37,22 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => { confirmText: user ? 'Enable' : 'Sign in and Enable', cancelText: 'Skip', }).then(confirm => { - if (user) { - updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); - } else { - confirm && login(); - updateWorkspaceMeta(currentWorkspace.id, { isPublish: true }); + if (confirm) { + if (user) { + updateWorkspaceMeta(workspace.id, { isPublish: true }); + } else { + login(); + updateWorkspaceMeta(workspace.id, { isPublish: true }); + } } }); }; return ( <> - {currentWorkspace.type === 'cloud' ? ( + {workspace.type === 'cloud' ? (
    - {currentWorkspace?.isPublish ? ( + {workspace?.isPublish ? ( <> Publishing to web requires AFFiNE Cloud service . @@ -74,7 +76,7 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => { )} - {!currentWorkspace?.isPublish ? ( + {!workspace.isPublish ? ( - ) : ( + {workspace.isPublish ? ( + ) : ( + )}
    ) : ( diff --git a/packages/app/src/components/workspace-setting/style.ts b/packages/app/src/components/workspace-setting/style.ts index af2e03def1..7b4e645526 100644 --- a/packages/app/src/components/workspace-setting/style.ts +++ b/packages/app/src/components/workspace-setting/style.ts @@ -215,8 +215,7 @@ export const StyledPublishCopyContainer = styled('div')(() => { display: 'flex', flexDirection: 'row', alignItems: 'center', - - height: '38px', + marginBottom: '20px', paddingTop: '20px', }; }); diff --git a/packages/app/src/providers/temporary-helper-provider.tsx b/packages/app/src/providers/temporary-helper-provider.tsx index fa80a8a435..c0a4e939a0 100644 --- a/packages/app/src/providers/temporary-helper-provider.tsx +++ b/packages/app/src/providers/temporary-helper-provider.tsx @@ -156,7 +156,6 @@ export const TemporaryHelperProvider = ({ setWorkspaceMetaList(workspacesMeta); }, setActiveWorkspace(workspaceData) { - console.log('workspaceData: ', workspaceData); localStorage.setItem( 'affine-active-workspace', JSON.stringify(workspaceData) From d75e5fff926158831c6db18d9b67fca9b64b4b0c Mon Sep 17 00:00:00 2001 From: alt0 Date: Sun, 8 Jan 2023 19:14:21 +0800 Subject: [PATCH 053/298] fix: module path --- packages/data-center/src/datacenter.ts | 2 +- packages/data-center/src/provider/affine/affine.ts | 2 +- packages/data-center/src/provider/affine/apis/business.ts | 4 ++-- packages/data-center/src/provider/base.ts | 4 ++-- packages/data-center/src/provider/local/local.ts | 4 ++-- packages/data-center/src/workspaces/workspaces.ts | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index bec4794df4..bce67be90f 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -3,7 +3,7 @@ import { Workspace } from '@blocksuite/store'; import { BaseProvider } from './provider/base'; import { LocalProvider } from './provider/local/local'; import { AffineProvider } from './provider'; -import type { Workspace as WS, WorkspaceMeta } from 'src/types'; +import type { Workspace as WS, WorkspaceMeta } from './types'; import assert from 'assert'; import { getLogger } from './logger'; import { BlockSchema } from '@blocksuite/blocks/models'; diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index ae986cdb7c..25516386d0 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -21,7 +21,7 @@ import assert from 'assert'; import { getAuthorizer } from './apis/token'; import { WebsocketProvider } from './sync'; import { IndexedDBProvider } from '../indexeddb'; -import { getDefaultHeadImgBlob } from 'src/utils'; +import { getDefaultHeadImgBlob } from '../../utils'; export class AffineProvider extends BaseProvider { public id = 'affine'; diff --git a/packages/data-center/src/provider/affine/apis/business.ts b/packages/data-center/src/provider/affine/apis/business.ts index a43cac2418..11a4720851 100644 --- a/packages/data-center/src/provider/affine/apis/business.ts +++ b/packages/data-center/src/provider/affine/apis/business.ts @@ -1,6 +1,6 @@ import { uuidv4 } from '@blocksuite/store'; -import { getDataCenter } from 'src'; -import { DataCenter } from 'src/datacenter'; +// import { getDataCenter } from '.'; +// import { DataCenter } from './datacenter'; // import { Workspace } from '../types'; // export class Business { diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 77cd9fdd3f..d1568dbbc6 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -1,6 +1,6 @@ import { BlobStorage, Workspace } from '@blocksuite/store'; -import { Logger, User, Workspace as WS, WorkspaceMeta } from 'src/types'; -import { Workspaces } from 'src/workspaces'; +import { Logger, User, Workspace as WS, WorkspaceMeta } from '../types'; +import { Workspaces } from '../workspaces'; export class BaseProvider { public readonly id: string = 'base'; diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 1acc6db7dd..c741b9da06 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -1,10 +1,10 @@ import { BaseProvider } from '../base'; import { varStorage as storage } from 'lib0/storage'; -import { Workspace as WS, WorkspaceMeta } from 'src/types'; +import { Workspace as WS, WorkspaceMeta } from '../../types'; import { Workspace } from '@blocksuite/store'; import { IndexedDBProvider } from '../indexeddb'; import assert from 'assert'; -import { getDefaultHeadImgBlob } from 'src/utils'; +import { getDefaultHeadImgBlob } from '../../utils'; const WORKSPACE_KEY = 'workspaces'; diff --git a/packages/data-center/src/workspaces/workspaces.ts b/packages/data-center/src/workspaces/workspaces.ts index 4dc704e8b7..f813f6b16d 100644 --- a/packages/data-center/src/workspaces/workspaces.ts +++ b/packages/data-center/src/workspaces/workspaces.ts @@ -1,8 +1,8 @@ -import { Workspace as WS } from 'src/types'; +import { Workspace as WS } from '../types'; import { Observable } from 'lib0/observable'; import { uuidv4 } from '@blocksuite/store'; -import { DataCenter } from 'src/datacenter'; +import { DataCenter } from '../datacenter'; export class Workspaces extends Observable { private _workspaces: WS[]; From e0d31659d9a9039ccfc9fab99ab0bbc78b2db123 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Sun, 8 Jan 2023 19:15:25 +0800 Subject: [PATCH 054/298] fix: hooks error --- packages/app/src/providers/temporary-helper-provider.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/app/src/providers/temporary-helper-provider.tsx b/packages/app/src/providers/temporary-helper-provider.tsx index c0a4e939a0..5731646a15 100644 --- a/packages/app/src/providers/temporary-helper-provider.tsx +++ b/packages/app/src/providers/temporary-helper-provider.tsx @@ -84,13 +84,8 @@ export const TemporaryHelperProvider = ({ const newWorkspacesMeta = workspacesMeta.map( (workspace: Workspace) => { if (workspace.id === workspaceId) { - workspaceData.name && (workspace.name = workspaceData.name); - workspaceData.avatar && - (workspace.avatar = workspaceData.avatar); - workspaceData.type && (workspace.type = workspaceData.type); - workspaceData.isPublish && - (workspace.isPublish = workspaceData.isPublish); - return workspace; + const workspaceObj = Object.assign(workspace, workspaceData); + return workspaceObj; } return workspace; } From 231615b134b3d00ed7021d2881f1ad548f216efd Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Sun, 8 Jan 2023 19:25:12 +0800 Subject: [PATCH 055/298] fix: lint error --- .../components/workspace-setting/MembersPage.tsx | 2 +- packages/app/src/ui/input/Input.tsx | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/app/src/components/workspace-setting/MembersPage.tsx b/packages/app/src/components/workspace-setting/MembersPage.tsx index 61fb80c75e..8b5210653b 100644 --- a/packages/app/src/components/workspace-setting/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/MembersPage.tsx @@ -54,7 +54,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { useEffect(() => { setMembersList(); // refreshMembers(); - }, [setMembersList]); + }); return (
    diff --git a/packages/app/src/ui/input/Input.tsx b/packages/app/src/ui/input/Input.tsx index 718eb70034..c4fe7600ca 100644 --- a/packages/app/src/ui/input/Input.tsx +++ b/packages/app/src/ui/input/Input.tsx @@ -1,4 +1,10 @@ -import { InputHTMLAttributes, useEffect, useState } from 'react'; +import { + InputHTMLAttributes, + useEffect, + useState, + FocusEventHandler, + KeyboardEventHandler, +} from 'react'; import { StyledInput } from './style'; type inputProps = { @@ -9,9 +15,8 @@ type inputProps = { maxLength?: number; minLength?: number; onChange?: (value: string) => void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onBlur?: (e: any) => void; - onKeyDown?: (e: any) => void; + onBlur?: FocusEventHandler; + onKeyDown?: KeyboardEventHandler; }; export const Input = (props: inputProps) => { From 090890a94d27248bec71ec0a264e3c31ba210657 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Sun, 8 Jan 2023 19:37:15 +0800 Subject: [PATCH 056/298] fix: build lint error --- packages/app/src/components/create-workspace/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/app/src/components/create-workspace/index.tsx b/packages/app/src/components/create-workspace/index.tsx index 8f8ce49d1c..d2decdfe4e 100644 --- a/packages/app/src/components/create-workspace/index.tsx +++ b/packages/app/src/components/create-workspace/index.tsx @@ -4,6 +4,7 @@ import { Button } from '@/ui/button'; import { useState } from 'react'; import Input from '@/ui/input'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; +import { KeyboardEvent } from 'react'; interface ICloseParams { workspaceId?: string; } @@ -20,7 +21,7 @@ export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { onClose({ workspaceId: workspace.id }); setActiveWorkspace(workspace); }; - const handleKeyDown = (event: KeyboardEvent) => { + const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Enter') { // 👇 Get input value handleCreateWorkspace(); From 055b63382b2ce911565cc0f2fad063e6c5c3d416 Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 00:41:29 +0800 Subject: [PATCH 057/298] refactor: workspace crud --- packages/data-center/src/datacenter.ts | 105 +++++----- .../data-center/src/provider/affine/affine.ts | 35 +++- packages/data-center/src/provider/base.ts | 12 +- .../data-center/src/provider/local/local.ts | 52 +++-- packages/data-center/src/workspaces/index.ts | 1 + .../data-center/src/workspaces/workspaces.ts | 196 ++++++++++-------- .../src/workspaces/workspaces.ts.bak | 101 +++++++++ 7 files changed, 335 insertions(+), 167 deletions(-) create mode 100644 packages/data-center/src/workspaces/workspaces.ts.bak diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index bce67be90f..7db16c1ca0 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -1,4 +1,5 @@ import { Workspaces } from './workspaces'; +import type { WorkspacesChangeEvent } from './workspaces'; import { Workspace } from '@blocksuite/store'; import { BaseProvider } from './provider/base'; import { LocalProvider } from './provider/local/local'; @@ -14,9 +15,10 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; * @classdesc DataCenter is a data center, it can manage different providers for business */ export class DataCenter { - private readonly workspaces = new Workspaces(this); + private readonly _workspaces = new Workspaces(); private currentWorkspace: Workspace | null = null; private readonly _logger = getLogger('dc'); + private _defaultProvider?: BaseProvider; providerMap: Map = new Map(); constructor(debug: boolean) { @@ -28,32 +30,43 @@ export class DataCenter { // TODO: switch different provider dc.registerProvider(new LocalProvider()); dc.registerProvider(new AffineProvider()); - dc.workspaces.init(); return dc; } + /** + * Register provider. + * We will automatically set the first provider to default provider. + */ registerProvider(provider: BaseProvider) { + if (!this._defaultProvider) { + this._defaultProvider = provider; + } // inject data in provider - provider.inject({ logger: this._logger, workspaces: this.workspaces }); + provider.inject({ + logger: this._logger, + workspaces: this._workspaces.createScope(), + }); provider.init(); this.providerMap.set(provider.id, provider); } + setDefaultProvider(providerId: string) { + this._defaultProvider = this.providerMap.get(providerId); + } + get providers() { return Array.from(this.providerMap.values()); } - /** - * get workspaces list if focusUpdate is true, it will refresh workspaces - * @param {string} name workspace name - * @returns {Promise} - */ - public async getWorkspaces(focusUpdate = false) { - if (focusUpdate) { - this.workspaces.refreshWorkspaces(); - } - return this.workspaces.workspaces; + public get workspaces() { + return this._workspaces.workspaces; + } + + public async refreshWorkspaces() { + return Promise.allSettled( + Object.values(this.providerMap).map(provider => provider.loadWorkspaces()) + ); } /** @@ -61,11 +74,16 @@ export class DataCenter { * @param {string} name workspace name * @returns {Promise} */ - public async createWorkspace(name: string) { - const workspaceInfo = this.workspaces.addLocalWorkspace(name); - // IMP: create workspace in local provider - this.providerMap.get('local')?.createWorkspace({ name }); - return workspaceInfo; + public async createWorkspace(workspaceMeta: WorkspaceMeta) { + assert( + this._defaultProvider, + 'There is no provider. You should add provider first.' + ); + + const workspace = await this._defaultProvider.createWorkspace( + workspaceMeta + ); + return workspace; } /** @@ -73,14 +91,11 @@ export class DataCenter { * @param {string} workspaceId workspace id */ public async deleteWorkspace(workspaceId: string) { - const workspaceInfo = this.workspaces.getWorkspace(workspaceId); + const workspaceInfo = this._workspaces.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); - if (provider && this.workspaces.hasWorkspace(workspaceId)) { - await provider.delete(workspaceId); - // may be refresh all workspaces - this.workspaces.delete(workspaceId); - } + assert(provider, `Workspace exists, but we couldn't find its provider.`); + await provider.deleteWorkspace(workspaceId); } /** @@ -119,11 +134,11 @@ export class DataCenter { * @returns {Promise} */ public async loadWorkspace(workspaceId: string) { - const workspaceInfo = this.workspaces.getWorkspace(workspaceId); + const workspaceInfo = this._workspaces.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const currentProvider = this.providerMap.get(workspaceInfo.provider); if (currentProvider) { - currentProvider.close(workspaceId); + currentProvider.closeWorkspace(workspaceId); } const provider = this.providerMap.get(workspaceInfo.provider); assert(provider, `provide '${workspaceInfo.provider}' is not registered`); @@ -149,8 +164,10 @@ export class DataCenter { * listen workspaces list change * @param {Function} callback callback function */ - public async onWorkspacesChange(callback: (workspaces: WS[]) => void) { - this.workspaces.onWorkspacesChange(callback); + public async onWorkspacesChange( + callback: (workspaces: WorkspacesChangeEvent) => void + ) { + this._workspaces.on('change', callback); } /** @@ -166,20 +183,18 @@ export class DataCenter { assert(w?.room, 'No workspace to set meta'); const update: Partial = {}; if (name) { - w.doc.meta.setName(name); + w.meta.setName(name); update.name = name; } if (avatar) { - w.doc.meta.setAvatar(avatar); + w.meta.setAvatar(avatar); update.avatar = avatar; } // may run for change workspace meta - const workspaceInfo = this.workspaces.getWorkspace(w.room); + const workspaceInfo = this._workspaces.find(w.room); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); provider?.updateWorkspaceMeta(w.room, update); - // update workspace list directly - this.workspaces.updateWorkspaceInfo(w.room, update); } /** @@ -188,27 +203,26 @@ export class DataCenter { * @param id workspace id */ public async leaveWorkspace(workspaceId: string) { - const workspaceInfo = this.workspaces.getWorkspace(workspaceId); + const workspaceInfo = this._workspaces.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { - await provider.close(workspaceId); - await provider.leave(workspaceId); + await provider.closeWorkspace(workspaceId); + await provider.leaveWorkspace(workspaceId); } } public async setWorkspacePublish(workspaceId: string, isPublish: boolean) { - const workspaceInfo = this.workspaces.getWorkspace(workspaceId); + const workspaceInfo = this._workspaces.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { await provider.publish(workspaceId, isPublish); - this.workspaces.updateWorkspaceInfo(workspaceId, { isPublish }); } } public async inviteMember(id: string, email: string) { - const workspaceInfo = this.workspaces.getWorkspace(id); + const workspaceInfo = this._workspaces.find(id); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -221,7 +235,7 @@ export class DataCenter { * @param {number} permissionId permission id */ public async removeMember(workspaceId: string, permissionId: number) { - const workspaceInfo = this.workspaces.getWorkspace(workspaceId); + const workspaceInfo = this._workspaces.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -235,13 +249,11 @@ export class DataCenter { */ public async closeCurrentWorkspace() { assert(this.currentWorkspace?.room, 'No workspace to close'); - const currentWorkspace = this.workspaces.getWorkspace( - this.currentWorkspace.room - ); + const currentWorkspace = this._workspaces.find(this.currentWorkspace.room); assert(currentWorkspace, 'Workspace not found'); const provider = this.providerMap.get(currentWorkspace.provider); assert(provider, 'Provider not found'); - await provider.close(currentWorkspace.id); + await provider.closeWorkspace(currentWorkspace.id); } private async _transWorkspaceProvider( @@ -249,7 +261,7 @@ export class DataCenter { providerId: string ) { assert(workspace.room, 'No workspace id'); - const workspaceInfo = this.workspaces.getWorkspace(workspace.room); + const workspaceInfo = this._workspaces.find(workspace.room); assert(workspaceInfo, 'Workspace not found'); if (workspaceInfo.provider === providerId) { this._logger('Workspace provider is same'); @@ -270,8 +282,7 @@ export class DataCenter { ); applyUpdate(newWorkspace.doc, encodeStateAsUpdate(workspace.doc)); assert(newWorkspace, 'Create workspace failed'); - await currentProvider.delete(workspace.room); - this.workspaces.refreshWorkspaces(); + await currentProvider.deleteWorkspace(workspace.room); } /** diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 25516386d0..1651cba12d 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -119,9 +119,8 @@ export class AffineProvider extends BaseProvider { return Promise.resolve(null); } }); - await ( - await Promise.all(workspaceInstances) - ).forEach((workspace, i) => { + + (await Promise.all(workspaceInstances)).forEach((workspace, i) => { if (workspace) { workspaces[i] = { ...workspaces[i], @@ -159,6 +158,11 @@ export class AffineProvider extends BaseProvider { } } }); + + workspaces.forEach(workspace => { + this._workspaces.add(workspace); + }); + return workspaces; } @@ -185,17 +189,19 @@ export class AffineProvider extends BaseProvider { return this._user; } - public override async delete(id: string): Promise { - await this.close(id); + public override async deleteWorkspace(id: string): Promise { + await this.closeWorkspace(id); IndexedDBProvider.delete(id); await deleteWorkspace({ id }); + this._workspaces.remove(id); } public override async clear(): Promise { for (const w of this._workspacesCache.values()) { if (w.room) { try { - await this.delete(w.room); + await this.deleteWorkspace(w.room); + this._workspaces.remove(w.room); } catch (e) { this._logger('has a problem of delete workspace ', e); } @@ -204,14 +210,14 @@ export class AffineProvider extends BaseProvider { this._workspacesCache.clear(); } - public override async close(id: string) { + public override async closeWorkspace(id: string) { const idb = this._idbMap.get(id); idb?.destroy(); const ws = this._wsMap.get(id); ws?.disconnect(); } - public override async leave(id: string): Promise { + public override async leaveWorkspace(id: string): Promise { await leaveWorkspace({ id }); } @@ -251,6 +257,19 @@ export class AffineProvider extends BaseProvider { nw.meta.setName(meta.name); nw.meta.setAvatar(meta.avatar); this._initWorkspaceDb(nw); + + const workspaceInfo: WS = { + name: meta.name, + id, + isPublish: false, + avatar: '', + owner: undefined, + isLocal: true, + memberCount: 1, + provider: 'local', + }; + + this._workspaces.add(workspaceInfo); return nw; } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index d1568dbbc6..dbf24df431 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -1,10 +1,10 @@ import { BlobStorage, Workspace } from '@blocksuite/store'; import { Logger, User, Workspace as WS, WorkspaceMeta } from '../types'; -import { Workspaces } from '../workspaces'; +import type { WorkspacesScope } from '../workspaces'; export class BaseProvider { public readonly id: string = 'base'; - protected _workspaces!: Workspaces; + protected _workspaces!: WorkspacesScope; protected _logger!: Logger; protected _blobs!: BlobStorage; @@ -13,7 +13,7 @@ export class BaseProvider { workspaces, }: { logger: Logger; - workspaces: Workspaces; + workspaces: WorkspacesScope; }) { this._logger = logger; this._workspaces = workspaces; @@ -83,7 +83,7 @@ export class BaseProvider { * delete workspace include all data * @param id workspace id */ - public async delete(id: string): Promise { + public async deleteWorkspace(id: string): Promise { id; return; } @@ -92,7 +92,7 @@ export class BaseProvider { * leave workspace by workspace id * @param id workspace id */ - public async leave(id: string): Promise { + public async leaveWorkspace(id: string): Promise { id; return; } @@ -101,7 +101,7 @@ export class BaseProvider { * close db link and websocket connection and other resources * @param id workspace id */ - public async close(id: string) { + public async closeWorkspace(id: string) { id; return; } diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index c741b9da06..0a383a05bd 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -1,7 +1,7 @@ import { BaseProvider } from '../base'; import { varStorage as storage } from 'lib0/storage'; import { Workspace as WS, WorkspaceMeta } from '../../types'; -import { Workspace } from '@blocksuite/store'; +import { Workspace, uuidv4 } from '@blocksuite/store'; import { IndexedDBProvider } from '../indexeddb'; import assert from 'assert'; import { getDefaultHeadImgBlob } from '../../utils'; @@ -11,11 +11,10 @@ const WORKSPACE_KEY = 'workspaces'; export class LocalProvider extends BaseProvider { public id = 'local'; private _idbMap: Map = new Map(); - private _workspacesList: WS[] = []; constructor() { super(); - this._workspacesList = []; + this.loadWorkspaces(); } private _storeWorkspaces(workspaces: WS[]) { @@ -46,6 +45,9 @@ export class LocalProvider extends BaseProvider { if (workspaceStr) { try { workspaces = JSON.parse(workspaceStr) as WS[]; + workspaces.forEach(workspace => { + this._workspaces.add(workspace); + }); } catch (error) { this._logger(`Failed to parse workspaces from storage`); } @@ -53,12 +55,12 @@ export class LocalProvider extends BaseProvider { return Promise.resolve(workspaces); } - public override async delete(id: string): Promise { - const index = this._workspacesList.findIndex(ws => ws.id === id); - if (index !== -1) { + public override async deleteWorkspace(id: string): Promise { + const workspace = this._workspaces.get(id); + if (workspace) { IndexedDBProvider.delete(id); - this._workspacesList.splice(index, 1); - this._storeWorkspaces(this._workspacesList); + this._workspaces.remove(id); + this._storeWorkspaces(this._workspaces.list()); } else { this._logger(`Failed to delete workspace ${id}`); } @@ -68,15 +70,8 @@ export class LocalProvider extends BaseProvider { id: string, meta: Partial ) { - const index = this._workspacesList.findIndex(ws => ws.id === id); - if (index !== -1) { - const workspace = this._workspacesList[index]; - meta.name && (workspace.name = meta.name); - meta.avatar && (workspace.avatar = meta.avatar); - this._storeWorkspaces(this._workspacesList); - } else { - this._logger(`Failed to update workspace ${id}`); - } + this._workspaces.update(id, meta); + this._storeWorkspaces(this._workspaces.list()); } public override async createWorkspace( @@ -88,13 +83,27 @@ export class LocalProvider extends BaseProvider { const blob = await getDefaultHeadImgBlob(meta.name); meta.avatar = (await this.setBlob(blob)) || ''; } - const workspaceInfos = this._workspaces.addLocalWorkspace(meta.name); this._logger('Creating affine workspace'); - const workspace = new Workspace({ room: workspaceInfos.id }); + + const workspaceInfo: WS = { + name: meta.name, + id: uuidv4(), + isPublish: false, + avatar: '', + owner: undefined, + isLocal: true, + memberCount: 1, + provider: 'local', + }; + + const workspace = new Workspace({ room: workspaceInfo.id }); + this._initWorkspaceDb(workspace); workspace.meta.setName(meta.name); workspace.meta.setAvatar(meta.avatar); - this._storeWorkspaces([...this._workspacesList, workspaceInfos]); - this._initWorkspaceDb(workspace); + + this._workspaces.add(workspaceInfo); + this._storeWorkspaces(this._workspaces.list()); + return workspace; } @@ -102,5 +111,6 @@ export class LocalProvider extends BaseProvider { const workspaces = await this.loadWorkspaces(); workspaces.forEach(ws => IndexedDBProvider.delete(ws.id)); this._storeWorkspaces([]); + this._workspaces.clear(); } } diff --git a/packages/data-center/src/workspaces/index.ts b/packages/data-center/src/workspaces/index.ts index 05a26f8e2b..41419a6eb4 100644 --- a/packages/data-center/src/workspaces/index.ts +++ b/packages/data-center/src/workspaces/index.ts @@ -1 +1,2 @@ export { Workspaces } from './workspaces'; +export type { WorkspacesScope, WorkspacesChangeEvent } from './workspaces'; diff --git a/packages/data-center/src/workspaces/workspaces.ts b/packages/data-center/src/workspaces/workspaces.ts index f813f6b16d..2d8661b2bb 100644 --- a/packages/data-center/src/workspaces/workspaces.ts +++ b/packages/data-center/src/workspaces/workspaces.ts @@ -1,101 +1,127 @@ -import { Workspace as WS } from '../types'; - import { Observable } from 'lib0/observable'; -import { uuidv4 } from '@blocksuite/store'; -import { DataCenter } from '../datacenter'; +import type { Workspace, WorkspaceMeta } from '../types'; -export class Workspaces extends Observable { - private _workspaces: WS[]; - private readonly _dc: DataCenter; +export interface WorkspacesScope { + get: (workspaceId: string) => Workspace | undefined; + list: () => Workspace[]; + add: (workspace: Workspace) => void; + remove: (workspaceId: string) => boolean; + clear: () => void; + update: (workspaceId: string, workspaceMeta: Partial) => void; +} - constructor(dc: DataCenter) { - super(); - this._workspaces = []; - this._dc = dc; +export interface WorkspacesChangeEvent { + added?: Workspace; + deleted?: Workspace; + updated?: Workspace; +} + +export class Workspaces extends Observable<'change'> { + private _workspacesMap = new Map(); + + get workspaces(): Workspace[] { + return Object.values(this._workspacesMap); } - public init() { - this._loadWorkspaces(); + find(workspaceId: string) { + return this._workspacesMap.get(workspaceId); } - get workspaces() { - return this._workspaces; - } + createScope(): WorkspacesScope { + const scopedWorkspaceIds = new Set(); - /** - * emit when workspaces changed - * @param {(workspace: WS[]) => void} cb - */ - onWorkspacesChange(cb: (workspace: WS[]) => void) { - this.on('change', cb); - } + const get = (workspaceId: string) => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return; + } + return this._workspacesMap.get(workspaceId); + }; - private async _loadWorkspaces() { - const providers = this._dc.providers; - let workspaces: WS[] = []; - providers.forEach(async p => { - const pWorkspaces = await p.loadWorkspaces(); - workspaces = [...workspaces, ...pWorkspaces]; - this._updateWorkspaces([...workspaces, ...pWorkspaces]); - }); - } + const add = (workspace: Workspace) => { + if (this._workspacesMap.has(workspace.id)) { + throw new Error(`Duplicate workspace id.`); + } + this._workspacesMap.set(workspace.id, workspace); + scopedWorkspaceIds.add(workspace.id); - /** - * focus load all workspaces list - */ - public async refreshWorkspaces() { - this._loadWorkspaces(); - } + this.emit('change', [ + { + added: workspace, + } as WorkspacesChangeEvent, + ]); + }; - private _updateWorkspaces(workspaces: WS[]) { - this._workspaces = workspaces; - this.emit('change', this._workspaces); - } + const remove = (workspaceId: string) => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return true; + } + + const workspace = this._workspacesMap.get(workspaceId); + if (workspace) { + const ret = this._workspacesMap.delete(workspaceId); + // If deletion failed, return. + if (!ret) { + return ret; + } + + scopedWorkspaceIds.delete(workspaceId); + + this.emit('change', [ + { + deleted: workspace, + } as WorkspacesChangeEvent, + ]); + } + return true; + }; + + const clear = () => { + scopedWorkspaceIds.forEach(id => { + remove(id); + }); + }; + + const update = ( + workspaceId: string, + workspaceMeta: Partial + ) => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return true; + } + + const workspace = this._workspacesMap.get(workspaceId); + if (!workspace) { + return true; + } + + this._workspacesMap.set(workspaceId, { ...workspace, ...workspaceMeta }); + + this.emit('change', [ + { + updated: this._workspacesMap.get(workspaceId), + } as WorkspacesChangeEvent, + ]); + }; + + // TODO: need to optimize + const list = () => { + const workspaces: Workspace[] = []; + scopedWorkspaceIds.forEach(id => { + const workspace = this._workspacesMap.get(id); + if (workspace) { + workspaces.push(workspace); + } + }); + return workspaces; + }; - private _getDefaultWorkspace(name: string): WS { return { - name, - id: uuidv4(), - isPublish: false, - avatar: '', - owner: undefined, - isLocal: true, - memberCount: 1, - provider: 'local', + get, + list, + add, + remove, + clear, + update, }; } - - /** add a local workspaces */ - public addLocalWorkspace(name: string) { - const workspace = this._getDefaultWorkspace(name); - this._updateWorkspaces([...this._workspaces, workspace]); - return workspace; - } - - /** delete a workspaces by id */ - public delete(id: string) { - const index = this._workspaces.findIndex(w => w.id === id); - if (index >= 0) { - this._workspaces.splice(index, 1); - this._updateWorkspaces(this._workspaces); - } - } - - /** get workspace info by id */ - public getWorkspace(id: string) { - return this._workspaces.find(w => w.id === id); - } - - /** check if workspace exists */ - public hasWorkspace(id: string) { - return this._workspaces.some(w => w.id === id); - } - - public updateWorkspaceInfo(id: string, info: Partial) { - const index = this._workspaces.findIndex(w => w.id === id); - if (index >= 0) { - this._workspaces[index] = { ...this._workspaces[index], ...info }; - this._updateWorkspaces(this._workspaces); - } - } } diff --git a/packages/data-center/src/workspaces/workspaces.ts.bak b/packages/data-center/src/workspaces/workspaces.ts.bak new file mode 100644 index 0000000000..f813f6b16d --- /dev/null +++ b/packages/data-center/src/workspaces/workspaces.ts.bak @@ -0,0 +1,101 @@ +import { Workspace as WS } from '../types'; + +import { Observable } from 'lib0/observable'; +import { uuidv4 } from '@blocksuite/store'; +import { DataCenter } from '../datacenter'; + +export class Workspaces extends Observable { + private _workspaces: WS[]; + private readonly _dc: DataCenter; + + constructor(dc: DataCenter) { + super(); + this._workspaces = []; + this._dc = dc; + } + + public init() { + this._loadWorkspaces(); + } + + get workspaces() { + return this._workspaces; + } + + /** + * emit when workspaces changed + * @param {(workspace: WS[]) => void} cb + */ + onWorkspacesChange(cb: (workspace: WS[]) => void) { + this.on('change', cb); + } + + private async _loadWorkspaces() { + const providers = this._dc.providers; + let workspaces: WS[] = []; + providers.forEach(async p => { + const pWorkspaces = await p.loadWorkspaces(); + workspaces = [...workspaces, ...pWorkspaces]; + this._updateWorkspaces([...workspaces, ...pWorkspaces]); + }); + } + + /** + * focus load all workspaces list + */ + public async refreshWorkspaces() { + this._loadWorkspaces(); + } + + private _updateWorkspaces(workspaces: WS[]) { + this._workspaces = workspaces; + this.emit('change', this._workspaces); + } + + private _getDefaultWorkspace(name: string): WS { + return { + name, + id: uuidv4(), + isPublish: false, + avatar: '', + owner: undefined, + isLocal: true, + memberCount: 1, + provider: 'local', + }; + } + + /** add a local workspaces */ + public addLocalWorkspace(name: string) { + const workspace = this._getDefaultWorkspace(name); + this._updateWorkspaces([...this._workspaces, workspace]); + return workspace; + } + + /** delete a workspaces by id */ + public delete(id: string) { + const index = this._workspaces.findIndex(w => w.id === id); + if (index >= 0) { + this._workspaces.splice(index, 1); + this._updateWorkspaces(this._workspaces); + } + } + + /** get workspace info by id */ + public getWorkspace(id: string) { + return this._workspaces.find(w => w.id === id); + } + + /** check if workspace exists */ + public hasWorkspace(id: string) { + return this._workspaces.some(w => w.id === id); + } + + public updateWorkspaceInfo(id: string, info: Partial) { + const index = this._workspaces.findIndex(w => w.id === id); + if (index >= 0) { + this._workspaces[index] = { ...this._workspaces[index], ...info }; + this._updateWorkspaces(this._workspaces); + } + } +} From e1e1d0c9647fe59dcf49d920773b27acb15d3a96 Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 00:48:54 +0800 Subject: [PATCH 058/298] test: add local provider test --- jest.config.js | 19 - package.json | 20 +- .../app/scripts/__tests__/printer.spec.ts | 2 +- .../src/utils/__tests__/get-is-mobile.spec.ts | 2 +- packages/data-center/src/datacenter.ts | 20 +- .../data-center/src/provider/affine/affine.ts | 5 +- packages/data-center/src/provider/base.ts | 19 +- .../src/provider/local/local.spec.ts | 49 + .../data-center/src/provider/local/local.ts | 5 +- packages/data-center/src/types/index.ts | 2 +- .../data-center/src/workspaces/workspaces.ts | 2 +- packages/data-center/tests/cloud/auth.spec.ts | 15 - .../tests/cloud/collaborate.spec.ts | 15 - .../tests/cloud/permission.spec.ts | 17 - .../data-center/tests/cloud/share.spec.ts | 15 - packages/data-center/tests/cloud/sync.spec.ts | 23 - .../tests/local/attachment.spec.ts | 13 - .../tests/local/import-export.spec.ts | 11 - packages/data-center/tests/local/init.spec.ts | 47 - .../data-center/tests/local/search.spec.ts | 23 - .../data-center/tests/local/workspace.spec.ts | 64 - packages/data-center/tests/utils.ts | 9 - pnpm-lock.yaml | 1667 +++++------------ vitest.config.ts | 7 + 24 files changed, 565 insertions(+), 1506 deletions(-) delete mode 100644 jest.config.js create mode 100644 packages/data-center/src/provider/local/local.spec.ts delete mode 100644 packages/data-center/tests/cloud/auth.spec.ts delete mode 100644 packages/data-center/tests/cloud/collaborate.spec.ts delete mode 100644 packages/data-center/tests/cloud/permission.spec.ts delete mode 100644 packages/data-center/tests/cloud/share.spec.ts delete mode 100644 packages/data-center/tests/cloud/sync.spec.ts delete mode 100644 packages/data-center/tests/local/attachment.spec.ts delete mode 100644 packages/data-center/tests/local/import-export.spec.ts delete mode 100644 packages/data-center/tests/local/init.spec.ts delete mode 100644 packages/data-center/tests/local/search.spec.ts delete mode 100644 packages/data-center/tests/local/workspace.spec.ts delete mode 100644 packages/data-center/tests/utils.ts create mode 100644 vitest.config.ts diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 4423f5ad0b..0000000000 --- a/jest.config.js +++ /dev/null @@ -1,19 +0,0 @@ -/** @type {import('ts-jest').JestConfigWithTsJest} */ -module.exports = { - projects: ['/packages/app'], - preset: 'ts-jest', - testEnvironment: 'node', - moduleNameMapper: { - '^(\\.{1,2}/.*)\\.js$': '$1', - }, - transform: { - // '^.+\\.[tj]sx?$' to process js/ts with `ts-jest` - // '^.+\\.m?[tj]sx?$' to process js/ts/mjs/mts with `ts-jest` - '^.+\\.tsx?$': [ - 'ts-jest', - { - useESM: true, - }, - ], - }, -}; diff --git a/package.json b/package.json index 9f4028cb70..624a14bee0 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "test": "playwright test", "test:dc": "pnpm --filter @affine/datacenter test", "test:e2e:codegen": "npx playwright codegen http://localhost:8080", - "test:unit": "jest", + "test:unit": "vitest run", + "test:unit:watch": "vitest", "postinstall": "husky install", "notify": "node --experimental-modules scripts/notify.mjs", "check:ci": "pnpm lint & pnpm test" @@ -24,24 +25,23 @@ "*.{ts,tsx,js,jsx}": "npx eslint --cache --fix" }, "devDependencies": { - "@jest/globals": "^29.3.1", + "@changesets/cli": "^2.26.0", "@playwright/test": "^1.29.1", - "@typescript-eslint/eslint-plugin": "^5.47.0", - "@typescript-eslint/parser": "^5.47.0", "@types/eslint": "^8.4.10", "@types/node": "^18.11.17", + "@typescript-eslint/eslint-plugin": "^5.47.0", + "@typescript-eslint/parser": "^5.47.0", "eslint": "^8.30.0", "eslint-config-next": "12.3.1", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.2.1", + "fake-indexeddb": "4.0.1", "got": "^12.5.3", - "jest": "^29.3.1", - "prettier": "^2.7.1", - "ts-jest": "^29.0.3", - "typescript": "^4.9.3", - "lint-staged": "^13.1.0", "husky": "^8.0.2", - "@changesets/cli": "^2.26.0" + "lint-staged": "^13.1.0", + "prettier": "^2.7.1", + "typescript": "^4.9.3", + "vitest": "^0.26.3" }, "eslintConfig": { "root": true, diff --git a/packages/app/scripts/__tests__/printer.spec.ts b/packages/app/scripts/__tests__/printer.spec.ts index beb14114e6..7f67223c1d 100644 --- a/packages/app/scripts/__tests__/printer.spec.ts +++ b/packages/app/scripts/__tests__/printer.spec.ts @@ -1,4 +1,4 @@ -import { describe, test, expect } from '@jest/globals'; +import { describe, test, expect } from 'vitest'; import { printer } from './../printer'; const chalk = require('chalk'); describe('printer', () => { diff --git a/packages/app/src/utils/__tests__/get-is-mobile.spec.ts b/packages/app/src/utils/__tests__/get-is-mobile.spec.ts index bef77b03ba..c5df2c6a63 100644 --- a/packages/app/src/utils/__tests__/get-is-mobile.spec.ts +++ b/packages/app/src/utils/__tests__/get-is-mobile.spec.ts @@ -1,4 +1,4 @@ -import { describe, test, expect } from '@jest/globals'; +import { describe, test, expect } from 'vitest'; import { isMobile } from '../get-is-mobile'; describe('get-is-mobile', () => { diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 7db16c1ca0..c859ad7d02 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -28,8 +28,18 @@ export class DataCenter { static async init(debug: boolean): Promise { const dc = new DataCenter(debug); // TODO: switch different provider - dc.registerProvider(new LocalProvider()); - dc.registerProvider(new AffineProvider()); + dc.registerProvider( + new LocalProvider({ + logger: dc._logger, + workspaces: dc._workspaces.createScope(), + }) + ); + dc.registerProvider( + new AffineProvider({ + logger: dc._logger, + workspaces: dc._workspaces.createScope(), + }) + ); return dc; } @@ -42,11 +52,7 @@ export class DataCenter { if (!this._defaultProvider) { this._defaultProvider = provider; } - // inject data in provider - provider.inject({ - logger: this._logger, - workspaces: this._workspaces.createScope(), - }); + provider.init(); this.providerMap.set(provider.id, provider); } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 1651cba12d..b9f168a328 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -11,6 +11,7 @@ import { updateWorkspace, } from './apis/workspace'; import { BaseProvider } from '../base'; +import type { ProviderConstructorParams } from '../base'; import { User, Workspace as WS, WorkspaceMeta } from '../../types'; import { Workspace } from '@blocksuite/store'; import { BlockSchema } from '@blocksuite/blocks/models'; @@ -32,8 +33,8 @@ export class AffineProvider extends BaseProvider { private _wsMap: Map = new Map(); private _idbMap: Map = new Map(); - constructor() { - super(); + constructor(params: ProviderConstructorParams) { + super(params); } override async init() { diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index dbf24df431..40572a136a 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -2,20 +2,23 @@ import { BlobStorage, Workspace } from '@blocksuite/store'; import { Logger, User, Workspace as WS, WorkspaceMeta } from '../types'; import type { WorkspacesScope } from '../workspaces'; +const defaultLogger = () => { + return; +}; + +export interface ProviderConstructorParams { + logger?: Logger; + workspaces: WorkspacesScope; +} + export class BaseProvider { public readonly id: string = 'base'; protected _workspaces!: WorkspacesScope; protected _logger!: Logger; protected _blobs!: BlobStorage; - public inject({ - logger, - workspaces, - }: { - logger: Logger; - workspaces: WorkspacesScope; - }) { - this._logger = logger; + public constructor({ logger, workspaces }: ProviderConstructorParams) { + this._logger = (logger || defaultLogger) as Logger; this._workspaces = workspaces; } diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts new file mode 100644 index 0000000000..442263c070 --- /dev/null +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -0,0 +1,49 @@ +import { describe, test, expect } from 'vitest'; +import { Workspaces } from '../../workspaces'; +import { LocalProvider } from './local'; +import 'fake-indexeddb/auto'; + +describe('local provider', () => { + const workspaces = new Workspaces(); + const provider = new LocalProvider({ + workspaces: workspaces.createScope(), + }); + + const workspaceName = 'workspace-test'; + let workspaceId: string | undefined; + + test('create workspace', async () => { + const w = await provider.createWorkspace({ + name: workspaceName, + avatar: 'avatar-url-test', + }); + workspaceId = w?.room; + + expect(workspaces.workspaces.length).toEqual(1); + expect(workspaces.workspaces[0].name).toEqual(workspaceName); + }); + + test('workspace list cache', async () => { + const workspaces1 = new Workspaces(); + const provider1 = new LocalProvider({ + workspaces: workspaces1.createScope(), + }); + await provider1.loadWorkspaces(); + expect(workspaces1.workspaces.length).toEqual(1); + expect(workspaces1.workspaces[0].name).toEqual(workspaceName); + expect(workspaces1.workspaces[0].id).toEqual(workspaceId); + }); + + test('update workspace', async () => { + await provider.updateWorkspaceMeta(workspaceId!, { + name: '1111', + }); + expect(workspaces.workspaces[0].name).toEqual('1111'); + }); + + test('delete workspace', async () => { + expect(workspaces.workspaces.length).toEqual(1); + await provider.deleteWorkspace(workspaces.workspaces[0].id); + expect(workspaces.workspaces.length).toEqual(0); + }); +}); diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 0a383a05bd..a01d516a35 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -1,4 +1,5 @@ import { BaseProvider } from '../base'; +import type { ProviderConstructorParams } from '../base'; import { varStorage as storage } from 'lib0/storage'; import { Workspace as WS, WorkspaceMeta } from '../../types'; import { Workspace, uuidv4 } from '@blocksuite/store'; @@ -12,8 +13,8 @@ export class LocalProvider extends BaseProvider { public id = 'local'; private _idbMap: Map = new Map(); - constructor() { - super(); + constructor(params: ProviderConstructorParams) { + super(params); this.loadWorkspaces(); } diff --git a/packages/data-center/src/types/index.ts b/packages/data-center/src/types/index.ts index c43fa2ed65..61bc12be81 100644 --- a/packages/data-center/src/types/index.ts +++ b/packages/data-center/src/types/index.ts @@ -1,4 +1,4 @@ -import { getLogger } from 'src'; +import { getLogger } from '../logger'; export type Workspace = { name: string; diff --git a/packages/data-center/src/workspaces/workspaces.ts b/packages/data-center/src/workspaces/workspaces.ts index 2d8661b2bb..90b1a5e9ea 100644 --- a/packages/data-center/src/workspaces/workspaces.ts +++ b/packages/data-center/src/workspaces/workspaces.ts @@ -20,7 +20,7 @@ export class Workspaces extends Observable<'change'> { private _workspacesMap = new Map(); get workspaces(): Workspace[] { - return Object.values(this._workspacesMap); + return Array.from(this._workspacesMap.values()); } find(workspaceId: string) { diff --git a/packages/data-center/tests/cloud/auth.spec.ts b/packages/data-center/tests/cloud/auth.spec.ts deleted file mode 100644 index f896dc99e6..0000000000 --- a/packages/data-center/tests/cloud/auth.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Auth', () => { - test('sign in', async () => {}); - - test('sign out', async () => {}); - - test('isLogin', async () => {}); - - test('getUserInfo', async () => {}); -}); diff --git a/packages/data-center/tests/cloud/collaborate.spec.ts b/packages/data-center/tests/cloud/collaborate.spec.ts deleted file mode 100644 index abe771109c..0000000000 --- a/packages/data-center/tests/cloud/collaborate.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Collaborate', () => { - test('collaborate editor content', async () => {}); - - test('collaborate workspace name', async () => {}); - - test('collaborate workspace avatar', async () => {}); - - test('collaborate workspace list', async () => {}); -}); diff --git a/packages/data-center/tests/cloud/permission.spec.ts b/packages/data-center/tests/cloud/permission.spec.ts deleted file mode 100644 index 69f40ad8f3..0000000000 --- a/packages/data-center/tests/cloud/permission.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Permission', () => { - test('get the public of workspace', async () => {}); - - test('make workspace public', async () => {}); - - test('make workspace private', async () => {}); - - test('un-login user open the public workspace ', async () => {}); - - test('un-login user open the private workspace ', async () => {}); -}); diff --git a/packages/data-center/tests/cloud/share.spec.ts b/packages/data-center/tests/cloud/share.spec.ts deleted file mode 100644 index 1698e29eab..0000000000 --- a/packages/data-center/tests/cloud/share.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Share', () => { - test('add(invite) member by email', async () => {}); - - test('accept invite member link', async () => {}); - - test('members list', async () => {}); - - test('delete member', async () => {}); -}); diff --git a/packages/data-center/tests/cloud/sync.spec.ts b/packages/data-center/tests/cloud/sync.spec.ts deleted file mode 100644 index f81cde5758..0000000000 --- a/packages/data-center/tests/cloud/sync.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Sync', () => { - test('get cloud the sync flag of workspace', async () => {}); - - test('enable [cloud sync feature]', async () => {}); - - test('close [cloud sync feature]', async () => {}); - - test('editor cloud storage', async () => {}); - - test('cloud sync is in-progress', async () => {}); - - test('cloud sync is completed', async () => {}); - - test('cloud sync is error', async () => {}); - - test('cloud storage is right', async () => {}); -}); diff --git a/packages/data-center/tests/local/attachment.spec.ts b/packages/data-center/tests/local/attachment.spec.ts deleted file mode 100644 index 3a017080b6..0000000000 --- a/packages/data-center/tests/local/attachment.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Attachment', () => { - test('upload blob', async () => {}); - - test('get blob', async () => {}); - - test('remove blob', async () => {}); -}); diff --git a/packages/data-center/tests/local/import-export.spec.ts b/packages/data-center/tests/local/import-export.spec.ts deleted file mode 100644 index 14d8a8a4f6..0000000000 --- a/packages/data-center/tests/local/import-export.spec.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Import/Export Workspace', () => { - test('import workspace', async () => {}); - - test('export workspace', async () => {}); -}); diff --git a/packages/data-center/tests/local/init.spec.ts b/packages/data-center/tests/local/init.spec.ts deleted file mode 100644 index c802bd64c0..0000000000 --- a/packages/data-center/tests/local/init.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Init Data Center', () => { - test('init', async () => { - // const dataCenter = await getDataCenter(); - // expect(dataCenter).toBeTruthy(); - // await dataCenter.clear(); - // const workspace = await dataCenter.load('test1'); - // expect(workspace).toBeTruthy(); - }); - - test('init singleton', async () => { - // // data center is singleton - // const [dc1, dc2] = await Promise.all([getDataCenter(), getDataCenter()]); - // expect(dc1).toEqual(dc2); - // // load same workspace will get same instance - // const [ws1, ws2] = await Promise.all([ - // dc1.load('test1'), - // dc2.load('test1'), - // ]); - // expect(ws1).toEqual(ws2); - }); - - test('should init error with unknown provider', async () => { - // const dc = await getDataCenter(); - // await dc.clear(); - // // load workspace with unknown provider will throw error - // test.fail(); - // await dc.load('test2', { providerId: 'not exist provider' }); - }); - - test.skip('init affine provider', async () => { - // const dataCenter = await getDataCenter(); - // await dataCenter.clear(); - // // load workspace with affine provider - // // TODO: set constant token for testing - // const workspace = await dataCenter.load('6', { - // providerId: 'affine', - // config: { token: 'YOUR_TOKEN' }, - // }); - // expect(workspace).toBeTruthy(); - }); -}); diff --git a/packages/data-center/tests/local/search.spec.ts b/packages/data-center/tests/local/search.spec.ts deleted file mode 100644 index 235d7ff36b..0000000000 --- a/packages/data-center/tests/local/search.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import assert from 'assert'; -import { test, expect } from '@playwright/test'; - -import { getDataCenter, waitOnce } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Search', () => { - test('search result', async () => { - // const dc = await getDataCenter(); - // const workspace = await dc.load('test'); - // assert(workspace); - // workspace.createPage('test'); - // await waitOnce(workspace.signals.pageAdded); - // const page = workspace.getPage('test'); - // assert(page); - // const text = new page.Text(page, 'hello world'); - // const blockId = page.addBlock({ flavour: 'affine:paragraph', text }); - // expect(workspace.search('hello')).toStrictEqual( - // new Map([[blockId, 'test']]) - // ); - }); -}); diff --git a/packages/data-center/tests/local/workspace.spec.ts b/packages/data-center/tests/local/workspace.spec.ts deleted file mode 100644 index c9d55398f2..0000000000 --- a/packages/data-center/tests/local/workspace.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { test, expect } from '@playwright/test'; - -import { getDataCenter } from '../utils.js'; - -import 'fake-indexeddb/auto'; - -test.describe('Workspace', () => { - test('create', async () => {}); - - test('load', async () => {}); - - test('get workspace name', async () => {}); - test('set workspace name', async () => {}); - - test('get workspace avatar', async () => {}); - test('set workspace avatar', async () => {}); - - test('list', async () => { - // const dataCenter = await getDataCenter(); - // await dataCenter.clear(); - // await Promise.all([ - // dataCenter.load('test3'), - // dataCenter.load('test4'), - // dataCenter.load('test5'), - // dataCenter.load('test6'), - // ]); - // expect(await dataCenter.list()).toStrictEqual({ - // test3: { local: true }, - // test4: { local: true }, - // test5: { local: true }, - // test6: { local: true }, - // }); - // await dataCenter.reload('test3', { providerId: 'affine' }); - // expect(await dataCenter.list()).toStrictEqual({ - // test3: { affine: true }, - // test4: { local: true }, - // test5: { local: true }, - // test6: { local: true }, - // }); - }); - - test('destroy', async () => { - // const dataCenter = await getDataCenter(); - // await dataCenter.clear(); - // // return new workspace if origin workspace is destroyed - // const ws1 = await dataCenter.load('test7'); - // await dataCenter.destroy('test7'); - // const ws2 = await dataCenter.load('test7'); - // expect(ws1 !== ws2).toBeTruthy(); - // // return new workspace if workspace is reload - // const ws3 = await dataCenter.load('test8'); - // const ws4 = await dataCenter.reload('test8', { providerId: 'affine' }); - // expect(ws3 !== ws4).toBeTruthy(); - }); - - test('remove', async () => { - // const dataCenter = await getDataCenter(); - // await dataCenter.clear(); - // // remove workspace will remove workspace data - // await Promise.all([dataCenter.load('test9'), dataCenter.load('test10')]); - // await dataCenter.delete('test9'); - // expect(await dataCenter.list()).toStrictEqual({ test10: { local: true } }); - }); -}); diff --git a/packages/data-center/tests/utils.ts b/packages/data-center/tests/utils.ts deleted file mode 100644 index 1f4f128333..0000000000 --- a/packages/data-center/tests/utils.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Signal } from '@blocksuite/store'; - -export const getDataCenter = async () => { - const dataCenter = await import('../src/index.js'); - return await dataCenter.getDataCenter(false); -}; - -export const waitOnce = (signal: Signal) => - new Promise(resolve => signal.once(val => resolve(val))); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a5e883aae..35c82751c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,6 @@ importers: .: specifiers: '@changesets/cli': ^2.26.0 - '@jest/globals': ^29.3.1 '@playwright/test': ^1.29.1 '@types/eslint': ^8.4.10 '@types/node': ^18.11.17 @@ -15,16 +14,15 @@ importers: eslint-config-next: 12.3.1 eslint-config-prettier: ^8.5.0 eslint-plugin-prettier: ^4.2.1 + fake-indexeddb: 4.0.1 got: ^12.5.3 husky: ^8.0.2 - jest: ^29.3.1 lint-staged: ^13.1.0 prettier: ^2.7.1 - ts-jest: ^29.0.3 typescript: ^4.9.3 + vitest: ^0.26.3 devDependencies: '@changesets/cli': 2.26.0 - '@jest/globals': 29.3.1 '@playwright/test': 1.29.1 '@types/eslint': 8.4.10 '@types/node': 18.11.18 @@ -34,13 +32,13 @@ importers: eslint-config-next: 12.3.1_p4cjf2r47dnfiqufepc5hp43sq eslint-config-prettier: 8.5.0_eslint@8.31.0 eslint-plugin-prettier: 4.2.1_vkmhlldugy3fnk7p2bqhsfnaiq + fake-indexeddb: 4.0.1 got: 12.5.3 husky: 8.0.2 - jest: 29.3.1_@types+node@18.11.18 lint-staged: 13.1.0 prettier: 2.7.1 - ts-jest: 29.0.3_4f6uxrzmuwipl5rr3bcogf6k74 typescript: 4.9.3 + vitest: 0.26.3 packages/app: specifiers: @@ -755,15 +753,6 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.20.5: - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.5 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.20.5: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -811,15 +800,6 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.20.5: - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.5 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: @@ -838,16 +818,6 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: false - /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.20.5: - resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.5 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.20.5: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: @@ -922,16 +892,6 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-typescript/7.20.0_@babel+core@7.20.5: - resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.5 - '@babel/helper-plugin-utils': 7.19.0 - dev: true - /@babel/plugin-transform-arrow-functions/7.20.7_@babel+core@7.20.5: resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} engines: {node: '>=6.9.0'} @@ -1466,15 +1426,6 @@ packages: - supports-color dev: true - /@babel/types/7.19.4: - resolution: {integrity: sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - /@babel/types/7.20.5: resolution: {integrity: sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==} engines: {node: '>=6.9.0'} @@ -1492,10 +1443,6 @@ packages: to-fast-properties: 2.0.0 dev: true - /@bcoe/v8-coverage/0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - /@blocksuite/blocks/0.3.1_yjs@13.5.44: resolution: {integrity: sha512-b0dGz2MG4yIgngJPRumaMY58wAsd2FEVSZl3tpCXlagK9I0HD165Bq70PxcaRHVjBSV1Gf29ZVHUF6BVTYogPw==} dependencies: @@ -1900,6 +1847,204 @@ packages: resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==} dev: false + /@esbuild/android-arm/0.16.15: + resolution: {integrity: sha512-JsJtmadyWcR+DEtHLixM7bAQsfi1s0Xotv9kVOoXbCLyhKPOHvMEyh3kJBuTbCPSE4c2jQkQVmarwc9Mg9k3bA==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.16.15: + resolution: {integrity: sha512-OdbkUv7468dSsgoFtHIwTaYAuI5lDEv/v+dlfGBUbVa2xSDIIuSOHXawynw5N9+5lygo/JdXa5/sgGjiEU18gQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.16.15: + resolution: {integrity: sha512-dPUOBiNNWAm+/bxoA75o7R7qqqfcEzXaYlb5uJk2xGHmUMNKSAnDCtRYLgx9/wfE4sXyn8H948OrDyUAHhPOuA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.16.15: + resolution: {integrity: sha512-AksarYV85Hxgwh5/zb6qGl4sYWxIXPQGBAZ+jUro1ZpINy3EWumK+/4DPOKUBPnsrOIvnNXy7Rq4mTeCsMQDNA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.16.15: + resolution: {integrity: sha512-qqrKJxoohceZGGP+sZ5yXkzW9ZiyFZJ1gWSEfuYdOWzBSL18Uy3w7s/IvnDYHo++/cxwqM0ch3HQVReSZy7/4Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.16.15: + resolution: {integrity: sha512-LBWaep6RvJm5KnsKkocdVEzuwnGMjz54fcRVZ9d3R7FSEWOtPBxMhuxeA1n98JVbCLMkTPFmKN6xSnfhnM9WXQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.16.15: + resolution: {integrity: sha512-LE8mKC6JPR04kPLRP9A6k7ZmG0k2aWF4ru79Sde6UeWCo7yDby5f48uJNFQ2pZqzUUkLrHL8xNdIHerJeZjHXg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.16.15: + resolution: {integrity: sha512-+1sGlqtMJTOnJUXwLUGnDhPaGRKqxT0UONtYacS+EjdDOrSgpQ/1gUXlnze45Z/BogwYaswQM19Gu1YD1T19/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.16.15: + resolution: {integrity: sha512-mRYpuQGbzY+XLczy3Sk7fMJ3DRKLGDIuvLKkkUkyecDGQMmil6K/xVKP9IpKO7JtNH477qAiMjjX7jfKae8t4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.16.15: + resolution: {integrity: sha512-puXVFvY4m8EB6/fzu3LdgjiNnEZ3gZMSR7NmKoQe51l3hyQalvTjab3Dt7aX4qGf+8Pj7dsCOBNzNzkSlr/4Aw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.16.15: + resolution: {integrity: sha512-ATMGb3eg8T6ZTGZFldlGeFEcevBiVq6SBHvRAO04HMfUjZWneZ/U+JJb3YzlNZxuscJ4Tmzq+JrYxlk7ro4dRg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.16.15: + resolution: {integrity: sha512-3SEA4L82OnoSATW+Ve8rPgLaKjC8WMt8fnx7De9kvi/NcVbkj8W+J7qnu/tK2P9pUPQP7Au/0sjPEqZtFeyKQQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.16.15: + resolution: {integrity: sha512-8PgbeX+N6vmqeySzyxO0NyDOltCEW13OS5jUHTvCHmCgf4kNXZtAWJ+zEfJxjRGYhVezQ1FdIm7WfN1R27uOyg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.16.15: + resolution: {integrity: sha512-U+coqH+89vbPVoU30no1Fllrn6gvEeO5tfEArBhjYZ+dQ3Gv7ciQXYf5nrT1QdlIFwEjH4Is1U1iiaGWW+tGpQ==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.16.15: + resolution: {integrity: sha512-M0nKLFMdyFGBoitxG42kq6Xap0CPeDC6gfF9lg7ZejzGF6kqYUGT+pQGl2QCQoxJBeat/LzTma1hG8C3dq2ocg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.16.15: + resolution: {integrity: sha512-t7/fOXBUKfigvhJLGKZ9TPHHgqNgpIpYaAbcXQk1X+fPeUG7x0tpAbXJ2wST9F/gJ02+CLETPMnhG7Tra2wqsQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.16.15: + resolution: {integrity: sha512-0k0Nxi6DOJmTnLtKD/0rlyqOPpcqONXY53vpkoAsue8CfyhNPWtwzba1ICFNCfCY1dqL3Ho/xEzujJhmdXq1rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.16.15: + resolution: {integrity: sha512-3SkckazfIbdSjsGpuIYT3d6n2Hx0tck3MS1yVsbahhWiLvdy4QozTpvlbjqO3GmvtvhxY4qdyhFOO2wiZKeTAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.16.15: + resolution: {integrity: sha512-8PNvBC+O8X5EnyIGqE8St2bOjjrXMR17NOLenIrzolvwWnJXvwPo0tE/ahOeiAJmTOS/eAcN8b4LAZcn17Uj7w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.16.15: + resolution: {integrity: sha512-YPaSgm/mm7kNcATB53OxVGVfn6rDNbImTn330ZlF3hKej1e9ktCaljGjn2vH08z2dlHEf3kdt57tNjE6zs8SzA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32/0.16.15: + resolution: {integrity: sha512-0movUXbSNrTeNf5ZXT0avklEvlJD0hNGZsrrXHfsp9z4tK5xC+apCqmUEZeE9mqrb84Z8XbgGr/MS9LqafTP2A==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64/0.16.15: + resolution: {integrity: sha512-27h5GCcbfomVAqAnMJWvR1LqEY0dFqIq4vTe5nY3becnZNu0SX8F0+gTk3JPvgWQHzaGc6VkPzlOiMkdSUunUA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint/eslintrc/1.3.2: resolution: {integrity: sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2470,235 +2615,6 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@istanbuljs/load-nyc-config/1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - dev: true - - /@istanbuljs/schema/0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true - - /@jest/console/29.3.1: - resolution: {integrity: sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - chalk: 4.1.2 - jest-message-util: 29.3.1 - jest-util: 29.3.1 - slash: 3.0.0 - dev: true - - /@jest/core/29.3.1: - resolution: {integrity: sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/console': 29.3.1 - '@jest/reporters': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.7.0 - exit: 0.1.2 - graceful-fs: 4.2.10 - jest-changed-files: 29.2.0 - jest-config: 29.3.1_@types+node@18.11.18 - jest-haste-map: 29.3.1 - jest-message-util: 29.3.1 - jest-regex-util: 29.2.0 - jest-resolve: 29.3.1 - jest-resolve-dependencies: 29.3.1 - jest-runner: 29.3.1 - jest-runtime: 29.3.1 - jest-snapshot: 29.3.1 - jest-util: 29.3.1 - jest-validate: 29.3.1 - jest-watcher: 29.3.1 - micromatch: 4.0.5 - pretty-format: 29.3.1 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - supports-color - - ts-node - dev: true - - /@jest/environment/29.3.1: - resolution: {integrity: sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/fake-timers': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - jest-mock: 29.3.1 - dev: true - - /@jest/expect-utils/29.3.1: - resolution: {integrity: sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.2.0 - dev: true - - /@jest/expect/29.3.1: - resolution: {integrity: sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - expect: 29.3.1 - jest-snapshot: 29.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/fake-timers/29.3.1: - resolution: {integrity: sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.3.1 - '@sinonjs/fake-timers': 9.1.2 - '@types/node': 18.11.18 - jest-message-util: 29.3.1 - jest-mock: 29.3.1 - jest-util: 29.3.1 - dev: true - - /@jest/globals/29.3.1: - resolution: {integrity: sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.3.1 - '@jest/expect': 29.3.1 - '@jest/types': 29.3.1 - jest-mock: 29.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/reporters/29.3.1: - resolution: {integrity: sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 - '@jridgewell/trace-mapping': 0.3.17 - '@types/node': 18.11.18 - chalk: 4.1.2 - collect-v8-coverage: 1.0.1 - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.10 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-instrument: 5.2.1 - istanbul-lib-report: 3.0.0 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 - jest-message-util: 29.3.1 - jest-util: 29.3.1 - jest-worker: 29.3.1 - slash: 3.0.0 - string-length: 4.0.2 - strip-ansi: 6.0.1 - v8-to-istanbul: 9.0.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/schemas/29.0.0: - resolution: {integrity: sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@sinclair/typebox': 0.24.51 - dev: true - - /@jest/source-map/29.2.0: - resolution: {integrity: sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jridgewell/trace-mapping': 0.3.17 - callsites: 3.1.0 - graceful-fs: 4.2.10 - dev: true - - /@jest/test-result/29.3.1: - resolution: {integrity: sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.3.1 - '@jest/types': 29.3.1 - '@types/istanbul-lib-coverage': 2.0.4 - collect-v8-coverage: 1.0.1 - dev: true - - /@jest/test-sequencer/29.3.1: - resolution: {integrity: sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.3.1 - graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 - slash: 3.0.0 - dev: true - - /@jest/transform/29.3.1: - resolution: {integrity: sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.20.5 - '@jest/types': 29.3.1 - '@jridgewell/trace-mapping': 0.3.17 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 - jest-regex-util: 29.2.0 - jest-util: 29.3.1 - micromatch: 4.0.5 - pirates: 4.0.5 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/types/29.3.1: - resolution: {integrity: sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.0.0 - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 18.11.18 - '@types/yargs': 17.0.15 - chalk: 4.1.2 - dev: true - /@jridgewell/gen-mapping/0.1.1: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} @@ -3501,27 +3417,11 @@ packages: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} dev: true - /@sinclair/typebox/0.24.51: - resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} - dev: true - /@sindresorhus/is/5.3.0: resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==} engines: {node: '>=14.16'} dev: true - /@sinonjs/commons/1.8.6: - resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} - dependencies: - type-detect: 4.0.8 - dev: true - - /@sinonjs/fake-timers/9.1.2: - resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==} - dependencies: - '@sinonjs/commons': 1.8.6 - dev: true - /@surma/rollup-plugin-off-main-thread/2.2.3: resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} dependencies: @@ -3559,33 +3459,14 @@ packages: resolution: {integrity: sha512-GiS5Df3CzXY/fPBFcM0CKFERZfI4Cg1X33VPZX+NLo7Fwm/h9zu/aU24N1mG75Q9LuMnwKm7woxKr8BiUXGYCg==} dev: false - /@types/babel__core/7.1.20: - resolution: {integrity: sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==} + /@types/chai-subset/1.3.3: + resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: - '@babel/parser': 7.20.5 - '@babel/types': 7.20.5 - '@types/babel__generator': 7.6.4 - '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.18.3 + '@types/chai': 4.3.4 dev: true - /@types/babel__generator/7.6.4: - resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} - dependencies: - '@babel/types': 7.20.5 - dev: true - - /@types/babel__template/7.4.1: - resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} - dependencies: - '@babel/parser': 7.20.5 - '@babel/types': 7.20.5 - dev: true - - /@types/babel__traverse/7.18.3: - resolution: {integrity: sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==} - dependencies: - '@babel/types': 7.20.5 + /@types/chai/4.3.4: + resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} dev: true /@types/debug/4.1.7: @@ -3616,12 +3497,6 @@ packages: '@types/node': 18.7.18 dev: true - /@types/graceful-fs/4.1.5: - resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} - dependencies: - '@types/node': 18.11.18 - dev: true - /@types/http-cache-semantics/4.0.1: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} dev: true @@ -3632,22 +3507,6 @@ packages: ci-info: 3.7.0 dev: true - /@types/istanbul-lib-coverage/2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} - dev: true - - /@types/istanbul-lib-report/3.0.0: - resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} - dependencies: - '@types/istanbul-lib-coverage': 2.0.4 - dev: true - - /@types/istanbul-reports/3.0.1: - resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} - dependencies: - '@types/istanbul-lib-report': 3.0.0 - dev: true - /@types/json-schema/7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true @@ -3691,10 +3550,6 @@ packages: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} dev: false - /@types/prettier/2.7.1: - resolution: {integrity: sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==} - dev: true - /@types/prop-types/15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} @@ -3754,10 +3609,6 @@ packages: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true - /@types/stack-utils/2.0.1: - resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} - dev: true - /@types/trusted-types/2.0.2: resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==} @@ -3765,16 +3616,6 @@ packages: resolution: {integrity: sha512-UYK244awtmcUYQfs7FR8710MJcefL2WvkyHMjA8yJzxd1mo0Gfn88sRZ1Bls7hiUhA2w7ne1gpJ9T5g3G0wOyA==} dev: true - /@types/yargs-parser/21.0.0: - resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} - dev: true - - /@types/yargs/17.0.15: - resolution: {integrity: sha512-ZHc4W2dnEQPfhn06TBEdWaiUHEZAocYaiVMfwOipY5jcJt/251wVrKCBWBetGZWO5CF8tdb7L3DmdxVlZ2BOIg==} - dependencies: - '@types/yargs-parser': 21.0.0 - dev: true - /@typescript-eslint/eslint-plugin/5.48.0_wxmz6cyorqfuzhhglktlvr5lve: resolution: {integrity: sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3960,11 +3801,22 @@ packages: acorn: 8.8.0 dev: true + /acorn-walk/8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + /acorn/8.8.0: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} engines: {node: '>=0.4.0'} dev: true + /acorn/8.8.1: + resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /aggregate-error/3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -4032,24 +3884,11 @@ packages: dependencies: color-convert: 2.0.1 - /ansi-styles/5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true - /ansi-styles/6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} dev: true - /anymatch/3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -4136,6 +3975,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /assertion-error/1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + /ast-types-flow/0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: true @@ -4175,24 +4018,6 @@ packages: resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} dev: true - /babel-jest/29.3.1_@babel+core@7.20.5: - resolution: {integrity: sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - dependencies: - '@babel/core': 7.20.5 - '@jest/transform': 29.3.1 - '@types/babel__core': 7.1.20 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.2.0_@babel+core@7.20.5 - chalk: 4.1.2 - graceful-fs: 4.2.10 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - dev: true - /babel-loader/8.3.0: resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==} engines: {node: '>= 8.9'} @@ -4206,29 +4031,6 @@ packages: schema-utils: 2.7.1 dev: true - /babel-plugin-istanbul/6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - dependencies: - '@babel/helper-plugin-utils': 7.19.0 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /babel-plugin-jest-hoist/29.2.0: - resolution: {integrity: sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/template': 7.18.10 - '@babel/types': 7.20.5 - '@types/babel__core': 7.1.20 - '@types/babel__traverse': 7.18.3 - dev: true - /babel-plugin-macros/3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -4274,37 +4076,6 @@ packages: - supports-color dev: true - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.20.5: - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.5 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.20.5 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.20.5 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.20.5 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.20.5 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.20.5 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.20.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.20.5 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.20.5 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.20.5 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.20.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.20.5 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.20.5 - dev: true - - /babel-preset-jest/29.2.0_@babel+core@7.20.5: - resolution: {integrity: sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.5 - babel-plugin-jest-hoist: 29.2.0 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.5 - dev: true - /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -4366,19 +4137,6 @@ packages: update-browserslist-db: 1.0.10_browserslist@4.21.4 dev: true - /bs-logger/0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - dependencies: - fast-json-stable-stringify: 2.1.0 - dev: true - - /bser/2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - dependencies: - node-int64: 0.4.0 - dev: true - /buffer-from/0.1.2: resolution: {integrity: sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==} dev: false @@ -4441,14 +4199,22 @@ packages: engines: {node: '>=6'} dev: true - /camelcase/6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true - /caniuse-lite/1.0.30001419: resolution: {integrity: sha512-aFO1r+g6R7TW+PNQxKzjITwLOyDhVRLjW0LcwS/HCZGUUKTGNp9+IwLC4xyDSZBygVL/mxaFR3HIV6wEKQuSzw==} + /chai/4.3.7: + resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.2 + deep-eql: 4.1.3 + get-func-name: 2.0.0 + loupe: 2.3.6 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + /chalk-next/6.1.5: resolution: {integrity: sha512-OAx9F3vSk18qpfCohk0849/j3GyaoIpv8eXjmpdbmLZt+5+sWYq8xwt3B5ue25irLcxFcLL2hAbxxHSsBxupbw==} engines: {node: '>=10'} @@ -4477,24 +4243,19 @@ packages: supports-color: 7.2.0 dev: true - /char-regex/1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true - /chardet/0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true + /check-error/1.0.2: + resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + dev: true + /ci-info/3.7.0: resolution: {integrity: sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==} engines: {node: '>=8'} dev: true - /cjs-module-lexer/1.2.2: - resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} - dev: true - /clean-stack/2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -4589,15 +4350,6 @@ packages: - '@types/react' dev: false - /co/4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true - - /collect-v8-coverage/1.0.1: - resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} - dev: true - /color-convert/1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -4648,10 +4400,6 @@ packages: /convert-source-map/1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - /convert-source-map/2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - /core-js-compat/3.27.1: resolution: {integrity: sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==} dependencies: @@ -4797,8 +4545,11 @@ packages: mimic-response: 3.1.0 dev: true - /dedent/0.7.0: - resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + /deep-eql/4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 dev: true /deep-equal/1.1.1: @@ -4857,20 +4608,10 @@ packages: engines: {node: '>=8'} dev: true - /detect-newline/3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true - /detect-node-es/1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} dev: false - /diff-sequences/29.3.1: - resolution: {integrity: sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -4931,11 +4672,6 @@ packages: resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} dev: true - /emittery/0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - dev: true - /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5014,6 +4750,36 @@ packages: is-symbol: 1.0.4 dev: true + /esbuild/0.16.15: + resolution: {integrity: sha512-v+3ozjy9wyj8cOElzx3//Lsb4TCxPfZxRmdsfm0YaEkvZu7y6rKH7Zi1UpDx4JI7dSQui+U1Qxhfij9KBbHfrA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.16.15 + '@esbuild/android-arm64': 0.16.15 + '@esbuild/android-x64': 0.16.15 + '@esbuild/darwin-arm64': 0.16.15 + '@esbuild/darwin-x64': 0.16.15 + '@esbuild/freebsd-arm64': 0.16.15 + '@esbuild/freebsd-x64': 0.16.15 + '@esbuild/linux-arm': 0.16.15 + '@esbuild/linux-arm64': 0.16.15 + '@esbuild/linux-ia32': 0.16.15 + '@esbuild/linux-loong64': 0.16.15 + '@esbuild/linux-mips64el': 0.16.15 + '@esbuild/linux-ppc64': 0.16.15 + '@esbuild/linux-riscv64': 0.16.15 + '@esbuild/linux-s390x': 0.16.15 + '@esbuild/linux-x64': 0.16.15 + '@esbuild/netbsd-x64': 0.16.15 + '@esbuild/openbsd-x64': 0.16.15 + '@esbuild/sunos-x64': 0.16.15 + '@esbuild/win32-arm64': 0.16.15 + '@esbuild/win32-ia32': 0.16.15 + '@esbuild/win32-x64': 0.16.15 + dev: true + /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -5022,11 +4788,6 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - /escape-string-regexp/2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true - /escape-string-regexp/4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -5606,21 +5367,6 @@ packages: resolution: {integrity: sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==} dev: false - /execa/5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - /execa/6.1.0: resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5636,22 +5382,6 @@ packages: strip-final-newline: 3.0.0 dev: true - /exit/0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - dev: true - - /expect/29.3.1: - resolution: {integrity: sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/expect-utils': 29.3.1 - jest-get-type: 29.2.0 - jest-matcher-utils: 29.3.1 - jest-message-util: 29.3.1 - jest-util: 29.3.1 - dev: true - /extend/3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} dev: false @@ -5719,12 +5449,6 @@ packages: websocket-driver: 0.7.4 dev: false - /fb-watchman/2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - dependencies: - bser: 2.1.1 - dev: true - /fetch-blob/3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -5937,6 +5661,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + /get-func-name/2.0.0: + resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + dev: true + /get-intrinsic/1.1.3: resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} dependencies: @@ -5953,11 +5681,6 @@ packages: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} dev: true - /get-package-type/0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true - /get-stream/6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -6132,10 +5855,6 @@ packages: resolution: {integrity: sha512-mshqjgTqx8ee0qryHvRgZaZDxTwxam/2yTQmQlqAWS3+twnq1jsY9Yng9zB7lWq6WRrjTbTOc7knNwccXQiAjQ==} dev: false - /html-escaper/2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true - /html-parse-stringify/3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} dependencies: @@ -6172,11 +5891,6 @@ packages: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: true - /human-signals/2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true - /human-signals/3.0.1: resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} engines: {node: '>=12.20.0'} @@ -6238,15 +5952,6 @@ packages: parent-module: 1.0.1 resolve-from: 4.0.0 - /import-local/3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 - dev: true - /imurmurhash/0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -6344,11 +6049,6 @@ packages: engines: {node: '>=12'} dev: true - /is-generator-fn/2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - dev: true - /is-glob/4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -6487,52 +6187,6 @@ packages: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} dev: false - /istanbul-lib-coverage/3.2.0: - resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} - engines: {node: '>=8'} - dev: true - - /istanbul-lib-instrument/5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - dependencies: - '@babel/core': 7.20.5 - '@babel/parser': 7.20.5 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-lib-report/3.0.0: - resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} - engines: {node: '>=8'} - dependencies: - istanbul-lib-coverage: 3.2.0 - make-dir: 3.1.0 - supports-color: 7.2.0 - dev: true - - /istanbul-lib-source-maps/4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - dependencies: - debug: 4.3.4 - istanbul-lib-coverage: 3.2.0 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - dev: true - - /istanbul-reports/3.1.5: - resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} - engines: {node: '>=8'} - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.0 - dev: true - /jake/10.8.5: resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==} engines: {node: '>=10'} @@ -6544,385 +6198,6 @@ packages: minimatch: 3.1.2 dev: true - /jest-changed-files/29.2.0: - resolution: {integrity: sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - execa: 5.1.1 - p-limit: 3.1.0 - dev: true - - /jest-circus/29.3.1: - resolution: {integrity: sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.3.1 - '@jest/expect': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - chalk: 4.1.2 - co: 4.6.0 - dedent: 0.7.0 - is-generator-fn: 2.1.0 - jest-each: 29.3.1 - jest-matcher-utils: 29.3.1 - jest-message-util: 29.3.1 - jest-runtime: 29.3.1 - jest-snapshot: 29.3.1 - jest-util: 29.3.1 - p-limit: 3.1.0 - pretty-format: 29.3.1 - slash: 3.0.0 - stack-utils: 2.0.6 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-cli/29.3.1_@types+node@18.11.18: - resolution: {integrity: sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/types': 29.3.1 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.10 - import-local: 3.1.0 - jest-config: 29.3.1_@types+node@18.11.18 - jest-util: 29.3.1 - jest-validate: 29.3.1 - prompts: 2.4.2 - yargs: 17.6.2 - transitivePeerDependencies: - - '@types/node' - - supports-color - - ts-node - dev: true - - /jest-config/29.3.1_@types+node@18.11.18: - resolution: {integrity: sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.20.5 - '@jest/test-sequencer': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - babel-jest: 29.3.1_@babel+core@7.20.5 - chalk: 4.1.2 - ci-info: 3.7.0 - deepmerge: 4.2.2 - glob: 7.2.3 - graceful-fs: 4.2.10 - jest-circus: 29.3.1 - jest-environment-node: 29.3.1 - jest-get-type: 29.2.0 - jest-regex-util: 29.2.0 - jest-resolve: 29.3.1 - jest-runner: 29.3.1 - jest-util: 29.3.1 - jest-validate: 29.3.1 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.3.1 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-diff/29.3.1: - resolution: {integrity: sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 29.3.1 - jest-get-type: 29.2.0 - pretty-format: 29.3.1 - dev: true - - /jest-docblock/29.2.0: - resolution: {integrity: sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - detect-newline: 3.1.0 - dev: true - - /jest-each/29.3.1: - resolution: {integrity: sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.3.1 - chalk: 4.1.2 - jest-get-type: 29.2.0 - jest-util: 29.3.1 - pretty-format: 29.3.1 - dev: true - - /jest-environment-node/29.3.1: - resolution: {integrity: sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.3.1 - '@jest/fake-timers': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - jest-mock: 29.3.1 - jest-util: 29.3.1 - dev: true - - /jest-get-type/29.2.0: - resolution: {integrity: sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-haste-map/29.3.1: - resolution: {integrity: sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.3.1 - '@types/graceful-fs': 4.1.5 - '@types/node': 18.11.18 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.10 - jest-regex-util: 29.2.0 - jest-util: 29.3.1 - jest-worker: 29.3.1 - micromatch: 4.0.5 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.2 - dev: true - - /jest-leak-detector/29.3.1: - resolution: {integrity: sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.2.0 - pretty-format: 29.3.1 - dev: true - - /jest-matcher-utils/29.3.1: - resolution: {integrity: sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.3.1 - jest-get-type: 29.2.0 - pretty-format: 29.3.1 - dev: true - - /jest-message-util/29.3.1: - resolution: {integrity: sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.18.6 - '@jest/types': 29.3.1 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.10 - micromatch: 4.0.5 - pretty-format: 29.3.1 - slash: 3.0.0 - stack-utils: 2.0.6 - dev: true - - /jest-mock/29.3.1: - resolution: {integrity: sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - jest-util: 29.3.1 - dev: true - - /jest-pnp-resolver/1.2.3_jest-resolve@29.3.1: - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: - jest-resolve: 29.3.1 - dev: true - - /jest-regex-util/29.2.0: - resolution: {integrity: sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-resolve-dependencies/29.3.1: - resolution: {integrity: sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-regex-util: 29.2.0 - jest-snapshot: 29.3.1 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-resolve/29.3.1: - resolution: {integrity: sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 - jest-pnp-resolver: 1.2.3_jest-resolve@29.3.1 - jest-util: 29.3.1 - jest-validate: 29.3.1 - resolve: 1.22.1 - resolve.exports: 1.1.0 - slash: 3.0.0 - dev: true - - /jest-runner/29.3.1: - resolution: {integrity: sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.3.1 - '@jest/environment': 29.3.1 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - chalk: 4.1.2 - emittery: 0.13.1 - graceful-fs: 4.2.10 - jest-docblock: 29.2.0 - jest-environment-node: 29.3.1 - jest-haste-map: 29.3.1 - jest-leak-detector: 29.3.1 - jest-message-util: 29.3.1 - jest-resolve: 29.3.1 - jest-runtime: 29.3.1 - jest-util: 29.3.1 - jest-watcher: 29.3.1 - jest-worker: 29.3.1 - p-limit: 3.1.0 - source-map-support: 0.5.13 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-runtime/29.3.1: - resolution: {integrity: sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.3.1 - '@jest/fake-timers': 29.3.1 - '@jest/globals': 29.3.1 - '@jest/source-map': 29.2.0 - '@jest/test-result': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - chalk: 4.1.2 - cjs-module-lexer: 1.2.2 - collect-v8-coverage: 1.0.1 - glob: 7.2.3 - graceful-fs: 4.2.10 - jest-haste-map: 29.3.1 - jest-message-util: 29.3.1 - jest-mock: 29.3.1 - jest-regex-util: 29.2.0 - jest-resolve: 29.3.1 - jest-snapshot: 29.3.1 - jest-util: 29.3.1 - slash: 3.0.0 - strip-bom: 4.0.0 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-snapshot/29.3.1: - resolution: {integrity: sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.20.5 - '@babel/generator': 7.20.5 - '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.20.5 - '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.20.5 - '@babel/traverse': 7.20.5 - '@babel/types': 7.19.4 - '@jest/expect-utils': 29.3.1 - '@jest/transform': 29.3.1 - '@jest/types': 29.3.1 - '@types/babel__traverse': 7.18.3 - '@types/prettier': 2.7.1 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.5 - chalk: 4.1.2 - expect: 29.3.1 - graceful-fs: 4.2.10 - jest-diff: 29.3.1 - jest-get-type: 29.2.0 - jest-haste-map: 29.3.1 - jest-matcher-utils: 29.3.1 - jest-message-util: 29.3.1 - jest-util: 29.3.1 - natural-compare: 1.4.0 - pretty-format: 29.3.1 - semver: 7.3.7 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-util/29.3.1: - resolution: {integrity: sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - chalk: 4.1.2 - ci-info: 3.7.0 - graceful-fs: 4.2.10 - picomatch: 2.3.1 - dev: true - - /jest-validate/29.3.1: - resolution: {integrity: sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.3.1 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.2.0 - leven: 3.1.0 - pretty-format: 29.3.1 - dev: true - - /jest-watcher/29.3.1: - resolution: {integrity: sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.3.1 - '@jest/types': 29.3.1 - '@types/node': 18.11.18 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 29.3.1 - string-length: 4.0.2 - dev: true - /jest-worker/26.6.2: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} @@ -6941,36 +6216,6 @@ packages: supports-color: 8.1.1 dev: true - /jest-worker/29.3.1: - resolution: {integrity: sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@types/node': 18.11.18 - jest-util: 29.3.1 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - - /jest/29.3.1_@types+node@18.11.18: - resolution: {integrity: sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.3.1 - '@jest/types': 29.3.1 - import-local: 3.1.0 - jest-cli: 29.3.1_@types+node@18.11.18 - transitivePeerDependencies: - - '@types/node' - - supports-color - - ts-node - dev: true - /js-sdsl/4.2.0: resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==} dev: true @@ -7039,6 +6284,10 @@ packages: hasBin: true dev: true + /jsonc-parser/3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + /jsonfile/4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: @@ -7077,11 +6326,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /kleur/3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true - /kleur/4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -7248,6 +6492,11 @@ packages: json5: 2.2.1 dev: true + /local-pkg/0.4.2: + resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==} + engines: {node: '>=14'} + dev: true + /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -7270,10 +6519,6 @@ packages: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} dev: true - /lodash.memoize/4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - dev: true - /lodash.merge/4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -7312,6 +6557,12 @@ packages: dependencies: js-tokens: 4.0.0 + /loupe/2.3.6: + resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + dependencies: + get-func-name: 2.0.0 + dev: true + /lowercase-keys/3.0.0: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -7350,16 +6601,6 @@ packages: semver: 6.3.0 dev: true - /make-error/1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true - - /makeerror/1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - dependencies: - tmpl: 1.0.5 - dev: true - /map-obj/1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -7465,6 +6706,15 @@ packages: engines: {node: '>= 8.0.0'} dev: true + /mlly/1.0.0: + resolution: {integrity: sha512-QL108Hwt+u9bXdWgOI0dhzZfACovn5Aen4Xvc8Jasd9ouRH4NjnrXEiyP3nVvJo91zPlYjVRckta0Nt2zfoR6g==} + dependencies: + acorn: 8.8.1 + pathe: 1.0.0 + pkg-types: 1.0.1 + ufo: 1.0.1 + dev: true + /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} dev: true @@ -7637,10 +6887,6 @@ packages: formdata-polyfill: 4.0.10 dev: false - /node-int64/0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true - /node-releases/2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} dev: true @@ -7664,13 +6910,6 @@ packages: engines: {node: '>=14.16'} dev: true - /npm-run-path/4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: true - /npm-run-path/5.1.0: resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -7894,6 +7133,18 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + /pathe/0.2.0: + resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} + dev: true + + /pathe/1.0.0: + resolution: {integrity: sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==} + dev: true + + /pathval/1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + /perfect-freehand/1.2.0: resolution: {integrity: sha512-h/0ikF1M3phW7CwpZ5MMvKnfpHficWoOEyr//KVNTxV4F6deRK1eYMtHyBKEAKFK0aXIEUK9oBvlF6PNXMDsAw==} dev: false @@ -7934,11 +7185,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /pirates/4.0.5: - resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} - engines: {node: '>= 6'} - dev: true - /pkg-dir/4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -7946,6 +7192,14 @@ packages: find-up: 4.1.0 dev: true + /pkg-types/1.0.1: + resolution: {integrity: sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.0.0 + pathe: 1.0.0 + dev: true + /playwright-core/1.29.1: resolution: {integrity: sha512-20Ai3d+lMkWpI9YZYlxk8gxatfgax5STW8GaMozAHwigLiyiKQrdkt7gaoT9UQR8FIVDg6qVXs9IoZUQrDjIIg==} engines: {node: '>=14'} @@ -7960,6 +7214,15 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postcss/8.4.21: + resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /preferred-pm/3.0.3: resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} engines: {node: '>=10'} @@ -7991,27 +7254,10 @@ packages: engines: {node: '>=6'} dev: true - /pretty-format/29.3.1: - resolution: {integrity: sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.0.0 - ansi-styles: 5.2.0 - react-is: 18.2.0 - dev: true - /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: false - /prompts/2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - dev: true - /prop-types/15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -8153,6 +7399,7 @@ packages: /react-is/18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + dev: false /react-remove-scroll-bar/2.3.4_w5j4k42lgipnm43s3brx6h3c34: resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} @@ -8377,13 +7624,6 @@ packages: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} dev: true - /resolve-cwd/3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - dependencies: - resolve-from: 5.0.0 - dev: true - /resolve-from/4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -8393,11 +7633,6 @@ packages: engines: {node: '>=8'} dev: true - /resolve.exports/1.1.0: - resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==} - engines: {node: '>=10'} - dev: true - /resolve/1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} dependencies: @@ -8471,6 +7706,14 @@ packages: fsevents: 2.3.2 dev: true + /rollup/3.9.1: + resolution: {integrity: sha512-GswCYHXftN8ZKGVgQhTFUJB/NBXxrRGgO2NCy6E8s1rwEJ4Q9/VttNqcYfEvx4dTo4j58YqdC3OVztPzlKSX8w==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -8604,10 +7847,6 @@ packages: - supports-color dev: false - /sisteransi/1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true - /slash/3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -8660,13 +7899,6 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - /source-map-support/0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - /source-map-support/0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: @@ -8729,13 +7961,6 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true - /stack-utils/2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - /stream-transform/2.1.3: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: @@ -8747,14 +7972,6 @@ packages: engines: {node: '>=0.6.19'} dev: true - /string-length/4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - dev: true - /string-width/4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8844,21 +8061,11 @@ packages: engines: {node: '>=4'} dev: true - /strip-bom/4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true - /strip-comments/2.0.1: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} engines: {node: '>=10'} dev: true - /strip-final-newline/2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - /strip-final-newline/3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -8876,6 +8083,12 @@ packages: engines: {node: '>=8'} dev: true + /strip-literal/1.0.0: + resolution: {integrity: sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==} + dependencies: + acorn: 8.8.1 + dev: true + /styled-jsx/5.0.7_react@18.2.0: resolution: {integrity: sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==} engines: {node: '>= 12.0.0'} @@ -8999,15 +8212,6 @@ packages: source-map-support: 0.5.21 dev: true - /test-exclude/6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - /text-table/0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -9022,6 +8226,20 @@ packages: xtend: 2.1.2 dev: false + /tinybench/2.3.1: + resolution: {integrity: sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==} + dev: true + + /tinypool/0.3.0: + resolution: {integrity: sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy/1.0.2: + resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} + engines: {node: '>=14.0.0'} + dev: true + /tmp/0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -9029,10 +8247,6 @@ packages: os-tmpdir: 1.0.2 dev: true - /tmpl/1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true - /to-fast-properties/2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -9066,39 +8280,6 @@ packages: engines: {node: '>=8'} dev: true - /ts-jest/29.0.3_4f6uxrzmuwipl5rr3bcogf6k74: - resolution: {integrity: sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - jest: 29.3.1_@types+node@18.11.18 - jest-util: 29.3.1 - json5: 2.2.1 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.3.7 - typescript: 4.9.3 - yargs-parser: 21.1.1 - dev: true - /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: @@ -9229,6 +8410,10 @@ packages: engines: {node: '>=0.1.14'} dev: true + /ufo/1.0.1: + resolution: {integrity: sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==} + dev: true + /unbox-primitive/1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: @@ -9353,15 +8538,6 @@ packages: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true - /v8-to-istanbul/9.0.1: - resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} - engines: {node: '>=10.12.0'} - dependencies: - '@jridgewell/trace-mapping': 0.3.17 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.9.0 - dev: true - /validate-npm-package-license/3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -9369,17 +8545,112 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /vite-node/0.26.3_@types+node@18.11.18: + resolution: {integrity: sha512-Te2bq0Bfvq6XiO718I+1EinMjpNYKws6SNHKOmVbILAQimKoZKDd+IZLlkaYcBXPpK3HFe2U80k8Zw+m3w/a2w==} + engines: {node: '>=v14.16.0'} + hasBin: true + dependencies: + debug: 4.3.4 + mlly: 1.0.0 + pathe: 0.2.0 + source-map: 0.6.1 + source-map-support: 0.5.21 + vite: 4.0.4_@types+node@18.11.18 + transitivePeerDependencies: + - '@types/node' + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vite/4.0.4_@types+node@18.11.18: + resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.11.18 + esbuild: 0.16.15 + postcss: 8.4.21 + resolve: 1.22.1 + rollup: 3.9.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vitest/0.26.3: + resolution: {integrity: sha512-FmHxU9aUCxTi23keF3vxb/Qp0lYXaaJ+jRLGOUmMS3qVTOJvgGE+f1VArupA6pEhaG2Ans4X+zV9dqM5WISMbg==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 4.3.4 + '@types/chai-subset': 1.3.3 + '@types/node': 18.11.18 + acorn: 8.8.1 + acorn-walk: 8.2.0 + chai: 4.3.7 + debug: 4.3.4 + local-pkg: 0.4.2 + source-map: 0.6.1 + strip-literal: 1.0.0 + tinybench: 2.3.1 + tinypool: 0.3.0 + tinyspy: 1.0.2 + vite: 4.0.4_@types+node@18.11.18 + vite-node: 0.26.3_@types+node@18.11.18 + transitivePeerDependencies: + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /void-elements/3.1.0: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} dev: false - /walker/1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - dependencies: - makeerror: 1.0.12 - dev: true - /wcwidth/1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: @@ -9673,14 +8944,6 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /write-file-atomic/4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - dev: true - /ws/7.5.9: resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} engines: {node: '>=8.3.0'} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000000..4c6feaa4dd --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['packages/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + }, +}); From 59fc7731747a7d56a3b181a3b57eb8103a5cc35a Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 01:03:10 +0800 Subject: [PATCH 059/298] test: add workspaces unit test --- .../src/workspaces/workspaces.spec.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 packages/data-center/src/workspaces/workspaces.spec.ts diff --git a/packages/data-center/src/workspaces/workspaces.spec.ts b/packages/data-center/src/workspaces/workspaces.spec.ts new file mode 100644 index 0000000000..859cbabfb0 --- /dev/null +++ b/packages/data-center/src/workspaces/workspaces.spec.ts @@ -0,0 +1,50 @@ +import { describe, test, expect } from 'vitest'; +import { Workspaces } from './workspaces'; +import type { WorkspacesChangeEvent } from './workspaces'; + +describe('workspaces observable', () => { + const workspaces = new Workspaces(); + + const scope = workspaces.createScope(); + + test('add workspace', () => { + workspaces.once('change', (event: WorkspacesChangeEvent) => { + expect(event.added?.id).toEqual('123'); + }); + scope.add({ + id: '123', + name: 'test', + memberCount: 1, + provider: '', + }); + }); + + test('list workspace', () => { + const list = scope.list(); + expect(list.length).toEqual(1); + expect(list[0].id).toEqual('123'); + }); + + test('get workspace', () => { + expect(scope.get('123')?.id).toEqual('123'); + }); + + test('update workspace', () => { + workspaces.once('change', (event: WorkspacesChangeEvent) => { + expect(event.updated?.name).toEqual('demo'); + }); + scope.update('123', { name: 'demo' }); + }); + + test('get workspace form other scope', () => { + const scope1 = workspaces.createScope(); + expect(scope1.get('123')).toBeFalsy(); + }); + + test('delete workspace', () => { + workspaces.once('change', (event: WorkspacesChangeEvent) => { + expect(event.deleted?.id).toEqual('123'); + }); + scope.remove('123'); + }); +}); From c8101dfa4c056fc697ba92e7f4cda36a5ebe5a77 Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 01:07:09 +0800 Subject: [PATCH 060/298] refactor: rename defaultProvider -> mainProvider --- packages/data-center/src/datacenter.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index c859ad7d02..410c60366b 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -18,7 +18,10 @@ export class DataCenter { private readonly _workspaces = new Workspaces(); private currentWorkspace: Workspace | null = null; private readonly _logger = getLogger('dc'); - private _defaultProvider?: BaseProvider; + /** + * A mainProvider must exist as the only data trustworthy source. + */ + private _mainProvider?: BaseProvider; providerMap: Map = new Map(); constructor(debug: boolean) { @@ -49,16 +52,16 @@ export class DataCenter { * We will automatically set the first provider to default provider. */ registerProvider(provider: BaseProvider) { - if (!this._defaultProvider) { - this._defaultProvider = provider; + if (!this._mainProvider) { + this._mainProvider = provider; } provider.init(); this.providerMap.set(provider.id, provider); } - setDefaultProvider(providerId: string) { - this._defaultProvider = this.providerMap.get(providerId); + setMainProvider(providerId: string) { + this._mainProvider = this.providerMap.get(providerId); } get providers() { @@ -82,13 +85,11 @@ export class DataCenter { */ public async createWorkspace(workspaceMeta: WorkspaceMeta) { assert( - this._defaultProvider, + this._mainProvider, 'There is no provider. You should add provider first.' ); - const workspace = await this._defaultProvider.createWorkspace( - workspaceMeta - ); + const workspace = await this._mainProvider.createWorkspace(workspaceMeta); return workspace; } From 1124d14055dfc3d2db3f239c4b4fc34124d6d62d Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 10:37:40 +0800 Subject: [PATCH 061/298] feat: remove current workspaces --- packages/data-center/src/datacenter.ts | 36 +++++++------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 410c60366b..5714fe98fa 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -16,7 +16,6 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; */ export class DataCenter { private readonly _workspaces = new Workspaces(); - private currentWorkspace: Workspace | null = null; private readonly _logger = getLogger('dc'); /** * A mainProvider must exist as the only data trustworthy source. @@ -150,9 +149,8 @@ export class DataCenter { const provider = this.providerMap.get(workspaceInfo.provider); assert(provider, `provide '${workspaceInfo.provider}' is not registered`); this._logger(`Loading ${workspaceInfo.provider} workspace: `, workspaceId); - const workspace = this._getWorkspace(workspaceId); - this.currentWorkspace = await provider.warpWorkspace(workspace); - return this.currentWorkspace; + + return await provider.warpWorkspace(this._getWorkspace(workspaceId)); } /** @@ -184,24 +182,23 @@ export class DataCenter { */ public async resetWorkspaceMeta( { name, avatar }: WorkspaceMeta, - workspace?: Workspace + workspace: Workspace ) { - const w = workspace ?? this.currentWorkspace; - assert(w?.room, 'No workspace to set meta'); + assert(workspace?.room, 'No workspace to set meta'); const update: Partial = {}; if (name) { - w.meta.setName(name); + workspace.doc.meta.setName(name); update.name = name; } if (avatar) { - w.meta.setAvatar(avatar); + workspace.doc.meta.setAvatar(avatar); update.avatar = avatar; } // may run for change workspace meta - const workspaceInfo = this._workspaces.find(w.room); + const workspaceInfo = this._workspaces.find(workspace.room); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); - provider?.updateWorkspaceMeta(w.room, update); + provider?.updateWorkspaceMeta(workspace.room, update); } /** @@ -250,19 +247,6 @@ export class DataCenter { } } - /** - * - * do close current workspace - */ - public async closeCurrentWorkspace() { - assert(this.currentWorkspace?.room, 'No workspace to close'); - const currentWorkspace = this._workspaces.find(this.currentWorkspace.room); - assert(currentWorkspace, 'Workspace not found'); - const provider = this.providerMap.get(currentWorkspace.provider); - assert(provider, 'Provider not found'); - await provider.closeWorkspace(currentWorkspace.id); - } - private async _transWorkspaceProvider( workspace: Workspace, providerId: string @@ -296,9 +280,7 @@ export class DataCenter { * Enable workspace cloud * @param {string} id ID of workspace. */ - public async enableWorkspaceCloud( - workspace: Workspace | null = this.currentWorkspace - ) { + public async enableWorkspaceCloud(workspace: Workspace) { assert(workspace?.room, 'No workspace to enable cloud'); return await this._transWorkspaceProvider(workspace, 'affine'); } From dd529f80355aa6134c1ec143f7b60e316ea77587 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 10:53:18 +0800 Subject: [PATCH 062/298] feat: change new data center --- .../src/components/invite-members/index.tsx | 46 ++-- .../login-modal/LoginOptionButton.tsx | 16 +- .../general/delete/delete.tsx | 10 +- .../workspace-setting/general/general.tsx | 26 +-- .../workspace-setting/general/leave/leave.tsx | 4 +- .../workspace-setting/workspace-setting.tsx | 68 +++--- .../SelectorPopperContent.tsx | 6 +- .../workspace-create/workspace-create.tsx | 42 ++-- .../app/src/pages/invite/[invite_code].tsx | 26 +-- .../src/provider/affine/apis/business.ts | 198 ------------------ 10 files changed, 122 insertions(+), 320 deletions(-) delete mode 100644 packages/data-center/src/provider/affine/apis/business.ts diff --git a/packages/app/src/components/invite-members/index.tsx b/packages/app/src/components/invite-members/index.tsx index f06674cb6b..22a72220ee 100644 --- a/packages/app/src/components/invite-members/index.tsx +++ b/packages/app/src/components/invite-members/index.tsx @@ -60,19 +60,19 @@ export const InviteMembers = ({ setShowTip(false); debounce( () => { - getDataCenter() - .then(dc => - dc.apis.getUserByEmail({ - email: value, - workspace_id: workspaceId, - }) - ) - .then(data => { - if (data?.name) { - setUserData(data); - setShowTip(false); - } - }); + // getDataCenter() + // .then(dc => + // dc.apis.getUserByEmail({ + // email: value, + // workspace_id: workspaceId, + // }) + // ) + // .then(data => { + // if (data?.name) { + // setUserData(data); + // setShowTip(false); + // } + // }); }, 300, true @@ -134,16 +134,16 @@ export const InviteMembers = ({ shape="circle" type="primary" onClick={() => { - getDataCenter() - .then(dc => dc.apis.inviteMember({ id: workspaceId, email })) - .then(() => { - onClose(); - onInviteSuccess && onInviteSuccess(); - }) - .catch(err => { - // toast('Invite failed'); - console.log(err); - }); + // getDataCenter() + // .then(dc => dc.apis.inviteMember({ id: workspaceId, email })) + // .then(() => { + // onClose(); + // onInviteSuccess && onInviteSuccess(); + // }) + // .catch(err => { + // // toast('Invite failed'); + // console.log(err); + // }); }} > Invite diff --git a/packages/app/src/components/login-modal/LoginOptionButton.tsx b/packages/app/src/components/login-modal/LoginOptionButton.tsx index e04d8fecc7..f8e3cdafce 100644 --- a/packages/app/src/components/login-modal/LoginOptionButton.tsx +++ b/packages/app/src/components/login-modal/LoginOptionButton.tsx @@ -9,14 +9,14 @@ export const GoogleLoginButton = () => { return ( { - getDataCenter() - .then(dc => dc.apis.signInWithGoogle?.()) - .then(() => { - triggerLoginModal(); - }) - .catch(error => { - console.log('sign google error', error); - }); + // getDataCenter() + // .then(dc => dc.apis.signInWithGoogle?.()) + // .then(() => { + // triggerLoginModal(); + // }) + // .catch(error => { + // console.log('sign google error', error); + // }); }} > diff --git a/packages/app/src/components/workspace-setting/general/delete/delete.tsx b/packages/app/src/components/workspace-setting/general/delete/delete.tsx index 7fd14ef818..5ba8b120f4 100644 --- a/packages/app/src/components/workspace-setting/general/delete/delete.tsx +++ b/packages/app/src/components/workspace-setting/general/delete/delete.tsx @@ -39,11 +39,11 @@ export const WorkspaceDelete = ({ }; const handleDelete = async () => { - const dc = await getDataCenter(); - await dc.apis.deleteWorkspace({ id: workspaceId }); - router.push(`/workspace/${nextWorkSpaceId}`); - refreshWorkspacesMeta(); - onClose(); + // const dc = await getDataCenter(); + // await dc.apis.deleteWorkspace({ id: workspaceId }); + // router.push(`/workspace/${nextWorkSpaceId}`); + // refreshWorkspacesMeta(); + // onClose(); }; return ( diff --git a/packages/app/src/components/workspace-setting/general/general.tsx b/packages/app/src/components/workspace-setting/general/general.tsx index cef2daccb7..fc3c4cacfd 100644 --- a/packages/app/src/components/workspace-setting/general/general.tsx +++ b/packages/app/src/components/workspace-setting/general/general.tsx @@ -72,19 +72,19 @@ export const GeneralPage = ({ }; const fileChange = async (file: File) => { - setUploading(true); - const blob = new Blob([file], { type: file.type }); - const blobId = await getDataCenter() - .then(dc => dc.apis.uploadBlob({ blob })) - .finally(() => { - setUploading(false); - }); - if (blobId) { - currentWorkspace?.meta.setAvatar(blobId); - workspaces[workspace.id]?.meta.setAvatar(blobId); - setUploading(false); - debouncedRefreshWorkspacesMeta(); - } + // setUploading(true); + // const blob = new Blob([file], { type: file.type }); + // const blobId = await getDataCenter() + // .then(dc => dc.apis.uploadBlob({ blob })) + // .finally(() => { + // setUploading(false); + // }); + // if (blobId) { + // currentWorkspace?.meta.setAvatar(blobId); + // workspaces[workspace.id]?.meta.setAvatar(blobId); + // setUploading(false); + // debouncedRefreshWorkspacesMeta(); + // } }; return workspace ? ( diff --git a/packages/app/src/components/workspace-setting/general/leave/leave.tsx b/packages/app/src/components/workspace-setting/general/leave/leave.tsx index 3c2cf8ce22..baea054915 100644 --- a/packages/app/src/components/workspace-setting/general/leave/leave.tsx +++ b/packages/app/src/components/workspace-setting/general/leave/leave.tsx @@ -28,8 +28,8 @@ export const WorkspaceLeave = ({ const router = useRouter(); const { refreshWorkspacesMeta } = useAppState(); const handleLeave = async () => { - const dc = await getDataCenter(); - await dc.apis.leaveWorkspace({ id: workspaceId }); + // const dc = await getDataCenter(); + // await dc.apis.leaveWorkspace({ id: workspaceId }); router.push(`/workspace/${nextWorkSpaceId}`); refreshWorkspacesMeta(); onClose(); diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index c1b07e2441..fc11df64bb 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -163,18 +163,18 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { const [isInviteModalShow, setIsInviteModalShow] = useState(false); const [members, setMembers] = useState([]); const refreshMembers = useCallback(() => { - getDataCenter() - .then(dc => - dc.apis.getWorkspaceMembers({ - id: workspace.id, - }) - ) - .then(data => { - setMembers(data); - }) - .catch(err => { - console.log(err); - }); + // getDataCenter() + // .then(dc => + // dc.apis.getWorkspaceMembers({ + // id: workspace.id, + // }) + // ) + // .then(data => { + // setMembers(data); + // }) + // .catch(err => { + // console.log(err); + // }); }, [workspace.id]); useEffect(() => { refreshMembers(); @@ -233,17 +233,17 @@ const MembersPage = ({ workspace }: { workspace: Workspace }) => { // confirmText: 'Delete', // confirmType: 'danger', // }).then(confirm => { - getDataCenter() - .then(dc => - dc.apis.removeMember({ - permissionId: member.id, - }) - ) - .then(() => { - // console.log('data: ', data); - toast('Moved to Trash'); - refreshMembers(); - }); + // getDataCenter() + // .then(dc => + // dc.apis.removeMember({ + // permissionId: member.id, + // }) + // ) + // .then(() => { + // // console.log('data: ', data); + // toast('Moved to Trash'); + // refreshMembers(); + // }); // }); }} icon={} @@ -298,17 +298,17 @@ const PublishPage = ({ workspace }: { workspace: Workspace }) => { workspace.public ); const togglePublic = (flag: boolean) => { - getDataCenter() - .then(dc => - dc.apis.updateWorkspace({ - id: workspace.id, - public: flag, - }) - ) - .then(data => { - setPublicStatus(data?.public); - toast('Updated Public Status Success'); - }); + // getDataCenter() + // .then(dc => + // dc.apis.updateWorkspace({ + // id: workspace.id, + // public: flag, + // }) + // ) + // .then(data => { + // setPublicStatus(data?.public); + // toast('Updated Public Status Success'); + // }); }; const copyUrl = () => { navigator.clipboard.writeText(shareUrl); diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx index 8e101307bb..5a35becfcf 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx @@ -54,9 +54,9 @@ export const SelectorPopperContent = ({ if (type === WorkspaceType.Private) { return { id, member_count: 1, owner: user }; } else { - const dc = await getDataCenter(); - const data = await dc.apis.getWorkspaceDetail({ id }); - return { id, ...data } || { id, member_count: 0, owner: user }; + // const dc = await getDataCenter(); + // const data = await dc.apis.getWorkspaceDetail({ id }); + // return { id, ...data } || { id, member_count: 0, owner: user }; } } }) diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/workspace-create.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/workspace-create.tsx index b07fdeecac..23434c28d2 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/workspace-create.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/workspace-create.tsx @@ -52,10 +52,10 @@ export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => { ctx.fillText(workspaceName[0], 50, 50); canvas.toBlob(blob => { if (blob) { - const blobId = getDataCenter().then(dc => - dc.apis.uploadBlob({ blob }) - ); - resolve(blobId); + // const blobId = getDataCenter().then(dc => + // dc.apis.uploadBlob({ blob }) + // ); + // resolve(blobId); } else { reject(); } @@ -71,23 +71,23 @@ export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => { setCreating(false); }); if (blobId) { - getDataCenter() - .then(dc => - dc.apis.createWorkspace({ name: workspaceName, avatar: blobId }) - ) - .then(async data => { - await refreshWorkspacesMeta(); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - router.push(`/workspace/${data.id}`); - onClose(); - }) - .catch(err => { - console.log(err, 'err'); - }) - .finally(() => { - setCreating(false); - }); + // getDataCenter() + // .then(dc => + // dc.apis.createWorkspace({ name: workspaceName, avatar: blobId }) + // ) + // .then(async data => { + // await refreshWorkspacesMeta(); + // // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // // @ts-ignore + // router.push(`/workspace/${data.id}`); + // onClose(); + // }) + // .catch(err => { + // console.log(err, 'err'); + // }) + // .finally(() => { + // setCreating(false); + // }); } }; return ( diff --git a/packages/app/src/pages/invite/[invite_code].tsx b/packages/app/src/pages/invite/[invite_code].tsx index c6ef0b6b4e..91488a7397 100644 --- a/packages/app/src/pages/invite/[invite_code].tsx +++ b/packages/app/src/pages/invite/[invite_code].tsx @@ -24,19 +24,19 @@ export default function DevPage() { // eslint-disable-next-line @typescript-eslint/no-explicit-any const [inviteData, setInviteData] = useState(null); useEffect(() => { - getDataCenter() - .then(dc => - dc.apis.acceptInviting({ - invitingCode: router.query.invite_code as string, - }) - ) - .then(data => { - setSuccessInvited(true); - setInviteData(data); - }) - .catch(err => { - console.log('err: ', err); - }); + // getDataCenter() + // .then(dc => + // dc.apis.acceptInviting({ + // invitingCode: router.query.invite_code as string, + // }) + // ) + // .then(data => { + // setSuccessInvited(true); + // setInviteData(data); + // }) + // .catch(err => { + // console.log('err: ', err); + // }); }, [router.query.invite_code]); return ( diff --git a/packages/data-center/src/provider/affine/apis/business.ts b/packages/data-center/src/provider/affine/apis/business.ts deleted file mode 100644 index 11a4720851..0000000000 --- a/packages/data-center/src/provider/affine/apis/business.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { uuidv4 } from '@blocksuite/store'; -// import { getDataCenter } from '.'; -// import { DataCenter } from './datacenter'; -// import { Workspace } from '../types'; - -// export class Business { -// private _dc: DataCenter | undefined; - -// private async _getDc() { -// if (!this._dc) { -// this._dc = await getDataCenter(); -// } -// return this._dc; -// } - -// // async createWorkspace( -// // name: string -// // ): Promise> { -// // let id = ''; -// // let type = WorkspaceType.local; -// // this._dc?.load(uuidv4()); -// // const newWorkspaces = (await this.getWorkspaces()).find(w => w.id === id); -// // return { -// // id: newWorkspaces?.id || '', -// // name, -// // avatar: '', -// // type, -// // }; -// // } - -// // not think out a good way to update workspace meta -// // updateWorkspaceMeta( -// // id: string, -// // meta: { name?: string; avatar: Partial } -// // ) {} - -// // async getWorkspaces(focusUpdated?: boolean): Promise { -// // const dc = await this._getDc(); -// // if (focusUpdated) { -// // await dc.workspacesList.refreshWorkspaceList(); -// // } -// // return dc.workspacesList.getWorkspaces(); -// // } - -// /** -// * Get page list by workspace id -// * @param {string} id ID of workspace. -// */ -// getPagesByWorkspaceId(id: string) { -// return []; -// } - -// /** -// * Observe the update of the workspace -// * @param {function} callback({Workspace[]}). -// */ -// async onWorkspaceChange(cb: (workspaces: Workspace[]) => void) { -// const dc = await this._getDc(); -// dc.workspacesList.on('change', cb); -// } - -// async deleteWorkspace(id: string) { -// const dc = await this._getDc(); -// const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); -// if (workspace?.type === WorkspaceType.cloud) { -// dc.apis.deleteWorkspace({ id }); -// } -// dc.delete(id); -// } - -// /** -// * The member of the workspace go to leave workspace -// * @param {string} id ID of workspace. -// */ -// async leaveWorkspace(id: string) { -// const dc = await this._getDc(); -// const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); -// if (workspace?.type === WorkspaceType.cloud) { -// dc.apis.leaveWorkspace({ id }); -// dc.delete(id); -// } -// } - -// /** -// * Let the workspace to be public -// * @param {string} id ID of workspace. -// * @param {string} isPublish publish flag of workspace. -// */ -// setWorkspacePublish(id: string, isPublish: boolean): boolean { -// return isPublish; -// } - -// /** -// * Get workspace by workspace id -// * @param {string} id ID of workspace. -// */ -// async getWorkspaceById(id: string) { -// const dc = await this._getDc(); -// const workspace = dc.workspacesList.getWorkspaces().find(w => w.id === id); -// if (workspace?.type === WorkspaceType.cloud) { -// return dc.load(id, { providerId: 'affine' }); -// } else { -// return dc.load(id, { providerId: 'local' }); -// } -// } - -// // no time -// /** -// * Get the members of the workspace -// * @param {string} id ID of workspace. -// */ -// getMembers(id: string): any { -// void 0; -// } -// /** -// * Add a new member to the workspace -// * @param {string} id ID of workspace. -// * @param {string} email new member email. -// */ -// inviteMember(id: string, email: string) { -// void 0; -// } - -// /** -// * remove the new member to the workspace -// * @param {string} workspaceId ID of workspace. -// * @param {string} memberId ID of member -// */ -// removeMember(workspaceId: string, memberId: string) { -// void 0; -// } - -// /** -// * A new member click the invite link, finish to join the workspace -// * @param {string} inviteCode token for invitation. -// */ -// async acceptInvitation(invitingCode: string) { -// const dc = await this._getDc(); -// dc.apis.acceptInviting({ invitingCode }); -// } - -// // check with dark sky -// /** -// * Get login user info -// */ -// getUserInfo() { -// void 0; -// } - -// // TODO check with dark sky -// async login() { -// const dc = await this._getDc(); -// await dc.auth('affine'); -// } - -// // just has no time -// /** -// * Logout and clear login session -// */ -// logout() { -// void 0; -// } - -// // need discuss -// /** -// * Create a connection between local and cloud, sync cloud data to local -// * @param {string} id ID of workspace. -// * @param {string} id type of workspace. -// */ -// // setWorkspaceSyncType(id: string, type: 'local' | 'cloud') {} - -// // need discuss -// /** -// * Select a file to import the workspace -// * @param {File} file file of workspace. -// */ -// importWorkspace(file: File) { -// void 0; -// } - -// // need discuss may be not in apis -// // /** -// // * Generate a file ,and export it to local file system -// // * @param {string} id ID of workspace. -// // */ -// exportWorkspace(id: string) { -// void 0; -// } - -// // need discuss -// // /** -// // * Enable workspace cloud flag -// // * @param {string} id ID of workspace. -// // */ -// enableWorkspaceCloud(id: string) { -// void 0; -// } -// } From e46cf6c543890c395386a38de9c9144a5a22c822 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 11:34:26 +0800 Subject: [PATCH 063/298] feat: add blob apis --- packages/data-center/src/datacenter.ts | 43 ++++++++++++++++++- .../data-center/src/provider/affine/affine.ts | 19 +++++++- packages/data-center/src/provider/base.ts | 19 +++++++- .../data-center/src/provider/local/local.ts | 3 +- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 5714fe98fa..92785e7e6c 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -1,10 +1,10 @@ import { Workspaces } from './workspaces'; import type { WorkspacesChangeEvent } from './workspaces'; -import { Workspace } from '@blocksuite/store'; +import { BlobStorage, Workspace } from '@blocksuite/store'; import { BaseProvider } from './provider/base'; import { LocalProvider } from './provider/local/local'; import { AffineProvider } from './provider'; -import type { Workspace as WS, WorkspaceMeta } from './types'; +import type { WorkspaceMeta } from './types'; import assert from 'assert'; import { getLogger } from './logger'; import { BlockSchema } from '@blocksuite/blocks/models'; @@ -17,6 +17,7 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; export class DataCenter { private readonly _workspaces = new Workspaces(); private readonly _logger = getLogger('dc'); + private readonly _blobStorage: BlobStorage = new BlobStorage(); /** * A mainProvider must exist as the only data trustworthy source. */ @@ -34,12 +35,14 @@ export class DataCenter { new LocalProvider({ logger: dc._logger, workspaces: dc._workspaces.createScope(), + blobs: dc._blobStorage, }) ); dc.registerProvider( new AffineProvider({ logger: dc._logger, workspaces: dc._workspaces.createScope(), + blobs: dc._blobStorage, }) ); @@ -247,6 +250,24 @@ export class DataCenter { } } + /** + * get user info by email + * @param workspaceId + * @param email + * @param provider + * @returns {Promise} User info + */ + public async getUserByEmail( + workspaceId: string, + email: string, + provider = 'affine' + ) { + const providerInstance = this.providerMap.get(provider); + if (providerInstance) { + return await providerInstance.getUserByEmail(workspaceId, email); + } + } + private async _transWorkspaceProvider( workspace: Workspace, providerId: string @@ -312,4 +333,22 @@ export class DataCenter { id; return; } + + /** + * get blob url by workspaces id + * @param id + * @returns {Promise} blob url + */ + async getBlob(id: string): Promise { + return await this._blobStorage.get(id); + } + + /** + * up load blob and get a blob url + * @param id + * @returns {Promise} blob url + */ + async setBlob(blob: Blob): Promise { + return await this._blobStorage.set(blob); + } } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index b9f168a328..0f78ba7048 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -23,6 +23,7 @@ import { getAuthorizer } from './apis/token'; import { WebsocketProvider } from './sync'; import { IndexedDBProvider } from '../indexeddb'; import { getDefaultHeadImgBlob } from '../../utils'; +import { getUserByEmail } from './apis/user'; export class AffineProvider extends BaseProvider { public id = 'affine'; @@ -248,7 +249,8 @@ export class AffineProvider extends BaseProvider { if (!meta.avatar) { // set default avatar const blob = await getDefaultHeadImgBlob(meta.name); - meta.avatar = (await this.setBlob(blob)) || ''; + const blobId = await this.setBlob(blob); + meta.avatar = (await this.getBlob(blobId)) || ''; } const { id } = await createWorkspace(meta as Required); this._logger('Creating affine workspace'); @@ -277,4 +279,19 @@ export class AffineProvider extends BaseProvider { public override async publish(id: string, isPublish: boolean): Promise { await updateWorkspace({ id, public: isPublish }); } + + public override async getUserByEmail( + workspace_id: string, + email: string + ): Promise { + const user = await getUserByEmail({ workspace_id, email }); + return user + ? { + id: user.id, + name: user.name, + avatar: user.avatar_url, + email: user.email, + } + : null; + } } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 40572a136a..62fc943ebd 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -9,6 +9,7 @@ const defaultLogger = () => { export interface ProviderConstructorParams { logger?: Logger; workspaces: WorkspacesScope; + blobs: BlobStorage; } export class BaseProvider { @@ -17,9 +18,10 @@ export class BaseProvider { protected _logger!: Logger; protected _blobs!: BlobStorage; - public constructor({ logger, workspaces }: ProviderConstructorParams) { + public constructor({ logger, workspaces, blobs }: ProviderConstructorParams) { this._logger = (logger || defaultLogger) as Logger; this._workspaces = workspaces; + this._blobs = blobs; } /** @@ -149,10 +151,25 @@ export class BaseProvider { return; } + /** + * create workspace by workspace meta + * @param {WorkspaceMeta} meta + */ public async createWorkspace( meta: WorkspaceMeta ): Promise { meta; return; } + + /** + * get user by email + * @param {string} id + * @param {string} email + * @returns + */ + public async getUserByEmail(id: string, email: string): Promise { + email; + return null; + } } diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index a01d516a35..8454f212b5 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -82,7 +82,8 @@ export class LocalProvider extends BaseProvider { if (!meta.avatar) { // set default avatar const blob = await getDefaultHeadImgBlob(meta.name); - meta.avatar = (await this.setBlob(blob)) || ''; + const blobId = await this.setBlob(blob); + meta.avatar = (await this.getBlob(blobId)) || ''; } this._logger('Creating affine workspace'); From 84bea549169b4a849994c6d55ac2a237cccd8a18 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 12:02:09 +0800 Subject: [PATCH 064/298] feat: rm business --- packages/data-center/src/datacenter.ts | 3 ++- packages/data-center/src/provider/affine/apis/index.ts | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 92785e7e6c..2fc9431e93 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -12,7 +12,7 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; /** * @class DataCenter - * @classdesc DataCenter is a data center, it can manage different providers for business + * @classdesc Data center is made for managing different providers for business */ export class DataCenter { private readonly _workspaces = new Workspaces(); @@ -284,6 +284,7 @@ export class DataCenter { const newProvider = this.providerMap.get(providerId); assert(newProvider, `provide '${providerId}' is not registered`); this._logger(`create ${providerId} workspace: `, workspaceInfo.name); + // TODO optimize this function const newWorkspace = await newProvider.createWorkspace({ name: workspaceInfo.name, avatar: workspaceInfo.avatar, diff --git a/packages/data-center/src/provider/affine/apis/index.ts b/packages/data-center/src/provider/affine/apis/index.ts index 57c003d8fd..28e49b02a7 100644 --- a/packages/data-center/src/provider/affine/apis/index.ts +++ b/packages/data-center/src/provider/affine/apis/index.ts @@ -4,11 +4,9 @@ export type { Callback } from './token.js'; import { getAuthorizer } from './token.js'; import * as user from './user.js'; import * as workspace from './workspace.js'; -import * as business from './business.js'; export type Apis = typeof user & typeof workspace & { - business: typeof business; signInWithGoogle: ReturnType[0]; onAuthStateChanged: ReturnType[1]; }; @@ -18,7 +16,6 @@ export const getApis = (): Apis => { return { ...user, ...workspace, - business, signInWithGoogle, onAuthStateChanged, }; From 7f8a577bd2984880ad302364aaa4bfec3e028dba Mon Sep 17 00:00:00 2001 From: JimmFly Date: Mon, 9 Jan 2023 12:07:17 +0800 Subject: [PATCH 065/298] chore: update i18n keys --- .../src/components/create-workspace/index.tsx | 11 +- .../src/components/edgeless-toolbar/index.tsx | 124 +++++++++--------- .../app/src/components/file-upload/index.tsx | 4 +- .../header-right-items/trash-button-group.tsx | 14 +- packages/app/src/libs/i18n/resources/en.json | 18 ++- 5 files changed, 95 insertions(+), 76 deletions(-) diff --git a/packages/app/src/components/create-workspace/index.tsx b/packages/app/src/components/create-workspace/index.tsx index d2decdfe4e..05c37f9900 100644 --- a/packages/app/src/components/create-workspace/index.tsx +++ b/packages/app/src/components/create-workspace/index.tsx @@ -5,6 +5,7 @@ import { useState } from 'react'; import Input from '@/ui/input'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { KeyboardEvent } from 'react'; +import { useTranslation } from 'react-i18next'; interface ICloseParams { workspaceId?: string; } @@ -27,12 +28,13 @@ export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { handleCreateWorkspace(); } }; + const { t } = useTranslation(); return (
    - New Workspace + {t('New Workspace')} { />
    -

    - Workspace is your virtual space to capture, create and plan as - just one person or together as a team. -

    +

    {t('Workspace description')}

    { @@ -57,7 +56,7 @@ export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { handleCreateWorkspace(); }} > - Create + {t('Create')}
    diff --git a/packages/app/src/components/edgeless-toolbar/index.tsx b/packages/app/src/components/edgeless-toolbar/index.tsx index c44f6396ca..697c5a6261 100644 --- a/packages/app/src/components/edgeless-toolbar/index.tsx +++ b/packages/app/src/components/edgeless-toolbar/index.tsx @@ -19,73 +19,77 @@ import Slide from '@mui/material/Slide'; import useCurrentPageMeta from '@/hooks/use-current-page-meta'; import { useAppState } from '@/providers/app-state-provider'; import useHistoryUpdated from '@/hooks/use-history-update'; +import { useTranslation } from 'react-i18next'; -const toolbarList1 = [ - { - flavor: 'select', - icon: , - toolTip: 'Select', - disable: false, - callback: () => { - window.dispatchEvent( - new CustomEvent('affine.switch-mouse-mode', { - detail: { - type: 'default', - }, - }) - ); +const useToolbarList1 = () => { + const { t } = useTranslation(); + return [ + { + flavor: 'select', + icon: , + toolTip: t('Select'), + disable: false, + callback: () => { + window.dispatchEvent( + new CustomEvent('affine.switch-mouse-mode', { + detail: { + type: 'default', + }, + }) + ); + }, }, - }, - { - flavor: 'text', - icon: , - toolTip: 'Text (coming soon)', - disable: true, - }, - { - flavor: 'shape', - icon: , - toolTip: 'Shape', - disable: false, - callback: () => { - window.dispatchEvent( - new CustomEvent('affine.switch-mouse-mode', { - detail: { - type: 'shape', - color: 'black', - shape: 'rectangle', - }, - }) - ); + { + flavor: 'text', + icon: , + toolTip: t('Text'), + disable: true, + }, + { + flavor: 'shape', + icon: , + toolTip: t('Shape'), + disable: false, + callback: () => { + window.dispatchEvent( + new CustomEvent('affine.switch-mouse-mode', { + detail: { + type: 'shape', + color: 'black', + shape: 'rectangle', + }, + }) + ); + }, + }, + { + flavor: 'sticky', + icon: , + toolTip: t('Sticky'), + disable: true, + }, + { + flavor: 'pen', + icon: , + toolTip: t('Pen'), + disable: true, }, - }, - { - flavor: 'sticky', - icon: , - toolTip: 'Sticky (coming soon)', - disable: true, - }, - { - flavor: 'pen', - icon: , - toolTip: 'Pen (coming soon)', - disable: true, - }, - { - flavor: 'connector', - icon: , - toolTip: 'Connector (coming soon)', - disable: true, - }, -]; + { + flavor: 'connector', + icon: , + toolTip: t('Connector'), + disable: true, + }, + ]; +}; const UndoRedo = () => { const [canUndo, setCanUndo] = useState(false); const [canRedo, setCanRedo] = useState(false); const { currentPage } = useAppState(); const onHistoryUpdated = useHistoryUpdated(); - + const { t } = useTranslation(); useEffect(() => { onHistoryUpdated(page => { setCanUndo(page.canUndo); @@ -95,7 +99,7 @@ const UndoRedo = () => { return ( - + { @@ -105,7 +109,7 @@ const UndoRedo = () => { - + { @@ -131,7 +135,7 @@ export const EdgelessToolbar = () => { > - {toolbarList1.map( + {useToolbarList1().map( ({ icon, toolTip, flavor, disable, callback }, index) => { return ( diff --git a/packages/app/src/components/file-upload/index.tsx b/packages/app/src/components/file-upload/index.tsx index 25d91fb06d..090d628b22 100644 --- a/packages/app/src/components/file-upload/index.tsx +++ b/packages/app/src/components/file-upload/index.tsx @@ -1,6 +1,7 @@ import { Button } from '@/ui/button'; import { FC, useRef, ChangeEvent, ReactElement } from 'react'; import { styled } from '@/styles'; +import { useTranslation } from 'react-i18next'; interface Props { uploadType?: string; children?: ReactElement; @@ -9,6 +10,7 @@ interface Props { } export const Upload: FC = props => { const { fileChange, accept } = props; + const { t } = useTranslation(); const input_ref = useRef(null); const _chooseFile = () => { if (input_ref.current) { @@ -28,7 +30,7 @@ export const Upload: FC = props => { }; return ( - {props.children ?? } + {props.children ?? } { const { permanentlyDeletePage } = usePageHelper(); @@ -12,7 +13,7 @@ export const TrashButtonGroup = () => { const { confirm } = useConfirm(); const router = useRouter(); const { id = '' } = useCurrentPageMeta() || {}; - + const { t } = useTranslation(); return ( <> ); diff --git a/packages/app/src/libs/i18n/resources/en.json b/packages/app/src/libs/i18n/resources/en.json index 9ce5282e71..a4be5ecf05 100644 --- a/packages/app/src/libs/i18n/resources/en.json +++ b/packages/app/src/libs/i18n/resources/en.json @@ -34,7 +34,7 @@ "Delete page?": "Delete page?", "Delete permanently?": "Delete permanently?", "will be moved to Trash": "{{title}} will be moved to Trash", - "Once deleted, you can't undo this action.": "Once deleted,you can't undo this action.", + "Once deleted, you can't undo this action.": "Once deleted, you can't undo this action.", "Moved to Trash": "Moved to Trash", "Permanently deleted": "Permanently deleted", "restored": "{{title}} restored", @@ -61,5 +61,19 @@ "Reduce indent": "Reduce indent", "Markdown Syntax": "Markdown Syntax", "Divider": "Divider", - "404 - Page Not Found": "404 - Page Not Found" + "404 - Page Not Found": "404 - Page Not Found", + "New Workspace": "New Workspace", + "Workspace description": "Workspace is your virtual space to capture, create and plan as just one person or together as a team.", + "Create": "Create", + "Select": "Select", + "Text": "Text (coming soon)", + "Shape": "Shape", + "Sticky": "Sticky (coming soon)", + "Pen": "Pen (coming soon)", + "Connector": "Connector (coming soon)", + "Upload": "Upload", + "Restore it": "Restore it", + "TrashButtonGroupTitle": "Permanently delete", + "TrashButtonGroupDescription": "Once deleted, you can't undo this action. Do you confirm?", + "Delete permanently": "Delete permanently" } From 2ff46fa831ffa08ed89006175b8c152fae4cefb9 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 13:58:53 +0800 Subject: [PATCH 066/298] feat: fix type problem --- .../src/provider/local/local.spec.ts | 3 + .../src/provider/selfhosted/index.ts | 63 ------------------- .../src/provider/selfhosted/index.ts.bk | 63 +++++++++++++++++++ 3 files changed, 66 insertions(+), 63 deletions(-) delete mode 100644 packages/data-center/src/provider/selfhosted/index.ts create mode 100644 packages/data-center/src/provider/selfhosted/index.ts.bk diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts index 442263c070..72803370ba 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -2,11 +2,13 @@ import { describe, test, expect } from 'vitest'; import { Workspaces } from '../../workspaces'; import { LocalProvider } from './local'; import 'fake-indexeddb/auto'; +import { BlobStorage } from '@blocksuite/store'; describe('local provider', () => { const workspaces = new Workspaces(); const provider = new LocalProvider({ workspaces: workspaces.createScope(), + blobs: new BlobStorage(), }); const workspaceName = 'workspace-test'; @@ -27,6 +29,7 @@ describe('local provider', () => { const workspaces1 = new Workspaces(); const provider1 = new LocalProvider({ workspaces: workspaces1.createScope(), + blobs: new BlobStorage(), }); await provider1.loadWorkspaces(); expect(workspaces1.workspaces.length).toEqual(1); diff --git a/packages/data-center/src/provider/selfhosted/index.ts b/packages/data-center/src/provider/selfhosted/index.ts deleted file mode 100644 index 48632480ef..0000000000 --- a/packages/data-center/src/provider/selfhosted/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -import assert from 'assert'; - -import { LocalProvider } from '../local/index.js'; -import { WebsocketProvider } from './sync.js'; - -export class SelfHostedProvider extends LocalProvider { - static id = 'selfhosted'; - private _ws?: WebsocketProvider; - - constructor() { - super(); - } - - async destroy() { - this._ws?.disconnect(); - } - - async initData() { - const databases = await indexedDB.databases(); - await super.initData( - // set locally to true if exists a same name db - databases - .map(db => db.name) - .filter(v => v) - .includes(this._workspace.room) - ); - - const workspace = this._workspace; - const doc = workspace.doc; - - if (workspace.room) { - try { - // Wait for ws synchronization to complete, otherwise the data will be modified in reverse, which can be optimized later - this._ws = new WebsocketProvider(this.host, workspace.room, doc); - await new Promise((resolve, reject) => { - // TODO: synced will also be triggered on reconnection after losing sync - // There needs to be an event mechanism to emit the synchronization state to the upper layer - assert(this._ws); - this._ws.once('synced', () => resolve()); - this._ws.once('lost-connection', () => resolve()); - this._ws.once('connection-error', () => reject()); - }); - this._signals.listAdd.emit({ - workspace: workspace.room, - provider: this.id, - locally: true, - }); - } catch (e) { - this._logger('Failed to init cloud workspace', e); - } - } - - // if after update, the space:meta is empty - // then we need to get map with doc - // just a workaround for yjs - doc.getMap('space:meta'); - } - - private get host() { - const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; - return `${protocol}//${location.host}/collaboration/`; - } -} diff --git a/packages/data-center/src/provider/selfhosted/index.ts.bk b/packages/data-center/src/provider/selfhosted/index.ts.bk new file mode 100644 index 0000000000..c74a13cf81 --- /dev/null +++ b/packages/data-center/src/provider/selfhosted/index.ts.bk @@ -0,0 +1,63 @@ +// import assert from 'assert'; + +// import { LocalProvider } from '../local/index.js'; +// import { WebsocketProvider } from './sync.js'; + +// export class SelfHostedProvider extends LocalProvider { +// static id = 'selfhosted'; +// private _ws?: WebsocketProvider; + +// constructor() { +// super(); +// } + +// async destroy() { +// this._ws?.disconnect(); +// } + +// async initData() { +// const databases = await indexedDB.databases(); +// await super.initData( +// // set locally to true if exists a same name db +// databases +// .map(db => db.name) +// .filter(v => v) +// .includes(this._workspace.room) +// ); + +// const workspace = this._workspace; +// const doc = workspace.doc; + +// if (workspace.room) { +// try { +// // Wait for ws synchronization to complete, otherwise the data will be modified in reverse, which can be optimized later +// this._ws = new WebsocketProvider(this.host, workspace.room, doc); +// await new Promise((resolve, reject) => { +// // TODO: synced will also be triggered on reconnection after losing sync +// // There needs to be an event mechanism to emit the synchronization state to the upper layer +// assert(this._ws); +// this._ws.once('synced', () => resolve()); +// this._ws.once('lost-connection', () => resolve()); +// this._ws.once('connection-error', () => reject()); +// }); +// this._signals.listAdd.emit({ +// workspace: workspace.room, +// provider: this.id, +// locally: true, +// }); +// } catch (e) { +// this._logger('Failed to init cloud workspace', e); +// } +// } + +// // if after update, the space:meta is empty +// // then we need to get map with doc +// // just a workaround for yjs +// doc.getMap('space:meta'); +// } + +// private get host() { +// const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; +// return `${protocol}//${location.host}/collaboration/`; +// } +// } From ae88dbd7171264d7055ae9a82edcad07e95e19bd Mon Sep 17 00:00:00 2001 From: QiShaoXuan Date: Mon, 9 Jan 2023 14:23:01 +0800 Subject: [PATCH 067/298] feat: add pacakge module --- packages/data-center/package.json | 5 +- pnpm-lock.yaml | 1449 ++++++++++++++++++++++++++--- 2 files changed, 1325 insertions(+), 129 deletions(-) diff --git a/packages/data-center/package.json b/packages/data-center/package.json index fe639b306e..76d234439e 100644 --- a/packages/data-center/package.json +++ b/packages/data-center/package.json @@ -36,7 +36,8 @@ "ky-universal": "^0.11.0", "lib0": "^0.2.58", "swr": "^2.0.0", - "yjs": "^13.5.44", - "y-protocols": "^1.0.5" + "vitest": "^0.26.3", + "y-protocols": "^1.0.5", + "yjs": "^13.5.44" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55cf7d85c1..7af385e9a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,7 @@ importers: .: specifiers: '@changesets/cli': ^2.26.0 + '@jest/globals': ^29.3.1 '@playwright/test': ^1.29.1 '@types/eslint': ^8.4.10 '@types/node': ^18.11.17 @@ -17,12 +18,14 @@ importers: fake-indexeddb: 4.0.1 got: ^12.5.3 husky: ^8.0.2 + jest: ^29.3.1 lint-staged: ^13.1.0 prettier: ^2.7.1 + ts-jest: ^29.0.3 typescript: ^4.9.3 - vitest: ^0.26.3 devDependencies: '@changesets/cli': 2.26.0 + '@jest/globals': 29.3.1 '@playwright/test': 1.29.1 '@types/eslint': 8.4.10 '@types/node': 18.11.18 @@ -35,10 +38,11 @@ importers: fake-indexeddb: 4.0.1 got: 12.5.3 husky: 8.0.2 + jest: 29.3.1_@types+node@18.11.18 lint-staged: 13.1.0 prettier: 2.7.1 + ts-jest: 29.0.3_4f6uxrzmuwipl5rr3bcogf6k74 typescript: 4.9.3 - vitest: 0.26.3 packages/app: specifiers: @@ -143,6 +147,7 @@ importers: lib0: ^0.2.58 swr: ^2.0.0 typescript: ^4.8.4 + vitest: ^0.26.3 y-protocols: ^1.0.5 yjs: ^13.5.44 dependencies: @@ -156,6 +161,7 @@ importers: ky-universal: 0.11.0_ky@0.33.1 lib0: 0.2.58 swr: 2.0.0 + vitest: 0.26.3 y-protocols: 1.0.5 yjs: 13.5.44 devDependencies: @@ -753,6 +759,15 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: true + /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.20.5: + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.5 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.20.5: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -800,6 +815,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.20.5: + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.5 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.20.5: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: @@ -818,6 +842,16 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: false + /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.20.5: + resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.5 + '@babel/helper-plugin-utils': 7.19.0 + dev: true + /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.20.5: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: @@ -892,6 +926,16 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: true + /@babel/plugin-syntax-typescript/7.20.0_@babel+core@7.20.5: + resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.5 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-arrow-functions/7.20.7_@babel+core@7.20.5: resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} engines: {node: '>=6.9.0'} @@ -1443,6 +1487,10 @@ packages: to-fast-properties: 2.0.0 dev: true + /@bcoe/v8-coverage/0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + /@blocksuite/blocks/0.3.1-20230106060050-1aad55d_yjs@13.5.44: resolution: {integrity: sha512-qRNXmhjw+GAGsV1mI2XXPxYTlHfsFHv9ttTCNQ6IIcxvc5Hh6lWmdwVibxvlpYUkgEc1zv3/GxOEsR/ngpZXzQ==} dependencies: @@ -1905,202 +1953,202 @@ packages: resolution: {integrity: sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==} dev: false - /@esbuild/android-arm/0.16.15: - resolution: {integrity: sha512-JsJtmadyWcR+DEtHLixM7bAQsfi1s0Xotv9kVOoXbCLyhKPOHvMEyh3kJBuTbCPSE4c2jQkQVmarwc9Mg9k3bA==} + /@esbuild/android-arm/0.16.16: + resolution: {integrity: sha512-BUuWMlt4WSXod1HSl7aGK8fJOsi+Tab/M0IDK1V1/GstzoOpqc/v3DqmN8MkuapPKQ9Br1WtLAN4uEgWR8x64A==} engines: {node: '>=12'} cpu: [arm] os: [android] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/android-arm64/0.16.15: - resolution: {integrity: sha512-OdbkUv7468dSsgoFtHIwTaYAuI5lDEv/v+dlfGBUbVa2xSDIIuSOHXawynw5N9+5lygo/JdXa5/sgGjiEU18gQ==} + /@esbuild/android-arm64/0.16.16: + resolution: {integrity: sha512-hFHVAzUKp9Tf8psGq+bDVv+6hTy1bAOoV/jJMUWwhUnIHsh6WbFMhw0ZTkqDuh7TdpffFoHOiIOIxmHc7oYRBQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/android-x64/0.16.15: - resolution: {integrity: sha512-dPUOBiNNWAm+/bxoA75o7R7qqqfcEzXaYlb5uJk2xGHmUMNKSAnDCtRYLgx9/wfE4sXyn8H948OrDyUAHhPOuA==} + /@esbuild/android-x64/0.16.16: + resolution: {integrity: sha512-9WhxJpeb6XumlfivldxqmkJepEcELekmSw3NkGrs+Edq6sS5KRxtUBQuKYDD7KqP59dDkxVbaoPIQFKWQG0KLg==} engines: {node: '>=12'} cpu: [x64] os: [android] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/darwin-arm64/0.16.15: - resolution: {integrity: sha512-AksarYV85Hxgwh5/zb6qGl4sYWxIXPQGBAZ+jUro1ZpINy3EWumK+/4DPOKUBPnsrOIvnNXy7Rq4mTeCsMQDNA==} + /@esbuild/darwin-arm64/0.16.16: + resolution: {integrity: sha512-8Z+wld+vr/prHPi2O0X7o1zQOfMbXWGAw9hT0jEyU/l/Yrg+0Z3FO9pjPho72dVkZs4ewZk0bDOFLdZHm8jEfw==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/darwin-x64/0.16.15: - resolution: {integrity: sha512-qqrKJxoohceZGGP+sZ5yXkzW9ZiyFZJ1gWSEfuYdOWzBSL18Uy3w7s/IvnDYHo++/cxwqM0ch3HQVReSZy7/4Q==} + /@esbuild/darwin-x64/0.16.16: + resolution: {integrity: sha512-CYkxVvkZzGCqFrt7EgjFxQKhlUPyDkuR9P0Y5wEcmJqVI8ncerOIY5Kej52MhZyzOBXkYrJgZeVZC9xXXoEg9A==} engines: {node: '>=12'} cpu: [x64] os: [darwin] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/freebsd-arm64/0.16.15: - resolution: {integrity: sha512-LBWaep6RvJm5KnsKkocdVEzuwnGMjz54fcRVZ9d3R7FSEWOtPBxMhuxeA1n98JVbCLMkTPFmKN6xSnfhnM9WXQ==} + /@esbuild/freebsd-arm64/0.16.16: + resolution: {integrity: sha512-fxrw4BYqQ39z/3Ja9xj/a1gMsVq0xEjhSyI4a9MjfvDDD8fUV8IYliac96i7tzZc3+VytyXX+XNsnpEk5sw5Wg==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/freebsd-x64/0.16.15: - resolution: {integrity: sha512-LE8mKC6JPR04kPLRP9A6k7ZmG0k2aWF4ru79Sde6UeWCo7yDby5f48uJNFQ2pZqzUUkLrHL8xNdIHerJeZjHXg==} + /@esbuild/freebsd-x64/0.16.16: + resolution: {integrity: sha512-8p3v1D+du2jiDvSoNVimHhj7leSfST9YlKsAEO7etBfuqjaBMndo0fmjNLp0JCMld+XIx9L80tooOkyUv1a1PQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-arm/0.16.15: - resolution: {integrity: sha512-+1sGlqtMJTOnJUXwLUGnDhPaGRKqxT0UONtYacS+EjdDOrSgpQ/1gUXlnze45Z/BogwYaswQM19Gu1YD1T19/w==} + /@esbuild/linux-arm/0.16.16: + resolution: {integrity: sha512-bYaocE1/PTMRmkgSckZ0D0Xn2nox8v2qlk+MVVqm+VECNKDdZvghVZtH41dNtBbwADSvA6qkCHGYeWm9LrNCBw==} engines: {node: '>=12'} cpu: [arm] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-arm64/0.16.15: - resolution: {integrity: sha512-mRYpuQGbzY+XLczy3Sk7fMJ3DRKLGDIuvLKkkUkyecDGQMmil6K/xVKP9IpKO7JtNH477qAiMjjX7jfKae8t4g==} + /@esbuild/linux-arm64/0.16.16: + resolution: {integrity: sha512-N3u6BBbCVY3xeP2D8Db7QY8I+nZ+2AgOopUIqk+5yCoLnsWkcVxD2ay5E9iIdvApFi1Vg1lZiiwaVp8bOpAc4A==} engines: {node: '>=12'} cpu: [arm64] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-ia32/0.16.15: - resolution: {integrity: sha512-puXVFvY4m8EB6/fzu3LdgjiNnEZ3gZMSR7NmKoQe51l3hyQalvTjab3Dt7aX4qGf+8Pj7dsCOBNzNzkSlr/4Aw==} + /@esbuild/linux-ia32/0.16.16: + resolution: {integrity: sha512-dxjqLKUW8GqGemoRT9v8IgHk+T4tRm1rn1gUcArsp26W9EkK/27VSjBVUXhEG5NInHZ92JaQ3SSMdTwv/r9a2A==} engines: {node: '>=12'} cpu: [ia32] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-loong64/0.16.15: - resolution: {integrity: sha512-ATMGb3eg8T6ZTGZFldlGeFEcevBiVq6SBHvRAO04HMfUjZWneZ/U+JJb3YzlNZxuscJ4Tmzq+JrYxlk7ro4dRg==} + /@esbuild/linux-loong64/0.16.16: + resolution: {integrity: sha512-MdUFggHjRiCCwNE9+1AibewoNq6wf94GLB9Q9aXwl+a75UlRmbRK3h6WJyrSGA6ZstDJgaD2wiTSP7tQNUYxwA==} engines: {node: '>=12'} cpu: [loong64] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-mips64el/0.16.15: - resolution: {integrity: sha512-3SEA4L82OnoSATW+Ve8rPgLaKjC8WMt8fnx7De9kvi/NcVbkj8W+J7qnu/tK2P9pUPQP7Au/0sjPEqZtFeyKQQ==} + /@esbuild/linux-mips64el/0.16.16: + resolution: {integrity: sha512-CO3YmO7jYMlGqGoeFeKzdwx/bx8Vtq/SZaMAi+ZLDUnDUdfC7GmGwXzIwDJ70Sg+P9pAemjJyJ1icKJ9R3q/Fg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-ppc64/0.16.15: - resolution: {integrity: sha512-8PgbeX+N6vmqeySzyxO0NyDOltCEW13OS5jUHTvCHmCgf4kNXZtAWJ+zEfJxjRGYhVezQ1FdIm7WfN1R27uOyg==} + /@esbuild/linux-ppc64/0.16.16: + resolution: {integrity: sha512-DSl5Czh5hCy/7azX0Wl9IdzPHX2H8clC6G87tBnZnzUpNgRxPFhfmArbaHoAysu4JfqCqbB/33u/GL9dUgCBAw==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-riscv64/0.16.15: - resolution: {integrity: sha512-U+coqH+89vbPVoU30no1Fllrn6gvEeO5tfEArBhjYZ+dQ3Gv7ciQXYf5nrT1QdlIFwEjH4Is1U1iiaGWW+tGpQ==} + /@esbuild/linux-riscv64/0.16.16: + resolution: {integrity: sha512-sSVVMEXsqf1fQu0j7kkhXMViroixU5XoaJXl1u/u+jbXvvhhCt9YvA/B6VM3aM/77HuRQ94neS5bcisijGnKFQ==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-s390x/0.16.15: - resolution: {integrity: sha512-M0nKLFMdyFGBoitxG42kq6Xap0CPeDC6gfF9lg7ZejzGF6kqYUGT+pQGl2QCQoxJBeat/LzTma1hG8C3dq2ocg==} + /@esbuild/linux-s390x/0.16.16: + resolution: {integrity: sha512-jRqBCre9gZGoCdCN/UWCCMwCMsOg65IpY9Pyj56mKCF5zXy9d60kkNRdDN6YXGjr3rzcC4DXnS/kQVCGcC4yPQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/linux-x64/0.16.15: - resolution: {integrity: sha512-t7/fOXBUKfigvhJLGKZ9TPHHgqNgpIpYaAbcXQk1X+fPeUG7x0tpAbXJ2wST9F/gJ02+CLETPMnhG7Tra2wqsQ==} + /@esbuild/linux-x64/0.16.16: + resolution: {integrity: sha512-G1+09TopOzo59/55lk5Q0UokghYLyHTKKzD5lXsAOOlGDbieGEFJpJBr3BLDbf7cz89KX04sBeExAR/pL/26sA==} engines: {node: '>=12'} cpu: [x64] os: [linux] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/netbsd-x64/0.16.15: - resolution: {integrity: sha512-0k0Nxi6DOJmTnLtKD/0rlyqOPpcqONXY53vpkoAsue8CfyhNPWtwzba1ICFNCfCY1dqL3Ho/xEzujJhmdXq1rg==} + /@esbuild/netbsd-x64/0.16.16: + resolution: {integrity: sha512-xwjGJB5wwDEujLaJIrSMRqWkbigALpBNcsF9SqszoNKc+wY4kPTdKrSxiY5ik3IatojePP+WV108MvF6q6np4w==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/openbsd-x64/0.16.15: - resolution: {integrity: sha512-3SkckazfIbdSjsGpuIYT3d6n2Hx0tck3MS1yVsbahhWiLvdy4QozTpvlbjqO3GmvtvhxY4qdyhFOO2wiZKeTAQ==} + /@esbuild/openbsd-x64/0.16.16: + resolution: {integrity: sha512-yeERkoxG2nR2oxO5n+Ms7MsCeNk23zrby2GXCqnfCpPp7KNc0vxaaacIxb21wPMfXXRhGBrNP4YLIupUBrWdlg==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/sunos-x64/0.16.15: - resolution: {integrity: sha512-8PNvBC+O8X5EnyIGqE8St2bOjjrXMR17NOLenIrzolvwWnJXvwPo0tE/ahOeiAJmTOS/eAcN8b4LAZcn17Uj7w==} + /@esbuild/sunos-x64/0.16.16: + resolution: {integrity: sha512-nHfbEym0IObXPhtX6Va3H5GaKBty2kdhlAhKmyCj9u255ktAj0b1YACUs9j5H88NRn9cJCthD1Ik/k9wn8YKVg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/win32-arm64/0.16.15: - resolution: {integrity: sha512-YPaSgm/mm7kNcATB53OxVGVfn6rDNbImTn330ZlF3hKej1e9ktCaljGjn2vH08z2dlHEf3kdt57tNjE6zs8SzA==} + /@esbuild/win32-arm64/0.16.16: + resolution: {integrity: sha512-pdD+M1ZOFy4hE15ZyPX09fd5g4DqbbL1wXGY90YmleVS6Y5YlraW4BvHjim/X/4yuCpTsAFvsT4Nca2lbyDH/A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/win32-ia32/0.16.15: - resolution: {integrity: sha512-0movUXbSNrTeNf5ZXT0avklEvlJD0hNGZsrrXHfsp9z4tK5xC+apCqmUEZeE9mqrb84Z8XbgGr/MS9LqafTP2A==} + /@esbuild/win32-ia32/0.16.16: + resolution: {integrity: sha512-IPEMfU9p0c3Vb8PqxaPX6BM9rYwlTZGYOf9u+kMdhoILZkVKEjq6PKZO0lB+isojWwAnAqh4ZxshD96njTXajg==} engines: {node: '>=12'} cpu: [ia32] os: [win32] requiresBuild: true - dev: true + dev: false optional: true - /@esbuild/win32-x64/0.16.15: - resolution: {integrity: sha512-27h5GCcbfomVAqAnMJWvR1LqEY0dFqIq4vTe5nY3becnZNu0SX8F0+gTk3JPvgWQHzaGc6VkPzlOiMkdSUunUA==} + /@esbuild/win32-x64/0.16.16: + resolution: {integrity: sha512-1YYpoJ39WV/2bnShPwgdzJklc+XS0bysN6Tpnt1cWPdeoKOG4RMEY1g7i534QxXX/rPvNx/NLJQTTCeORYzipg==} engines: {node: '>=12'} cpu: [x64] os: [win32] requiresBuild: true - dev: true + dev: false optional: true /@eslint/eslintrc/1.3.2: @@ -2673,6 +2721,235 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@istanbuljs/load-nyc-config/1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema/0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/console/29.3.1: + resolution: {integrity: sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + chalk: 4.1.2 + jest-message-util: 29.3.1 + jest-util: 29.3.1 + slash: 3.0.0 + dev: true + + /@jest/core/29.3.1: + resolution: {integrity: sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 29.3.1 + '@jest/reporters': 29.3.1 + '@jest/test-result': 29.3.1 + '@jest/transform': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.7.0 + exit: 0.1.2 + graceful-fs: 4.2.10 + jest-changed-files: 29.2.0 + jest-config: 29.3.1_@types+node@18.11.18 + jest-haste-map: 29.3.1 + jest-message-util: 29.3.1 + jest-regex-util: 29.2.0 + jest-resolve: 29.3.1 + jest-resolve-dependencies: 29.3.1 + jest-runner: 29.3.1 + jest-runtime: 29.3.1 + jest-snapshot: 29.3.1 + jest-util: 29.3.1 + jest-validate: 29.3.1 + jest-watcher: 29.3.1 + micromatch: 4.0.5 + pretty-format: 29.3.1 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + + /@jest/environment/29.3.1: + resolution: {integrity: sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/fake-timers': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + jest-mock: 29.3.1 + dev: true + + /@jest/expect-utils/29.3.1: + resolution: {integrity: sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.2.0 + dev: true + + /@jest/expect/29.3.1: + resolution: {integrity: sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + expect: 29.3.1 + jest-snapshot: 29.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/fake-timers/29.3.1: + resolution: {integrity: sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.3.1 + '@sinonjs/fake-timers': 9.1.2 + '@types/node': 18.11.18 + jest-message-util: 29.3.1 + jest-mock: 29.3.1 + jest-util: 29.3.1 + dev: true + + /@jest/globals/29.3.1: + resolution: {integrity: sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.3.1 + '@jest/expect': 29.3.1 + '@jest/types': 29.3.1 + jest-mock: 29.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/reporters/29.3.1: + resolution: {integrity: sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.3.1 + '@jest/test-result': 29.3.1 + '@jest/transform': 29.3.1 + '@jest/types': 29.3.1 + '@jridgewell/trace-mapping': 0.3.17 + '@types/node': 18.11.18 + chalk: 4.1.2 + collect-v8-coverage: 1.0.1 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.10 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-instrument: 5.2.1 + istanbul-lib-report: 3.0.0 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.5 + jest-message-util: 29.3.1 + jest-util: 29.3.1 + jest-worker: 29.3.1 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/schemas/29.0.0: + resolution: {integrity: sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@sinclair/typebox': 0.24.51 + dev: true + + /@jest/source-map/29.2.0: + resolution: {integrity: sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jridgewell/trace-mapping': 0.3.17 + callsites: 3.1.0 + graceful-fs: 4.2.10 + dev: true + + /@jest/test-result/29.3.1: + resolution: {integrity: sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.3.1 + '@jest/types': 29.3.1 + '@types/istanbul-lib-coverage': 2.0.4 + collect-v8-coverage: 1.0.1 + dev: true + + /@jest/test-sequencer/29.3.1: + resolution: {integrity: sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.3.1 + graceful-fs: 4.2.10 + jest-haste-map: 29.3.1 + slash: 3.0.0 + dev: true + + /@jest/transform/29.3.1: + resolution: {integrity: sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.20.5 + '@jest/types': 29.3.1 + '@jridgewell/trace-mapping': 0.3.17 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.10 + jest-haste-map: 29.3.1 + jest-regex-util: 29.2.0 + jest-util: 29.3.1 + micromatch: 4.0.5 + pirates: 4.0.5 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/types/29.3.1: + resolution: {integrity: sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.0.0 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/istanbul-reports': 3.0.1 + '@types/node': 18.11.18 + '@types/yargs': 17.0.19 + chalk: 4.1.2 + dev: true + /@jridgewell/gen-mapping/0.1.1: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} @@ -3475,11 +3752,27 @@ packages: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} dev: true + /@sinclair/typebox/0.24.51: + resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} + dev: true + /@sindresorhus/is/5.3.0: resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==} engines: {node: '>=14.16'} dev: true + /@sinonjs/commons/1.8.6: + resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers/9.1.2: + resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==} + dependencies: + '@sinonjs/commons': 1.8.6 + dev: true + /@surma/rollup-plugin-off-main-thread/2.2.3: resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} dependencies: @@ -3517,15 +3810,44 @@ packages: resolution: {integrity: sha512-GiS5Df3CzXY/fPBFcM0CKFERZfI4Cg1X33VPZX+NLo7Fwm/h9zu/aU24N1mG75Q9LuMnwKm7woxKr8BiUXGYCg==} dev: false + /@types/babel__core/7.1.20: + resolution: {integrity: sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==} + dependencies: + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + '@types/babel__generator': 7.6.4 + '@types/babel__template': 7.4.1 + '@types/babel__traverse': 7.18.3 + dev: true + + /@types/babel__generator/7.6.4: + resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} + dependencies: + '@babel/types': 7.20.7 + dev: true + + /@types/babel__template/7.4.1: + resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} + dependencies: + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 + dev: true + + /@types/babel__traverse/7.18.3: + resolution: {integrity: sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==} + dependencies: + '@babel/types': 7.20.7 + dev: true + /@types/chai-subset/1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: '@types/chai': 4.3.4 - dev: true + dev: false /@types/chai/4.3.4: resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} - dev: true + dev: false /@types/debug/4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} @@ -3555,6 +3877,12 @@ packages: '@types/node': 18.7.18 dev: true + /@types/graceful-fs/4.1.6: + resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} + dependencies: + '@types/node': 18.11.18 + dev: true + /@types/http-cache-semantics/4.0.1: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} dev: true @@ -3565,6 +3893,22 @@ packages: ci-info: 3.7.0 dev: true + /@types/istanbul-lib-coverage/2.0.4: + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + dev: true + + /@types/istanbul-lib-report/3.0.0: + resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.4 + dev: true + + /@types/istanbul-reports/3.0.1: + resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} + dependencies: + '@types/istanbul-lib-report': 3.0.0 + dev: true + /@types/json-schema/7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true @@ -3608,6 +3952,10 @@ packages: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} dev: false + /@types/prettier/2.7.2: + resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==} + dev: true + /@types/prop-types/15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} @@ -3667,6 +4015,10 @@ packages: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true + /@types/stack-utils/2.0.1: + resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + dev: true + /@types/trusted-types/2.0.2: resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==} @@ -3674,6 +4026,16 @@ packages: resolution: {integrity: sha512-UYK244awtmcUYQfs7FR8710MJcefL2WvkyHMjA8yJzxd1mo0Gfn88sRZ1Bls7hiUhA2w7ne1gpJ9T5g3G0wOyA==} dev: true + /@types/yargs-parser/21.0.0: + resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} + dev: true + + /@types/yargs/17.0.19: + resolution: {integrity: sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==} + dependencies: + '@types/yargs-parser': 21.0.0 + dev: true + /@typescript-eslint/eslint-plugin/5.48.0_wxmz6cyorqfuzhhglktlvr5lve: resolution: {integrity: sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3862,7 +4224,7 @@ packages: /acorn-walk/8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} - dev: true + dev: false /acorn/8.8.0: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} @@ -3873,7 +4235,7 @@ packages: resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} engines: {node: '>=0.4.0'} hasBin: true - dev: true + dev: false /aggregate-error/3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} @@ -3942,11 +4304,24 @@ packages: dependencies: color-convert: 2.0.1 + /ansi-styles/5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + /ansi-styles/6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} dev: true + /anymatch/3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -4035,7 +4410,7 @@ packages: /assertion-error/1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - dev: true + dev: false /ast-types-flow/0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} @@ -4068,6 +4443,24 @@ packages: resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} dev: true + /babel-jest/29.3.1_@babel+core@7.20.5: + resolution: {integrity: sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.20.5 + '@jest/transform': 29.3.1 + '@types/babel__core': 7.1.20 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.2.0_@babel+core@7.20.5 + chalk: 4.1.2 + graceful-fs: 4.2.10 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /babel-loader/8.3.0: resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==} engines: {node: '>= 8.9'} @@ -4081,6 +4474,29 @@ packages: schema-utils: 2.7.1 dev: true + /babel-plugin-istanbul/6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.20.2 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-jest-hoist/29.2.0: + resolution: {integrity: sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/template': 7.20.7 + '@babel/types': 7.20.7 + '@types/babel__core': 7.1.20 + '@types/babel__traverse': 7.18.3 + dev: true + /babel-plugin-macros/3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -4126,6 +4542,37 @@ packages: - supports-color dev: true + /babel-preset-current-node-syntax/1.0.1_@babel+core@7.20.5: + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.5 + '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.20.5 + '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.20.5 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.20.5 + '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.20.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.20.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.20.5 + '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.20.5 + dev: true + + /babel-preset-jest/29.2.0_@babel+core@7.20.5: + resolution: {integrity: sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.5 + babel-plugin-jest-hoist: 29.2.0 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.5 + dev: true + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -4187,13 +4634,25 @@ packages: update-browserslist-db: 1.0.10_browserslist@4.21.4 dev: true + /bs-logger/0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + dependencies: + fast-json-stable-stringify: 2.1.0 + dev: true + + /bser/2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + /buffer-from/0.1.2: resolution: {integrity: sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==} dev: false /buffer-from/1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true /buffer/6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -4249,6 +4708,11 @@ packages: engines: {node: '>=6'} dev: true + /camelcase/6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: true + /caniuse-lite/1.0.30001419: resolution: {integrity: sha512-aFO1r+g6R7TW+PNQxKzjITwLOyDhVRLjW0LcwS/HCZGUUKTGNp9+IwLC4xyDSZBygVL/mxaFR3HIV6wEKQuSzw==} @@ -4263,7 +4727,7 @@ packages: loupe: 2.3.6 pathval: 1.1.1 type-detect: 4.0.8 - dev: true + dev: false /chalk/2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} @@ -4281,19 +4745,28 @@ packages: supports-color: 7.2.0 dev: true + /char-regex/1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: true + /chardet/0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true /check-error/1.0.2: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} - dev: true + dev: false /ci-info/3.7.0: resolution: {integrity: sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==} engines: {node: '>=8'} dev: true + /cjs-module-lexer/1.2.2: + resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} + dev: true + /clean-stack/2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -4388,6 +4861,15 @@ packages: - '@types/react' dev: false + /co/4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: true + + /collect-v8-coverage/1.0.1: + resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} + dev: true + /color-convert/1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -4438,6 +4920,10 @@ packages: /convert-source-map/1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + /convert-source-map/2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + /core-js-compat/3.27.1: resolution: {integrity: sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==} dependencies: @@ -4583,12 +5069,16 @@ packages: mimic-response: 3.1.0 dev: true + /dedent/0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + dev: true + /deep-eql/4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} dependencies: type-detect: 4.0.8 - dev: true + dev: false /deep-equal/1.1.1: resolution: {integrity: sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==} @@ -4646,10 +5136,20 @@ packages: engines: {node: '>=8'} dev: true + /detect-newline/3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + /detect-node-es/1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} dev: false + /diff-sequences/29.3.1: + resolution: {integrity: sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -4710,6 +5210,11 @@ packages: resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} dev: true + /emittery/0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + dev: true + /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -4788,35 +5293,35 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild/0.16.15: - resolution: {integrity: sha512-v+3ozjy9wyj8cOElzx3//Lsb4TCxPfZxRmdsfm0YaEkvZu7y6rKH7Zi1UpDx4JI7dSQui+U1Qxhfij9KBbHfrA==} + /esbuild/0.16.16: + resolution: {integrity: sha512-24JyKq10KXM5EBIgPotYIJ2fInNWVVqflv3gicIyQqfmUqi4HvDW1VR790cBgLJHCl96Syy7lhoz7tLFcmuRmg==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.16.15 - '@esbuild/android-arm64': 0.16.15 - '@esbuild/android-x64': 0.16.15 - '@esbuild/darwin-arm64': 0.16.15 - '@esbuild/darwin-x64': 0.16.15 - '@esbuild/freebsd-arm64': 0.16.15 - '@esbuild/freebsd-x64': 0.16.15 - '@esbuild/linux-arm': 0.16.15 - '@esbuild/linux-arm64': 0.16.15 - '@esbuild/linux-ia32': 0.16.15 - '@esbuild/linux-loong64': 0.16.15 - '@esbuild/linux-mips64el': 0.16.15 - '@esbuild/linux-ppc64': 0.16.15 - '@esbuild/linux-riscv64': 0.16.15 - '@esbuild/linux-s390x': 0.16.15 - '@esbuild/linux-x64': 0.16.15 - '@esbuild/netbsd-x64': 0.16.15 - '@esbuild/openbsd-x64': 0.16.15 - '@esbuild/sunos-x64': 0.16.15 - '@esbuild/win32-arm64': 0.16.15 - '@esbuild/win32-ia32': 0.16.15 - '@esbuild/win32-x64': 0.16.15 - dev: true + '@esbuild/android-arm': 0.16.16 + '@esbuild/android-arm64': 0.16.16 + '@esbuild/android-x64': 0.16.16 + '@esbuild/darwin-arm64': 0.16.16 + '@esbuild/darwin-x64': 0.16.16 + '@esbuild/freebsd-arm64': 0.16.16 + '@esbuild/freebsd-x64': 0.16.16 + '@esbuild/linux-arm': 0.16.16 + '@esbuild/linux-arm64': 0.16.16 + '@esbuild/linux-ia32': 0.16.16 + '@esbuild/linux-loong64': 0.16.16 + '@esbuild/linux-mips64el': 0.16.16 + '@esbuild/linux-ppc64': 0.16.16 + '@esbuild/linux-riscv64': 0.16.16 + '@esbuild/linux-s390x': 0.16.16 + '@esbuild/linux-x64': 0.16.16 + '@esbuild/netbsd-x64': 0.16.16 + '@esbuild/openbsd-x64': 0.16.16 + '@esbuild/sunos-x64': 0.16.16 + '@esbuild/win32-arm64': 0.16.16 + '@esbuild/win32-ia32': 0.16.16 + '@esbuild/win32-x64': 0.16.16 + dev: false /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} @@ -4826,6 +5331,11 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + /escape-string-regexp/2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + /escape-string-regexp/4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -5405,6 +5915,21 @@ packages: resolution: {integrity: sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==} dev: false + /execa/5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + /execa/6.1.0: resolution: {integrity: sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5420,6 +5945,22 @@ packages: strip-final-newline: 3.0.0 dev: true + /exit/0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + dev: true + + /expect/29.3.1: + resolution: {integrity: sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/expect-utils': 29.3.1 + jest-get-type: 29.2.0 + jest-matcher-utils: 29.3.1 + jest-message-util: 29.3.1 + jest-util: 29.3.1 + dev: true + /extend/3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} dev: false @@ -5487,6 +6028,12 @@ packages: websocket-driver: 0.7.4 dev: false + /fb-watchman/2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + dependencies: + bser: 2.1.1 + dev: true + /fetch-blob/3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -5649,7 +6196,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /function-bind/1.1.1: @@ -5687,7 +6233,7 @@ packages: /get-func-name/2.0.0: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} - dev: true + dev: false /get-intrinsic/1.1.3: resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} @@ -5705,6 +6251,11 @@ packages: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} dev: true + /get-package-type/0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + /get-stream/6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -5879,6 +6430,10 @@ packages: resolution: {integrity: sha512-mshqjgTqx8ee0qryHvRgZaZDxTwxam/2yTQmQlqAWS3+twnq1jsY9Yng9zB7lWq6WRrjTbTOc7knNwccXQiAjQ==} dev: false + /html-escaper/2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + /html-parse-stringify/3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} dependencies: @@ -5915,6 +6470,11 @@ packages: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: true + /human-signals/2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + /human-signals/3.0.1: resolution: {integrity: sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==} engines: {node: '>=12.20.0'} @@ -5976,6 +6536,15 @@ packages: parent-module: 1.0.1 resolve-from: 4.0.0 + /import-local/3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + dev: true + /imurmurhash/0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -6073,6 +6642,11 @@ packages: engines: {node: '>=12'} dev: true + /is-generator-fn/2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + dev: true + /is-glob/4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -6211,6 +6785,52 @@ packages: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} dev: false + /istanbul-lib-coverage/3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument/5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.20.5 + '@babel/parser': 7.20.7 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report/3.0.0: + resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} + engines: {node: '>=8'} + dependencies: + istanbul-lib-coverage: 3.2.0 + make-dir: 3.1.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps/4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports/3.1.5: + resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.0 + dev: true + /jake/10.8.5: resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==} engines: {node: '>=10'} @@ -6222,6 +6842,385 @@ packages: minimatch: 3.1.2 dev: true + /jest-changed-files/29.2.0: + resolution: {integrity: sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + execa: 5.1.1 + p-limit: 3.1.0 + dev: true + + /jest-circus/29.3.1: + resolution: {integrity: sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.3.1 + '@jest/expect': 29.3.1 + '@jest/test-result': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + chalk: 4.1.2 + co: 4.6.0 + dedent: 0.7.0 + is-generator-fn: 2.1.0 + jest-each: 29.3.1 + jest-matcher-utils: 29.3.1 + jest-message-util: 29.3.1 + jest-runtime: 29.3.1 + jest-snapshot: 29.3.1 + jest-util: 29.3.1 + p-limit: 3.1.0 + pretty-format: 29.3.1 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-cli/29.3.1_@types+node@18.11.18: + resolution: {integrity: sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.3.1 + '@jest/test-result': 29.3.1 + '@jest/types': 29.3.1 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.10 + import-local: 3.1.0 + jest-config: 29.3.1_@types+node@18.11.18 + jest-util: 29.3.1 + jest-validate: 29.3.1 + prompts: 2.4.2 + yargs: 17.6.2 + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + dev: true + + /jest-config/29.3.1_@types+node@18.11.18: + resolution: {integrity: sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.20.5 + '@jest/test-sequencer': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + babel-jest: 29.3.1_@babel+core@7.20.5 + chalk: 4.1.2 + ci-info: 3.7.0 + deepmerge: 4.2.2 + glob: 7.2.3 + graceful-fs: 4.2.10 + jest-circus: 29.3.1 + jest-environment-node: 29.3.1 + jest-get-type: 29.2.0 + jest-regex-util: 29.2.0 + jest-resolve: 29.3.1 + jest-runner: 29.3.1 + jest-util: 29.3.1 + jest-validate: 29.3.1 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.3.1 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-diff/29.3.1: + resolution: {integrity: sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 29.3.1 + jest-get-type: 29.2.0 + pretty-format: 29.3.1 + dev: true + + /jest-docblock/29.2.0: + resolution: {integrity: sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-each/29.3.1: + resolution: {integrity: sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.3.1 + chalk: 4.1.2 + jest-get-type: 29.2.0 + jest-util: 29.3.1 + pretty-format: 29.3.1 + dev: true + + /jest-environment-node/29.3.1: + resolution: {integrity: sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.3.1 + '@jest/fake-timers': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + jest-mock: 29.3.1 + jest-util: 29.3.1 + dev: true + + /jest-get-type/29.2.0: + resolution: {integrity: sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-haste-map/29.3.1: + resolution: {integrity: sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.3.1 + '@types/graceful-fs': 4.1.6 + '@types/node': 18.11.18 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.10 + jest-regex-util: 29.2.0 + jest-util: 29.3.1 + jest-worker: 29.3.1 + micromatch: 4.0.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /jest-leak-detector/29.3.1: + resolution: {integrity: sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-get-type: 29.2.0 + pretty-format: 29.3.1 + dev: true + + /jest-matcher-utils/29.3.1: + resolution: {integrity: sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 29.3.1 + jest-get-type: 29.2.0 + pretty-format: 29.3.1 + dev: true + + /jest-message-util/29.3.1: + resolution: {integrity: sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/code-frame': 7.18.6 + '@jest/types': 29.3.1 + '@types/stack-utils': 2.0.1 + chalk: 4.1.2 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + pretty-format: 29.3.1 + slash: 3.0.0 + stack-utils: 2.0.6 + dev: true + + /jest-mock/29.3.1: + resolution: {integrity: sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + jest-util: 29.3.1 + dev: true + + /jest-pnp-resolver/1.2.3_jest-resolve@29.3.1: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 29.3.1 + dev: true + + /jest-regex-util/29.2.0: + resolution: {integrity: sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: true + + /jest-resolve-dependencies/29.3.1: + resolution: {integrity: sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + jest-regex-util: 29.2.0 + jest-snapshot: 29.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve/29.3.1: + resolution: {integrity: sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.10 + jest-haste-map: 29.3.1 + jest-pnp-resolver: 1.2.3_jest-resolve@29.3.1 + jest-util: 29.3.1 + jest-validate: 29.3.1 + resolve: 1.22.1 + resolve.exports: 1.1.0 + slash: 3.0.0 + dev: true + + /jest-runner/29.3.1: + resolution: {integrity: sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/console': 29.3.1 + '@jest/environment': 29.3.1 + '@jest/test-result': 29.3.1 + '@jest/transform': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.10 + jest-docblock: 29.2.0 + jest-environment-node: 29.3.1 + jest-haste-map: 29.3.1 + jest-leak-detector: 29.3.1 + jest-message-util: 29.3.1 + jest-resolve: 29.3.1 + jest-runtime: 29.3.1 + jest-util: 29.3.1 + jest-watcher: 29.3.1 + jest-worker: 29.3.1 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-runtime/29.3.1: + resolution: {integrity: sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/environment': 29.3.1 + '@jest/fake-timers': 29.3.1 + '@jest/globals': 29.3.1 + '@jest/source-map': 29.2.0 + '@jest/test-result': 29.3.1 + '@jest/transform': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + chalk: 4.1.2 + cjs-module-lexer: 1.2.2 + collect-v8-coverage: 1.0.1 + glob: 7.2.3 + graceful-fs: 4.2.10 + jest-haste-map: 29.3.1 + jest-message-util: 29.3.1 + jest-mock: 29.3.1 + jest-regex-util: 29.2.0 + jest-resolve: 29.3.1 + jest-snapshot: 29.3.1 + jest-util: 29.3.1 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-snapshot/29.3.1: + resolution: {integrity: sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@babel/core': 7.20.5 + '@babel/generator': 7.20.7 + '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.20.5 + '@babel/plugin-syntax-typescript': 7.20.0_@babel+core@7.20.5 + '@babel/traverse': 7.20.10 + '@babel/types': 7.20.7 + '@jest/expect-utils': 29.3.1 + '@jest/transform': 29.3.1 + '@jest/types': 29.3.1 + '@types/babel__traverse': 7.18.3 + '@types/prettier': 2.7.2 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.20.5 + chalk: 4.1.2 + expect: 29.3.1 + graceful-fs: 4.2.10 + jest-diff: 29.3.1 + jest-get-type: 29.2.0 + jest-haste-map: 29.3.1 + jest-matcher-utils: 29.3.1 + jest-message-util: 29.3.1 + jest-util: 29.3.1 + natural-compare: 1.4.0 + pretty-format: 29.3.1 + semver: 7.3.7 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-util/29.3.1: + resolution: {integrity: sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + chalk: 4.1.2 + ci-info: 3.7.0 + graceful-fs: 4.2.10 + picomatch: 2.3.1 + dev: true + + /jest-validate/29.3.1: + resolution: {integrity: sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.3.1 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.2.0 + leven: 3.1.0 + pretty-format: 29.3.1 + dev: true + + /jest-watcher/29.3.1: + resolution: {integrity: sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/test-result': 29.3.1 + '@jest/types': 29.3.1 + '@types/node': 18.11.18 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.3.1 + string-length: 4.0.2 + dev: true + /jest-worker/26.6.2: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} @@ -6240,6 +7239,36 @@ packages: supports-color: 8.1.1 dev: true + /jest-worker/29.3.1: + resolution: {integrity: sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@types/node': 18.11.18 + jest-util: 29.3.1 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jest/29.3.1_@types+node@18.11.18: + resolution: {integrity: sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 29.3.1 + '@jest/types': 29.3.1 + import-local: 3.1.0 + jest-cli: 29.3.1_@types+node@18.11.18 + transitivePeerDependencies: + - '@types/node' + - supports-color + - ts-node + dev: true + /js-sdsl/4.2.0: resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==} dev: true @@ -6310,7 +7339,7 @@ packages: /jsonc-parser/3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: true + dev: false /jsonfile/4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -6350,6 +7379,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /kleur/3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + /kleur/4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -6519,7 +7553,7 @@ packages: /local-pkg/0.4.2: resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==} engines: {node: '>=14'} - dev: true + dev: false /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} @@ -6543,6 +7577,10 @@ packages: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} dev: true + /lodash.memoize/4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: true + /lodash.merge/4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -6585,7 +7623,7 @@ packages: resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} dependencies: get-func-name: 2.0.0 - dev: true + dev: false /lowercase-keys/3.0.0: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} @@ -6625,6 +7663,16 @@ packages: semver: 6.3.0 dev: true + /make-error/1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /makeerror/1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + /map-obj/1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -6737,7 +7785,7 @@ packages: pathe: 1.0.0 pkg-types: 1.0.1 ufo: 1.0.1 - dev: true + dev: false /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -6911,6 +7959,10 @@ packages: formdata-polyfill: 4.0.10 dev: false + /node-int64/0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + dev: true + /node-releases/2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} dev: true @@ -6934,6 +7986,13 @@ packages: engines: {node: '>=14.16'} dev: true + /npm-run-path/4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + /npm-run-path/5.1.0: resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -7159,15 +8218,15 @@ packages: /pathe/0.2.0: resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} - dev: true + dev: false /pathe/1.0.0: resolution: {integrity: sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==} - dev: true + dev: false /pathval/1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - dev: true + dev: false /perfect-freehand/1.2.0: resolution: {integrity: sha512-h/0ikF1M3phW7CwpZ5MMvKnfpHficWoOEyr//KVNTxV4F6deRK1eYMtHyBKEAKFK0aXIEUK9oBvlF6PNXMDsAw==} @@ -7209,6 +8268,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /pirates/4.0.5: + resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} + engines: {node: '>= 6'} + dev: true + /pkg-dir/4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -7222,7 +8286,7 @@ packages: jsonc-parser: 3.2.0 mlly: 1.0.0 pathe: 1.0.0 - dev: true + dev: false /playwright-core/1.29.1: resolution: {integrity: sha512-20Ai3d+lMkWpI9YZYlxk8gxatfgax5STW8GaMozAHwigLiyiKQrdkt7gaoT9UQR8FIVDg6qVXs9IoZUQrDjIIg==} @@ -7245,7 +8309,7 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true + dev: false /preferred-pm/3.0.3: resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} @@ -7278,10 +8342,27 @@ packages: engines: {node: '>=6'} dev: true + /pretty-format/29.3.1: + resolution: {integrity: sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/schemas': 29.0.0 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: false + /prompts/2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + /prop-types/15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -7423,7 +8504,6 @@ packages: /react-is/18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: false /react-remove-scroll-bar/2.3.4_w5j4k42lgipnm43s3brx6h3c34: resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} @@ -7648,6 +8728,13 @@ packages: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} dev: true + /resolve-cwd/3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + /resolve-from/4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -7657,8 +8744,14 @@ packages: engines: {node: '>=8'} dev: true + /resolve.exports/1.1.0: + resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==} + engines: {node: '>=10'} + dev: true + /resolve/1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true dependencies: is-core-module: 2.10.0 path-parse: 1.0.7 @@ -7736,7 +8829,7 @@ packages: hasBin: true optionalDependencies: fsevents: 2.3.2 - dev: true + dev: false /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -7871,6 +8964,10 @@ packages: - supports-color dev: false + /sisteransi/1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + /slash/3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -7923,12 +9020,18 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + /source-map-support/0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + /source-map-support/0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true /source-map/0.5.7: resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} @@ -7938,7 +9041,6 @@ packages: /source-map/0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - dev: true /source-map/0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} @@ -7985,6 +9087,13 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true + /stack-utils/2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + /stream-transform/2.1.3: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: @@ -7996,6 +9105,14 @@ packages: engines: {node: '>=0.6.19'} dev: true + /string-length/4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + dev: true + /string-width/4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8085,11 +9202,21 @@ packages: engines: {node: '>=4'} dev: true + /strip-bom/4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + dev: true + /strip-comments/2.0.1: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} engines: {node: '>=10'} dev: true + /strip-final-newline/2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + /strip-final-newline/3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -8111,7 +9238,7 @@ packages: resolution: {integrity: sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==} dependencies: acorn: 8.8.1 - dev: true + dev: false /styled-jsx/5.0.7_react@18.2.0: resolution: {integrity: sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==} @@ -8236,6 +9363,15 @@ packages: source-map-support: 0.5.21 dev: true + /test-exclude/6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + /text-table/0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -8252,17 +9388,17 @@ packages: /tinybench/2.3.1: resolution: {integrity: sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==} - dev: true + dev: false /tinypool/0.3.0: resolution: {integrity: sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==} engines: {node: '>=14.0.0'} - dev: true + dev: false /tinyspy/1.0.2: resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} engines: {node: '>=14.0.0'} - dev: true + dev: false /tmp/0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} @@ -8271,6 +9407,10 @@ packages: os-tmpdir: 1.0.2 dev: true + /tmpl/1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + /to-fast-properties/2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -8304,6 +9444,39 @@ packages: engines: {node: '>=8'} dev: true + /ts-jest/29.0.3_4f6uxrzmuwipl5rr3bcogf6k74: + resolution: {integrity: sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.3.1_@types+node@18.11.18 + jest-util: 29.3.1 + json5: 2.2.1 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.3.7 + typescript: 4.9.3 + yargs-parser: 21.1.1 + dev: true + /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: @@ -8370,7 +9543,6 @@ packages: /type-detect/4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - dev: true /type-fest/0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} @@ -8436,7 +9608,7 @@ packages: /ufo/1.0.1: resolution: {integrity: sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==} - dev: true + dev: false /unbox-primitive/1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -8562,6 +9734,15 @@ packages: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true + /v8-to-istanbul/9.0.1: + resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.17 + '@types/istanbul-lib-coverage': 2.0.4 + convert-source-map: 1.9.0 + dev: true + /validate-npm-package-license/3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -8588,7 +9769,7 @@ packages: - sugarss - supports-color - terser - dev: true + dev: false /vite/4.0.4_@types+node@18.11.18: resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} @@ -8616,13 +9797,13 @@ packages: optional: true dependencies: '@types/node': 18.11.18 - esbuild: 0.16.15 + esbuild: 0.16.16 postcss: 8.4.21 resolve: 1.22.1 rollup: 3.9.1 optionalDependencies: fsevents: 2.3.2 - dev: true + dev: false /vitest/0.26.3: resolution: {integrity: sha512-FmHxU9aUCxTi23keF3vxb/Qp0lYXaaJ+jRLGOUmMS3qVTOJvgGE+f1VArupA6pEhaG2Ans4X+zV9dqM5WISMbg==} @@ -8668,13 +9849,19 @@ packages: - sugarss - supports-color - terser - dev: true + dev: false /void-elements/3.1.0: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} dev: false + /walker/1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + /wcwidth/1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: @@ -8968,6 +10155,14 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true + /write-file-atomic/4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + dev: true + /ws/7.5.9: resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} engines: {node: '>=8.3.0'} From 761345a226d271ad51f19caccaea2b533f6c8569 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Mon, 9 Jan 2023 14:56:14 +0800 Subject: [PATCH 068/298] fix: reference file name --- packages/app/src/components/workspace-setting/MembersPage.tsx | 2 +- packages/app/src/components/workspace-setting/PublishPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/app/src/components/workspace-setting/MembersPage.tsx b/packages/app/src/components/workspace-setting/MembersPage.tsx index 8b5210653b..0d45f4afae 100644 --- a/packages/app/src/components/workspace-setting/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/MembersPage.tsx @@ -25,7 +25,7 @@ import { } from '@/hooks/mock-data/mock'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { StyledMemberWarp } from './general/style'; -import { useConfirm } from '@/providers/confirm-provider'; +import { useConfirm } from '@/providers/ConfirmProvider'; // import { useAppState } from '@/providers/app-state-provider'; export const MembersPage = ({ workspace }: { workspace: Workspace }) => { diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx index 33a0e55961..2e0105214b 100644 --- a/packages/app/src/components/workspace-setting/PublishPage.tsx +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -11,7 +11,7 @@ import Input from '@/ui/input'; import { toast } from '@/ui/toast'; import { Workspace } from '@/hooks/mock-data/mock'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; -import { useConfirm } from '@/providers/confirm-provider'; +import { useConfirm } from '@/providers/ConfirmProvider'; export const PublishPage = ({ workspace }: { workspace: Workspace }) => { console.log('workspace: ', workspace); From b46a7fc8ce20cfe50c7fdef66b48082108a3b8de Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 15:26:30 +0800 Subject: [PATCH 069/298] fix: fix init head icon --- packages/data-center/src/datacenter.ts | 35 +++++++++---------- .../data-center/src/provider/affine/affine.ts | 19 ++++++---- packages/data-center/src/provider/base.ts | 19 +++++----- .../data-center/src/provider/local/local.ts | 19 ++++++---- 4 files changed, 48 insertions(+), 44 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 2fc9431e93..00ca590ae3 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -17,7 +17,6 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; export class DataCenter { private readonly _workspaces = new Workspaces(); private readonly _logger = getLogger('dc'); - private readonly _blobStorage: BlobStorage = new BlobStorage(); /** * A mainProvider must exist as the only data trustworthy source. */ @@ -35,14 +34,12 @@ export class DataCenter { new LocalProvider({ logger: dc._logger, workspaces: dc._workspaces.createScope(), - blobs: dc._blobStorage, }) ); dc.registerProvider( new AffineProvider({ logger: dc._logger, workspaces: dc._workspaces.createScope(), - blobs: dc._blobStorage, }) ); @@ -335,21 +332,21 @@ export class DataCenter { return; } - /** - * get blob url by workspaces id - * @param id - * @returns {Promise} blob url - */ - async getBlob(id: string): Promise { - return await this._blobStorage.get(id); - } + // /** + // * get blob url by workspaces id + // * @param id + // * @returns {Promise} blob url + // */ + // async getBlob(id: string): Promise { + // return await this._blobStorage.get(id); + // } - /** - * up load blob and get a blob url - * @param id - * @returns {Promise} blob url - */ - async setBlob(blob: Blob): Promise { - return await this._blobStorage.set(blob); - } + // /** + // * up load blob and get a blob url + // * @param id + // * @returns {Promise} blob url + // */ + // async setBlob(blob: Blob): Promise { + // return await this._blobStorage.set(blob); + // } } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 0f78ba7048..cb9b1704d3 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -246,19 +246,12 @@ export class AffineProvider extends BaseProvider { meta: WorkspaceMeta ): Promise { assert(meta.name, 'Workspace name is required'); - if (!meta.avatar) { - // set default avatar - const blob = await getDefaultHeadImgBlob(meta.name); - const blobId = await this.setBlob(blob); - meta.avatar = (await this.getBlob(blobId)) || ''; - } const { id } = await createWorkspace(meta as Required); this._logger('Creating affine workspace'); const nw = new Workspace({ room: id, }).register(BlockSchema); nw.meta.setName(meta.name); - nw.meta.setAvatar(meta.avatar); this._initWorkspaceDb(nw); const workspaceInfo: WS = { @@ -272,6 +265,18 @@ export class AffineProvider extends BaseProvider { provider: 'local', }; + if (!meta.avatar) { + // set default avatar + const blob = await getDefaultHeadImgBlob(meta.name); + const blobStorage = await nw.blobs; + assert(blobStorage, 'No blob storage'); + const blobId = await blobStorage.set(blob); + const avatar = await blobStorage.get(blobId); + if (avatar) { + nw.meta.setAvatar(avatar); + workspaceInfo.avatar = avatar; + } + } this._workspaces.add(workspaceInfo); return nw; } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 62fc943ebd..249a536f21 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -9,19 +9,16 @@ const defaultLogger = () => { export interface ProviderConstructorParams { logger?: Logger; workspaces: WorkspacesScope; - blobs: BlobStorage; } export class BaseProvider { public readonly id: string = 'base'; protected _workspaces!: WorkspacesScope; protected _logger!: Logger; - protected _blobs!: BlobStorage; - public constructor({ logger, workspaces, blobs }: ProviderConstructorParams) { + public constructor({ logger, workspaces }: ProviderConstructorParams) { this._logger = (logger || defaultLogger) as Logger; this._workspaces = workspaces; - this._blobs = blobs; } /** @@ -69,19 +66,19 @@ export class BaseProvider { return; } - async getBlob(id: string): Promise { - return await this._blobs.get(id); - } + // async getBlob(id: string): Promise { + // return await this._blobs.get(id); + // } - async setBlob(blob: Blob): Promise { - return await this._blobs.set(blob); - } + // async setBlob(blob: Blob): Promise { + // return await this._blobs.set(blob); + // } /** * clear all local data in provider */ async clear() { - this._blobs.clear(); + // this._blobs.clear(); } /** diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 8454f212b5..8988068b8a 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -79,12 +79,6 @@ export class LocalProvider extends BaseProvider { meta: WorkspaceMeta ): Promise { assert(meta.name, 'Workspace name is required'); - if (!meta.avatar) { - // set default avatar - const blob = await getDefaultHeadImgBlob(meta.name); - const blobId = await this.setBlob(blob); - meta.avatar = (await this.getBlob(blobId)) || ''; - } this._logger('Creating affine workspace'); const workspaceInfo: WS = { @@ -101,7 +95,18 @@ export class LocalProvider extends BaseProvider { const workspace = new Workspace({ room: workspaceInfo.id }); this._initWorkspaceDb(workspace); workspace.meta.setName(meta.name); - workspace.meta.setAvatar(meta.avatar); + if (!meta.avatar) { + // set default avatar + const blob = await getDefaultHeadImgBlob(meta.name); + const blobStorage = await workspace.blobs; + assert(blobStorage, 'No blob storage'); + const blobId = await blobStorage.set(blob); + const avatar = await blobStorage.get(blobId); + if (avatar) { + workspace.meta.setAvatar(avatar); + workspaceInfo.avatar = avatar; + } + } this._workspaces.add(workspaceInfo); this._storeWorkspaces(this._workspaces.list()); From 28b2943dc67c381e66ec1799a3c3c9754fb5b13d Mon Sep 17 00:00:00 2001 From: QiShaoXuan Date: Mon, 9 Jan 2023 16:40:23 +0800 Subject: [PATCH 070/298] feat: refactor app state provider --- .../src/components/header/EditorHeader.tsx | 2 +- .../header/header-right-items/SyncUser.tsx | 2 +- packages/app/src/components/import/index.tsx | 2 +- .../app/src/components/page-list/index.tsx | 2 +- .../app/src/components/quick-search/Input.tsx | 9 +- .../app/src/components/quick-search/index.tsx | 9 +- .../SelectorPopperContent.tsx | 2 +- .../WorkspaceItem/PrivateWorkspaceItem.tsx | 2 +- .../components/workspace-slider-bar/index.tsx | 2 +- .../app/src/hooks/use-ensure-workspace.ts | 16 +- packages/app/src/hooks/use-init-workspace.ts | 12 +- packages/app/src/pages/_app.tsx | 8 +- .../app/src/pages/playground/templates.tsx | 2 +- .../workspace/[workspaceId]/[pageId].tsx | 2 +- .../pages/workspace/[workspaceId]/index.tsx | 2 +- .../app/src/providers/GlobalModalProvider.tsx | 12 +- .../app-state-provider/DynamicBlocksuite.tsx | 6 +- .../providers/app-state-provider/Provider.tsx | 200 ++++++++++-------- .../src/providers/app-state-provider/index.ts | 3 +- .../providers/app-state-provider/interface.ts | 44 ++-- .../src/providers/app-state-provider/utils.ts | 10 + .../app-state-provider3/DynamicBlocksuite.tsx | 25 +++ .../app-state-provider3/Provider.tsx | 144 +++++++++++++ .../context.ts | 0 .../providers/app-state-provider3/index.ts | 2 + .../app-state-provider3/interface.ts | 17 ++ packages/data-center/src/index.ts | 3 +- pnpm-lock.yaml | 46 +++- 28 files changed, 423 insertions(+), 163 deletions(-) create mode 100644 packages/app/src/providers/app-state-provider/utils.ts create mode 100644 packages/app/src/providers/app-state-provider3/DynamicBlocksuite.tsx create mode 100644 packages/app/src/providers/app-state-provider3/Provider.tsx rename packages/app/src/providers/{app-state-provider => app-state-provider3}/context.ts (100%) create mode 100644 packages/app/src/providers/app-state-provider3/index.ts create mode 100644 packages/app/src/providers/app-state-provider3/interface.ts diff --git a/packages/app/src/components/header/EditorHeader.tsx b/packages/app/src/components/header/EditorHeader.tsx index b343179496..76bdb9c88b 100644 --- a/packages/app/src/components/header/EditorHeader.tsx +++ b/packages/app/src/components/header/EditorHeader.tsx @@ -6,7 +6,7 @@ import { StyledTitleWrapper, } from './styles'; import { Content } from '@/ui/layout'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import EditorModeSwitch from '@/components/editor-mode-switch'; import QuickSearchButton from './QuickSearchButton'; import Header from './Header'; diff --git a/packages/app/src/components/header/header-right-items/SyncUser.tsx b/packages/app/src/components/header/header-right-items/SyncUser.tsx index 86c85926bf..60af1b461a 100644 --- a/packages/app/src/components/header/header-right-items/SyncUser.tsx +++ b/packages/app/src/components/header/header-right-items/SyncUser.tsx @@ -1,6 +1,6 @@ import { CloudUnsyncedIcon, CloudInsyncIcon } from '@blocksuite/icons'; import { useModal } from '@/providers/GlobalModalProvider'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { IconButton } from '@/ui/button'; export const SyncUser = () => { diff --git a/packages/app/src/components/import/index.tsx b/packages/app/src/components/import/index.tsx index 96a383dad2..e296a7a0b9 100644 --- a/packages/app/src/components/import/index.tsx +++ b/packages/app/src/components/import/index.tsx @@ -4,7 +4,7 @@ import { Button } from '@/ui/button'; import { Wrapper, Content } from '@/ui/layout'; import Loading from '@/components/loading'; import { usePageHelper } from '@/hooks/use-page-helper'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; // import { Tooltip } from '@/ui/tooltip'; diff --git a/packages/app/src/components/page-list/index.tsx b/packages/app/src/components/page-list/index.tsx index 2d5f13ed58..429ee6bbb9 100644 --- a/packages/app/src/components/page-list/index.tsx +++ b/packages/app/src/components/page-list/index.tsx @@ -20,7 +20,7 @@ import DateCell from '@/components/page-list/DateCell'; import { IconButton } from '@/ui/button'; import { Tooltip } from '@/ui/tooltip'; import { useRouter } from 'next/router'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { toast } from '@/ui/toast'; import { usePageHelper } from '@/hooks/use-page-helper'; import { useTheme } from '@/providers/ThemeProvider'; diff --git a/packages/app/src/components/quick-search/Input.tsx b/packages/app/src/components/quick-search/Input.tsx index a3897675fb..69d47a16a1 100644 --- a/packages/app/src/components/quick-search/Input.tsx +++ b/packages/app/src/components/quick-search/Input.tsx @@ -17,11 +17,10 @@ export const Input = (props: { const [isComposition, setIsComposition] = useState(false); const [inputValue, setInputValue] = useState(''); const inputRef = useRef(null); - const { currentWorkspaceId, workspacesMeta, currentWorkspace } = - useAppState(); - const isPublic = workspacesMeta.find( + const { currentWorkspaceId, workspaceList, currentWorkspace } = useAppState(); + const isPublish = workspaceList.find( meta => String(meta.id) === String(currentWorkspaceId) - )?.public; + )?.isPublish; useEffect(() => { inputRef.current?.addEventListener( 'blur', @@ -80,7 +79,7 @@ export const Input = (props: { } }} placeholder={ - isPublic + isPublish ? `Search in ${currentWorkspace?.meta.name}` : 'Quick Search...' } diff --git a/packages/app/src/components/quick-search/index.tsx b/packages/app/src/components/quick-search/index.tsx index b08f69196e..87eeadf09b 100644 --- a/packages/app/src/components/quick-search/index.tsx +++ b/packages/app/src/components/quick-search/index.tsx @@ -22,16 +22,17 @@ const isMac = () => { return getUaHelper().isMacOs; }; export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => { + const { currentWorkspaceId, workspaceList } = useAppState(); + const [query, setQuery] = useState(''); const [loading, setLoading] = useState(true); const [showCreatePage, setShowCreatePage] = useState(true); const { triggerQuickSearchModal } = useModal(); - const { currentWorkspaceId, workspacesMeta } = useAppState(); - const currentWorkspace = workspacesMeta.find( + const currentWorkspace = workspaceList.find( meta => String(meta.id) === String(currentWorkspaceId) ); - const isPublic = currentWorkspace?.public; + const isPublish = currentWorkspace?.isPublish; // Add ‘⌘+K’ shortcut keys as switches useEffect(() => { @@ -98,7 +99,7 @@ export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => { setShowCreatePage={setShowCreatePage} /> - {isPublic ? ( + {isPublish ? ( <> ) : showCreatePage ? ( <> diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx index f8bca4787d..208f3a76d7 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx @@ -1,7 +1,7 @@ import { InformationIcon, LogOutIcon } from '@blocksuite/icons'; import { styled } from '@/styles'; import { Divider } from '@/ui/divider'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { SelectorPopperContainer } from './styles'; import { PrivateWorkspaceItem, diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx index 1301200f79..ea5ae4f7b2 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx @@ -1,5 +1,5 @@ import { styled } from '@/styles'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { WorkspaceItemAvatar, PrivateWorkspaceWrapper, diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index 333dea3e6e..7640b35ce0 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -26,7 +26,7 @@ import { import Link from 'next/link'; import { Tooltip } from '@/ui/tooltip'; import { useModal } from '@/providers/GlobalModalProvider'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { IconButton } from '@/ui/button'; import useLocalStorage from '@/hooks/use-local-storage'; import usePageMetaList from '@/hooks/use-page-meta-list'; diff --git a/packages/app/src/hooks/use-ensure-workspace.ts b/packages/app/src/hooks/use-ensure-workspace.ts index d20c63b05f..9412379008 100644 --- a/packages/app/src/hooks/use-ensure-workspace.ts +++ b/packages/app/src/hooks/use-ensure-workspace.ts @@ -7,22 +7,18 @@ const defaultOutLineWorkspaceId = 'affine'; // Cause it not just ensure workspace loaded, but also have router change. export const useEnsureWorkspace = () => { const [workspaceLoaded, setWorkspaceLoaded] = useState(false); - const { workspacesMeta, loadWorkspace, synced, user } = useAppState(); + const { workspaceList, loadWorkspace, user } = useAppState(); const router = useRouter(); // const defaultOutLineWorkspaceId = '99ce7eb7'; // console.log(defaultOutLineWorkspaceId); useEffect(() => { - if (!synced) { - setWorkspaceLoaded(false); - return; - } // If router.query.workspaceId is not in workspace list, jump to 404 page - // If workspacesMeta is empty, we need to create a default workspace but not jump to 404 + // If workspaceList is empty, we need to create a default workspace but not jump to 404 if ( - workspacesMeta.length && + workspaceList.length && router.query.workspaceId && - workspacesMeta.findIndex( + workspaceList.findIndex( meta => meta.id.toString() === router.query.workspaceId ) === -1 ) { @@ -40,13 +36,13 @@ export const useEnsureWorkspace = () => { // } const workspaceId = user - ? (router.query.workspaceId as string) || workspacesMeta[0]?.id + ? (router.query.workspaceId as string) || workspaceList[0]?.id : (router.query.workspaceId as string) || defaultOutLineWorkspaceId; loadWorkspace(workspaceId).finally(() => { setWorkspaceLoaded(true); }); - }, [loadWorkspace, router, synced, user, workspacesMeta]); + }, [loadWorkspace, router, user, workspaceList]); return { workspaceLoaded, diff --git a/packages/app/src/hooks/use-init-workspace.ts b/packages/app/src/hooks/use-init-workspace.ts index 1866e69b4c..4f916365c2 100644 --- a/packages/app/src/hooks/use-init-workspace.ts +++ b/packages/app/src/hooks/use-init-workspace.ts @@ -1,5 +1,5 @@ import { useRouter } from 'next/router'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { useEffect, useRef, useState } from 'react'; export const useInitWorkspace = (disabled?: boolean) => { @@ -8,15 +8,11 @@ export const useInitWorkspace = (disabled?: boolean) => { const defaultOutLineWorkspaceId = useRef(new Date().getTime().toString()); const router = useRouter(); - const { - workspacesMeta, - loadWorkspace, - currentWorkspace, - currentWorkspaceId, - } = useAppState(); + const { workspaceList, loadWorkspace, currentWorkspace, currentWorkspaceId } = + useAppState(); const workspaceId = (router.query.workspaceId as string) || - workspacesMeta?.[0]?.id || + workspaceList?.[0]?.id || defaultOutLineWorkspaceId.current; useEffect(() => { diff --git a/packages/app/src/pages/_app.tsx b/packages/app/src/pages/_app.tsx index da94a4eede..a8a4ecb762 100644 --- a/packages/app/src/pages/_app.tsx +++ b/packages/app/src/pages/_app.tsx @@ -10,9 +10,11 @@ import '../utils/print-build-info'; import ProviderComposer from '@/components/provider-composer'; import type { PropsWithChildren, ReactElement, ReactNode } from 'react'; import type { NextPage } from 'next'; -import { AppStateProvider } from '@/providers/app-state-provider/Provider'; +import { AppStateProvider } from '@/providers/app-state-provider'; import ConfirmProvider from '@/providers/ConfirmProvider'; import { ModalProvider } from '@/providers/GlobalModalProvider'; +// import AppStateProvider2 from '@/providers/app-state-provider2/provider'; + import { useRouter } from 'next/router'; import { useEffect } from 'react'; import { useAppState } from '@/providers/app-state-provider'; @@ -56,6 +58,7 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => { , , , + // , , , ]} @@ -67,9 +70,8 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => { }; const AppDefender = ({ children }: PropsWithChildren) => { - const router = useRouter(); - const { synced } = useAppState(); + const router = useRouter(); useEffect(() => { if (router.pathname === '/') { diff --git a/packages/app/src/pages/playground/templates.tsx b/packages/app/src/pages/playground/templates.tsx index a83d25e516..3dc825b1e9 100644 --- a/packages/app/src/pages/playground/templates.tsx +++ b/packages/app/src/pages/playground/templates.tsx @@ -4,7 +4,7 @@ import exampleMarkdown1 from '@/templates/Welcome-to-the-AFFiNE-Alpha.md'; import exampleMarkdown2 from '@/templates/AFFiNE-Docs.md'; import { usePageHelper } from '@/hooks/use-page-helper'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import { Button } from '@/ui/button'; interface Template { name: string; diff --git a/packages/app/src/pages/workspace/[workspaceId]/[pageId].tsx b/packages/app/src/pages/workspace/[workspaceId]/[pageId].tsx index 05c2c17eba..eba930db91 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/[pageId].tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/[pageId].tsx @@ -10,7 +10,7 @@ import { styled } from '@/styles'; import { EditorHeader } from '@/components/header'; import EdgelessToolbar from '@/components/edgeless-toolbar'; import MobileModal from '@/components/mobile-modal'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import exampleMarkdown from '@/templates/Welcome-to-AFFiNE-Alpha-v2.0.md'; import type { NextPageWithLayout } from '../..//_app'; import WorkspaceLayout from '@/components/workspace-layout'; diff --git a/packages/app/src/pages/workspace/[workspaceId]/index.tsx b/packages/app/src/pages/workspace/[workspaceId]/index.tsx index 39a1ad121b..d502f57980 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/index.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/index.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import { useRouter } from 'next/router'; -import { useAppState } from '@/providers/app-state-provider/context'; +import { useAppState } from '@/providers/app-state-provider'; import useEnsureWorkspace from '@/hooks/use-ensure-workspace'; import { PageLoading } from '@/components/loading'; import usePageHelper from '@/hooks/use-page-helper'; diff --git a/packages/app/src/providers/GlobalModalProvider.tsx b/packages/app/src/providers/GlobalModalProvider.tsx index 76a0365dfc..5f72397ff9 100644 --- a/packages/app/src/providers/GlobalModalProvider.tsx +++ b/packages/app/src/providers/GlobalModalProvider.tsx @@ -97,12 +97,12 @@ export const ModalProvider = ({ triggerHandler('shortcuts', false); }} > - { - triggerHandler('quickSearch', false); - }} - > + {/* {*/} + {/* triggerHandler('quickSearch', false);*/} + {/* }}*/} + {/*>*/} { diff --git a/packages/app/src/providers/app-state-provider/DynamicBlocksuite.tsx b/packages/app/src/providers/app-state-provider/DynamicBlocksuite.tsx index 4b7b876545..611f316a4f 100644 --- a/packages/app/src/providers/app-state-provider/DynamicBlocksuite.tsx +++ b/packages/app/src/providers/app-state-provider/DynamicBlocksuite.tsx @@ -2,11 +2,11 @@ import { useEffect } from 'react'; import type { Page } from '@blocksuite/store'; import '@blocksuite/blocks'; import { EditorContainer } from '@blocksuite/editor'; -import type { CreateEditorHandler } from './context'; +import { CreateEditorHandler } from './interface'; -interface Props { +type Props = { setCreateEditorHandler: (handler: CreateEditorHandler) => void; -} +}; const DynamicBlocksuite = ({ setCreateEditorHandler }: Props) => { useEffect(() => { diff --git a/packages/app/src/providers/app-state-provider/Provider.tsx b/packages/app/src/providers/app-state-provider/Provider.tsx index f104e9be3e..50ef656fb6 100644 --- a/packages/app/src/providers/app-state-provider/Provider.tsx +++ b/packages/app/src/providers/app-state-provider/Provider.tsx @@ -1,46 +1,30 @@ -import { useMemo, useState, useCallback, useRef } from 'react'; -import type { ReactNode } from 'react'; -import dynamic from 'next/dynamic'; +import { + createContext, + useCallback, + useContext, + useEffect, + useState, +} from 'react'; +import type { PropsWithChildren } from 'react'; import { getDataCenter } from '@affine/datacenter'; -import { AppState, AppStateContext } from './context'; -import type { - AppStateValue, - CreateEditorHandler, - LoadWorkspaceHandler, -} from './context'; -import { Page } from '@blocksuite/store'; -import { EditorContainer } from '@blocksuite/editor'; +import { AppStateContext, AppStateValue } from './interface'; +import { createDefaultWorkspace } from './utils'; + +type AppStateContextProps = PropsWithChildren>; +import dynamic from 'next/dynamic'; +import { CreateEditorHandler } from '@/providers/app-state-provider3'; + const DynamicBlocksuite = dynamic(() => import('./DynamicBlocksuite'), { ssr: false, }); +export const AppState = createContext({} as AppStateContext); -const loadWorkspaceHandler: LoadWorkspaceHandler = async workspaceId => { - if (workspaceId) { - const dc = await getDataCenter(); - return dc.load(workspaceId, { providerId: 'affine' }); - } else { - return null; - } -}; -export const AppStateProvider = ({ children }: { children?: ReactNode }) => { - const refreshWorkspacesMeta = async () => { - const dc = await getDataCenter(); - const workspacesMeta = await dc.apis.getWorkspaces().catch(() => { - return []; - }); - setState(state => ({ ...state, workspacesMeta })); - }; +export const useAppState = () => useContext(AppState); - const [state, setState] = useState({ - user: null, - workspacesMeta: [], - currentWorkspaceId: '', - currentWorkspace: null, - currentPage: null, - editor: null, - refreshWorkspacesMeta, - synced: true, - }); +export const AppStateProvider = ({ + children, +}: PropsWithChildren) => { + const [appState, setAppState] = useState({} as AppStateValue); const [createEditorHandler, _setCreateEditorHandler] = useState(); @@ -52,54 +36,84 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { [_setCreateEditorHandler] ); - const loadWorkspace = useRef(() => - Promise.resolve(null) - ); - loadWorkspace.current = async (workspaceId: string) => { - if (state.currentWorkspaceId === workspaceId) { - return state.currentWorkspace; + useEffect(() => { + const init = async () => { + const dataCenter = await getDataCenter(); + + if (dataCenter.workspaces.length === 0) { + await createDefaultWorkspace(dataCenter); + } + + const currentWorkspace = await dataCenter.loadWorkspace( + dataCenter.workspaces[0].id + ); + + setAppState({ + dataCenter, + user: await dataCenter.getUserInfo(), + workspaceList: dataCenter.workspaces, + currentWorkspaceId: dataCenter.workspaces[0].id, + currentWorkspace, + pageList: currentWorkspace.meta.pageMetas, + currentPage: null, + editor: null, + synced: true, + }); + }; + + init(); + }, []); + + useEffect(() => { + if (!appState?.currentWorkspace) { + return; } - const workspace = - (await loadWorkspaceHandler(workspaceId, state.user)) || null; + const currentWorkspace = appState.currentWorkspace; + const dispose = currentWorkspace.meta.pagesUpdated.on(() => { + setAppState({ + ...appState, + pageList: currentWorkspace.meta.pageMetas, + }); + }).dispose; + return () => { + dispose(); + }; + }, [appState]); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - window.workspace = workspace; - // FIXME: there needs some method to destroy websocket. - // Or we need a manager to manage websocket. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - state.currentWorkspace?.__ws__?.destroy(); - - setState(state => ({ - ...state, - currentWorkspace: workspace, - currentWorkspaceId: workspaceId, - })); - return workspace; - }; - - const loadPage = useRef(() => - Promise.resolve(null) - ); - loadPage.current = async (pageId: string) => { - const { currentWorkspace, currentPage } = state; + const loadPage = (pageId: string) => { + const { currentWorkspace, currentPage } = appState; if (pageId === currentPage?.id) { - return currentPage; + return; } - const page = (pageId ? currentWorkspace?.getPage(pageId) : null) || null; - setState(state => ({ ...state, currentPage: page })); - return page; + const page = currentWorkspace?.getPage(pageId) || null; + setAppState({ + ...appState, + currentPage: page, + }); }; - const createEditor = useRef< - ((page: Page) => EditorContainer | null) | undefined - >(); - createEditor.current = () => { - const { currentPage, currentWorkspace } = state; + const loadWorkspace = async (workspaceId: string) => { + const { dataCenter, workspaceList, currentWorkspaceId } = appState; + if (!workspaceList.find(v => v.id === workspaceId)) { + return; + } + if (workspaceId === currentWorkspaceId) { + return; + } + + setAppState({ + ...appState, + currentWorkspace: await dataCenter.loadWorkspace(workspaceId), + currentWorkspaceId: workspaceId, + }); + }; + + const createEditor = () => { + const { currentPage, currentWorkspace } = appState; if (!currentPage || !currentWorkspace) { return null; } + const editor = createEditorHandler?.(currentPage) || null; if (editor) { @@ -117,28 +131,28 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { return editor; }; - const setEditor = useRef<(editor: AppStateValue['editor']) => void>(); - - setEditor.current = (editor: AppStateValue['editor']) => { - setState(state => ({ ...state, editor })); + const setEditor = (editor: AppStateValue['editor']) => { + setAppState({ + ...appState, + editor, + }); }; - const context = useMemo( - () => ({ - ...state, - setState, - createEditor, - setEditor, - loadWorkspace: loadWorkspace.current, - loadPage: loadPage.current, - }), - [state, setState, loadPage, loadWorkspace] - ); - return ( - + + {children} ); }; + +export default AppStateProvider; diff --git a/packages/app/src/providers/app-state-provider/index.ts b/packages/app/src/providers/app-state-provider/index.ts index 88c38fd7cf..505094109d 100644 --- a/packages/app/src/providers/app-state-provider/index.ts +++ b/packages/app/src/providers/app-state-provider/index.ts @@ -1,2 +1 @@ -export * from './context'; -export * from './interface'; +export * from './Provider'; diff --git a/packages/app/src/providers/app-state-provider/interface.ts b/packages/app/src/providers/app-state-provider/interface.ts index 19b028703d..cd789a84da 100644 --- a/packages/app/src/providers/app-state-provider/interface.ts +++ b/packages/app/src/providers/app-state-provider/interface.ts @@ -1,17 +1,31 @@ -import { PageMeta as OriginalPageMeta } from '@blocksuite/store/dist/workspace/workspace'; +import { DataCenter, User, Workspace } from '@affine/datacenter'; +import type { EditorContainer } from '@blocksuite/editor'; -// export type PageMeta = { -// favorite: boolean; -// trash: boolean; -// trashDate: number | void; -// updatedDate: number | void; -// mode: EditorContainer['mode']; -// } & OriginalPageMeta; +import type { + Page as StorePage, + Workspace as StoreWorkspace, + PageMeta, +} from '@blocksuite/store'; -export interface PageMeta extends OriginalPageMeta { - favorite: boolean; - trash: boolean; - trashDate: number; - updatedDate: number; - mode: 'edgeless' | 'page'; -} +export type AppStateValue = { + dataCenter: DataCenter; + user: User | null; + workspaceList: Workspace[]; + currentWorkspace: StoreWorkspace; + currentWorkspaceId: string; + pageList: PageMeta[]; + currentPage: StorePage | null; + editor?: EditorContainer | null; + synced: boolean; +}; + +export type AppStateFunction = { + createEditor: (page: StorePage) => EditorContainer | null; + setEditor: (page: EditorContainer) => void; + loadWorkspace: (workspaceId: string) => Promise; + loadPage: (pageId: string) => void; +}; + +export type AppStateContext = AppStateValue & AppStateFunction; + +export type CreateEditorHandler = (page: StorePage) => EditorContainer | null; diff --git a/packages/app/src/providers/app-state-provider/utils.ts b/packages/app/src/providers/app-state-provider/utils.ts new file mode 100644 index 0000000000..066ef7a2c8 --- /dev/null +++ b/packages/app/src/providers/app-state-provider/utils.ts @@ -0,0 +1,10 @@ +import { DataCenter } from '@affine/datacenter'; + +const DEFAULT_WORKSPACE_NAME = 'affine'; + +export const createDefaultWorkspace = async (dataCenter: DataCenter) => { + return dataCenter.createWorkspace({ + avatar: 'test', + name: DEFAULT_WORKSPACE_NAME, + }); +}; diff --git a/packages/app/src/providers/app-state-provider3/DynamicBlocksuite.tsx b/packages/app/src/providers/app-state-provider3/DynamicBlocksuite.tsx new file mode 100644 index 0000000000..4b7b876545 --- /dev/null +++ b/packages/app/src/providers/app-state-provider3/DynamicBlocksuite.tsx @@ -0,0 +1,25 @@ +import { useEffect } from 'react'; +import type { Page } from '@blocksuite/store'; +import '@blocksuite/blocks'; +import { EditorContainer } from '@blocksuite/editor'; +import type { CreateEditorHandler } from './context'; + +interface Props { + setCreateEditorHandler: (handler: CreateEditorHandler) => void; +} + +const DynamicBlocksuite = ({ setCreateEditorHandler }: Props) => { + useEffect(() => { + const createEditorHandler: CreateEditorHandler = (page: Page) => { + const editor = new EditorContainer(); + editor.page = page; + return editor; + }; + + setCreateEditorHandler(createEditorHandler); + }, [setCreateEditorHandler]); + + return <>; +}; + +export default DynamicBlocksuite; diff --git a/packages/app/src/providers/app-state-provider3/Provider.tsx b/packages/app/src/providers/app-state-provider3/Provider.tsx new file mode 100644 index 0000000000..f104e9be3e --- /dev/null +++ b/packages/app/src/providers/app-state-provider3/Provider.tsx @@ -0,0 +1,144 @@ +import { useMemo, useState, useCallback, useRef } from 'react'; +import type { ReactNode } from 'react'; +import dynamic from 'next/dynamic'; +import { getDataCenter } from '@affine/datacenter'; +import { AppState, AppStateContext } from './context'; +import type { + AppStateValue, + CreateEditorHandler, + LoadWorkspaceHandler, +} from './context'; +import { Page } from '@blocksuite/store'; +import { EditorContainer } from '@blocksuite/editor'; +const DynamicBlocksuite = dynamic(() => import('./DynamicBlocksuite'), { + ssr: false, +}); + +const loadWorkspaceHandler: LoadWorkspaceHandler = async workspaceId => { + if (workspaceId) { + const dc = await getDataCenter(); + return dc.load(workspaceId, { providerId: 'affine' }); + } else { + return null; + } +}; +export const AppStateProvider = ({ children }: { children?: ReactNode }) => { + const refreshWorkspacesMeta = async () => { + const dc = await getDataCenter(); + const workspacesMeta = await dc.apis.getWorkspaces().catch(() => { + return []; + }); + setState(state => ({ ...state, workspacesMeta })); + }; + + const [state, setState] = useState({ + user: null, + workspacesMeta: [], + currentWorkspaceId: '', + currentWorkspace: null, + currentPage: null, + editor: null, + refreshWorkspacesMeta, + synced: true, + }); + + const [createEditorHandler, _setCreateEditorHandler] = + useState(); + + const setCreateEditorHandler = useCallback( + (handler: CreateEditorHandler) => { + _setCreateEditorHandler(() => handler); + }, + [_setCreateEditorHandler] + ); + + const loadWorkspace = useRef(() => + Promise.resolve(null) + ); + loadWorkspace.current = async (workspaceId: string) => { + if (state.currentWorkspaceId === workspaceId) { + return state.currentWorkspace; + } + const workspace = + (await loadWorkspaceHandler(workspaceId, state.user)) || null; + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + window.workspace = workspace; + // FIXME: there needs some method to destroy websocket. + // Or we need a manager to manage websocket. + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + state.currentWorkspace?.__ws__?.destroy(); + + setState(state => ({ + ...state, + currentWorkspace: workspace, + currentWorkspaceId: workspaceId, + })); + return workspace; + }; + + const loadPage = useRef(() => + Promise.resolve(null) + ); + loadPage.current = async (pageId: string) => { + const { currentWorkspace, currentPage } = state; + if (pageId === currentPage?.id) { + return currentPage; + } + const page = (pageId ? currentWorkspace?.getPage(pageId) : null) || null; + setState(state => ({ ...state, currentPage: page })); + return page; + }; + + const createEditor = useRef< + ((page: Page) => EditorContainer | null) | undefined + >(); + createEditor.current = () => { + const { currentPage, currentWorkspace } = state; + if (!currentPage || !currentWorkspace) { + return null; + } + const editor = createEditorHandler?.(currentPage) || null; + + if (editor) { + const pageMeta = currentWorkspace.meta.pageMetas.find( + p => p.id === currentPage.id + ); + if (pageMeta?.mode) { + editor.mode = pageMeta.mode as 'page' | 'edgeless' | undefined; + } + if (pageMeta?.trash) { + editor.readonly = true; + } + } + + return editor; + }; + + const setEditor = useRef<(editor: AppStateValue['editor']) => void>(); + + setEditor.current = (editor: AppStateValue['editor']) => { + setState(state => ({ ...state, editor })); + }; + + const context = useMemo( + () => ({ + ...state, + setState, + createEditor, + setEditor, + loadWorkspace: loadWorkspace.current, + loadPage: loadPage.current, + }), + [state, setState, loadPage, loadWorkspace] + ); + + return ( + + + {children} + + ); +}; diff --git a/packages/app/src/providers/app-state-provider/context.ts b/packages/app/src/providers/app-state-provider3/context.ts similarity index 100% rename from packages/app/src/providers/app-state-provider/context.ts rename to packages/app/src/providers/app-state-provider3/context.ts diff --git a/packages/app/src/providers/app-state-provider3/index.ts b/packages/app/src/providers/app-state-provider3/index.ts new file mode 100644 index 0000000000..88c38fd7cf --- /dev/null +++ b/packages/app/src/providers/app-state-provider3/index.ts @@ -0,0 +1,2 @@ +export * from './context'; +export * from './interface'; diff --git a/packages/app/src/providers/app-state-provider3/interface.ts b/packages/app/src/providers/app-state-provider3/interface.ts new file mode 100644 index 0000000000..19b028703d --- /dev/null +++ b/packages/app/src/providers/app-state-provider3/interface.ts @@ -0,0 +1,17 @@ +import { PageMeta as OriginalPageMeta } from '@blocksuite/store/dist/workspace/workspace'; + +// export type PageMeta = { +// favorite: boolean; +// trash: boolean; +// trashDate: number | void; +// updatedDate: number | void; +// mode: EditorContainer['mode']; +// } & OriginalPageMeta; + +export interface PageMeta extends OriginalPageMeta { + favorite: boolean; + trash: boolean; + trashDate: number; + updatedDate: number; + mode: 'edgeless' | 'page'; +} diff --git a/packages/data-center/src/index.ts b/packages/data-center/src/index.ts index 6fbb0e45db..297b1cf0c1 100644 --- a/packages/data-center/src/index.ts +++ b/packages/data-center/src/index.ts @@ -26,5 +26,6 @@ const _initializeDataCenter = () => { export const getDataCenter = _initializeDataCenter(); export type { AccessTokenMessage } from './provider/affine/apis'; -export type { Workspace } from './types'; +export * from './types'; +export { DataCenter } from './datacenter'; export { getLogger } from './logger'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37654527ef..40aca469e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,7 +151,7 @@ importers: y-protocols: ^1.0.5 yjs: ^13.5.44 dependencies: - '@blocksuite/blocks': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 + '@blocksuite/blocks': 0.3.1_yjs@13.5.44 '@blocksuite/store': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 debug: 4.3.4 encoding: 0.1.13 @@ -1491,8 +1491,8 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@blocksuite/blocks/0.3.1-20230106060050-1aad55d_yjs@13.5.44: - resolution: {integrity: sha512-qRNXmhjw+GAGsV1mI2XXPxYTlHfsFHv9ttTCNQ6IIcxvc5Hh6lWmdwVibxvlpYUkgEc1zv3/GxOEsR/ngpZXzQ==} + /@blocksuite/blocks/0.3.1-20230109032243-37ad3ba_yjs@13.5.44: + resolution: {integrity: sha512-UTlbk0Is7TMRBbvUyM2nivbqM/TLwRj1qArMYbOmvDGUNYadWo68cTwv/Ej2WwiKn22q4/4JHryGsv3gTCRz1Q==} dependencies: '@blocksuite/phasor': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 '@blocksuite/store': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 @@ -1511,6 +1511,25 @@ packages: - yjs dev: false + /@blocksuite/blocks/0.3.1_yjs@13.5.44: + resolution: {integrity: sha512-b0dGz2MG4yIgngJPRumaMY58wAsd2FEVSZl3tpCXlagK9I0HD165Bq70PxcaRHVjBSV1Gf29ZVHUF6BVTYogPw==} + dependencies: + '@blocksuite/store': 0.3.1_yjs@13.5.44 + '@tldraw/intersect': 1.8.0 + autosize: 5.0.2 + highlight.js: 11.7.0 + hotkeys-js: 3.10.1 + lit: 2.5.0 + perfect-freehand: 1.2.0 + quill: 1.3.7 + quill-cursors: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + - yjs + dev: false + /@blocksuite/editor/0.3.1-20230109032243-37ad3ba_yjs@13.5.44: resolution: {integrity: sha512-bYbMn4EL/od+xP4K3u2kJT08kJBpK6H7b4cbRb9No3SUwgNHvvVNxia/QH1AQXyKaZQj/DHFgVxrw9GKo2GIPA==} dependencies: @@ -1565,6 +1584,27 @@ packages: - utf-8-validate dev: false + /@blocksuite/store/0.3.1_yjs@13.5.44: + resolution: {integrity: sha512-kynVTDfNCSChz2JI2rtGHxRIV2YrLzvAgVajcbfDVCuXKG0siBoEjLasG1a0kvevbvW/FabrNAj+xaIplklioA==} + peerDependencies: + yjs: ^13 + dependencies: + '@types/flexsearch': 0.7.3 + '@types/quill': 1.3.10 + buffer: 6.0.3 + flexsearch: 0.7.21 + idb-keyval: 6.2.0 + ky: 0.33.1 + lib0: 0.2.58 + y-protocols: 1.0.5 + y-webrtc: 10.2.3 + yjs: 13.5.44 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /@changesets/apply-release-plan/6.1.3: resolution: {integrity: sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==} dependencies: From 3e9304fb050e4c4930c16a47c5a79317c769a015 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 16:45:26 +0800 Subject: [PATCH 071/298] feat: cache workspace instances --- packages/data-center/src/datacenter.ts | 53 +++++++++++-------- .../data-center/src/provider/affine/affine.ts | 16 +++--- packages/data-center/src/provider/base.ts | 9 ++++ .../data-center/src/provider/local/local.ts | 8 +-- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 00ca590ae3..907b0e310a 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -1,6 +1,6 @@ import { Workspaces } from './workspaces'; import type { WorkspacesChangeEvent } from './workspaces'; -import { BlobStorage, Workspace } from '@blocksuite/store'; +import { Workspace } from '@blocksuite/store'; import { BaseProvider } from './provider/base'; import { LocalProvider } from './provider/local/local'; import { AffineProvider } from './provider'; @@ -17,6 +17,7 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; export class DataCenter { private readonly _workspaces = new Workspaces(); private readonly _logger = getLogger('dc'); + private _workspaceInstances: Map = new Map(); /** * A mainProvider must exist as the only data trustworthy source. */ @@ -109,9 +110,14 @@ export class DataCenter { * @param {string} workspaceId workspace id */ private _getWorkspace(workspaceId: string) { - return new Workspace({ - room: workspaceId, - }).register(BlockSchema); + const workspaceInfo = this._workspaces.find(workspaceId); + assert(workspaceInfo, 'Workspace not found'); + return ( + this._workspaceInstances.get(workspaceId) || + new Workspace({ + room: workspaceId, + }).register(BlockSchema) + ); } /** @@ -149,8 +155,9 @@ export class DataCenter { const provider = this.providerMap.get(workspaceInfo.provider); assert(provider, `provide '${workspaceInfo.provider}' is not registered`); this._logger(`Loading ${workspaceInfo.provider} workspace: `, workspaceId); - - return await provider.warpWorkspace(this._getWorkspace(workspaceId)); + const workspace = this._getWorkspace(workspaceId); + this._workspaceInstances.set(workspaceId, workspace); + return await provider.warpWorkspace(workspace); } /** @@ -332,21 +339,23 @@ export class DataCenter { return; } - // /** - // * get blob url by workspaces id - // * @param id - // * @returns {Promise} blob url - // */ - // async getBlob(id: string): Promise { - // return await this._blobStorage.get(id); - // } + /** + * get blob url by workspaces id + * @param id + * @returns {Promise} blob url + */ + async getBlob(workspace: Workspace, id: string): Promise { + const blob = await workspace.blobs; + return (await blob?.get(id)) || ''; + } - // /** - // * up load blob and get a blob url - // * @param id - // * @returns {Promise} blob url - // */ - // async setBlob(blob: Blob): Promise { - // return await this._blobStorage.set(blob); - // } + /** + * up load blob and get a blob url + * @param id + * @returns {Promise} blob url + */ + async setBlob(workspace: Workspace, blob: Blob): Promise { + const blobStorage = await workspace.blobs; + return (await blobStorage?.set(blob)) || ''; + } } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index cb9b1704d3..28cb19f1f6 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -69,7 +69,7 @@ export class AffineProvider extends BaseProvider { override async warpWorkspace(workspace: Workspace) { const { doc, room } = workspace; assert(room); - this._initWorkspaceDb(workspace); + this.linkLocal(workspace); const updates = await downloadWorkspace(room); if (updates) { await new Promise(resolve => { @@ -77,8 +77,12 @@ export class AffineProvider extends BaseProvider { applyUpdate(doc, new Uint8Array(updates)); }); } - const ws = new WebsocketProvider('/', room, doc); - this._wsMap.set(room, ws); + let ws = this._wsMap.get(room); + if (!ws) { + ws = new WebsocketProvider('/', room, doc); + this._wsMap.set(room, ws); + } + ws.connect(); await new Promise((resolve, reject) => { // TODO: synced will also be triggered on reconnection after losing sync // There needs to be an event mechanism to emit the synchronization state to the upper layer @@ -231,7 +235,7 @@ export class AffineProvider extends BaseProvider { return await removeMember({ permissionId }); } - private async _initWorkspaceDb(workspace: Workspace) { + public override async linkLocal(workspace: Workspace) { assert(workspace.room); let idb = this._idbMap.get(workspace.room); idb?.destroy(); @@ -239,7 +243,7 @@ export class AffineProvider extends BaseProvider { this._idbMap.set(workspace.room, idb); await idb.whenSynced; this._logger('Local data loaded'); - return idb; + return workspace; } public override async createWorkspace( @@ -252,7 +256,7 @@ export class AffineProvider extends BaseProvider { room: id, }).register(BlockSchema); nw.meta.setName(meta.name); - this._initWorkspaceDb(nw); + this.linkLocal(nw); const workspaceInfo: WS = { name: meta.name, diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 249a536f21..5f531e2940 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -169,4 +169,13 @@ export class BaseProvider { email; return null; } + + /** + * link workspace to local caches + * @param workspace + * @returns + */ + public async linkLocal(workspace: Workspace): Promise { + return workspace; + } } diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index fb73ccce42..10df431481 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -22,21 +22,21 @@ export class LocalProvider extends BaseProvider { storage.setItem(WORKSPACE_KEY, JSON.stringify(workspaces)); } - private async _initWorkspaceDb(workspace: Workspace) { + public override async linkLocal(workspace: Workspace) { assert(workspace.room); let idb = this._idbMap.get(workspace.room); idb?.destroy(); idb = new IndexedDBProvider(workspace.room, workspace.doc); this._idbMap.set(workspace.room, idb); this._logger('Local data loaded'); - return idb; + return workspace; } public override async warpWorkspace( workspace: Workspace ): Promise { assert(workspace.room); - await this._initWorkspaceDb(workspace); + await this.linkLocal(workspace); return workspace; } @@ -93,7 +93,7 @@ export class LocalProvider extends BaseProvider { }; const workspace = new Workspace({ room: workspaceInfo.id }); - this._initWorkspaceDb(workspace); + this.linkLocal(workspace); workspace.meta.setName(meta.name); if (!meta.avatar) { // set default avatar From 15f06fe85e515314f22296e73ce627079518a5bd Mon Sep 17 00:00:00 2001 From: QiShaoXuan Date: Mon, 9 Jan 2023 16:51:52 +0800 Subject: [PATCH 072/298] feat: add workspace change event handler --- .../app/src/providers/app-state-provider/Provider.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/app/src/providers/app-state-provider/Provider.tsx b/packages/app/src/providers/app-state-provider/Provider.tsx index 50ef656fb6..9c65aae97c 100644 --- a/packages/app/src/providers/app-state-provider/Provider.tsx +++ b/packages/app/src/providers/app-state-provider/Provider.tsx @@ -80,6 +80,17 @@ export const AppStateProvider = ({ }; }, [appState]); + useEffect(() => { + const { dataCenter } = appState; + // FIXME: onWorkspacesChange should have dispose function + dataCenter?.onWorkspacesChange(() => { + setAppState({ + ...appState, + workspaceList: dataCenter.workspaces, + }); + }); + }, [appState]); + const loadPage = (pageId: string) => { const { currentWorkspace, currentPage } = appState; if (pageId === currentPage?.id) { From f7ff8f29b8a8e46bc1658aa14b807e20a10d99d4 Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 17:04:31 +0800 Subject: [PATCH 073/298] fix: test case for delete workspace --- packages/data-center/src/provider/local/local.spec.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts index f6a7c764ec..d1778f5b0f 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -48,10 +48,13 @@ test.describe.serial('local provider', () => { expect(workspaces.workspaces.length).toEqual(1); /** * FIXME - * Running following code will crash the worker, and get error like next line: + * If we don't wrap setTimeout, + * Running deleteWorkspace will crash the worker, and get error like next line: * InvalidStateError: An operation was called on an object on which it is not allowed or at a time when it is not allowed. Also occurs if a request is made on a source object that has been deleted or removed. Use TransactionInactiveError or ReadOnlyError when possible, as they are more specific variations of InvalidStateError. * */ - // await provider.deleteWorkspace(workspaces.workspaces[0].id); - // expect(workspaces.workspaces.length).toEqual(0); + setTimeout(async () => { + await provider.deleteWorkspace(workspaces.workspaces[0].id); + expect(workspaces.workspaces.length).toEqual(0); + }, 10); }); }); From 44008719592e0f52d1037280034e969b2ac05a71 Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 17:05:10 +0800 Subject: [PATCH 074/298] fix: remove type error --- packages/data-center/src/provider/local/local.spec.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts index d1778f5b0f..f24f118ffb 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -2,13 +2,11 @@ import { test, expect } from '@playwright/test'; import { Workspaces } from '../../workspaces/index.js'; import { LocalProvider } from './local.js'; import 'fake-indexeddb/auto'; -import { BlobStorage } from '@blocksuite/store'; test.describe.serial('local provider', () => { const workspaces = new Workspaces(); const provider = new LocalProvider({ workspaces: workspaces.createScope(), - blobs: new BlobStorage(), }); const workspaceName = 'workspace-test'; @@ -29,7 +27,6 @@ test.describe.serial('local provider', () => { const workspaces1 = new Workspaces(); const provider1 = new LocalProvider({ workspaces: workspaces1.createScope(), - blobs: new BlobStorage(), }); await provider1.loadWorkspaces(); expect(workspaces1.workspaces.length).toEqual(1); From dacfdfa57f16cd90c907e6490675af65f22d87af Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 17:15:19 +0800 Subject: [PATCH 075/298] refactor: remove unused files --- .../src/provider/{ => local}/indexeddb.ts | 0 .../data-center/src/provider/local/local.ts | 2 +- .../src/workspaces/workspaces.ts.bak | 101 ------------------ 3 files changed, 1 insertion(+), 102 deletions(-) rename packages/data-center/src/provider/{ => local}/indexeddb.ts (100%) delete mode 100644 packages/data-center/src/workspaces/workspaces.ts.bak diff --git a/packages/data-center/src/provider/indexeddb.ts b/packages/data-center/src/provider/local/indexeddb.ts similarity index 100% rename from packages/data-center/src/provider/indexeddb.ts rename to packages/data-center/src/provider/local/indexeddb.ts diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 10df431481..82ffe77741 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -3,7 +3,7 @@ import type { ProviderConstructorParams } from '../base'; import { varStorage as storage } from 'lib0/storage'; import { Workspace as WS, WorkspaceMeta } from '../../types'; import { Workspace, uuidv4 } from '@blocksuite/store'; -import { IndexedDBProvider } from '../indexeddb.js'; +import { IndexedDBProvider } from './indexeddb.js'; import assert from 'assert'; import { getDefaultHeadImgBlob } from '../../utils/index.js'; diff --git a/packages/data-center/src/workspaces/workspaces.ts.bak b/packages/data-center/src/workspaces/workspaces.ts.bak deleted file mode 100644 index f813f6b16d..0000000000 --- a/packages/data-center/src/workspaces/workspaces.ts.bak +++ /dev/null @@ -1,101 +0,0 @@ -import { Workspace as WS } from '../types'; - -import { Observable } from 'lib0/observable'; -import { uuidv4 } from '@blocksuite/store'; -import { DataCenter } from '../datacenter'; - -export class Workspaces extends Observable { - private _workspaces: WS[]; - private readonly _dc: DataCenter; - - constructor(dc: DataCenter) { - super(); - this._workspaces = []; - this._dc = dc; - } - - public init() { - this._loadWorkspaces(); - } - - get workspaces() { - return this._workspaces; - } - - /** - * emit when workspaces changed - * @param {(workspace: WS[]) => void} cb - */ - onWorkspacesChange(cb: (workspace: WS[]) => void) { - this.on('change', cb); - } - - private async _loadWorkspaces() { - const providers = this._dc.providers; - let workspaces: WS[] = []; - providers.forEach(async p => { - const pWorkspaces = await p.loadWorkspaces(); - workspaces = [...workspaces, ...pWorkspaces]; - this._updateWorkspaces([...workspaces, ...pWorkspaces]); - }); - } - - /** - * focus load all workspaces list - */ - public async refreshWorkspaces() { - this._loadWorkspaces(); - } - - private _updateWorkspaces(workspaces: WS[]) { - this._workspaces = workspaces; - this.emit('change', this._workspaces); - } - - private _getDefaultWorkspace(name: string): WS { - return { - name, - id: uuidv4(), - isPublish: false, - avatar: '', - owner: undefined, - isLocal: true, - memberCount: 1, - provider: 'local', - }; - } - - /** add a local workspaces */ - public addLocalWorkspace(name: string) { - const workspace = this._getDefaultWorkspace(name); - this._updateWorkspaces([...this._workspaces, workspace]); - return workspace; - } - - /** delete a workspaces by id */ - public delete(id: string) { - const index = this._workspaces.findIndex(w => w.id === id); - if (index >= 0) { - this._workspaces.splice(index, 1); - this._updateWorkspaces(this._workspaces); - } - } - - /** get workspace info by id */ - public getWorkspace(id: string) { - return this._workspaces.find(w => w.id === id); - } - - /** check if workspace exists */ - public hasWorkspace(id: string) { - return this._workspaces.some(w => w.id === id); - } - - public updateWorkspaceInfo(id: string, info: Partial) { - const index = this._workspaces.findIndex(w => w.id === id); - if (index >= 0) { - this._workspaces[index] = { ...this._workspaces[index], ...info }; - this._updateWorkspaces(this._workspaces); - } - } -} From 0b5cc1beda4f27cc67b5cd50917f27c6bdb6ac4f Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 17:18:58 +0800 Subject: [PATCH 076/298] feat: fix --- packages/data-center/src/datacenter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 907b0e310a..ee320d75ec 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -81,7 +81,7 @@ export class DataCenter { /** * create new workspace , new workspace is a local workspace * @param {string} name workspace name - * @returns {Promise} + * @returns {Promise} */ public async createWorkspace(workspaceMeta: WorkspaceMeta) { assert( From d6640e0793daf8565543faf7d046696b4e431e05 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Mon, 9 Jan 2023 17:25:00 +0800 Subject: [PATCH 077/298] feat: add createWoresapce function --- .../src/components/create-workspace/index.tsx | 7 ++-- .../src/components/workspace-modal/index.tsx | 33 ++++++++----------- .../components/workspace-slider-bar/index.tsx | 6 ++-- .../providers/app-state-provider/Provider.tsx | 14 ++++++++ .../providers/app-state-provider/interface.ts | 3 +- 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/packages/app/src/components/create-workspace/index.tsx b/packages/app/src/components/create-workspace/index.tsx index 05c37f9900..545eaec4c0 100644 --- a/packages/app/src/components/create-workspace/index.tsx +++ b/packages/app/src/components/create-workspace/index.tsx @@ -6,6 +6,7 @@ import Input from '@/ui/input'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { KeyboardEvent } from 'react'; import { useTranslation } from 'react-i18next'; +import { useAppState } from '@/providers/app-state-provider'; interface ICloseParams { workspaceId?: string; } @@ -16,11 +17,11 @@ interface ModalProps { export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { const [workspaceName, setWorkspaceName] = useState(''); - const { createWorkspace, setActiveWorkspace } = useTemporaryHelper(); + const { createWorkspace } = useAppState(); const handleCreateWorkspace = () => { const workspace = createWorkspace(workspaceName); - onClose({ workspaceId: workspace.id }); - setActiveWorkspace(workspace); + // onClose({ workspaceId: workspace.id }); + // setActiveWorkspace(workspace); }; const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Enter') { diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index cb0605a785..398a71acc4 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -10,10 +10,11 @@ import { UsersIcon, AddIcon, } from '@blocksuite/icons'; -import { useConfirm } from '@/providers/confirm-provider'; +import { useConfirm } from '@/providers/ConfirmProvider'; import { toast } from '@/ui/toast'; import { WorkspaceAvatar } from '@/components/workspace-avatar'; -import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; +// import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; +import { useAppState } from '@/providers/app-state-provider'; interface LoginModalProps { open: boolean; @@ -23,13 +24,7 @@ interface LoginModalProps { export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false); const { confirm } = useConfirm(); - const { - user, - login, - workspaceMetaList, - setActiveWorkspace, - updateWorkspaceMeta, - } = useTemporaryHelper(); + const { user, workspaceList } = useAppState(); return (
    @@ -51,11 +46,11 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { - {workspaceMetaList.map((item, index) => { + {workspaceList.map((item, index) => { return ( { - setActiveWorkspace(item); + // setActiveWorkspace(item); onClose(); }} key={index} @@ -93,10 +88,10 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { top: '20px', }} > - {(item.type === 'local' || !item.type) && ( + {(item.provider === 'local' || !item.provider) && ( )} - {item.type === 'cloud' && ( + {item.provider === 'affine' && ( )} {item.isPublish && } @@ -136,7 +131,7 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => { {!user ? ( diff --git a/packages/app/src/components/loading/PageLoading.tsx b/packages/app/src/components/loading/PageLoading.tsx index 025eba7687..0369d19b6f 100644 --- a/packages/app/src/components/loading/PageLoading.tsx +++ b/packages/app/src/components/loading/PageLoading.tsx @@ -1,5 +1,6 @@ import { styled } from '@/styles'; import Loading from './Loading'; +import { useTranslation } from 'react-i18next'; // Used for the full page loading const StyledLoadingContainer = styled('div')(() => { @@ -17,12 +18,13 @@ const StyledLoadingContainer = styled('div')(() => { }; }); -export const PageLoading = ({ text = 'Loading...' }: { text?: string }) => { +export const PageLoading = ({ text }: { text?: string }) => { + const { t } = useTranslation(); return (
    -

    {text}

    +

    {text ? text : t('Loading')}

    ); diff --git a/packages/app/src/components/login-modal/LoginOptionButton.tsx b/packages/app/src/components/login-modal/LoginOptionButton.tsx index c1384bc8eb..3da3010127 100644 --- a/packages/app/src/components/login-modal/LoginOptionButton.tsx +++ b/packages/app/src/components/login-modal/LoginOptionButton.tsx @@ -3,9 +3,10 @@ import { styled } from '@/styles'; import { Button } from '@/ui/button'; // import { useModal } from '@/providers/GlobalModalProvider'; import { GoogleIcon, StayLogOutIcon } from './Icons'; - +import { useTranslation } from 'react-i18next'; export const GoogleLoginButton = () => { // const { triggerLoginModal } = useModal(); + const { t } = useTranslation(); return ( { @@ -24,8 +25,10 @@ export const GoogleLoginButton = () => { - Continue with Google - Set up an AFFiNE account to sync data + {t('Continue with Google')} + + {t('Set up an AFFiNE account to sync data')} + @@ -33,6 +36,7 @@ export const GoogleLoginButton = () => { }; export const StayLogOutButton = () => { + const { t } = useTranslation(); return ( @@ -40,8 +44,8 @@ export const StayLogOutButton = () => { - Stay logged out - All changes are saved locally + {t('Stay logged out')} + {t('All changes are saved locally')} diff --git a/packages/app/src/components/login-modal/index.tsx b/packages/app/src/components/login-modal/index.tsx index f398383196..1af4aab2ae 100644 --- a/packages/app/src/components/login-modal/index.tsx +++ b/packages/app/src/components/login-modal/index.tsx @@ -3,13 +3,14 @@ import { styled } from '@/styles'; import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { TextButton } from '@/ui/button'; import { GoogleLoginButton, StayLogOutButton } from './LoginOptionButton'; - +import { useTranslation } from 'react-i18next'; interface LoginModalProps { open: boolean; onClose: () => void; } export const LoginModal = ({ open, onClose }: LoginModalProps) => { + const { t } = useTranslation(); return ( @@ -23,12 +24,12 @@ export const LoginModal = ({ open, onClose }: LoginModalProps) => { /> - Currently not logged in + {t('NotLoggedIn')}
    - }>Clear local data + }>{t('ClearData')}
    diff --git a/packages/app/src/components/mobile-modal/index.tsx b/packages/app/src/components/mobile-modal/index.tsx index ff9796359b..9142a5f170 100644 --- a/packages/app/src/components/mobile-modal/index.tsx +++ b/packages/app/src/components/mobile-modal/index.tsx @@ -3,8 +3,10 @@ import Modal, { ModalCloseButton, ModalWrapper } from '@/ui/modal'; import getIsMobile from '@/utils/get-is-mobile'; import { StyledButton, StyledContent, StyledTitle } from './styles'; import bg from './bg.png'; +import { useTranslation } from 'react-i18next'; export const MobileModal = () => { const [showModal, setShowModal] = useState(getIsMobile()); + const { t } = useTranslation(); return ( { }} /> - Ooops! + {t('Ooops!')} -

    Looks like you are browsing on a mobile device.

    -

    - We are still working on mobile support and recommend you use a - desktop device. -

    +

    {t('mobile device')}

    +

    {t('mobile device description')}

    { setShowModal(false); }} > - Got it + {t('Got it')}
    diff --git a/packages/app/src/components/page-list/Empty.tsx b/packages/app/src/components/page-list/Empty.tsx index ef13e1b117..f7a4e838b4 100644 --- a/packages/app/src/components/page-list/Empty.tsx +++ b/packages/app/src/components/page-list/Empty.tsx @@ -1,6 +1,9 @@ import React from 'react'; import { Empty } from '@/ui/empty'; -export const PageListEmpty = () => { +import { useTranslation } from 'react-i18next'; +export const PageListEmpty = (props: { listType: string }) => { + const { listType } = props; + const { t } = useTranslation(); return (
    { height={300} sx={{ marginTop: '100px', marginBottom: '30px' }} /> -

    Tips: Click Add to Favourites/Trash and the page will appear here.

    -

    (Designer is grappling with designing)

    + {listType === 'all' &&

    {t('emptyAllPages')}

    } + {listType === 'favorite' &&

    {t('emptyFavourite')}

    } + {listType === 'trash' &&

    {t('emptyTrash')}

    } +

    {t('still designed')}

    ); }; diff --git a/packages/app/src/components/page-list/index.tsx b/packages/app/src/components/page-list/index.tsx index 429ee6bbb9..1423406d58 100644 --- a/packages/app/src/components/page-list/index.tsx +++ b/packages/app/src/components/page-list/index.tsx @@ -67,16 +67,18 @@ export const PageList = ({ pageList, showFavoriteTag = false, isTrash = false, + listType, }: { pageList: PageMeta[]; showFavoriteTag?: boolean; isTrash?: boolean; + listType?: 'all' | 'trash' | 'favorite'; }) => { const router = useRouter(); const { currentWorkspaceId } = useAppState(); const { t } = useTranslation(); if (pageList.length === 0) { - return ; + return ; } return ( diff --git a/packages/app/src/components/quick-search/Input.tsx b/packages/app/src/components/quick-search/Input.tsx index 69d47a16a1..960f764c2c 100644 --- a/packages/app/src/components/quick-search/Input.tsx +++ b/packages/app/src/components/quick-search/Input.tsx @@ -9,6 +9,7 @@ import { SearchIcon } from '@blocksuite/icons'; import { StyledInputContent, StyledLabel } from './style'; import { Command } from 'cmdk'; import { useAppState } from '@/providers/app-state-provider'; +import { useTranslation } from 'react-i18next'; export const Input = (props: { query: string; setQuery: Dispatch>; @@ -17,6 +18,7 @@ export const Input = (props: { const [isComposition, setIsComposition] = useState(false); const [inputValue, setInputValue] = useState(''); const inputRef = useRef(null); + const { t } = useTranslation(); const { currentWorkspaceId, workspaceList, currentWorkspace } = useAppState(); const isPublish = workspaceList.find( meta => String(meta.id) === String(currentWorkspaceId) @@ -80,8 +82,10 @@ export const Input = (props: { }} placeholder={ isPublish - ? `Search in ${currentWorkspace?.meta.name}` - : 'Quick Search...' + ? t('Quick search placeholder2', { + workspace = currentWorkspace?.meta.name, + }) + : t('Quick search placeholder') } /> diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 641d8fbd30..40142a256d 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -16,7 +16,7 @@ import { WorkspaceAvatar } from '@/components/workspace-avatar'; import { useAppState } from '@/providers/app-state-provider'; import { useRouter } from 'next/router'; import { useUserHelper } from '@/hooks/use-user-helper'; - +import { useTranslation } from 'react-i18next'; interface WorkspaceModalProps { open: boolean; onClose: () => void; @@ -28,6 +28,7 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { const { workspaceList, currentWorkspace } = useAppState(); const { login, user } = useUserHelper(); const router = useRouter(); + const { t } = useTranslation(); return (
    @@ -36,7 +37,7 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { style={{ padding: '10px', display: 'flex', flexDirection: 'column' }} >
    - My Workspaces + {t('My Workspaces')} {/* */} { marginRight: '10px', }} /> - Create Or Import + {t('Create Or Import')}

    - Tips:Workspace is your virtual space to capture, create and plan - as just one person or together as a team. + {t('Tips')} + {t('Workspace description')}

    @@ -135,10 +136,10 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { ) : ( )}
    diff --git a/packages/app/src/components/workspace-setting/ExportPage.tsx b/packages/app/src/components/workspace-setting/ExportPage.tsx index 85d2b52799..fc95c119f2 100644 --- a/packages/app/src/components/workspace-setting/ExportPage.tsx +++ b/packages/app/src/components/workspace-setting/ExportPage.tsx @@ -1,6 +1,6 @@ import { styled } from '@/styles'; import { Workspace } from '@affine/datacenter'; - +import { Trans } from 'react-i18next'; export const ExportPageTitleContainer = styled('div')(() => { return { display: 'flex', @@ -12,8 +12,13 @@ export const ExportPageTitleContainer = styled('div')(() => { export const ExportPage = ({ workspace }: { workspace: Workspace }) => { return ( - Export Workspace{' '} - {workspace.name} Is Comming + + Export Workspace + + {{ workspace: workspace.name }} + + Is Comming + ); }; diff --git a/packages/app/src/components/workspace-setting/MembersPage.tsx b/packages/app/src/components/workspace-setting/MembersPage.tsx index ea0b68536b..fb303b69b5 100644 --- a/packages/app/src/components/workspace-setting/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/MembersPage.tsx @@ -27,6 +27,7 @@ import { Workspace } from '@affine/datacenter'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { StyledMemberWarp } from './general/style'; import { useConfirm } from '@/providers/ConfirmProvider'; +import { useTranslation } from 'react-i18next'; // import { useAppState } from '@/providers/app-state-provider'; export const MembersPage = ({ workspace }: { workspace: Workspace }) => { @@ -36,6 +37,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { ]); const { user, login, updateWorkspaceMeta } = useTemporaryHelper(); const { confirm } = useConfirm(); + const { t } = useTranslation(); // const refreshMembers = useCallback(() => { // getDataCenter() // .then(dc => @@ -66,9 +68,11 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { <> - Users({members.length}) + {t('Users')} ({members.length}) - Access level + + {t('Access level')} + {members.length ? ( @@ -92,7 +96,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { ? 'Member' : 'Workspace Owner' : 'Pending'} */} - Pending + {t('Pending')} { }} icon={} > - Delete + {t('Delete')} } @@ -154,7 +158,7 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { type="primary" shape="circle" > - Invite Members + {t('Invite Members')} { @@ -172,19 +176,17 @@ export const MembersPage = ({ workspace }: { workspace: Workspace }) => { ) : ( -
    - Collaborating with other members requires AFFiNE Cloud service. -
    +
    {t('Collaboration Description')}
    diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx index e3c36b9343..26961a221e 100644 --- a/packages/app/src/components/workspace-setting/PublishPage.tsx +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -13,12 +13,13 @@ import { useConfirm } from '@/providers/ConfirmProvider'; // import { useAppState } from '@/providers/app-state-provider3'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { Workspace } from '@affine/datacenter'; +import { useTranslation } from 'react-i18next'; export const PublishPage = ({ workspace }: { workspace: Workspace }) => { const shareUrl = window.location.host + '/workspace/' + workspace.id + '?share=true'; const { publishWorkspace } = useWorkspaceHelper(); - + const { t } = useTranslation(); const { confirm } = useConfirm(); const togglePublic = (flag: boolean) => { @@ -32,11 +33,11 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => { const enableAffineCloud = () => { confirm({ - title: 'Enable AFFiNE Cloud?', - content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`, + title: `${t('Enable AFFiNE Cloud')}?`, + content: t('Enable AFFiNE Cloud Description'), confirmText: - workspace.provider === 'local' ? 'Enable' : 'Sign in and Enable', - cancelText: 'Skip', + workspace.provider === 'local' ? t('Enable') : t('Sign in and Enable'), + cancelText: t('Skip'), }).then(confirm => { if (confirm) { // if (user) { @@ -56,22 +57,21 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => { {workspace?.isPublish ? ( <> - Publishing to web requires AFFiNE Cloud service . + {t('Publishing')} - Share with link + {t('Share with link')} ) : ( - After publishing to the web, everyone can view the content of - this workspace through the link. + {'Publishing Description'} )} @@ -83,7 +83,7 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => { type="primary" shape="circle" > - Stop publishing + {t('Stop publishing')} ) : ( )}
    @@ -101,7 +101,7 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => { <> - Publishing to web requires AFFiNE Cloud service. + {t('Publishing')} @@ -112,7 +112,7 @@ export const PublishPage = ({ workspace }: { workspace: Workspace }) => { type="primary" shape="circle" > - Enable AFFiNE Cloud + {t('Enable AFFiNE Cloud')} diff --git a/packages/app/src/components/workspace-setting/SyncPage.tsx b/packages/app/src/components/workspace-setting/SyncPage.tsx index 1c3cdaea8f..00bbeb9785 100644 --- a/packages/app/src/components/workspace-setting/SyncPage.tsx +++ b/packages/app/src/components/workspace-setting/SyncPage.tsx @@ -8,9 +8,11 @@ import { Button } from '@/ui/button'; import { Menu, MenuItem } from '@/ui/menu'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { Workspace } from '@affine/datacenter'; +import { Trans, useTranslation } from 'react-i18next'; export const SyncPage = ({ workspace }: { workspace: Workspace }) => { console.log('workspace: ', workspace); const { currentWorkspace, updateWorkspaceMeta } = useTemporaryHelper(); + const { t } = useTranslation(); return (
    diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index 87278ce734..6dee18e82e 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -17,6 +17,7 @@ import { Upload } from '@/components/file-upload'; import { WorkspaceAvatar } from '@/components/workspace-avatar'; import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { Workspace } from '@affine/datacenter'; +import { useTranslation } from 'react-i18next'; export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { // const { refreshWorkspacesMeta } = useAppState(); const { updateWorkspaceMeta } = useTemporaryHelper(); @@ -24,6 +25,7 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { const [showLeave, setShowLeave] = useState(false); const [uploading, setUploading] = useState(false); const [workspaceName, setWorkspaceName] = useState(''); + const { t } = useTranslation(); // const debouncedRefreshWorkspacesMeta = debounce(() => { // refreshWorkspacesMeta(); // }, 100); @@ -68,7 +70,7 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { return workspace ? (
    - Workspace Icon + {t('Workspace Icon')}
    { accept="image/gif,image/jpeg,image/jpg,image/png,image/svg" fileChange={fileChange} > - + {/* TODO: add upload logic */} - Workspace Name + {t('Workspace Name')} { '' )} */} - Workspace Type + {t('Workspace Type')} {workspace.provider} @@ -130,7 +132,7 @@ export const GeneralPage = ({ workspace }: { workspace: Workspace }) => { {isOwner ? ( <> { ) : ( <> void; @@ -31,6 +31,7 @@ export const WorkspaceDelete = ({ workspace, }: WorkspaceDeleteProps) => { const [deleteStr, setDeleteStr] = useState(''); + const { t } = useTranslation(); const router = useRouter(); const handlerInputChange = (workspaceName: string) => { @@ -55,31 +56,40 @@ export const WorkspaceDelete = ({ - Delete Workspace + {t('Delete Workspace')} {workspace.provider === 'local' ? ( - Deleting ( - {workspace.name}) cannot - be undone, please proceed with caution. along with all its content. + + Deleting ( + + {{ workspace: workspace.name }} + + ) cannot be undone, please proceed with caution. along with all + its content. + ) : ( - Deleting ( - {workspace.name}) will - delete both local and cloud data, this operation cannot be undone, - please proceed with caution. + + Deleting ( + + {{ workspace: workspace.name }} + + ) will delete both local and cloud data, this operation cannot be + undone, please proceed with caution. + )} diff --git a/packages/app/src/components/workspace-setting/general/leave/Leave.tsx b/packages/app/src/components/workspace-setting/general/leave/Leave.tsx index e34b4ac257..730c1cedbf 100644 --- a/packages/app/src/components/workspace-setting/general/leave/Leave.tsx +++ b/packages/app/src/components/workspace-setting/general/leave/Leave.tsx @@ -7,6 +7,7 @@ import { } from './style'; import { ModalCloseButton } from '@/ui/modal'; import { Button } from '@/ui/button'; +import { useTranslation } from 'react-i18next'; // import { getDataCenter } from '@affine/datacenter'; // import { useAppState } from '@/providers/app-state-provider'; @@ -22,6 +23,7 @@ export const WorkspaceLeave = ({ onClose, workspaceId, }: WorkspaceDeleteProps) => { + const { t } = useTranslation(); console.log('workspaceId: ', workspaceId); // const router = useRouter(); // const { refreshWorkspacesMeta } = useAppState(); @@ -37,14 +39,13 @@ export const WorkspaceLeave = ({ - Leave Workspace + {t('Leave Workspace')} - After you leave, you will not be able to access all the contents of - this workspace. + {t('Leave Workspace Description')} diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index c40dc31c11..18862017d5 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -157,7 +157,7 @@ export const WorkSpaceSliderBar = () => { setShowWorkspaceSetting(true); }} > - Setting + {t('Settings')} Chrome browser for optimal experience.", + "upgradeBrowser": "Please upgrade to the latest version of Chrome for the best experience.", + "Invite Members": "Invite Members", + "Invite placeholder": "Search mail (Gmail support only)", + "Non-Gmail": "Non-Gmail is not supported", + "Invite": "Invite", + "Loading": "Loading...", + "NotLoggedIn": "Currently not logged in", + "ClearData": "Clear local data", + "Continue with Google": "Continue with Google", + "Set up an AFFiNE account to sync data": "Set up an AFFiNE account to sync data", + "Stay logged out": "Stay logged out", + "All changes are saved locally": "All changes are saved locally", + "Ooops!": "Ooops!", + "mobile device": "Looks like you are browsing on a mobile device.", + "mobile device description": "We are still working on mobile support and recommend you use a desktop device.", + "Got it": "Got it", + "emptyAllPages": "This workspace is empty. Create a new page to begin editing.", + "emptyFavourite": "Click Add to Favourites and the page will appear here.", + "emptyTrash": "Click Add to Trash and the page will appear here.", + "still designed": "(This page is still being designed.)", + "My Workspaces": "My Workspaces", + "Create Or Import": "Create Or Import", + "Tips": "Tips: ", + "login success": "Login success", + "Sign in": "Sign in AFFiNE Cloud", + "Sign out": "Sign out of AFFiNE Cloud", + "Delete Workspace": "Delete Workspace", + "Delete Workspace Description": "Deleting (<1>{{workspace}}) cannot be undone, please proceed with caution. along with all its content.", + "Delete Workspace Description2": "Deleting (<1>{{workspace}}) will delete both local and cloud data, this operation cannot be undone, please proceed with caution.", + "Delete Workspace placeholder": "Please type “Delete” to confirm", + "Leave Workspace": "Leave Workspace", + "Leave Workspace Description": "After you leave, you will not be able to access all the contents of this workspace.", + "Leave": "Leave", + "Workspace Icon": "Workspace Icon", + "Workspace Name": "Workspace Name", + "Workspace Type": "Workspace Type", + "Export Workspace": "Export Workspace <1>{{workspace}} Is Coming", + "Users": "Users", + "Access level": "Access level", + "Pending": "Pending", + "Collaboration Description": "Collaborating with other members requires AFFiNE Cloud service.", + "Enable AFFiNE Cloud": "Enable AFFiNE Cloud", + "Enable AFFiNE Cloud Description": "If enabled, the data in this workspace will be backed up and synchronised via AFFiNE Cloud.", + "Enable": "Enable", + "Sign in and Enable": "Sign in and Enable", + "Skip": "Skip", + "Publishing": "Publishing to web requires AFFiNE Cloud service.", + "Share with link": "Share with link", + "Copy Link": "Copy Link", + "Publishing Description": "After publishing to the web, everyone can view the content of this workspace through the link.", + "Stop publishing": "Stop publishing", + "Publish to web": "Publish to web", + "Sync Description": "{{workspaceName}} is Local Workspace. All data is stored on the current device. You can enable AFFiNE Cloud for this workspace to keep data in sync with the cloud." } diff --git a/packages/app/src/pages/workspace/[workspaceId]/all.tsx b/packages/app/src/pages/workspace/[workspaceId]/all.tsx index 18f6e2a64b..6464a903bb 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/all.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/all.tsx @@ -14,6 +14,7 @@ const All = () => { !p.trash)} showFavoriteTag={true} + listType="all" /> ); diff --git a/packages/app/src/pages/workspace/[workspaceId]/favorite.tsx b/packages/app/src/pages/workspace/[workspaceId]/favorite.tsx index d787f34e1b..689bd3ead4 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/favorite.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/favorite.tsx @@ -13,7 +13,10 @@ export const Favorite = () => { }> {t('Favourites')} - p.favorite && !p.trash)} /> + p.favorite && !p.trash)} + listType="favorite" + /> ); }; diff --git a/packages/app/src/pages/workspace/[workspaceId]/trash.tsx b/packages/app/src/pages/workspace/[workspaceId]/trash.tsx index 2343b39138..e2baa990af 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/trash.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/trash.tsx @@ -11,7 +11,11 @@ export const Trash = () => { return ( <> }>{t('Trash')} - p.trash)} isTrash={true} /> + p.trash)} + isTrash={true} + listType="trash" + /> ); }; From 57749561757cd6df1ff2e87b25f275390a02da23 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Tue, 10 Jan 2023 14:53:27 +0800 Subject: [PATCH 122/298] chore: update i18n keys --- .../components/workspace-setting/SyncPage.tsx | 23 +++++++++++-------- .../workspace-setting/WorkspaceSetting.tsx | 16 +++++++------ packages/app/src/libs/i18n/resources/en.json | 9 +++++++- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/app/src/components/workspace-setting/SyncPage.tsx b/packages/app/src/components/workspace-setting/SyncPage.tsx index 00bbeb9785..0cb0069d2d 100644 --- a/packages/app/src/components/workspace-setting/SyncPage.tsx +++ b/packages/app/src/components/workspace-setting/SyncPage.tsx @@ -20,9 +20,7 @@ export const SyncPage = ({ workspace }: { workspace: Workspace }) => { {currentWorkspace?.type === 'local' ? ( <> - {currentWorkspace.name} is Local Workspace. All data is stored on - the current device. You can enable AFFiNE Cloud for this workspace - to keep data in sync with the cloud. + {t('Sync Description', { workspaceName: currentWorkspace.name })} @@ -35,15 +33,20 @@ export const SyncPage = ({ workspace }: { workspace: Workspace }) => { type="primary" shape="circle" > - Enable AFFiNE Cloud + {t('Enable AFFiNE Cloud')} ) : ( <> - {currentWorkspace && currentWorkspace.name} is Cloud - Workspace. All data will be synchronized and saved to the AFFiNE + + + {{ workspaceName: currentWorkspace && currentWorkspace.name }} + + is Cloud Workspace. All data will be synchronized and saved to + the AFFiNE + { }} icon={} > - Download core data to device + {t('Download data to device', { CoreOrAll: 'core' })} { @@ -63,14 +66,16 @@ export const SyncPage = ({ workspace }: { workspace: Workspace }) => { }} icon={} > - Download all data to device + {t('Download data to device', { CoreOrAll: 'all' })} } placement="bottom-end" disablePortal={true} > - + diff --git a/packages/app/src/components/workspace-setting/WorkspaceSetting.tsx b/packages/app/src/components/workspace-setting/WorkspaceSetting.tsx index c0213c2cca..64ffd5b8f9 100644 --- a/packages/app/src/components/workspace-setting/WorkspaceSetting.tsx +++ b/packages/app/src/components/workspace-setting/WorkspaceSetting.tsx @@ -21,6 +21,7 @@ import { PublishPage } from './PublishPage'; import { ExportPage } from './ExportPage'; import { SyncPage } from './SyncPage'; import { useAppState } from '@/providers/app-state-provider'; +import { useTranslation } from 'react-i18next'; enum ActiveTab { 'general' = 'general', @@ -41,6 +42,7 @@ type WorkspaceSettingProps = { }; const WorkspaceSettingTab = ({ activeTab, onTabChange }: SettingTabProps) => { + const { t } = useTranslation(); return ( { - General + {t('General')} { - Sync + {t('Sync')} { - Collaboration + {t('Collaboration')} { - Publish + {t('Publish')} { - Export + {t('Export')} ); @@ -114,7 +116,7 @@ export const WorkspaceSetting = ({ const handleTabChange = (tab: ActiveTab) => { setActiveTab(tab); }; - + const { t } = useTranslation(); const { currentMetaWorkSpace } = useAppState(); const handleClickClose = () => { onClose && onClose(); @@ -133,7 +135,7 @@ export const WorkspaceSetting = ({ {isOwner ? ( - Workspace Settings + {t('Workspace Settings')} {{workspaceName}} is Cloud Workspace. All data will be synchronized and saved to the AFFiNE", + "Download data to device": "Download {{CoreOrAll}} data to device", + "General": "General", + "Sync": "Sync", + "Collaboration": "Collaboration", + "Publish": "Publish", + "Workspace Settings": "Workspace Settings" } From aeb1b1688da79c8bb31f43430a30647a4419a8c1 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Tue, 10 Jan 2023 14:56:53 +0800 Subject: [PATCH 123/298] fix: fix avatar id --- packages/data-center/src/provider/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/data-center/src/provider/utils.ts b/packages/data-center/src/provider/utils.ts index b0a08b92d7..d8e5f6d058 100644 --- a/packages/data-center/src/provider/utils.ts +++ b/packages/data-center/src/provider/utils.ts @@ -8,8 +8,7 @@ export const setDefaultAvatar = async ( const blob = await getDefaultHeadImgBlob(blocksuiteWorkspace.meta.name); const blobStorage = await blocksuiteWorkspace.blobs; assert(blobStorage, 'No blob storage'); - const blobId = await blobStorage.set(blob); - const avatar = await blobStorage.get(blobId); + const avatar = await blobStorage.set(blob); if (avatar) { blocksuiteWorkspace.meta.setAvatar(avatar); } From ff63de2aa5302fb44f76c2f32bc81154fdea4cf9 Mon Sep 17 00:00:00 2001 From: alt0 Date: Tue, 10 Jan 2023 15:03:28 +0800 Subject: [PATCH 124/298] refactor: workspaces -> workspaceMetaCollection --- packages/data-center/src/datacenter.ts | 34 +++++++++---------- packages/data-center/src/provider/base.ts | 6 ++-- ...c.ts => workspace-meta-collection.spec.ts} | 14 ++++---- ...spaces.ts => workspace-meta-collection.ts} | 16 ++++----- packages/data-center/src/workspaces/index.ts | 2 -- 5 files changed, 35 insertions(+), 37 deletions(-) rename packages/data-center/src/{workspaces/workspaces.spec.ts => workspace-meta-collection.spec.ts} (64%) rename packages/data-center/src/{workspaces/workspaces.ts => workspace-meta-collection.ts} (86%) delete mode 100644 packages/data-center/src/workspaces/index.ts diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 8455737b5a..1efb93ca79 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -1,5 +1,5 @@ -import { Workspaces } from './workspaces'; -import type { WorkspacesChangeEvent } from './workspaces'; +import { WorkspaceMetaCollection } from './workspace-meta-collection.js'; +import type { WorkspaceMetaCollectionChangeEvent } from './workspace-meta-collection'; import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; import { BaseProvider } from './provider/base'; import { LocalProvider } from './provider/local/local'; @@ -15,7 +15,7 @@ import { createBlocksuiteWorkspace } from './utils/index.js'; * @classdesc Data center is made for managing different providers for business */ export class DataCenter { - private readonly _workspaces = new Workspaces(); + private readonly _workspaceMetaCollection = new WorkspaceMetaCollection(); private readonly _logger = getLogger('dc'); private _workspaceInstances: Map = new Map(); /** @@ -34,13 +34,13 @@ export class DataCenter { dc.registerProvider( new LocalProvider({ logger: dc._logger, - workspaces: dc._workspaces.createScope(), + workspaces: dc._workspaceMetaCollection.createScope(), }) ); dc.registerProvider( new AffineProvider({ logger: dc._logger, - workspaces: dc._workspaces.createScope(), + workspaces: dc._workspaceMetaCollection.createScope(), }) ); @@ -69,7 +69,7 @@ export class DataCenter { } public get workspaces() { - return this._workspaces.workspaces; + return this._workspaceMetaCollection.workspaces; } public async refreshWorkspaces() { @@ -104,7 +104,7 @@ export class DataCenter { * @param {string} workspaceId workspace id */ public async deleteWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaces.find(workspaceId); + const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); assert(provider, `Workspace exists, but we couldn't find its provider.`); @@ -116,7 +116,7 @@ export class DataCenter { * @param {string} workspaceId workspace id */ private _getBlocksuiteWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaces.find(workspaceId); + const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); return ( this._workspaceInstances.get(workspaceId) || @@ -150,7 +150,7 @@ export class DataCenter { * @returns {Promise} */ public async loadWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaces.find(workspaceId); + const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const currentProvider = this.providerMap.get(workspaceInfo.provider); if (currentProvider) { @@ -181,9 +181,9 @@ export class DataCenter { * @param {Function} callback callback function */ public async onWorkspacesChange( - callback: (workspaces: WorkspacesChangeEvent) => void + callback: (workspaces: WorkspaceMetaCollectionChangeEvent) => void ) { - this._workspaces.on('change', callback); + this._workspaceMetaCollection.on('change', callback); } /** @@ -206,7 +206,7 @@ export class DataCenter { update.avatar = avatar; } // may run for change workspace meta - const workspaceInfo = this._workspaces.find(workspace.room); + const workspaceInfo = this._workspaceMetaCollection.find(workspace.room); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); provider?.updateWorkspaceMeta(workspace.room, update); @@ -218,7 +218,7 @@ export class DataCenter { * @param id workspace id */ public async leaveWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaces.find(workspaceId); + const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -228,7 +228,7 @@ export class DataCenter { } public async setWorkspacePublish(workspaceId: string, isPublish: boolean) { - const workspaceInfo = this._workspaces.find(workspaceId); + const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -237,7 +237,7 @@ export class DataCenter { } public async inviteMember(id: string, email: string) { - const workspaceInfo = this._workspaces.find(id); + const workspaceInfo = this._workspaceMetaCollection.find(id); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -250,7 +250,7 @@ export class DataCenter { * @param {number} permissionId permission id */ public async removeMember(workspaceId: string, permissionId: number) { - const workspaceInfo = this._workspaces.find(workspaceId); + const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -281,7 +281,7 @@ export class DataCenter { providerId: string ) { assert(workspace.room, 'No workspace id'); - const workspaceInfo = this._workspaces.find(workspace.room); + const workspaceInfo = this._workspaceMetaCollection.find(workspace.room); assert(workspaceInfo, 'Workspace not found'); if (workspaceInfo.provider === providerId) { this._logger('Workspace provider is same'); diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index f7a056110c..c21939103f 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -1,6 +1,6 @@ import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; import { Logger, User, WorkspaceInfo, WorkspaceMeta } from '../types'; -import type { WorkspacesScope } from '../workspaces'; +import type { WorkspaceMetaCollectionScope } from '../workspace-meta-collection'; const defaultLogger = () => { return; @@ -8,12 +8,12 @@ const defaultLogger = () => { export interface ProviderConstructorParams { logger?: Logger; - workspaces: WorkspacesScope; + workspaces: WorkspaceMetaCollectionScope; } export class BaseProvider { public readonly id: string = 'base'; - protected _workspaces!: WorkspacesScope; + protected _workspaces!: WorkspaceMetaCollectionScope; protected _logger!: Logger; public constructor({ logger, workspaces }: ProviderConstructorParams) { diff --git a/packages/data-center/src/workspaces/workspaces.spec.ts b/packages/data-center/src/workspace-meta-collection.spec.ts similarity index 64% rename from packages/data-center/src/workspaces/workspaces.spec.ts rename to packages/data-center/src/workspace-meta-collection.spec.ts index c7925fdfff..afb3eb65f5 100644 --- a/packages/data-center/src/workspaces/workspaces.spec.ts +++ b/packages/data-center/src/workspace-meta-collection.spec.ts @@ -1,14 +1,14 @@ import { test, expect } from '@playwright/test'; -import { Workspaces } from './workspaces.js'; -import type { WorkspacesChangeEvent } from './workspaces'; +import { WorkspaceMetaCollection } from './workspace-meta-collection.js'; +import type { WorkspaceMetaCollectionChangeEvent } from './workspace-meta-collection'; -test.describe.serial('workspaces observable', () => { - const workspaces = new Workspaces(); +test.describe.serial('workspace meta collection observable', () => { + const workspaces = new WorkspaceMetaCollection(); const scope = workspaces.createScope(); test('add workspace', () => { - workspaces.once('change', (event: WorkspacesChangeEvent) => { + workspaces.once('change', (event: WorkspaceMetaCollectionChangeEvent) => { expect(event.added?.id).toEqual('123'); }); scope.add({ @@ -30,7 +30,7 @@ test.describe.serial('workspaces observable', () => { }); test('update workspace', () => { - workspaces.once('change', (event: WorkspacesChangeEvent) => { + workspaces.once('change', (event: WorkspaceMetaCollectionChangeEvent) => { expect(event.updated?.name).toEqual('demo'); }); scope.update('123', { name: 'demo' }); @@ -42,7 +42,7 @@ test.describe.serial('workspaces observable', () => { }); test('delete workspace', () => { - workspaces.once('change', (event: WorkspacesChangeEvent) => { + workspaces.once('change', (event: WorkspaceMetaCollectionChangeEvent) => { expect(event.deleted?.id).toEqual('123'); }); scope.remove('123'); diff --git a/packages/data-center/src/workspaces/workspaces.ts b/packages/data-center/src/workspace-meta-collection.ts similarity index 86% rename from packages/data-center/src/workspaces/workspaces.ts rename to packages/data-center/src/workspace-meta-collection.ts index d248951dc7..6b7ce4a350 100644 --- a/packages/data-center/src/workspaces/workspaces.ts +++ b/packages/data-center/src/workspace-meta-collection.ts @@ -1,7 +1,7 @@ import { Observable } from 'lib0/observable'; -import type { WorkspaceInfo, WorkspaceMeta } from '../types'; +import type { WorkspaceInfo, WorkspaceMeta } from './types'; -export interface WorkspacesScope { +export interface WorkspaceMetaCollectionScope { get: (workspaceId: string) => WorkspaceInfo | undefined; list: () => WorkspaceInfo[]; add: (workspace: WorkspaceInfo) => void; @@ -10,13 +10,13 @@ export interface WorkspacesScope { update: (workspaceId: string, workspaceMeta: Partial) => void; } -export interface WorkspacesChangeEvent { +export interface WorkspaceMetaCollectionChangeEvent { added?: WorkspaceInfo; deleted?: WorkspaceInfo; updated?: WorkspaceInfo; } -export class Workspaces extends Observable<'change'> { +export class WorkspaceMetaCollection extends Observable<'change'> { private _workspacesMap = new Map(); get workspaces(): WorkspaceInfo[] { @@ -27,7 +27,7 @@ export class Workspaces extends Observable<'change'> { return this._workspacesMap.get(workspaceId); } - createScope(): WorkspacesScope { + createScope(): WorkspaceMetaCollectionScope { const scopedWorkspaceIds = new Set(); const get = (workspaceId: string) => { @@ -47,7 +47,7 @@ export class Workspaces extends Observable<'change'> { this.emit('change', [ { added: workspace, - } as WorkspacesChangeEvent, + } as WorkspaceMetaCollectionChangeEvent, ]); }; @@ -69,7 +69,7 @@ export class Workspaces extends Observable<'change'> { this.emit('change', [ { deleted: workspace, - } as WorkspacesChangeEvent, + } as WorkspaceMetaCollectionChangeEvent, ]); } return true; @@ -99,7 +99,7 @@ export class Workspaces extends Observable<'change'> { this.emit('change', [ { updated: this._workspacesMap.get(workspaceId), - } as WorkspacesChangeEvent, + } as WorkspaceMetaCollectionChangeEvent, ]); }; diff --git a/packages/data-center/src/workspaces/index.ts b/packages/data-center/src/workspaces/index.ts deleted file mode 100644 index a8ef316e8d..0000000000 --- a/packages/data-center/src/workspaces/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Workspaces } from './workspaces.js'; -export type { WorkspacesScope, WorkspacesChangeEvent } from './workspaces'; From 51e6f4344ae21bd73176a55e6a55ff1efcc1d4dd Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Tue, 10 Jan 2023 15:06:55 +0800 Subject: [PATCH 125/298] fix: setting style and replace refer --- .../src/components/workspace-avatar/index.tsx | 1 + .../workspace-setting/general/General.tsx | 22 ++++++------------- .../src/components/workspace-setting/index.ts | 1 + .../src/components/workspace-setting/style.ts | 4 ---- .../WorkspaceSelector/WorkspaceSelector.tsx | 3 +-- .../app/src/hooks/use-workspace-helper.ts | 12 +++++----- .../pages/workspace/[workspaceId]/setting.tsx | 15 +++++++------ 7 files changed, 23 insertions(+), 35 deletions(-) diff --git a/packages/app/src/components/workspace-avatar/index.tsx b/packages/app/src/components/workspace-avatar/index.tsx index b810a0e720..bcb5b1aa20 100644 --- a/packages/app/src/components/workspace-avatar/index.tsx +++ b/packages/app/src/components/workspace-avatar/index.tsx @@ -3,6 +3,7 @@ import { stringToColour } from '@/utils'; interface IWorkspaceAvatar { size: number; name: string; + avatar: string; } export const WorkspaceAvatar = (props: IWorkspaceAvatar) => { diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index a424685e97..f33f3e3ebd 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -43,24 +43,12 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceInfo }) => { const handleUpdateWorkspaceName = () => { console.log('currentWorkspace: ', currentWorkspace); updateWorkspace({ name: workspaceName }, currentWorkspace); - // workspace && currentWorkspace(workspace.id, { name: workspaceName }); }; const fileChange = async (file: File) => { - console.log('file: ', file); + // console.log('file: ', file); setUploading(true); - // const blob = new Blob([file], { type: file.type }); - // const blobId = await getDataCenter() - // .then(dc => dc.apis.uploadBlob({ blob })) - // .finally(() => { - // setUploading(false); - // }); - // if (blobId) { - // currentWorkspace?.meta.setAvatar(blobId); - // // workspaces[workspace.id]?.meta.setAvatar(blobId); - // setUploading(false); - // debouncedRefreshWorkspacesMeta(); - // } + const blob = new Blob([file], { type: file.type }); }; return workspace ? ( @@ -73,7 +61,11 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceInfo }) => { marginRight: '20px', }} > - +
    { export const StyledSettingContent = styled('div')(() => { return { paddingLeft: '48px', - height: '620px', }; }); @@ -30,7 +29,6 @@ export const StyledSetting = styled('div')(({ theme }) => { { return { width: '236px', - height: '620px', background: theme.mode === 'dark' ? '#272727' : '#FBFBFC', }; } @@ -136,7 +134,6 @@ export const StyledMemberRoleContainer = styled('div')(() => { export const StyledMemberListContainer = styled('ul')(() => { return { marginTop: '15px', - height: '432px', overflowY: 'scroll', }; }); @@ -220,7 +217,6 @@ export const StyledCopyButtonContainer = styled('div')(() => { export const StyledPublishContent = styled('div')(() => { return { - height: '494px', display: 'flex', flexDirection: 'column', }; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx index 1f2b9612f6..2a19bd7d90 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceSelector.tsx @@ -6,14 +6,12 @@ import { useAppState } from '@/providers/app-state-provider'; export const WorkspaceSelector = () => { const [workspaceListShow, setWorkspaceListShow] = useState(false); const { currentMetaWorkSpace, workspaceList } = useAppState(); - console.log('currentMetaWorkSpace: ', currentMetaWorkSpace); useEffect(() => { if (workspaceList.length === 0) { setWorkspaceListShow(true); } }, [workspaceList]); - return ( <> {
    diff --git a/packages/app/src/hooks/use-workspace-helper.ts b/packages/app/src/hooks/use-workspace-helper.ts index 798c7c3831..f22f8cd4aa 100644 --- a/packages/app/src/hooks/use-workspace-helper.ts +++ b/packages/app/src/hooks/use-workspace-helper.ts @@ -1,13 +1,10 @@ import { useAppState } from '@/providers/app-state-provider'; -import { stringToColour } from '@/utils'; -import { WorkspaceInfo } from '@affine/datacenter'; import { Workspace } from '@blocksuite/store'; export const useWorkspaceHelper = () => { const { dataCenter } = useAppState(); const createWorkspace = async (name: string) => { const workspaceInfo = await dataCenter.createWorkspace({ name: name, - avatar: 'cccc', }); if (workspaceInfo && workspaceInfo.room) { const workspace = await dataCenter.loadWorkspace(workspaceInfo.room); @@ -23,15 +20,16 @@ export const useWorkspaceHelper = () => { }; const updateWorkspace = async ( - { name, avatar }: { name?: string; avatar?: string }, + { name, avatarBlob }: { name?: string; avatarBlob?: Blob }, workspace: Workspace ) => { if (name) { dataCenter.updateWorkspaceMeta({ name }, workspace); } - // if (avatar) { - // dataCenter.resetWorkspaceMeta({ avatar }, workspace); - // } + if (avatarBlob) { + const blobId = await dataCenter.setBlob(workspace, avatarBlob); + dataCenter.updateWorkspaceMeta({ avatar: blobId }, workspace); + } }; return { createWorkspace, diff --git a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx index 27122bb2f4..8a2eb21296 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx @@ -1,4 +1,3 @@ -import Modal, { ModalCloseButton } from '@/ui/modal'; import { StyledSettingContainer, StyledSettingContent, @@ -7,7 +6,7 @@ import { StyledSettingTabContainer, StyledSettingTagIconContainer, WorkspaceSettingTagItem, -} from '../../../components/workspace-setting/style'; +} from '@/components/workspace-setting/style'; import { EditIcon, UsersIcon, @@ -15,11 +14,13 @@ import { CloudInsyncIcon, } from '@blocksuite/icons'; import { ReactElement, useEffect, useState } from 'react'; -import { GeneralPage } from '../../../components/workspace-setting/general'; -import { MembersPage } from '../../../components/workspace-setting/MembersPage'; -import { PublishPage } from '../../../components/workspace-setting/PublishPage'; -import { ExportPage } from '../../../components/workspace-setting/ExportPage'; -import { SyncPage } from '../../../components/workspace-setting/SyncPage'; +import { + GeneralPage, + MembersPage, + PublishPage, + ExportPage, + SyncPage, +} from '@/components/workspace-setting'; import { useAppState } from '@/providers/app-state-provider'; import WorkspaceLayout from '@/components/workspace-layout'; From ecec2d6efe44ee96465795c1fb6599502be033ee Mon Sep 17 00:00:00 2001 From: alt0 Date: Tue, 10 Jan 2023 15:07:50 +0800 Subject: [PATCH 126/298] test: fix test case --- .../provider/affine/__tests__/affine.spec.ts | 2 +- .../src/provider/local/local.spec.ts | 28 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/data-center/src/provider/affine/__tests__/affine.spec.ts b/packages/data-center/src/provider/affine/__tests__/affine.spec.ts index 3208c6d54d..f60af0d139 100644 --- a/packages/data-center/src/provider/affine/__tests__/affine.spec.ts +++ b/packages/data-center/src/provider/affine/__tests__/affine.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from '@playwright/test'; import { AffineProvider } from '../affine.js'; -import { Workspaces } from '../../../workspaces/index.js'; +// import { Workspaces } from '../../../workspaces/index.js'; import { apis } from './mock-apis.js'; import 'fake-indexeddb/auto'; diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts index 5d388470a6..eff462ef86 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -1,13 +1,13 @@ import { test, expect } from '@playwright/test'; -import { Workspaces } from '../../workspaces/index.js'; +import { WorkspaceMetaCollection } from '../../workspace-meta-collection.js'; import { LocalProvider } from './local.js'; import { createBlocksuiteWorkspace } from '../../utils/index.js'; import 'fake-indexeddb/auto'; test.describe.serial('local provider', () => { - const workspaces = new Workspaces(); + const workspaceMetaCollection = new WorkspaceMetaCollection(); const provider = new LocalProvider({ - workspaces: workspaces.createScope(), + workspaces: workspaceMetaCollection.createScope(), }); const workspaceName = 'workspace-test'; @@ -25,30 +25,30 @@ test.describe.serial('local provider', () => { avatar: 'avatar-url-test', }); - expect(workspaces.workspaces.length).toEqual(1); - expect(workspaces.workspaces[0].name).toEqual(workspaceName); + expect(workspaceMetaCollection.workspaces.length).toEqual(1); + expect(workspaceMetaCollection.workspaces[0].name).toEqual(workspaceName); }); test('workspace list cache', async () => { - const workspaces1 = new Workspaces(); + const workspacesMetaCollection1 = new WorkspaceMetaCollection(); const provider1 = new LocalProvider({ - workspaces: workspaces1.createScope(), + workspaces: workspacesMetaCollection1.createScope(), }); await provider1.loadWorkspaces(); - expect(workspaces1.workspaces.length).toEqual(1); - expect(workspaces1.workspaces[0].name).toEqual(workspaceName); - expect(workspaces1.workspaces[0].id).toEqual(workspaceId); + expect(workspacesMetaCollection1.workspaces.length).toEqual(1); + expect(workspacesMetaCollection1.workspaces[0].name).toEqual(workspaceName); + expect(workspacesMetaCollection1.workspaces[0].id).toEqual(workspaceId); }); test('update workspace', async () => { await provider.updateWorkspaceMeta(workspaceId!, { name: '1111', }); - expect(workspaces.workspaces[0].name).toEqual('1111'); + expect(workspaceMetaCollection.workspaces[0].name).toEqual('1111'); }); test('delete workspace', async () => { - expect(workspaces.workspaces.length).toEqual(1); + expect(workspaceMetaCollection.workspaces.length).toEqual(1); /** * FIXME * If we don't wrap setTimeout, @@ -56,8 +56,8 @@ test.describe.serial('local provider', () => { * InvalidStateError: An operation was called on an object on which it is not allowed or at a time when it is not allowed. Also occurs if a request is made on a source object that has been deleted or removed. Use TransactionInactiveError or ReadOnlyError when possible, as they are more specific variations of InvalidStateError. * */ setTimeout(async () => { - await provider.deleteWorkspace(workspaces.workspaces[0].id); - expect(workspaces.workspaces.length).toEqual(0); + await provider.deleteWorkspace(workspaceMetaCollection.workspaces[0].id); + expect(workspaceMetaCollection.workspaces.length).toEqual(0); }, 10); }); }); From 64e90640b9e74a40a4d287cd8b6542aced1534a0 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Tue, 10 Jan 2023 15:20:54 +0800 Subject: [PATCH 127/298] feat:update workspace avatar --- .../src/components/workspace-avatar/index.tsx | 60 ++++++++++++++----- .../src/components/workspace-modal/index.tsx | 6 +- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/packages/app/src/components/workspace-avatar/index.tsx b/packages/app/src/components/workspace-avatar/index.tsx index bcb5b1aa20..494758100e 100644 --- a/packages/app/src/components/workspace-avatar/index.tsx +++ b/packages/app/src/components/workspace-avatar/index.tsx @@ -1,4 +1,6 @@ +import { useAppState } from '@/providers/app-state-provider'; import { stringToColour } from '@/utils'; +import { useEffect, useState } from 'react'; interface IWorkspaceAvatar { size: number; @@ -9,23 +11,51 @@ interface IWorkspaceAvatar { export const WorkspaceAvatar = (props: IWorkspaceAvatar) => { const size = props.size || 20; const sizeStr = size + 'px'; + const { dataCenter, currentWorkspace } = useAppState(); + dataCenter.getBlob(currentWorkspace, props.avatar).then(res => { + console.log(res); + setAvatar(res ?? ''); + }); + const [avatar, setAvatar] = useState(props.avatar); + + useEffect(() => { + dataCenter.getBlob(currentWorkspace, props.avatar).then(res => { + setAvatar(res ?? ''); + }); + }, [props.avatar]); + return ( <> -
    - {(props.name || 'AFFiNE').substring(0, 1)} -
    + {avatar ? ( +
    + +
    + ) : ( +
    + {(props.name || 'AFFiNE').substring(0, 1)} +
    + )} ); }; diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 641d8fbd30..3621d22e47 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -67,7 +67,11 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { marginRight: '10px', }} > - +
    Date: Tue, 10 Jan 2023 15:35:07 +0800 Subject: [PATCH 128/298] feat: setting style --- .../src/components/workspace-avatar/index.tsx | 1 - .../workspace-setting/MembersPage.tsx | 9 ++++----- .../components/workspace-setting/SyncPage.tsx | 20 +++++++++---------- .../workspace-setting/general/style.ts | 3 +-- .../src/components/workspace-setting/style.ts | 2 ++ 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/packages/app/src/components/workspace-avatar/index.tsx b/packages/app/src/components/workspace-avatar/index.tsx index 494758100e..ebce8a9f13 100644 --- a/packages/app/src/components/workspace-avatar/index.tsx +++ b/packages/app/src/components/workspace-avatar/index.tsx @@ -13,7 +13,6 @@ export const WorkspaceAvatar = (props: IWorkspaceAvatar) => { const sizeStr = size + 'px'; const { dataCenter, currentWorkspace } = useAppState(); dataCenter.getBlob(currentWorkspace, props.avatar).then(res => { - console.log(res); setAvatar(res ?? ''); }); const [avatar, setAvatar] = useState(props.avatar); diff --git a/packages/app/src/components/workspace-setting/MembersPage.tsx b/packages/app/src/components/workspace-setting/MembersPage.tsx index e596e2d5f8..32639f874f 100644 --- a/packages/app/src/components/workspace-setting/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/MembersPage.tsx @@ -10,6 +10,7 @@ import { StyledMemberRoleContainer, StyledMemberTitleContainer, StyledMoreVerticalButton, + StyledPublishExplanation, } from './style'; import { MoreVerticalIcon, EmailIcon, TrashIcon } from '@blocksuite/icons'; import { useEffect, useState } from 'react'; @@ -173,10 +174,8 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceInfo }) => { ) : ( -
    - Collaborating with other members requires AFFiNE Cloud service. -
    -
    + <>Collaborating with other members requires AFFiNE Cloud service. + -
    +
    )}
    diff --git a/packages/app/src/components/workspace-setting/SyncPage.tsx b/packages/app/src/components/workspace-setting/SyncPage.tsx index 89c2df5a02..f2ffbeafec 100644 --- a/packages/app/src/components/workspace-setting/SyncPage.tsx +++ b/packages/app/src/components/workspace-setting/SyncPage.tsx @@ -6,29 +6,27 @@ import { import { DownloadIcon } from '@blocksuite/icons'; import { Button } from '@/ui/button'; import { Menu, MenuItem } from '@/ui/menu'; -import { useTemporaryHelper } from '@/providers/temporary-helper-provider'; import { WorkspaceInfo } from '@affine/datacenter'; export const SyncPage = ({ workspace }: { workspace: WorkspaceInfo }) => { console.log('workspace: ', workspace); - const { currentWorkspace, updateWorkspaceMeta } = useTemporaryHelper(); return (
    - {currentWorkspace?.type === 'local' ? ( + {workspace?.provider === 'local' ? ( <> - {currentWorkspace.name} is Local Workspace. All data is stored on - the current device. You can enable AFFiNE Cloud for this workspace - to keep data in sync with the cloud. + {workspace.name ?? 'Affine'} is Local Workspace. All data is + stored on the current device. You can enable AFFiNE Cloud for this + workspace to keep data in sync with the cloud.
    ) : (
    { // await login(); // } const id = await enableWorkspace(currentWorkspace); - router.push(`/workspace/${id}`); + router.push(`/workspace/${id}/setting`); toast('Enabled success'); } }); diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index ec541b9f11..0b01941475 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -48,9 +48,11 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const fileChange = async (file: File) => { // console.log('file: ', file); - // setUploading(true); + setUploading(true); const blob = new Blob([file], { type: file.type }); - currentWorkspace && updateWorkspace({ avatarBlob: blob }, currentWorkspace); + currentWorkspace && + (await updateWorkspace({ avatarBlob: blob }, currentWorkspace)); + setUploading(false); }; return workspace ? ( diff --git a/packages/app/src/components/workspace-setting/style.ts b/packages/app/src/components/workspace-setting/style.ts index a6b162fab3..f750ef8598 100644 --- a/packages/app/src/components/workspace-setting/style.ts +++ b/packages/app/src/components/workspace-setting/style.ts @@ -2,7 +2,7 @@ import { styled } from '@/styles'; import { Button } from '@/ui/button'; import MuiAvatar from '@mui/material/Avatar'; -export const StyledSettingContainer = styled('div')(({ theme }) => { +export const StyledSettingContainer = styled('div')(() => { return { display: 'flex', padding: '50px', @@ -12,7 +12,7 @@ export const StyledSettingContainer = styled('div')(({ theme }) => { }; }); -export const StyledSettingSidebar = styled('div')(({ theme }) => { +export const StyledSettingSidebar = styled('div')(() => { { return { flexShrink: 0, diff --git a/packages/app/src/hooks/use-ensure-workspace.ts b/packages/app/src/hooks/use-ensure-workspace.ts index a59f73881b..0ef15580a0 100644 --- a/packages/app/src/hooks/use-ensure-workspace.ts +++ b/packages/app/src/hooks/use-ensure-workspace.ts @@ -18,7 +18,8 @@ export const useEnsureWorkspace = () => { // If workspaceList is empty, we need to create a default workspace but not jump to 404 if ( workspaceList.length && - router.query.workspaceId && + // FIXME: router is not ready when this hook is called + location.pathname.startsWith(`/workspace/${router.query.workspaceId}`) && workspaceList.findIndex( meta => meta.id.toString() === router.query.workspaceId ) === -1 @@ -35,14 +36,13 @@ export const useEnsureWorkspace = () => { // router.push('/404'); // return; // } - const workspaceId = (router.query.workspaceId as string) || workspaceList[0]?.id; loadWorkspace(workspaceId).finally(() => { setWorkspaceLoaded(true); setActiveWorkspaceId(activeWorkspaceId); }); - }, [loadWorkspace, router, user, workspaceList]); + }, [loadWorkspace, router, user, workspaceList, activeWorkspaceId]); return { workspaceLoaded, diff --git a/packages/app/src/pages/workspace/[workspaceId]/index.tsx b/packages/app/src/pages/workspace/[workspaceId]/index.tsx index d0a9e086d1..cdfd343af3 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/index.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/index.tsx @@ -16,9 +16,7 @@ const WorkspaceIndex = () => { if (!workspaceLoaded) { return; } - const savedPageId = currentWorkspace?.meta.pageMetas[0]?.id; - if (savedPageId) { router.replace(`/workspace/${activeWorkspaceId}/${savedPageId}`); return; @@ -34,6 +32,7 @@ const WorkspaceIndex = () => { createPage, router, workspaceLoaded, + activeWorkspaceId, ]); return ; diff --git a/packages/app/src/providers/app-state-provider/Provider.tsx b/packages/app/src/providers/app-state-provider/Provider.tsx index 9c2afcf757..619b7fc2cd 100644 --- a/packages/app/src/providers/app-state-provider/Provider.tsx +++ b/packages/app/src/providers/app-state-provider/Provider.tsx @@ -100,7 +100,6 @@ export const AppStateProvider = ({ if (workspaceId === currentWorkspaceId) { return currentWorkspace; } - const workspace = await dataCenter.loadWorkspace(workspaceId); const currentMetaWorkSpace = dataCenter.workspaces.find( (item: WorkspaceUnit) => { diff --git a/packages/app/src/providers/app-state-provider/utils.ts b/packages/app/src/providers/app-state-provider/utils.ts index 066ef7a2c8..6dc3c8ccaf 100644 --- a/packages/app/src/providers/app-state-provider/utils.ts +++ b/packages/app/src/providers/app-state-provider/utils.ts @@ -4,7 +4,6 @@ const DEFAULT_WORKSPACE_NAME = 'affine'; export const createDefaultWorkspace = async (dataCenter: DataCenter) => { return dataCenter.createWorkspace({ - avatar: 'test', name: DEFAULT_WORKSPACE_NAME, }); }; diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 8e70718c36..76499b11e5 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -43,8 +43,8 @@ export class DataCenter { }; }; // TODO: switch different provider - dc.registerProvider(new LocalProvider(getInitParams())); - dc.registerProvider(new AffineProvider(getInitParams())); + await dc.registerProvider(new LocalProvider(getInitParams())); + await dc.registerProvider(new AffineProvider(getInitParams())); for (const provider of dc.providerMap.values()) { await provider.loadWorkspaces(); @@ -57,12 +57,12 @@ export class DataCenter { * Register provider. * We will automatically set the first provider to default provider. */ - registerProvider(provider: BaseProvider) { + async registerProvider(provider: BaseProvider) { if (!this._mainProvider) { this._mainProvider = provider; } - provider.init(); + await provider.init(); this.providerMap.set(provider.id, provider); } @@ -123,7 +123,7 @@ export class DataCenter { const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); return ( - this._workspaceInstances.get(workspaceId) || + // this._workspaceInstances.get(workspaceId) || createBlocksuiteWorkspace(workspaceId) ); } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 890fc6dc00..1ba3524fef 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -212,6 +212,7 @@ export class AffineProvider extends BaseProvider { } public override async getUserInfo(): Promise { + await this.init(); const user = this._apis.token.user; return user ? { diff --git a/packages/data-center/src/provider/affine/apis/workspace.ts b/packages/data-center/src/provider/affine/apis/workspace.ts index 8bdc25b21f..29a729ae6b 100644 --- a/packages/data-center/src/provider/affine/apis/workspace.ts +++ b/packages/data-center/src/provider/affine/apis/workspace.ts @@ -84,7 +84,10 @@ export interface CreateWorkspaceParams { export async function createWorkspace( params: CreateWorkspaceParams ): Promise<{ id: string }> { - return client.post('api/workspace', { json: params }).json(); + // FIXME: avatar should be optional + return client + .post('api/workspace', { json: { ...params, avatar: '123' } }) + .json(); } export interface UpdateWorkspaceParams { From ee6138134d9df3383807789aa63a0f2733e5e8b8 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Wed, 11 Jan 2023 12:12:12 +0800 Subject: [PATCH 156/298] feat: publish workspace --- .../workspace-setting/MembersPage.tsx | 2 +- .../workspace-setting/PublishPage.tsx | 32 ++++--------------- .../components/workspace-setting/SyncPage.tsx | 26 ++------------- .../app/src/hooks/use-workspace-helper.ts | 32 +++++++++++++++---- .../providers/app-state-provider/Provider.tsx | 2 +- .../data-center/src/provider/affine/affine.ts | 1 + 6 files changed, 38 insertions(+), 57 deletions(-) diff --git a/packages/app/src/components/workspace-setting/MembersPage.tsx b/packages/app/src/components/workspace-setting/MembersPage.tsx index 3859bcbd26..08b2640c97 100644 --- a/packages/app/src/components/workspace-setting/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/MembersPage.tsx @@ -64,7 +64,7 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { return (
    - {workspace.provider === 'cloud' ? ( + {workspace.provider === 'affine' ? ( <> diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx index dce254dc21..c5c39cc2de 100644 --- a/packages/app/src/components/workspace-setting/PublishPage.tsx +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -9,20 +9,17 @@ import { import { Button } from '@/ui/button'; import Input from '@/ui/input'; import { toast } from '@/ui/toast'; -import { useConfirm } from '@/providers/ConfirmProvider'; // import { useAppState } from '@/providers/app-state-provider3'; -import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { WorkspaceUnit } from '@affine/datacenter'; +import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const shareUrl = window.location.host + '/workspace/' + workspace.id + '?share=true'; - const { publishWorkspace } = useWorkspaceHelper(); + const { publishWorkspace, enableWorkspace } = useWorkspaceHelper(); - const { confirm } = useConfirm(); - - const togglePublic = (flag: boolean) => { - workspace.id && publishWorkspace(workspace?.id, flag); + const togglePublic = async (flag: boolean) => { + await publishWorkspace(workspace.id.toString(), flag); }; const copyUrl = () => { @@ -30,27 +27,12 @@ export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => { toast('Copied url to clipboard'); }; - const enableAffineCloud = () => { - confirm({ - title: 'Enable AFFiNE Cloud?', - content: `If enabled, the data in this workspace will be backed up and synchronized via AFFiNE Cloud.`, - confirmText: - workspace.provider === 'local' ? 'Enable' : 'Sign in and Enable', - cancelText: 'Skip', - }).then(confirm => { - if (confirm) { - // if (user) { - // updateWorkspaceMeta(workspace.id, { type: 'cloud' }); - // } else { - // login(); - // updateWorkspaceMeta(workspace.id, { type: 'cloud' }); - // } - } - }); + const enableAffineCloud = async () => { + await enableWorkspace(); }; return ( <> - {workspace.provider === 'cloud' ? ( + {workspace.provider === 'affine' ? (
    {workspace?.published ? ( diff --git a/packages/app/src/components/workspace-setting/SyncPage.tsx b/packages/app/src/components/workspace-setting/SyncPage.tsx index 37ba8ab3f6..d6345a294b 100644 --- a/packages/app/src/components/workspace-setting/SyncPage.tsx +++ b/packages/app/src/components/workspace-setting/SyncPage.tsx @@ -8,16 +8,8 @@ import { Button } from '@/ui/button'; import { Menu, MenuItem } from '@/ui/menu'; import { WorkspaceUnit } from '@affine/datacenter'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; -import { useAppState } from '@/providers/app-state-provider'; -import { useConfirm } from '@/providers/ConfirmProvider'; -import { toast } from '@/ui/toast'; -import { useRouter } from 'next/router'; export const SyncPage = ({ workspace }: { workspace: WorkspaceUnit }) => { - // console.log('workspace: ', workspace); const { enableWorkspace } = useWorkspaceHelper(); - const { currentWorkspace, user } = useAppState(); - const { confirm } = useConfirm(); - const router = useRouter(); return (
    @@ -31,22 +23,8 @@ export const SyncPage = ({ workspace }: { workspace: WorkspaceUnit }) => { - { - setIsInviteModalShow(false); - }} - onInviteSuccess={() => { - setMembersList(); - setIsInviteModalShow(false); - // refreshMembers(); - }} - workspaceId={workspace.id} - open={isInviteModalShow} - > - - - ) : ( - - <>Collaborating with other members requires AFFiNE Cloud service. - - - - - )} -
    - ); -}; diff --git a/packages/app/src/components/workspace-setting/general/style.ts b/packages/app/src/components/workspace-setting/general/style.ts index 4a82017e96..739ec24aec 100644 --- a/packages/app/src/components/workspace-setting/general/style.ts +++ b/packages/app/src/components/workspace-setting/general/style.ts @@ -26,11 +26,3 @@ export const StyledSettingAvatarContent = styled('div')(() => { export const StyledSettingAvatar = styled(MuiAvatar)(() => { return { height: '72px', width: '72px', marginRight: '24px' }; }); - -export const StyledMemberWarp = styled('div')(() => { - return { - display: 'flex', - flexDirection: 'column', - padding: '40px 0', - }; -}); diff --git a/packages/app/src/components/workspace-setting/index.ts b/packages/app/src/components/workspace-setting/index.ts index c0eea1cfb0..0468074d2f 100644 --- a/packages/app/src/components/workspace-setting/index.ts +++ b/packages/app/src/components/workspace-setting/index.ts @@ -1,5 +1,5 @@ export * from './general'; export * from './ExportPage'; -export * from './MembersPage'; +export * from './member'; export * from './SyncPage'; export * from './PublishPage'; diff --git a/packages/app/src/components/invite-members/index.tsx b/packages/app/src/components/workspace-setting/member/InviteMemberModal.tsx similarity index 77% rename from packages/app/src/components/invite-members/index.tsx rename to packages/app/src/components/workspace-setting/member/InviteMemberModal.tsx index 6fb020fc52..c066908ed0 100644 --- a/packages/app/src/components/invite-members/index.tsx +++ b/packages/app/src/components/workspace-setting/member/InviteMemberModal.tsx @@ -4,9 +4,9 @@ import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Button } from '@/ui/button'; import Input from '@/ui/input'; import { useState } from 'react'; -// import { getDataCenter } from '@affine/datacenter'; import { Avatar } from '@mui/material'; -import { setMember } from '@/hooks/mock-data/mock'; +import useMembers from '@/hooks/use-members'; +import { User } from '@affine/datacenter'; interface LoginModalProps { open: boolean; onClose: () => void; @@ -43,46 +43,27 @@ export const debounce = any>( }; const gmailReg = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@gmail\.com$/; -export const InviteMembers = ({ +export const InviteMemberModal = ({ open, onClose, - workspaceId, onInviteSuccess, }: LoginModalProps) => { const [email, setEmail] = useState(''); const [showMember, setShowMember] = useState(false); const [showTip, setShowTip] = useState(false); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const [userData, setUserData] = useState({}); + const [userData, setUserData] = useState(null); + const { inviteMember, getUserByEmail } = useMembers(); const inputChange = (value: string) => { setShowMember(true); if (gmailReg.test(value)) { setEmail(value); setShowTip(false); - setUserData({ - name: 'wxl', - avatar: 'https://avatars.githubusercontent.com/u/20501502?v=4', - email: value, + getUserByEmail(value).then(data => { + if (data?.name) { + setUserData(data); + setShowTip(false); + } }); - // debounce( - // () => { - // getDataCenter() - // .then(dc => - // dc.apis.getUserByEmail({ - // email: value, - // workspace_id: workspaceId, - // }) - // ) - // .then(data => { - // if (data?.name) { - // setUserData(data); - // setShowTip(false); - // } - // }); - // }, - // 300, - // true - // )(); } else { setShowTip(true); } @@ -118,8 +99,8 @@ export const InviteMembers = ({ Non-Gmail is not supported ) : ( - {userData?.avatar_url ? ( - + {userData?.avatar ? ( + ) : ( @@ -139,19 +120,9 @@ export const InviteMembers = ({ + { + setIsInviteModalShow(false); + }} + onInviteSuccess={() => { + setIsInviteModalShow(false); + // refreshMembers(); + }} + workspaceId={workspace.id} + open={isInviteModalShow} + > + + + ); + } + + return ( + + <>Collaborating with other members requires AFFiNE Cloud service. + + + + + ); +}; diff --git a/packages/app/src/components/workspace-setting/member/index.ts b/packages/app/src/components/workspace-setting/member/index.ts new file mode 100644 index 0000000000..aced79efe5 --- /dev/null +++ b/packages/app/src/components/workspace-setting/member/index.ts @@ -0,0 +1 @@ +export * from './MembersPage'; diff --git a/packages/app/src/components/workspace-setting/member/style.ts b/packages/app/src/components/workspace-setting/member/style.ts new file mode 100644 index 0000000000..a5bf612f9a --- /dev/null +++ b/packages/app/src/components/workspace-setting/member/style.ts @@ -0,0 +1,107 @@ +import { styled } from '@/styles'; +import MuiAvatar from '@mui/material/Avatar'; +import { Button } from '@/ui/button'; + +export const StyledMemberTitleContainer = styled('div')(() => { + return { + display: 'flex', + marginTop: '60px', + fontWeight: '500', + flex: 1, + }; +}); + +export const StyledMemberAvatar = styled(MuiAvatar)(() => { + return { height: '40px', width: '40px' }; +}); + +export const StyledMemberNameContainer = styled('div')(() => { + return { + display: 'flex', + alignItems: 'center', + width: '402px', + }; +}); + +export const StyledMemberRoleContainer = styled('div')(() => { + return { + display: 'flex', + alignItems: 'center', + width: '222px', + }; +}); + +export const StyledMemberListContainer = styled('ul')(() => { + return { + marginTop: '15px', + overflowY: 'scroll', + }; +}); + +export const StyledMemberListItem = styled('li')(() => { + return { + display: 'flex', + alignItems: 'center', + height: '72px', + }; +}); + +export const StyledMemberInfo = styled('div')(() => { + return { + paddingLeft: '12px', + }; +}); + +export const StyledMemberName = styled('div')(({ theme }) => { + return { + fontWeight: '400', + fontSize: '18px', + lineHeight: '16px', + color: theme.colors.textColor, + }; +}); + +export const StyledMemberEmail = styled('div')(({ theme }) => { + return { + fontWeight: '400', + fontSize: '16px', + lineHeight: '22px', + color: theme.colors.iconColor, + }; +}); + +export const StyledMemberButtonContainer = styled('div')(() => { + return { + marginTop: '14px', + }; +}); + +export const StyledMoreVerticalButton = styled('button')(() => { + return { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + width: '24px', + height: '24px', + cursor: 'pointer', + }; +}); + +export const StyledPublishExplanation = styled('div')(() => { + return { + paddingRight: '48px', + fontWeight: '500', + fontSize: '18px', + lineHeight: '26px', + flex: 1, + marginTop: '60px', + }; +}); + +export const StyledMemberWarp = styled('div')(() => { + return { + display: 'flex', + flexDirection: 'column', + padding: '40px 0', + }; +}); diff --git a/packages/app/src/components/workspace-setting/style.ts b/packages/app/src/components/workspace-setting/style.ts index f750ef8598..1809ed4280 100644 --- a/packages/app/src/components/workspace-setting/style.ts +++ b/packages/app/src/components/workspace-setting/style.ts @@ -96,99 +96,6 @@ export const StyledSettingH2 = styled('h2')<{ marginTop?: number }>( } ); -export const StyledAvatarUploadBtn = styled(Button)(({ theme }) => { - return { - backgroundColor: theme.colors.hoverBackground, - color: theme.colors.primaryColor, - margin: '0 12px 0 24px', - }; -}); - -export const StyledMemberTitleContainer = styled('div')(() => { - return { - display: 'flex', - marginTop: '60px', - fontWeight: '500', - flex: 1, - }; -}); - -export const StyledMemberAvatar = styled(MuiAvatar)(() => { - return { height: '40px', width: '40px' }; -}); - -export const StyledMemberNameContainer = styled('div')(() => { - return { - display: 'flex', - alignItems: 'center', - width: '402px', - }; -}); - -export const StyledMemberRoleContainer = styled('div')(() => { - return { - display: 'flex', - alignItems: 'center', - width: '222px', - }; -}); - -export const StyledMemberListContainer = styled('ul')(() => { - return { - marginTop: '15px', - overflowY: 'scroll', - }; -}); - -export const StyledMemberListItem = styled('li')(() => { - return { - display: 'flex', - alignItems: 'center', - height: '72px', - }; -}); - -export const StyledMemberInfo = styled('div')(() => { - return { - paddingLeft: '12px', - }; -}); - -export const StyledMemberName = styled('div')(({ theme }) => { - return { - fontWeight: '400', - fontSize: '18px', - lineHeight: '16px', - color: theme.colors.textColor, - }; -}); - -export const StyledMemberEmail = styled('div')(({ theme }) => { - return { - fontWeight: '400', - fontSize: '16px', - lineHeight: '22px', - color: theme.colors.iconColor, - }; -}); - -export const StyledMemberButtonContainer = styled('div')(() => { - return { - marginTop: '14px', - }; -}); - -export const StyledMoreVerticalButton = styled('button')(() => { - return { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - width: '24px', - height: '24px', - cursor: 'pointer', - }; -}); - export const StyledPublishExplanation = styled('div')(() => { return { paddingRight: '48px', diff --git a/packages/app/src/hooks/use-members.ts b/packages/app/src/hooks/use-members.ts new file mode 100644 index 0000000000..3011c94f83 --- /dev/null +++ b/packages/app/src/hooks/use-members.ts @@ -0,0 +1,51 @@ +import { useCallback, useEffect, useState } from 'react'; +import { Member } from '@affine/datacenter'; +import { useAppState } from '@/providers/app-state-provider'; +export const useMembers = () => { + const { dataCenter, currentWorkspace } = useAppState(); + const [members, setMembers] = useState([]); + const [loaded, setLoaded] = useState(false); + const refreshMembers = useCallback(async () => { + if (!currentWorkspace || !dataCenter) return; + const members = await dataCenter.getMembers(currentWorkspace.id); + setMembers(members); + }, [dataCenter, currentWorkspace]); + + useEffect(() => { + const init = async () => { + await refreshMembers(); + setLoaded(true); + }; + init(); + }, [refreshMembers]); + + const inviteMember = async (email: string) => { + currentWorkspace && + dataCenter && + (await dataCenter.inviteMember(currentWorkspace?.id, email)); + }; + + const removeMember = async (permissionId: number) => { + if (!currentWorkspace || !dataCenter) { + return; + } + setLoaded(false); + await dataCenter.removeMember(currentWorkspace.id, permissionId); + await refreshMembers(); + setLoaded(true); + }; + + const getUserByEmail = async (email: string) => { + if (!currentWorkspace) return null; + return dataCenter?.getUserByEmail(currentWorkspace.id, email); + }; + return { + members, + removeMember, + inviteMember, + getUserByEmail, + loaded, + }; +}; + +export default useMembers; diff --git a/packages/app/src/hooks/use-workspace-helper.ts b/packages/app/src/hooks/use-workspace-helper.ts index f67a3b152f..397371e52f 100644 --- a/packages/app/src/hooks/use-workspace-helper.ts +++ b/packages/app/src/hooks/use-workspace-helper.ts @@ -56,16 +56,10 @@ export const useWorkspaceHelper = () => { }); }; - const inviteMember = async (email: string) => { - currentWorkspace && - (await dataCenter.inviteMember(currentWorkspace?.id, email)); - }; - return { createWorkspace, publishWorkspace, updateWorkspace, enableWorkspace, - inviteMember, }; }; diff --git a/packages/app/src/providers/app-state-provider/Provider.tsx b/packages/app/src/providers/app-state-provider/Provider.tsx index 710bf81853..ef6c594b0b 100644 --- a/packages/app/src/providers/app-state-provider/Provider.tsx +++ b/packages/app/src/providers/app-state-provider/Provider.tsx @@ -20,11 +20,9 @@ export const AppStateProvider = ({ children, }: PropsWithChildren) => { const [appState, setAppState] = useState({} as AppStateValue); - useEffect(() => { const initState = async () => { const dataCenter = await getDataCenter(); - // Ensure datacenter has at least one workspace if (dataCenter.workspaces.length === 0) { await createDefaultWorkspace(dataCenter); diff --git a/packages/data-center/src/index.ts b/packages/data-center/src/index.ts index fd199935fc..591a83b14a 100644 --- a/packages/data-center/src/index.ts +++ b/packages/data-center/src/index.ts @@ -26,7 +26,7 @@ const _initializeDataCenter = () => { export const getDataCenter = _initializeDataCenter(); export type { DataCenter }; -export type { AccessTokenMessage } from './provider/affine/apis'; +export * from './provider/affine/apis'; export { WorkspaceUnit } from './workspace-unit'; export { getLogger } from './logger'; export * from './message'; From 49eff042fe66cbc2e3c8aac287c370aebb199e97 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Wed, 11 Jan 2023 21:35:40 +0800 Subject: [PATCH 187/298] feat: add accept invite --- packages/data-center/src/datacenter.ts | 12 ++++++++++++ packages/data-center/src/provider/affine/affine.ts | 5 +++++ packages/data-center/src/provider/base.ts | 10 ++++++++++ 3 files changed, 27 insertions(+) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index c15861223e..add13ec0ee 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -438,6 +438,18 @@ export class DataCenter { return []; } + /** + * accept invitation + * @param {string} inviteCode + */ + async acceptInvitation(inviteCode: string, providerStr = 'affine') { + const provider = this.providerMap.get(providerStr); + if (provider) { + return await provider.acceptInvitation(inviteCode); + } + return []; + } + onMessage(cb: (message: Message) => void) { return this._messageCenter.onMessage(cb); } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 41b93b7dc2..acc1ce0cfb 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -99,6 +99,7 @@ export class AffineProvider extends BaseProvider { ws_details: Record; metadata: Record; }) { + this._logger('receive server message'); Object.entries(ws_details).forEach(([id, detail]) => { const { name, avatar } = metadata[id]; assert(name); @@ -442,4 +443,8 @@ export class AffineProvider extends BaseProvider { public override async getWorkspaceMembers(id: string) { return this._apis.getWorkspaceMembers({ id }); } + + public override async acceptInvitation(invitingCode: string): Promise { + await this._apis.acceptInviting({ invitingCode }); + } } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index fed8626811..11547c6a66 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -233,4 +233,14 @@ export class BaseProvider { workspaceId; return Promise.resolve([]); } + + /** + * accept invitation + * @param {string} inviteCode + * @returns + */ + public async acceptInvitation(inviteCode: string): Promise { + inviteCode; + return; + } } From 9d431dbc183723c5a5c2882d63a22d3efa95e115 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Wed, 11 Jan 2023 21:44:32 +0800 Subject: [PATCH 188/298] feat:add logout --- .../src/components/create-workspace/index.tsx | 3 +- .../src/components/workspace-modal/index.tsx | 28 ++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/app/src/components/create-workspace/index.tsx b/packages/app/src/components/create-workspace/index.tsx index e4645df8e4..7b473afbfb 100644 --- a/packages/app/src/components/create-workspace/index.tsx +++ b/packages/app/src/components/create-workspace/index.tsx @@ -7,6 +7,7 @@ import { KeyboardEvent } from 'react'; import { useTranslation } from '@affine/i18n'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { useRouter } from 'next/router'; +import { toast } from '@/ui/toast'; interface ModalProps { open: boolean; @@ -23,7 +24,7 @@ export const CreateWorkspaceModal = ({ open, onClose }: ModalProps) => { router.replace(`/workspace/${workspace.id}`); onClose(); } else { - console.log('create error'); + toast('create error'); } }; const handleKeyDown = (event: KeyboardEvent) => { diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 419654fdec..4328224d8c 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -2,7 +2,6 @@ import { styled } from '@/styles'; import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal'; import { Button } from '@/ui/button'; import { useState } from 'react'; -import { SignOut } from '@/hooks/mock-data/mock'; import { CreateWorkspaceModal } from '../create-workspace'; import { CloudUnsyncedIcon, @@ -14,6 +13,7 @@ import { toast } from '@/ui/toast'; import { WorkspaceAvatar } from '@/components/workspace-avatar'; import { useAppState } from '@/providers/app-state-provider'; import { useRouter } from 'next/router'; +import { useConfirm } from '@/providers/ConfirmProvider'; interface WorkspaceModalProps { open: boolean; @@ -22,8 +22,9 @@ interface WorkspaceModalProps { export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false); - // const { confirm } = useConfirm(); - const { workspaceList, currentWorkspace, login, user } = useAppState(); + const { confirm } = useConfirm(); + const { workspaceList, currentWorkspace, login, user, logout } = + useAppState(); const router = useRouter(); return (
    @@ -134,9 +135,9 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => {
    {!user ? ( { + setShowDelete(false); + }} workspace={workspace} /> ) : ( <> - { + setShowLeave(false); + }} /> )} diff --git a/packages/app/src/components/workspace-setting/general/leave/Leave.tsx b/packages/app/src/components/workspace-setting/general/leave/Leave.tsx index e34b4ac257..aed3617abc 100644 --- a/packages/app/src/components/workspace-setting/general/leave/Leave.tsx +++ b/packages/app/src/components/workspace-setting/general/leave/Leave.tsx @@ -7,29 +7,19 @@ import { } from './style'; import { ModalCloseButton } from '@/ui/modal'; import { Button } from '@/ui/button'; +import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; // import { getDataCenter } from '@affine/datacenter'; // import { useAppState } from '@/providers/app-state-provider'; interface WorkspaceDeleteProps { open: boolean; onClose: () => void; - workspaceName: string; - workspaceId: string; } -export const WorkspaceLeave = ({ - open, - onClose, - workspaceId, -}: WorkspaceDeleteProps) => { - console.log('workspaceId: ', workspaceId); - // const router = useRouter(); - // const { refreshWorkspacesMeta } = useAppState(); +export const WorkspaceLeave = ({ open, onClose }: WorkspaceDeleteProps) => { + const { leaveWorkSpace } = useWorkspaceHelper(); const handleLeave = async () => { - // const dc = await getDataCenter(); - // await dc.apis.leaveWorkspace({ id: workspaceId }); - // // router.push(`/workspace/${nextWorkSpaceId}`); - // refreshWorkspacesMeta(); + await leaveWorkSpace(); onClose(); }; diff --git a/packages/app/src/hooks/use-workspace-helper.ts b/packages/app/src/hooks/use-workspace-helper.ts index c8e05d6e2c..f1dee901d3 100644 --- a/packages/app/src/hooks/use-workspace-helper.ts +++ b/packages/app/src/hooks/use-workspace-helper.ts @@ -47,10 +47,10 @@ export const useWorkspaceHelper = () => { if (!user) { await login(); } - const newWorkspaceId = await dataCenter.enableWorkspaceCloud( + const workspace = await dataCenter.enableWorkspaceCloud( currentWorkspace ); - router.push(`/workspace/${newWorkspaceId}/setting`); + workspace && router.push(`/workspace/${workspace.id}/setting`); toast('Enabled success'); } }); @@ -60,6 +60,9 @@ export const useWorkspaceHelper = () => { currentWorkspace && (await dataCenter.deleteWorkspace(currentWorkspace?.id)); }; + const leaveWorkSpace = async () => { + currentWorkspace && (await dataCenter.leaveWorkspace(currentWorkspace?.id)); + }; return { createWorkspace, @@ -67,5 +70,6 @@ export const useWorkspaceHelper = () => { updateWorkspace, enableWorkspace, deleteWorkSpace, + leaveWorkSpace, }; }; From 4fe2febda347030e33fe38ea4c12dcbde91a58b3 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 17:06:54 +0800 Subject: [PATCH 203/298] feat:add isOwner --- .../workspace-setting/general/General.tsx | 22 +++++---- .../app/src/pages/new-workspace/index.tsx | 47 ------------------- .../pages/workspace/[workspaceId]/setting.tsx | 19 ++++++-- .../providers/app-state-provider/Provider.tsx | 11 ++++- .../providers/app-state-provider/interface.ts | 1 + 5 files changed, 39 insertions(+), 61 deletions(-) delete mode 100644 packages/app/src/pages/new-workspace/index.tsx diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index b3f5af88a1..0ced889c68 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -21,9 +21,8 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const [showLeave, setShowLeave] = useState(false); const [uploading, setUploading] = useState(false); const [workspaceName, setWorkspaceName] = useState(workspace.name); - const { currentWorkspace } = useAppState(); + const { currentWorkspace, isOwner } = useAppState(); const { updateWorkspace } = useWorkspaceHelper(); - const isOwner = true; const handleChangeWorkSpaceName = (newName: string) => { setWorkspaceName(newName); }; @@ -72,16 +71,19 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { placeholder="Workspace Name" maxLength={14} minLength={1} + disabled={!isOwner} onChange={handleChangeWorkSpaceName} > - { - handleUpdateWorkspaceName(); - }} - style={{ marginLeft: '0px' }} - > - ✔️ - + {isOwner ? ( + { + handleUpdateWorkspaceName(); + }} + style={{ marginLeft: '0px' }} + > + ✔️ + + ) : null} Workspace Type diff --git a/packages/app/src/pages/new-workspace/index.tsx b/packages/app/src/pages/new-workspace/index.tsx deleted file mode 100644 index 1a1d9e1a44..0000000000 --- a/packages/app/src/pages/new-workspace/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { WorkspaceModal } from '@/components/workspace-modal'; -import { getWorkspaces } from '@/hooks/mock-data/mock'; -import { useEffect, useState } from 'react'; -import { styled } from '@/styles'; -import Button from '@/ui/button/Button'; - -const Page = () => { - const [open, setOpen] = useState(false); - - useEffect(() => { - const data = getWorkspaces(); - if (!data.length) { - setOpen(true); - } - }, []); - return ( - -

    workspace

    -
    - -
    - { - setOpen(false); - }} - > -
    - ); -}; -export default Page; - -const Workspace = styled.div(({ theme }) => { - return { - height: '100vh', - background: theme.colors.pageBackground, - color: '#FFFFFF', - fontSize: '18px', - fontWeight: 500, - }; -}); diff --git a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx index e8c40aacf2..e39a424166 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx @@ -60,7 +60,7 @@ const tabMap: { ]; const WorkspaceSetting = () => { - const { currentWorkspace } = useAppState(); + const { currentWorkspace, isOwner } = useAppState(); const [activeTab, setActiveTab] = useState(tabMap[0].name); const handleTabChange = (tab: TabNames) => { @@ -70,7 +70,20 @@ const WorkspaceSetting = () => { const activeTabPanelRender = tabMap.find( tab => tab.name === activeTab )?.panelRender; - + let tableArr: { + name: TabNames; + icon: ReactNode; + panelRender: (workspace: WorkspaceUnit) => ReactNode; + }[] = tabMap; + if (!isOwner) { + tableArr = [ + { + name: 'general', + icon: , + panelRender: workspace => , + }, + ]; + } return ( @@ -78,7 +91,7 @@ const WorkspaceSetting = () => { Workspace Settings - {tabMap.map(({ icon, name }) => { + {tableArr.map(({ icon, name }) => { return ( (); loadWorkspace.current = async (workspaceId: string) => { - const { dataCenter, workspaceList, currentWorkspace } = appState; + const { dataCenter, workspaceList, currentWorkspace, user } = appState; if (!workspaceList.find(v => v.id.toString() === workspaceId)) { return null; } @@ -99,6 +100,13 @@ export const AppStateProvider = ({ return currentWorkspace; } const workspace = (await dataCenter.loadWorkspace(workspaceId)) ?? null; + let isOwner; + if (workspace.provider === 'local') { + // isOwner is useful only in the cloud + isOwner = true; + } else { + isOwner = workspace?.owner && user?.id === workspace?.owner?.id; + } const pageList = (workspace?.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? []; setAppState({ @@ -107,6 +115,7 @@ export const AppStateProvider = ({ pageList: pageList, currentPage: null, editor: null, + isOwner, }); return workspace; diff --git a/packages/app/src/providers/app-state-provider/interface.ts b/packages/app/src/providers/app-state-provider/interface.ts index 6cb5f5551c..c76b2993ce 100644 --- a/packages/app/src/providers/app-state-provider/interface.ts +++ b/packages/app/src/providers/app-state-provider/interface.ts @@ -23,6 +23,7 @@ export type AppStateValue = { currentPage: StorePage | null; editor?: EditorContainer | null; synced: boolean; + isOwner?: boolean; }; export type AppStateFunction = { From 251cfc2340d850ad7d3eac2ddfd36b41f63109e6 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 17:16:44 +0800 Subject: [PATCH 204/298] fix: message in affine --- packages/data-center/src/provider/affine/affine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 309af9570d..944d19c7fe 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -21,7 +21,7 @@ import { import { WorkspaceUnit } from '../../workspace-unit.js'; import { createBlocksuiteWorkspace, applyUpdate } from '../../utils/index.js'; import type { SyncMode } from '../../workspace-unit'; -import { MessageCenter } from 'src/message/message.js'; +import { MessageCenter } from '../../message/index.js'; type ChannelMessage = { ws_list: Workspace[]; From 11edef1bbdc893045ecf8c0d99756db121055878 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 12 Jan 2023 17:18:40 +0800 Subject: [PATCH 205/298] feat: add new workspaces by arrays --- .../data-center/src/provider/affine/affine.ts | 30 +++++++++++++++---- .../src/provider/affine/apis/workspace.ts | 2 +- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index d4c4027772..c389363abb 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -21,7 +21,7 @@ import { import { WorkspaceUnit } from '../../workspace-unit.js'; import { createBlocksuiteWorkspace, applyUpdate } from '../../utils/index.js'; import type { SyncMode } from '../../workspace-unit'; -import { MessageCenter } from 'src/message/message.js'; +import { MessageCenter } from '../../message/index.js'; type ChannelMessage = { ws_list: Workspace[]; @@ -102,10 +102,19 @@ export class AffineProvider extends BaseProvider { }); } - private _handlerAffineListMessage({ ws_details, metadata }: ChannelMessage) { + private async _handlerAffineListMessage({ + ws_details, + metadata, + }: ChannelMessage) { this._logger('receive server message'); - Object.entries(ws_details).forEach(async ([id, detail]) => { + const addedWorkspaces: WorkspaceUnit[] = []; + const removeWorkspaceList = this._workspaces.list().map(w => w.id); + for (const [id, detail] of Object.entries(ws_details)) { const { name, avatar } = metadata[id]; + const index = removeWorkspaceList.indexOf(id); + if (index !== -1) { + removeWorkspaceList.splice(index, 1); + } assert(name); const workspace = { name: name, @@ -122,15 +131,26 @@ export class AffineProvider extends BaseProvider { syncMode: 'core' as SyncMode, }; if (this._workspaces.get(id)) { + // update workspaces this._workspaces.update(id, workspace); } else { const workspaceUnit = await loadWorkspaceUnit( { id, ...workspace }, this._apis ); - this._workspaces.add(workspaceUnit); + addedWorkspaces.push(workspaceUnit); } - }); + } + if (addedWorkspaces.length) { + // add workspaces + this._workspaces.add(addedWorkspaces); + } + if (removeWorkspaceList.length) { + // remove workspaces + removeWorkspaceList.forEach(id => { + this._workspaces.remove(id); + }); + } } private _getWebsocketProvider(workspace: BlocksuiteWorkspace) { diff --git a/packages/data-center/src/provider/affine/apis/workspace.ts b/packages/data-center/src/provider/affine/apis/workspace.ts index 0101832d28..f2455810eb 100644 --- a/packages/data-center/src/provider/affine/apis/workspace.ts +++ b/packages/data-center/src/provider/affine/apis/workspace.ts @@ -1,4 +1,4 @@ -import { MessageCenter } from 'src/message/message.js'; +import { MessageCenter } from '../../../message/index.js'; import { bareClient, client } from './request.js'; import type { User } from './user'; From 03a827e75952d7002e752221a22be4ce3c923ad1 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Thu, 12 Jan 2023 17:28:18 +0800 Subject: [PATCH 206/298] chore: update searchArrowButton style --- .../components/header/QuickSearchButton.tsx | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/app/src/components/header/QuickSearchButton.tsx b/packages/app/src/components/header/QuickSearchButton.tsx index a1c68ffba8..dfc00eef14 100644 --- a/packages/app/src/components/header/QuickSearchButton.tsx +++ b/packages/app/src/components/header/QuickSearchButton.tsx @@ -1,12 +1,10 @@ import React from 'react'; import { IconButton, IconButtonProps } from '@/ui/button'; -import { Tooltip } from '@/ui/tooltip'; import { ArrowDownIcon } from '@blocksuite/icons'; import { useModal } from '@/providers/GlobalModalProvider'; -import { useTranslation } from '@affine/i18n'; import { styled } from '@/styles'; -const StyledIconButtonWithAnimate = styled(IconButton)(() => { +const StyledIconButtonWithAnimate = styled(IconButton)(({ theme }) => { return { svg: { transition: 'transform 0.15s ease-in-out', @@ -15,6 +13,9 @@ const StyledIconButtonWithAnimate = styled(IconButton)(() => { svg: { transform: 'translateY(3px)', }, + '::after': { + background: theme.colors.pageBackground, + }, }, }; }); @@ -23,20 +24,17 @@ export const QuickSearchButton = ({ ...props }: Omit) => { const { triggerQuickSearchModal } = useModal(); - const { t } = useTranslation(); return ( - - { - onClick?.(e); - triggerQuickSearchModal(); - }} - > - - - + { + onClick?.(e); + triggerQuickSearchModal(); + }} + > + + ); }; From a0c9f9a49c25668cc85df6e7cd1de7232b0cad59 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 17:33:12 +0800 Subject: [PATCH 207/298] feat: add backhome --- packages/app/src/components/404/index.tsx | 16 +++++++++++++++- packages/app/src/pages/404.tsx | 4 ---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/app/src/components/404/index.tsx b/packages/app/src/components/404/index.tsx index 8ed4232807..36f1b90a34 100644 --- a/packages/app/src/components/404/index.tsx +++ b/packages/app/src/components/404/index.tsx @@ -1,10 +1,24 @@ import { NotFoundTitle, PageContainer } from './styles'; import { useTranslation } from '@affine/i18n'; +import { Button } from '@/ui/button'; +import { useRouter } from 'next/router'; export const NotfoundPage = () => { const { t } = useTranslation(); + const router = useRouter(); return ( - {t('404 - Page Not Found')} + + {t('404 - Page Not Found')} +

    + +

    +
    ); }; diff --git a/packages/app/src/pages/404.tsx b/packages/app/src/pages/404.tsx index 74f25f07ed..0eef5261e5 100644 --- a/packages/app/src/pages/404.tsx +++ b/packages/app/src/pages/404.tsx @@ -1,9 +1,5 @@ import NotfoundPage from '@/components/404'; -import { useAppState } from '@/providers/app-state-provider'; export default function Custom404() { - const { workspaceList } = useAppState(); - console.log('workspaceList: ', workspaceList); - return ; } From 0b623a522b828f8bab1922671fa37d1bf634f515 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 12 Jan 2023 17:38:18 +0800 Subject: [PATCH 208/298] feat: add remove workspace by ids --- .../data-center/src/provider/affine/affine.ts | 16 ++---- .../src/workspace-unit-collection.ts | 54 ++++++++++++------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index c389363abb..88dab8485b 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -141,16 +141,10 @@ export class AffineProvider extends BaseProvider { addedWorkspaces.push(workspaceUnit); } } - if (addedWorkspaces.length) { - // add workspaces - this._workspaces.add(addedWorkspaces); - } - if (removeWorkspaceList.length) { - // remove workspaces - removeWorkspaceList.forEach(id => { - this._workspaces.remove(id); - }); - } + // add workspaces + this._workspaces.add(addedWorkspaces); + // remove workspaces + this._workspaces.remove(removeWorkspaceList); } private _getWebsocketProvider(workspace: BlocksuiteWorkspace) { @@ -174,7 +168,7 @@ export class AffineProvider extends BaseProvider { blocksuiteWorkspace: BlocksuiteWorkspace, published = false ) { - const { doc, room: workspaceId } = blocksuiteWorkspace; + const { room: workspaceId } = blocksuiteWorkspace; assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); const updates = await this._apis.downloadWorkspace(workspaceId, published); await applyUpdate(blocksuiteWorkspace, new Uint8Array(updates)); diff --git a/packages/data-center/src/workspace-unit-collection.ts b/packages/data-center/src/workspace-unit-collection.ts index 7d55762560..b51f5d160f 100644 --- a/packages/data-center/src/workspace-unit-collection.ts +++ b/packages/data-center/src/workspace-unit-collection.ts @@ -8,7 +8,7 @@ export interface WorkspaceUnitCollectionScope { get: (workspaceId: string) => WorkspaceUnit | undefined; list: () => WorkspaceUnit[]; add: (workspace: WorkspaceUnit | WorkspaceUnit[]) => void; - remove: (workspaceId: string) => boolean; + remove: (workspaceId: string | string[]) => boolean; clear: () => void; update: ( workspaceId: string, @@ -18,7 +18,7 @@ export interface WorkspaceUnitCollectionScope { export interface WorkspaceUnitCollectionChangeEvent { added?: WorkspaceUnit[]; - deleted?: WorkspaceUnit; + deleted?: WorkspaceUnit[]; updated?: WorkspaceUnit; } @@ -62,16 +62,22 @@ export class WorkspaceUnitCollection { const workspaceUnits = Array.isArray(workspaceUnit) ? workspaceUnit : [workspaceUnit]; + let added = false; workspaceUnits.forEach(workspaceUnit => { if (this._workspaceUnitMap.has(workspaceUnit.id)) { // FIXME: multiple add same workspace return; } + added = true; this._workspaceUnitMap.set(workspaceUnit.id, workspaceUnit); scopedWorkspaceIds.add(workspaceUnit.id); }); + if (!added) { + return; + } + this._events.emit('change', [ { added: workspaceUnits, @@ -79,27 +85,39 @@ export class WorkspaceUnitCollection { ]); }; - const remove = (workspaceId: string) => { - if (!scopedWorkspaceIds.has(workspaceId)) { - return true; - } + const remove = (workspaceId: string | string[]) => { + const workspaceIds = Array.isArray(workspaceId) + ? workspaceId + : [workspaceId]; + const workspaceUnits: WorkspaceUnit[] = []; - const workspaceUnit = this._workspaceUnitMap.get(workspaceId); - if (workspaceUnit) { - const ret = this._workspaceUnitMap.delete(workspaceId); - // If deletion failed, return. - if (!ret) { - return ret; + workspaceIds.forEach(workspaceId => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return; } + const workspaceUnit = this._workspaceUnitMap.get(workspaceId); + if (workspaceUnit) { + const ret = this._workspaceUnitMap.delete(workspaceId); + // If deletion failed, return. + if (!ret) { + return; + } - scopedWorkspaceIds.delete(workspaceId); + workspaceUnits.push(workspaceUnit); + scopedWorkspaceIds.delete(workspaceId); + } + }); - this._events.emit('change', [ - { - deleted: workspaceUnit, - } as WorkspaceUnitCollectionChangeEvent, - ]); + if (!workspaceUnits.length) { + return false; } + + this._events.emit('change', [ + { + deleted: workspaceUnits, + } as WorkspaceUnitCollectionChangeEvent, + ]); + return true; }; From dedf03ae5063db3d1300ef1735b65c169f1bc5c9 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Thu, 12 Jan 2023 17:47:46 +0800 Subject: [PATCH 209/298] feat: add temporary language switch button --- .../components/workspace-slider-bar/index.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index 4663afa56a..b81204f1e9 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -70,7 +70,7 @@ export const WorkSpaceSliderBar = () => { const { currentWorkspace } = useAppState(); const { openPage, createPage } = usePageHelper(); const router = useRouter(); - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const [showTip, setShowTip] = useState(false); const [show, setShow] = useLocalStorage('AFFiNE_SLIDE_BAR', false, true); const currentWorkspaceId = currentWorkspace?.id; @@ -84,7 +84,9 @@ export const WorkSpaceSliderBar = () => { ? `/workspace/${currentWorkspaceId}/setting` : '', }; - + const changeLanguage = (event: string) => { + i18n.changeLanguage(event); + }; return ( <> @@ -176,6 +178,20 @@ export const WorkSpaceSliderBar = () => { {t('Trash')} + { + changeLanguage('en'); + }} + > + change to English + + { + changeLanguage('zh-Hans'); + }} + > + 切换到中文 + { const pageId = await createPage(); From cf6b1731b02c50bcf9a208aa961babfca9a4bddd Mon Sep 17 00:00:00 2001 From: JimmFly Date: Thu, 12 Jan 2023 17:53:11 +0800 Subject: [PATCH 210/298] chore: update translation --- packages/i18n/src/resources/en.json | 8 +- packages/i18n/src/resources/index.ts | 11 ++ packages/i18n/src/resources/zh-Hans.json | 148 +++++++++++++++++++++++ 3 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 packages/i18n/src/resources/zh-Hans.json diff --git a/packages/i18n/src/resources/en.json b/packages/i18n/src/resources/en.json index 2831a8aafe..6886bbacb5 100644 --- a/packages/i18n/src/resources/en.json +++ b/packages/i18n/src/resources/en.json @@ -15,7 +15,6 @@ "Add to favourites": "Add to favourites", "Paper": "Paper", "Edgeless": "Edgeless", - "Jump to": "Jump to", "Convert to ": "Convert to ", "Page": "Page", "Export": "Export", @@ -57,12 +56,13 @@ "Reduce indent": "Reduce indent", "Markdown Syntax": "Markdown Syntax", "Divider": "Divider", - "404 - Page Not Found": "404 - Page Not Found", "Once deleted, you can't undo this action": { "": "Once deleted, you can't undo this action." }, "Remove from favourites": "Remove from favourites", "Removed from Favourites": "Removed from Favourites", + "Jump to": "Jump to", + "404 - Page Not Found": "404 - Page Not Found", "New Workspace": "New Workspace", "Workspace description": "Workspace is your virtual space to capture, create and plan as just one person or together as a team.", "Create": "Create", @@ -141,5 +141,7 @@ "Sign in": "Sign in to AFFiNE Cloud", "Sync Description": "{{workspaceName}} is a Local Workspace. All data is stored on the current device. You can enable AFFiNE Cloud for this workspace to keep data in sync with the cloud.", "Sync Description2": "<1>{{workspaceName}} is a Cloud Workspace. All data will be synchronised and saved to AFFiNE Cloud.", - "Delete Workspace Description": "Deleting (<1>{{workspace}}) cannot be undone, please proceed with caution. All contents will be lost." + "Delete Workspace Description": "Deleting (<1>{{workspace}}) cannot be undone, please proceed with caution. All contents will be lost.", + "core": "core", + "all": "all" } diff --git a/packages/i18n/src/resources/index.ts b/packages/i18n/src/resources/index.ts index 2081ad8aaf..cf5c5fc729 100644 --- a/packages/i18n/src/resources/index.ts +++ b/packages/i18n/src/resources/index.ts @@ -2,6 +2,7 @@ // Run `pnpm run download-resources` to regenerate. // To overwrite this, please overwrite download.ts script. import en from './en.json'; +import zh_Hans from './zh-Hans.json'; export const LOCALES = [ { @@ -14,4 +15,14 @@ export const LOCALES = [ completeRate: 1, res: en, }, + { + id: 1000040004, + name: 'Simplified Chinese', + tag: 'zh-Hans', + originalName: '简体中文', + flagEmoji: '🇨🇳', + base: false, + completeRate: 1, + res: zh_Hans, + }, ] as const; diff --git a/packages/i18n/src/resources/zh-Hans.json b/packages/i18n/src/resources/zh-Hans.json new file mode 100644 index 0000000000..2a2e17c660 --- /dev/null +++ b/packages/i18n/src/resources/zh-Hans.json @@ -0,0 +1,148 @@ +{ + "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "", + "Quick search": "快速搜索", + "All pages": "全部页面", + "Favourites": "收藏夹", + "No item": "无项目", + "Import": "导入", + "Trash": "垃圾箱", + "New Page": "新建页面", + "New Keyword Page": "新建 “{{query}}“ 为标题的页面 ", + "Find 0 result": "找到 0 个结果", + "Find results": "找到 {{number}} 个结果", + "Collapse sidebar": "折叠侧边栏", + "Expand sidebar": "展开侧边栏", + "Added to Favourites": "已收藏", + "Add to favourites": "加入收藏", + "Paper": "文档", + "Edgeless": "无界", + "Convert to ": "转换为", + "Page": "页面", + "Export": "导出", + "Export to HTML": "导出为 HTML", + "Export to Markdown": "导出为 Markdown", + "Delete": "删除", + "Title": "标题", + "Untitled": "未命名", + "Created": "已创建", + "Updated": "已更新", + "Open in new tab": "在新标签页打开", + "Favourite": "收藏", + "Favourited": "已收藏", + "Delete page?": "确定要删除页面?", + "Delete permanently?": "是否永久删除?", + "will be moved to Trash": "{{title}} 将被移到垃圾箱", + "Once deleted, you can't undo this action": { + "": "一旦删除,将无法撤销!" + }, + "Moved to Trash": "已移到垃圾箱", + "Permanently deleted": "已永久删除", + "restored": "{{title}} 已恢复", + "Cancel": "取消", + "Keyboard Shortcuts": "键盘快捷键", + "Contact Us": "联系我们", + "Official Website": "官网", + "Get in touch!": "保持联络!", + "AFFiNE Community": "AFFiNE 社区", + "How is AFFiNE Alpha different?": "AFFiNE Alpha有何不同?", + "Shortcuts": "快捷键", + "Undo": "撤销", + "Redo": "重做", + "Bold": "粗体", + "Italic": "斜体", + "Underline": "下划线", + "Strikethrough": "删除线", + "Inline code": "行内代码", + "Code block": "代码块", + "Link": "超链接(选定文本)", + "Body text": "正文", + "Heading": "标题 {{number}}", + "Increase indent": "增加缩进", + "Reduce indent": "减少缩进", + "Markdown Syntax": "Markdown 语法", + "Divider": "分割线", + "404 - Page Not Found": "404 - 页面不见了", + "Remove from favourites": "从收藏中移除", + "Removed from Favourites": "已从收藏中移除", + "New Workspace": "新建工作区", + "Workspace description": "工作区是为个人和团队进行引用、创建和规划的虚拟空间。", + "Create": "创建", + "Select": "选择", + "Text": "文本(即将上线)", + "Shape": "图形", + "Sticky": "便利贴(即将上线)", + "Pen": "笔(即将上线)", + "Connector": "链接(即将上线)", + "Upload": "上传", + "Restore it": "恢复TA", + "TrashButtonGroupTitle": "永久删除", + "TrashButtonGroupDescription": "一旦删除,将无法撤消此操作。确定吗?", + "Delete permanently": "永久删除", + "Quick search placeholder": "快速搜索...", + "Quick search placeholder2": "在{{workspace}} 中搜索", + "Settings": "设置", + "recommendBrowser": "建议使用 <1>Chrome 浏览器以获得最佳体验。", + "upgradeBrowser": "请升级到最新版本的 Chrome 以获得最佳体验。", + "Invite Members": "邀请成员", + "Invite placeholder": "搜索邮件(仅支持Gmail)", + "Non-Gmail": "不支持非Gmail邮箱", + "Invite": "邀请", + "Loading": "加载中...", + "NotLoggedIn": "当前未登录", + "ClearData": "清除本地数据", + "Continue with Google": "谷歌登录以继续", + "Set up an AFFiNE account to sync data": "设置AFFiNE帐户以同步数据", + "Stay logged out": "保持登出状态", + "All changes are saved locally": "所有改动已保存到本地", + "Ooops!": "啊哦!", + "mobile device": "貌似你正在移动设备上浏览。", + "mobile device description": "我们仍在进行移动端的支持工作,建议使用桌面设备。", + "Got it": "知道了", + "emptyAllPages": "此工作区为空。创建新页面并开始编辑。", + "emptyFavourite": "单击“添加到收藏夹”,页面将显示在此处。", + "emptyTrash": "单击“添加到垃圾箱”,页面将显示在此处。", + "still designed": "(此页面仍在设计中。)", + "My Workspaces": "我的工作区", + "Create Or Import": "创建或导入", + "Tips": "提示:", + "login success": "登录成功", + "Sign in": "登录 AFFiNE 云", + "Sign out": "登出 AFFiNE 云", + "Delete Workspace": "删除工作空间", + "Delete Workspace Description": "正在删除 (<1>{{workspace}}) ,此操作无法撤销,所有内容将会丢失。", + "Delete Workspace Description2": "正在删除(<1>{{workspace}}),将同时删除本地和云端数据。此操作无法撤消,请谨慎操作。", + "Delete Workspace placeholder": "请输入”Delete“以确认", + "Leave Workspace": "退出工作区", + "Leave Workspace Description": "退出后,您将无法再访问此工作区的内容。", + "Jump to": "跳转到", + "Leave": "退出", + "Workspace Icon": "工作区图标", + "Workspace Name": "工作区名称", + "Workspace Type": "工作区类型", + "Export Workspace": "导出工作区 <1>{{workspace}} 即将上线", + "Users": "用户", + "Access level": "访问权限", + "Pending": "待定", + "Collaboration Description": "与其他成员协作需要AFFiNE云服务支持。", + "Enable AFFiNE Cloud": "启用 AFFiNE 云服务", + "Enable AFFiNE Cloud Description": "如启用,此工作区中的数据将通过AFFiNE Cloud进行备份和同步。", + "Enable": "启动", + "Sign in and Enable": "登录并启用", + "Skip": "跳过", + "Publishing": "发布到web需要AFFiNE云服务。", + "Share with link": "通过链接分享", + "Copy Link": "复制链接", + "Publishing Description": "发布到web后,所有人都可以通过链接查看此工作区的内容。", + "Stop publishing": "中止发布", + "Publish to web": "发布到web", + "Sync Description": "{{workspaceName}}是本地工作区,所有数据都存储在当前设备上。您可以为此工作区启用AFFiNE Cloud,以使数据与云端保持同步。", + "Sync Description2": "<1>{{workspaceName}}是云端工作区。所有数据将同步并保存到AFFiNE Cloud。", + "Download data to device": "下载{{CoreOrAll}}数据到设备", + "General": "常规", + "Sync": "同步", + "Collaboration": "协作", + "Publish": "发布", + "Workspace Settings": "工作区设置", + "core": "核心", + "all": "全部" +} From cf47098631db5134d66ea78e153ea2b75380ce01 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 12 Jan 2023 18:13:44 +0800 Subject: [PATCH 211/298] feat: fix access permission api --- packages/data-center/src/datacenter.ts | 3 ++- packages/data-center/src/provider/affine/affine.ts | 4 ++-- .../src/provider/affine/apis/workspace.ts | 14 +++++++------- packages/data-center/src/provider/base.ts | 7 +++++-- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 551fa009cf..e8876ac2d6 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -416,13 +416,14 @@ export class DataCenter { /** * accept invitation * @param {string} inviteCode + * @returns {Promise} permission */ async acceptInvitation(inviteCode: string, providerStr = 'affine') { const provider = this.providerMap.get(providerStr); if (provider) { return await provider.acceptInvitation(inviteCode); } - return []; + return null; } onMessage(cb: (message: Message) => void) { diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 88dab8485b..6e14e82513 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -399,7 +399,7 @@ export class AffineProvider extends BaseProvider { return this._apis.getWorkspaceMembers({ id }); } - public override async acceptInvitation(invitingCode: string): Promise { - await this._apis.acceptInviting({ invitingCode }); + public override async acceptInvitation(invitingCode: string) { + return await this._apis.acceptInviting({ invitingCode }); } } diff --git a/packages/data-center/src/provider/affine/apis/workspace.ts b/packages/data-center/src/provider/affine/apis/workspace.ts index f2455810eb..09574b3e82 100644 --- a/packages/data-center/src/provider/affine/apis/workspace.ts +++ b/packages/data-center/src/provider/affine/apis/workspace.ts @@ -197,13 +197,13 @@ export interface AcceptInvitingParams { export async function acceptInviting( params: AcceptInvitingParams -): Promise { - await bareClient - .post(`api/invitation/${params.invitingCode}`) - .catch(error => { - sendMessage(messageCode.acceptInvitingFailed); - throw new RequestError('accept inviting failed', error); - }); +): Promise { + try { + return bareClient.post(`api/invitation/${params.invitingCode}`).json(); + } catch (error) { + sendMessage(messageCode.acceptInvitingFailed); + throw new RequestError('accept inviting failed', error); + } } export async function uploadBlob(params: { blob: Blob }): Promise { diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 0f0a23ead3..eb9a68d748 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -4,6 +4,7 @@ import { Logger, User } from '../types'; import type { WorkspaceUnitCollectionScope } from '../workspace-unit-collection'; import type { WorkspaceUnitCtorParams, WorkspaceUnit } from '../workspace-unit'; import { Member } from './affine/apis'; +import { Permission } from './affine/apis/workspace.js'; const defaultLogger = () => { return; @@ -233,8 +234,10 @@ export class BaseProvider { * @param {string} inviteCode * @returns */ - public async acceptInvitation(inviteCode: string): Promise { + public async acceptInvitation( + inviteCode: string + ): Promise { inviteCode; - return; + return null; } } From 32a5788504ac9c78ffef66a27d0c6670ccde491f Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 18:36:57 +0800 Subject: [PATCH 212/298] feat: add invite info --- .../app/src/hooks/use-workspace-helper.ts | 9 +++ .../app/src/pages/invite/[invite_code].tsx | 63 +++++++++---------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/packages/app/src/hooks/use-workspace-helper.ts b/packages/app/src/hooks/use-workspace-helper.ts index f1dee901d3..480ba409c1 100644 --- a/packages/app/src/hooks/use-workspace-helper.ts +++ b/packages/app/src/hooks/use-workspace-helper.ts @@ -64,6 +64,14 @@ export const useWorkspaceHelper = () => { currentWorkspace && (await dataCenter.leaveWorkspace(currentWorkspace?.id)); }; + const acceptInvite = async (inviteCode: string) => { + let inviteInfo; + if (inviteCode) { + inviteInfo = await dataCenter.acceptInvitation(inviteCode); + } + return inviteInfo; + }; + return { createWorkspace, publishWorkspace, @@ -71,5 +79,6 @@ export const useWorkspaceHelper = () => { enableWorkspace, deleteWorkSpace, leaveWorkSpace, + acceptInvite, }; }; diff --git a/packages/app/src/pages/invite/[invite_code].tsx b/packages/app/src/pages/invite/[invite_code].tsx index e007a6cd25..22122db138 100644 --- a/packages/app/src/pages/invite/[invite_code].tsx +++ b/packages/app/src/pages/invite/[invite_code].tsx @@ -1,44 +1,36 @@ +import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; +import { useAppState } from '@/providers/app-state-provider'; import { styled } from '@/styles'; import { Empty } from '@/ui/empty'; -import { Avatar } from '@mui/material'; -// import { getDataCenter } from '@affine/datacenter'; +// import { Avatar } from '@mui/material'; import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; -const User = ({ name, avatar }: { name: string; avatar?: string }) => { - return ( - - {avatar ? ( - - ) : ( - {name.slice(0, 1)} - )} - {name} - - ); -}; +// const User = ({ name, avatar }: { name: string; avatar?: string }) => { +// return ( +// +// {avatar ? ( +// +// ) : ( +// {name.slice(0, 1)} +// )} +// {name} +// +// ); +// }; export default function DevPage() { const router = useRouter(); const [successInvited, setSuccessInvited] = useState(false); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const [inviteData, setInviteData] = useState(null); + const { acceptInvite } = useWorkspaceHelper(); + const { user } = useAppState(); useEffect(() => { - // getDataCenter() - // .then(dc => - // dc.apis.acceptInviting({ - // invitingCode: router.query.invite_code as string, - // }) - // ) - // .then(data => { - // setSuccessInvited(true); - // setInviteData(data); - // }) - // .catch(err => { - // console.log('err: ', err); - // }); - setSuccessInvited(true); - setInviteData(null); + acceptInvite(router.query.invite_code as string).then(data => { + if (data && data.accepted) { + setSuccessInvited(true); + user && router.push(`/workspace/${data.workspace_id}`); + } + }); }, [router.query.invite_code]); return ( @@ -47,11 +39,12 @@ export default function DevPage() { - invited - you to join - invited */} + {/* you to join */} + {/* + > */} {successInvited ? ( Date: Thu, 12 Jan 2023 18:37:43 +0800 Subject: [PATCH 213/298] fix: add error catch --- packages/app/src/pages/invite/[invite_code].tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/app/src/pages/invite/[invite_code].tsx b/packages/app/src/pages/invite/[invite_code].tsx index 22122db138..342fa7c481 100644 --- a/packages/app/src/pages/invite/[invite_code].tsx +++ b/packages/app/src/pages/invite/[invite_code].tsx @@ -25,12 +25,13 @@ export default function DevPage() { const { acceptInvite } = useWorkspaceHelper(); const { user } = useAppState(); useEffect(() => { - acceptInvite(router.query.invite_code as string).then(data => { - if (data && data.accepted) { - setSuccessInvited(true); - user && router.push(`/workspace/${data.workspace_id}`); - } - }); + router.query.invite_code && + acceptInvite(router.query.invite_code as string).then(data => { + if (data && data.accepted) { + setSuccessInvited(true); + user && router.push(`/workspace/${data.workspace_id}`); + } + }); }, [router.query.invite_code]); return ( From c8fb9868884fc854ea2d9cc6e84506f70eaca3d4 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Thu, 12 Jan 2023 18:57:55 +0800 Subject: [PATCH 214/298] chore: update translation --- .../workspace-setting/member/MembersPage.tsx | 21 ++++++++++--------- .../pages/workspace/[workspaceId]/setting.tsx | 5 +++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/app/src/components/workspace-setting/member/MembersPage.tsx b/packages/app/src/components/workspace-setting/member/MembersPage.tsx index 45ab2c30da..e93e65b6e6 100644 --- a/packages/app/src/components/workspace-setting/member/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/member/MembersPage.tsx @@ -26,11 +26,12 @@ import { toast } from '@/ui/toast'; import useMembers from '@/hooks/use-members'; import Loading from '@/components/loading'; import { Wrapper } from '@/ui/layout'; +import { useTranslation } from '@affine/i18n'; export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const [isInviteModalShow, setIsInviteModalShow] = useState(false); const { members, removeMember, loaded } = useMembers(); - + const { t } = useTranslation(); // FIXME: DELETE THIS const { user, login, updateWorkspaceMeta } = useTemporaryHelper(); const { confirm } = useConfirm(); @@ -51,10 +52,10 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { <> - Users({members.length}) + {t('Users')} ({members.length}) - Access level + {t('Access level')} {members.map((member, index) => { @@ -138,7 +139,7 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { type="primary" shape="circle" > - Invite Members + {t('Invite Members')} { @@ -158,17 +159,17 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { return ( - <>Collaborating with other members requires AFFiNE Cloud service. + <>{t('Collaboration Description')} diff --git a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx index e8c40aacf2..55426cc604 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx @@ -24,6 +24,7 @@ import { import { useAppState } from '@/providers/app-state-provider'; import WorkspaceLayout from '@/components/workspace-layout'; import { WorkspaceUnit } from '@affine/datacenter'; +import { useTranslation } from '@affine/i18n'; type TabNames = 'general' | 'members' | 'publish' | 'sync' | 'export'; @@ -61,7 +62,7 @@ const tabMap: { const WorkspaceSetting = () => { const { currentWorkspace } = useAppState(); - + const { t } = useTranslation(); const [activeTab, setActiveTab] = useState(tabMap[0].name); const handleTabChange = (tab: TabNames) => { setActiveTab(tab); @@ -75,7 +76,7 @@ const WorkspaceSetting = () => { - Workspace Settings + {t('Workspace Settings')} {tabMap.map(({ icon, name }) => { From cea3d13805663b3b467d3d8aca3e14f7a299b08c Mon Sep 17 00:00:00 2001 From: alt0 Date: Thu, 12 Jan 2023 19:50:26 +0800 Subject: [PATCH 215/298] fix: workspace avatar --- .../{index.tsx => Avatar.tsx} | 6 ++- .../workspace-avatar/WorkspaceUnitAvatar.tsx | 39 +++++++++++++++++++ .../src/components/workspace-avatar/index.ts | 2 + .../src/components/workspace-modal/index.tsx | 8 +--- .../WorkspaceSelector/WorkspaceSelector.tsx | 8 ++-- .../src/provider/local/indexeddb/utils.ts | 1 + .../data-center/src/provider/local/local.ts | 2 + pnpm-lock.yaml | 24 ------------ 8 files changed, 55 insertions(+), 35 deletions(-) rename packages/app/src/components/workspace-avatar/{index.tsx => Avatar.tsx} (88%) create mode 100644 packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx create mode 100644 packages/app/src/components/workspace-avatar/index.ts diff --git a/packages/app/src/components/workspace-avatar/index.tsx b/packages/app/src/components/workspace-avatar/Avatar.tsx similarity index 88% rename from packages/app/src/components/workspace-avatar/index.tsx rename to packages/app/src/components/workspace-avatar/Avatar.tsx index 22f5fdd048..c01808e68f 100644 --- a/packages/app/src/components/workspace-avatar/index.tsx +++ b/packages/app/src/components/workspace-avatar/Avatar.tsx @@ -23,7 +23,11 @@ export const WorkspaceAvatar = (props: IWorkspaceAvatar) => { }} > - +
    ) : ( diff --git a/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx b/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx new file mode 100644 index 0000000000..8a390bddda --- /dev/null +++ b/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx @@ -0,0 +1,39 @@ +import { useState, useEffect } from 'react'; +import type { WorkspaceUnit } from '@affine/datacenter'; +import { WorkspaceAvatar as Avatar } from './Avatar'; + +const useAvatar = (workspaceUnit?: WorkspaceUnit) => { + const [avatarUrl, setAvatarUrl] = useState(''); + const avatarId = + workspaceUnit?.avatar || workspaceUnit?.blocksuiteWorkspace?.meta.avatar; + useEffect(() => { + if (avatarId && workspaceUnit?.blocksuiteWorkspace?.blobs) { + workspaceUnit.blocksuiteWorkspace.blobs.then(blobs => { + blobs?.get(avatarId).then(url => setAvatarUrl(url || '')); + }); + } else { + setAvatarUrl(''); + } + }, [avatarId]); + + return avatarUrl; +}; + +export const WorkspaceUnitAvatar = ({ + size = 20, + name, + workspaceUnit, +}: { + size?: number; + name?: string; + workspaceUnit?: WorkspaceUnit | null; +}) => { + const avatarUrl = useAvatar(workspaceUnit || undefined); + return ( + + ); +}; diff --git a/packages/app/src/components/workspace-avatar/index.ts b/packages/app/src/components/workspace-avatar/index.ts new file mode 100644 index 0000000000..8d6dfe17ba --- /dev/null +++ b/packages/app/src/components/workspace-avatar/index.ts @@ -0,0 +1,2 @@ +export { WorkspaceAvatar } from './Avatar'; +export { WorkspaceUnitAvatar } from './WorkspaceUnitAvatar'; diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 4328224d8c..a34abdb878 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -10,7 +10,7 @@ import { AddIcon, } from '@blocksuite/icons'; import { toast } from '@/ui/toast'; -import { WorkspaceAvatar } from '@/components/workspace-avatar'; +import { WorkspaceUnitAvatar } from '@/components/workspace-avatar'; import { useAppState } from '@/providers/app-state-provider'; import { useRouter } from 'next/router'; import { useConfirm } from '@/providers/ConfirmProvider'; @@ -65,11 +65,7 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { marginRight: '10px', }} > - +
    { const [workspaceListShow, setWorkspaceListShow] = useState(false); @@ -23,17 +23,17 @@ export const WorkspaceSelector = () => {
    -
    diff --git a/packages/data-center/src/provider/local/indexeddb/utils.ts b/packages/data-center/src/provider/local/indexeddb/utils.ts index 0a83282a6a..68a4172eb3 100644 --- a/packages/data-center/src/provider/local/indexeddb/utils.ts +++ b/packages/data-center/src/provider/local/indexeddb/utils.ts @@ -20,6 +20,7 @@ export const writeUpdatesToLocal = async ( if (updatesStore) { await idb.addAutoKey(updatesStore, currState); } + db.close(); }; export const applyLocalUpdates = async ( diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 7388c4b2ab..f9b819ea40 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -8,6 +8,7 @@ import type { import { varStorage as storage } from 'lib0/storage'; import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; import { IndexedDBProvider } from './indexeddb/indexeddb.js'; +import { applyLocalUpdates } from './indexeddb/utils.js'; import assert from 'assert'; import { loadWorkspaceUnit, createWorkspaceUnit } from './utils.js'; import type { WorkspaceUnit } from '../../workspace-unit'; @@ -48,6 +49,7 @@ export class LocalProvider extends BaseProvider { workspace: BlocksuiteWorkspace ): Promise { assert(workspace.room); + await applyLocalUpdates(workspace); await this.linkLocal(workspace); return workspace; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4844bc6a23..f608cb2fab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3011,7 +3011,6 @@ packages: /@next/env/13.1.0: resolution: {integrity: sha512-6iNixFzCndH+Bl4FetQzOMjxCJqg8fs0LAlZviig1K6mIjOWH2m2oPcHcOg1Ta5VCe7Bx5KG1Hs+NrWDUkBt9A==} - dev: false /@next/eslint-plugin-next/12.3.1: resolution: {integrity: sha512-sw+lTf6r6P0j+g/n9y4qdWWI2syPqZx+uc0+B/fRENqfR3KpSid6MIKqc9gNwGhJASazEQ5b3w8h4cAET213jw==} @@ -3034,7 +3033,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: false optional: true /@next/swc-android-arm64/12.3.1: @@ -3052,7 +3050,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: false optional: true /@next/swc-darwin-arm64/12.3.1: @@ -3070,7 +3067,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-darwin-x64/12.3.1: @@ -3088,7 +3084,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-freebsd-x64/12.3.1: @@ -3106,7 +3101,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm-gnueabihf/12.3.1: @@ -3124,7 +3118,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-gnu/12.3.1: @@ -3142,7 +3135,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-musl/12.3.1: @@ -3160,7 +3152,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-gnu/12.3.1: @@ -3178,7 +3169,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-musl/12.3.1: @@ -3196,7 +3186,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-win32-arm64-msvc/12.3.1: @@ -3214,7 +3203,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-ia32-msvc/12.3.1: @@ -3232,7 +3220,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-x64-msvc/12.3.1: @@ -3250,7 +3237,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@nodelib/fs.scandir/2.1.5: @@ -3613,7 +3599,6 @@ packages: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} dependencies: tslib: 2.4.0 - dev: false /@szmarczak/http-timer/5.0.1: resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} @@ -4580,7 +4565,6 @@ packages: /client-only/0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - dev: false /cliui/6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -7512,7 +7496,6 @@ packages: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false /natural-compare-lite/1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -7635,7 +7618,6 @@ packages: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - dev: false /node-domexception/1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} @@ -7986,7 +7968,6 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false /preferred-pm/3.0.3: resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} @@ -8156,7 +8137,6 @@ packages: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.0 - dev: false /react-i18next/11.18.6_i18next@21.10.0: resolution: {integrity: sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==} @@ -8253,7 +8233,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: false /read-pkg-up/7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -8531,7 +8510,6 @@ packages: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: loose-envify: 1.4.0 - dev: false /schema-utils/2.7.1: resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} @@ -8690,7 +8668,6 @@ packages: /source-map-js/1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - dev: false /source-map-support/0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} @@ -8939,7 +8916,6 @@ packages: dependencies: client-only: 0.0.1 react: 18.2.0 - dev: false /stylis/4.0.13: resolution: {integrity: sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==} From f892af6dcd548a6b3f765adbbf830913550c30e0 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Fri, 13 Jan 2023 09:59:44 +0800 Subject: [PATCH 216/298] fix:workspace avatar --- .../src/components/workspace-setting/general/General.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index 0ced889c68..6921282d7b 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -13,7 +13,10 @@ import { useAppState } from '@/providers/app-state-provider'; import { WorkspaceDelete } from './delete'; import { WorkspaceLeave } from './leave'; import { Upload } from '@/components/file-upload'; -import { WorkspaceAvatar } from '@/components/workspace-avatar'; +import { + WorkspaceAvatar, + WorkspaceUnitAvatar, +} from '@/components/workspace-avatar'; import { WorkspaceUnit } from '@affine/datacenter'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { @@ -49,10 +52,10 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { marginRight: '20px', }} > -
    Date: Fri, 13 Jan 2023 14:02:37 +0800 Subject: [PATCH 217/298] feat: add language switch in workspace modal --- .../app/src/components/workspace-modal/index.tsx | 3 ++- .../src/components/workspace-slider-bar/index.tsx | 14 -------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index a5f2369c4b..2822fbb367 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -15,6 +15,7 @@ import { useAppState } from '@/providers/app-state-provider'; import { useRouter } from 'next/router'; import { useConfirm } from '@/providers/ConfirmProvider'; import { useTranslation } from '@affine/i18n'; +import { LanguageMenu } from './languageMenu'; interface WorkspaceModalProps { open: boolean; @@ -37,7 +38,7 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { >
    {t('My Workspaces')} - {/* */} + { {t('Trash')} - { - changeLanguage('en'); - }} - > - change to English - - { - changeLanguage('zh-Hans'); - }} - > - 切换到中文 - { const pageId = await createPage(); From 8f38504009ad6d21c6fa96f976bc18c082171a63 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Fri, 13 Jan 2023 14:07:33 +0800 Subject: [PATCH 218/298] chore: remove unused function --- packages/app/src/components/workspace-slider-bar/index.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index 75ad72ea33..e5ec3b8e00 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -84,9 +84,6 @@ export const WorkSpaceSliderBar = () => { ? `/workspace/${currentWorkspaceId}/setting` : '', }; - const changeLanguage = (event: string) => { - i18n.changeLanguage(event); - }; return ( <> From b57d8d35295b5f2ab8baf745de3cc9cb07980485 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Fri, 13 Jan 2023 14:08:12 +0800 Subject: [PATCH 219/298] chore: remove unused variable --- packages/app/src/components/workspace-slider-bar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index e5ec3b8e00..ce6f8d43d3 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -70,7 +70,7 @@ export const WorkSpaceSliderBar = () => { const { currentWorkspace } = useAppState(); const { openPage, createPage } = usePageHelper(); const router = useRouter(); - const { t, i18n } = useTranslation(); + const { t } = useTranslation(); const [showTip, setShowTip] = useState(false); const [show, setShow] = useLocalStorage('AFFiNE_SLIDE_BAR', false, true); const currentWorkspaceId = currentWorkspace?.id; From d1c9a4070576a0143e51b9b7c7f2e111c7a85dbd Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Fri, 13 Jan 2023 14:11:29 +0800 Subject: [PATCH 220/298] fix: lint error --- .../workspace-avatar/WorkspaceUnitAvatar.tsx | 7 ++-- .../app/src/pages/invite/[invite_code].tsx | 33 +++++++------------ 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx b/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx index 8a390bddda..4144d9645d 100644 --- a/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx +++ b/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx @@ -6,15 +6,16 @@ const useAvatar = (workspaceUnit?: WorkspaceUnit) => { const [avatarUrl, setAvatarUrl] = useState(''); const avatarId = workspaceUnit?.avatar || workspaceUnit?.blocksuiteWorkspace?.meta.avatar; + const blobs = workspaceUnit?.blocksuiteWorkspace?.blobs; useEffect(() => { - if (avatarId && workspaceUnit?.blocksuiteWorkspace?.blobs) { - workspaceUnit.blocksuiteWorkspace.blobs.then(blobs => { + if (avatarId && blobs) { + blobs.then(blobs => { blobs?.get(avatarId).then(url => setAvatarUrl(url || '')); }); } else { setAvatarUrl(''); } - }, [avatarId]); + }, [avatarId, blobs]); return avatarUrl; }; diff --git a/packages/app/src/pages/invite/[invite_code].tsx b/packages/app/src/pages/invite/[invite_code].tsx index 342fa7c481..872b3f927a 100644 --- a/packages/app/src/pages/invite/[invite_code].tsx +++ b/packages/app/src/pages/invite/[invite_code].tsx @@ -1,5 +1,4 @@ import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; -import { useAppState } from '@/providers/app-state-provider'; import { styled } from '@/styles'; import { Empty } from '@/ui/empty'; // import { Avatar } from '@mui/material'; @@ -23,16 +22,14 @@ export default function DevPage() { const router = useRouter(); const [successInvited, setSuccessInvited] = useState(false); const { acceptInvite } = useWorkspaceHelper(); - const { user } = useAppState(); useEffect(() => { router.query.invite_code && acceptInvite(router.query.invite_code as string).then(data => { if (data && data.accepted) { setSuccessInvited(true); - user && router.push(`/workspace/${data.workspace_id}`); } }); - }, [router.query.invite_code]); + }, [router, acceptInvite]); return ( @@ -98,16 +95,16 @@ export default function DevPage() { ); } -const UserIcon = styled('div')({ - display: 'inline-block', - width: '28px', - height: '28px', - borderRadius: '50%', - backgroundColor: '#FFF5AB', - textAlign: 'center', - color: '#896406', - lineHeight: '28px', -}); +// const UserIcon = styled('div')({ +// display: 'inline-block', +// width: '28px', +// height: '28px', +// borderRadius: '50%', +// backgroundColor: '#FFF5AB', +// textAlign: 'center', +// color: '#896406', +// lineHeight: '28px', +// }); const Invited = styled('div')(({ theme }) => { return { @@ -126,14 +123,6 @@ const Content = styled('div')({ marginTop: '35px', }); -const UserContent = styled('span')({ - fontSize: '18px', - marginLeft: '12px', - span: { - padding: '0 12px', - }, -}); - const Status = styled('div')(() => { return { marginTop: '16px', From 3efc4b554b52d5dfb38769b3f263b891284318be Mon Sep 17 00:00:00 2001 From: zuomeng wang Date: Fri, 13 Jan 2023 14:50:15 +0800 Subject: [PATCH 221/298] Merge remote-tracking branch 'origin/master' into feat/datacenter (#727) --- package.json | 3 +- packages/app/package.json | 6 +- packages/data-center/package.json | 4 +- pnpm-lock.yaml | 192 ++++++++++++++++++++++++------ 4 files changed, 162 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 2838c7b64e..967a98bfa4 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ "test:unit": "playwright test --config=playwright.config.unit.ts", "postinstall": "husky install", "notify": "node --experimental-modules scripts/notify.mjs", - "check:ci": "pnpm lint & pnpm test" + "check:ci": "pnpm lint & pnpm test", + "update:blocksuite": "pnpm i --filter @affine/app --filter @affine/datacenter @blocksuite/blocks@nightly @blocksuite/store@nightly && pnpm i --filter @affine/app @blocksuite/editor@nightly" }, "lint-staged": { "*": "prettier --write --ignore-unknown", diff --git a/packages/app/package.json b/packages/app/package.json index aece2897f9..31fa964621 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -11,10 +11,10 @@ "dependencies": { "@affine/datacenter": "workspace:*", "@affine/i18n": "workspace:*", - "@blocksuite/blocks": "0.3.1-20230109032243-37ad3ba", - "@blocksuite/editor": "0.3.1-20230109032243-37ad3ba", + "@blocksuite/blocks": "0.4.0-20230111171650-bc63456", + "@blocksuite/editor": "0.4.0-20230111171650-bc63456", "@blocksuite/icons": "^2.0.2", - "@blocksuite/store": "0.3.1-20230109032243-37ad3ba", + "@blocksuite/store": "0.4.0-20230111171650-bc63456", "@emotion/css": "^11.10.0", "@emotion/react": "^11.10.4", "@emotion/server": "^11.10.0", diff --git a/packages/data-center/package.json b/packages/data-center/package.json index 4dce08d73c..d8e0f47f1b 100644 --- a/packages/data-center/package.json +++ b/packages/data-center/package.json @@ -26,8 +26,8 @@ "typescript": "^4.8.4" }, "dependencies": { - "@blocksuite/blocks": "0.3.1-20230109032243-37ad3ba", - "@blocksuite/store": "0.3.1-20230109032243-37ad3ba", + "@blocksuite/blocks": "0.4.0-20230111171650-bc63456", + "@blocksuite/store": "0.4.0-20230111171650-bc63456", "debug": "^4.3.4", "encoding": "^0.1.13", "firebase": "^9.15.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f608cb2fab..d7edf50741 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,10 +46,10 @@ importers: specifiers: '@affine/datacenter': workspace:* '@affine/i18n': workspace:* - '@blocksuite/blocks': 0.3.1-20230109032243-37ad3ba - '@blocksuite/editor': 0.3.1-20230109032243-37ad3ba + '@blocksuite/blocks': 0.4.0-20230111171650-bc63456 + '@blocksuite/editor': 0.4.0-20230111171650-bc63456 '@blocksuite/icons': ^2.0.2 - '@blocksuite/store': 0.3.1-20230109032243-37ad3ba + '@blocksuite/store': 0.4.0-20230111171650-bc63456 '@emotion/css': ^11.10.0 '@emotion/react': ^11.10.4 '@emotion/server': ^11.10.0 @@ -87,10 +87,10 @@ importers: dependencies: '@affine/datacenter': link:../data-center '@affine/i18n': link:../i18n - '@blocksuite/blocks': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 - '@blocksuite/editor': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 + '@blocksuite/blocks': 0.4.0-20230111171650-bc63456_yjs@13.5.44 + '@blocksuite/editor': 0.4.0-20230111171650-bc63456_yjs@13.5.44 '@blocksuite/icons': 2.0.4_w5j4k42lgipnm43s3brx6h3c34 - '@blocksuite/store': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 + '@blocksuite/store': 0.4.0-20230111171650-bc63456_yjs@13.5.44 '@emotion/css': 11.10.0 '@emotion/react': 11.10.4_w5j4k42lgipnm43s3brx6h3c34 '@emotion/server': 11.10.0_@emotion+css@11.10.0 @@ -129,8 +129,8 @@ importers: packages/data-center: specifiers: - '@blocksuite/blocks': 0.3.1-20230109032243-37ad3ba - '@blocksuite/store': 0.3.1-20230109032243-37ad3ba + '@blocksuite/blocks': 0.4.0-20230111171650-bc63456 + '@blocksuite/store': 0.4.0-20230111171650-bc63456 '@playwright/test': ^1.29.1 '@types/debug': ^4.1.7 debug: ^4.3.4 @@ -145,8 +145,8 @@ importers: typescript: ^4.8.4 y-protocols: ^1.0.5 dependencies: - '@blocksuite/blocks': 0.3.1-20230109032243-37ad3ba - '@blocksuite/store': 0.3.1-20230109032243-37ad3ba + '@blocksuite/blocks': 0.4.0-20230111171650-bc63456 + '@blocksuite/store': 0.4.0-20230111171650-bc63456 debug: 4.3.4 encoding: 0.1.13 firebase: 9.15.0_encoding@0.1.13 @@ -168,6 +168,7 @@ importers: i18next: ^21.9.1 prettier: ^2.7.1 react-i18next: ^11.18.4 + ts-node: ^10.9.1 typescript: ^4.8.4 dependencies: i18next: 21.10.0 @@ -175,6 +176,7 @@ importers: react-i18next: 11.18.6_i18next@21.10.0 devDependencies: '@types/prettier': 2.7.2 + ts-node: 10.9.1_typescript@4.9.3 typescript: 4.9.3 packages/logger: @@ -1499,16 +1501,17 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@blocksuite/blocks/0.3.1-20230109032243-37ad3ba: - resolution: {integrity: sha512-UTlbk0Is7TMRBbvUyM2nivbqM/TLwRj1qArMYbOmvDGUNYadWo68cTwv/Ej2WwiKn22q4/4JHryGsv3gTCRz1Q==} + /@blocksuite/blocks/0.4.0-20230111171650-bc63456: + resolution: {integrity: sha512-7fpb++pT9laoyLFWl4h09v7TUqZ/9udMrC1qxdX2XFgMPJjg3MJ9RG+Ud2s/zqZ1SkU1+0hMBvJP5ci9vV44gw==} dependencies: - '@blocksuite/phasor': 0.3.1-20230109032243-37ad3ba - '@blocksuite/store': 0.3.1-20230109032243-37ad3ba + '@blocksuite/global': 0.4.0-20230111171650-bc63456 + '@blocksuite/phasor': 0.4.0-20230111171650-bc63456 + '@blocksuite/store': 0.4.0-20230111171650-bc63456 '@tldraw/intersect': 1.8.0 autosize: 5.0.2 highlight.js: 11.7.0 hotkeys-js: 3.10.1 - lit: 2.5.0 + lit: 2.6.1 perfect-freehand: 1.2.0 quill: 1.3.7 quill-cursors: 4.0.0 @@ -1519,16 +1522,17 @@ packages: - yjs dev: false - /@blocksuite/blocks/0.3.1-20230109032243-37ad3ba_yjs@13.5.44: - resolution: {integrity: sha512-UTlbk0Is7TMRBbvUyM2nivbqM/TLwRj1qArMYbOmvDGUNYadWo68cTwv/Ej2WwiKn22q4/4JHryGsv3gTCRz1Q==} + /@blocksuite/blocks/0.4.0-20230111171650-bc63456_yjs@13.5.44: + resolution: {integrity: sha512-7fpb++pT9laoyLFWl4h09v7TUqZ/9udMrC1qxdX2XFgMPJjg3MJ9RG+Ud2s/zqZ1SkU1+0hMBvJP5ci9vV44gw==} dependencies: - '@blocksuite/phasor': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 - '@blocksuite/store': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 + '@blocksuite/global': 0.4.0-20230111171650-bc63456 + '@blocksuite/phasor': 0.4.0-20230111171650-bc63456_yjs@13.5.44 + '@blocksuite/store': 0.4.0-20230111171650-bc63456_yjs@13.5.44 '@tldraw/intersect': 1.8.0 autosize: 5.0.2 highlight.js: 11.7.0 hotkeys-js: 3.10.1 - lit: 2.5.0 + lit: 2.6.1 perfect-freehand: 1.2.0 quill: 1.3.7 quill-cursors: 4.0.0 @@ -1539,12 +1543,12 @@ packages: - yjs dev: false - /@blocksuite/editor/0.3.1-20230109032243-37ad3ba_yjs@13.5.44: - resolution: {integrity: sha512-bYbMn4EL/od+xP4K3u2kJT08kJBpK6H7b4cbRb9No3SUwgNHvvVNxia/QH1AQXyKaZQj/DHFgVxrw9GKo2GIPA==} + /@blocksuite/editor/0.4.0-20230111171650-bc63456_yjs@13.5.44: + resolution: {integrity: sha512-NbghDNWDGHXXfEqgnNhbw7zewGRyx9LUzOv1FmY2WVhzDu02MSrTWxMduChH1/tfLHRLe6jusmZKS9BNSUPynA==} dependencies: - '@blocksuite/blocks': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 - '@blocksuite/store': 0.3.1-20230109032243-37ad3ba_yjs@13.5.44 - lit: 2.5.0 + '@blocksuite/blocks': 0.4.0-20230111171650-bc63456_yjs@13.5.44 + '@blocksuite/store': 0.4.0-20230111171650-bc63456_yjs@13.5.44 + lit: 2.6.1 marked: 4.2.5 turndown: 7.1.1 transitivePeerDependencies: @@ -1554,6 +1558,10 @@ packages: - yjs dev: false + /@blocksuite/global/0.4.0-20230111171650-bc63456: + resolution: {integrity: sha512-/Kqg73vPLzxiWp6UqRmRoKfYmH4Sij3mU52RJf9adyywZOdM5e9E1gvPP+Eruz/x2jJ1uzR5/ivFqp5t688/tg==} + dev: false + /@blocksuite/icons/2.0.4_w5j4k42lgipnm43s3brx6h3c34: resolution: {integrity: sha512-Ewx30d3W6MXJGPXYvv48UpvAVfDB+gIVu90sHZX5curnSn+e1DdpCVfL0DeZA7Iyq6aLbxnKVzOAewlfoP8kDQ==} peerDependencies: @@ -1564,25 +1572,26 @@ packages: react: 18.2.0 dev: false - /@blocksuite/phasor/0.3.1-20230109032243-37ad3ba: - resolution: {integrity: sha512-mL1gSQ3rzrjdQSbWPtgyMXpbbl266UUjw26d0aIjkOh+iMMI6rWtmKWDoiDkO7tejIjwSNQ4w5zJOjJRIj+mSA==} + /@blocksuite/phasor/0.4.0-20230111171650-bc63456: + resolution: {integrity: sha512-fzmrG8KVJXkm5YyvHpPG1RRFhXjzuOey8OIoDu+/z87n9HJc4SkOd9JKH6wEL37F7P5ZoEM9Yl9YHxQjUc4/CA==} peerDependencies: yjs: ^13 dev: false - /@blocksuite/phasor/0.3.1-20230109032243-37ad3ba_yjs@13.5.44: - resolution: {integrity: sha512-mL1gSQ3rzrjdQSbWPtgyMXpbbl266UUjw26d0aIjkOh+iMMI6rWtmKWDoiDkO7tejIjwSNQ4w5zJOjJRIj+mSA==} + /@blocksuite/phasor/0.4.0-20230111171650-bc63456_yjs@13.5.44: + resolution: {integrity: sha512-fzmrG8KVJXkm5YyvHpPG1RRFhXjzuOey8OIoDu+/z87n9HJc4SkOd9JKH6wEL37F7P5ZoEM9Yl9YHxQjUc4/CA==} peerDependencies: yjs: ^13 dependencies: yjs: 13.5.44 dev: false - /@blocksuite/store/0.3.1-20230109032243-37ad3ba: - resolution: {integrity: sha512-zOUz19jfhuhsUkx9BGEQPZWbPyD/AgX0LB7ShVRdd3YM73x25hD6tPLLz1HEV2b69XokC0P9oSru4aNomm4jkg==} + /@blocksuite/store/0.4.0-20230111171650-bc63456: + resolution: {integrity: sha512-f/PKFPadA0KZq/wSLxxlS29c4SDuMfzHN1/gdrxFEIY0gC8caK2jZnT4K62R9Nquik/mXL60h8fBVAkQ0KbHzg==} peerDependencies: yjs: ^13 dependencies: + '@blocksuite/global': 0.4.0-20230111171650-bc63456 '@types/flexsearch': 0.7.3 '@types/quill': 1.3.10 buffer: 6.0.3 @@ -1598,11 +1607,12 @@ packages: - utf-8-validate dev: false - /@blocksuite/store/0.3.1-20230109032243-37ad3ba_yjs@13.5.44: - resolution: {integrity: sha512-zOUz19jfhuhsUkx9BGEQPZWbPyD/AgX0LB7ShVRdd3YM73x25hD6tPLLz1HEV2b69XokC0P9oSru4aNomm4jkg==} + /@blocksuite/store/0.4.0-20230111171650-bc63456_yjs@13.5.44: + resolution: {integrity: sha512-f/PKFPadA0KZq/wSLxxlS29c4SDuMfzHN1/gdrxFEIY0gC8caK2jZnT4K62R9Nquik/mXL60h8fBVAkQ0KbHzg==} peerDependencies: yjs: ^13 dependencies: + '@blocksuite/global': 0.4.0-20230111171650-bc63456 '@types/flexsearch': 0.7.3 '@types/quill': 1.3.10 buffer: 6.0.3 @@ -1803,6 +1813,13 @@ packages: prettier: 2.7.1 dev: true + /@cspotcode/source-map-support/0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: true + /@emotion/babel-plugin/11.10.2: resolution: {integrity: sha512-xNQ57njWTFVfPAc3cjfuaPdsgLp5QOSuRsj9MA6ndEhH/AzuZM86qIQzt6rq+aGBwj3n5/TkLmU5lhAfdRmogA==} peerDependencies: @@ -2802,6 +2819,17 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true + /@jridgewell/trace-mapping/0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + + /@lit-labs/ssr-dom-shim/1.0.0: + resolution: {integrity: sha512-ic93MBXfApIFTrup4a70M/+ddD8xdt2zxxj9sRwHQzhS9ag/syqkD8JPdTXsc1gUy2K8TTirhlCqyTEM/sifNw==} + dev: false + /@lit/reactive-element/1.4.1: resolution: {integrity: sha512-qDv4851VFSaBWzpS02cXHclo40jsbAjRXnebNXpm0uVg32kCneZPo9RYVQtrTNICtZ+1wAYHu1ZtxWSWMbKrBw==} dev: false @@ -2810,6 +2838,12 @@ packages: resolution: {integrity: sha512-fQh9FDK0LPTwDk+0HhSZEtb8K0LTN1wXerwpGrWA+a8tWulYRDLI4vQDWp4GOIsewn0572KYV/oZ3+492D7osA==} dev: false + /@lit/reactive-element/1.6.1: + resolution: {integrity: sha512-va15kYZr7KZNNPZdxONGQzpUr+4sxVu7V/VG7a8mRfPPXUyhEYj5RzXCQmGrlP3tAh0L3HHm5AjBMFYRqlM9SA==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.0.0 + dev: false + /@manypkg/find-root/1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: @@ -3617,6 +3651,22 @@ packages: resolution: {integrity: sha512-GiS5Df3CzXY/fPBFcM0CKFERZfI4Cg1X33VPZX+NLo7Fwm/h9zu/aU24N1mG75Q9LuMnwKm7woxKr8BiUXGYCg==} dev: false + /@tsconfig/node10/1.0.9: + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + dev: true + + /@tsconfig/node12/1.0.11: + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + dev: true + + /@tsconfig/node14/1.0.3: + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + dev: true + + /@tsconfig/node16/1.0.3: + resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} + dev: true + /@types/babel__core/7.1.20: resolution: {integrity: sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==} dependencies: @@ -4018,9 +4068,15 @@ packages: acorn: 8.8.0 dev: true + /acorn-walk/8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + /acorn/8.8.0: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} engines: {node: '>=0.4.0'} + hasBin: true dev: true /aggregate-error/3.1.0: @@ -4108,6 +4164,10 @@ packages: picomatch: 2.3.1 dev: true + /arg/4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true + /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: @@ -4709,6 +4769,10 @@ packages: yaml: 1.10.2 dev: false + /create-require/1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true + /cross-spawn/5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} dependencies: @@ -4902,6 +4966,11 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true + /diff/4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -7230,6 +7299,12 @@ packages: '@types/trusted-types': 2.0.2 dev: false + /lit-html/2.6.1: + resolution: {integrity: sha512-Z3iw+E+3KKFn9t2YKNjsXNEu/LRLI98mtH/C6lnFg7kvaqPIzPn124Yd4eT/43lyqrejpc5Wb6BHq3fdv4S8Rw==} + dependencies: + '@types/trusted-types': 2.0.2 + dev: false + /lit/2.4.0: resolution: {integrity: sha512-fdgzxEtLrZFQU/BqTtxFQCLwlZd9bdat+ltzSFjvWkZrs7eBmeX0L5MHUMb3kYIkuS8Xlfnii/iI5klirF8/Xg==} dependencies: @@ -7238,12 +7313,12 @@ packages: lit-html: 2.4.0 dev: false - /lit/2.5.0: - resolution: {integrity: sha512-DtnUP6vR3l4Q8nRPPNBD+UxbAhwJPeky+OVbi3pdgMqm0g57xFSl1Sj64D1rIB+nVNdiVVg8YxB0hqKjvdadZA==} + /lit/2.6.1: + resolution: {integrity: sha512-DT87LD64f8acR7uVp7kZfhLRrHkfC/N4BVzAtnw9Yg8087mbBJ//qedwdwX0kzDbxgPccWRW6mFwGbRQIxy0pw==} dependencies: - '@lit/reactive-element': 1.5.0 + '@lit/reactive-element': 1.6.1 lit-element: 3.2.2 - lit-html: 2.5.0 + lit-html: 2.6.1 dev: false /load-yaml-file/0.2.0: @@ -7363,6 +7438,10 @@ packages: semver: 6.3.0 dev: true + /make-error/1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + /makeerror/1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} dependencies: @@ -9075,6 +9154,36 @@ packages: engines: {node: '>=8'} dev: true + /ts-node/10.9.1_typescript@4.9.3: + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + acorn: 8.8.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: @@ -9325,6 +9434,10 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: false + /v8-compile-cache-lib/3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + dev: true + /v8-compile-cache/2.3.0: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true @@ -9798,6 +9911,11 @@ packages: lib0: 0.2.52 dev: false + /yn/3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: true + /yocto-queue/0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} From 03ff4c3e3db4efa46c868763b191df7bac112020 Mon Sep 17 00:00:00 2001 From: zuomeng wang Date: Fri, 13 Jan 2023 15:09:56 +0800 Subject: [PATCH 222/298] fix: upload origin doc when enable cloud (#729) --- .../data-center/src/provider/affine/affine.ts | 37 +++++++++++-------- .../src/provider/affine/apis/workspace.ts | 4 +- .../data-center/src/provider/affine/utils.ts | 34 ----------------- 3 files changed, 24 insertions(+), 51 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index c8078c4cdc..793d7e7cd9 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -13,11 +13,7 @@ import { getApis, Workspace } from './apis/index.js'; import type { Apis, WorkspaceDetail, Callback } from './apis'; import { token } from './apis/token.js'; import { WebsocketClient } from './channel'; -import { - loadWorkspaceUnit, - createWorkspaceUnit, - syncToCloud, -} from './utils.js'; +import { loadWorkspaceUnit, createWorkspaceUnit } from './utils.js'; import { WorkspaceUnit } from '../../workspace-unit.js'; import { createBlocksuiteWorkspace, applyUpdate } from '../../utils/index.js'; import type { SyncMode } from '../../workspace-unit'; @@ -316,7 +312,22 @@ export class AffineProvider extends BaseProvider { public override async createWorkspace( meta: CreateWorkspaceInfoParams ): Promise { - const { id } = await this._apis.createWorkspace(meta); + const workspaceUnitForUpload = await createWorkspaceUnit({ + id: '', + name: meta.name, + avatar: undefined, + owner: await this.getUserInfo(), + published: false, + memberCount: 1, + provider: this.id, + syncMode: 'core', + }); + const { id } = await this._apis.createWorkspace( + new Blob([ + encodeStateAsUpdate(workspaceUnitForUpload.blocksuiteWorkspace!.doc) + .buffer, + ]) + ); const workspaceUnit = await createWorkspaceUnit({ id, @@ -329,10 +340,6 @@ export class AffineProvider extends BaseProvider { syncMode: 'core', }); - await syncToCloud( - workspaceUnit.blocksuiteWorkspace!, - this._apis.token.refresh - ); this._workspaces.add(workspaceUnit); return workspaceUnit; @@ -360,9 +367,11 @@ export class AffineProvider extends BaseProvider { public override async extendWorkspace( workspaceUnit: WorkspaceUnit ): Promise { - const { id } = await this._apis.createWorkspace({ - name: workspaceUnit.name, - }); + const { id } = await this._apis.createWorkspace( + new Blob([ + encodeStateAsUpdate(workspaceUnit.blocksuiteWorkspace!.doc).buffer, + ]) + ); const newWorkspaceUnit = new WorkspaceUnit({ id, name: workspaceUnit.name, @@ -381,8 +390,6 @@ export class AffineProvider extends BaseProvider { encodeStateAsUpdate(workspaceUnit.blocksuiteWorkspace.doc) ); - await syncToCloud(blocksuiteWorkspace, this._apis.token.refresh); - newWorkspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace); this._workspaces.add(newWorkspaceUnit); diff --git a/packages/data-center/src/provider/affine/apis/workspace.ts b/packages/data-center/src/provider/affine/apis/workspace.ts index 106dc72b04..584db159fe 100644 --- a/packages/data-center/src/provider/affine/apis/workspace.ts +++ b/packages/data-center/src/provider/affine/apis/workspace.ts @@ -112,10 +112,10 @@ export interface CreateWorkspaceParams { } export async function createWorkspace( - params: CreateWorkspaceParams + encodedYDoc: Blob ): Promise<{ id: string }> { try { - return client.post('api/workspace', { json: params }).json(); + return client.post('api/workspace', { body: encodedYDoc }).json(); } catch (error) { sendMessage(messageCode.createWorkspaceFailed); throw new RequestError('create workspace failed', error); diff --git a/packages/data-center/src/provider/affine/utils.ts b/packages/data-center/src/provider/affine/utils.ts index 93c2f56007..4bb401fbf2 100644 --- a/packages/data-center/src/provider/affine/utils.ts +++ b/packages/data-center/src/provider/affine/utils.ts @@ -1,10 +1,7 @@ -import assert from 'assert'; -import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; import { WorkspaceUnit } from '../../workspace-unit.js'; import type { WorkspaceUnitCtorParams } from '../../workspace-unit'; import { createBlocksuiteWorkspace } from '../../utils/index.js'; import type { Apis } from './apis'; -import { WebsocketProvider } from './sync.js'; import { setDefaultAvatar } from '../utils.js'; import { applyUpdate } from '../../utils/index.js'; @@ -42,37 +39,6 @@ export const loadWorkspaceUnit = async ( return workspaceUnit; }; -export const syncToCloud = async ( - blocksuiteWorkspace: BlocksuiteWorkspace, - refreshToken: string -) => { - const workspaceId = blocksuiteWorkspace.room; - assert(workspaceId, 'Blocksuite workspace without room(workspaceId).'); - - const wsUrl = `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${ - window.location.host - }/api/sync/`; - - const ws = new WebsocketProvider( - wsUrl, - workspaceId, - blocksuiteWorkspace.doc, - { - params: { token: refreshToken }, - } - ); - - await new Promise((resolve, reject) => { - ws.once('synced', () => { - // FIXME: we don't when send local data to cloud successfully, so hack to wait 1s. - // Server will support this by add a new api. - setTimeout(resolve, 1000); - }); - ws.once('lost-connection', () => reject()); - ws.once('connection-error', () => reject()); - }); -}; - export const createWorkspaceUnit = async (params: WorkspaceUnitCtorParams) => { const workspaceUnit = new WorkspaceUnit(params); From 7fb5aae8b5d04d2a3cda7bb29f9fc445b62769e7 Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Fri, 13 Jan 2023 15:25:33 +0800 Subject: [PATCH 223/298] fix: deepscan error and warning (#728) --- .../app/src/components/quick-search/index.tsx | 2 +- .../workspace-setting/PublishPage.tsx | 2 +- .../components/workspace-setting/SyncPage.tsx | 2 +- .../workspace-setting/member/MembersPage.tsx | 2 +- .../SelectorPopperContent.tsx | 183 ------------------ .../CreateWorkspaceItem.tsx | 39 ---- .../CreateWorkspaceItem/index.ts | 1 - .../workspace-create/WorkspaceCreate.tsx | 123 ------------ .../workspace-create/index.ts | 1 - .../workspace-create/style.ts | 63 ------ .../WorkspaceItem/PrivateWorkspaceItem.tsx | 63 ------ .../WorkspaceItem/FooterSetting.tsx | 32 --- .../WorkspaceItem/FooterUsers.tsx | 29 --- .../WorkspaceItem/WorkspaceItem.tsx | 100 ---------- .../WorkspaceItem/WorkspaceItem/index.ts | 1 - .../WorkspaceSelector/WorkspaceItem/index.ts | 3 - packages/app/src/hooks/use-members.ts | 2 +- .../app/src/hooks/use-workspace-helper.ts | 5 +- .../providers/app-state-provider/Provider.tsx | 4 +- .../data-center/src/provider/affine/affine.ts | 2 - packages/data-center/src/workspace-unit.ts | 2 +- 21 files changed, 10 insertions(+), 651 deletions(-) delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/CreateWorkspaceItem.tsx delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/index.ts delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/WorkspaceCreate.tsx delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/index.ts delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/style.ts delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterSetting.tsx delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterUsers.tsx delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx delete mode 100644 packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/index.ts diff --git a/packages/app/src/components/quick-search/index.tsx b/packages/app/src/components/quick-search/index.tsx index 4000ce7756..9d6e477968 100644 --- a/packages/app/src/components/quick-search/index.tsx +++ b/packages/app/src/components/quick-search/index.tsx @@ -94,7 +94,7 @@ export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => { setShowCreatePage={setShowCreatePage} /> - {currentWorkspace?.isPublish ? ( + {currentWorkspace?.published ? ( <> ) : showCreatePage ? ( <> diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx index 86fbf399f9..d61bf4fcf9 100644 --- a/packages/app/src/components/workspace-setting/PublishPage.tsx +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -34,7 +34,7 @@ export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => { {workspace.provider === 'affine' ? (
    - {workspace?.published ? ( + {workspace.published ? ( <> {t('Publishing')} diff --git a/packages/app/src/components/workspace-setting/SyncPage.tsx b/packages/app/src/components/workspace-setting/SyncPage.tsx index fe677b33a1..7d56d0233c 100644 --- a/packages/app/src/components/workspace-setting/SyncPage.tsx +++ b/packages/app/src/components/workspace-setting/SyncPage.tsx @@ -15,7 +15,7 @@ export const SyncPage = ({ workspace }: { workspace: WorkspaceUnit }) => { return (
    - {workspace?.provider === 'local' ? ( + {workspace.provider === 'local' ? ( <> {t('Sync Description', { diff --git a/packages/app/src/components/workspace-setting/member/MembersPage.tsx b/packages/app/src/components/workspace-setting/member/MembersPage.tsx index 4f96371ba0..dc6a7132f3 100644 --- a/packages/app/src/components/workspace-setting/member/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/member/MembersPage.tsx @@ -48,7 +48,7 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { {loaded && members.length === 0 && ( )} - {loaded && members.length && ( + {loaded && members.length > 0 && ( <> diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx deleted file mode 100644 index 287523689e..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx +++ /dev/null @@ -1,183 +0,0 @@ -// import { InformationIcon, LogOutIcon } from '@blocksuite/icons'; -// import { styled } from '@/styles'; -// import { Divider } from '@/ui/divider'; -// import { useAppState } from '@/providers/app-state-provider'; -// import { SelectorPopperContainer } from './styles'; -// import { -// PrivateWorkspaceItem, -// WorkspaceItem, -// CreateWorkspaceItem, -// ListItem, -// LoginItem, -// } from './WorkspaceItem'; -// import { WorkspaceSetting } from '@/components/workspace-setting'; -// import { useCallback, useEffect, useState } from 'react'; -// import { WorkspaceInfo } from '@affine/datacenter'; -// import { useModal } from '@/providers/GlobalModalProvider'; - -// export type WorkspaceDetails = Record< -// string, -// { memberCount: number; owner: { id: string; name: string } } -// >; - -// type SelectorPopperContentProps = { -// isShow: boolean; -// }; - -// export const SelectorPopperContent = ({ -// isShow, -// }: SelectorPopperContentProps) => { -// const { user, workspacesMeta, refreshWorkspacesMeta } = useAppState(); -// const [settingWorkspaceId, setSettingWorkspaceId] = useState( -// null -// ); -// const [workSpaceDetails, setWorkSpaceDetails] = useState( -// {} -// ); -// const { triggerContactModal } = useModal(); - -// const handleClickSettingWorkspace = (workspaceId: string) => { -// setSettingWorkspaceId(workspaceId); -// }; -// const handleCloseWorkSpace = () => { -// setSettingWorkspaceId(null); -// }; -// const settingWorkspace = settingWorkspaceId -// ? workspacesMeta.find(workspace => workspace.id === settingWorkspaceId) -// : undefined; - -// const refreshDetails = useCallback(async () => { -// const workspaceDetailList = await Promise.all( -// workspacesMeta.map(async ({ id, type }) => { -// if (user) { -// if (type === WorkspaceType.Private) { -// return { id, member_count: 1, owner: user }; -// } else { -// // const dc = await getDataCenter(); -// // const data = await dc.apis.getWorkspaceDetail({ id }); -// // return { id, ...data } || { id, member_count: 0, owner: user }; -// } -// } -// }) -// ); -// const workSpaceDetails: WorkspaceDetails = {}; -// workspaceDetailList.forEach(details => { -// if (details) { -// const { id, member_count, owner } = details; -// if (!owner) return; -// workSpaceDetails[id] = { -// memberCount: member_count || 1, -// owner: { -// id: owner.id, -// name: owner.name, -// }, -// }; -// } -// }); -// setWorkSpaceDetails(workSpaceDetails); -// }, [user, workspacesMeta]); - -// useEffect(() => { -// if (isShow) { -// setSettingWorkspaceId(null); -// refreshWorkspacesMeta(); -// refreshDetails(); -// } -// // eslint-disable-next-line react-hooks/exhaustive-deps -// }, [isShow]); - -// return !user ? ( -// -// -// -// } -// name="About AFFiNE" -// onClick={() => triggerContactModal()} -// /> -// -// ) : ( -// -// workspace.type === WorkspaceType.Private -// )?.id -// } -// /> -// -// Workspace -// -// {workspacesMeta.map(workspace => { -// return workspace.type !== WorkspaceType.Private ? ( -// -// ) : null; -// })} -// -// -// {settingWorkspace ? ( -// -// ) : null} -// -// } -// name="About AFFiNE" -// onClick={() => triggerContactModal()} -// /> -// } -// name="Sign out" -// onClick={() => { -// console.log('Sign out'); -// // FIXME: remove token from local storage and reload the page -// localStorage.removeItem('affine_token'); -// window.location.reload(); -// }} -// /> -// -// ); -// }; - -// const StyledDivider = styled(Divider)({ -// margin: '8px 12px', -// width: 'calc(100% - 24px)', -// }); - -// const WorkspaceGroupTitle = styled('div')(({ theme }) => { -// return { -// color: theme.colors.iconColor, -// fontSize: theme.font.sm, -// lineHeight: '30px', -// height: '30px', -// padding: '0 12px', -// }; -// }); - -// const WorkspaceWrapper = styled('div')(() => { -// return { -// maxHeight: '200px', -// overflow: 'auto', -// }; -// }); -export const test = () => { - return <>; -}; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/CreateWorkspaceItem.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/CreateWorkspaceItem.tsx deleted file mode 100644 index ccb6526691..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/CreateWorkspaceItem.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { useState } from 'react'; -import { AddIcon } from '@blocksuite/icons'; -import { styled } from '@/styles'; -import { - WorkspaceItemAvatar, - WorkspaceItemWrapper, - WorkspaceItemContent, -} from '../styles'; -import { WorkspaceCreate } from './workspace-create'; - -const name = 'Create new Workspace'; - -export const CreateWorkspaceItem = () => { - const [open, setOpen] = useState(false); - return ( - <> - setOpen(true)}> - - - - - {name} - - - setOpen(false)} /> - - ); -}; - -const Name = styled('div')(({ theme }) => { - return { - color: theme.colors.quoteColor, - fontSize: theme.font.base, - fontWeight: 400, - overflow: 'hidden', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - }; -}); diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/index.ts b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/index.ts deleted file mode 100644 index 8db80b1dc7..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './CreateWorkspaceItem'; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/WorkspaceCreate.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/WorkspaceCreate.tsx deleted file mode 100644 index c71ee76d14..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/WorkspaceCreate.tsx +++ /dev/null @@ -1,123 +0,0 @@ -// import { getDataCenter } from '@affine/datacenter'; -import Modal from '@/ui/modal'; -import Input from '@/ui/input'; -import { - StyledModalHeader, - StyledTextContent, - StyledModalWrapper, - StyledInputContent, - StyledButtonContent, - StyledButton, -} from './style'; -import { useState } from 'react'; -import { ModalCloseButton } from '@/ui/modal'; -// import router from 'next/router'; -// import { useAppState } from '@/providers/app-state-provider'; - -interface WorkspaceCreateProps { - open: boolean; - onClose: () => void; -} - -const DefaultHeadImgColors = [ - ['#C6F2F3', '#0C6066'], - ['#FFF5AB', '#896406'], - ['#FFCCA7', '#8F4500'], - ['#FFCECE', '#AF1212'], - ['#E3DEFF', '#511AAB'], -]; - -export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => { - const [workspaceName, setWorkspaceId] = useState(''); - const [creating, setCreating] = useState(false); - // const { refreshWorkspacesMeta } = useAppState(); - const handlerInputChange = (workspaceName: string) => { - setWorkspaceId(workspaceName); - }; - const createDefaultHeadImg = (workspaceName: string) => { - const canvas = document.createElement('canvas'); - canvas.height = 100; - canvas.width = 100; - const ctx = canvas.getContext('2d'); - return new Promise((resolve, reject) => { - if (ctx) { - const randomNumber = Math.floor(Math.random() * 5); - const randomColor = DefaultHeadImgColors[randomNumber]; - ctx.fillStyle = randomColor[0]; - ctx.fillRect(0, 0, 100, 100); - ctx.font = "600 50px 'PingFang SC', 'Microsoft Yahei'"; - ctx.fillStyle = randomColor[1]; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillText(workspaceName[0], 50, 50); - canvas.toBlob(blob => { - if (blob) { - // const blobId = getDataCenter().then(dc => - // dc.apis.uploadBlob({ blob }) - // ); - // resolve(blobId); - } else { - reject(); - } - }, 'image/png'); - } else { - reject(); - } - }); - }; - const handleCreateWorkspace = async () => { - setCreating(true); - const blobId = await createDefaultHeadImg(workspaceName).catch(() => { - setCreating(false); - }); - if (blobId) { - // getDataCenter() - // .then(dc => - // dc.apis.createWorkspace({ name: workspaceName, avatar: blobId }) - // ) - // .then(async data => { - // await refreshWorkspacesMeta(); - // // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // // @ts-ignore - // router.push(`/workspace/${data.id}`); - // onClose(); - // }) - // .catch(err => { - // console.log(err, 'err'); - // }) - // .finally(() => { - // setCreating(false); - // }); - } - }; - return ( - - - - Create new Workspace - - Workspaces are shared environments where teams can collaborate. After - creating a Workspace, you can invite others to join. - - - - - - - Create - - - - - ); -}; - -export default WorkspaceCreate; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/index.ts b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/index.ts deleted file mode 100644 index 85746bc70d..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './WorkspaceCreate'; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/style.ts b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/style.ts deleted file mode 100644 index 4c5162a94f..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/CreateWorkspaceItem/workspace-create/style.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { styled } from '@/styles'; -import { Button } from '@/ui/button'; - -export const StyledModalWrapper = styled('div')(({ theme }) => { - return { - position: 'relative', - padding: '0px', - width: '460px', - background: theme.colors.popoverBackground, - borderRadius: '12px', - }; -}); - -export const StyledModalHeader = styled('div')(({ theme }) => { - return { - margin: '44px 0px 12px 0px', - width: '460px', - fontWeight: '600', - fontSize: '20px;', - textAlign: 'center', - color: theme.colors.popoverColor, - }; -}); - -// export const StyledModalContent = styled('div')(({ theme }) => {}); - -export const StyledTextContent = styled('div')(() => { - return { - margin: 'auto', - width: '425px', - fontFamily: 'Avenir Next', - fontStyle: 'normal', - fontWeight: '400', - fontSize: '18px', - lineHeight: '26px', - textAlign: 'center', - }; -}); - -export const StyledInputContent = styled('div')(() => { - return { - display: 'flex', - flexDirection: 'row', - justifyContent: 'center', - margin: '40px 0 24px 0', - }; -}); - -export const StyledButtonContent = styled('div')(() => { - return { - display: 'flex', - flexDirection: 'row', - justifyContent: 'center', - margin: '0px 0 32px 0', - }; -}); - -export const StyledButton = styled(Button)(() => { - return { - width: '260px', - justifyContent: 'center', - }; -}); diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx deleted file mode 100644 index b9d9522a91..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/PrivateWorkspaceItem.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// import { styled } from '@/styles'; -// import { useAppState } from '@/providers/app-state-provider'; -// import { -// WorkspaceItemAvatar, -// PrivateWorkspaceWrapper, -// WorkspaceItemContent, -// } from './styles'; -// import { useRouter } from 'next/router'; - -// type PrivateWorkspaceItemProps = { -// privateWorkspaceId?: string; -// }; - -// export const PrivateWorkspaceItem = ({ -// privateWorkspaceId, -// }: PrivateWorkspaceItemProps) => { -// const { user } = useAppState(); -// const router = useRouter(); -// const handleClick = () => { -// if (privateWorkspaceId) { -// router.push(`/workspace/${privateWorkspaceId}`); -// } -// }; -// if (user) { -// const Username = user.name; -// return ( -// -// -// {Username} -// -// -// {Username} -// {user.email} -// -// -// ); -// } -// return null; -// }; - -// const Name = styled('div')(({ theme }) => { -// return { -// color: theme.colors.quoteColor, -// fontSize: theme.font.base, -// fontWeight: 500, -// overflow: 'hidden', -// textOverflow: 'ellipsis', -// whiteSpace: 'nowrap', -// }; -// }); - -// const Email = styled('div')(({ theme }) => { -// return { -// color: theme.colors.iconColor, -// fontSize: theme.font.sm, -// overflow: 'hidden', -// textOverflow: 'ellipsis', -// whiteSpace: 'nowrap', -// }; -// }); -export const test = () => { - return <>; -}; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterSetting.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterSetting.tsx deleted file mode 100644 index eb761058b6..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterSetting.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { SettingsIcon } from '@blocksuite/icons'; -import { styled } from '@/styles'; -import { IconButton } from '@/ui/button'; -import { MouseEventHandler } from 'react'; - -type SettingProps = { - onClick?: () => void; -}; - -export const FooterSetting = ({ onClick }: SettingProps) => { - const handleClick: MouseEventHandler = e => { - e.stopPropagation(); - onClick && onClick(); - }; - return ( - { - e.stopPropagation(); - handleClick(e); - }} - > - - - ); -}; - -const Wrapper = styled(IconButton)(() => { - return { - fontSize: '20px', - }; -}); diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterUsers.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterUsers.tsx deleted file mode 100644 index c241555877..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/FooterUsers.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { UsersIcon } from '@blocksuite/icons'; -import { styled } from '@/styles'; -import { IconButton } from '@/ui/button'; - -type FooterUsersProps = { - memberCount: number; -}; - -export const FooterUsers = ({ memberCount = 1 }: FooterUsersProps) => { - return ( - - <> - - {memberCount > 99 ? '99+' : memberCount} - - - ); -}; - -const Wrapper = styled(IconButton)({ - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - fontSize: '16px', -}); - -const Tip = styled('span')({ - fontSize: '12px', -}); diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx deleted file mode 100644 index 3833f1b516..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx +++ /dev/null @@ -1,100 +0,0 @@ -// import { useRouter } from 'next/router'; -// import { styled } from '@/styles'; -// import { -// WorkspaceItemAvatar, -// WorkspaceItemWrapper, -// WorkspaceItemContent, -// } from '../styles'; -// import { FooterSetting } from './FooterSetting'; -// import { FooterUsers } from './FooterUsers'; -// import { WorkspaceType } from '@affine/datacenter'; -// import { useAppState } from '@/providers/app-state-provider'; - -// interface WorkspaceItemProps { -// id: string; -// name: string; -// icon: string; -// type: WorkspaceType; -// memberCount: number; -// onClickSetting?: (workspaceId: string) => void; -// } - -// export const WorkspaceItem = ({ -// id, -// name, -// icon, -// type, -// onClickSetting, -// memberCount, -// }: WorkspaceItemProps) => { -// const router = useRouter(); - -// const { currentWorkspaceId } = useAppState(); - -// const handleClickSetting = async () => { -// onClickSetting && onClickSetting(id); -// }; - -// return ( -// { -// router.push(`/workspace/${id}`); -// }} -// canSet={ -// type !== WorkspaceType.Private && currentWorkspaceId === String(id) -// } -// > -// -// {name.charAt(0)} -// -// -// {name} -// -//
    -// -// -//
    -//
    -// ); -// }; - -// const Name = styled('div')(({ theme }) => { -// return { -// color: theme.colors.quoteColor, -// fontSize: theme.font.sm, -// fontWeight: 400, -// overflow: 'hidden', -// textOverflow: 'ellipsis', -// whiteSpace: 'nowrap', -// }; -// }); - -// const StyledWrapper = styled(WorkspaceItemWrapper)<{ canSet: boolean }>( -// ({ canSet }) => { -// return { -// '& .footer-setting': { -// display: 'none', -// }, -// ':hover .footer-users': { -// display: canSet ? 'none' : '', -// }, -// ':hover .footer-setting': { -// display: canSet ? 'block' : 'none', -// }, -// }; -// } -// ); - -// const Footer = styled('div')({ -// width: '42px', -// flex: '0 42px', -// fontSize: '20px', -// display: 'flex', -// alignItems: 'center', -// justifyContent: 'center', -// marginLeft: '12px', -// }); - -export const test = () => { - return <>; -}; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/index.ts b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/index.ts deleted file mode 100644 index 60080d5a77..0000000000 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './WorkspaceItem'; diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/index.ts b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/index.ts index 2c8649631c..59d6e170a4 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/index.ts +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/index.ts @@ -1,5 +1,2 @@ -export * from './PrivateWorkspaceItem'; -// export * from './WorkspaceItem'; -export * from './CreateWorkspaceItem'; export * from './ListItem'; export * from './LoginItem'; diff --git a/packages/app/src/hooks/use-members.ts b/packages/app/src/hooks/use-members.ts index 3011c94f83..a0e7cd8156 100644 --- a/packages/app/src/hooks/use-members.ts +++ b/packages/app/src/hooks/use-members.ts @@ -22,7 +22,7 @@ export const useMembers = () => { const inviteMember = async (email: string) => { currentWorkspace && dataCenter && - (await dataCenter.inviteMember(currentWorkspace?.id, email)); + (await dataCenter.inviteMember(currentWorkspace.id, email)); }; const removeMember = async (permissionId: number) => { diff --git a/packages/app/src/hooks/use-workspace-helper.ts b/packages/app/src/hooks/use-workspace-helper.ts index 480ba409c1..64387a9848 100644 --- a/packages/app/src/hooks/use-workspace-helper.ts +++ b/packages/app/src/hooks/use-workspace-helper.ts @@ -57,11 +57,10 @@ export const useWorkspaceHelper = () => { }; const deleteWorkSpace = async () => { - currentWorkspace && - (await dataCenter.deleteWorkspace(currentWorkspace?.id)); + currentWorkspace && (await dataCenter.deleteWorkspace(currentWorkspace.id)); }; const leaveWorkSpace = async () => { - currentWorkspace && (await dataCenter.leaveWorkspace(currentWorkspace?.id)); + currentWorkspace && (await dataCenter.leaveWorkspace(currentWorkspace.id)); }; const acceptInvite = async (inviteCode: string) => { diff --git a/packages/app/src/providers/app-state-provider/Provider.tsx b/packages/app/src/providers/app-state-provider/Provider.tsx index 3e864b76d2..77b50384fa 100644 --- a/packages/app/src/providers/app-state-provider/Provider.tsx +++ b/packages/app/src/providers/app-state-provider/Provider.tsx @@ -105,10 +105,10 @@ export const AppStateProvider = ({ // isOwner is useful only in the cloud isOwner = true; } else { - isOwner = workspace?.owner && user?.id === workspace?.owner?.id; + isOwner = workspace.owner && user?.id === workspace.owner.id; } const pageList = - (workspace?.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? []; + (workspace.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? []; setAppState({ ...appState, currentWorkspace: workspace, diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 793d7e7cd9..b71019b91a 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -244,9 +244,7 @@ export class AffineProvider extends BaseProvider { } public override async getUserInfo(): Promise { - await this.init(); const user = this._apis.token.user; - await this.init; return user ? { id: user.id, diff --git a/packages/data-center/src/workspace-unit.ts b/packages/data-center/src/workspace-unit.ts index 5bc4bf8aef..1560ec7bf6 100644 --- a/packages/data-center/src/workspace-unit.ts +++ b/packages/data-center/src/workspace-unit.ts @@ -52,7 +52,7 @@ export class WorkspaceUnit { } setBlocksuiteWorkspace(blocksuiteWorkspace: BlocksuiteWorkspace | null) { - if (blocksuiteWorkspace && blocksuiteWorkspace?.room !== this.id) { + if (blocksuiteWorkspace && blocksuiteWorkspace.room !== this.id) { throw new Error('Workspace id inconsistent.'); } this._blocksuiteWorkspace = blocksuiteWorkspace; From ba9a57d4ae1f47a3ad1c231ea15b646594332f92 Mon Sep 17 00:00:00 2001 From: zuomeng wang Date: Fri, 13 Jan 2023 15:33:42 +0800 Subject: [PATCH 224/298] fix: error TS2742: The inferred type of 'bareClient' cannot be name (#731) --- packages/data-center/src/provider/affine/apis/request.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/data-center/src/provider/affine/apis/request.ts b/packages/data-center/src/provider/affine/apis/request.ts index 2520b1d535..c5bdf7e300 100644 --- a/packages/data-center/src/provider/affine/apis/request.ts +++ b/packages/data-center/src/provider/affine/apis/request.ts @@ -2,11 +2,13 @@ import ky from 'ky-universal'; import { MessageCenter } from '../../../message/index.js'; import { token } from './token.js'; +type KyInstance = typeof ky; + const messageCenter = MessageCenter.getInstance(); const _sendMessage = messageCenter.getMessageSender('affine'); -export const bareClient = ky.extend({ +export const bareClient: KyInstance = ky.extend({ prefixUrl: 'http://localhost:8080', retry: 1, hooks: { @@ -26,7 +28,7 @@ export const bareClient = ky.extend({ }, }); -export const client = bareClient.extend({ +export const client: KyInstance = bareClient.extend({ hooks: { beforeRequest: [ async request => { From 21d24ad54284bb4d8aac969cd75f3a5450703c69 Mon Sep 17 00:00:00 2001 From: zuomeng wang Date: Fri, 13 Jan 2023 15:54:21 +0800 Subject: [PATCH 225/298] fix: deepscan error (#733) --- packages/app/src/components/editor/index.tsx | 2 +- .../src/pages/public-workspace/[workspaceId]/[pageId].tsx | 2 +- packages/app/src/providers/app-state-provider/Provider.tsx | 7 ++++--- packages/data-center/src/datacenter.ts | 4 +++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/app/src/components/editor/index.tsx b/packages/app/src/components/editor/index.tsx index 3d62a9323a..e7d962e8dd 100644 --- a/packages/app/src/components/editor/index.tsx +++ b/packages/app/src/components/editor/index.tsx @@ -60,7 +60,7 @@ export const Editor = ({ page, workspace, setEditor }: Props) => { } setEditor(editor); - document.title = page?.meta.title || 'Untitled'; + document.title = page.meta.title || 'Untitled'; return ret; }, [workspace, page, setEditor]); diff --git a/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx b/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx index 734e627f3e..a3629580b5 100644 --- a/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx +++ b/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx @@ -25,7 +25,7 @@ const Page: NextPageWithLayout = () => { p => p.id === router.query.pageId ) ) { - const page = data.blocksuiteWorkspace?.getPage( + const page = data.blocksuiteWorkspace.getPage( router.query.pageId as string ); page && setPage(page); diff --git a/packages/app/src/providers/app-state-provider/Provider.tsx b/packages/app/src/providers/app-state-provider/Provider.tsx index 77b50384fa..59cfee3344 100644 --- a/packages/app/src/providers/app-state-provider/Provider.tsx +++ b/packages/app/src/providers/app-state-provider/Provider.tsx @@ -101,14 +101,15 @@ export const AppStateProvider = ({ } const workspace = (await dataCenter.loadWorkspace(workspaceId)) ?? null; let isOwner; - if (workspace.provider === 'local') { + if (workspace?.provider === 'local') { // isOwner is useful only in the cloud isOwner = true; } else { - isOwner = workspace.owner && user?.id === workspace.owner.id; + // We must ensure workspace.owner exists, then ensure id same. + isOwner = workspace?.owner && user?.id === workspace.owner.id; } const pageList = - (workspace.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? []; + (workspace?.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? []; setAppState({ ...appState, currentWorkspace: workspace, diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index e8876ac2d6..1488d8b84d 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -150,7 +150,9 @@ export class DataCenter { * @param {string} workspaceId workspace id * @returns {Promise} */ - public async loadWorkspace(workspaceId: string) { + public async loadWorkspace( + workspaceId: string + ): Promise { const workspaceUnit = this._workspaceUnitCollection.find(workspaceId); assert(workspaceUnit, 'Workspace not found'); const currentProvider = this.providerMap.get(workspaceUnit.provider); From 2c1eee11948aae093b8d51fcf9e0fde56b1437c2 Mon Sep 17 00:00:00 2001 From: zuomeng wang Date: Fri, 13 Jan 2023 17:10:08 +0800 Subject: [PATCH 226/298] fix: websocket should be link to blocksuiteWorkspace, not workspace id (#735) --- .../data-center/src/provider/affine/affine.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index b71019b91a..a07340f08a 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -37,7 +37,7 @@ const { export class AffineProvider extends BaseProvider { public id = 'affine'; private _onTokenRefresh?: Callback = undefined; - private _wsMap: Map = new Map(); + private _wsMap: Map = new Map(); private _apis: Apis; private _channel?: WebsocketClient; // private _idbMap: Map = new Map(); @@ -147,7 +147,7 @@ export class AffineProvider extends BaseProvider { const { doc, room } = workspace; assert(room); assert(doc); - let ws = this._wsMap.get(room); + let ws = this._wsMap.get(workspace); if (!ws) { const wsUrl = `${ window.location.protocol === 'https:' ? 'wss' : 'ws' @@ -155,7 +155,7 @@ export class AffineProvider extends BaseProvider { ws = new WebsocketProvider(wsUrl, room, doc, { params: { token: this._apis.token.refresh }, }); - this._wsMap.set(room, ws); + this._wsMap.set(workspace, ws); } return ws; } @@ -182,8 +182,8 @@ export class AffineProvider extends BaseProvider { this.linkLocal(workspace); const ws = this._getWebsocketProvider(workspace); // close all websocket links - Array.from(this._wsMap.entries()).forEach(([id, ws]) => { - if (id !== room) { + Array.from(this._wsMap.entries()).forEach(([blocksuiteWorkspace, ws]) => { + if (blocksuiteWorkspace !== workspace) { ws.disconnect(); } }); @@ -279,7 +279,13 @@ export class AffineProvider extends BaseProvider { public override async closeWorkspace(id: string) { // const idb = this._idbMap.get(id); // idb?.destroy(); - const ws = this._wsMap.get(id); + const workspaceUnit = this._workspaces.get(id); + const ws = workspaceUnit?.blocksuiteWorkspace + ? this._wsMap.get(workspaceUnit?.blocksuiteWorkspace) + : null; + if (!ws) { + console.error('close workspace websocket which not exist.'); + } ws?.disconnect(); } From c95667eafbe7f92181281025aad5abac9bebce2b Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Fri, 13 Jan 2023 17:16:15 +0800 Subject: [PATCH 227/298] fix: fix reconnect logic (#730) --- .../src/provider/affine/channel.ts | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/data-center/src/provider/affine/channel.ts b/packages/data-center/src/provider/affine/channel.ts index 1503a8b450..da9e81c35e 100644 --- a/packages/data-center/src/provider/affine/channel.ts +++ b/packages/data-center/src/provider/affine/channel.ts @@ -3,13 +3,13 @@ import { Logger } from 'src/types'; import { token } from './apis/token'; import * as url from 'lib0/url'; -const RECONNECT_INTERVAL_TIME = 5000; +const RECONNECT_INTERVAL_TIME = 500; const MAX_RECONNECT_TIMES = 50; export class WebsocketClient extends websocket.WebsocketClient { public shouldReconnect = false; - private _reconnectInterval: number | null = null; private _logger: Logger; + private _retryTimes = 0; constructor( serverUrl: string, logger: Logger, @@ -34,30 +34,28 @@ export class WebsocketClient extends websocket.WebsocketClient { this.on('connect', () => { this._logger('Affine channel connected'); this.shouldReconnect = true; - if (this._reconnectInterval) { - window.clearInterval(this._reconnectInterval); - } + this._retryTimes = 0; }); this.on('disconnect', ({ error }: { error: Error }) => { if (error) { - let times = 0; // Try reconnect if connect error has occurred - this._reconnectInterval = window.setInterval(() => { - if (this.shouldReconnect && token.isLogin && !this.connected) { - try { - this.connect(); - this._logger(`try reconnect channel ${++times} times`); - if (times > MAX_RECONNECT_TIMES) { + if (this.shouldReconnect && token.isLogin && !this.connected) { + try { + setTimeout(() => { + if (this._retryTimes <= MAX_RECONNECT_TIMES) { + this.connect(); + this._logger( + `try reconnect channel ${++this._retryTimes} times` + ); + } else { this._logger('reconnect failed, max reconnect times reached'); - this._reconnectInterval && - window.clearInterval(this._reconnectInterval); } - } catch (e) { - this._logger('reconnect failed', e); - } + }, RECONNECT_INTERVAL_TIME); + } catch (e) { + this._logger('reconnect failed', e); } - }, RECONNECT_INTERVAL_TIME); + } } }); } From 911cc3e2179d412b41d374f1ec13c242818f166c Mon Sep 17 00:00:00 2001 From: DiamondThree Date: Fri, 13 Jan 2023 17:41:13 +0800 Subject: [PATCH 228/298] Fix/publish style (#732) --- .../workspace-setting/PublishPage.tsx | 44 ++++++++++--------- .../components/workspace-setting/SyncPage.tsx | 2 +- .../workspace-setting/general/General.tsx | 23 +++++----- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx index d61bf4fcf9..f2a87c7d51 100644 --- a/packages/app/src/components/workspace-setting/PublishPage.tsx +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -55,27 +55,29 @@ export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => {
    )}
    - {workspace.published ? ( - - ) : ( - - )} + + {workspace.published ? ( + + ) : ( + + )} +
    ) : ( diff --git a/packages/app/src/components/workspace-setting/SyncPage.tsx b/packages/app/src/components/workspace-setting/SyncPage.tsx index 7d56d0233c..72f1d08fda 100644 --- a/packages/app/src/components/workspace-setting/SyncPage.tsx +++ b/packages/app/src/components/workspace-setting/SyncPage.tsx @@ -69,7 +69,7 @@ export const SyncPage = ({ workspace }: { workspace: WorkspaceUnit }) => { placement="bottom-end" disablePortal={true} > -
    diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index 8b444bb55f..7d9294f276 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -12,7 +12,7 @@ import Input from '@/ui/input'; import { useAppState } from '@/providers/app-state-provider'; import { WorkspaceDelete } from './delete'; import { WorkspaceLeave } from './leave'; -import { Upload } from '@/components/file-upload'; +// import { Upload } from '@/components/file-upload'; import { WorkspaceUnitAvatar } from '@/components/workspace-avatar'; import { WorkspaceUnit } from '@affine/datacenter'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; @@ -20,7 +20,7 @@ import { useTranslation } from '@affine/i18n'; export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const [showDelete, setShowDelete] = useState(false); const [showLeave, setShowLeave] = useState(false); - const [uploading, setUploading] = useState(false); + // const [uploading, setUploading] = useState(false); const [workspaceName, setWorkspaceName] = useState(workspace.name); const { currentWorkspace, isOwner } = useAppState(); const { updateWorkspace } = useWorkspaceHelper(); @@ -34,13 +34,13 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { updateWorkspace({ name: workspaceName }, currentWorkspace); }; - const fileChange = async (file: File) => { - setUploading(true); - const blob = new Blob([file], { type: file.type }); - currentWorkspace && - (await updateWorkspace({ avatarBlob: blob }, currentWorkspace)); - setUploading(false); - }; + // const fileChange = async (file: File) => { + // setUploading(true); + // const blob = new Blob([file], { type: file.type }); + // currentWorkspace && + // (await updateWorkspace({ avatarBlob: blob }, currentWorkspace)); + // setUploading(false); + // }; return workspace ? (
    @@ -58,12 +58,13 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { workspaceUnit={workspace} />
    - - + */} {/* TODO: add upload logic */} {t('Workspace Name')} From a739c1f773b7a98dbf71698ec1b3c959f40c0f26 Mon Sep 17 00:00:00 2001 From: zuomeng wang Date: Fri, 13 Jan 2023 18:29:02 +0800 Subject: [PATCH 229/298] =?UTF-8?q?fix:=20@blocksuite/store=20was=20alread?= =?UTF-8?q?y=20imported.=20This=20breaks=20constructor=20=E2=80=A6=20(#736?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …checks and will lead to issues --- packages/data-center/package.json | 7 +--- pnpm-lock.yaml | 66 +++---------------------------- 2 files changed, 7 insertions(+), 66 deletions(-) diff --git a/packages/data-center/package.json b/packages/data-center/package.json index d8e0f47f1b..11031a8e4c 100644 --- a/packages/data-center/package.json +++ b/packages/data-center/package.json @@ -23,7 +23,8 @@ "@playwright/test": "^1.29.1", "@types/debug": "^4.1.7", "fake-indexeddb": "4.0.1", - "typescript": "^4.8.4" + "typescript": "^4.8.4", + "yjs": "^13.5.44" }, "dependencies": { "@blocksuite/blocks": "0.4.0-20230111171650-bc63456", @@ -37,9 +38,5 @@ "lib0": "^0.2.58", "swr": "^2.0.0", "y-protocols": "^1.0.5" - }, - "peerDependencies": { - "@blocksuite/blocks": "0.3.1-*", - "@blocksuite/store": "0.3.1-*" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7edf50741..e3871e7978 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -144,9 +144,10 @@ importers: swr: ^2.0.0 typescript: ^4.8.4 y-protocols: ^1.0.5 + yjs: ^13.5.44 dependencies: - '@blocksuite/blocks': 0.4.0-20230111171650-bc63456 - '@blocksuite/store': 0.4.0-20230111171650-bc63456 + '@blocksuite/blocks': 0.4.0-20230111171650-bc63456_yjs@13.5.44 + '@blocksuite/store': 0.4.0-20230111171650-bc63456_yjs@13.5.44 debug: 4.3.4 encoding: 0.1.13 firebase: 9.15.0_encoding@0.1.13 @@ -161,6 +162,7 @@ importers: '@types/debug': 4.1.7 fake-indexeddb: 4.0.1 typescript: 4.9.3 + yjs: 13.5.44 packages/i18n: specifiers: @@ -1501,27 +1503,6 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@blocksuite/blocks/0.4.0-20230111171650-bc63456: - resolution: {integrity: sha512-7fpb++pT9laoyLFWl4h09v7TUqZ/9udMrC1qxdX2XFgMPJjg3MJ9RG+Ud2s/zqZ1SkU1+0hMBvJP5ci9vV44gw==} - dependencies: - '@blocksuite/global': 0.4.0-20230111171650-bc63456 - '@blocksuite/phasor': 0.4.0-20230111171650-bc63456 - '@blocksuite/store': 0.4.0-20230111171650-bc63456 - '@tldraw/intersect': 1.8.0 - autosize: 5.0.2 - highlight.js: 11.7.0 - hotkeys-js: 3.10.1 - lit: 2.6.1 - perfect-freehand: 1.2.0 - quill: 1.3.7 - quill-cursors: 4.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - yjs - dev: false - /@blocksuite/blocks/0.4.0-20230111171650-bc63456_yjs@13.5.44: resolution: {integrity: sha512-7fpb++pT9laoyLFWl4h09v7TUqZ/9udMrC1qxdX2XFgMPJjg3MJ9RG+Ud2s/zqZ1SkU1+0hMBvJP5ci9vV44gw==} dependencies: @@ -1572,12 +1553,6 @@ packages: react: 18.2.0 dev: false - /@blocksuite/phasor/0.4.0-20230111171650-bc63456: - resolution: {integrity: sha512-fzmrG8KVJXkm5YyvHpPG1RRFhXjzuOey8OIoDu+/z87n9HJc4SkOd9JKH6wEL37F7P5ZoEM9Yl9YHxQjUc4/CA==} - peerDependencies: - yjs: ^13 - dev: false - /@blocksuite/phasor/0.4.0-20230111171650-bc63456_yjs@13.5.44: resolution: {integrity: sha512-fzmrG8KVJXkm5YyvHpPG1RRFhXjzuOey8OIoDu+/z87n9HJc4SkOd9JKH6wEL37F7P5ZoEM9Yl9YHxQjUc4/CA==} peerDependencies: @@ -1586,27 +1561,6 @@ packages: yjs: 13.5.44 dev: false - /@blocksuite/store/0.4.0-20230111171650-bc63456: - resolution: {integrity: sha512-f/PKFPadA0KZq/wSLxxlS29c4SDuMfzHN1/gdrxFEIY0gC8caK2jZnT4K62R9Nquik/mXL60h8fBVAkQ0KbHzg==} - peerDependencies: - yjs: ^13 - dependencies: - '@blocksuite/global': 0.4.0-20230111171650-bc63456 - '@types/flexsearch': 0.7.3 - '@types/quill': 1.3.10 - buffer: 6.0.3 - flexsearch: 0.7.21 - idb-keyval: 6.2.0 - ky: 0.33.1 - lib0: 0.2.58 - y-protocols: 1.0.5 - y-webrtc: 10.2.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - dev: false - /@blocksuite/store/0.4.0-20230111171650-bc63456_yjs@13.5.44: resolution: {integrity: sha512-f/PKFPadA0KZq/wSLxxlS29c4SDuMfzHN1/gdrxFEIY0gC8caK2jZnT4K62R9Nquik/mXL60h8fBVAkQ0KbHzg==} peerDependencies: @@ -6571,7 +6525,6 @@ packages: /isomorphic.js/0.2.5: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - dev: false /istanbul-lib-coverage/3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} @@ -7216,19 +7169,11 @@ packages: type-check: 0.4.0 dev: true - /lib0/0.2.52: - resolution: {integrity: sha512-CjxlM7UgICfN6b2OPALBXchIBiNk6jE+1g7JP8ha+dh1xKRDSYpH0WQl1+rMqCju49xUnwPG34v4CR5/rPOZhg==} - engines: {node: '>=14'} - dependencies: - isomorphic.js: 0.2.5 - dev: false - /lib0/0.2.58: resolution: {integrity: sha512-6ovqPaYfOKU7GkkVxz/wjMR0zsqmNsISLvH+h9Lx5YNtWDZey69aYsTGXaSVpUPpJ+ZFtIvcZHsTGL3MbwOM8A==} engines: {node: '>=14'} dependencies: isomorphic.js: 0.2.5 - dev: false /lilconfig/2.0.6: resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} @@ -9908,8 +9853,7 @@ packages: /yjs/13.5.44: resolution: {integrity: sha512-UL+abIh2lQonqXfaJ+en7z9eGshpY11j1zNLc2kDYs0vrTjee4gZJUXC3ZsuhP6geQt0IRU04epCGRaVPQAVCA==} dependencies: - lib0: 0.2.52 - dev: false + lib0: 0.2.58 /yn/3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} From b8efa9aa2572dbc7089135fd841fb96910cb7e30 Mon Sep 17 00:00:00 2001 From: zuomeng wang Date: Fri, 13 Jan 2023 18:42:37 +0800 Subject: [PATCH 230/298] fix: change request baseUrl to dynamic (#737) --- packages/data-center/src/provider/affine/apis/request.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-center/src/provider/affine/apis/request.ts b/packages/data-center/src/provider/affine/apis/request.ts index c5bdf7e300..306ac5b9e7 100644 --- a/packages/data-center/src/provider/affine/apis/request.ts +++ b/packages/data-center/src/provider/affine/apis/request.ts @@ -9,7 +9,7 @@ const messageCenter = MessageCenter.getInstance(); const _sendMessage = messageCenter.getMessageSender('affine'); export const bareClient: KyInstance = ky.extend({ - prefixUrl: 'http://localhost:8080', + prefixUrl: '/', retry: 1, hooks: { // afterResponse: [ From e1234df1412498f32c7550be8e9be031ada8435d Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 13 Jan 2023 21:06:10 +0800 Subject: [PATCH 231/298] feat: throw error if user not found --- packages/app/src/providers/app-state-provider/Provider.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/app/src/providers/app-state-provider/Provider.tsx b/packages/app/src/providers/app-state-provider/Provider.tsx index 59cfee3344..9ec23cd69c 100644 --- a/packages/app/src/providers/app-state-provider/Provider.tsx +++ b/packages/app/src/providers/app-state-provider/Provider.tsx @@ -134,7 +134,11 @@ export const AppStateProvider = ({ const login = async () => { const { dataCenter } = appState; await dataCenter.login(); + const user = (await dataCenter.getUserInfo()) as User; + if (!user) { + throw new Error('User info not found'); + } setAppState({ ...appState, user, From d6007a54e7197b7d6e1352e3bb149eb3265080e0 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Fri, 13 Jan 2023 21:21:20 +0800 Subject: [PATCH 232/298] feat: add danger to sign out button --- packages/app/src/components/workspace-modal/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index b9e833a27a..910d0fbacd 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -143,6 +143,7 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { ) : ( )} + {!loaded && ( + + + + )} Date: Fri, 13 Jan 2023 22:17:10 +0800 Subject: [PATCH 234/298] feat: add loading for PublishPage --- .../workspace-setting/PublishPage.tsx | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/app/src/components/workspace-setting/PublishPage.tsx b/packages/app/src/components/workspace-setting/PublishPage.tsx index f2a87c7d51..d8692acbb4 100644 --- a/packages/app/src/components/workspace-setting/PublishPage.tsx +++ b/packages/app/src/components/workspace-setting/PublishPage.tsx @@ -5,7 +5,7 @@ import { StyledPublishExplanation, StyledSettingH2, } from './style'; - +import { useState } from 'react'; import { Button } from '@/ui/button'; import Input from '@/ui/input'; import { toast } from '@/ui/toast'; @@ -13,10 +13,13 @@ import { toast } from '@/ui/toast'; import { WorkspaceUnit } from '@affine/datacenter'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; import { useTranslation } from '@affine/i18n'; +import Loading from '@/components/loading'; +import { Wrapper } from '@/ui/layout'; export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const shareUrl = window.location.host + '/public-workspace/' + workspace.id; const { publishWorkspace, enableWorkspace } = useWorkspaceHelper(); const { t } = useTranslation(); + const [loaded, setLoaded] = useState(true); const togglePublic = async (flag: boolean) => { await publishWorkspace(workspace.id.toString(), flag); }; @@ -58,8 +61,10 @@ export const PublishPage = ({ workspace }: { workspace: WorkspaceUnit }) => { {workspace.published ? ( ) : ( - {/* */} + )} From af2359154184849ba52ab75acfabddc4b31fb333 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Sat, 14 Jan 2023 10:07:59 +0800 Subject: [PATCH 241/298] chore: support 4 environments for developers --- packages/app/next.config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/app/next.config.js b/packages/app/next.config.js index 478bbfa12e..2e54ff005a 100644 --- a/packages/app/next.config.js +++ b/packages/app/next.config.js @@ -12,6 +12,9 @@ const EDITOR_VERSION = enableDebugLocal const profileTarget = { ac: '100.85.73.88:12001', dev: '100.77.180.48:11001', + test: '100.77.180.48:11001', + stage: '', + pro: 'http://pathfinder.affine.pro', local: '127.0.0.1:3000', }; From c7c8ea71037433a2fb872f34c1291ab3404ecfc2 Mon Sep 17 00:00:00 2001 From: tzhangchi Date: Sat, 14 Jan 2023 10:12:38 +0800 Subject: [PATCH 242/298] chore: remove unused code --- .../app/src/pages/public-workspace/[workspaceId]/[pageId].tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx b/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx index 81ae823295..4993246384 100644 --- a/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx +++ b/packages/app/src/pages/public-workspace/[workspaceId]/[pageId].tsx @@ -7,8 +7,6 @@ import { useRouter } from 'next/router'; import { Page as PageStore, Workspace } from '@blocksuite/store'; import { PageLoading } from '@/components/loading'; -import { useTranslation } from '@affine/i18n'; - const DynamicBlocksuite = dynamic(() => import('@/components/editor'), { ssr: false, }); @@ -18,7 +16,7 @@ const Page: NextPageWithLayout = () => { const { dataCenter } = useAppState(); const router = useRouter(); const [loaded, setLoaded] = useState(false); - const { t } = useTranslation(); + useEffect(() => { dataCenter .loadPublicWorkspace(router.query.workspaceId as string) From 743c7212fe659a37ee0a1efe86165b01cd479649 Mon Sep 17 00:00:00 2001 From: JimmFly Date: Mon, 16 Jan 2023 17:40:14 +0800 Subject: [PATCH 243/298] feat: adapt the quick search to the public page --- .../app/src/components/quick-search/Input.tsx | 8 +- .../quick-search/PublishedResults.tsx | 95 +++++++++++++++++++ .../app/src/components/quick-search/index.tsx | 67 +++++++++---- packages/app/src/hooks/use-page-helper.ts | 20 +++- 4 files changed, 162 insertions(+), 28 deletions(-) create mode 100644 packages/app/src/components/quick-search/PublishedResults.tsx diff --git a/packages/app/src/components/quick-search/Input.tsx b/packages/app/src/components/quick-search/Input.tsx index 6d96d239b0..e39d92e6b9 100644 --- a/packages/app/src/components/quick-search/Input.tsx +++ b/packages/app/src/components/quick-search/Input.tsx @@ -8,17 +8,17 @@ import React, { import { SearchIcon } from '@blocksuite/icons'; import { StyledInputContent, StyledLabel } from './style'; import { Command } from 'cmdk'; -import { useAppState } from '@/providers/app-state-provider'; import { useTranslation } from '@affine/i18n'; export const Input = (props: { query: string; setQuery: Dispatch>; setLoading: Dispatch>; + isPublic: boolean; + publishWorkspaceName: string | undefined; }) => { const [isComposition, setIsComposition] = useState(false); const [inputValue, setInputValue] = useState(''); const inputRef = useRef(null); - const { currentWorkspace } = useAppState(); const { t } = useTranslation(); useEffect(() => { inputRef.current?.addEventListener( @@ -78,9 +78,9 @@ export const Input = (props: { } }} placeholder={ - currentWorkspace?.isPublish + props.isPublic ? t('Quick search placeholder2', { - workspace: currentWorkspace?.blocksuiteWorkspace?.meta.name, + workspace: props.publishWorkspaceName, }) : t('Quick search placeholder') } diff --git a/packages/app/src/components/quick-search/PublishedResults.tsx b/packages/app/src/components/quick-search/PublishedResults.tsx new file mode 100644 index 0000000000..2a99737110 --- /dev/null +++ b/packages/app/src/components/quick-search/PublishedResults.tsx @@ -0,0 +1,95 @@ +import { Command } from 'cmdk'; +import { StyledListItem, StyledNotFound } from './style'; +import { PaperIcon, EdgelessIcon } from '@blocksuite/icons'; +import { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import { useAppState, PageMeta } from '@/providers/app-state-provider'; +import { useRouter } from 'next/router'; +import { NoResultSVG } from './NoResultSVG'; +import { useTranslation } from '@affine/i18n'; +import usePageHelper from '@/hooks/use-page-helper'; +import { Workspace } from '@blocksuite/store'; + +export const PublishedResults = (props: { + query: string; + loading: boolean; + setLoading: Dispatch>; + setPublishWorkspaceName: Dispatch>; + onClose: () => void; +}) => { + const [workspace, setWorkspace] = useState(); + const { query, loading, setLoading, onClose, setPublishWorkspaceName } = + props; + const { search } = usePageHelper(); + const [results, setResults] = useState(new Map()); + const { dataCenter } = useAppState(); + const router = useRouter(); + const [pageList, setPageList] = useState([]); + useEffect(() => { + dataCenter + .loadPublicWorkspace(router.query.workspaceId as string) + .then(data => { + setPageList(data.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]); + if (data && data.blocksuiteWorkspace) { + setWorkspace(data.blocksuiteWorkspace); + setPublishWorkspaceName(data.blocksuiteWorkspace.meta.name); + } + }) + .catch(() => { + router.push('/404'); + }); + }, [router, dataCenter, setPublishWorkspaceName]); + const { t } = useTranslation(); + useEffect(() => { + setResults(search(query, workspace)); + setLoading(false); + //Save the Map obtained from the search as state + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [query, setResults, setLoading]); + const pageIds = [...results.values()]; + const resultsPageMeta = pageList.filter( + page => pageIds.indexOf(page.id) > -1 && !page.trash + ); + + return loading ? null : ( + <> + {query ? ( + resultsPageMeta.length ? ( + + {resultsPageMeta.map(result => { + return ( + { + router.push( + `/public-workspace/${router.query.workspaceId}/${result.id}` + ); + onClose(); + }} + value={result.id} + > + + {result.mode === 'edgeless' ? ( + + ) : ( + + )} + {result.title} + + + ); + })} + + ) : ( + + {t('Find 0 result')} + + + ) + ) : ( + <> + )} + + ); +}; diff --git a/packages/app/src/components/quick-search/index.tsx b/packages/app/src/components/quick-search/index.tsx index 9d6e477968..9400f72031 100644 --- a/packages/app/src/components/quick-search/index.tsx +++ b/packages/app/src/components/quick-search/index.tsx @@ -13,7 +13,8 @@ import { Command } from 'cmdk'; import { useEffect, useState } from 'react'; import { useModal } from '@/providers/GlobalModalProvider'; import { getUaHelper } from '@/utils'; -import { useAppState } from '@/providers/app-state-provider'; +import { useRouter } from 'next/router'; +import { PublishedResults } from './PublishedResults'; type TransitionsModalProps = { open: boolean; onClose: () => void; @@ -22,10 +23,11 @@ const isMac = () => { return getUaHelper().isMacOs; }; export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => { - const { currentWorkspace } = useAppState(); - + const router = useRouter(); const [query, setQuery] = useState(''); const [loading, setLoading] = useState(true); + const [isPublic, setIsPublic] = useState(false); + const [publishWorkspaceName, setPublishWorkspaceName] = useState(''); const [showCreatePage, setShowCreatePage] = useState(true); const { triggerQuickSearchModal } = useModal(); @@ -51,6 +53,17 @@ export const QuickSearch = ({ open, onClose }: TransitionsModalProps) => { document.removeEventListener('keydown', down, { capture: true }); }, [open, triggerQuickSearchModal]); + useEffect(() => { + if ( + router.pathname === '/public-workspace/[workspaceId]/[pageId]' || + router.pathname === '/public-workspace/[workspaceId]' + ) { + return setIsPublic(true); + } else { + return setIsPublic(false); + } + }, [router]); + return ( { }} > - + {isMac() ? '⌘ + K' : 'Ctrl + K'} - + {!isPublic ? ( + + ) : ( + + )} - {currentWorkspace?.published ? ( - <> - ) : showCreatePage ? ( - <> - - -