fix: improve code

This commit is contained in:
dream2023 2024-01-17 21:54:18 +08:00
parent 2724521000
commit d2d5532127
10 changed files with 85 additions and 284 deletions

View File

@ -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<MenuProps> = (props) => {
};
export const SchemaInitializerSubMenu: FC<SchemaInitializerSubMenuProps> = (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<SchemaInitializerSubMenuProps> = (prop
},
];
}, [childrenItems, compile, icon, name, others, title]);
return <SchemaInitializerMenu items={items}></SchemaInitializerMenu>;
return <SchemaInitializerMenu onOpenChange={onOpenChange} items={items}></SchemaInitializerMenu>;
};
export const SchemaInitializerSubMenuInternal = () => {

View File

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

View File

@ -43,7 +43,6 @@ export {
useAssociatedFormItemInitializerFields,
useAssociatedTableColumnInitializerFields,
useCollectionDataSourceItems,
useCollectionDataSourceItemsV2,
useCurrentSchema,
useFormItemInitializerFields,
useInheritsTableColumnInitializerFields,

View File

@ -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<MenuProps['items']>(() => {
// isMenuType 为了 `useSchemaInitializerMenuItems()` 里面处理判断标识的
const res: any[] = [
// 开头:搜索框
Object.assign(
{
key: 'search',
label: (
<SearchCollections
value={searchValue}
onChange={(val: string) => {
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: (
<LoadingItem
maxHeight={STEP * MENU_ITEM_HEIGHT}
loadMore={() => {
setCount((count) => count + STEP);
}}
/>
),
},
showType ? { isMenuType: true } : {},
),
);
}
} else {
// 搜索结果为空
res.push(
Object.assign(
{
key: 'empty',
style: {
height: 150,
},
label: (
<div onClick={(e) => e.stopPropagation()}>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</div>
),
},
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 (
<SchemaInitializerMenu
onOpenChange={(keys) => {

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@ import { message } from 'antd';
import { getWorkflowDetailPath } from '../constant';
export const executionCollection = {
name: 'executions',
name: 'executions-1',
fields: [
{
interface: 'createdAt',

View File

@ -8,7 +8,7 @@ import React from 'react';
import { executionSchema } from './executions';
const collection = {
name: 'workflows',
name: 'workflows-1',
fields: [
{
type: 'string',