mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
refactor(core): move hooks to core (#5458)
* move @toeverything/hooks -> @affine/core/hooks * delete @toeverything/hooks hooks are all business-related logic and are deeply coupled with other parts. Move them into the core and then reconstruct them by feature.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { updateReadyAtom } from '@affine/core/hooks/use-app-updater';
|
||||
import { apis } from '@affine/electron-api';
|
||||
import type { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ResetIcon } from '@blocksuite/icons';
|
||||
import { updateReadyAtom } from '@toeverything/hooks/use-app-updater';
|
||||
import { registerAffineCommand } from '@toeverything/infra/command';
|
||||
import type { createStore } from 'jotai';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useTheme } from 'next-themes';
|
||||
import {
|
||||
type FC,
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
ModalHeader,
|
||||
} from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { useCurrentLoginStatus } from '../../../hooks/affine/use-current-login-status';
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
ModalHeader,
|
||||
} from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { type FC, useCallback } from 'react';
|
||||
|
||||
import { useCurrentLoginStatus } from '../../../hooks/affine/use-current-login-status';
|
||||
|
||||
@@ -7,13 +7,13 @@ import {
|
||||
} from '@affine/component/auth-components';
|
||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import {
|
||||
sendChangeEmailMutation,
|
||||
sendChangePasswordEmailMutation,
|
||||
sendSetPasswordEmailMutation,
|
||||
} from '@affine/graphql';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useSetAtom } from 'jotai/react';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
ModalHeader,
|
||||
} from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { useSession } from 'next-auth/react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
@@ -4,11 +4,11 @@ import {
|
||||
ModalHeader,
|
||||
} from '@affine/component/auth-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { type GetUserQuery, getUserQuery } from '@affine/graphql';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowDownBigIcon, GoogleDuotoneIcon } from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import { type FC, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
@@ -2,6 +2,7 @@ import { SignUpPage } from '@affine/component/auth-components';
|
||||
import { AffineShapeIcon } from '@affine/component/page-list';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { Loading } from '@affine/component/ui/loading';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import type { SubscriptionRecurring } from '@affine/graphql';
|
||||
import {
|
||||
changePasswordMutation,
|
||||
@@ -9,7 +10,6 @@ import {
|
||||
subscriptionQuery,
|
||||
} from '@affine/graphql';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { Suspense, useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ import {
|
||||
type ConfirmModalProps,
|
||||
Modal,
|
||||
} from '@affine/component/ui/modal';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { apis } from '@affine/electron-api';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { workspaceManagerAtom } from '@affine/workspace/atom';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import {
|
||||
buildShowcaseWorkspace,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { usePageMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspacePage } from '@affine/core/hooks/use-block-suite-workspace-page';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import {
|
||||
fetchWithTraceReport,
|
||||
@@ -11,8 +13,6 @@ import {
|
||||
} from '@affine/workspace';
|
||||
import { assertEquals } from '@blocksuite/global/utils';
|
||||
import { Workspace } from '@blocksuite/store';
|
||||
import { usePageMetaHelper } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page';
|
||||
import { revertUpdate } from '@toeverything/y-indexeddb';
|
||||
import { useMemo } from 'react';
|
||||
import useSWRImmutable from 'swr/immutable';
|
||||
|
||||
@@ -6,13 +6,13 @@ import {
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { ConfirmModal, Modal } from '@affine/component/ui/modal';
|
||||
import type { PageMode } from '@affine/core/atoms';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import { ToggleCollapseIcon } from '@blocksuite/icons';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import type { DialogContentProps } from '@radix-ui/react-dialog';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import {
|
||||
Fragment,
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@affine/component/setting-components';
|
||||
import { Avatar } from '@affine/component/ui/avatar';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import {
|
||||
allBlobSizesQuery,
|
||||
removeAvatarMutation,
|
||||
@@ -15,7 +16,6 @@ import {
|
||||
} from '@affine/graphql';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowRightSmallIcon, CameraIcon } from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import bytes from 'bytes';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import {
|
||||
|
||||
@@ -2,9 +2,9 @@ import { Switch } from '@affine/component';
|
||||
import { SettingHeader } from '@affine/component/setting-components';
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { SettingWrapper } from '@affine/component/setting-components';
|
||||
import { useAppUpdater } from '@affine/core/hooks/use-app-updater';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowRightSmallIcon, OpenInNewIcon } from '@blocksuite/icons';
|
||||
import { useAppUpdater } from '@toeverything/hooks/use-app-updater';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useAppSettingHelper } from '../../../../../hooks/affine/use-app-setting-helper';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Loading } from '@affine/component';
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useAppUpdater } from '@affine/core/hooks/use-app-updater';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAppUpdater } from '@toeverything/hooks/use-app-updater';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from '@affine/component/setting-components';
|
||||
import { Button, IconButton } from '@affine/component/ui/button';
|
||||
import { Loading } from '@affine/component/ui/loading';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import {
|
||||
createCustomerPortalMutation,
|
||||
getInvoicesCountQuery,
|
||||
@@ -21,7 +22,6 @@ import {
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowRightSmallIcon } from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { Suspense, useCallback, useMemo, useState } from 'react';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import type { SubscriptionMutator } from '@affine/core/hooks/use-subscription';
|
||||
import {
|
||||
cancelSubscriptionMutation,
|
||||
resumeSubscriptionMutation,
|
||||
} from '@affine/graphql';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import type {
|
||||
Subscription,
|
||||
SubscriptionMutator,
|
||||
@@ -14,7 +15,6 @@ import {
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { DoneIcon } from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useAtom } from 'jotai';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
} from '@affine/component/setting-components';
|
||||
import { Avatar } from '@affine/component/ui/avatar';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { useWorkspaceBlobObjectUrl } from '@affine/core/hooks/use-workspace-blob';
|
||||
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { WorkspaceMetadata } from '@affine/workspace';
|
||||
@@ -12,8 +14,6 @@ import {
|
||||
workspaceListAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import { Logo1Icon } from '@blocksuite/icons';
|
||||
import { useWorkspaceBlobObjectUrl } from '@toeverything/hooks/use-workspace-blob';
|
||||
import { useWorkspaceInfo } from '@toeverything/hooks/use-workspace-info';
|
||||
import clsx from 'clsx';
|
||||
import { useAtom, useAtomValue } from 'jotai/react';
|
||||
import { type ReactElement, Suspense, useCallback } from 'react';
|
||||
|
||||
@@ -3,12 +3,12 @@ import {
|
||||
ConfirmModal,
|
||||
type ConfirmModalProps,
|
||||
} from '@affine/component/ui/modal';
|
||||
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { WorkspaceMetadata } from '@affine/workspace/metadata';
|
||||
import { useWorkspaceInfo } from '@toeverything/hooks/use-workspace-info';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import * as styles from './style.css';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { ConfirmModal } from '@affine/component/ui/modal';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
@@ -9,7 +10,6 @@ import {
|
||||
workspaceManagerAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import { ArrowRightSmallIcon } from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { WorkspaceFlavour, WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Workspace } from '@affine/workspace';
|
||||
import { workspaceManagerAtom } from '@affine/workspace/atom';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useWorkspaceInfo } from '@toeverything/hooks/use-workspace-info';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useState } from 'react';
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { apis } from '@affine/electron-api';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Workspace, WorkspaceMetadata } from '@affine/workspace';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useState } from 'react';
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import {
|
||||
SettingWrapper,
|
||||
} from '@affine/component/setting-components';
|
||||
import { useSelfHosted } from '@affine/core/hooks/affine/use-server-config';
|
||||
import { useWorkspace } from '@affine/core/hooks/use-workspace';
|
||||
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useWorkspace } from '@toeverything/hooks/use-workspace';
|
||||
import { useWorkspaceInfo } from '@toeverything/hooks/use-workspace-info';
|
||||
|
||||
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
|
||||
import { EnableCloudPanel } from './enable-cloud';
|
||||
|
||||
@@ -3,15 +3,15 @@ import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||
import { Avatar } from '@affine/component/ui/avatar';
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { Upload } from '@affine/core/components/pure/file-upload';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useWorkspaceBlobObjectUrl } from '@affine/core/hooks/use-workspace-blob';
|
||||
import { useWorkspaceStatus } from '@affine/core/hooks/use-workspace-status';
|
||||
import { validateAndReduceImage } from '@affine/core/utils/reduce-image';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Workspace } from '@affine/workspace';
|
||||
import { SyncPeerStep } from '@affine/workspace';
|
||||
import { CameraIcon } from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useWorkspaceBlobObjectUrl } from '@toeverything/hooks/use-workspace-blob';
|
||||
import { useWorkspaceStatus } from '@toeverything/hooks/use-workspace-status';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import {
|
||||
type KeyboardEvent,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import type { Workspace } from '@affine/workspace';
|
||||
import { workspaceManagerAtom } from '@affine/workspace/atom';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useState } from 'react';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||
import {
|
||||
useBlockSuitePageMeta,
|
||||
usePageMetaHelper,
|
||||
} from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
} from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import type { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||
import {
|
||||
type FocusEvent,
|
||||
type InputHTMLAttributes,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
MenuItem,
|
||||
MenuSeparator,
|
||||
} from '@affine/component/ui/menu';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
@@ -19,7 +20,6 @@ import {
|
||||
ImportIcon,
|
||||
PageIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { usePageMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspaceHelper } from '@affine/core/hooks/use-block-suite-workspace-helper';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { usePageMetaHelper } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper';
|
||||
import { initEmptyPage } from '@toeverything/infra/blocksuite';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Avatar } from '@affine/component/ui/avatar';
|
||||
import { Menu, MenuIcon, MenuItem } from '@affine/component/ui/menu';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { SignOutIcon } from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useMemo } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import './page-detail-editor.css';
|
||||
|
||||
import { useActiveBlocksuiteEditor } from '@affine/core/hooks/use-block-suite-editor';
|
||||
import { useBlockSuiteWorkspacePage } from '@affine/core/hooks/use-block-suite-workspace-page';
|
||||
import { assertExists, DisposableGroup } from '@blocksuite/global/utils';
|
||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { useActiveBlocksuiteEditor } from '@toeverything/hooks/use-block-suite-editor';
|
||||
import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page';
|
||||
import { fontStyleOptions } from '@toeverything/infra/atom';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue } from 'jotai';
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { commandScore } from '@affine/cmdk';
|
||||
import { useCollectionManager } from '@affine/component/page-list';
|
||||
import {
|
||||
useBlockSuitePageMeta,
|
||||
usePageMetaHelper,
|
||||
} from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
@@ -8,10 +12,6 @@ import {
|
||||
} from '@affine/workspace/atom';
|
||||
import { EdgelessIcon, PageIcon, ViewLayersIcon } from '@blocksuite/icons';
|
||||
import type { Page, PageMeta } from '@blocksuite/store';
|
||||
import {
|
||||
useBlockSuitePageMeta,
|
||||
usePageMetaHelper,
|
||||
} from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import {
|
||||
type AffineCommand,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Command } from '@affine/cmdk';
|
||||
import { useCommandState } from '@affine/cmdk';
|
||||
import { formatDate } from '@affine/component/page-list';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import type { CommandCategory } from '@toeverything/infra/command';
|
||||
import clsx from 'clsx';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
appSidebarOpenAtom,
|
||||
SidebarSwitch,
|
||||
} from '@affine/component/app-sidebar';
|
||||
import { useIsTinyScreen } from '@toeverything/hooks/use-is-tiny-screen';
|
||||
import { useIsTinyScreen } from '@affine/core/hooks/use-is-tiny-screen';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { ConfirmModal } from '@affine/component/ui/modal';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { DeleteIcon, ResetIcon } from '@blocksuite/icons';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ import {
|
||||
} from '@affine/component/page-list';
|
||||
import { RenameModal } from '@affine/component/rename-modal';
|
||||
import { Button, IconButton } from '@affine/component/ui/button';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import type { Collection, DeleteCollectionInfo } from '@affine/env/filter';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { MoreHorizontalIcon, ViewLayersIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta, Workspace } from '@blocksuite/store';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { MenuItem as CollectionItem } from '@affine/component/app-sidebar';
|
||||
import { useBlockSuitePageReferences } from '@affine/core/hooks/use-block-suite-page-references';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta, Workspace } from '@blocksuite/store';
|
||||
import { useDraggable } from '@dnd-kit/core';
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { useBlockSuitePageReferences } from '@toeverything/hooks/use-block-suite-page-references';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { RenameModal } from '@affine/component/rename-modal';
|
||||
import { usePageMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Workspace } from '@blocksuite/store';
|
||||
import { usePageMetaHelper } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { AddFavouriteButton } from '../favorite/add-favourite-button';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { MenuLinkItem } from '@affine/component/app-sidebar';
|
||||
import { useBlockSuitePageReferences } from '@affine/core/hooks/use-block-suite-page-references';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
||||
import { type PageMeta, type Workspace } from '@blocksuite/store';
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { useBlockSuitePageReferences } from '@toeverything/hooks/use-block-suite-page-references';
|
||||
import { useAtomValue } from 'jotai/react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { IconButton } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { usePageMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import type { Workspace } from '@blocksuite/store';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { usePageMetaHelper } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
|
||||
import { usePageHelper } from '../../../blocksuite/block-suite-page-list/utils';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { getDropItemId } from '../../../../hooks/affine/use-sidebar-drag';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { MenuLinkItem } from '@affine/component/app-sidebar';
|
||||
import { useBlockSuitePageReferences } from '@affine/core/hooks/use-block-suite-page-references';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { EdgelessIcon, PageIcon } from '@blocksuite/icons';
|
||||
import { useDraggable } from '@dnd-kit/core';
|
||||
import * as Collapsible from '@radix-ui/react-collapsible';
|
||||
import { useBlockSuitePageReferences } from '@toeverything/hooks/use-block-suite-page-references';
|
||||
import { useAtomValue } from 'jotai/index';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { ScrollableContainer } from '@affine/component';
|
||||
import { Divider } from '@affine/component/ui/divider';
|
||||
import { WorkspaceList } from '@affine/component/workspace-list';
|
||||
import {
|
||||
useWorkspaceAvatar,
|
||||
useWorkspaceName,
|
||||
} from '@affine/core/hooks/use-workspace-info';
|
||||
import { WorkspaceFlavour, WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { WorkspaceMetadata } from '@affine/workspace';
|
||||
@@ -9,10 +13,6 @@ import {
|
||||
workspaceListAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import {
|
||||
useWorkspaceAvatar,
|
||||
useWorkspaceName,
|
||||
} from '@toeverything/hooks/use-workspace-info';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { useSession } from 'next-auth/react';
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Avatar } from '@affine/component/ui/avatar';
|
||||
import { Loading } from '@affine/component/ui/loading';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { useWorkspaceBlobObjectUrl } from '@affine/core/hooks/use-workspace-blob';
|
||||
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { type SyncEngineStatus, SyncEngineStep } from '@affine/workspace';
|
||||
@@ -12,8 +14,6 @@ import {
|
||||
NoNetworkIcon,
|
||||
UnsyncIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useWorkspaceBlobObjectUrl } from '@toeverything/hooks/use-workspace-blob';
|
||||
import { useWorkspaceInfo } from '@toeverything/hooks/use-workspace-info';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { debounce, mean } from 'lodash-es';
|
||||
import {
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
} from '@affine/component/page-list';
|
||||
import { Menu } from '@affine/component/ui/menu';
|
||||
import { collectionsCRUDAtom } from '@affine/core/atoms/collections';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { apis, events } from '@affine/electron-api';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -26,7 +27,6 @@ import type { Workspace } from '@affine/workspace';
|
||||
import { FolderIcon, SettingsIcon } from '@blocksuite/icons';
|
||||
import { type Page } from '@blocksuite/store';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { HTMLAttributes, ReactElement } from 'react';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppUpdaterButton } from '@affine/component/app-sidebar/app-updater-button';
|
||||
import { useAppUpdater } from '@toeverything/hooks/use-app-updater';
|
||||
import { useAppUpdater } from '@affine/core/hooks/use-app-updater';
|
||||
|
||||
export const UpdaterButton = () => {
|
||||
const appUpdater = useAppUpdater();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { BrowserWarning } from '@affine/component/affine-banner';
|
||||
import { LocalDemoTips } from '@affine/component/affine-banner';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { Workspace } from '@affine/workspace';
|
||||
import { workspaceManagerAtom } from '@affine/workspace/atom';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { AffineShapeIcon } from '@affine/component/page-list'; // TODO: import from page-list temporarily, need to defined common svg icon/images management.
|
||||
import { Button } from '@affine/component/ui/button';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { useWorkspaceStatus } from '@affine/core/hooks/use-workspace-status';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
waitForCurrentWorkspaceAtom,
|
||||
workspaceManagerAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useWorkspaceStatus } from '@toeverything/hooks/use-workspace-status';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useState } from 'react';
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import 'fake-indexeddb/auto';
|
||||
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import { Schema, Workspace } from '@blocksuite/store';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { initEmptyPage } from '@toeverything/infra/blocksuite';
|
||||
import { beforeEach, describe, expect, test } from 'vitest';
|
||||
|
||||
import { useBlockSuitePageMeta } from '../use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspaceHelper } from '../use-block-suite-workspace-helper';
|
||||
|
||||
let blockSuiteWorkspace: Workspace;
|
||||
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas).register(__unstableSchemas);
|
||||
|
||||
beforeEach(async () => {
|
||||
blockSuiteWorkspace = new Workspace({
|
||||
id: 'test',
|
||||
schema,
|
||||
});
|
||||
await initEmptyPage(blockSuiteWorkspace.createPage({ id: 'page0' }));
|
||||
await initEmptyPage(blockSuiteWorkspace.createPage({ id: 'page1' }));
|
||||
await initEmptyPage(blockSuiteWorkspace.createPage({ id: 'page2' }));
|
||||
});
|
||||
|
||||
describe('useBlockSuiteWorkspaceHelper', () => {
|
||||
test('should create page', () => {
|
||||
expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(3);
|
||||
const helperHook = renderHook(() =>
|
||||
useBlockSuiteWorkspaceHelper(blockSuiteWorkspace)
|
||||
);
|
||||
const pageMetaHook = renderHook(() =>
|
||||
useBlockSuitePageMeta(blockSuiteWorkspace)
|
||||
);
|
||||
expect(pageMetaHook.result.current.length).toBe(3);
|
||||
expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(3);
|
||||
const page = helperHook.result.current.createPage('page4');
|
||||
expect(page.id).toBe('page4');
|
||||
expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(4);
|
||||
pageMetaHook.rerender();
|
||||
expect(pageMetaHook.result.current.length).toBe(4);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @vitest-environment happy-dom
|
||||
*/
|
||||
import 'fake-indexeddb/auto';
|
||||
|
||||
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import { Schema, Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { describe, expect, test, vi } from 'vitest';
|
||||
import { beforeEach } from 'vitest';
|
||||
|
||||
import { useBlockSuiteWorkspacePageTitle } from '../use-block-suite-workspace-page-title';
|
||||
|
||||
let blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas).register(__unstableSchemas);
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.useFakeTimers({ toFake: ['requestIdleCallback'] });
|
||||
blockSuiteWorkspace = new BlockSuiteWorkspace({ id: 'test', schema });
|
||||
const initPage = async (page: Page) => {
|
||||
await page.waitForLoaded();
|
||||
expect(page).not.toBeNull();
|
||||
assertExists(page);
|
||||
const pageBlockId = page.addBlock('affine:page', {
|
||||
title: new page.Text(''),
|
||||
});
|
||||
const frameId = page.addBlock('affine:note', {}, pageBlockId);
|
||||
page.addBlock('affine:paragraph', {}, frameId);
|
||||
};
|
||||
await initPage(blockSuiteWorkspace.createPage({ id: 'page0' }));
|
||||
await initPage(blockSuiteWorkspace.createPage({ id: 'page1' }));
|
||||
await initPage(blockSuiteWorkspace.createPage({ id: 'page2' }));
|
||||
});
|
||||
|
||||
describe('useBlockSuiteWorkspacePageTitle', () => {
|
||||
test('basic', async () => {
|
||||
const pageTitleHook = renderHook(() =>
|
||||
useBlockSuiteWorkspacePageTitle(blockSuiteWorkspace, 'page0')
|
||||
);
|
||||
expect(pageTitleHook.result.current).toBe('Untitled');
|
||||
blockSuiteWorkspace.setPageMeta('page0', { title: '1' });
|
||||
pageTitleHook.rerender();
|
||||
expect(pageTitleHook.result.current).toBe('1');
|
||||
});
|
||||
});
|
||||
29
packages/frontend/core/src/hooks/affine-async-hooks.ts
Normal file
29
packages/frontend/core/src/hooks/affine-async-hooks.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
|
||||
export type AsyncErrorHandler = (error: Error) => void;
|
||||
|
||||
/**
|
||||
* App should provide a global error handler for async callback in the root.
|
||||
*/
|
||||
export const AsyncCallbackContext = React.createContext<AsyncErrorHandler>(
|
||||
e => {
|
||||
console.error(e);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Translate async function to sync function and handle error automatically.
|
||||
* Only accept void function, return data here is meaningless.
|
||||
*/
|
||||
export function useAsyncCallback<T extends any[]>(
|
||||
callback: (...args: T) => Promise<void>,
|
||||
deps: any[]
|
||||
): (...args: T) => void {
|
||||
const handleAsyncError = React.useContext(AsyncCallbackContext);
|
||||
return React.useCallback(
|
||||
(...args: any) => {
|
||||
callback(...args).catch(e => handleAsyncError(e));
|
||||
},
|
||||
[...deps] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
);
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import {
|
||||
type AllPageListConfig,
|
||||
FavoriteTag,
|
||||
} from '@affine/component/page-list';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import {
|
||||
useBlockSuitePageMeta,
|
||||
usePageMetaHelper,
|
||||
} from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper';
|
||||
} from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspaceHelper } from '@affine/core/hooks/use-block-suite-workspace-helper';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { applyUpdate, encodeStateAsUpdate } from 'yjs';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { LOCALES, useI18N } from '@affine/i18n';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export function useLanguageHelper() {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { toast } from '@affine/component';
|
||||
import { usePageMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { EdgelessIcon, HistoryIcon, PageIcon } from '@blocksuite/icons';
|
||||
import { usePageMetaHelper } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import {
|
||||
PreconditionStrategy,
|
||||
registerAffineCommand,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { toast } from '@affine/component';
|
||||
import type { DraggableTitleCellData } from '@affine/component/page-list';
|
||||
import { usePageMetaHelper } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import type { DragEndEvent, UniqueIdentifier } from '@dnd-kit/core';
|
||||
import { usePageMetaHelper } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useBlockSuiteWorkspacePage } from '@affine/core/hooks/use-block-suite-workspace-page';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page';
|
||||
import { useAtomValue } from 'jotai';
|
||||
|
||||
import { currentPageIdAtom } from '../../atoms/mode';
|
||||
|
||||
198
packages/frontend/core/src/hooks/use-app-updater.ts
Normal file
198
packages/frontend/core/src/hooks/use-app-updater.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import { apis, events, type UpdateMeta } from '@affine/electron-api';
|
||||
import { isBrowser } from '@affine/env/constant';
|
||||
import { appSettingAtom } from '@toeverything/infra/atom';
|
||||
import { atom, useAtom, useAtomValue } from 'jotai';
|
||||
import { atomWithObservable, atomWithStorage } from 'jotai/utils';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { useAsyncCallback } from './affine-async-hooks';
|
||||
|
||||
function rpcToObservable<
|
||||
T,
|
||||
H extends () => Promise<T>,
|
||||
E extends (callback: (t: T) => void) => () => void,
|
||||
>(
|
||||
initialValue: T | null,
|
||||
{
|
||||
event,
|
||||
handler,
|
||||
onSubscribe,
|
||||
}: {
|
||||
event?: E;
|
||||
handler?: H;
|
||||
onSubscribe?: () => void;
|
||||
}
|
||||
): Observable<T | null> {
|
||||
return new Observable<T | null>(subscriber => {
|
||||
subscriber.next(initialValue);
|
||||
onSubscribe?.();
|
||||
if (!isBrowser || !environment.isDesktop || !event) {
|
||||
subscriber.complete();
|
||||
return;
|
||||
}
|
||||
handler?.()
|
||||
.then(t => {
|
||||
subscriber.next(t);
|
||||
})
|
||||
.catch(err => {
|
||||
subscriber.error(err);
|
||||
});
|
||||
return event(t => {
|
||||
subscriber.next(t);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// download complete, ready to install
|
||||
export const updateReadyAtom = atomWithObservable(() => {
|
||||
return rpcToObservable(null as UpdateMeta | null, {
|
||||
event: events?.updater.onUpdateReady,
|
||||
});
|
||||
});
|
||||
|
||||
// update available, but not downloaded yet
|
||||
export const updateAvailableAtom = atomWithObservable(() => {
|
||||
return rpcToObservable(null as UpdateMeta | null, {
|
||||
event: events?.updater.onUpdateAvailable,
|
||||
});
|
||||
});
|
||||
|
||||
// downloading new update
|
||||
export const downloadProgressAtom = atomWithObservable(() => {
|
||||
return rpcToObservable(null as number | null, {
|
||||
event: events?.updater.onDownloadProgress,
|
||||
});
|
||||
});
|
||||
|
||||
export const changelogCheckedAtom = atomWithStorage<Record<string, boolean>>(
|
||||
'affine:client-changelog-checked',
|
||||
{}
|
||||
);
|
||||
|
||||
export const checkingForUpdatesAtom = atom(false);
|
||||
|
||||
export const currentVersionAtom = atom(async () => {
|
||||
if (!isBrowser) {
|
||||
return null;
|
||||
}
|
||||
const currentVersion = await apis?.updater.currentVersion();
|
||||
return currentVersion;
|
||||
});
|
||||
|
||||
const currentChangelogUnreadAtom = atom(
|
||||
async get => {
|
||||
if (!isBrowser) {
|
||||
return false;
|
||||
}
|
||||
const mapping = get(changelogCheckedAtom);
|
||||
const currentVersion = await get(currentVersionAtom);
|
||||
if (currentVersion) {
|
||||
return !mapping[currentVersion];
|
||||
}
|
||||
return false;
|
||||
},
|
||||
async (get, set, v: boolean) => {
|
||||
const currentVersion = await get(currentVersionAtom);
|
||||
if (currentVersion) {
|
||||
set(changelogCheckedAtom, mapping => {
|
||||
return {
|
||||
...mapping,
|
||||
[currentVersion]: v,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const useAppUpdater = () => {
|
||||
const [appQuitting, setAppQuitting] = useState(false);
|
||||
const updateReady = useAtomValue(updateReadyAtom);
|
||||
const [setting, setSetting] = useAtom(appSettingAtom);
|
||||
const downloadProgress = useAtomValue(downloadProgressAtom);
|
||||
const [changelogUnread, setChangelogUnread] = useAtom(
|
||||
currentChangelogUnreadAtom
|
||||
);
|
||||
|
||||
const [checkingForUpdates, setCheckingForUpdates] = useAtom(
|
||||
checkingForUpdatesAtom
|
||||
);
|
||||
|
||||
const quitAndInstall = useCallback(() => {
|
||||
if (updateReady) {
|
||||
setAppQuitting(true);
|
||||
apis?.updater.quitAndInstall().catch(err => {
|
||||
// TODO: add error toast here
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
}, [updateReady]);
|
||||
|
||||
const checkForUpdates = useCallback(async () => {
|
||||
if (checkingForUpdates) {
|
||||
return;
|
||||
}
|
||||
setCheckingForUpdates(true);
|
||||
try {
|
||||
const updateInfo = await apis?.updater.checkForUpdates();
|
||||
return updateInfo?.version ?? false;
|
||||
} catch (err) {
|
||||
console.error('Error checking for updates:', err);
|
||||
return null;
|
||||
} finally {
|
||||
setCheckingForUpdates(false);
|
||||
}
|
||||
}, [checkingForUpdates, setCheckingForUpdates]);
|
||||
|
||||
const downloadUpdate = useCallback(() => {
|
||||
apis?.updater.downloadUpdate().catch(err => {
|
||||
console.error('Error downloading update:', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const toggleAutoDownload = useCallback(
|
||||
(enable: boolean) => {
|
||||
setSetting({
|
||||
autoDownloadUpdate: enable,
|
||||
});
|
||||
},
|
||||
[setSetting]
|
||||
);
|
||||
|
||||
const toggleAutoCheck = useCallback(
|
||||
(enable: boolean) => {
|
||||
setSetting({
|
||||
autoCheckUpdate: enable,
|
||||
});
|
||||
},
|
||||
[setSetting]
|
||||
);
|
||||
|
||||
const openChangelog = useAsyncCallback(async () => {
|
||||
window.open(runtimeConfig.changelogUrl, '_blank');
|
||||
await setChangelogUnread(true);
|
||||
}, [setChangelogUnread]);
|
||||
|
||||
const dismissChangelog = useAsyncCallback(async () => {
|
||||
await setChangelogUnread(true);
|
||||
}, [setChangelogUnread]);
|
||||
|
||||
return {
|
||||
quitAndInstall,
|
||||
checkForUpdates,
|
||||
downloadUpdate,
|
||||
toggleAutoDownload,
|
||||
toggleAutoCheck,
|
||||
appQuitting,
|
||||
checkingForUpdates,
|
||||
autoCheck: setting.autoCheckUpdate,
|
||||
autoDownload: setting.autoDownloadUpdate,
|
||||
changelogUnread,
|
||||
openChangelog,
|
||||
dismissChangelog,
|
||||
updateReady,
|
||||
updateAvailable: useAtomValue(updateAvailableAtom),
|
||||
downloadProgress,
|
||||
currentVersion: useAtomValue(currentVersionAtom),
|
||||
};
|
||||
};
|
||||
15
packages/frontend/core/src/hooks/use-block-suite-editor.ts
Normal file
15
packages/frontend/core/src/hooks/use-block-suite-editor.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||
import { atom, type SetStateAction, useAtom } from 'jotai';
|
||||
|
||||
const activeEditorContainerAtom = atom<AffineEditorContainer | null>(null);
|
||||
|
||||
export function useActiveBlocksuiteEditor(): [
|
||||
AffineEditorContainer | null,
|
||||
React.Dispatch<SetStateAction<AffineEditorContainer | null>>,
|
||||
] {
|
||||
const [editorContainer, setEditorContainer] = useAtom(
|
||||
activeEditorContainerAtom
|
||||
);
|
||||
|
||||
return [editorContainer, setEditorContainer];
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { PageBlockModel } from '@blocksuite/blocks';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { PageMeta, Workspace } from '@blocksuite/store';
|
||||
import type { Atom } from 'jotai';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const weakMap = new WeakMap<Workspace, Atom<PageMeta[]>>();
|
||||
|
||||
export function useBlockSuitePageMeta(
|
||||
blockSuiteWorkspace: Workspace
|
||||
): PageMeta[] {
|
||||
if (!weakMap.has(blockSuiteWorkspace)) {
|
||||
const baseAtom = atom<PageMeta[]>(blockSuiteWorkspace.meta.pageMetas);
|
||||
weakMap.set(blockSuiteWorkspace, baseAtom);
|
||||
baseAtom.onMount = set => {
|
||||
set(blockSuiteWorkspace.meta.pageMetas);
|
||||
const dispose = blockSuiteWorkspace.meta.pageMetasUpdated.on(() => {
|
||||
set(blockSuiteWorkspace.meta.pageMetas);
|
||||
});
|
||||
return () => {
|
||||
dispose.dispose();
|
||||
};
|
||||
};
|
||||
}
|
||||
return useAtomValue(weakMap.get(blockSuiteWorkspace) as Atom<PageMeta[]>);
|
||||
}
|
||||
|
||||
export function usePageMetaHelper(blockSuiteWorkspace: Workspace) {
|
||||
return useMemo(
|
||||
() => ({
|
||||
setPageTitle: (pageId: string, newTitle: string) => {
|
||||
const page = blockSuiteWorkspace.getPage(pageId);
|
||||
assertExists(page);
|
||||
const pageBlock = page
|
||||
.getBlockByFlavour('affine:page')
|
||||
.at(0) as PageBlockModel;
|
||||
assertExists(pageBlock);
|
||||
page.transact(() => {
|
||||
pageBlock.title.delete(0, pageBlock.title.length);
|
||||
pageBlock.title.insert(newTitle, 0);
|
||||
});
|
||||
blockSuiteWorkspace.meta.setPageMeta(pageId, { title: newTitle });
|
||||
},
|
||||
setPageReadonly: (pageId: string, readonly: boolean) => {
|
||||
const page = blockSuiteWorkspace.getPage(pageId);
|
||||
assertExists(page);
|
||||
page.awarenessStore.setReadonly(page, readonly);
|
||||
},
|
||||
setPageMeta: (pageId: string, pageMeta: Partial<PageMeta>) => {
|
||||
blockSuiteWorkspace.meta.setPageMeta(pageId, pageMeta);
|
||||
},
|
||||
getPageMeta: (pageId: string) => {
|
||||
return blockSuiteWorkspace.meta.getPageMeta(pageId);
|
||||
},
|
||||
}),
|
||||
[blockSuiteWorkspace]
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { type Atom, atom, useAtomValue } from 'jotai';
|
||||
|
||||
import { useBlockSuiteWorkspacePage } from './use-block-suite-workspace-page';
|
||||
|
||||
const weakMap = new WeakMap<Page, Atom<string[]>>();
|
||||
function getPageReferences(page: Page): string[] {
|
||||
return Object.values(
|
||||
page.workspace.indexer.backlink.linkIndexMap[page.id] ?? {}
|
||||
).flatMap(linkNodes => linkNodes.map(linkNode => linkNode.pageId));
|
||||
}
|
||||
|
||||
const getPageReferencesAtom = (page: Page | null) => {
|
||||
if (!page) {
|
||||
return atom([]);
|
||||
}
|
||||
|
||||
if (!weakMap.has(page)) {
|
||||
const baseAtom = atom<string[]>([]);
|
||||
baseAtom.onMount = set => {
|
||||
const disposables = [
|
||||
page.slots.ready.on(() => {
|
||||
set(getPageReferences(page));
|
||||
}),
|
||||
page.workspace.indexer.backlink.slots.indexUpdated.on(() => {
|
||||
set(getPageReferences(page));
|
||||
}),
|
||||
];
|
||||
set(getPageReferences(page));
|
||||
return () => {
|
||||
disposables.forEach(disposable => disposable.dispose());
|
||||
};
|
||||
};
|
||||
weakMap.set(page, baseAtom);
|
||||
}
|
||||
return weakMap.get(page) as Atom<string[]>;
|
||||
};
|
||||
|
||||
export function useBlockSuitePageReferences(
|
||||
blockSuiteWorkspace: Workspace,
|
||||
pageId: string
|
||||
): string[] {
|
||||
const page = useBlockSuiteWorkspacePage(blockSuiteWorkspace, pageId);
|
||||
return useAtomValue(getPageReferencesAtom(page));
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export function useBlockSuiteWorkspaceHelper(blockSuiteWorkspace: Workspace) {
|
||||
return useMemo(
|
||||
() => ({
|
||||
createPage: (pageId?: string): Page => {
|
||||
return blockSuiteWorkspace.createPage({ id: pageId });
|
||||
},
|
||||
}),
|
||||
[blockSuiteWorkspace]
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { Workspace } from '@blocksuite/store';
|
||||
import type { Atom } from 'jotai';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
|
||||
const weakMap = new WeakMap<Workspace, Map<string, Atom<string>>>();
|
||||
|
||||
function getAtom(w: Workspace, pageId: string): Atom<string> {
|
||||
if (!weakMap.has(w)) {
|
||||
weakMap.set(w, new Map());
|
||||
}
|
||||
const map = weakMap.get(w);
|
||||
assertExists(map);
|
||||
if (!map.has(pageId)) {
|
||||
const baseAtom = atom<string>(w.getPage(pageId)?.meta.title || 'Untitled');
|
||||
baseAtom.onMount = set => {
|
||||
const disposable = w.meta.pageMetasUpdated.on(() => {
|
||||
const page = w.getPage(pageId);
|
||||
set(page?.meta.title || 'Untitled');
|
||||
});
|
||||
return () => {
|
||||
disposable.dispose();
|
||||
};
|
||||
};
|
||||
map.set(pageId, baseAtom);
|
||||
return baseAtom;
|
||||
} else {
|
||||
return map.get(pageId) as Atom<string>;
|
||||
}
|
||||
}
|
||||
|
||||
export function useBlockSuiteWorkspacePageTitle(
|
||||
blockSuiteWorkspace: Workspace,
|
||||
pageId: string
|
||||
) {
|
||||
const titleAtom = getAtom(blockSuiteWorkspace, pageId);
|
||||
assertExists(titleAtom);
|
||||
return useAtomValue(titleAtom);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const logger = new DebugLogger('use-block-suite-workspace-page');
|
||||
|
||||
export function useBlockSuiteWorkspacePage(
|
||||
blockSuiteWorkspace: Workspace,
|
||||
pageId: string | null
|
||||
): Page | null {
|
||||
const [page, setPage] = useState(
|
||||
pageId ? blockSuiteWorkspace.getPage(pageId) : null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const group = new DisposableGroup();
|
||||
group.add(
|
||||
blockSuiteWorkspace.slots.pageAdded.on(id => {
|
||||
if (pageId === id) {
|
||||
setPage(blockSuiteWorkspace.getPage(id));
|
||||
}
|
||||
})
|
||||
);
|
||||
group.add(
|
||||
blockSuiteWorkspace.slots.pageRemoved.on(id => {
|
||||
if (pageId === id) {
|
||||
setPage(null);
|
||||
}
|
||||
})
|
||||
);
|
||||
return () => {
|
||||
group.dispose();
|
||||
};
|
||||
}, [blockSuiteWorkspace, pageId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (page && !page.loaded) {
|
||||
page.load().catch(err => {
|
||||
logger.error('Failed to load page', err);
|
||||
});
|
||||
}
|
||||
}, [page]);
|
||||
|
||||
return page;
|
||||
}
|
||||
15
packages/frontend/core/src/hooks/use-data-source-status.ts
Normal file
15
packages/frontend/core/src/hooks/use-data-source-status.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { useCallback, useSyncExternalStore } from 'react';
|
||||
import type { DataSourceAdapter, Status } from 'y-provider';
|
||||
|
||||
type UIStatus =
|
||||
| Status
|
||||
| {
|
||||
type: 'unknown';
|
||||
};
|
||||
|
||||
export function useDataSourceStatus(provider: DataSourceAdapter): UIStatus {
|
||||
return useSyncExternalStore(
|
||||
provider.subscribeStatusChange,
|
||||
useCallback(() => provider.status, [provider])
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import type { GetPageInfoById } from '@affine/env/page-info';
|
||||
import type { Workspace } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
|
||||
73
packages/frontend/core/src/hooks/use-is-tiny-screen.ts
Normal file
73
packages/frontend/core/src/hooks/use-is-tiny-screen.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'foxact/use-debounced-state';
|
||||
|
||||
import { debounce } from 'lodash-es';
|
||||
import { type RefObject, useEffect, useState } from 'react';
|
||||
|
||||
export function useIsTinyScreen({
|
||||
container,
|
||||
leftStatic,
|
||||
leftSlot,
|
||||
centerDom,
|
||||
rightSlot,
|
||||
}: {
|
||||
container: HTMLElement | null;
|
||||
leftStatic: RefObject<HTMLElement>;
|
||||
leftSlot: RefObject<HTMLElement>[];
|
||||
centerDom: RefObject<HTMLElement>;
|
||||
rightSlot: RefObject<HTMLElement>[];
|
||||
}) {
|
||||
const [isTinyScreen, setIsTinyScreen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
const handleResize = debounce(() => {
|
||||
if (!centerDom.current) {
|
||||
return;
|
||||
}
|
||||
const leftStaticWidth = leftStatic.current?.clientWidth || 0;
|
||||
const leftSlotWidth = leftSlot.reduce((accWidth, dom) => {
|
||||
return accWidth + (dom.current?.clientWidth || 0);
|
||||
}, 0);
|
||||
|
||||
const rightSlotWidth = rightSlot.reduce((accWidth, dom) => {
|
||||
return accWidth + (dom.current?.clientWidth || 0);
|
||||
}, 0);
|
||||
|
||||
if (!leftSlotWidth && !rightSlotWidth) {
|
||||
if (isTinyScreen) {
|
||||
setIsTinyScreen(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const centerRect = centerDom.current.getBoundingClientRect();
|
||||
|
||||
if (
|
||||
leftStaticWidth + leftSlotWidth + containerRect.left >=
|
||||
centerRect.left ||
|
||||
containerRect.right - centerRect.right <= rightSlotWidth
|
||||
) {
|
||||
setIsTinyScreen(true);
|
||||
} else {
|
||||
setIsTinyScreen(false);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
handleResize();
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
handleResize();
|
||||
});
|
||||
|
||||
resizeObserver.observe(container);
|
||||
|
||||
return () => {
|
||||
resizeObserver.unobserve(container);
|
||||
};
|
||||
}, [centerDom, isTinyScreen, leftSlot, leftStatic, container, rightSlot]);
|
||||
|
||||
return isTinyScreen;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { type SubscriptionQuery, subscriptionQuery } from '@affine/graphql';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
|
||||
import { useSelfHosted } from './affine/use-server-config';
|
||||
import { useQuery } from './use-query';
|
||||
|
||||
40
packages/frontend/core/src/hooks/use-workspace-blob.ts
Normal file
40
packages/frontend/core/src/hooks/use-workspace-blob.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { workspaceManagerAtom } from '@affine/workspace/atom';
|
||||
import type { WorkspaceMetadata } from '@affine/workspace/metadata';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function useWorkspaceBlobObjectUrl(
|
||||
meta?: WorkspaceMetadata,
|
||||
blobKey?: string | null
|
||||
) {
|
||||
const workspaceManager = useAtomValue(workspaceManagerAtom);
|
||||
|
||||
const [blob, setBlob] = useState<string | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
setBlob(undefined);
|
||||
if (!blobKey || !meta) {
|
||||
return;
|
||||
}
|
||||
let canceled = false;
|
||||
let objectUrl: string = '';
|
||||
workspaceManager
|
||||
.getWorkspaceBlob(meta, blobKey)
|
||||
.then(blob => {
|
||||
if (blob && !canceled) {
|
||||
objectUrl = URL.createObjectURL(blob);
|
||||
setBlob(objectUrl);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('get workspace blob error: ' + err);
|
||||
});
|
||||
|
||||
return () => {
|
||||
canceled = true;
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
};
|
||||
}, [meta, blobKey, workspaceManager]);
|
||||
|
||||
return blob;
|
||||
}
|
||||
38
packages/frontend/core/src/hooks/use-workspace-info.ts
Normal file
38
packages/frontend/core/src/hooks/use-workspace-info.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { WorkspaceMetadata } from '@affine/workspace';
|
||||
import { workspaceManagerAtom } from '@affine/workspace/atom';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useWorkspaceBlobObjectUrl } from './use-workspace-blob';
|
||||
|
||||
export function useWorkspaceInfo(meta: WorkspaceMetadata) {
|
||||
const workspaceManager = useAtomValue(workspaceManagerAtom);
|
||||
|
||||
const [information, setInformation] = useState(
|
||||
() => workspaceManager.list.getInformation(meta).info
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const information = workspaceManager.list.getInformation(meta);
|
||||
|
||||
setInformation(information.info);
|
||||
return information.onUpdated.on(info => {
|
||||
setInformation(info);
|
||||
}).dispose;
|
||||
}, [meta, workspaceManager]);
|
||||
|
||||
return information;
|
||||
}
|
||||
|
||||
export function useWorkspaceName(meta: WorkspaceMetadata) {
|
||||
const information = useWorkspaceInfo(meta);
|
||||
|
||||
return information?.name;
|
||||
}
|
||||
|
||||
export function useWorkspaceAvatar(meta: WorkspaceMetadata) {
|
||||
const information = useWorkspaceInfo(meta);
|
||||
const avatar = useWorkspaceBlobObjectUrl(meta, information?.avatar);
|
||||
|
||||
return avatar;
|
||||
}
|
||||
34
packages/frontend/core/src/hooks/use-workspace-status.ts
Normal file
34
packages/frontend/core/src/hooks/use-workspace-status.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { Workspace, WorkspaceStatus } from '@affine/workspace';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function useWorkspaceStatus<
|
||||
Selector extends ((status: WorkspaceStatus) => any) | undefined | null,
|
||||
Status = Selector extends (status: WorkspaceStatus) => any
|
||||
? ReturnType<Selector>
|
||||
: WorkspaceStatus,
|
||||
>(workspace?: Workspace | null, selector?: Selector): Status | null {
|
||||
// avoid re-render when selector is changed
|
||||
const [cachedSelector] = useState(() => selector);
|
||||
|
||||
const [status, setStatus] = useState<Status | null>(() => {
|
||||
if (!workspace) {
|
||||
return null;
|
||||
}
|
||||
return cachedSelector ? cachedSelector(workspace.status) : workspace.status;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!workspace) {
|
||||
setStatus(null);
|
||||
return;
|
||||
}
|
||||
setStatus(
|
||||
cachedSelector ? cachedSelector(workspace.status) : workspace.status
|
||||
);
|
||||
return workspace.onStatusChange.on(status =>
|
||||
setStatus(cachedSelector ? cachedSelector(status) : status)
|
||||
).dispose;
|
||||
}, [cachedSelector, workspace]);
|
||||
|
||||
return status;
|
||||
}
|
||||
28
packages/frontend/core/src/hooks/use-workspace.ts
Normal file
28
packages/frontend/core/src/hooks/use-workspace.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { Workspace } from '@affine/workspace';
|
||||
import { workspaceManagerAtom } from '@affine/workspace/atom';
|
||||
import type { WorkspaceMetadata } from '@affine/workspace/metadata';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
/**
|
||||
* definitely be careful when using this hook, open workspace is a heavy operation
|
||||
*/
|
||||
export function useWorkspace(meta?: WorkspaceMetadata | null) {
|
||||
const workspaceManager = useAtomValue(workspaceManagerAtom);
|
||||
|
||||
const [workspace, setWorkspace] = useState<Workspace | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!meta) {
|
||||
setWorkspace(null); // set to null if meta is null or undefined
|
||||
return;
|
||||
}
|
||||
const ref = workspaceManager.use(meta);
|
||||
setWorkspace(ref.workspace);
|
||||
return () => {
|
||||
ref.release();
|
||||
};
|
||||
}, [meta, workspaceManager]);
|
||||
|
||||
return workspace;
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
PageListDragOverlay,
|
||||
} from '@affine/component/page-list';
|
||||
import { MainContainer, WorkspaceFallback } from '@affine/component/workspace';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useWorkspaceStatus } from '@affine/core/hooks/use-workspace-status';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import {
|
||||
@@ -18,8 +20,6 @@ import {
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useWorkspaceStatus } from '@toeverything/hooks/use-workspace-status';
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import type { PropsWithChildren, ReactNode } from 'react';
|
||||
import { lazy, Suspense, useCallback, useEffect, useState } from 'react';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NotFoundPage } from '@affine/component/not-found-page';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { useSession } from 'next-auth/react';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
useCollectionManager,
|
||||
VirtualizedPageList,
|
||||
} from '@affine/component/page-list';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
@@ -19,7 +20,6 @@ import {
|
||||
ViewLayersIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { PageMeta, Workspace } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
useEditCollection,
|
||||
} from '@affine/component/page-list';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -20,7 +21,6 @@ import {
|
||||
PageIcon,
|
||||
ViewLayersIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useSetAtom } from 'jotai';
|
||||
|
||||
@@ -4,13 +4,13 @@ import {
|
||||
useCollectionManager,
|
||||
} from '@affine/component/page-list';
|
||||
import { ResizePanel } from '@affine/component/resize-panel';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useWorkspaceStatus } from '@affine/core/hooks/use-workspace-status';
|
||||
import { WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import { globalBlockSuiteSchema, SyncEngineStep } from '@affine/workspace';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useWorkspaceStatus } from '@toeverything/hooks/use-workspace-status';
|
||||
import { appSettingAtom } from '@toeverything/infra/atom';
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useActiveBlocksuiteEditor } from '@affine/core/hooks/use-block-suite-editor';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { AiIcon } from '@blocksuite/icons';
|
||||
import { CopilotPanel } from '@blocksuite/presets';
|
||||
import { useActiveBlocksuiteEditor } from '@toeverything/hooks/use-block-suite-editor';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import type { EditorExtension } from '../types';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useActiveBlocksuiteEditor } from '@affine/core/hooks/use-block-suite-editor';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { FrameIcon } from '@blocksuite/icons';
|
||||
import { FramePanel } from '@blocksuite/presets';
|
||||
import { useActiveBlocksuiteEditor } from '@toeverything/hooks/use-block-suite-editor';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import type { EditorExtension } from '../types';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useActiveBlocksuiteEditor } from '@affine/core/hooks/use-block-suite-editor';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { TocIcon } from '@blocksuite/icons';
|
||||
import { TOCPanel } from '@blocksuite/presets';
|
||||
import { useActiveBlocksuiteEditor } from '@toeverything/hooks/use-block-suite-editor';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import type { EditorExtension } from '../types';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { WorkspaceFallback } from '@affine/component/workspace';
|
||||
import { useWorkspace } from '@affine/core/hooks/use-workspace';
|
||||
import { type Workspace } from '@affine/workspace';
|
||||
import {
|
||||
currentWorkspaceAtom,
|
||||
@@ -6,7 +7,6 @@ import {
|
||||
workspaceListLoadingStatusAtom,
|
||||
workspaceManagerAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import { useWorkspace } from '@toeverything/hooks/use-workspace';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import { type ReactElement, Suspense, useEffect, useMemo } from 'react';
|
||||
import { Outlet, useParams } from 'react-router-dom';
|
||||
|
||||
@@ -4,12 +4,12 @@ import {
|
||||
TrashOperationCell,
|
||||
VirtualizedPageList,
|
||||
} from '@affine/component/page-list';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/workspace/atom';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { DeleteIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { WorkspaceFlavour, WorkspaceSubPath } from '@affine/env/workspace';
|
||||
import {
|
||||
currentWorkspaceAtom,
|
||||
@@ -5,7 +6,6 @@ import {
|
||||
workspaceListAtom,
|
||||
} from '@affine/workspace/atom';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import type { ReactElement } from 'react';
|
||||
import { lazy, Suspense, useCallback } from 'react';
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import '@toeverything/hooks/use-affine-ipc-renderer';
|
||||
|
||||
import { pushNotificationAtom } from '@affine/component/notification-center';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { affine } from '@affine/electron-api';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CLOUD_WORKSPACE_CHANGED_BROADCAST_CHANNEL_KEY } from '@affine/workspace';
|
||||
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { SessionProvider, useSession } from 'next-auth/react';
|
||||
@@ -51,7 +50,7 @@ const SessionDefence = (props: PropsWithChildren) => {
|
||||
});
|
||||
|
||||
if (environment.isDesktop) {
|
||||
window.affine.ipcRenderer.send('affine:login');
|
||||
affine?.ipcRenderer.send('affine:login');
|
||||
}
|
||||
}
|
||||
prevSession.current = session;
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
{
|
||||
"path": "../../frontend/graphql"
|
||||
},
|
||||
{
|
||||
"path": "../../frontend/hooks"
|
||||
},
|
||||
{
|
||||
"path": "../../frontend/i18n"
|
||||
},
|
||||
@@ -32,6 +29,9 @@
|
||||
{
|
||||
"path": "../../common/env"
|
||||
},
|
||||
{
|
||||
"path": "../../common/y-indexeddb"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user