fix(core): canDrop check for external (#9058)

This commit is contained in:
pengx17
2024-12-09 10:25:38 +00:00
parent 9365958a02
commit 814b4c9cb0
12 changed files with 141 additions and 55 deletions

View File

@@ -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>
);

View File

@@ -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,

View File

@@ -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]
);

View File

@@ -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]
);

View File

@@ -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'] =

View File

@@ -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 (

View File

@@ -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 (

View File

@@ -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;