diff --git a/packages/core/client/src/flow/flowSetting/TitleField.tsx b/packages/core/client/src/flow/flowSetting/TitleField.tsx index fac6610d2f..726e3050c1 100644 --- a/packages/core/client/src/flow/flowSetting/TitleField.tsx +++ b/packages/core/client/src/flow/flowSetting/TitleField.tsx @@ -46,24 +46,37 @@ export const titleField = defineAction({ }, }, defaultParams: (ctx: any) => { - const { target } = ctx.model.collectionField.options; - const collectionManager = ctx.model.collectionField.collection.collectionManager; - const targetCollection = collectionManager.getCollection(target); + const targetCollection = ctx.model.targetCollection; const filterKey = getUniqueKeyFromCollection(targetCollection.options as any); return { label: ctx.model.props.fieldNames?.label || targetCollection.options.titleField || filterKey, }; }, - handler(ctx: any, params) { - const { target } = ctx.model.collectionField.options; - const collectionManager = ctx.model.collectionField.collection.collectionManager; - ctx.model.setStepParams; - const targetCollection = collectionManager.getCollection(target); + async handler(ctx: any, params) { + const target = ctx.model.collectionField.target; + const targetCollection = ctx.model.collectionField.targetCollection; + console.log(ctx.model.collectionField); const filterKey = getUniqueKeyFromCollection(targetCollection.options as any); + const label = params.label || targetCollection.options.titleField || filterKey; const newFieldNames = { value: filterKey, - label: params.label || targetCollection.options.titleField || filterKey, + label, }; ctx.model.setComponentProps({ fieldNames: newFieldNames }); + const targetCollectionField = targetCollection.getField(label); + const use = targetCollectionField.getFirstSubclassNameOf('ReadPrettyFieldModel') || 'ReadPrettyFieldModel'; + const model = ctx.model.setSubModel('field', { + use, + stepParams: { + default: { + step1: { + dataSourceKey: ctx.model.collectionField.dataSourceKey, + collectionName: target, + fieldPath: newFieldNames.label, + }, + }, + }, + }); + await model.applyAutoFlows(); }, }); diff --git a/packages/core/client/src/flow/models/fields/EditableField/AssociationFieldModel/AssociationSelectEditableFieldModel.tsx b/packages/core/client/src/flow/models/fields/EditableField/AssociationFieldModel/AssociationSelectEditableFieldModel.tsx index 5dca643652..78bfd5c752 100644 --- a/packages/core/client/src/flow/models/fields/EditableField/AssociationFieldModel/AssociationSelectEditableFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/EditableField/AssociationFieldModel/AssociationSelectEditableFieldModel.tsx @@ -9,8 +9,7 @@ import { connect, mapProps, mapReadPretty } from '@formily/react'; import { Select } from 'antd'; import React from 'react'; -import { FlowModelRenderer, useFlowEngine, useFlowModel, reactive } from '@nocobase/flow-engine'; -import { useCompile } from '../../../../../schema-component'; +import { useFlowModel, FlowModel } from '@nocobase/flow-engine'; import { tval } from '@nocobase/utils/client'; import { AssociationFieldEditableFieldModel } from './AssociationFieldEditableFieldModel'; @@ -34,52 +33,19 @@ function toValue(record: any | any[], fieldNames, multiple = false) { return convert(record); } -const modelCache = new Map(); function LabelByField(props) { const { option, fieldNames } = props; - const cacheKey = option[fieldNames.value] + option[fieldNames.label]; - const currentModel: any = useFlowModel(); - const flowEngine = useFlowEngine(); - if (modelCache.has(cacheKey)) { - return option[fieldNames.label] ? : tval('N/A'); - } - const collectionManager = currentModel.collectionField.collection.collectionManager; - const target = currentModel.collectionField?.options?.target; - const targetCollection = collectionManager.getCollection(target); - const targetLabelField = targetCollection.getField(fieldNames.label); - const fieldClasses = Array.from(flowEngine.filterModelClassByParent('ReadPrettyFieldModel').values()).sort( - (a, b) => (a.meta?.sort || 0) - (b.meta?.sort || 0), - ); - - const fieldClass = fieldClasses.find( - (cls) => cls.supportedFieldInterfaces?.includes(targetLabelField?.options?.interface), - ); - const model = flowEngine.createModel({ - use: fieldClass?.name || 'ReadPrettyFieldModel', - stepParams: { - default: { - step1: { - dataSourceKey: currentModel.collectionField.collection.dataSourceKey, - collectionName: target, - fieldPath: fieldNames.label, - }, - }, - }, - }); - model.setSharedContext({ - ...currentModel.getSharedContext(), - value: option[fieldNames.label], + const currentModel = useFlowModel(); + const field = currentModel.subModels.field as FlowModel; + const key = option[fieldNames.value]; + const fieldModel = field.createFork({}, key); + fieldModel.setSharedContext({ + value: option?.[fieldNames.label], + currentRecord: option, }); - model.setParent(currentModel.parent); - modelCache.set(cacheKey, model); - - return ( - - {option[fieldNames.label] ? : tval('N/A')} - - ); + return {option[fieldNames.label] ? fieldModel.render() : tval('N/A')}; } function LazySelect(props) { diff --git a/packages/core/client/src/flow/models/fields/EditableField/MarkdownEditableFieldModel/index.tsx b/packages/core/client/src/flow/models/fields/EditableField/MarkdownEditableFieldModel/index.tsx index 3532d2a43a..dd9c115959 100644 --- a/packages/core/client/src/flow/models/fields/EditableField/MarkdownEditableFieldModel/index.tsx +++ b/packages/core/client/src/flow/models/fields/EditableField/MarkdownEditableFieldModel/index.tsx @@ -11,13 +11,14 @@ import { Input } from '@formily/antd-v5'; import React from 'react'; import { connect, mapProps, mapReadPretty } from '@formily/react'; import { EditableFieldModel } from '../EditableFieldModel'; -import { useParseMarkdown } from './util'; +import { useParseMarkdown, convertToText } from './util'; import { useMarkdownStyles } from './style'; -const MarkdownReadPretty = (props) => { +export const MarkdownReadPretty = (props) => { + const { textOnly } = props; const markdownClass = useMarkdownStyles(); const { html = '' } = useParseMarkdown(props.value); - + const text = convertToText(html); const value = (
{ /> ); - return value; + return <>{textOnly ? text : value}; }; const Markdown: any = connect( diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationReadPrettyFieldModel.tsx index e80d4264d6..ae4a562274 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationReadPrettyFieldModel.tsx @@ -13,20 +13,3 @@ import { ReadPrettyFieldModel } from '../ReadPrettyFieldModel'; export class AssociationReadPrettyFieldModel extends ReadPrettyFieldModel { targetCollection; } - -AssociationReadPrettyFieldModel.registerFlow({ - key: 'AssociationReadPrettyFieldDefault', - auto: true, - sort: 150, - steps: { - step1: { - handler(ctx, params) { - const { collectionField } = ctx.model; - const { target } = collectionField?.options || {}; - const collectionManager = collectionField.collection.collectionManager; - const targetCollection = collectionManager.getCollection(target); - ctx.model.targetCollection = targetCollection; - }, - }, - }, -}); diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationSelectReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationSelectReadPrettyFieldModel.tsx index f8ed9b6b9c..7dc1c2bf7f 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationSelectReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/AssociationFieldModel/AssociationSelectReadPrettyFieldModel.tsx @@ -8,10 +8,11 @@ */ import React from 'react'; +import { castArray } from 'lodash'; import { Button } from 'antd'; import { tval } from '@nocobase/utils/client'; import { AssociationReadPrettyFieldModel } from './AssociationReadPrettyFieldModel'; -import { FlowEngineProvider, reactive } from '@nocobase/flow-engine'; +import { reactive, FlowModel } from '@nocobase/flow-engine'; import { getUniqueKeyFromCollection } from '../../../../../collection-manager/interfaces/utils'; const LinkToggleWrapper = ({ enableLink, children, currentRecord, ...props }) => { @@ -46,70 +47,43 @@ export class AssociationSelectReadPrettyFieldModel extends AssociationReadPretty set onClick(fn) { this.setProps({ ...this.props, onClick: fn }); } + private fieldModelCache: Record = {}; @reactive public render() { const { fieldNames, enableLink = true } = this.props; const value = this.getValue(); - if (!this.collectionField || !value) { - return; - } - const { target } = this.collectionField?.options || {}; - const collectionManager = this.collectionField.collection.collectionManager; - const targetCollection = collectionManager.getCollection(target); - const targetLabelField = targetCollection.getField(fieldNames.label); - const fieldClasses = Array.from(this.flowEngine.filterModelClassByParent('ReadPrettyFieldModel').values())?.sort( - (a, b) => (a.meta?.sort || 0) - (b.meta?.sort || 0), - ); - const fieldInterfaceName = targetLabelField?.options?.interface; - const fieldClass = fieldClasses.find((fieldClass) => { - return fieldClass.supportedFieldInterfaces?.includes(fieldInterfaceName); - }); - const model = this.flowEngine.createModel({ - use: fieldClass?.name || 'ReadPrettyFieldModel', - stepParams: { - default: { - step1: { - dataSourceKey: this.collectionField.collection.dataSourceKey, - collectionName: target, - fieldPath: fieldNames.label, - }, - }, - }, - props: { - dataSource: targetLabelField.enum, - ...targetLabelField.getComponentProps(), - }, - }); - model.setSharedContext({ - ...this.ctx.shared, - value: value?.[fieldNames.label], - currentRecord: value, - }); - model.setParent(this.parent); - if (Array.isArray(value)) { - return ( -
- {value.map((v, idx) => { - const mol = model.createFork({}, `${idx}`); - mol.setSharedContext({ ...this.ctx.shared, index: idx, value: v?.[fieldNames.label], currentRecord: v }); - return ( - - {idx > 0 && ,} - - - {v?.[fieldNames.label] ? mol.render() : this.flowEngine.translate('N/A')} - - - - ); - })} -
- ); - } + if (!value) return null; + + const arrayValue = castArray(value); + const field = this.subModels.field as FlowModel; return ( - - {model.render()} - + <> + {arrayValue.map((v, index) => { + const key = `${index}`; + let fieldModel = this.fieldModelCache[v?.[fieldNames.label]]; + + if (!fieldModel) { + fieldModel = field.createFork({}, key); + fieldModel.setSharedContext({ + index, + value: v?.[fieldNames.label], + currentRecord: v, + }); + this.fieldModelCache[v?.[fieldNames.label]] = fieldModel; + } + + const content = v?.[fieldNames.label] ? fieldModel.render() : this.flowEngine.translate('N/A'); + + return ( + + {index > 0 && ', '} + + {content} + + + ); + })} + ); } } @@ -123,16 +97,32 @@ AssociationSelectReadPrettyFieldModel.registerFlow({ fieldNames: { use: 'titleField', title: tval('Title field'), - handler(ctx, params) { - const { target } = ctx.model.collectionField.options; + async handler(ctx, params) { + const { target } = ctx.model.collectionField; const collectionManager = ctx.model.collectionField.collection.collectionManager; const targetCollection = collectionManager.getCollection(target); const filterKey = getUniqueKeyFromCollection(targetCollection.options as any); + const label = params.label || targetCollection.options.titleField || filterKey; const newFieldNames = { value: filterKey, - label: params.label || targetCollection.options.titleField || filterKey, + label, }; + const targetCollectionField = targetCollection.getField(label); + const use = targetCollectionField.getFirstSubclassNameOf('ReadPrettyFieldModel') || 'ReadPrettyFieldModel'; ctx.model.setProps({ fieldNames: newFieldNames }); + const model = ctx.model.setSubModel('field', { + use, + stepParams: { + default: { + step1: { + dataSourceKey: ctx.model.collectionField.dataSourceKey, + collectionName: target, + fieldPath: newFieldNames.label, + }, + }, + }, + }); + await model.applyAutoFlows(); }, }, enableLink: { diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/CheckboxReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/CheckboxReadPrettyFieldModel.tsx index 40221ba0b0..0ffdc3e3b9 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/CheckboxReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/CheckboxReadPrettyFieldModel.tsx @@ -1,10 +1,21 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + import React from 'react'; +import { reactive } from '@nocobase/flow-engine'; import { ReadPrettyFieldModel } from './ReadPrettyFieldModel'; import { Checkbox } from 'antd'; import { CheckOutlined, CloseOutlined } from '@ant-design/icons'; export class CheckboxReadPrettyFieldModel extends ReadPrettyFieldModel { public static readonly supportedFieldInterfaces = ['checkbox']; + @reactive public render() { const value = this.getValue(); const { prefix = '', suffix = '', showUnchecked } = this.props; diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/ColorReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/ColorReadPrettyFieldModel.tsx index 4bc12005b4..b1dade0160 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/ColorReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/ColorReadPrettyFieldModel.tsx @@ -10,10 +10,12 @@ import React from 'react'; import { ColorPicker } from 'antd'; import { css } from '@emotion/css'; +import { reactive } from '@nocobase/flow-engine'; import { ReadPrettyFieldModel } from './ReadPrettyFieldModel'; export class ColorReadPrettyFieldModel extends ReadPrettyFieldModel { public static readonly supportedFieldInterfaces = ['color']; + @reactive public render() { const value = this.getValue(); diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/IconReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/IconReadPrettyFieldModel.tsx index 2acc9e9358..a6ec14d7a5 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/IconReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/IconReadPrettyFieldModel.tsx @@ -8,11 +8,13 @@ */ import React from 'react'; +import { reactive } from '@nocobase/flow-engine'; import { ReadPrettyFieldModel } from './ReadPrettyFieldModel'; import { Icon } from '../../../../icon'; export class IconReadPrettyFieldModel extends ReadPrettyFieldModel { public static readonly supportedFieldInterfaces = ['icon']; + @reactive public render() { const value = this.getValue(); diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/JsonReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/JsonReadPrettyFieldModel.tsx index aa0b34d9b7..70356c7354 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/JsonReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/JsonReadPrettyFieldModel.tsx @@ -7,7 +7,8 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import React, { useMemo } from 'react'; +import React from 'react'; +import { reactive } from '@nocobase/flow-engine'; import { cx, css } from '@emotion/css'; import { ReadPrettyFieldModel } from './ReadPrettyFieldModel'; @@ -19,6 +20,7 @@ const JSONClassName = css` export class JsonReadPrettyFieldModel extends ReadPrettyFieldModel { public static readonly supportedFieldInterfaces = ['json']; + @reactive public render() { const value = this.getValue(); const { space, style, className } = this.props; diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/MarkdownReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/MarkdownReadPrettyFieldModel.tsx new file mode 100644 index 0000000000..9f2084e3a2 --- /dev/null +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/MarkdownReadPrettyFieldModel.tsx @@ -0,0 +1,53 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import React from 'react'; +import { reactive } from '@nocobase/flow-engine'; +import { tval } from '@nocobase/utils/client'; +import { ReadPrettyFieldModel } from './ReadPrettyFieldModel'; +import { MarkdownReadPretty } from '../EditableField/MarkdownEditableFieldModel/index'; + +export class MarkdownReadPrettyFieldModel extends ReadPrettyFieldModel { + public static readonly supportedFieldInterfaces = ['markdown']; + @reactive + public render() { + const { textOnly = true } = this.props; + const value = this.getValue(); + return ; + } +} + +MarkdownReadPrettyFieldModel.registerFlow({ + key: 'displayMode', + title: tval('Specific properties'), + auto: true, + sort: 200, + steps: { + displayMode: { + uiSchema: { + textOnly: { + type: 'string', + enum: [ + { label: tval('Text only'), value: true }, + { label: tval('Html'), value: false }, + ], + 'x-decorator': 'FormItem', + 'x-component': 'Radio.Group', + }, + }, + title: tval('Display mode'), + defaultParams: { + textOnly: true, + }, + handler(ctx, params) { + ctx.model.setProps({ textOnly: params.textOnly }); + }, + }, + }, +}); diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/PercentReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/PercentReadPrettyFieldModel.tsx index cff6d18b8c..ee1a14c376 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/PercentReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/PercentReadPrettyFieldModel.tsx @@ -1,5 +1,15 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + import React from 'react'; import * as math from 'mathjs'; +import { reactive } from '@nocobase/flow-engine'; import { isNum } from '@formily/shared'; import { ReadPrettyFieldModel } from './ReadPrettyFieldModel'; @@ -13,6 +23,7 @@ const toValue = (value: any, callback: (v: number) => number) => { }; export class PercentReadPrettyFieldModel extends ReadPrettyFieldModel { public static readonly supportedFieldInterfaces = ['percent']; + @reactive public render() { const value = this.getValue(); const { prefix = '', suffix = '' } = this.props; diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/RichTextReadPrettyFieldModel.tsx b/packages/core/client/src/flow/models/fields/ReadPrettyField/RichTextReadPrettyFieldModel.tsx index aa7dd6d3de..c1cbdb12d7 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/RichTextReadPrettyFieldModel.tsx +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/RichTextReadPrettyFieldModel.tsx @@ -8,23 +8,46 @@ */ import React from 'react'; +import { tval } from '@nocobase/utils/client'; +import { reactive } from '@nocobase/flow-engine'; import { ReadPrettyFieldModel } from './ReadPrettyFieldModel'; - -const lineHeight142 = { lineHeight: '1.42' }; +import { MarkdownReadPretty } from '../EditableField/MarkdownEditableFieldModel/index'; export class RichTextReadPrettyFieldModel extends ReadPrettyFieldModel { public static readonly supportedFieldInterfaces = ['richText']; + @reactive public render() { + const { textOnly = true } = this.props; const value = this.getValue(); - const html = ( -
- ); - - return
{html}
; + return ; } } + +RichTextReadPrettyFieldModel.registerFlow({ + key: 'displayMode', + title: tval('Specific properties'), + auto: true, + sort: 200, + steps: { + displayMode: { + uiSchema: { + textOnly: { + type: 'string', + enum: [ + { label: tval('Text only'), value: true }, + { label: tval('Html'), value: false }, + ], + 'x-decorator': 'FormItem', + 'x-component': 'Radio.Group', + }, + }, + title: tval('Display mode'), + defaultParams: { + textOnly: true, + }, + handler(ctx, params) { + ctx.model.setProps({ textOnly: params.textOnly }); + }, + }, + }, +}); diff --git a/packages/core/client/src/flow/models/fields/ReadPrettyField/index.ts b/packages/core/client/src/flow/models/fields/ReadPrettyField/index.ts index 47064a57af..6d3d967b61 100644 --- a/packages/core/client/src/flow/models/fields/ReadPrettyField/index.ts +++ b/packages/core/client/src/flow/models/fields/ReadPrettyField/index.ts @@ -19,3 +19,4 @@ export * from './ColorReadPrettyFieldModel'; export * from './IconReadPrettyFieldModel'; export * from './JsonReadPrettyFieldModel'; export * from './AssociationFieldModel'; +export * from './MarkdownReadPrettyFieldModel';