From 847eacce705e2c119c2c50eab2afe2e64dadb1ea Mon Sep 17 00:00:00 2001 From: katherinehhh Date: Sun, 20 Aug 2023 11:03:43 +0800 Subject: [PATCH 1/8] fix: tagcolor value error (#2487) --- .../schema-component/antd/association-field/InternalTag.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/client/src/schema-component/antd/association-field/InternalTag.tsx b/packages/core/client/src/schema-component/antd/association-field/InternalTag.tsx index e70862e05..f5b6177b4 100644 --- a/packages/core/client/src/schema-component/antd/association-field/InternalTag.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/InternalTag.tsx @@ -41,11 +41,10 @@ export const ReadPrettyInternalTag: React.FC = observer( const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label'); const { snapshot } = useActionContext(); const ellipsisWithTooltipRef = useRef(); - const tagColor = flat(recordCtx)[`${fieldSchema.name}.${tagColorField}`]; const renderRecords = () => toArr(props.value).map((record, index, arr) => { const val = toValue(compile(record?.[fieldNames?.label || 'label']), 'N/A'); - const text = getTabFormatValue(compile(labelUiSchema), val, tagColor); + const text = getTabFormatValue(compile(labelUiSchema), val, record[tagColorField]); return ( From 95e1cd390b0bce8a66e366e179e77a729805f296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=AB=E9=9B=A8=E6=B0=B4=E8=BF=87=E6=BB=A4=E7=9A=84?= =?UTF-8?q?=E7=A9=BA=E6=B0=94-Rain?= <958414905@qq.com> Date: Sun, 20 Aug 2023 12:08:07 +0800 Subject: [PATCH 2/8] chore: remove Default value option for sequence field (#2488) * chore: remove Default value option for sequence field * chore: remove console.log --- .../antd/form-item/FormItem.tsx | 3 +- .../src/schema-settings/SchemaSettings.tsx | 30 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx index 75fac30cb..a481f007a 100644 --- a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx +++ b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx @@ -1,5 +1,5 @@ import { css, cx } from '@emotion/css'; -import { ArrayCollapse, ArrayItems, FormLayout, FormItem as Item } from '@formily/antd-v5'; +import { ArrayCollapse, FormLayout, FormItem as Item } from '@formily/antd-v5'; import { Field } from '@formily/core'; import { ISchema, observer, useField, useFieldSchema } from '@formily/react'; import { Select } from 'antd'; @@ -70,6 +70,7 @@ export const FormItem: any = observer( const variablesCtx = useVariablesCtx(); const { getCollectionJoinField } = useCollectionManager(); const collectionField = getCollectionJoinField(schema['x-collection-field']); + useEffect(() => { if (ctx?.block === 'form') { ctx.field.data = ctx.field.data || {}; diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index eef1603d5..8b8df1eaa 100644 --- a/packages/core/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/core/client/src/schema-settings/SchemaSettings.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/css'; import { ArrayCollapse, ArrayItems, FormItem, FormLayout, Input } from '@formily/antd-v5'; -import { createForm, Field, GeneralField } from '@formily/core'; +import { Field, GeneralField, createForm } from '@formily/core'; import { ISchema, Schema, SchemaOptionsContext, useField, useFieldSchema, useForm } from '@formily/react'; import { uid } from '@formily/shared'; import { error } from '@nocobase/utils/client'; @@ -21,33 +21,34 @@ import { } from 'antd'; import _, { cloneDeep } from 'lodash'; import React, { - createContext, ReactNode, + createContext, useCallback, useContext, useMemo, - useState, // @ts-ignore useTransition as useReactTransition, + useState, } from 'react'; import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; import { - ActionContextProvider, APIClientProvider, + ActionContextProvider, CollectionFieldOptions, CollectionManagerContext, CollectionProvider, - createDesignable, Designable, - findFormBlock, FormDialog, FormProvider, RemoteSchemaComponent, SchemaComponent, SchemaComponentContext, SchemaComponentOptions, + createDesignable, + findFormBlock, useAPIClient, + useActionContext, useBlockRequestContext, useCollection, useCollectionManager, @@ -57,7 +58,6 @@ import { useGlobalTheme, useLinkageCollectionFilterOptions, useSortFields, - useActionContext, } from '..'; import { useTableBlockContext } from '../block-provider'; import { findFilterTargets, updateFilterTargets } from '../block-provider/hooks'; @@ -1678,9 +1678,19 @@ SchemaSettings.SortingRule = function SortRuleConfigure(props) { // 是否显示默认值配置项 export const isShowDefaultValue = (collectionField: CollectionFieldOptions, getInterface) => { return ( - !['o2o', 'oho', 'obo', 'o2m', 'attachment', 'expression', 'point', 'lineString', 'circle', 'polygon'].includes( - collectionField?.interface, - ) && !isSystemField(collectionField, getInterface) + ![ + 'o2o', + 'oho', + 'obo', + 'o2m', + 'attachment', + 'expression', + 'point', + 'lineString', + 'circle', + 'polygon', + 'sequence', + ].includes(collectionField?.interface) && !isSystemField(collectionField, getInterface) ); }; From a59ed4ee172845ca1d6549f0453f421355e4009b Mon Sep 17 00:00:00 2001 From: Junyi Date: Sun, 20 Aug 2023 16:45:46 +0700 Subject: [PATCH 3/8] fix(plugin-workflow): fix variable type check (#2492) * fix(plugin-workflow): fix variable type check * fix(plugin-workflow): fix node job button style --- .../workflow/src/client/nodes/aggregate.tsx | 5 +-- .../workflow/src/client/nodes/index.tsx | 2 ++ .../plugins/workflow/src/client/variable.tsx | 33 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/plugins/workflow/src/client/nodes/aggregate.tsx b/packages/plugins/workflow/src/client/nodes/aggregate.tsx index 3812fd307..5e19e119c 100644 --- a/packages/plugins/workflow/src/client/nodes/aggregate.tsx +++ b/packages/plugins/workflow/src/client/nodes/aggregate.tsx @@ -20,8 +20,9 @@ import { BaseTypeSets, defaultFieldNames, nodesOptions, triggerOptions } from '. function matchToManyField(field, appends): boolean { const fieldPrefix = `${field.name}.`; return ( - ['hasMany', 'belongsToMany'].includes(field.type) && - (appends ? appends.includes(field.name) || appends.some((item) => item.startsWith(fieldPrefix)) : true) + (['hasOne', 'belongsTo'].includes(field.type) && + (appends ? appends.includes(field.name) || appends.some((item) => item.startsWith(fieldPrefix)) : true)) || + ['hasMany', 'belongsToMany'].includes(field.type) ); } diff --git a/packages/plugins/workflow/src/client/nodes/index.tsx b/packages/plugins/workflow/src/client/nodes/index.tsx index 0a20c1dc7..d210f526f 100644 --- a/packages/plugins/workflow/src/client/nodes/index.tsx +++ b/packages/plugins/workflow/src/client/nodes/index.tsx @@ -265,6 +265,8 @@ export function JobButton() { border: 2px solid #d9d9d9; border-radius: 50%; cursor: not-allowed; + width: 24px; + height: 24px; `, )} /> diff --git a/packages/plugins/workflow/src/client/variable.tsx b/packages/plugins/workflow/src/client/variable.tsx index a3cd3baf9..5ee107ebe 100644 --- a/packages/plugins/workflow/src/client/variable.tsx +++ b/packages/plugins/workflow/src/client/variable.tsx @@ -165,28 +165,25 @@ function getNextAppends(field, appends: string[]) { function filterTypedFields({ fields, types, appends, compile, getCollectionFields }) { return fields.filter((field) => { - const match = types?.length ? types.some((type) => matchFieldType(field, type, appends)) : true; + if (types?.length) { + return types.some((type) => matchFieldType(field, type, appends)); + } if (isAssociationField(field)) { const nextAppends = getNextAppends(field, appends); const included = appends.includes(field.name); - if (match) { - return included; - } else { - return ( - (nextAppends.length || included) && - filterTypedFields({ - fields: getNormalizedFields(field.target, { compile, getCollectionFields }), - types, - // depth: depth - 1, - appends: nextAppends, - compile, - getCollectionFields, - }).length - ); - } - } else { - return match; + return ( + (nextAppends.length || included) && + filterTypedFields({ + fields: getNormalizedFields(field.target, { compile, getCollectionFields }), + types, + // depth: depth - 1, + appends: nextAppends, + compile, + getCollectionFields, + }).length + ); } + return true; }); } From 9e99b00182d809a05e71dbe76b3838c22f4ee3be Mon Sep 17 00:00:00 2001 From: jack zhang <1098626505@qq.com> Date: Sun, 20 Aug 2023 18:10:34 +0800 Subject: [PATCH 4/8] fix: dev load plugin (#2455) * fix: dev load plugin * fix: bug * fix: bug --- packages/core/app/client/.umirc.ts | 2 +- packages/core/app/client/src/pages/index.tsx | 4 +- .../client/src/application/Application.tsx | 7 +- .../client/src/application/PluginManager.ts | 7 +- .../src/application/utils/remotePlugins.ts | 21 ++-- packages/core/devtools/umiConfig.js | 95 ++++++++++++------- 6 files changed, 87 insertions(+), 49 deletions(-) diff --git a/packages/core/app/client/.umirc.ts b/packages/core/app/client/.umirc.ts index 6447221c6..013345e53 100644 --- a/packages/core/app/client/.umirc.ts +++ b/packages/core/app/client/.umirc.ts @@ -10,7 +10,7 @@ process.env.DID_YOU_KNOW = 'none'; const pluginPrefix = (process.env.PLUGIN_PACKAGE_PREFIX || '').split(',').filter((item) => !item.includes('preset')); // 因为现在 preset 是直接引入的,所以不能忽略,如果以后 preset 也是动态插件的形式引入,那么这里可以去掉 const pluginDirs = 'packages/plugins/,packages/samples/'.split(',').map((item) => path.join(process.cwd(), item)); -const outputPluginPath = path.join(__dirname, 'src', '.plugins', 'index.ts'); +const outputPluginPath = path.join(__dirname, 'src', '.plugins'); const indexGenerator = new IndexGenerator(outputPluginPath, pluginDirs); indexGenerator.generate(); diff --git a/packages/core/app/client/src/pages/index.tsx b/packages/core/app/client/src/pages/index.tsx index 514f9e1f9..d098cfbec 100644 --- a/packages/core/app/client/src/pages/index.tsx +++ b/packages/core/app/client/src/pages/index.tsx @@ -1,13 +1,13 @@ import { Application } from '@nocobase/client'; import { NocoBaseClientPresetPlugin } from '@nocobase/preset-nocobase/client'; -import devPlugins from '../.plugins/index'; +import devDynamicImport from '../.plugins/index'; export const app = new Application({ apiClient: { baseURL: process.env.API_BASE_URL, }, plugins: [NocoBaseClientPresetPlugin], - devPlugins, + devDynamicImport, }); export default app.getRootComponent(); diff --git a/packages/core/client/src/application/Application.tsx b/packages/core/client/src/application/Application.tsx index dbfec6725..3ce0ac745 100644 --- a/packages/core/client/src/application/Application.tsx +++ b/packages/core/client/src/application/Application.tsx @@ -24,6 +24,7 @@ declare global { } } +export type DevDynamicImport = (packageName: string) => Promise<{ default: typeof Plugin }>; export type ComponentAndProps = [ComponentType, T]; export interface ApplicationOptions { apiClient?: APIClientOptions; @@ -33,7 +34,7 @@ export interface ApplicationOptions { components?: Record; scopes?: Record; router?: RouterOptions; - devPlugins?: Record>; + devDynamicImport?: DevDynamicImport; } export class Application { @@ -44,12 +45,12 @@ export class Application { public apiClient: APIClient; public components: Record = { ...defaultAppComponents }; public pm: PluginManager; - public devPlugins: Record> = {}; + public devDynamicImport: DevDynamicImport; public requirejs: RequireJS; constructor(protected options: ApplicationOptions = {}) { this.initRequireJs(); - this.devPlugins = options.devPlugins || {}; + this.devDynamicImport = options.devDynamicImport; this.scopes = merge(this.scopes, options.scopes); this.components = merge(this.components, options.components); this.apiClient = new APIClient(options.apiClient); diff --git a/packages/core/client/src/application/PluginManager.ts b/packages/core/client/src/application/PluginManager.ts index e91e4c452..6285e29ea 100644 --- a/packages/core/client/src/application/PluginManager.ts +++ b/packages/core/client/src/application/PluginManager.ts @@ -17,7 +17,10 @@ export class PluginManager { protected pluginsAliases: Record = {}; private initPlugins: Promise; - constructor(protected _plugins: PluginType[], protected app: Application) { + constructor( + protected _plugins: PluginType[], + protected app: Application, + ) { this.app = app; this.initPlugins = this.init(_plugins); } @@ -43,7 +46,7 @@ export class PluginManager { requirejs: this.app.requirejs, pluginData: pluginList, baseURL: this.app.apiClient.axios?.defaults?.baseURL, - devPlugins: this.app.devPlugins, + devDynamicImport: this.app.devDynamicImport, }); for await (const plugin of plugins) { await this.add(plugin); diff --git a/packages/core/client/src/application/utils/remotePlugins.ts b/packages/core/client/src/application/utils/remotePlugins.ts index 2168ae3d3..e76709b75 100644 --- a/packages/core/client/src/application/utils/remotePlugins.ts +++ b/packages/core/client/src/application/utils/remotePlugins.ts @@ -1,6 +1,7 @@ import type { Plugin } from '../Plugin'; import type { PluginData } from '../PluginManager'; import type { RequireJS } from './requirejs'; +import type { DevDynamicImport } from '../Application'; export function defineDevPlugins(plugins: Record) { Object.entries(plugins).forEach(([name, plugin]) => { @@ -44,11 +45,11 @@ interface GetPluginsOption { requirejs: RequireJS; pluginData: PluginData[]; baseURL?: string; - devPlugins?: Record>; + devDynamicImport?: DevDynamicImport; } export async function getPlugins(options: GetPluginsOption): Promise> { - const { requirejs, pluginData, baseURL, devPlugins = {} } = options; + const { requirejs, pluginData, baseURL, devDynamicImport } = options; if (pluginData.length === 0) return []; @@ -57,16 +58,18 @@ export async function getPlugins(options: GetPluginsOption): Promise = {}; const pluginPackageNames = pluginData.map((item) => item.packageName); - for await (const packageName of pluginPackageNames) { - if (devPlugins[packageName]) { - const plugin = await devPlugins[packageName]; - plugins.push(plugin.default); - resolveDevPlugins[packageName] = plugin.default; + if (devDynamicImport) { + for await (const packageName of pluginPackageNames) { + const plugin = await devDynamicImport(packageName); + if (plugin) { + plugins.push(plugin.default); + resolveDevPlugins[packageName] = plugin.default; + } } + defineDevPlugins(resolveDevPlugins); } - defineDevPlugins(resolveDevPlugins); - const remotePlugins = pluginData.filter((item) => !devPlugins[item.packageName]); + const remotePlugins = pluginData.filter((item) => !resolveDevPlugins[item.packageName]); if (remotePlugins.length === 0) { return plugins; diff --git a/packages/core/devtools/umiConfig.js b/packages/core/devtools/umiConfig.js index 43a2be8ff..59c5868fc 100644 --- a/packages/core/devtools/umiConfig.js +++ b/packages/core/devtools/umiConfig.js @@ -105,70 +105,101 @@ class IndexGenerator { this.pluginsPath = pluginsPath; } + get indexPath() { + return path.join(this.outputPath, 'index.ts'); + } + + get packageMapPath() { + return path.join(this.outputPath, 'packageMap.json'); + } + + get packagesPath() { + return path.join(this.outputPath, 'packages'); + } + generate() { - this.generatePluginIndex(); + this.generatePluginContent(); if (process.env.NODE_ENV === 'production') return; this.pluginsPath.forEach((pluginPath) => { if (!fs.existsSync(pluginPath)) { return; } fs.watch(pluginPath, { recursive: false }, () => { - this.generatePluginIndex(); + this.generatePluginContent(); }); }); } - generatePluginIndex() { - if (!fs.existsSync(this.outputPath)) { - fs.mkdirSync(path.dirname(this.outputPath), { recursive: true }); - fs.writeFileSync(this.outputPath, 'export default {}'); + get indexContent() { + return `// @ts-nocheck +import packageMap from './packageMap.json'; + +function devDynamicImport(packageName: string): Promise { + const fileName = packageMap[packageName]; + if (!fileName) { + return Promise.resolve(null); + } + return import(\`./packages/\${fileName}\`) +} +export default devDynamicImport;`; + } + + get emptyIndexContent() { + return ` +export default function devDynamicImport(packageName: string): Promise { + return Promise.resolve(null); +}`; + } + + generatePluginContent() { + if (fs.existsSync(this.outputPath)) { + fs.rmdirSync(this.outputPath, { recursive: true, force: true }); } + fs.mkdirSync(this.outputPath); const validPluginPaths = this.pluginsPath.filter((pluginPath) => fs.existsSync(pluginPath)); - if (!validPluginPaths.length) { + if (!validPluginPaths.length || process.env.NODE_ENV === 'production') { + fs.writeFileSync(this.indexPath, this.emptyIndexContent); return; } - if (process.env.NODE_ENV === 'production') { - fs.writeFileSync(this.outputPath, 'export default {}'); - return; - } - const pluginInfo = validPluginPaths.map((pluginPath) => this.getContent(pluginPath)); - const importContent = pluginInfo.map(({ indexContent }) => indexContent).join('\n'); - const exportContent = pluginInfo.map(({ exportContent }) => exportContent).join('\n'); - const fileContent = `${importContent}\n\nexport default {\n${exportContent}\n}`; + const pluginInfos = validPluginPaths.map((pluginPath) => this.getContent(pluginPath)).flat(); - fs.writeFileSync(this.outputPath, fileContent); + // index.ts + fs.writeFileSync(this.indexPath, this.indexContent); + // packageMap.json + const packageMapContent = pluginInfos.reduce((memo, item) => { + memo[item.packageJsonName] = item.pluginFileName + '.ts'; + return memo; + }, {}); + fs.writeFileSync(this.packageMapPath, JSON.stringify(packageMapContent, null, 2)); + // packages + fs.mkdirSync(this.packagesPath, { recursive: true }); + pluginInfos.forEach((item) => { + const pluginPackagePath = path.join(this.packagesPath, item.pluginFileName + '.ts'); + fs.writeFileSync(pluginPackagePath, item.exportStatement); + }); } getContent(pluginPath) { const pluginFolders = fs.readdirSync(pluginPath); - const pluginImports = pluginFolders + const pluginInfos = pluginFolders .filter((folder) => { const pluginPackageJsonPath = path.join(pluginPath, folder, 'package.json'); const pluginSrcClientPath = path.join(pluginPath, folder, 'src', 'client'); return fs.existsSync(pluginPackageJsonPath) && fs.existsSync(pluginSrcClientPath); }) - .map((folder, index) => { + .map((folder) => { const pluginPackageJsonPath = path.join(pluginPath, folder, 'package.json'); const pluginPackageJson = require(pluginPackageJsonPath); const pluginSrcClientPath = path - .relative(path.dirname(this.outputPath), path.join(pluginPath, folder, 'src', 'client')) + .relative(this.packagesPath, path.join(pluginPath, folder, 'src', 'client')) .replaceAll('\\', '/'); - const pluginName = `${folder.replaceAll('-', '_')}${index}`; - const importStatement = `const ${pluginName} = import('${pluginSrcClientPath}');`; - return { importStatement, pluginName, packageJsonName: pluginPackageJson.name }; + const pluginFileName = `${path.basename(pluginPath)}_${folder.replaceAll('-', '_')}`; + const exportStatement = `export { default } from '${pluginSrcClientPath}';`; + return { exportStatement, pluginFileName, packageJsonName: pluginPackageJson.name }; }); - const indexContent = pluginImports.map(({ importStatement }) => importStatement).join('\n'); - - const exportContent = pluginImports - .map(({ pluginName, packageJsonName }) => ` "${packageJsonName}": ${pluginName},`) - .join('\n'); - - return { - indexContent, - exportContent, - }; + return pluginInfos; } } From f70d17c5cdc51d9cedb6f1a45ada2ba76e265343 Mon Sep 17 00:00:00 2001 From: katherinehhh Date: Sun, 20 Aug 2023 20:54:32 +0800 Subject: [PATCH 5/8] fix: view collection reported error when editing (#2493) --- packages/core/client/src/collection-manager/templates/view.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/core/client/src/collection-manager/templates/view.tsx b/packages/core/client/src/collection-manager/templates/view.tsx index bf5ca5528..f2308f6e9 100644 --- a/packages/core/client/src/collection-manager/templates/view.tsx +++ b/packages/core/client/src/collection-manager/templates/view.tsx @@ -132,9 +132,6 @@ export const view: ICollectionTemplate = { schema: { 'x-component-props': '{{$form.values}}', //任意层次属性都支持表达式 }, - state: { - visible: `{{$deps[1]?.length > 0}}`, - }, }, }, }, From ccf8b651ffc65133bbe27272a9b2d1c253097419 Mon Sep 17 00:00:00 2001 From: katherinehhh Date: Mon, 21 Aug 2023 11:27:48 +0800 Subject: [PATCH 6/8] refactor(graph-collection-manager): update antv-x6 to 2.x (#2466) * refactor: update antv-x6 to 2.x * refactor: code improve * refactor: code improve * refactor: code improve * refactor: code improve * refactor: code improve * refactor: code improve --- .../Configuration/EditFieldAction.tsx | 3 + .../Configuration/ViewInheritedField.tsx | 3 + .../components/CollectionCategory.tsx | 6 +- .../graph-collection-manager/package.json | 10 +- .../src/client/GraphCollectionProvider.tsx | 3 - .../src/client/GraphDrawPage.tsx | 898 +++++++++--------- .../src/client/action-hooks.tsx | 2 +- .../src/client/components/Entity.tsx | 640 ++++++------- .../src/client/utils.tsx | 16 +- 9 files changed, 772 insertions(+), 809 deletions(-) diff --git a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx index 92b1dae27..5a1535e63 100644 --- a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx @@ -55,6 +55,9 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema [uid()]: { type: 'void', 'x-component': 'Action.Drawer', + 'x-component-props': { + getContainer: '{{ getContainer }}', + }, 'x-decorator': 'Form', 'x-decorator-props': { useValues(options) { diff --git a/packages/core/client/src/collection-manager/Configuration/ViewInheritedField.tsx b/packages/core/client/src/collection-manager/Configuration/ViewInheritedField.tsx index 892823bf3..94da22b84 100644 --- a/packages/core/client/src/collection-manager/Configuration/ViewInheritedField.tsx +++ b/packages/core/client/src/collection-manager/Configuration/ViewInheritedField.tsx @@ -29,6 +29,9 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema [uid()]: { type: 'void', 'x-component': 'Action.Drawer', + 'x-component-props': { + getContainer: '{{ getContainer }}', + }, 'x-decorator': 'Form', 'x-decorator-props': { useValues(options) { diff --git a/packages/core/client/src/collection-manager/Configuration/components/CollectionCategory.tsx b/packages/core/client/src/collection-manager/Configuration/components/CollectionCategory.tsx index 39e9d3e3f..109671e2c 100644 --- a/packages/core/client/src/collection-manager/Configuration/components/CollectionCategory.tsx +++ b/packages/core/client/src/collection-manager/Configuration/components/CollectionCategory.tsx @@ -10,7 +10,11 @@ export const CollectionCategory = observer( return ( <> {value.map((item) => { - return {compile(item?.name)}; + return ( + + {compile(item?.name)} + + ); })} ); diff --git a/packages/plugins/graph-collection-manager/package.json b/packages/plugins/graph-collection-manager/package.json index 68f680c73..34e3b733c 100644 --- a/packages/plugins/graph-collection-manager/package.json +++ b/packages/plugins/graph-collection-manager/package.json @@ -9,8 +9,14 @@ "main": "./dist/server/index.js", "devDependencies": { "@ant-design/icons": "5.x", - "@antv/x6": "^1.9.0", - "@antv/x6-react-shape": "^1.6.2", + "@antv/x6": "^2.0.0", + "@antv/x6-plugin-minimap": "^2.0.0", + "@antv/x6-plugin-scroller": "^2.0.0", + "@antv/x6-plugin-selection": "^2.0.0", + "@antv/x6-plugin-snapline": "^2.0.0", + "@antv/x6-plugin-dnd": "^2.0.0", + "@antv/x6-plugin-export": "^2.0.0", + "@antv/x6-react-shape": "^2.0.0", "@formily/react": "2.x", "@formily/reactive": "2.x", "@formily/shared": "2.x", diff --git a/packages/plugins/graph-collection-manager/src/client/GraphCollectionProvider.tsx b/packages/plugins/graph-collection-manager/src/client/GraphCollectionProvider.tsx index 298fb77cb..1085dad0b 100644 --- a/packages/plugins/graph-collection-manager/src/client/GraphCollectionProvider.tsx +++ b/packages/plugins/graph-collection-manager/src/client/GraphCollectionProvider.tsx @@ -5,9 +5,6 @@ import { useGCMTranslation } from './utils'; export const GraphCollectionProvider = React.memo((props) => { const ctx = useContext(PluginManagerContext); - // i18n.addResources('en-US', 'graphPositions', enUS); - // i18n.addResources('ja-JP', 'graphPositions', jaJP); - // i18n.addResources('zh-CN', 'graphPositions', zhCN); const { t } = useGCMTranslation(); const items = useContext(SettingsCenterContext); diff --git a/packages/plugins/graph-collection-manager/src/client/GraphDrawPage.tsx b/packages/plugins/graph-collection-manager/src/client/GraphDrawPage.tsx index 2231a4e7c..843bad9fe 100644 --- a/packages/plugins/graph-collection-manager/src/client/GraphDrawPage.tsx +++ b/packages/plugins/graph-collection-manager/src/client/GraphDrawPage.tsx @@ -7,7 +7,11 @@ import { ShareAltOutlined, } from '@ant-design/icons'; import { Graph } from '@antv/x6'; -import '@antv/x6-react-shape'; +import { register } from '@antv/x6-react-shape'; +import { Scroller } from '@antv/x6-plugin-scroller'; +import { MiniMap } from '@antv/x6-plugin-minimap'; +import { Selection } from '@antv/x6-plugin-selection'; +import { Snapline } from '@antv/x6-plugin-snapline'; import { SchemaOptionsContext } from '@formily/react'; import { APIClientProvider, @@ -20,17 +24,16 @@ import { SchemaComponentOptions, Select, collection, - css, - cx, useAPIClient, useCollectionManager, useCompile, useCurrentAppInfo, useGlobalTheme, } from '@nocobase/client'; +import { css, cx } from '@emotion/css'; import lodash from 'lodash'; import { useFullscreen } from 'ahooks'; -import { Button, ConfigProvider, Input, Layout, Menu, Popover, Switch, Tooltip } from 'antd'; +import { Button, ConfigProvider, Input, Layout, Menu, Popover, Switch, Tooltip, App, Spin } from 'antd'; import dagre from 'dagre'; import React, { createContext, forwardRef, useContext, useEffect, useLayoutEffect, useState } from 'react'; import { useAsyncDataSource, useCreateActionAndRefreshCM } from './action-hooks'; @@ -47,7 +50,6 @@ import { getPopupContainer, useGCMTranslation, } from './utils'; - const { drop, groupBy, last, maxBy, minBy, take } = lodash; const LINE_HEIGHT = 40; @@ -90,11 +92,10 @@ async function layout(createPositions) { g.setNode(node.id, { width, height }); }); dagre.layout(g); - targetGraph.freeze(); const dNodes = getGridData(15, g.nodes()); dNodes.forEach((arr, row) => { arr.forEach((id, index) => { - const node = targetGraph.getCell(id); + const node = targetGraph.getCellById(id); const col = index % 15; if (node) { const targetPosition = @@ -119,7 +120,6 @@ async function layout(createPositions) { edges.forEach((edge) => { optimizeEdge(edge); }); - targetGraph.unfreeze(); if (targetNode) { typeof targetNode === 'string' ? targetGraph.positionCell(last(nodes), 'top', { padding: 100 }) @@ -141,13 +141,13 @@ function optimizeEdge(edge) { } = edge; const source = edge.getSource(); const target = edge.getTarget(); - const sorceNodeX = targetGraph.getCell(source.cell).position().x; - const targeNodeX = targetGraph.getCell(target.cell).position().x; + const sorceNodeX = targetGraph.getCellById(source.cell).position().x; + const targeNodeX = targetGraph.getCellById(target.cell).position().x; const leftAnchor = connectionType ? { name: 'topLeft', args: { - dy: -20, + dy: 20, }, } : { @@ -157,7 +157,7 @@ function optimizeEdge(edge) { ? { name: 'topRight', args: { - dy: -20, + dy: 20, }, } : 'right'; @@ -181,8 +181,8 @@ function optimizeEdge(edge) { direction: 'H', }); } else if (Math.abs(sorceNodeX - targeNodeX) < 100) { - const sourceCell = targetGraph.getCell(source.cell); - const targetCell = targetGraph.getCell(target.cell); + const sourceCell = targetGraph.getCellById(source.cell); + const targetCell = targetGraph.getCellById(target.cell); edge.setSource({ cell: source.cell, port: source.port, @@ -219,24 +219,6 @@ function optimizeEdge(edge) { } } -function getNodes(nodes) { - targetGraph.addNodes(nodes); -} - -function getEdges(edges) { - edges.forEach((item) => { - if (item.source && item.target) { - targetGraph.addEdge({ - ...item, - connector: { - name: 'normal', - zIndex: 1000, - }, - }); - } - }); -} - const CollapsedContext = createContext({}); const formatNodeData = () => { const layoutNodes = []; @@ -280,12 +262,11 @@ const handelResetLayout = () => { g.setEdge(source.cell, target.cell, {}); }); dagre.layout(g); - targetGraph.freeze(); const gNodes = g.nodes(); const nodeWithEdges = take(gNodes, linkNodes.length); const nodeWithoutEdges = drop(gNodes, linkNodes.length); nodeWithEdges.forEach((id) => { - const node = targetGraph.getCell(id); + const node = targetGraph.getCellById(id); const positionId = positions.find((v) => v.collectionName === node.id)?.id; if (node) { const pos = g.node(id); @@ -319,7 +300,7 @@ const handelResetLayout = () => { return Math.abs(targetGraph.getCellById(v).position().y - maxY) < 50; }); const referenceNode: any = targetGraph - .getCell(maxBy(yNodes, (k) => targetGraph.getCellById(k).position().x)) + .getCellById(maxBy(yNodes, (k) => targetGraph.getCellById(k).position().x)) ?.position(); num = Math.round(maxX / 320) || 1; alternateNum = Math.floor((4500 - (maxX + 100 - referenceNode.x)) / 280); @@ -328,7 +309,7 @@ const handelResetLayout = () => { const alternateNodes = take(nodeWithoutEdges, alternateNum); rawEntity = getGridData(num, drop(nodeWithoutEdges, alternateNum)); alternateNodes.forEach((id, index) => { - const node = targetGraph.getCell(id); + const node = targetGraph.getCellById(id); if (node) { const calculatedPosition = { x: referenceNode.x + 320 * index + 280, y: referenceNode.y }; node.position(calculatedPosition.x, calculatedPosition.y); @@ -346,7 +327,7 @@ const handelResetLayout = () => { } rawEntity.forEach((arr, row) => { arr.forEach((id, index) => { - const node = targetGraph.getCell(id); + const node = targetGraph.getCellById(id); const col = index % num; if (node) { const calculatedPosition = { x: col * 325 + minX, y: row * 300 + maxY + 300 }; @@ -359,7 +340,6 @@ const handelResetLayout = () => { edges.forEach((edge) => { optimizeEdge(edge); }); - targetGraph.unfreeze(); targetGraph.positionCell(nodes[0], 'top-left', { padding: 100 }); targetGraph.updatePositionAction(updatePositionData, true); }; @@ -374,7 +354,8 @@ export const GraphDrawPage = React.memo(() => { const { t } = useGCMTranslation(); const [collectionData, setCollectionData] = useState([]); const [collectionList, setCollectionList] = useState([]); - const { refreshCM } = useCollectionManager(); + const [loading, setLoading] = useState(false); + const { refreshCM, collections } = useCollectionManager(); const currentAppInfo = useCurrentAppInfo(); const { data: { database }, @@ -410,8 +391,8 @@ export const GraphDrawPage = React.memo(() => { refreshPositions(); } }; - const refreshGM = async () => { - const data = await refreshCM(); + const refreshGM = async (collections?) => { + const data = collections?.length > 0 ? collections : await refreshCM(); targetGraph.collections = data; targetGraph.updatePositionAction = updatePositionAction; const currentNodes = targetGraph.getNodes(); @@ -427,39 +408,8 @@ export const GraphDrawPage = React.memo(() => { targetGraph = new Graph({ container: document.getElementById('container')!, moveThreshold: 0, - scroller: { - enabled: true, - pannable: true, - padding: { top: 0, left: 500, right: 300, bottom: 400 }, - }, - selecting: { - enabled: false, - multiple: true, - rubberband: true, - movable: true, - className: 'node-selecting', - modifiers: 'shift', - }, - minimap: { - enabled: true, - container: document.getElementById('graph-minimap'), - width: 300, - height: 250, - padding: 10, - graphOptions: { - async: true, - getCellView(cell) { - if (cell.isNode()) { - return SimpleNodeView; - } - }, - createCellView(cell) { - if (cell.isEdge()) { - return null; - } - }, - }, - }, + virtual: false, + async: true, connecting: { anchor: { name: 'midSide', @@ -469,19 +419,9 @@ export const GraphDrawPage = React.memo(() => { enabled: true, modifiers: ['ctrl', 'meta'], }, - snapline: { - enabled: !0, - }, - keyboard: { - enabled: false, - }, - clipboard: { - enabled: false, - }, interacting: { magnetConnectable: false, }, - async: true, preventDefaultBlankAction: true, }); targetGraph.connectionType = ConnectionType.Both; @@ -502,11 +442,39 @@ export const GraphDrawPage = React.memo(() => { }, true, ); - Graph.registerNode( - 'er-rect', - { - inherit: 'react-shape', - component: (node) => ( + + register({ + shape: 'er-rect', + width: NODE_WIDTH, + height: LINE_HEIGHT, + ports: { + groups: { + list: { + markup: [ + { + tagName: 'rect', + selector: 'portBody', + }, + ], + attrs: { + portBody: { + width: NODE_WIDTH, + height: LINE_HEIGHT, + strokeWidth: 1, + // magnet: true, + visibility: 'hidden', + }, + }, + position: 'erPortPosition', + }, + }, + }, + body: { + refWidth: 100, + refHeight: 100, + }, + component: React.forwardRef((props, ref) => { + return ( @@ -519,7 +487,9 @@ export const GraphDrawPage = React.memo(() => { {/* TODO: 因为画布中的卡片是一次性注册进 Graph 的,这里的 theme 是存在闭包里的,因此当主题动态变更时,并不会触发卡片的重新渲染 */}
- + + +
@@ -527,35 +497,49 @@ export const GraphDrawPage = React.memo(() => {
- ), - ports: { - groups: { - list: { - markup: [ - { - tagName: 'rect', - selector: 'portBody', - }, - ], - attrs: { - portBody: { - width: NODE_WIDTH, - height: LINE_HEIGHT, - strokeWidth: 1, - // magnet: true, - visibility: 'hidden', - }, - }, - position: 'erPortPosition', - }, + ); + }), + }); + targetGraph.use( + new Scroller({ + enabled: true, + pannable: true, + padding: { top: 0, left: 500, right: 300, bottom: 400 }, + }), + ); + targetGraph.use( + new MiniMap({ + container: document.getElementById('graph-minimap'), + width: 300, + height: 250, + padding: 10, + graphOptions: { + async: true, + createCellView(cell) { + if (cell.isEdge()) { + return null; + } + if (cell.isNode()) { + return SimpleNodeView; + } }, }, - body: { - refWidth: 100, - refHeight: 100, - }, - }, - true, + }), + ); + targetGraph.use( + new Selection({ + enabled: false, + multiple: true, + rubberband: true, + movable: true, + className: 'node-selecting', + modifiers: 'shift', + }), + ); + targetGraph.use( + new Snapline({ + enabled: true, + }), ); targetGraph.on('edge:mouseleave', ({ e, edge: targetEdge }) => { e.stopPropagation(); @@ -594,7 +578,7 @@ export const GraphDrawPage = React.memo(() => { handleEdgeUnActive(targetGraph?.activeEdge); } targetGraph.collapseNodes?.map((v) => { - const node = targetGraph.getCell(Object.keys(v)[0]); + const node = targetGraph.getCellById(Object.keys(v)[0]); Object.values(v)[0] && node.setData({ collapse: false }); }); targetGraph.cleanSelection(); @@ -699,9 +683,7 @@ export const GraphDrawPage = React.memo(() => { const renderInitGraphCollection = (rawData) => { const { nodesData, edgesData, inheritEdges } = formatData(rawData); targetGraph.data = { nodes: nodesData, edges: edgesData }; - getNodes(nodesData); - getEdges(edgesData); - getEdges(inheritEdges); + targetGraph.fromJSON({ nodes: nodesData, edges: inheritEdges.concat(edgesData) }); layout(saveGraphPositionAction); }; @@ -784,7 +766,7 @@ export const GraphDrawPage = React.memo(() => { }; setTimeout(() => { renderDiffEdges(diffEdges.concat(diffInheritEdge)); - }); + }, 300); }; const handleSearchCollection = (e) => { @@ -1012,14 +994,18 @@ export const GraphDrawPage = React.memo(() => { }, []); useEffect(() => { + setLoading(true); refreshPositions() - .then(() => { - refreshGM(); + .then(async () => { + await refreshGM(collections); + setLoading(false); }) .catch((err) => { + setLoading(false); throw err; }); }, []); + const loadCollections = async () => { return targetGraph.collections?.map((collection: any) => ({ label: compile(collection.title), @@ -1029,359 +1015,361 @@ export const GraphDrawPage = React.memo(() => { return (
- - -
- ( - + ), + AddCollectionAction, + }} + schema={{ + type: 'void', + properties: { + block1: { + type: 'void', + 'x-collection': 'collections', + 'x-decorator': 'ResourceActionProvider', + 'x-decorator-props': { + collection, + request: { + resource: 'collections', + action: 'list', + params: { + pageSize: 50, + filter: { + inherit: false, + }, + sort: ['sort'], + appends: [], }, - sort: ['sort'], - appends: [], }, }, - }, - properties: { - actions: { - type: 'void', - 'x-component': 'ActionBar', - 'x-component-props': { - style: { - fontSize: 16, - }, - }, - properties: { - create: { - type: 'void', - title: '{{ t("Create collection") }}', - 'x-component': 'AddCollectionAction', - 'x-component-props': { - type: 'primary', + properties: { + actions: { + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + fontSize: 16, }, }, - fullScreen: { - type: 'void', - 'x-component': 'Action', - 'x-component-props': { - component: forwardRef(() => { - const [isFullscreen, { toggleFullscreen }] = useFullscreen( - document.getElementById('graph_container'), + properties: { + create: { + type: 'void', + title: '{{ t("Create collection") }}', + 'x-component': 'AddCollectionAction', + 'x-component-props': { + type: 'primary', + }, + }, + fullScreen: { + type: 'void', + 'x-component': 'Action', + 'x-component-props': { + component: forwardRef(() => { + const [isFullscreen, { toggleFullscreen }] = useFullscreen( + document.getElementById('graph_container'), + ); + return ( + + + + ); + }), + useAction: () => { + return { + run() {}, + }; + }, + }, + }, + collectionList: { + type: 'void', + 'x-component': function Com() { + const { handleSearchCollection, collectionList } = useContext(CollapsedContext); + const [selectedKeys, setSelectKey] = useState([]); + const content = ( +
+ + { + return { + key: v.name, + label: compile(v.title), + onClick: (e: any) => { + if (e.key !== selectedKeys[0]) { + setSelectKey([e.key]); + handleFiterCollections(e.key); + } else { + targetGraph.filterConfig = null; + handleFiterCollections(false); + setSelectKey([]); + } + }, + }; + }), + ]} + /> +
); return ( - - - - ); - }), - useAction: () => { - return { - run() {}, - }; - }, - }, - }, - collectionList: { - type: 'void', - 'x-component': function Com() { - const { handleSearchCollection, collectionList } = useContext(CollapsedContext); - const [selectedKeys, setSelectKey] = useState([]); - const content = ( -
- - { - return { - key: v.name, - label: compile(v.title), - onClick: (e: any) => { - if (e.key !== selectedKeys[0]) { - setSelectKey([e.key]); - handleFiterCollections(e.key); - } else { - targetGraph.filterConfig = null; - handleFiterCollections(false); - setSelectKey([]); - } - }, - }; - }), - ]} - /> -
- ); - return ( - - - - ); - }, - 'x-component-props': { - icon: 'MenuOutlined', - useAction: () => { - return { - run() {}, - }; + > + + + ); + }, + 'x-component-props': { + icon: 'MenuOutlined', + useAction: () => { + return { + run() {}, + }; + }, }, }, - }, - autoLayout: { - type: 'void', - 'x-component': 'Action', - 'x-component-props': { - component: forwardRef(() => { + autoLayout: { + type: 'void', + 'x-component': 'Action', + 'x-component-props': { + component: forwardRef(() => { + return ( + + + + ); + }), + useAction: () => { + return { + run() {}, + }; + }, + }, + }, + connectionType: { + type: 'void', + 'x-component': () => { + const menuItems = [ + { + key: ConnectionType.Both, + label: 'All relationships', + }, + { + key: ConnectionType.Entity, + label: 'Entity relationship only', + }, + { + key: ConnectionType.Inherit, + label: 'Inheritance relationship only', + }, + ]; + const content = ( +
+ { + return { + key: v.key, + label: t(v.label), + onClick: (e: any) => { + targetGraph.connectionType = v.key; + const { filterConfig } = targetGraph; + filterConfig && handleFiterCollections(filterConfig.key); + handleSetRelationshipType(v.key); + }, + }; + }), + ]} + /> +
+ ); return ( - - + + ); + }, + 'x-component-props': { + icon: 'MenuOutlined', + useAction: () => { + return { + run() {}, + }; + }, + }, + }, + direction: { + type: 'void', + 'x-component': () => { + const menuItems = [ + { + key: DirectionType.Both, + label: 'All directions', + }, + { + key: DirectionType.Target, + label: 'Target index', + }, + { + key: DirectionType.Source, + label: 'Source index', + }, + ]; + const content = ( +
+ { + return { + key: v.key, + label: t(v.label), + onClick: (e: any) => { + targetGraph.direction = v.key; + const { filterConfig } = targetGraph; + if (filterConfig) { + handleFiterCollections(filterConfig.key); + } + }, + }; + }), + ]} + /> +
+ ); + return ( + + + + ); + }, + }, + selectMode: { + type: 'void', + 'x-component': () => { + return ( + + { + targetGraph.toggleSelection(); + }} + /> ); - }), - useAction: () => { - return { - run() {}, - }; }, }, }, - connectionType: { - type: 'void', - 'x-component': () => { - const menuItems = [ - { - key: ConnectionType.Both, - label: 'All relationships', - }, - { - key: ConnectionType.Entity, - label: 'Entity relationship only', - }, - { - key: ConnectionType.Inherit, - label: 'Inheritance relationship only', - }, - ]; - const content = ( -
- { - return { - key: v.key, - label: t(v.label), - onClick: (e: any) => { - targetGraph.connectionType = v.key; - const { filterConfig } = targetGraph; - filterConfig && handleFiterCollections(filterConfig.key); - handleSetRelationshipType(v.key); - }, - }; - }), - ]} - /> -
- ); - return ( - - - - ); - }, - 'x-component-props': { - icon: 'MenuOutlined', - useAction: () => { - return { - run() {}, - }; - }, - }, - }, - direction: { - type: 'void', - 'x-component': () => { - const menuItems = [ - { - key: DirectionType.Both, - label: 'All directions', - }, - { - key: DirectionType.Target, - label: 'Target index', - }, - { - key: DirectionType.Source, - label: 'Source index', - }, - ]; - const content = ( -
- { - return { - key: v.key, - label: t(v.label), - onClick: (e: any) => { - targetGraph.direction = v.key; - const { filterConfig } = targetGraph; - if (filterConfig) { - handleFiterCollections(filterConfig.key); - } - }, - }; - }), - ]} - /> -
- ); - return ( - - - - ); - }, - }, - selectMode: { - type: 'void', - 'x-component': () => { - return ( - - { - targetGraph.toggleSelection(); - }} - /> - - ); - }, - }, }, }, }, }, - }, - }} - scope={{ - useAsyncDataSource, - loadCollections, - useCreateActionAndRefreshCM: () => useCreateActionAndRefreshCM(setTargetNode), - enableInherits: database?.dialect === 'postgres', - }} - /> -
-
-
-
-
+ }} + scope={{ + useAsyncDataSource, + loadCollections, + useCreateActionAndRefreshCM: () => useCreateActionAndRefreshCM(setTargetNode), + enableInherits: database?.dialect === 'postgres', + }} + /> +
+ + +
+
+
); diff --git a/packages/plugins/graph-collection-manager/src/client/action-hooks.tsx b/packages/plugins/graph-collection-manager/src/client/action-hooks.tsx index be8cb09d8..e2f68d139 100644 --- a/packages/plugins/graph-collection-manager/src/client/action-hooks.tsx +++ b/packages/plugins/graph-collection-manager/src/client/action-hooks.tsx @@ -10,7 +10,7 @@ import { } from '@nocobase/client'; import { error } from '@nocobase/utils/client'; import { Select, message } from 'antd'; -import { lodash } from '@nocobase/utils/client' +import { lodash } from '@nocobase/utils/client'; import React, { useContext, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { GraphCollectionContext } from './components/CollectionNodeProvder'; diff --git a/packages/plugins/graph-collection-manager/src/client/components/Entity.tsx b/packages/plugins/graph-collection-manager/src/client/components/Entity.tsx index 5dc3ffcdf..e132356d9 100644 --- a/packages/plugins/graph-collection-manager/src/client/components/Entity.tsx +++ b/packages/plugins/graph-collection-manager/src/client/components/Entity.tsx @@ -1,32 +1,21 @@ import { DeleteOutlined, DownOutlined, EditOutlined, UpOutlined } from '@ant-design/icons'; -import '@antv/x6-react-shape'; import { uid } from '@formily/shared'; +import { css } from '@emotion/css'; import { - Action, - Checkbox, CollectionCategroriesContext, - CollectionField, CollectionProvider, - Form, - FormItem, - Formula, - Grid, - Input, - InputNumber, - Radio, - ResourceActionProvider, SchemaComponent, SchemaComponentProvider, Select, collection, - css, useCollectionManager, useCompile, useCurrentAppInfo, useRecord, } from '@nocobase/client'; import lodash from 'lodash'; -import { Badge, Dropdown, Popover, Tag } from 'antd'; +import { SchemaOptionsContext } from '@formily/react'; +import { Badge, Popover, Tag } from 'antd'; import React, { useContext, useRef, useState } from 'react'; import { useAsyncDataSource, @@ -46,12 +35,306 @@ import { FieldSummary } from './FieldSummary'; import { OverrideFieldAction } from './OverrideFieldAction'; import { ViewFieldAction } from './ViewFieldAction'; +const OperationButton: any = React.memo((props: any) => { + const { property, loadCollections, collectionData, setTargetNode, node, handelOpenPorts, title, name } = props; + const isInheritField = !(property.collectionName !== name); + const options = useContext(SchemaOptionsContext); + const { + data: { database }, + } = useCurrentAppInfo(); + const useNewId = (prefix) => { + return `${prefix || ''}${uid()}`; + }; + // 获取当前字段列表 + const useCurrentFields = () => { + const record = useRecord(); + const { getCollectionFields } = useCollectionManager(); + const fields = getCollectionFields(record.collectionName || record.name) as any[]; + return fields; + }; + return ( +
+ - ), - Checkbox, - Radio, - InputNumber, - Grid, - FieldSummary, - Action, - EditOutlined, - DeleteOutlined, - AddFieldAction, - OverrideFieldAction, - ViewFieldAction, - Dropdown, - Formula, - }} - scope={{ - useAsyncDataSource, - loadCollections, - useCancelAction, - useNewId, - useCurrentFields, - useValuesFromRecord, - useUpdateCollectionActionAndRefreshCM, - isInheritField, - }} - > - handelOpenPorts(true)} - > - - useDestroyFieldActionAndRefreshCM({ - collectionName: property.collectionName, - name: property.name, - }), - }, - }, - override: { - type: 'void', - 'x-action': 'create', - 'x-visible': '{{!isInheritField}}', - 'x-component': 'OverrideFieldAction', - 'x-component-props': { - icon: 'ReconciliationOutlined', - item: { - ...property, - title, - __parent: collectionData.current, - targetCollection: name, - }, - }, - }, - view: { - type: 'void', - 'x-action': 'view', - 'x-visible': '{{!isInheritField}}', - 'x-component': 'ViewFieldAction', - 'x-component-props': { - icon: 'ReconciliationOutlined', - item: { - ...property, - title, - __parent: collectionData.current, - }, - }, - }, - }, - }} - /> - - -
- ); - }; - const { getInterface } = useCollectionManager(); - // 获取当前字段列表 - const useCurrentFields = () => { - const record = useRecord(); - const { getCollectionFields } = useCollectionManager(); - const fields = getCollectionFields(record.collectionName || record.name) as any[]; - return fields; - }; - const handelOpenPorts = (isCollapse?) => { - targetGraph.getCellById(item.name)?.toFront(); - setCollapse(isCollapse); - const collapseNodes = targetGraph.collapseNodes || []; - collapseNodes.push({ - [item.name]: isCollapse, - }); - targetGraph.collapseNodes = collapseNodes; - targetGraph.getCellById(item.name).setData({ collapse: true }); - }; - const isCollapse = collapse && data?.collapse; - return ( -
- {portsData['initPorts']?.map((property) => { - return ( - property.uiSchema && ( - - {compile(property.uiSchema?.title)} - - {compile(getInterface(property.interface)?.title)} - -
- } - key={property.id} - placement="right" - > -
-
- - {compile(property.uiSchema?.title)} -
-
{compile(getInterface(property.interface)?.title)}
- -
- - ) - ); - })} -
- {isCollapse && - portsData['morePorts']?.map((property) => { - return ( - property.uiSchema && ( - - {compile(property.uiSchema?.title)} - - {compile(getInterface(property.interface)?.title)} - -
- } - key={property.id} - placement="right" - > -
-
- - {compile(property.uiSchema?.title)} -
-
{compile(getInterface(property.interface)?.title)}
- -
- - ) - ); - })} - - handelOpenPorts(!isCollapse)} - > - {isCollapse - ? [ - , - {t('Association Fields')}, - ] - : [ - , - {t('All Fields')}, - ]} - - - ); -}); - export default Entity; diff --git a/packages/plugins/graph-collection-manager/src/client/utils.tsx b/packages/plugins/graph-collection-manager/src/client/utils.tsx index 52bca3eb9..5774a7f89 100644 --- a/packages/plugins/graph-collection-manager/src/client/utils.tsx +++ b/packages/plugins/graph-collection-manager/src/client/utils.tsx @@ -85,12 +85,12 @@ export const formatData = (data) => { name: item.name, title: item.title, width: 250, - // height: 40 * portsData.initPorts?.length||40, + // height: 40 * portsData.initPorts?.length || 40, ports: [...(portsData.initPorts || []), ...(portsData.morePorts || [])], item: item, }; }); - const edges = formatEdgeData(edgeData, targetTablekeys, tableData); + const edges = formatRelationEdgeData(edgeData, targetTablekeys, tableData); const inheritEdges = formatInheritEdgeData(data); return { nodesData: tableData, edgesData: edges, inheritEdges }; }; @@ -119,7 +119,6 @@ export const formatInheritEdgeData = (collections) => { textVerticalAnchor: 'middle', stroke: '#ddd', sourceMarker: null, - // targetMarker: null, }, }, router: { @@ -185,7 +184,10 @@ export const formatInheritEdgeData = (collections) => { cell: k, connectionPoint: 'rect', }, - connector: 'rounded', + connector: { + name: 'normal', + zIndex: 1000, + }, connectionType: 'inherited', ...commonAttrs, }); @@ -195,7 +197,7 @@ export const formatInheritEdgeData = (collections) => { return inheritEdges; }; -const formatEdgeData = (data, targetTables, tableData) => { +const formatRelationEdgeData = (data, targetTables, tableData) => { const edges = []; for (let i = 0; i < data.length; i++) { if (targetTables.includes(data[i].target)) { @@ -314,6 +316,10 @@ const formatEdgeData = (data, targetTables, tableData) => { }, }, ], + connector: { + name: 'normal', + zIndex: 1000, + }, }; const isuniq = (id) => { const targetEdge = edges.find((v) => v.id === id); From 0532d67e0bc59da4a0391ac98cf1f078f07f03d6 Mon Sep 17 00:00:00 2001 From: katherinehhh Date: Mon, 21 Aug 2023 22:08:37 +0800 Subject: [PATCH 7/8] refactor: m2m data filtering through collection data (#2497) --- .../client/src/schema-component/antd/form-item/FormItem.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx index a481f007a..6d9233158 100644 --- a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx +++ b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx @@ -89,7 +89,10 @@ export const FormItem: any = observer( let iniValues = []; contextData?.map((v) => { const data = parseVariables(schema.default, { $context: v }); - iniValues = iniValues.concat(data); + iniValues = iniValues.concat(data).map((v) => { + delete v[collectionField.through]; + return v; + }); }); const data = _.uniqBy(iniValues, 'id'); field.setInitialValue?.(data.length > 0 ? data : [{}]); From 9c5f630ae70c306dce3867c8a76f4728f3c8ff4c Mon Sep 17 00:00:00 2001 From: ChengLei Shao Date: Tue, 22 Aug 2023 09:01:29 +0800 Subject: [PATCH 8/8] chore: database connection error log --- packages/core/database/src/database.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts index 7440c2c16..cb18366a5 100644 --- a/packages/core/database/src/database.ts +++ b/packages/core/database/src/database.ts @@ -708,6 +708,7 @@ export class Database extends EventEmitter implements AsyncEmitter { console.log('Connection has been established successfully.'); return true; } catch (error) { + console.log(`Unable to connect to the database: ${error.message}`); if (count >= (retry as number)) { throw new Error('Connection failed, please check your database connection credentials and try again.'); }