feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
type FC,
|
||||
type RefObject,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
|
||||
import { type ProjectResourceGroupType } from '@coze-arch/bot-api/plugin_develop';
|
||||
import {
|
||||
mapResourceTree,
|
||||
ResourceFolder,
|
||||
type ResourceFolderProps,
|
||||
type ResourceFolderRefType,
|
||||
ResourceTypeEnum,
|
||||
useIDEService,
|
||||
} from '@coze-project-ide/framework';
|
||||
|
||||
import { usePrimarySidebarStore } from '@/stores';
|
||||
|
||||
import {
|
||||
type BizGroupTypeWithFolder,
|
||||
BizResourceContextMenuBtnType,
|
||||
type ResourceFolderCozeProps,
|
||||
type ResourceSubType,
|
||||
} from './type';
|
||||
import { ResourceGroupActions } from './resource-group-actions';
|
||||
import { ResourceGroup } from './resource-group';
|
||||
import { CustomResourceFolderShortcutService } from './plugins/shortcut-service';
|
||||
import {
|
||||
useDeleteModal,
|
||||
useResourceFolderConfig,
|
||||
useResourceOpen,
|
||||
withRenameSync,
|
||||
} from './hooks';
|
||||
import { resourceTitleMap } from './constants';
|
||||
|
||||
import styles from './styles.module.less';
|
||||
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
const ResourceFolderCozeImpl: FC<ResourceFolderCozeProps> = ({
|
||||
groupType,
|
||||
resourceTree,
|
||||
onDelete,
|
||||
onAction,
|
||||
onCreate,
|
||||
onCustomCreate,
|
||||
canCreate,
|
||||
iconRender,
|
||||
initLoaded,
|
||||
createResourceConfig,
|
||||
defaultResourceType,
|
||||
validateConfig,
|
||||
hideMoreBtn,
|
||||
...props
|
||||
}) => {
|
||||
const resourceMap = useMemo(
|
||||
() => mapResourceTree(resourceTree),
|
||||
[resourceTree],
|
||||
);
|
||||
|
||||
const ref = useRef<ResourceFolderRefType>();
|
||||
const handleFocusResourceFolder = (visible: boolean) => {
|
||||
if (visible) {
|
||||
ref.current?.focus();
|
||||
ref.current?.closeContextMenu();
|
||||
}
|
||||
};
|
||||
|
||||
const groupExpandMap = usePrimarySidebarStore(state => state.groupExpandMap);
|
||||
const updateGroupExpand = usePrimarySidebarStore(
|
||||
state => state.updateGroupExpand,
|
||||
);
|
||||
|
||||
const handleExpandChange = (_expand: boolean) => {
|
||||
ref.current?.focus();
|
||||
updateGroupExpand?.(groupType, _expand);
|
||||
};
|
||||
|
||||
const shortcutService = useIDEService<CustomResourceFolderShortcutService>(
|
||||
CustomResourceFolderShortcutService,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const disposable1 = shortcutService.onDuplicateEvent(event => {
|
||||
if (event.id !== props.id) {
|
||||
return;
|
||||
}
|
||||
const selectResources = Object.values(event.tempSelectedMap || {}).filter(
|
||||
item => item.type !== ResourceTypeEnum.Folder,
|
||||
);
|
||||
if (!selectResources?.length) {
|
||||
return;
|
||||
}
|
||||
if (selectResources.length === 1) {
|
||||
onAction?.(
|
||||
BizResourceContextMenuBtnType.DuplicateResource,
|
||||
selectResources[0],
|
||||
);
|
||||
}
|
||||
});
|
||||
const disposable2 = shortcutService.onCreateResourceEvent(event => {
|
||||
if (!canCreate) {
|
||||
return;
|
||||
}
|
||||
if (event.id !== props.id) {
|
||||
return;
|
||||
}
|
||||
// 多个创建资源菜单,不使用快捷键
|
||||
if (createResourceConfig) {
|
||||
return;
|
||||
}
|
||||
// 快捷键触发的创建资源
|
||||
handleCreateResource(groupType);
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposable1.dispose();
|
||||
disposable2.dispose();
|
||||
};
|
||||
}, [
|
||||
defaultResourceType,
|
||||
groupType,
|
||||
onCustomCreate,
|
||||
onAction,
|
||||
shortcutService,
|
||||
canCreate,
|
||||
createResourceConfig,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const disposable = shortcutService.onRenameResource(event => {
|
||||
ref.current?.renameResource(event.id);
|
||||
});
|
||||
return () => {
|
||||
disposable.dispose();
|
||||
};
|
||||
}, [shortcutService]);
|
||||
|
||||
const creatingResourceSubTypeRef = useRef<ResourceSubType>();
|
||||
const handleCreateResource = (
|
||||
_groupType: BizGroupTypeWithFolder,
|
||||
subType?: ResourceSubType,
|
||||
) => {
|
||||
if (!canCreate) {
|
||||
return;
|
||||
}
|
||||
handleExpandChange(true);
|
||||
if (_groupType === ResourceTypeEnum.Folder) {
|
||||
ref.current?.createFolder();
|
||||
} else {
|
||||
if (onCustomCreate) {
|
||||
onCustomCreate(_groupType, subType);
|
||||
} else if (defaultResourceType) {
|
||||
creatingResourceSubTypeRef.current = subType;
|
||||
ref.current?.createResource(defaultResourceType);
|
||||
} else {
|
||||
console.error(
|
||||
'[ResourceFolderCoze]must specify defaultResourceType when use props onCreate creating resource',
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDefaultCreateResource: ResourceFolderProps['onCreate'] =
|
||||
createEvent => onCreate?.(createEvent, creatingResourceSubTypeRef.current);
|
||||
|
||||
const handleImportResource = (_groupType: ProjectResourceGroupType) => {
|
||||
if (!canCreate) {
|
||||
return;
|
||||
}
|
||||
handleExpandChange(true);
|
||||
onAction?.(BizResourceContextMenuBtnType.ImportLibraryResource);
|
||||
};
|
||||
|
||||
const { handleDeleteResource, node: deleteModal } = useDeleteModal({
|
||||
onDelete,
|
||||
});
|
||||
|
||||
const configProps = useResourceFolderConfig({
|
||||
groupType,
|
||||
iconRender,
|
||||
onAction,
|
||||
createResourceConfig,
|
||||
validateConfig,
|
||||
onCreateSubTypeResource: handleCreateResource,
|
||||
hideMoreBtn,
|
||||
});
|
||||
|
||||
const { selectedResource, handleOpenResource } = useResourceOpen();
|
||||
return (
|
||||
<>
|
||||
<ResourceGroup
|
||||
className={styles['resource-folder-coze']}
|
||||
title={resourceTitleMap[groupType]}
|
||||
content={
|
||||
initLoaded ? (
|
||||
<ResourceFolder
|
||||
ref={ref as RefObject<ResourceFolderRefType>}
|
||||
resourceTree={resourceTree}
|
||||
resourceMap={resourceMap}
|
||||
onDelete={handleDeleteResource}
|
||||
onCreate={handleDefaultCreateResource}
|
||||
selected={selectedResource}
|
||||
onSelected={handleOpenResource}
|
||||
defaultResourceType={defaultResourceType}
|
||||
{...configProps}
|
||||
{...props}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
expand={groupExpandMap[groupType]}
|
||||
onExpandChange={handleExpandChange}
|
||||
actions={
|
||||
canCreate ? (
|
||||
<ResourceGroupActions
|
||||
createResourceConfig={createResourceConfig}
|
||||
groupType={groupType}
|
||||
onCreateResource={handleCreateResource}
|
||||
onImportResource={handleImportResource}
|
||||
onActionVisibleChange={handleFocusResourceFolder}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
{deleteModal}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ResourceFolderCoze = withRenameSync(ResourceFolderCozeImpl);
|
||||
Reference in New Issue
Block a user