diff --git a/packages/core/client/src/application/schema-initializer/components/SchemaInitializerSubMenu.tsx b/packages/core/client/src/application/schema-initializer/components/SchemaInitializerSubMenu.tsx index f666277241..98daa70190 100644 --- a/packages/core/client/src/application/schema-initializer/components/SchemaInitializerSubMenu.tsx +++ b/packages/core/client/src/application/schema-initializer/components/SchemaInitializerSubMenu.tsx @@ -13,6 +13,7 @@ export interface SchemaInitializerSubMenuProps { name: string; title?: string; onClick?: (args: any) => void; + onOpenChange?: (openKeys: string[]) => void; icon?: string | ReactNode; children?: SchemaInitializerOptions['items']; } @@ -66,9 +67,10 @@ export const SchemaInitializerMenu: FC = (props) => { }; export const SchemaInitializerSubMenu: FC = (props) => { - const { children, title, name = uid(), icon, ...others } = props; + const { children, title, name = uid(), onOpenChange, icon, ...others } = props; const compile = useCompile(); const childrenItems = useSchemaInitializerMenuItems(children, name); + const items = useMemo(() => { return [ { @@ -80,7 +82,7 @@ export const SchemaInitializerSubMenu: FC = (prop }, ]; }, [childrenItems, compile, icon, name, others, title]); - return ; + return ; }; export const SchemaInitializerSubMenuInternal = () => { diff --git a/packages/core/client/src/application/schema-initializer/hooks/index.tsx b/packages/core/client/src/application/schema-initializer/hooks/index.tsx index 5940e50a7b..cc6648e2eb 100644 --- a/packages/core/client/src/application/schema-initializer/hooks/index.tsx +++ b/packages/core/client/src/application/schema-initializer/hooks/index.tsx @@ -5,87 +5,16 @@ import { useApp } from '../../hooks'; import { SchemaInitializerChild, SchemaInitializerItems } from '../components'; import { SchemaInitializerButton } from '../components/SchemaInitializerButton'; import { withInitializer } from '../hoc'; -import { SchemaInitializerItemType, SchemaInitializerOptions } from '../types'; +import { SchemaInitializerOptions } from '../types'; export * from './useAriaAttributeOfMenuItem'; export function useSchemaInitializerMenuItems(items: any[], name?: string, onClick?: (args: any) => void) { - const compile = useCompile(); - - const getMenuItems = useCallback( - (items: SchemaInitializerItemType[], parentKey: string) => { - if (!items?.length) { - return []; - } - return items.map((item: any, indexA) => { - const ItemComponent = item.component || item.Component; - let element: ReactNode; - const compiledTitle = item.title ? compile(item.title) : undefined; - if (ItemComponent) { - element = React.createElement(SchemaInitializerChild, { ...item, title: compiledTitle }); - if (!element) return; - } - - if (item.type === 'divider') { - return { type: 'divider', key: `divider-${indexA}` }; - } - if (item.type === 'item' && ItemComponent) { - if (!item.key) { - item.key = `${item.title}-${indexA}`; - } - return { - key: item.key, - label: element, - }; - } - if (item.type === 'itemGroup') { - const label = typeof item.title === 'string' ? compiledTitle : item.title; - const key = `${parentKey}-item-group-${indexA}`; - return { - type: 'group', - key, - label, - // className: styles.nbMenuItemGroup, - children: item?.children.length ? getMenuItems(item.children, key) : [], - }; - } - if (item.type === 'subMenu') { - const label = compiledTitle; - const key = `${parentKey}-sub-menu-${indexA}`; - return { - key, - label, - children: item?.children.length ? getMenuItems(item.children, key) : [], - }; - } - if (item.isMenuType) { - const { isMenuType, ...menuData } = item; - return menuData; - } - - const label = element || compiledTitle || item.label; - const key = `${parentKey}-${item.title}-${indexA}`; - return { - key, - label, - onClick: (info) => { - if (info.key !== key) return; - if (item.onClick) { - item.onClick({ ...info, item }); - } else { - onClick?.({ ...info, item }); - } - }, - }; - }); - }, - [compile, onClick], - ); - + const getMenuItems = useGetSchemaInitializerMenuItems(onClick); return getMenuItems(items, name); } -export function useSchemaInitializerMenuItemsV2(onClick?: (args: any) => void) { +export function useGetSchemaInitializerMenuItems(onClick?: (args: any) => void) { const compile = useCompile(); const getMenuItems = useCallback( diff --git a/packages/core/client/src/schema-initializer/index.ts b/packages/core/client/src/schema-initializer/index.ts index da7a8ce3fe..46a4327547 100644 --- a/packages/core/client/src/schema-initializer/index.ts +++ b/packages/core/client/src/schema-initializer/index.ts @@ -43,7 +43,6 @@ export { useAssociatedFormItemInitializerFields, useAssociatedTableColumnInitializerFields, useCollectionDataSourceItems, - useCollectionDataSourceItemsV2, useCurrentSchema, useFormItemInitializerFields, useInheritsTableColumnInitializerFields, diff --git a/packages/core/client/src/schema-initializer/items/DataBlockInitializer.tsx b/packages/core/client/src/schema-initializer/items/DataBlockInitializer.tsx index 70b6a9d6f3..aa7becabd8 100644 --- a/packages/core/client/src/schema-initializer/items/DataBlockInitializer.tsx +++ b/packages/core/client/src/schema-initializer/items/DataBlockInitializer.tsx @@ -7,12 +7,11 @@ import { SchemaInitializerItem, SchemaInitializerMenu, useSchemaInitializer, - useSchemaInitializerMenuItems, - useSchemaInitializerMenuItemsV2, + useGetSchemaInitializerMenuItems, } from '../../application'; import { useCompile } from '../../schema-component'; import { useSchemaTemplateManager } from '../../schema-templates'; -import { useCollectionDataSourceItemsV2, useCollectionDataSourceItemsV3 } from '../utils'; +import { useCollectionDataSourceItems } from '../utils'; const MENU_ITEM_HEIGHT = 40; const STEP = 15; @@ -110,109 +109,7 @@ const LoadingItem = ({ loadMore, maxHeight }) => { ); }; -export function useMenuSearch(items: any[], isOpenSubMenu: boolean, showType?: boolean) { - const [searchValue, setSearchValue] = useState(''); - const [count, setCount] = useState(STEP); - useEffect(() => { - if (isOpenSubMenu) { - setSearchValue(''); - } - }, [isOpenSubMenu]); - - // 根据搜索的值进行处理 - const searchedItems = useMemo(() => { - if (!searchValue) return items; - const lowerSearchValue = searchValue.toLocaleLowerCase(); - return items.filter( - (item) => - (item.label || item.title) && - String(item.label || item.title) - .toLocaleLowerCase() - .includes(lowerSearchValue), - ); - }, [searchValue, items]); - - const shouldLoadMore = useMemo(() => searchedItems.length > count, [count, searchedItems]); - - // 根据 count 进行懒加载处理 - const limitedSearchedItems = useMemo(() => { - return searchedItems.slice(0, count); - }, [searchedItems, count]); - - // 最终的返回结果 - const resultItems = useMemo(() => { - // isMenuType 为了 `useSchemaInitializerMenuItems()` 里面处理判断标识的 - const res: any[] = [ - // 开头:搜索框 - Object.assign( - { - key: 'search', - label: ( - { - setCount(STEP); - setSearchValue(val); - }} - /> - ), - onClick({ domEvent }) { - domEvent.stopPropagation(); - }, - }, - showType ? { isMenuType: true } : {}, - ), - ]; - - // 中间:搜索的数据 - if (limitedSearchedItems.length > 0) { - // 有搜索结果 - res.push(...limitedSearchedItems); - if (shouldLoadMore) { - res.push( - Object.assign( - { - key: 'load-more', - label: ( - { - setCount((count) => count + STEP); - }} - /> - ), - }, - showType ? { isMenuType: true } : {}, - ), - ); - } - } else { - // 搜索结果为空 - res.push( - Object.assign( - { - key: 'empty', - style: { - height: 150, - }, - label: ( -
e.stopPropagation()}> - -
- ), - }, - showType ? { isMenuType: true } : {}, - ), - ); - } - - return res; - }, [limitedSearchedItems, searchValue, shouldLoadMore, showType]); - - return resultItems; -} - -export function useMenuSearchV2(data: any, openKey: string, showType?: boolean) { +export function useMenuSearch(data: any, openKey: string, showType?: boolean) { const [searchValue, setSearchValue] = useState(''); const [count, setCount] = useState(STEP); @@ -390,17 +287,12 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => { }, [createBlockSchema, getTemplateSchemaByMode, insert, isCusomeizeCreate, onCreateBlockSchema, templateWrap], ); - // const defaultItems = useCollectionDataSourceItemsV2(componentType); - const defaultItemsV2 = useCollectionDataSourceItemsV3(componentType, filter); - // const menuChildren = useMemo(() => items || defaultItems, [items, defaultItems]); - // const childItems = useSchemaInitializerMenuItems(menuChildren, name, onClick); - const getMenuItems = useSchemaInitializerMenuItemsV2(onClick); - const childItemsV2 = useMemo(() => getMenuItems(defaultItemsV2, name), [defaultItemsV2]); - // const [isOpenSubMenu, setIsOpenSubMenu] = useState(false); + const items = useCollectionDataSourceItems(componentType, filter); + console.log('items', items); + const getMenuItems = useGetSchemaInitializerMenuItems(onClick); + const childItems = useMemo(() => getMenuItems(items, name), [items]); const [openMenuKey, setOpenMenuKey] = useState(''); - // const searchedChildren = useMenuSearch(childItems, isOpenSubMenu); - const searchedChildrenV2 = useMenuSearchV2(childItemsV2, openMenuKey); - + const searchedChildren = useMenuSearch(childItems, openMenuKey); const compiledMenuItems = useMemo( () => [ { @@ -411,13 +303,12 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => { if (info.key !== name) return; onClick({ ...info, item: props }); }, - children: searchedChildrenV2, - // children: searchedChildren, + children: searchedChildren, }, ], - [name, compile, title, icon, childItemsV2, onClick, props], + [name, compile, title, icon, childItems, onClick, props], ); - if (childItemsV2.length > 0) { + if (childItems.length > 0) { return ( { diff --git a/packages/core/client/src/schema-initializer/utils.ts b/packages/core/client/src/schema-initializer/utils.ts index cd42e852ee..6d48c79d3b 100644 --- a/packages/core/client/src/schema-initializer/utils.ts +++ b/packages/core/client/src/schema-initializer/utils.ts @@ -864,50 +864,7 @@ export const useRecordCollectionDataSourceItems = ( ]; }; -export const useCollectionDataSourceItems = (componentName) => { - const { t } = useTranslation(); - const { collections, getCollectionFields } = useCollectionManager(); - const { getTemplatesByCollection } = useSchemaTemplateManager(); - - return [ - { - type: 'itemGroup', - title: null, - children: [], - loadChildren: ({ searchValue } = { searchValue: '' }) => { - return getChildren({ - collections, - getCollectionFields, - componentName, - searchValue, - getTemplatesByCollection, - t, - }); - }, - }, - ]; -}; - -export const useCollectionDataSourceItemsV2 = (componentName) => { - const { t } = useTranslation(); - const { collections, getCollectionFields } = useCollectionManager(); - const { getTemplatesByCollection } = useSchemaTemplateManager(); - - const res = useMemo(() => { - return getChildren({ - collections, - getCollectionFields, - componentName, - searchValue: '', - getTemplatesByCollection, - t, - }); - }, [collections, componentName, getCollectionFields, getTemplatesByCollection, t]); - - return res; -}; - -export const useCollectionDataSourceItemsV3 = ( +export const useCollectionDataSourceItems = ( componentName, filter: (collection: CollectionV2) => boolean = () => true, ) => { @@ -1697,7 +1654,7 @@ const getChildrenV3 = ({ } }) ?.map((item, index) => { - const title = item.title || item.tableName; + const title = item.title || item.tableName || item.label; const templates = getTemplatesByCollection(item.name).filter((template) => { return ( componentName && diff --git a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/SchemaConfig.tsx b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/SchemaConfig.tsx index aade8c6bd3..673d296bba 100644 --- a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/SchemaConfig.tsx +++ b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/SchemaConfig.tsx @@ -25,6 +25,7 @@ import { css, gridRowColWrap, useCollectionManager, + useCollectionManagerV2, useCompile, useFormActiveFields, useFormBlockContext, @@ -68,7 +69,7 @@ export type FormType = { export type ManualFormType = { title: string; config: { - useInitializer: ({ collections }?: { collections: any[] }) => SchemaInitializerItemType; + useInitializer: ({ allCollections }?: { allCollections: any[] }) => SchemaInitializerItemType; initializers?: { [key: string]: React.FC; }; @@ -164,10 +165,11 @@ export const addBlockButton: SchemaInitializer = new SchemaInitializer({ name: 'form', title: '{{t("Form")}}', useChildren() { - const { collections } = useCollectionManager(); + const cm = useCollectionManagerV2(); + const allCollections = cm.getAllCollections((collection) => !collection.isLocal); return Array.from(manualFormTypes.getValues()).map((item: ManualFormType) => { const { useInitializer: getInitializer } = item.config; - return getInitializer({ collections }); + return getInitializer({ allCollections }); }); }, }, @@ -412,11 +414,9 @@ export function SchemaConfig({ value, onChange }) { const form = useForm(); const { workflow } = useFlowContext(); - const nodeInitializers = {}; const nodeComponents = {}; nodes.forEach((item) => { const instruction = workflowPlugin.instructions.get(item.type); - Object.assign(nodeInitializers, instruction.initializers); Object.assign(nodeComponents, instruction.components); }); diff --git a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/create.tsx b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/create.tsx index e1fde959ac..0e0cdf1237 100644 --- a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/create.tsx +++ b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/create.tsx @@ -8,6 +8,7 @@ import { SchemaSettingsLinkageRules, SchemaSettingsRemove, useCollection, + useGetSchemaInitializerMenuItems, useMenuSearch, } from '@nocobase/client'; @@ -39,26 +40,34 @@ function CreateFormDesigner() { export default { title: `{{t("Create record form", { ns: "${NAMESPACE}" })}}`, config: { - useInitializer({ collections }) { - const childItems = useMemo( + useInitializer({ allCollections }) { + const items = useMemo( () => - collections.map((item) => ({ - name: _.camelCase(`createRecordForm-child-${item.name}`), - type: 'item', - title: item.title, - label: item.label, - schema: { - collection: item.name, - title: `{{t("Create record", { ns: "${NAMESPACE}" })}}`, - formType: 'create', - 'x-designer': 'CreateFormDesigner', - }, - Component: FormBlockInitializer, + allCollections.map(({ nsName, nsTitle, collections }) => ({ + name: nsName, + label: nsTitle, + type: 'subMenu', + children: collections.map((item) => ({ + name: _.camelCase(`createRecordForm-child-${item.name}`), + type: 'item', + title: item.title || item.tableName, + schema: { + collection: item.name, + namespace: nsName, + title: `{{t("Create record", { ns: "${NAMESPACE}" })}}`, + formType: 'create', + 'x-designer': 'CreateFormDesigner', + }, + Component: FormBlockInitializer, + })), })), - [collections], + [allCollections], ); - const [isOpenSubMenu, setIsOpenSubMenu] = useState(false); - const searchedChildren = useMenuSearch(childItems, isOpenSubMenu, true); + const getMenuItems = useGetSchemaInitializerMenuItems(); + const childItems = useMemo(() => getMenuItems(items, 'createRecordForm'), [items]); + const [openMenuKey, setOpenMenuKey] = useState(''); + const searchedChildren = useMenuSearch(childItems, openMenuKey); + return { name: 'createRecordForm', key: 'createRecordForm', @@ -66,7 +75,11 @@ export default { title: `{{t("Create record form", { ns: "${NAMESPACE}" })}}`, componentProps: { onOpenChange(keys) { - setIsOpenSubMenu(keys.length > 0); + if (keys.length === 2) { + setOpenMenuKey(keys[1]); + } else if (keys.length === 0) { + setOpenMenuKey(''); + } }, }, children: searchedChildren, diff --git a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/update.tsx b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/update.tsx index 2a8e26eee4..a5bdfa75ea 100644 --- a/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/update.tsx +++ b/packages/plugins/@nocobase/plugin-workflow-manual/src/client/instruction/forms/update.tsx @@ -12,6 +12,7 @@ import { SchemaSettingsRemove, useCollection, useCollectionFilterOptions, + useCollectionManagerV2, useDesignable, useMenuSearch, } from '@nocobase/client'; @@ -76,26 +77,31 @@ function UpdateFormDesigner() { export default { title: `{{t("Update record form", { ns: "${NAMESPACE}" })}}`, config: { - useInitializer({ collections }) { + useInitializer({ allCollections }) { const childItems = useMemo( () => - collections.map((item) => ({ - name: _.camelCase(`updateRecordForm-child-${item.name}`), - type: 'item', - title: item.title, - label: item.label, - schema: { - collection: item.name, - title: `{{t("Update record", { ns: "${NAMESPACE}" })}}`, - formType: 'update', - 'x-designer': 'UpdateFormDesigner', - }, - Component: FormBlockInitializer, + allCollections.map(({ nsName, nsTitle, collections }) => ({ + name: nsName, + label: nsTitle, + type: 'subMenu', + children: collections.map((item) => ({ + name: _.camelCase(`updateRecordForm-child-${item.name}`), + type: 'item', + title: item.title || item.tableName, + schema: { + collection: item.name, + namespace: nsName, + title: `{{t("Update record", { ns: "${NAMESPACE}" })}}`, + formType: 'update', + 'x-designer': 'UpdateFormDesigner', + }, + Component: FormBlockInitializer, + })), })), - [collections], + [allCollections], ); - const [isOpenSubMenu, setIsOpenSubMenu] = useState(false); - const searchedChildren = useMenuSearch(childItems, isOpenSubMenu, true); + const [openMenuKey, setOpenMenuKey] = useState(''); + const searchedChildren = useMenuSearch(childItems, openMenuKey); return { name: 'updateRecordForm', key: 'updateRecordForm', @@ -103,7 +109,11 @@ export default { title: `{{t("Update record form", { ns: "${NAMESPACE}" })}}`, componentProps: { onOpenChange(keys) { - setIsOpenSubMenu(keys.length > 0); + if (keys.length === 2) { + setOpenMenuKey(keys[1]); + } else if (keys.length === 0) { + setOpenMenuKey(''); + } }, }, children: searchedChildren, diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/executions.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/executions.tsx index 06d8ae50d6..4fb7d67f8a 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/executions.tsx +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/executions.tsx @@ -9,7 +9,7 @@ import { message } from 'antd'; import { getWorkflowDetailPath } from '../constant'; export const executionCollection = { - name: 'executions', + name: 'executions-1', fields: [ { interface: 'createdAt', diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/workflows.ts b/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/workflows.ts index a72a1c224a..866776b38c 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/workflows.ts +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/schemas/workflows.ts @@ -8,7 +8,7 @@ import React from 'react'; import { executionSchema } from './executions'; const collection = { - name: 'workflows', + name: 'workflows-1', fields: [ { type: 'string',