diff --git a/packages/core/client/src/collection-manager/interfaces/color.ts b/packages/core/client/src/collection-manager/interfaces/color.ts new file mode 100644 index 000000000..6dfdcf41e --- /dev/null +++ b/packages/core/client/src/collection-manager/interfaces/color.ts @@ -0,0 +1,26 @@ +import { defaultProps, operators } from './properties'; +import { IField } from './types'; + +export const color: IField = { + name: 'color', + type: 'object', + group: 'basic', + order: 10, + title: '{{t("Color")}}', + default: { + type: 'string', + uiSchema: { + type: 'string', + 'x-component': 'ColorPicker', + default: '#1677FF', + }, + }, + availableTypes: ['string'], + hasDefaultValue: true, + properties: { + ...defaultProps, + }, + filterable: { + operators: operators.string, + }, +}; diff --git a/packages/core/client/src/collection-manager/interfaces/index.ts b/packages/core/client/src/collection-manager/interfaces/index.ts index e434f6fad..98a790fb6 100644 --- a/packages/core/client/src/collection-manager/interfaces/index.ts +++ b/packages/core/client/src/collection-manager/interfaces/index.ts @@ -2,6 +2,7 @@ export * from './checkbox'; export * from './checkboxGroup'; export * from './chinaRegion'; export * from './collection'; +export * from './color'; export * from './createdAt'; export * from './createdBy'; export * from './datetime'; diff --git a/packages/core/client/src/locale/en_US.ts b/packages/core/client/src/locale/en_US.ts index b1e2818d2..73e707a81 100644 --- a/packages/core/client/src/locale/en_US.ts +++ b/packages/core/client/src/locale/en_US.ts @@ -711,6 +711,8 @@ export default { "Date display format":"Date display format", "Assign data scope for the template":"Assign data scope for the template", "Table selected records":"Table selected records", + "Tag":"Tag", + "Tag color field":"Tag color field", "Sync successfully":"Sync successfully", "Sync from form fields":"Sync from form fields", "Select all":"Select all" diff --git a/packages/core/client/src/locale/ja_JP.ts b/packages/core/client/src/locale/ja_JP.ts index d23801238..0760d6d8f 100644 --- a/packages/core/client/src/locale/ja_JP.ts +++ b/packages/core/client/src/locale/ja_JP.ts @@ -621,6 +621,8 @@ export default { "Allow add new, update and delete actions":"削除変更操作の許可", "Date display format":"日付表示形式", "Assign data scope for the template":"テンプレートのデータ範囲の指定", + "Tag":"タブ", + "Tag color field":"ラベルの色フィールド", "Sync successfully":"同期成功", "Sync from form fields":"フォームフィールドの同期", "Select all":"すべて選択" diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts index 62a9a72a1..3eef3c722 100644 --- a/packages/core/client/src/locale/zh_CN.ts +++ b/packages/core/client/src/locale/zh_CN.ts @@ -796,6 +796,8 @@ export default { "Date display format":"日期显示格式", "Assign data scope for the template":"为模板指定数据范围", "Table selected records":"表格中选中的记录", + "Tag":"标签", + "Tag color field":"标签颜色字段", "Sync successfully":"同步成功", "Sync from form fields":"同步表单字段", "Select all":"全选" 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 new file mode 100644 index 000000000..e70862e05 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/association-field/InternalTag.tsx @@ -0,0 +1,123 @@ +import { observer, RecursionField, useField, useFieldSchema } from '@formily/react'; +import { toArr } from '@formily/shared'; +import flat from 'flat'; +import React, { Fragment, useRef, useState } from 'react'; +import { useDesignable } from '../../'; +import { BlockAssociationContext, WithoutTableFieldResource } from '../../../block-provider'; +import { CollectionProvider } from '../../../collection-manager'; +import { RecordProvider, useRecord } from '../../../record-provider'; +import { FormProvider } from '../../core'; +import { useCompile } from '../../hooks'; +import { ActionContextProvider, useActionContext } from '../action'; +import { EllipsisWithTooltip } from '../input/EllipsisWithTooltip'; +import { useAssociationFieldContext, useFieldNames, useInsertSchema } from './hooks'; +import schema from './schema'; +import { getTabFormatValue, useLabelUiSchema } from './util'; + +interface IEllipsisWithTooltipRef { + setPopoverVisible: (boolean) => void; +} + +const toValue = (value, placeholder) => { + if (value === null || value === undefined) { + return placeholder; + } + return value; +}; +export const ReadPrettyInternalTag: React.FC = observer( + (props: any) => { + const fieldSchema = useFieldSchema(); + const recordCtx = useRecord(); + const { enableLink, tagColorField } = fieldSchema['x-component-props']; + // value 做了转换,但 props.value 和原来 useField().value 的值不一致 + const field = useField(); + const fieldNames = useFieldNames(props); + const [visible, setVisible] = useState(false); + const insertViewer = useInsertSchema('Viewer'); + const { options: collectionField } = useAssociationFieldContext(); + const [record, setRecord] = useState({}); + const compile = useCompile(); + const { designable } = useDesignable(); + 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); + return ( + + + {snapshot ? ( + text + ) : enableLink !== false ? ( + { + e.stopPropagation(); + e.preventDefault(); + if (designable) { + insertViewer(schema.Viewer); + } + setVisible(true); + setRecord(record); + ellipsisWithTooltipRef?.current?.setPopoverVisible(false); + }} + > + {text} + + ) : ( + text + )} + + {index < arr.length - 1 ? , : null} + + ); + }); + + const renderWithoutTableFieldResourceProvider = () => ( + + + { + return s['x-component'] === 'AssociationField.Viewer'; + }} + /> + + + ); + + const renderRecordProvider = () => { + const collectionFieldNames = fieldSchema?.['x-collection-field']?.split('.'); + + return collectionFieldNames && collectionFieldNames.length > 2 ? ( + + {renderWithoutTableFieldResourceProvider()} + + ) : ( + {renderWithoutTableFieldResourceProvider()} + ); + }; + + return ( +
+ + + + {renderRecords()} + + + {renderRecordProvider()} + + + +
+ ); + }, + { displayName: 'ReadPrettyInternalTag' }, +); diff --git a/packages/core/client/src/schema-component/antd/association-field/ReadPretty.tsx b/packages/core/client/src/schema-component/antd/association-field/ReadPretty.tsx index 9362a54f6..d68ee7e23 100644 --- a/packages/core/client/src/schema-component/antd/association-field/ReadPretty.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/ReadPretty.tsx @@ -1,11 +1,12 @@ -import React, { useEffect, useState } from 'react'; -import { useField, observer } from '@formily/react'; +import { observer } from '@formily/react'; +import React from 'react'; import { AssociationFieldProvider } from './AssociationFieldProvider'; -import { InternalNester } from './InternalNester'; -import { ReadPrettyInternalViewer } from './InternalViewer'; -import { InternalSubTable } from './InternalSubTable'; import { FileManageReadPretty } from './FileManager'; import { useAssociationFieldContext } from './hooks'; +import { InternalNester } from './InternalNester'; +import { InternalSubTable } from './InternalSubTable'; +import { ReadPrettyInternalTag } from './InternalTag'; +import { ReadPrettyInternalViewer } from './InternalViewer'; const ReadPrettyAssociationField = observer( (props: any) => { @@ -14,6 +15,7 @@ const ReadPrettyAssociationField = observer( return ( <> {['Select', 'Picker'].includes(currentMode) && } + {currentMode === 'Tag' && } {currentMode === 'Nester' && } {currentMode === 'SubTable' && } {currentMode === 'FileManager' && } diff --git a/packages/core/client/src/schema-component/antd/association-field/util.ts b/packages/core/client/src/schema-component/antd/association-field/util.ts index b3fd4516a..cb56d9aa2 100644 --- a/packages/core/client/src/schema-component/antd/association-field/util.ts +++ b/packages/core/client/src/schema-component/antd/association-field/util.ts @@ -48,6 +48,28 @@ export const getLabelFormatValue = (labelUiSchema: ISchema, value: any, isTag = } }; +export const getTabFormatValue = (labelUiSchema: ISchema, value: any, tagColor): any => { + const options = labelUiSchema?.enum; + if (Array.isArray(options) && value) { + const values = toArr(value).map((val) => { + const opt: any = options.find((option: any) => option.value === val); + return React.createElement(Tag, { color: tagColor||opt?.color }, opt?.label); + }); + return values; + } + switch (labelUiSchema?.['x-component']) { + case 'DatePicker': + return React.createElement( + Tag, + { color: tagColor }, + getDatePickerLabels({ ...labelUiSchema?.['x-component-props'], value }), + ); + + default: + return React.createElement(Tag, { color: tagColor }, value); + } +}; + export function flatData(data) { const newArr = []; for (let i = 0; i < data.length; i++) { diff --git a/packages/core/client/src/schema-component/antd/color-picker/ColorPicker.tsx b/packages/core/client/src/schema-component/antd/color-picker/ColorPicker.tsx new file mode 100644 index 000000000..335a7bade --- /dev/null +++ b/packages/core/client/src/schema-component/antd/color-picker/ColorPicker.tsx @@ -0,0 +1,68 @@ +import { css } from '@emotion/css'; +import { usePrefixCls } from '@formily/antd-v5/esm/__builtins__'; +import { connect, mapProps, mapReadPretty } from '@formily/react'; +import { ColorPicker as AntdColorPicker } from 'antd'; +import cls from 'classnames'; +import React from 'react'; + +export const ColorPicker = connect( + (props) => { + const { value, onChange, ...others } = props; + return ( + current} + presets={[ + { + label: 'Recommended', + colors: [ + '#8BBB11', + '#52C41A', + '#13A8A8', + '#1677FF', + '#F5222D', + '#FADB14', + '#FA8C164D', + '#FADB144D', + '#52C41A4D', + '#1677FF4D', + '#2F54EB4D', + '#722ED14D', + '#EB2F964D', + ], + }, + ]} + onChange={(color) => onChange(color.toHexString())} + /> + ); + }, + mapProps((props, field) => { + return { + ...props, + }; + }), + mapReadPretty((props) => { + const prefixCls = usePrefixCls('description-color-picker', props); + return ( +
+ +
+ ); + }), +); + +export default ColorPicker; diff --git a/packages/core/client/src/schema-component/antd/color-picker/ReadPretty.tsx b/packages/core/client/src/schema-component/antd/color-picker/ReadPretty.tsx new file mode 100644 index 000000000..9b0357ec8 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/color-picker/ReadPretty.tsx @@ -0,0 +1,24 @@ +import { usePrefixCls } from '@formily/antd-v5/esm/__builtins__'; +import type { ColorPickerProps as AntdColorPickerProps } from 'antd/es/color-picker'; +import cls from 'classnames'; +import React from 'react'; + +type Composed = { + ColorPicker: React.FC; +}; + +export const ReadPretty: Composed = () => null; + +ReadPretty.ColorPicker = function ColorPicker(props: any) { + const prefixCls = usePrefixCls('description-color-picker', props); + + if (!props.value) { + return
; + } + + return ( +
+ +
+ ); +}; diff --git a/packages/core/client/src/schema-component/antd/color-picker/demos/demo1.tsx b/packages/core/client/src/schema-component/antd/color-picker/demos/demo1.tsx new file mode 100644 index 000000000..9ecd4fdb3 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/color-picker/demos/demo1.tsx @@ -0,0 +1,49 @@ +/** + * title: ColorPicker + */ +import { FormItem } from '@formily/antd-v5'; +import { ColorPicker, Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client'; +import React from 'react'; + +const schema = { + type: 'object', + properties: { + input: { + type: 'boolean', + title: `Editable`, + 'x-decorator': 'FormItem', + 'x-component': 'ColorPicker', + 'x-reactions': { + target: '*(read1,read2)', + fulfill: { + state: { + value: '{{$self.value}}', + }, + }, + }, + }, + read1: { + type: 'boolean', + title: `Read pretty`, + 'x-read-pretty': true, + 'x-decorator': 'FormItem', + 'x-component': 'ColorPicker', + }, + read2: { + type: 'string', + title: `Value`, + 'x-read-pretty': true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + 'x-component-props': {}, + }, + }, +}; + +export default () => { + return ( + + + + ); +}; diff --git a/packages/core/client/src/schema-component/antd/color-picker/index.md b/packages/core/client/src/schema-component/antd/color-picker/index.md new file mode 100644 index 000000000..f30325a47 --- /dev/null +++ b/packages/core/client/src/schema-component/antd/color-picker/index.md @@ -0,0 +1,18 @@ +--- +group: + title: Schema Components + order: 3 +--- + +# ColorPicker + +## Examples + +### Basic + + + + + + + diff --git a/packages/core/client/src/schema-component/antd/color-picker/index.tsx b/packages/core/client/src/schema-component/antd/color-picker/index.tsx new file mode 100644 index 000000000..2a3592dfd --- /dev/null +++ b/packages/core/client/src/schema-component/antd/color-picker/index.tsx @@ -0,0 +1 @@ +export * from './ColorPicker'; diff --git a/packages/core/client/src/schema-component/antd/color-picker/util.ts b/packages/core/client/src/schema-component/antd/color-picker/util.ts new file mode 100644 index 000000000..e037070bd --- /dev/null +++ b/packages/core/client/src/schema-component/antd/color-picker/util.ts @@ -0,0 +1,158 @@ +import { dayjs, getDefaultFormat, str2moment, toGmt, toLocal } from '@nocobase/utils/client'; +import type { Dayjs } from 'dayjs'; + +const toStringByPicker = (value, picker, timezone: 'gmt' | 'local') => { + if (!dayjs.isDayjs(value)) return value; + if (timezone === 'local') { + const offset = new Date().getTimezoneOffset(); + return dayjs(toStringByPicker(value, picker, 'gmt')).add(offset, 'minutes').toISOString(); + } + + if (picker === 'year') { + return value.format('YYYY') + '-01-01T00:00:00.000Z'; + } + if (picker === 'month') { + return value.format('YYYY-MM') + '-01T00:00:00.000Z'; + } + if (picker === 'quarter') { + return value.startOf('quarter').format('YYYY-MM') + '-01T00:00:00.000Z'; + } + if (picker === 'week') { + return value.startOf('week').add(1, 'day').format('YYYY-MM-DD') + 'T00:00:00.000Z'; + } + return value.format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z'; +}; + +const toGmtByPicker = (value: Dayjs, picker?: any) => { + if (!value || !dayjs.isDayjs(value)) { + return value; + } + return toStringByPicker(value, picker, 'gmt'); +}; + +const toLocalByPicker = (value: Dayjs, picker?: any) => { + if (!value || !dayjs.isDayjs(value)) { + return value; + } + return toStringByPicker(value, picker, 'local'); +}; + +export interface Moment2strOptions { + showTime?: boolean; + gmt?: boolean; + utc?: boolean; + picker?: 'year' | 'month' | 'week' | 'quarter'; +} + +export const moment2str = (value?: Dayjs | null, options: Moment2strOptions = {}) => { + const { showTime, gmt, picker, utc = true } = options; + if (!value) { + return value; + } + if (!utc) { + const format = showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'; + return value.format(format); + } + if (showTime) { + return gmt ? toGmt(value) : toLocal(value); + } + if (typeof gmt === 'boolean') { + return gmt ? toGmtByPicker(value, picker) : toLocalByPicker(value, picker); + } + return toGmtByPicker(value, picker); +}; + +export const mapDatePicker = function () { + return (props: any) => { + const format = getDefaultFormat(props) as any; + const onChange = props.onChange; + + return { + ...props, + format: format, + value: str2moment(props.value, props), + onChange: (value: Dayjs | null) => { + if (onChange) { + if (!props.showTime && value) { + value = value.startOf('day'); + } + onChange(moment2str(value, props)); + } + }, + }; + }; +}; + +export const mapRangePicker = function () { + return (props: any) => { + const format = getDefaultFormat(props) as any; + const onChange = props.onChange; + + return { + ...props, + format: format, + value: str2moment(props.value, props), + onChange: (value: Dayjs[]) => { + if (onChange) { + onChange( + value + ? [moment2str(getRangeStart(value[0], props), props), moment2str(getRangeEnd(value[1], props), props)] + : [], + ); + } + }, + } as any; + }; +}; + +function getRangeStart(value: Dayjs, options: Moment2strOptions) { + const { showTime } = options; + if (showTime) { + return value; + } + return value.startOf('day'); +} + +function getRangeEnd(value: Dayjs, options: Moment2strOptions) { + const { showTime } = options; + if (showTime) { + return value; + } + return value.endOf('day'); +} + +const getStart = (offset: any, unit: any) => { + return dayjs() + .add(offset, unit === 'isoWeek' ? 'week' : unit) + .startOf(unit); +}; + +const getEnd = (offset: any, unit: any) => { + return dayjs() + .add(offset, unit === 'isoWeek' ? 'week' : unit) + .endOf(unit); +}; + +export const getDateRanges = () => { + return { + today: () => [getStart(0, 'day'), getEnd(0, 'day')], + lastWeek: () => [getStart(-1, 'isoWeek'), getEnd(-1, 'isoWeek')], + thisWeek: () => [getStart(0, 'isoWeek'), getEnd(0, 'isoWeek')], + nextWeek: () => [getStart(1, 'isoWeek'), getEnd(1, 'isoWeek')], + lastMonth: () => [getStart(-1, 'month'), getEnd(-1, 'month')], + thisMonth: () => [getStart(0, 'month'), getEnd(0, 'month')], + nextMonth: () => [getStart(1, 'month'), getEnd(1, 'month')], + lastQuarter: () => [getStart(-1, 'quarter'), getEnd(-1, 'quarter')], + thisQuarter: () => [getStart(0, 'quarter'), getEnd(0, 'quarter')], + nextQuarter: () => [getStart(1, 'quarter'), getEnd(1, 'quarter')], + lastYear: () => [getStart(-1, 'year'), getEnd(-1, 'year')], + thisYear: () => [getStart(0, 'year'), getEnd(0, 'year')], + nextYear: () => [getStart(1, 'year'), getEnd(1, 'year')], + last7Days: () => [getStart(-6, 'days'), getEnd(0, 'days')], + next7Days: () => [getStart(1, 'day'), getEnd(7, 'days')], + last30Days: () => [getStart(-29, 'days'), getEnd(0, 'days')], + next30Days: () => [getStart(1, 'day'), getEnd(30, 'days')], + last90Days: () => [getStart(-89, 'days'), getEnd(0, 'days')], + next90Days: () => [getStart(1, 'day'), getEnd(90, 'days')], + }; +}; 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 05cf804f8..403c479f3 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 @@ -28,6 +28,7 @@ import { BlockItem } from '../block-item'; import { removeNullCondition } from '../filter'; import { HTMLEncode } from '../input/shared'; import { FilterDynamicComponent } from '../table-v2/FilterDynamicComponent'; +import { useColorFields } from '../table-v2/Table.Column.Designer'; import { FilterFormDesigner } from './FormItem.FilterFormDesigner'; import { useEnsureOperatorsValid } from './SchemaSettingOptions'; @@ -183,6 +184,7 @@ FormItem.Designer = function Designer() { value: field?.name, label: compile(field?.uiSchema?.title) || field?.name, })); + const colorFieldOptions = useColorFields(collectionField?.target ?? collectionField?.targetCollection); let readOnlyMode = 'editable'; if (fieldSchema['x-disabled'] === true) { @@ -529,10 +531,6 @@ FormItem.Designer = function Designer() { schema['x-component-props'] = fieldSchema['x-component-props']; field.componentProps = field.componentProps || {}; field.componentProps.mode = mode; - // if (mode === 'Nester') { - // const initValue = ['hasMany', 'belongsToMany'].includes(collectionField?.type) ? [{}] : {}; - // field.value = field.value || initValue; - // } dn.emit('patch', { schema, }); @@ -811,6 +809,29 @@ FormItem.Designer = function Designer() { /> )} {isDateField && } + + {isAssociationField && ['Tag'].includes(fieldMode) && ( + { + const schema = { + ['x-uid']: fieldSchema['x-uid'], + }; + + fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; + fieldSchema['x-component-props']['tagColorField'] = tagColorField; + schema['x-component-props'] = fieldSchema['x-component-props']; + field.componentProps.tagColorField = tagColorField; + dn.emit('patch', { + schema, + }); + dn.refresh(); + }} + /> + )} {collectionField && } { }); }; +export const useColorFields = (collectionName?: any) => { + const compile = useCompile(); + const { getCollectionFields } = useCollectionManager(); + if (!collectionName) { + return []; + } + const targetFields = getCollectionFields(collectionName); + return targetFields + ?.filter?.((field) => field?.interface === 'color') + ?.map?.((field) => { + return { + value: field.name, + label: compile(field?.uiSchema?.title || field.name), + }; + }); +}; export const TableColumnDesigner = (props) => { const { uiSchema, fieldSchema, collectionField } = props; const { getInterface, getCollection } = useCollectionManager(); @@ -37,6 +53,7 @@ export const TableColumnDesigner = (props) => { const fieldNames = fieldSchema?.['x-component-props']?.['fieldNames'] || uiSchema?.['x-component-props']?.['fieldNames']; const options = useLabelFields(collectionField?.target ?? collectionField?.targetCollection); + const colorFieldOptions = useColorFields(collectionField?.target ?? collectionField?.targetCollection); const intefaceCfg = getInterface(collectionField?.interface); const targetCollection = getCollection(collectionField?.target); const isFileField = isFileCollection(targetCollection); @@ -45,6 +62,7 @@ export const TableColumnDesigner = (props) => { const defaultFilter = fieldSchema?.['x-component-props']?.service?.params?.filter || {}; const dataSource = useCollectionFilterOptions(collectionField?.target); const isDateField = ['datetime', 'createdAt', 'updatedAt'].includes(collectionField?.interface); + const fieldMode = fieldSchema?.['x-component-props']?.['mode'] || 'Select'; let readOnlyMode = 'editable'; if (fieldSchema['x-disabled'] === true) { readOnlyMode = 'readonly'; @@ -232,6 +250,55 @@ export const TableColumnDesigner = (props) => { }} /> )} + {readOnlyMode === 'read-pretty' && + ['linkTo', 'm2m', 'm2o', 'o2m', 'obo', 'oho', 'snapshot'].includes(collectionField?.interface) && ( + { + const schema = { + ['x-uid']: fieldSchema['x-uid'], + }; + fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; + fieldSchema['x-component-props']['mode'] = mode; + schema['x-component-props'] = fieldSchema['x-component-props']; + field.componentProps = field.componentProps || {}; + field.componentProps.mode = mode; + dn.emit('patch', { + schema, + }); + dn.refresh(); + }} + /> + )} + + {['Tag'].includes(fieldMode) && ( + { + const schema = { + ['x-uid']: fieldSchema['x-uid'], + }; + + fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {}; + fieldSchema['x-component-props']['tagColorField'] = tagColorField; + schema['x-component-props'] = fieldSchema['x-component-props']; + field.componentProps.tagColorField = tagColorField; + dn.emit('patch', { + schema, + }); + dn.refresh(); + }} + /> + )} {isSubTableColumn && !field.readPretty && !uiSchema?.['x-read-pretty'] && ( diff --git a/packages/core/client/src/schema-component/hooks/useFieldModeOptions.tsx b/packages/core/client/src/schema-component/hooks/useFieldModeOptions.tsx index f78b4b754..8aee53fb5 100644 --- a/packages/core/client/src/schema-component/hooks/useFieldModeOptions.tsx +++ b/packages/core/client/src/schema-component/hooks/useFieldModeOptions.tsx @@ -24,6 +24,7 @@ export const useFieldModeOptions = () => { ? [ { label: t('Title'), value: 'Select' }, { label: t('File manager'), value: 'FileManager' }, + { label: t('Tag'), value: 'Tag' }, ] : [ { label: t('Select'), value: 'Select' }, @@ -37,6 +38,7 @@ export const useFieldModeOptions = () => { return isReadPretty ? [ { label: t('Title'), value: 'Select' }, + { label: t('Tag'), value: 'Tag' }, { label: t('Sub-table'), value: 'SubTable' }, { label: t('Sub-details'), value: 'Nester' }, ] @@ -50,6 +52,7 @@ export const useFieldModeOptions = () => { return isReadPretty ? [ { label: t('Title'), value: 'Select' }, + { label: t('Tag'), value: 'Tag' }, { label: t('Sub-details'), value: 'Nester' }, { label: t('Sub-table'), value: 'SubTable' }, ] @@ -64,6 +67,7 @@ export const useFieldModeOptions = () => { return isReadPretty ? [ { label: t('Title'), value: 'Select' }, + { label: t('Tag'), value: 'Tag' }, { label: t('Sub-details'), value: 'Nester' }, ] : [ @@ -76,6 +80,7 @@ export const useFieldModeOptions = () => { return isReadPretty ? [ { label: t('Title'), value: 'Select' }, + { label: t('Tag'), value: 'Tag' }, { label: t('Sub-details'), value: 'Nester' }, ] : [ diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index f8a3b3bb6..899fbf0f0 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 { Field, GeneralField, createForm } from '@formily/core'; +import { createForm, Field, GeneralField } 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,32 +21,32 @@ import { } from 'antd'; import _, { cloneDeep } from 'lodash'; import React, { - ReactNode, createContext, + ReactNode, useCallback, useContext, useMemo, + useState, // @ts-ignore useTransition as useReactTransition, - useState, } from 'react'; import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; import { - APIClientProvider, ActionContextProvider, + APIClientProvider, CollectionFieldOptions, CollectionManagerContext, CollectionProvider, + createDesignable, Designable, + findFormBlock, FormDialog, FormProvider, RemoteSchemaComponent, SchemaComponent, SchemaComponentContext, SchemaComponentOptions, - createDesignable, - findFormBlock, useAPIClient, useBlockRequestContext, useCollection,