mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 02:42:25 +08:00
fix(core): canDrop check for external (#9058)
This commit is contained in:
@@ -1,19 +1,22 @@
|
||||
import { DNDContext } from '@affine/component';
|
||||
import { AffineOtherPageLayout } from '@affine/component/affine-other-page-layout';
|
||||
import { workbenchRoutes } from '@affine/core/desktop/workbench-router';
|
||||
import {
|
||||
DefaultServerService,
|
||||
WorkspaceServerService,
|
||||
} from '@affine/core/modules/cloud';
|
||||
import { DndService } from '@affine/core/modules/dnd/services';
|
||||
import { ZipTransformer } from '@blocksuite/affine/blocks';
|
||||
import type { Workspace, WorkspaceMetadata } from '@toeverything/infra';
|
||||
import {
|
||||
FrameworkScope,
|
||||
GlobalContextService,
|
||||
useLiveData,
|
||||
useService,
|
||||
useServices,
|
||||
WorkspacesService,
|
||||
} from '@toeverything/infra';
|
||||
import type { ReactElement } from 'react';
|
||||
import type { PropsWithChildren, ReactElement } from 'react';
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { matchPath, useLocation, useParams } from 'react-router-dom';
|
||||
|
||||
@@ -128,6 +131,18 @@ export const Component = (): ReactElement => {
|
||||
return <WorkspacePage meta={meta} />;
|
||||
};
|
||||
|
||||
const DNDContextProvider = ({ children }: PropsWithChildren) => {
|
||||
const dndService = useService(DndService);
|
||||
const contextValue = useMemo(() => {
|
||||
return {
|
||||
externalDataAdapter: dndService.externalDataAdapter,
|
||||
};
|
||||
}, [dndService.externalDataAdapter]);
|
||||
return (
|
||||
<DNDContext.Provider value={contextValue}>{children}</DNDContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
|
||||
const { workspacesService, globalContextService, defaultServerService } =
|
||||
useServices({
|
||||
@@ -229,7 +244,9 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
|
||||
return (
|
||||
<FrameworkScope scope={workspaceServer?.scope}>
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<AppContainer fallback />
|
||||
<DNDContextProvider>
|
||||
<AppContainer fallback />
|
||||
</DNDContextProvider>
|
||||
</FrameworkScope>
|
||||
</FrameworkScope>
|
||||
);
|
||||
@@ -238,11 +255,13 @@ const WorkspacePage = ({ meta }: { meta: WorkspaceMetadata }) => {
|
||||
return (
|
||||
<FrameworkScope scope={workspaceServer?.scope}>
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<AffineErrorBoundary height="100vh">
|
||||
<WorkspaceLayout>
|
||||
<WorkbenchRoot />
|
||||
</WorkspaceLayout>
|
||||
</AffineErrorBoundary>
|
||||
<DNDContextProvider>
|
||||
<AffineErrorBoundary height="100vh">
|
||||
<WorkspaceLayout>
|
||||
<WorkbenchRoot />
|
||||
</WorkspaceLayout>
|
||||
</AffineErrorBoundary>
|
||||
</DNDContextProvider>
|
||||
</FrameworkScope>
|
||||
</FrameworkScope>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import type { ExternalGetDataFeedbackArgs } from '@affine/component';
|
||||
import type {
|
||||
ExternalDataAdapter,
|
||||
ExternalGetDataFeedbackArgs,
|
||||
} from '@affine/component';
|
||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||
import type { DocsService, WorkspaceService } from '@toeverything/infra';
|
||||
import { Service } from '@toeverything/infra';
|
||||
@@ -23,7 +26,13 @@ export class DndService extends Service {
|
||||
|
||||
private readonly resolvers = new Map<string, EntityResolver>();
|
||||
|
||||
externalDataAdapter = (args: ExternalGetDataFeedbackArgs) => {
|
||||
externalDataAdapter: ExternalDataAdapter<AffineDNDData> = (
|
||||
args: ExternalGetDataFeedbackArgs,
|
||||
isDropEvent?: boolean
|
||||
) => {
|
||||
if (!isDropEvent) {
|
||||
return {};
|
||||
}
|
||||
const from: AffineDNDData['draggable']['from'] = {
|
||||
at: 'external',
|
||||
};
|
||||
@@ -43,6 +52,10 @@ export class DndService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
if (!entity) {
|
||||
return {}; // no resolver can handle this data
|
||||
}
|
||||
|
||||
return {
|
||||
from,
|
||||
entity,
|
||||
|
||||
@@ -189,10 +189,9 @@ export const ExplorerCollectionNode = ({
|
||||
const handleCanDrop = useMemo<DropTargetOptions<AffineDNDData>['canDrop']>(
|
||||
() => args => {
|
||||
const entityType = args.source.data.entity?.type;
|
||||
const isExternalDrop = args.source.data.from?.at === 'external';
|
||||
return args.treeInstruction?.type !== 'make-child'
|
||||
? ((typeof canDrop === 'function' ? canDrop(args) : canDrop) ?? true)
|
||||
: entityType === 'doc' || isExternalDrop;
|
||||
: entityType === 'doc';
|
||||
},
|
||||
[canDrop]
|
||||
);
|
||||
|
||||
@@ -180,10 +180,9 @@ export const ExplorerDocNode = ({
|
||||
const handleCanDrop = useMemo<DropTargetOptions<AffineDNDData>['canDrop']>(
|
||||
() => args => {
|
||||
const entityType = args.source.data.entity?.type;
|
||||
const isExternalDrop = args.source.data.from?.at === 'external';
|
||||
return args.treeInstruction?.type !== 'make-child'
|
||||
? ((typeof canDrop === 'function' ? canDrop(args) : canDrop) ?? true)
|
||||
: entityType === 'doc' || isExternalDrop;
|
||||
: entityType === 'doc';
|
||||
},
|
||||
[canDrop]
|
||||
);
|
||||
|
||||
@@ -16,10 +16,8 @@ export const favoriteChildrenDropEffect: ExplorerTreeNodeDropEffect = data => {
|
||||
) {
|
||||
return 'move';
|
||||
} else if (
|
||||
(data.source.data.entity?.type &&
|
||||
isFavoriteSupportType(data.source.data.entity.type)) ||
|
||||
// always allow external drop
|
||||
data.source.data.from?.at === 'external'
|
||||
data.source.data.entity?.type &&
|
||||
isFavoriteSupportType(data.source.data.entity.type)
|
||||
) {
|
||||
return 'link';
|
||||
}
|
||||
@@ -39,7 +37,7 @@ export const favoriteRootCanDrop: DropTargetOptions<AffineDNDData>['canDrop'] =
|
||||
data => {
|
||||
return data.source.data.entity?.type
|
||||
? isFavoriteSupportType(data.source.data.entity.type)
|
||||
: data.source.data.from?.at === 'external'; // always allow external drop
|
||||
: false;
|
||||
};
|
||||
|
||||
export const favoriteChildrenCanDrop: DropTargetOptions<AffineDNDData>['canDrop'] =
|
||||
|
||||
@@ -3,11 +3,9 @@ import {
|
||||
Skeleton,
|
||||
useDropTarget,
|
||||
} from '@affine/component';
|
||||
import { DndService } from '@affine/core/modules/dnd/services';
|
||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { FavoriteIcon } from '@blocksuite/icons/rc';
|
||||
import { useService } from '@toeverything/infra';
|
||||
|
||||
import { ExplorerEmptySection } from '../../layouts/empty-section';
|
||||
import { DropEffect } from '../../tree';
|
||||
@@ -23,7 +21,6 @@ const RootEmptyLoading = () => {
|
||||
};
|
||||
const RootEmptyReady = ({ onDrop }: Omit<RootEmptyProps, 'isLoading'>) => {
|
||||
const t = useI18n();
|
||||
const dndService = useService(DndService);
|
||||
|
||||
const { dropTargetRef, draggedOverDraggable, draggedOverPosition } =
|
||||
useDropTarget<AffineDNDData>(
|
||||
@@ -33,9 +30,9 @@ const RootEmptyReady = ({ onDrop }: Omit<RootEmptyProps, 'isLoading'>) => {
|
||||
},
|
||||
onDrop: onDrop,
|
||||
canDrop: favoriteRootCanDrop,
|
||||
externalDataAdapter: dndService.externalDataAdapter,
|
||||
allowExternal: true,
|
||||
}),
|
||||
[dndService.externalDataAdapter, onDrop]
|
||||
[onDrop]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
useDropTarget,
|
||||
} from '@affine/component';
|
||||
import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils';
|
||||
import { DndService } from '@affine/core/modules/dnd/services';
|
||||
import {
|
||||
DropEffect,
|
||||
ExplorerTreeRoot,
|
||||
@@ -21,7 +20,6 @@ import { track } from '@affine/track';
|
||||
import { PlusIcon } from '@blocksuite/icons/rc';
|
||||
import {
|
||||
useLiveData,
|
||||
useService,
|
||||
useServices,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
@@ -151,8 +149,6 @@ export const ExplorerFavorites = () => {
|
||||
[favoriteService]
|
||||
);
|
||||
|
||||
const dndService = useService(DndService);
|
||||
|
||||
const { dropTargetRef, draggedOverDraggable, draggedOverPosition } =
|
||||
useDropTarget<AffineDNDData>(
|
||||
() => ({
|
||||
@@ -161,9 +157,9 @@ export const ExplorerFavorites = () => {
|
||||
},
|
||||
onDrop: handleDrop,
|
||||
canDrop: favoriteRootCanDrop,
|
||||
externalDataAdapter: dndService.externalDataAdapter,
|
||||
allowExternal: true,
|
||||
}),
|
||||
[dndService.externalDataAdapter, handleDrop]
|
||||
[handleDrop]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
} from '@affine/component';
|
||||
import { RenameModal } from '@affine/component/rename-modal';
|
||||
import { AppSidebarService } from '@affine/core/modules/app-sidebar';
|
||||
import { DndService } from '@affine/core/modules/dnd/services';
|
||||
import { WorkbenchLink } from '@affine/core/modules/workbench';
|
||||
import type { AffineDNDData } from '@affine/core/types/dnd';
|
||||
import { extractEmojiIcon } from '@affine/core/utils';
|
||||
@@ -186,7 +185,6 @@ export const ExplorerTreeNode = ({
|
||||
},
|
||||
[canDrop, reorderable]
|
||||
);
|
||||
const dndService = useService(DndService);
|
||||
|
||||
const {
|
||||
dropTargetRef,
|
||||
@@ -224,9 +222,7 @@ export const ExplorerTreeNode = ({
|
||||
}
|
||||
},
|
||||
canDrop: handleCanDrop,
|
||||
externalDataAdapter(args) {
|
||||
return dndService.externalDataAdapter(args) as any;
|
||||
},
|
||||
allowExternal: true,
|
||||
}),
|
||||
[
|
||||
dndData?.dropTarget,
|
||||
@@ -238,7 +234,6 @@ export const ExplorerTreeNode = ({
|
||||
cid,
|
||||
onDrop,
|
||||
setCollapsed,
|
||||
dndService,
|
||||
]
|
||||
);
|
||||
const isSelfDraggedOver = draggedOverDraggable?.data.__cid === cid;
|
||||
|
||||
Reference in New Issue
Block a user