fix: 将自定义筛选字段移到core/client (#1438)
Co-authored-by: sealday <zhanglin@daoyoucloud.com> Reviewed-on: daoyoucloud/tachybase#1438 Reviewed-by: sealday <zhanglin@daoyoucloud.com> Co-authored-by: wjh <wwwjh0710@163.com> Co-committed-by: wjh <wwwjh0710@163.com>
This commit is contained in:
parent
1742fa19fb
commit
bffb42601a
@ -22,7 +22,7 @@ import { useCollection_deprecated, useCollectionManager_deprecated } from '../..
|
||||
import { useFilterBlock } from '../../filter-provider/FilterProvider';
|
||||
import { mergeFilter, transformToFilter } from '../../filter-provider/utils';
|
||||
import { useRecord } from '../../record-provider';
|
||||
import { removeNullCondition, useActionContext, useCompile } from '../../schema-component';
|
||||
import { getCustomCondition, removeNullCondition, useActionContext, useCompile } from '../../schema-component';
|
||||
import { isSubMode } from '../../schema-component/antd/association-field/util';
|
||||
import { useCurrentUserContext } from '../../user';
|
||||
import { useLocalVariables, useVariables } from '../../variables';
|
||||
@ -393,7 +393,6 @@ export const useFilterBlockActionProps = () => {
|
||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
|
||||
actionField.data = actionField.data || {};
|
||||
|
||||
return {
|
||||
async onClick() {
|
||||
const { targets = [], uid } = findFilterTargets(fieldSchema);
|
||||
@ -407,16 +406,44 @@ export const useFilterBlockActionProps = () => {
|
||||
if (!target) return;
|
||||
|
||||
const param = block.service.params?.[0] || {};
|
||||
for (const key in form.values) {
|
||||
if (
|
||||
(typeof form.values[key] === 'object' &&
|
||||
(JSON.stringify(form.values[key]) === '{}' || JSON.stringify(form.values[key]) === '[]')) ||
|
||||
!form.values[key]
|
||||
) {
|
||||
delete form.values[key];
|
||||
}
|
||||
}
|
||||
// 保留原有的 filter
|
||||
const storedFilter = block.service.params?.[1]?.filters || {};
|
||||
|
||||
const filter = {
|
||||
formValues: {},
|
||||
customValues: {},
|
||||
customFilter: {},
|
||||
};
|
||||
|
||||
if (Object.keys(form.values)?.includes('custom')) {
|
||||
const values = { ...form.values };
|
||||
delete values['custom'];
|
||||
filter.formValues = { ...values };
|
||||
for (const key in form.values['custom']) {
|
||||
if (form.values['custom'][key]) {
|
||||
filter.customValues[key] = form.values['custom'][key];
|
||||
}
|
||||
}
|
||||
filter.customFilter = getCustomCondition(filter.customValues, fieldSchema);
|
||||
}
|
||||
|
||||
storedFilter[uid] = removeNullCondition(
|
||||
transformToFilter(form.values, fieldSchema, getCollectionJoinField, name),
|
||||
transformToFilter(filter.formValues, fieldSchema, getCollectionJoinField, name),
|
||||
);
|
||||
|
||||
const mergedFilter = mergeFilter([
|
||||
...Object.values(storedFilter).map((filter) => removeNullCondition(filter)),
|
||||
block.defaultFilter,
|
||||
filter.customFilter,
|
||||
]);
|
||||
|
||||
if (block.dataLoadingMode === 'manual' && _.isEmpty(mergedFilter)) {
|
||||
|
@ -51,11 +51,3 @@ export * from 'react-i18next';
|
||||
export { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
export * from './modules/blocks/useParentRecordCommon';
|
||||
|
||||
export * as __UNSAFE__ from './unsafe';
|
||||
export type {
|
||||
DynamicComponentProps as __UNSAFE__DynamicComponentProps,
|
||||
VariablesContextType as __UNSAFE__VariablesContextType,
|
||||
VariableOption as __UNSAFE__VariableOption,
|
||||
Option as __UNSAFE__VariableInputOption,
|
||||
} from './unsafe';
|
||||
|
@ -939,5 +939,15 @@
|
||||
"Show Data":"显示数据",
|
||||
"Setting Down Title":"设置文件名称",
|
||||
"The current return type is not a document type":"当前返回类型不是文档类型",
|
||||
"Test Data":"测试数据"
|
||||
"Test Data":"测试数据",
|
||||
"Custom filter field": "自定义筛选字段",
|
||||
"Custom option label": "自定义选项标签",
|
||||
"Add custom field":"添加自定义字段",
|
||||
"Input":"文本",
|
||||
"AutoComplete":"文本选择",
|
||||
"Field collection":"选择数据",
|
||||
"AssociationCascader":"关系型级联选择",
|
||||
"Edit Collection":"修改数据",
|
||||
"Field Component":"字段组件",
|
||||
"Custom filter":"自定义筛选"
|
||||
}
|
||||
|
@ -0,0 +1,294 @@
|
||||
import { Field, ISchema, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../..//collection-manager';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useFormBlockContext } from '../../../../block-provider';
|
||||
import { useCompile, useDesignable } from '../../../../schema-component';
|
||||
import {
|
||||
EditFormulaTitleField,
|
||||
FilterCustomVariableInput,
|
||||
SchemaSettingCollection,
|
||||
SchemaSettingComponent,
|
||||
SchemaSettingsCustomRemove,
|
||||
SchemaSettingsDataScope,
|
||||
} from '../../../../schema-settings';
|
||||
|
||||
export const FilterItemCustomSettings = new SchemaSettings({
|
||||
name: 'fieldSettings:FilterFormCustomSettings',
|
||||
items: [
|
||||
{
|
||||
name: 'editFieldTitle',
|
||||
type: 'modal',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField<Field>();
|
||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
const collectionField =
|
||||
getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
|
||||
return {
|
||||
title: t('Edit field title'),
|
||||
schema: {
|
||||
type: 'object',
|
||||
title: t('Edit field title'),
|
||||
properties: {
|
||||
title: {
|
||||
title: t('Field title'),
|
||||
default: field?.title,
|
||||
description: `${t('Original field title: ')}${collectionField?.uiSchema?.title}`,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
} as ISchema,
|
||||
onSubmit({ title }) {
|
||||
if (title) {
|
||||
field.title = title;
|
||||
fieldSchema.title = title;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
title: fieldSchema.title,
|
||||
},
|
||||
});
|
||||
}
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'editDescription',
|
||||
type: 'modal',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
|
||||
return {
|
||||
title: t('Edit description'),
|
||||
schema: {
|
||||
type: 'object',
|
||||
title: t('Edit description'),
|
||||
properties: {
|
||||
description: {
|
||||
// title: t('Description'),
|
||||
default: field?.description,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input.TextArea',
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
},
|
||||
onSubmit({ description }) {
|
||||
field.description = description;
|
||||
fieldSchema.description = description;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
description: fieldSchema.description,
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'setTheDataScope',
|
||||
Component: SchemaSettingsDataScope,
|
||||
useComponentProps() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { form } = useFormBlockContext();
|
||||
const field = useField();
|
||||
const { dn } = useDesignable();
|
||||
const fieldName = fieldSchema['name'] as string;
|
||||
const name = fieldName.includes('custom') ? fieldSchema['collectionName'] : fieldName;
|
||||
return {
|
||||
collectionName: name,
|
||||
defaultFilter: fieldSchema?.['x-component-props']?.params?.filter || {},
|
||||
form: form,
|
||||
onSubmit: ({ filter }) => {
|
||||
_.set(field.componentProps, 'params', {
|
||||
...field.componentProps?.params,
|
||||
filter,
|
||||
});
|
||||
fieldSchema['x-component-props']['params'] = field.componentProps.params;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
'x-component-props': fieldSchema['x-component-props'],
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const component = fieldSchema['x-component'];
|
||||
return component !== 'Input';
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'fieldCollection',
|
||||
Component: SchemaSettingCollection,
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const component = fieldSchema['x-component'];
|
||||
return component === 'Select' || component === 'AutoComplete';
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'fieldComponent',
|
||||
Component: SchemaSettingComponent,
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const component = fieldSchema['x-component'];
|
||||
return component === 'Select' || component === 'AutoComplete';
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'titleField',
|
||||
type: 'select',
|
||||
useComponentProps() {
|
||||
const { getCollectionFields, getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const compile = useCompile();
|
||||
const collectionManage = useCollectionManager_deprecated();
|
||||
const isCustomFilterItem = ((fieldSchema?.name as string) ?? '').startsWith('custom.');
|
||||
const collectionManageField = isCustomFilterItem
|
||||
? collectionManage.collections.filter((value) => value.name === fieldSchema['x-decorator-props'])[0]
|
||||
: {};
|
||||
const collectionField =
|
||||
getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
let targetFields = [];
|
||||
if (collectionField) {
|
||||
targetFields = collectionField?.target
|
||||
? getCollectionFields(collectionField?.target)
|
||||
: getCollectionFields(collectionField?.targetCollection) ?? [];
|
||||
} else if (collectionManageField) {
|
||||
targetFields = collectionManageField['fields'];
|
||||
}
|
||||
const options = targetFields
|
||||
.filter((field) => !field?.target && field.type !== 'boolean')
|
||||
.map((field) => ({
|
||||
value: field?.name,
|
||||
label: compile(field?.uiSchema?.title) || field?.name,
|
||||
}));
|
||||
return {
|
||||
title: t('Title field'),
|
||||
options,
|
||||
value: fieldSchema['x-component-props']?.['fieldNames']?.label || 'id',
|
||||
onChange(label) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
const fieldNames = {
|
||||
...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'],
|
||||
...field.componentProps.fieldNames,
|
||||
label,
|
||||
};
|
||||
if (isCustomFilterItem) fieldNames['value'] = label;
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps = fieldSchema['x-component-props'];
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const component = fieldSchema['x-component'];
|
||||
return component === 'Select' || component === 'AutoComplete';
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'EditFormulaTitleField',
|
||||
Component: EditFormulaTitleField,
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const component = fieldSchema['x-component'];
|
||||
return component === 'Select' || component === 'AutoComplete';
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'EditCustomDefaultValue',
|
||||
type: 'modal',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const title = fieldSchema.title;
|
||||
return {
|
||||
title: t('Set default value'),
|
||||
schema: {
|
||||
type: 'void',
|
||||
title: t('Set default value'),
|
||||
properties: {
|
||||
default: {
|
||||
title,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': FilterCustomVariableInput,
|
||||
'x-component-props': {
|
||||
fieldSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ISchema,
|
||||
onSubmit({ default: { value } }) {
|
||||
field.setValue(value);
|
||||
fieldSchema['default'] = value;
|
||||
fieldSchema['x-component-props']['defaultValue'] = value;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
['x-component-props']: fieldSchema['x-component-props'],
|
||||
default: fieldSchema.default,
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'divider',
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
name: 'delete',
|
||||
// Component: SchemaSettingsCustomRemove,
|
||||
// useComponentProps() {
|
||||
// const { t } = useTranslation();
|
||||
// return {
|
||||
// key: 'remove',
|
||||
// confirm: {
|
||||
// title: t('Delete field'),
|
||||
// },
|
||||
// removeParentsIfNoChildren: true,
|
||||
// breakRemoveOn: {
|
||||
// 'x-component': 'Grid',
|
||||
// },
|
||||
// };
|
||||
// },
|
||||
type: 'remove',
|
||||
},
|
||||
],
|
||||
});
|
@ -11,3 +11,4 @@ export * from './formActionInitializers';
|
||||
export * from './formItemInitializers';
|
||||
export * from './updateFormActionInitializers';
|
||||
export * from './createEditFormBlockUISchema';
|
||||
export * from './FilterItemCustomSettings';
|
||||
|
@ -37,6 +37,12 @@ export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitial
|
||||
Component: 'MarkdownFormItemInitializer',
|
||||
name: 'addText',
|
||||
},
|
||||
{
|
||||
title: '{{t("Custom filter field")}}',
|
||||
name: 'custom',
|
||||
type: 'item',
|
||||
Component: 'FilterFormItemCustom',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@ -70,6 +76,12 @@ export const filterFormItemInitializers = new CompatibleSchemaInitializer(
|
||||
Component: 'MarkdownFormItemInitializer',
|
||||
name: 'addText',
|
||||
},
|
||||
{
|
||||
title: '{{t("Custom filter field")}}',
|
||||
name: 'custom',
|
||||
type: 'item',
|
||||
Component: 'FilterFormItemCustom',
|
||||
},
|
||||
],
|
||||
},
|
||||
filterFormItemInitializers_deprecated,
|
||||
|
@ -20,7 +20,13 @@ import {
|
||||
useTitleFieldOptions,
|
||||
} from '../../../../schema-component/antd/form-item/FormItem.Settings';
|
||||
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||
import { getShouldChange, VariableInput } from '../../../../schema-settings';
|
||||
import {
|
||||
EditCustomDefaultValue,
|
||||
EditFormulaTitleField,
|
||||
getShouldChange,
|
||||
useFormulaTitleVisible,
|
||||
VariableInput,
|
||||
} from '../../../../schema-settings';
|
||||
import { useIsShowMultipleSwitch } from '../../../../schema-settings/hooks/useIsShowMultipleSwitch';
|
||||
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
|
||||
import { SchemaSettingsSortingRule } from '../../../../schema-settings/SchemaSettingsSortingRule';
|
||||
@ -381,5 +387,14 @@ export const selectComponentFieldSettings = new SchemaSettings({
|
||||
return useIsAssociationField() && readPretty;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'formulatitleField',
|
||||
Component: EditFormulaTitleField,
|
||||
useVisible: useFormulaTitleVisible,
|
||||
},
|
||||
{
|
||||
name: 'editDefaultValue',
|
||||
Component: EditCustomDefaultValue,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@ -20,16 +20,19 @@ import { isInitializersSame, useApp } from '../../../application';
|
||||
import { usePlugin } from '../../../application/hooks';
|
||||
import { SchemaSettingOptions, SchemaSettings } from '../../../application/schema-settings';
|
||||
import { useSchemaToolbar } from '../../../application/schema-toolbar';
|
||||
import { useFormBlockContext } from '../../../block-provider';
|
||||
import { useFormBlockContext, useFormBlockType } from '../../../block-provider';
|
||||
import {
|
||||
joinCollectionName,
|
||||
useCollection_deprecated,
|
||||
useCollectionFilterOptions,
|
||||
useCollectionManager_deprecated,
|
||||
} from '../../../collection-manager';
|
||||
import { DataSourceProvider, useDataSourceKey } from '../../../data-source';
|
||||
import { DataSourceProvider, useCollection, useDataSourceKey } from '../../../data-source';
|
||||
import { FlagProvider } from '../../../flag-provider';
|
||||
import { SaveMode } from '../../../modules/actions/submit/createSubmitActionSettings';
|
||||
import { useRecord } from '../../../record-provider';
|
||||
import { SchemaSettingOpenModeSchemaItems } from '../../../schema-items';
|
||||
import { FormFilterScope } from '../../../schema-settings/filter-form/FormFilterScope';
|
||||
import { GeneralSchemaDesigner } from '../../../schema-settings/GeneralSchemaDesigner';
|
||||
import { DefaultValueProvider } from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
||||
import {
|
||||
@ -41,6 +44,8 @@ import {
|
||||
SchemaSettingsRemove,
|
||||
SchemaSettingsSwitchItem,
|
||||
} from '../../../schema-settings/SchemaSettings';
|
||||
import { useSchemaTemplateManager } from '../../../schema-templates';
|
||||
import { useLocalVariables, useVariables } from '../../../variables';
|
||||
import { useLinkageAction } from './hooks';
|
||||
import { requestSettingsSchema } from './utils';
|
||||
|
||||
@ -598,6 +603,93 @@ export function WorkflowConfig() {
|
||||
);
|
||||
}
|
||||
|
||||
const findGridSchema = (fieldSchema) => {
|
||||
return fieldSchema.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === 'FormV2') {
|
||||
const f = s.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === 'Grid' || s['x-component'] === 'BlockTemplate') {
|
||||
return s;
|
||||
}
|
||||
return buf;
|
||||
}, null);
|
||||
if (f) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}, null);
|
||||
};
|
||||
|
||||
export const useSetFilterScopeVisible = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return (
|
||||
fieldSchema['x-component-props']?.useProps === '{{ useFilterBlockActionProps }}' ||
|
||||
fieldSchema['x-use-component-props'] === 'useFilterBlockActionProps'
|
||||
);
|
||||
};
|
||||
|
||||
export const SetFilterScope = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { collectionName } = props;
|
||||
const gridSchema = findGridSchema(fieldSchema) || fieldSchema;
|
||||
const { form } = useFormBlockContext();
|
||||
const type = props?.type || ['Action', 'Action.Link'].includes(fieldSchema['x-component']) ? 'button' : 'field';
|
||||
const variables = useVariables();
|
||||
const localVariables = useLocalVariables();
|
||||
const record = useRecord();
|
||||
const { type: formBlockType } = useFormBlockType();
|
||||
const schema = useMemo<ISchema>(
|
||||
() => ({
|
||||
type: 'object',
|
||||
title: t('Custom filter'),
|
||||
properties: {
|
||||
fieldReaction: {
|
||||
'x-component': FormFilterScope,
|
||||
'x-component-props': {
|
||||
useProps: () => {
|
||||
const options = useCollectionFilterOptions(collectionName);
|
||||
return {
|
||||
options,
|
||||
defaultValues: gridSchema?.['x-filter-rules'] || fieldSchema?.['x-filter-rules'],
|
||||
type,
|
||||
collectionName,
|
||||
form,
|
||||
variables,
|
||||
localVariables,
|
||||
record,
|
||||
formBlockType,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
const { getTemplateById } = useSchemaTemplateManager();
|
||||
const { dn } = useDesignable();
|
||||
const onSubmit = useCallback(
|
||||
(v) => {
|
||||
const rules = v.fieldReaction.condition;
|
||||
const templateId = gridSchema['x-component'] === 'BlockTemplate' && gridSchema['x-component-props'].templateId;
|
||||
const uid = (templateId && getTemplateById(templateId).uid) || gridSchema['x-uid'];
|
||||
const schema = {
|
||||
['x-uid']: uid,
|
||||
};
|
||||
|
||||
gridSchema['x-filter-rules'] = rules;
|
||||
schema['x-filter-rules'] = rules;
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
[dn, getTemplateById, gridSchema],
|
||||
);
|
||||
return <SchemaSettingsModalItem title={t('Custom filter')} width={770} schema={schema} onSubmit={onSubmit} />;
|
||||
};
|
||||
|
||||
export const actionSettingsItems: SchemaSettingOptions['items'] = [
|
||||
{
|
||||
name: 'Customize',
|
||||
@ -735,6 +827,17 @@ export const actionSettingsItems: SchemaSettingOptions['items'] = [
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Customize.setFilterScope',
|
||||
Component: SetFilterScope,
|
||||
useVisible: useSetFilterScopeVisible,
|
||||
useComponentProps() {
|
||||
const collection = useCollection();
|
||||
return {
|
||||
collectionName: collection.name,
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'remove',
|
||||
sort: 100,
|
||||
|
@ -8,6 +8,7 @@ import { useBlockRequestContext } from '../../../block-provider';
|
||||
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
|
||||
import { mergeFilter } from '../../../filter-provider/utils';
|
||||
import { useDataLoadingMode } from '../../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
|
||||
import { hasDuplicateKeys } from './utils';
|
||||
|
||||
export const useGetFilterOptions = () => {
|
||||
const { getCollectionFields } = useCollectionManager_deprecated();
|
||||
@ -149,8 +150,42 @@ const isEmpty = (obj) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const removeNullCondition = (filter) => {
|
||||
const items = flat(filter || {});
|
||||
export const getCustomCondition = (filter, fieldSchema, customFlat = flat) => {
|
||||
const filterSchema = fieldSchema ? fieldSchema['x-filter-rules'] : '';
|
||||
const filterSchemaItem = customFlat(filterSchema || '') as any;
|
||||
const items = customFlat(filter || {}) as any;
|
||||
const values = {};
|
||||
const isCustomFilter = filterSchema?.$and?.length || filterSchema?.$or?.length;
|
||||
const isFilterCustom = isCustomFilter ? hasDuplicateKeys(items, filterSchemaItem) : false;
|
||||
if (!isFilterCustom) {
|
||||
if (isCustomFilter) {
|
||||
for (const filterKey in filterSchemaItem) {
|
||||
const match = filterSchemaItem[filterKey]?.slice(11, -2);
|
||||
const collection = match?.split('.')[0];
|
||||
const filterItems = Object.keys(items).filter((item) => item.includes(collection))[0];
|
||||
if (filterItems) {
|
||||
filterSchemaItem[filterKey] = items[filterItems];
|
||||
}
|
||||
}
|
||||
for (const item in filterSchemaItem) {
|
||||
if (filterSchemaItem[item].includes('$nFilter')) {
|
||||
delete filterSchemaItem[item];
|
||||
}
|
||||
}
|
||||
const flatFieldSchema = customFlat.unflatten(filterSchemaItem);
|
||||
flatFieldSchema['$and'] = flatFieldSchema?.['$and']?.filter(Boolean);
|
||||
flatFieldSchema['$or'] = flatFieldSchema?.['$or']?.filter(Boolean);
|
||||
return flatFieldSchema;
|
||||
} else {
|
||||
return customFlat.unflatten({});
|
||||
}
|
||||
} else {
|
||||
return customFlat.unflatten(items);
|
||||
}
|
||||
};
|
||||
|
||||
export const removeNullCondition = (filter, customFlat = flat) => {
|
||||
const items = customFlat(filter || {}) as any;
|
||||
const values = {};
|
||||
for (const key in items) {
|
||||
const value = items[key];
|
||||
@ -158,7 +193,7 @@ export const removeNullCondition = (filter) => {
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
return flat.unflatten(values);
|
||||
return customFlat.unflatten(values);
|
||||
};
|
||||
|
||||
export const useFilterActionProps = () => {
|
||||
@ -179,7 +214,7 @@ export const useFilterFieldProps = ({ options, service, params }) => {
|
||||
// filter parameter for the block
|
||||
const defaultFilter = params.filter;
|
||||
// filter parameter for the filter action
|
||||
const filter = removeNullCondition(values?.filter);
|
||||
const filter = removeNullCondition(values?.filter) as any;
|
||||
|
||||
if (dataLoadingMode === 'manual' && _.isEmpty(filter)) {
|
||||
return service.mutate(undefined);
|
||||
|
@ -0,0 +1,12 @@
|
||||
// 数组去重
|
||||
const getArrayOfNoDuplicateValue = (arr: Array<string | number>): Array<string | number> => {
|
||||
return [...new Set(arr)];
|
||||
};
|
||||
|
||||
// 判断两个对象是否包含有相同的key
|
||||
export function hasDuplicateKeys(A: Object, B: Object): boolean {
|
||||
const keysA = getArrayOfNoDuplicateValue(Object.keys(A));
|
||||
const keysB = getArrayOfNoDuplicateValue(Object.keys(B));
|
||||
const keysA_B = getArrayOfNoDuplicateValue([...keysA, ...keysB]);
|
||||
return keysA_B.length < keysA.length + keysB.length;
|
||||
}
|
@ -558,23 +558,32 @@ export const EditTitleField = () => {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const compile = useCompile();
|
||||
const collectionManage = useCollectionManager_deprecated();
|
||||
const isCustomFilterItem = ((fieldSchema?.name as string) ?? '').startsWith('custom.');
|
||||
const collectionManageField = isCustomFilterItem
|
||||
? collectionManage.collections.filter((value) => value.name === fieldSchema['x-decorator-props'])[0]
|
||||
: {};
|
||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
const targetFields = collectionField?.target
|
||||
let targetFields = [];
|
||||
if (collectionField) {
|
||||
targetFields = collectionField?.target
|
||||
? getCollectionFields(collectionField?.target)
|
||||
: getCollectionFields(collectionField?.targetCollection) ?? [];
|
||||
} else if (collectionManageField) {
|
||||
targetFields = collectionManageField['fields'];
|
||||
}
|
||||
const options = targetFields
|
||||
.filter((field) => !field?.target && field.type !== 'boolean')
|
||||
.map((field) => ({
|
||||
value: field?.name,
|
||||
label: compile(field?.uiSchema?.title) || field?.name,
|
||||
}));
|
||||
|
||||
return options.length > 0 && fieldSchema['x-component'] === 'CollectionField' ? (
|
||||
return options.length > 0 && (fieldSchema['x-component'] === 'CollectionField' || isCustomFilterItem) ? (
|
||||
<SchemaSettingsSelectItem
|
||||
key="title-field"
|
||||
title={t('Title field')}
|
||||
options={options}
|
||||
value={field?.componentProps?.fieldNames?.label}
|
||||
value={fieldSchema['x-component-props']?.['fieldNames']?.label || 'id'}
|
||||
onChange={(label) => {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
@ -584,10 +593,11 @@ export const EditTitleField = () => {
|
||||
...field.componentProps.fieldNames,
|
||||
label,
|
||||
};
|
||||
if (isCustomFilterItem) fieldNames['value'] = label;
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps.fieldNames = fieldSchema['x-component-props'].fieldNames;
|
||||
field.componentProps = fieldSchema['x-component-props'];
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
|
@ -119,6 +119,7 @@ import {
|
||||
} from './buttons';
|
||||
import * as initializerComponents from './components';
|
||||
import * as items from './items';
|
||||
import { FilterFormItemCustom } from './items';
|
||||
|
||||
export * from './buttons';
|
||||
export * from './items';
|
||||
@ -176,6 +177,7 @@ export class SchemaInitializerPlugin extends Plugin {
|
||||
DisassociateActionInitializer,
|
||||
FilterActionInitializer,
|
||||
RefreshActionInitializer,
|
||||
FilterFormItemCustom,
|
||||
} as any);
|
||||
|
||||
this.app.schemaInitializerManager.add(blockInitializers_deprecated);
|
||||
|
@ -1,32 +1,4 @@
|
||||
import React, { memo, Profiler, useCallback, useContext, useMemo } from 'react';
|
||||
import {
|
||||
ACLCollectionFieldProvider,
|
||||
BlockItem,
|
||||
css,
|
||||
cx,
|
||||
EditComponent,
|
||||
EditDescription,
|
||||
FormDialog,
|
||||
FormItem,
|
||||
GeneralSchemaDesigner,
|
||||
gridRowColWrap,
|
||||
HTMLEncode,
|
||||
i18n,
|
||||
SchemaComponent,
|
||||
SchemaComponentOptions,
|
||||
SchemaInitializerItem,
|
||||
SchemaSettingsDataScope,
|
||||
SchemaSettingsDivider,
|
||||
Select,
|
||||
useAPIClient,
|
||||
useCollectionManager,
|
||||
useCollectionManager_deprecated,
|
||||
useCompile,
|
||||
useDesignable,
|
||||
useFormBlockContext,
|
||||
useGlobalTheme,
|
||||
useSchemaInitializerItem,
|
||||
} from '@tachybase/client';
|
||||
import React, { memo, useCallback, useContext, useMemo } from 'react';
|
||||
import { ArrayItems, FormLayout } from '@tachybase/components';
|
||||
import {
|
||||
Field,
|
||||
@ -37,22 +9,48 @@ import {
|
||||
uid,
|
||||
useField,
|
||||
useFieldSchema,
|
||||
useForm,
|
||||
} from '@tachybase/schema';
|
||||
|
||||
import { ConfigProvider, Radio, Space } from 'antd';
|
||||
import { ConfigProvider, Space } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { tval, useTranslation } from '../../locale';
|
||||
import { useAPIClient } from '../../api-client';
|
||||
import { SchemaInitializerItem, useSchemaInitializerItem } from '../../application';
|
||||
import { SchemaSettings } from '../../application/schema-settings/SchemaSettings';
|
||||
import { useFormBlockContext } from '../../block-provider';
|
||||
import { ACLCollectionFieldProvider } from '../../built-in/acl';
|
||||
import { useCollectionManager_deprecated } from '../../collection-manager';
|
||||
import { useCollectionManager } from '../../data-source';
|
||||
import { i18n } from '../../i18n';
|
||||
import {
|
||||
EditDefaultValue,
|
||||
EditFormulaTitleField,
|
||||
BlockItem,
|
||||
EditDescription,
|
||||
EditTitle,
|
||||
EditTitleField,
|
||||
FormDialog,
|
||||
FormItem,
|
||||
HTMLEncode,
|
||||
SchemaComponent,
|
||||
SchemaComponentOptions,
|
||||
Select,
|
||||
useCompile,
|
||||
useDesignable,
|
||||
} from '../../schema-component';
|
||||
import {
|
||||
EditCustomDefaultValue,
|
||||
EditFormulaTitleField,
|
||||
GeneralSchemaDesigner,
|
||||
SchemaSettingCollection,
|
||||
SchemaSettingComponent,
|
||||
SchemaSettingsCustomRemove,
|
||||
SchemaSettingsDataScope,
|
||||
SchemaSettingsDivider,
|
||||
SchemaSettingsRemove,
|
||||
} from '../../schema-settings';
|
||||
import { SchemaSettingsRemove } from '../../schema-settings/SchemaSettingsRemove';
|
||||
import { css, cx } from '../../style';
|
||||
import { useGlobalTheme } from '../../style/theme';
|
||||
import { gridRowColWrap } from '../utils';
|
||||
|
||||
const FieldComponentProps: React.FC = observer(
|
||||
(props) => {
|
||||
@ -228,7 +226,7 @@ export const FilterCustomItemInitializer: React.FC<{
|
||||
},
|
||||
associationField: {
|
||||
type: 'string',
|
||||
title: tval('Association field'),
|
||||
title: t('Association field'),
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Select',
|
||||
'x-visible': false,
|
||||
@ -290,7 +288,7 @@ export const FilterCustomItemInitializer: React.FC<{
|
||||
});
|
||||
const { title, component, collection, associationField } = values;
|
||||
const defaultSchema = getInterface(component)?.default?.uiSchema || {};
|
||||
const titleField = cm.getCollection(collection).titleField;
|
||||
const titleField = cm.getCollection(collection)?.titleField;
|
||||
const name = uid();
|
||||
insert(
|
||||
gridRowColWrap({
|
||||
@ -300,7 +298,8 @@ export const FilterCustomItemInitializer: React.FC<{
|
||||
name: 'custom.' + name,
|
||||
required: false,
|
||||
'x-component': component,
|
||||
'x-designer': 'FilterItemCustomDesigner',
|
||||
'x-toolbar': 'FormItemSchemaToolbar',
|
||||
'x-settings': 'fieldSettings:FilterFormCustomSettings',
|
||||
'x-decorator': 'FilterFormItem',
|
||||
'x-decorator-props': collection,
|
||||
'x-component-props': {
|
||||
@ -364,18 +363,9 @@ export const FilterItemCustomDesigner: React.FC = () => {
|
||||
{component === 'Select' || component === 'AutoComplete' ? <SchemaSettingComponent /> : null}
|
||||
{component === 'Select' || component === 'AutoComplete' ? <EditTitleField /> : null}
|
||||
{component === 'Select' || component === 'AutoComplete' ? <EditFormulaTitleField /> : null}
|
||||
<EditDefaultValue />
|
||||
<EditCustomDefaultValue />
|
||||
<SchemaSettingsDivider />
|
||||
<SchemaSettingsRemove
|
||||
key="remove"
|
||||
confirm={{
|
||||
title: t('Delete field'),
|
||||
}}
|
||||
removeParentsIfNoChildren
|
||||
breakRemoveOn={{
|
||||
'x-component': 'Grid',
|
||||
}}
|
||||
/>
|
||||
<SchemaSettingsRemove />
|
||||
</GeneralSchemaDesigner>
|
||||
);
|
||||
};
|
@ -21,3 +21,4 @@ export * from './RecordReadPrettyAssociationFormBlockInitializer';
|
||||
export * from './SelectActionInitializer';
|
||||
export * from './SubmitActionInitializer';
|
||||
export * from './TableActionColumnInitializer';
|
||||
export * from './CustomFilterFormItemInitializer';
|
||||
|
@ -0,0 +1,97 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { Field, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { SchemaComponent, useDesignable, VariableScopeProvider } from '../schema-component';
|
||||
import { SchemaSettingsModalItem } from './SchemaSettings';
|
||||
import { getShouldChange, useCurrentUserVariable, useDatetimeVariable, VariableInput } from './VariableInput';
|
||||
|
||||
export const EditCustomDefaultValue = () => {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const collectionName = fieldSchema['collectionName'];
|
||||
const title = fieldSchema.title;
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
key="set field default value"
|
||||
title={t('Set default value')}
|
||||
schema={{
|
||||
type: 'void',
|
||||
title: t('Set default value'),
|
||||
properties: {
|
||||
default: {
|
||||
title,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': FilterCustomVariableInput,
|
||||
'x-component-props': {
|
||||
fieldSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
onSubmit={({ default: { value } }) => {
|
||||
field.setValue(value);
|
||||
fieldSchema['default'] = value;
|
||||
fieldSchema['x-component-props']['defaultValue'] = value;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
['x-component-props']: fieldSchema['x-component-props'],
|
||||
default: fieldSchema.default,
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const FilterCustomVariableInput = (props: any) => {
|
||||
const { value, onChange, fieldSchema } = props;
|
||||
const { currentUserSettings } = useCurrentUserVariable({
|
||||
collectionField: { uiSchema: fieldSchema },
|
||||
uiSchema: fieldSchema,
|
||||
});
|
||||
const { datetimeSettings } = useDatetimeVariable({
|
||||
operator: fieldSchema['x-component-props']?.['filter-operator'],
|
||||
schema: fieldSchema,
|
||||
noDisabled: true,
|
||||
});
|
||||
const options = useMemo(
|
||||
() => [currentUserSettings, datetimeSettings].filter(Boolean),
|
||||
[datetimeSettings, currentUserSettings],
|
||||
);
|
||||
const schema = {
|
||||
...fieldSchema,
|
||||
'x-component': fieldSchema['x-component'] || 'Input',
|
||||
'x-decorator': '',
|
||||
title: '',
|
||||
name: 'value',
|
||||
};
|
||||
const componentProps = fieldSchema['x-component-props'] || {};
|
||||
const handleChange = useMemoizedFn(onChange);
|
||||
useEffect(() => {
|
||||
if (fieldSchema.default) {
|
||||
handleChange({ value: fieldSchema.default });
|
||||
}
|
||||
}, [fieldSchema.default, handleChange]);
|
||||
return (
|
||||
<VariableScopeProvider scope={options}>
|
||||
<VariableInput
|
||||
{...componentProps}
|
||||
renderSchemaComponent={() => <SchemaComponent schema={schema} />}
|
||||
fieldNames={{}}
|
||||
value={value?.value}
|
||||
scope={options}
|
||||
onChange={(v: any) => {
|
||||
onChange({ value: v });
|
||||
}}
|
||||
shouldChange={getShouldChange({} as any)}
|
||||
/>
|
||||
</VariableScopeProvider>
|
||||
);
|
||||
};
|
@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import { Field, ISchema, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useCollection_deprecated, useCollectionManager_deprecated } from '../collection-manager';
|
||||
import { useCompile, useDesignable } from '../schema-component';
|
||||
import { SchemaSettingsModalItem } from './SchemaSettings';
|
||||
|
||||
export const useFormulaTitleOptions = () => {
|
||||
const compile = useCompile();
|
||||
const { getCollectionJoinField, getCollectionFields } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const collectionManage = useCollectionManager_deprecated();
|
||||
const collectionManageField = collectionManage.collections.filter(
|
||||
(value) => value.name === fieldSchema['x-decorator-props'],
|
||||
)[0];
|
||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
let fields = [];
|
||||
if (collectionField) {
|
||||
fields = getCollectionFields(
|
||||
collectionField
|
||||
? collectionField.target
|
||||
? collectionField.target
|
||||
: collectionField.collectionName
|
||||
: fieldSchema['name'],
|
||||
);
|
||||
} else if (collectionManageField) {
|
||||
fields = collectionManageField['fields'];
|
||||
}
|
||||
const options = [];
|
||||
fields?.forEach((field) => {
|
||||
if (field.interface !== 'm2m') {
|
||||
if (field.uiSchema) {
|
||||
options.push({
|
||||
label: compile(field.uiSchema.title),
|
||||
value: field.name,
|
||||
children:
|
||||
getCollectionFields(field.target)
|
||||
?.filter((subField) => subField.uiSchema)
|
||||
.map((subField) => ({
|
||||
label: subField.uiSchema ? compile(subField.uiSchema.title) : '',
|
||||
value: subField.name,
|
||||
})) ?? [],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return options;
|
||||
};
|
||||
|
||||
export const EditFormulaTitleField = () => {
|
||||
const { getCollectionJoinField, collections } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
|
||||
let collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
collectionField = collectionField
|
||||
? collectionField
|
||||
: collections.find((value) => value.name === fieldSchema['x-decorator-props'])?.fields;
|
||||
const options = useFormulaTitleOptions();
|
||||
const editTitle = async (formula) => {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
const fieldNames = {
|
||||
...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'],
|
||||
...field.componentProps.fieldNames,
|
||||
formula,
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps.fieldNames = fieldSchema['x-component-props'].fieldNames;
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
};
|
||||
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
key="edit-field-title"
|
||||
title={t('Custom option label')}
|
||||
schema={
|
||||
{
|
||||
type: 'object',
|
||||
title: t('Custom option label'),
|
||||
properties: {
|
||||
formula: {
|
||||
required: true,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Variable.TextArea',
|
||||
'x-component-props': {
|
||||
scope: options,
|
||||
},
|
||||
default: field?.componentProps?.fieldNames?.formula || '',
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
onSubmit={({ formula }) => {
|
||||
if (formula) {
|
||||
editTitle(formula);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const useFormulaTitleVisible = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const options = useFormulaTitleOptions();
|
||||
// FIXME 这里现在只有当设置为 select,默认为 select 的时候看不到
|
||||
return (
|
||||
options.length > 0 &&
|
||||
(fieldSchema['x-component-props']?.mode === 'Select' || fieldSchema['x-component'] === 'CollectionField') &&
|
||||
fieldSchema['x-component-props']?.fieldNames?.value !== undefined
|
||||
);
|
||||
};
|
@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { Field, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import { useCollectionManager } from '../data-source';
|
||||
import { useDesignable } from '../schema-component';
|
||||
import { SchemaSettingsSelectItem } from './SchemaSettings';
|
||||
|
||||
export const SchemaSettingCollection = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const collections = useCollectionManager();
|
||||
const field = useField<Field>();
|
||||
const options = collections?.dataSource['options']?.collections.map((value) => {
|
||||
return {
|
||||
label: value.title,
|
||||
value: value.name,
|
||||
};
|
||||
});
|
||||
const { dn } = useDesignable();
|
||||
return (
|
||||
<SchemaSettingsSelectItem
|
||||
key="component-field"
|
||||
title="Edit Collection"
|
||||
options={options}
|
||||
value={fieldSchema['collectionName']}
|
||||
onChange={(name) => {
|
||||
field.setValue('');
|
||||
const titleField = collections.getCollection(name).titleField;
|
||||
fieldSchema['collectionName'] = name;
|
||||
fieldSchema.default = '';
|
||||
fieldSchema['x-component-props'] = {
|
||||
...fieldSchema['x-component-props'],
|
||||
collection: name,
|
||||
fieldNames: {
|
||||
label: titleField,
|
||||
value: titleField,
|
||||
},
|
||||
defaultValue: '',
|
||||
};
|
||||
fieldSchema['x-decorator-props'] = name;
|
||||
field.componentProps = fieldSchema['x-component-props'];
|
||||
void dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
collectionName: fieldSchema['collectionName'],
|
||||
['x-component-props']: fieldSchema['x-component-props'],
|
||||
['x-decorator-props']: fieldSchema['x-decorator-props'],
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import { useDesignable } from '../schema-component';
|
||||
import { useFieldComponents } from '../schema-initializer';
|
||||
import { SchemaSettingsSelectItem } from './SchemaSettings';
|
||||
|
||||
export const SchemaSettingComponent = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
const { options } = useFieldComponents();
|
||||
const { dn } = useDesignable();
|
||||
return (
|
||||
<SchemaSettingsSelectItem
|
||||
key="component-field"
|
||||
title="Field Component"
|
||||
options={options}
|
||||
value={fieldSchema['x-component']}
|
||||
onChange={(mode) => {
|
||||
field.component = mode;
|
||||
fieldSchema['x-component'] = mode;
|
||||
field.componentProps = fieldSchema['x-component-props'];
|
||||
void dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
['x-component']: fieldSchema['x-component'],
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
@ -23,6 +23,7 @@ import {
|
||||
detailsBlockSettings,
|
||||
singleDataDetailsBlockSettings,
|
||||
} from '../modules/blocks/data-blocks/details-single/detailsBlockSettings';
|
||||
import { FilterItemCustomSettings } from '../modules/blocks/data-blocks/form';
|
||||
import {
|
||||
createFormBlockSettings,
|
||||
creationFormBlockSettings,
|
||||
@ -95,6 +96,7 @@ export class SchemaSettingsPlugin extends Plugin {
|
||||
|
||||
// field settings
|
||||
this.schemaSettingsManager.add(fieldSettingsFormItem);
|
||||
this.schemaSettingsManager.add(FilterItemCustomSettings);
|
||||
this.schemaSettingsManager.add(tableColumnSettings);
|
||||
this.schemaSettingsManager.add(filterCollapseItemFieldSettings);
|
||||
|
||||
|
@ -1,19 +1,20 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
// @ts-ignore
|
||||
import { Form, Schema } from '@tachybase/schema';
|
||||
import { Form, Schema, useField } from '@tachybase/schema';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { CollectionFieldOptions_deprecated } from '../../collection-manager';
|
||||
import { useVariableScope, Variable } from '../../schema-component';
|
||||
import { CollectionFieldOptions_deprecated, useCollectionManager_deprecated } from '../../collection-manager';
|
||||
import { useCompile, useVariableScope, Variable } from '../../schema-component';
|
||||
import { useValues } from '../../schema-component/antd/filter/useValues';
|
||||
import { VariableOption, VariablesContextType } from '../../variables/types';
|
||||
import { isVariable } from '../../variables/utils/isVariable';
|
||||
import { useDateVariable } from './hooks';
|
||||
import { useBlockCollection } from './hooks/useBlockCollection';
|
||||
import { useContextAssociationFields } from './hooks/useContextAssociationFields';
|
||||
import { useCurrentRecordVariable } from './hooks/useRecordVariable';
|
||||
import { useCurrentUserVariable } from './hooks/useUserVariable';
|
||||
import { useCurrentUserVariable, useUserVariable } from './hooks/useUserVariable';
|
||||
import { useVariableOptions } from './hooks/useVariableOptions';
|
||||
import { Option } from './type';
|
||||
|
||||
|
@ -0,0 +1,61 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Field, useField } from '@tachybase/schema';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useFormActiveFields } from '../../../block-provider';
|
||||
import { useFilterContext } from '../../filter-form/context';
|
||||
|
||||
/**
|
||||
* 变量:`自定义筛选`
|
||||
* @param props
|
||||
* @returns
|
||||
*/
|
||||
export const useFilterVariable = (props: any = {}) => {
|
||||
const customFilter = useFilterContext();
|
||||
const field = useField<Field>();
|
||||
const { getActiveFieldsName } = useFormActiveFields();
|
||||
const activeFields = getActiveFieldsName('form');
|
||||
const fields = props?.form?.fields;
|
||||
const { t } = useTranslation();
|
||||
const settings = useMemo(() => {
|
||||
const customFields = [];
|
||||
|
||||
for (const field in fields) {
|
||||
customFields.push({
|
||||
key: field,
|
||||
...fields[field],
|
||||
});
|
||||
}
|
||||
const options = customFields
|
||||
.filter((value) => value?.props?.name.includes('custom.'))
|
||||
.map((custom) => {
|
||||
if (activeFields.includes(custom?.props?.name)) {
|
||||
const value = custom?.props?.name.replace(/^custom\./, '');
|
||||
return {
|
||||
key: custom?.props?.name,
|
||||
value,
|
||||
label: custom.title,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
return {
|
||||
label: t('Current filter'),
|
||||
value: '$nFilter',
|
||||
key: '$nFilter',
|
||||
children: options,
|
||||
};
|
||||
}, [fields]);
|
||||
|
||||
return {
|
||||
/** 变量配置 */
|
||||
currentCustomFilterSetting: settings,
|
||||
/** 变量值 */
|
||||
currentCustonFilterCtx: field?.value,
|
||||
/** 用于判断是否需要显示配置项 */
|
||||
shouldDisplayCustomFilter: !!customFilter,
|
||||
};
|
||||
};
|
@ -4,6 +4,7 @@ import { Form, ISchema, Schema } from '@tachybase/schema';
|
||||
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
|
||||
import { useBlockCollection } from './useBlockCollection';
|
||||
import { useDatetimeVariable } from './useDateVariable';
|
||||
import { useFilterVariable } from './useFilterVariable';
|
||||
import { useCurrentFormVariable } from './useFormVariable';
|
||||
import { useCurrentObjectVariable } from './useIterationVariable';
|
||||
import { useCurrentParentRecordVariable } from './useParentRecordVariable';
|
||||
@ -96,6 +97,14 @@ export const useVariableOptions = ({
|
||||
targetFieldSchema,
|
||||
});
|
||||
|
||||
const { currentCustomFilterSetting, shouldDisplayCustomFilter } = useFilterVariable({
|
||||
schema: uiSchema,
|
||||
form,
|
||||
collectionName: blockParentCollectionName,
|
||||
collectionField,
|
||||
targetFieldSchema,
|
||||
});
|
||||
|
||||
return useMemo(() => {
|
||||
return [
|
||||
currentUserSettings,
|
||||
@ -106,6 +115,7 @@ export const useVariableOptions = ({
|
||||
shouldDisplayCurrentRecord && currentRecordSettings,
|
||||
shouldDisplayCurrentParentRecord && currentParentRecordSettings,
|
||||
shouldDisplayPopupRecord && popupRecordSettings,
|
||||
shouldDisplayCustomFilter && currentCustomFilterSetting,
|
||||
].filter(Boolean);
|
||||
}, [
|
||||
currentUserSettings,
|
||||
@ -121,5 +131,7 @@ export const useVariableOptions = ({
|
||||
currentParentRecordSettings,
|
||||
shouldDisplayPopupRecord,
|
||||
popupRecordSettings,
|
||||
currentCustomFilterSetting,
|
||||
shouldDisplayCustomFilter,
|
||||
]);
|
||||
};
|
||||
|
@ -1,34 +1,30 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
__UNSAFE__DynamicComponentProps,
|
||||
__UNSAFE__VariableOption,
|
||||
__UNSAFE__VariablesContextType,
|
||||
css,
|
||||
FormBlockContext,
|
||||
getShouldChange,
|
||||
RecordProvider,
|
||||
SchemaComponent,
|
||||
useCollectionManager_deprecated,
|
||||
} from '@tachybase/client';
|
||||
import { ArrayCollapse } from '@tachybase/components';
|
||||
import { Form, observer, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import { css } from 'antd-style';
|
||||
|
||||
import { FormBlockContext } from '../../block-provider';
|
||||
import { useCollectionManager_deprecated } from '../../collection-manager';
|
||||
import { RecordProvider } from '../../record-provider';
|
||||
import { SchemaComponent } from '../../schema-component';
|
||||
import { DynamicComponentProps } from '../../schema-component/antd/filter/DynamicComponent';
|
||||
import { VariableOption, VariablesContextType } from '../../variables/types';
|
||||
import { getShouldChange, VariableInput } from '../VariableInput';
|
||||
import { FilterContext } from './context';
|
||||
import { VariableInput } from './VariableInput';
|
||||
|
||||
interface usePropsReturn {
|
||||
options: any;
|
||||
defaultValues: any[];
|
||||
collectionName: string;
|
||||
form: Form;
|
||||
variables: __UNSAFE__VariablesContextType;
|
||||
localVariables: __UNSAFE__VariableOption | __UNSAFE__VariableOption[];
|
||||
variables: VariablesContextType;
|
||||
localVariables: VariableOption | VariableOption[];
|
||||
record: Record<string, any>;
|
||||
/**
|
||||
* create 表示创建表单,update 表示更新表单
|
||||
*/
|
||||
formBlockType: 'create' | 'update';
|
||||
fields: any;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
@ -40,7 +36,7 @@ export const FormFilterScope = observer(
|
||||
(props: Props) => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { useProps, dynamicComponent } = props;
|
||||
const { options, defaultValues, collectionName, form, formBlockType, variables, localVariables, record, fields } =
|
||||
const { options, defaultValues, collectionName, form, formBlockType, variables, localVariables, record } =
|
||||
useProps();
|
||||
const { getAllCollectionsInheritChain } = useCollectionManager_deprecated();
|
||||
const components = useMemo(() => ({ ArrayCollapse }), []);
|
||||
@ -63,7 +59,7 @@ export const FormFilterScope = observer(
|
||||
`,
|
||||
};
|
||||
},
|
||||
dynamicComponent: (props: __UNSAFE__DynamicComponentProps) => {
|
||||
dynamicComponent: (props: DynamicComponentProps) => {
|
||||
const { collectionField } = props;
|
||||
return (
|
||||
<VariableInput
|
||||
@ -77,7 +73,6 @@ export const FormFilterScope = observer(
|
||||
localVariables,
|
||||
getAllCollectionsInheritChain,
|
||||
})}
|
||||
fields={fields}
|
||||
/>
|
||||
);
|
||||
},
|
||||
@ -85,15 +80,20 @@ export const FormFilterScope = observer(
|
||||
},
|
||||
},
|
||||
}),
|
||||
[collectionName, defaultValues, form, localVariables, options, props, record, variables, fields],
|
||||
[collectionName, defaultValues, form, localVariables, options, props, record, variables],
|
||||
);
|
||||
const value = useMemo(
|
||||
() => ({ field: options, fieldSchema, dynamicComponent, options: options || [] }),
|
||||
() => ({
|
||||
field: options,
|
||||
fieldSchema,
|
||||
dynamicComponent,
|
||||
options: options || [],
|
||||
}),
|
||||
[dynamicComponent, fieldSchema, options],
|
||||
);
|
||||
|
||||
return (
|
||||
<FormBlockContext.Provider value={{ form, type: formBlockType }}>
|
||||
<FormBlockContext.Provider value={{ form, type: formBlockType, collectionName: collectionName }}>
|
||||
<RecordProvider record={record}>
|
||||
<FilterContext.Provider value={value}>
|
||||
<SchemaComponent components={components} schema={schema} />
|
@ -1,4 +1,4 @@
|
||||
import { createContext } from 'react';
|
||||
import { createContext, useContext } from 'react';
|
||||
import { ObjectField, Schema } from '@tachybase/schema';
|
||||
|
||||
export interface FilterContextProps {
|
||||
@ -8,8 +8,13 @@ export interface FilterContextProps {
|
||||
options?: any[];
|
||||
disabled?: boolean;
|
||||
collectionName?: string;
|
||||
customFilter?: boolean;
|
||||
}
|
||||
|
||||
export const RemoveConditionContext = createContext(null);
|
||||
export const FilterContext = createContext<FilterContextProps>(null);
|
||||
export const FilterLogicContext = createContext(null);
|
||||
|
||||
export const useFilterContext = () => {
|
||||
return useContext(FilterContext);
|
||||
};
|
@ -9,6 +9,10 @@ export * from './SchemaSettingsDataScope';
|
||||
export * from './SchemaSettingsDefaultValue';
|
||||
export * from './SchemaSettingsDateFormat';
|
||||
export * from './SchemaSettingsSortingRule';
|
||||
export * from './SchemaSettingCollection';
|
||||
export * from './SchemaSettingComponent';
|
||||
export * from './EditFormulaTitleField';
|
||||
export * from './EditCustomDefaultValue';
|
||||
|
||||
export { default as useParseDataScopeFilter } from './hooks/useParseDataScopeFilter';
|
||||
|
||||
|
@ -1,58 +0,0 @@
|
||||
export {
|
||||
removeGridFormItem,
|
||||
useInheritsFormItemInitializerFields,
|
||||
useFormItemInitializerFields,
|
||||
useAssociatedFormItemInitializerFields,
|
||||
useFilterInheritsFormItemInitializerFields,
|
||||
useFilterFormItemInitializerFields,
|
||||
} from './schema-initializer/utils';
|
||||
export { parseVariables } from './schema-component/common/utils/uitls';
|
||||
export { linkageAction } from './schema-component/antd/action/utils';
|
||||
export { useCollectionState } from './schema-settings/DataTemplates/hooks/useCollectionState';
|
||||
export { useSyncFromForm } from './schema-settings/DataTemplates/utils';
|
||||
export { ColumnFieldProvider } from './schema-component/antd/table-v2/components/ColumnFieldProvider';
|
||||
export { default as schema } from './schema-component/antd/association-field/schema';
|
||||
export { ReadPrettyInternalViewer } from './schema-component/antd/association-field/InternalViewer';
|
||||
export { useSetAriaLabelForPopover } from './schema-component/antd/action/hooks/useSetAriaLabelForPopover';
|
||||
export { InternalFileManager } from './schema-component/antd/association-field/FileManager';
|
||||
export { CreateRecordAction } from './schema-component/antd/association-field/components/CreateRecordAction';
|
||||
export { AssociationSelect } from './schema-component/antd/association-field/AssociationSelect';
|
||||
export { AssociationFieldProvider } from './schema-component/antd/association-field/AssociationFieldProvider';
|
||||
export { InternalCascadeSelect } from './schema-component/antd/association-field/InternalCascadeSelect';
|
||||
export { InternalNester } from './schema-component/antd/association-field/InternalNester';
|
||||
export { InternalPicker } from './schema-component/antd/association-field/InternalPicker';
|
||||
export { InternalSubTable } from './schema-component/antd/association-field/InternalSubTable';
|
||||
export { InternaPopoverNester } from './schema-component/antd/association-field/InternalPopoverNester';
|
||||
export { InternalCascader } from './schema-component/antd/association-field/InternalCascader';
|
||||
export { Nester } from './schema-component/antd/association-field/Nester';
|
||||
export { SubTable } from './schema-component/antd/association-field/SubTable';
|
||||
export { ReadPretty } from './schema-component/antd/association-field/ReadPretty';
|
||||
export { SubFormProvider } from './schema-component/antd/association-field/hooks';
|
||||
export { useAssociationFieldContext } from './schema-component/antd/association-field/hooks';
|
||||
export { FlagProvider } from './flag-provider';
|
||||
export { isVariable } from './variables/utils/isVariable';
|
||||
export { transformVariableValue } from './variables/utils/transformVariableValue';
|
||||
export { useVariables } from './variables';
|
||||
export { VariableInput, getShouldChange } from './schema-settings/VariableInput/VariableInput';
|
||||
export { useLocalVariables } from './variables';
|
||||
export { VariablesContext } from './variables/VariablesProvider';
|
||||
export {
|
||||
EditComponent,
|
||||
EditDescription,
|
||||
EditOperator,
|
||||
EditTitle,
|
||||
EditTitleField,
|
||||
EditTooltip,
|
||||
EditValidationRules,
|
||||
} from './schema-component/antd/form-item/SchemaSettingOptions';
|
||||
export type { DynamicComponentProps } from './schema-component/antd/filter/DynamicComponent';
|
||||
export { DetailsBlockProvider, useDetailsBlockContext } from './block-provider/DetailsBlockProvider';
|
||||
export { getInnermostKeyAndValue } from './schema-component/common/utils/uitls';
|
||||
export { default as useServiceOptions } from './schema-component/antd/association-field/hooks';
|
||||
export type { VariablesContextType, VariableOption } from './variables/types';
|
||||
export type { Option } from './schema-settings/VariableInput/type';
|
||||
export { useBlockCollection } from './schema-settings/VariableInput/hooks/useBlockCollection';
|
||||
export { useValues } from './schema-component/antd/filter/useValues';
|
||||
export { useVariableOptions } from './schema-settings/VariableInput/hooks/useVariableOptions';
|
||||
export { useContextAssociationFields } from './schema-settings/VariableInput/hooks/useContextAssociationFields';
|
||||
export { useRecordVariable } from './schema-settings/VariableInput/hooks/useRecordVariable';
|
@ -47,11 +47,13 @@ export const nextTick = (fn: () => void) => {
|
||||
};
|
||||
|
||||
export function fuzzysearch(needle: string, haystack: string): boolean {
|
||||
const hlen = haystack.length;
|
||||
const nlen = needle.length;
|
||||
if (nlen > hlen) {
|
||||
if (!needle || !haystack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hlen = haystack.length;
|
||||
const nlen = needle.length;
|
||||
|
||||
if (nlen === hlen) {
|
||||
return needle === haystack;
|
||||
}
|
||||
|
@ -1,399 +0,0 @@
|
||||
import React, { useCallback, useContext, useMemo } from 'react';
|
||||
import {
|
||||
__UNSAFE__,
|
||||
__UNSAFE__VariableInputOption,
|
||||
__UNSAFE__VariableOption,
|
||||
__UNSAFE__VariablesContextType,
|
||||
CollectionFieldOptions,
|
||||
isVariable,
|
||||
useCollectionManager_deprecated,
|
||||
useCompile,
|
||||
useDateVariable,
|
||||
useUserVariable,
|
||||
useVariableScope,
|
||||
Variable,
|
||||
} from '@tachybase/client';
|
||||
// @ts-ignore
|
||||
import { Form, Schema, SchemaOptionsContext, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { FilterContext } from './context';
|
||||
|
||||
const { useBlockCollection, useValues, useVariableOptions, useContextAssociationFields, useRecordVariable } =
|
||||
__UNSAFE__;
|
||||
|
||||
interface GetShouldChangeProps {
|
||||
collectionField: CollectionFieldOptions;
|
||||
variables: __UNSAFE__VariablesContextType;
|
||||
localVariables: __UNSAFE__VariableOption | __UNSAFE__VariableOption[];
|
||||
/** `useCollectionManager` 返回的 */
|
||||
getAllCollectionsInheritChain: (collectionName: string) => string[];
|
||||
}
|
||||
|
||||
interface RenderSchemaComponentProps {
|
||||
value: any;
|
||||
onChange: (value: any) => void;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
value: any;
|
||||
onChange: (value: any, optionPath?: any[]) => void;
|
||||
renderSchemaComponent: (props: RenderSchemaComponentProps) => any;
|
||||
schema?: any;
|
||||
/** 消费变量值的字段 */
|
||||
targetFieldSchema?: Schema;
|
||||
children?: any;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
collectionField: CollectionFieldOptions;
|
||||
contextCollectionName?: string;
|
||||
/**指定当前表单数据表 */
|
||||
currentFormCollectionName?: string;
|
||||
/**指定当前对象数据表 */
|
||||
currentIterationCollectionName?: string;
|
||||
/**
|
||||
* 根据 `onChange` 的第一个参数,判断是否需要触发 `onChange`
|
||||
* @param value `onChange` 的第一个参数
|
||||
* @returns 返回为 `true` 时,才会触发 `onChange`
|
||||
*/
|
||||
shouldChange?: (value: any, optionPath?: any[]) => Promise<boolean>;
|
||||
form?: Form;
|
||||
/**
|
||||
* 当前表单的记录,数据来自数据库
|
||||
*/
|
||||
record?: Record<string, any>;
|
||||
/**
|
||||
* 可以用该方法对内部的 scope 进行筛选和修改
|
||||
* @param scope
|
||||
* @returns
|
||||
*/
|
||||
returnScope?: (scope: __UNSAFE__VariableInputOption[]) => any[];
|
||||
fields: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* 注意:该组件存在以下问题:
|
||||
* - 在选中选项的时候该组件不能触发重渲染
|
||||
* - 如果触发重渲染可能会导致无法展开子选项列表
|
||||
* @param props
|
||||
* @returns
|
||||
*/
|
||||
export const VariableInput = (props: Props) => {
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
renderSchemaComponent: RenderSchemaComponent,
|
||||
style,
|
||||
schema,
|
||||
className,
|
||||
contextCollectionName,
|
||||
collectionField,
|
||||
shouldChange,
|
||||
form,
|
||||
record,
|
||||
returnScope = _.identity,
|
||||
targetFieldSchema,
|
||||
currentFormCollectionName,
|
||||
currentIterationCollectionName,
|
||||
fields,
|
||||
} = props;
|
||||
const { name: blockCollectionName } = useBlockCollection();
|
||||
const scope = useVariableScope();
|
||||
const { operator, schema: uiSchema = collectionField?.uiSchema } = useValues();
|
||||
|
||||
const variableOptions = useVariableOptions({
|
||||
collectionField,
|
||||
form,
|
||||
record,
|
||||
operator,
|
||||
uiSchema,
|
||||
targetFieldSchema,
|
||||
});
|
||||
const contextVariable = useContextAssociationFields({ schema, maxDepth: 2, contextCollectionName, collectionField });
|
||||
const { compatOldVariables } = useCompatOldVariables({
|
||||
collectionField,
|
||||
uiSchema,
|
||||
targetFieldSchema,
|
||||
blockCollectionName,
|
||||
});
|
||||
|
||||
if (contextCollectionName && variableOptions.every((item) => item.value !== contextVariable.value)) {
|
||||
variableOptions.push(contextVariable);
|
||||
}
|
||||
|
||||
const handleChange = useCallback(
|
||||
(value: any, optionPath: any[]) => {
|
||||
if (!shouldChange) {
|
||||
return onChange(value);
|
||||
}
|
||||
|
||||
// `shouldChange` 这个函数的运算量比较大,会导致展开变量列表时有明显的卡顿感,在这里加个延迟能有效解决这个问题
|
||||
setTimeout(async () => {
|
||||
if (await shouldChange(value, optionPath)) {
|
||||
onChange(value);
|
||||
}
|
||||
});
|
||||
},
|
||||
[onChange, shouldChange],
|
||||
);
|
||||
const options = useVariableCustomOptions(fields);
|
||||
return (
|
||||
<Variable.Input
|
||||
className={className}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
scope={options}
|
||||
style={style}
|
||||
changeOnSelect
|
||||
>
|
||||
<RenderSchemaComponent value={value} onChange={onChange} />
|
||||
</Variable.Input>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 通过限制用户的选择,来防止用户选择错误的变量
|
||||
*/
|
||||
export const getShouldChange = ({
|
||||
collectionField,
|
||||
variables,
|
||||
localVariables,
|
||||
getAllCollectionsInheritChain,
|
||||
}: GetShouldChangeProps) => {
|
||||
const collectionsInheritChain = collectionField ? getAllCollectionsInheritChain(collectionField.target) : [];
|
||||
|
||||
return async (value: any, optionPath: any[]) => {
|
||||
if (_.isString(value) && value.includes('$nRole')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isVariable(value) || !variables || !collectionField) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// `json` 可以选择任意类型的变量,详见:https://tachybase.feishu.cn/docx/EmNEdEBOnoQohUx2UmBcqIQ5nyh#FPLfdSRDEoXR65xW0mBcdfL5n0c
|
||||
if (collectionField.interface === 'json') {
|
||||
return true;
|
||||
}
|
||||
|
||||
const lastOption = optionPath[optionPath.length - 1];
|
||||
|
||||
// 点击叶子节点时,必须更新 value
|
||||
if (lastOption && _.isEmpty(lastOption.children) && !lastOption.loadChildren) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const collectionFieldOfVariable = await variables.getCollectionField(value, localVariables);
|
||||
|
||||
if (!collectionField) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// `一对一` 和 `一对多` 的不能用于设置默认值,因为其具有唯一性
|
||||
if (['o2o', 'o2m', 'oho'].includes(collectionFieldOfVariable?.interface)) {
|
||||
return false;
|
||||
}
|
||||
if (!collectionField.target && collectionFieldOfVariable?.target) {
|
||||
return false;
|
||||
}
|
||||
if (collectionField.target && !collectionFieldOfVariable?.target) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
collectionField.target &&
|
||||
collectionFieldOfVariable?.target &&
|
||||
!collectionsInheritChain.includes(collectionFieldOfVariable?.target)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
export interface FormatVariableScopeParam {
|
||||
children: any[];
|
||||
disabled: boolean;
|
||||
name: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface FormatVariableScopeReturn {
|
||||
value: string;
|
||||
key: string;
|
||||
label: string;
|
||||
disabled: boolean;
|
||||
children?: any[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容老版本的变量
|
||||
* @param variables
|
||||
*/
|
||||
export function useCompatOldVariables(props: {
|
||||
uiSchema: any;
|
||||
collectionField: CollectionFieldOptions;
|
||||
blockCollectionName: string;
|
||||
noDisabled?: boolean;
|
||||
targetFieldSchema?: Schema;
|
||||
}) {
|
||||
const { uiSchema, collectionField, noDisabled, targetFieldSchema, blockCollectionName } = props;
|
||||
const { t } = useTranslation();
|
||||
const lowLevelUserVariable = useUserVariable({
|
||||
maxDepth: 1,
|
||||
uiSchema: uiSchema,
|
||||
collectionField,
|
||||
noDisabled,
|
||||
targetFieldSchema,
|
||||
});
|
||||
const currentRecordVariable = useRecordVariable({
|
||||
schema: uiSchema,
|
||||
collectionName: blockCollectionName,
|
||||
collectionField,
|
||||
noDisabled,
|
||||
targetFieldSchema,
|
||||
});
|
||||
|
||||
const compatOldVariables = useCallback(
|
||||
(variables: __UNSAFE__VariableInputOption[], { value }) => {
|
||||
if (!isVariable(value)) {
|
||||
return variables;
|
||||
}
|
||||
|
||||
variables = _.cloneDeep(variables);
|
||||
|
||||
const systemVariable: __UNSAFE__VariableInputOption = {
|
||||
value: '$system',
|
||||
key: '$system',
|
||||
label: t('System variables'),
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{
|
||||
value: 'now',
|
||||
key: 'now',
|
||||
label: t('Current time'),
|
||||
isLeaf: true,
|
||||
depth: 1,
|
||||
},
|
||||
],
|
||||
depth: 0,
|
||||
};
|
||||
const currentTime = {
|
||||
value: 'currentTime',
|
||||
label: t('Current time'),
|
||||
children: null,
|
||||
};
|
||||
|
||||
if (value.includes('$system')) {
|
||||
variables.push(systemVariable);
|
||||
}
|
||||
|
||||
if (value.includes(`${blockCollectionName}.`)) {
|
||||
const variable = variables.find((item) => item.value === '$nForm' || item.value === '$nRecord');
|
||||
if (variable) {
|
||||
variable.value = blockCollectionName;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.includes('$form')) {
|
||||
const variable = variables.find((item) => item.value === '$nForm');
|
||||
if (variable) {
|
||||
variable.value = '$form';
|
||||
}
|
||||
}
|
||||
|
||||
if (value.includes('currentUser')) {
|
||||
const userVariable = variables.find((item) => item.value === '$user');
|
||||
if (userVariable) {
|
||||
userVariable.value = 'currentUser';
|
||||
} else {
|
||||
variables.unshift({ ...lowLevelUserVariable, value: 'currentUser' });
|
||||
}
|
||||
}
|
||||
|
||||
if (value.includes('currentRecord')) {
|
||||
const formVariable = variables.find((item) => item.value === '$nRecord');
|
||||
if (formVariable) {
|
||||
formVariable.value = 'currentRecord';
|
||||
} else {
|
||||
variables.unshift({ ...currentRecordVariable, value: 'currentRecord' });
|
||||
}
|
||||
}
|
||||
|
||||
if (value.includes('currentTime')) {
|
||||
variables.push(currentTime);
|
||||
}
|
||||
|
||||
if (value.includes('$date')) {
|
||||
const formVariable = variables.find((item) => item.value === '$nDate');
|
||||
if (formVariable) {
|
||||
formVariable.value = '$date';
|
||||
}
|
||||
}
|
||||
|
||||
return variables;
|
||||
},
|
||||
[blockCollectionName],
|
||||
);
|
||||
|
||||
return { compatOldVariables };
|
||||
}
|
||||
|
||||
export const useVariableCustomOptions = (fields) => {
|
||||
const field = useField<any>();
|
||||
const { operator, schema } = field.data || {};
|
||||
const userVariable = useUserVariable({
|
||||
collectionField: { uiSchema: schema },
|
||||
uiSchema: schema,
|
||||
});
|
||||
const dateVariable = useDateVariable({ operator, schema });
|
||||
const filterVariable = useFilterVariable(fields);
|
||||
|
||||
const result = useMemo(
|
||||
() => [userVariable, dateVariable, filterVariable].filter(Boolean),
|
||||
[dateVariable, userVariable, filterVariable],
|
||||
);
|
||||
|
||||
if (!operator || !schema) return [];
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const useFilterVariable = (fields) => {
|
||||
const { t } = useTranslation();
|
||||
const compile = useCompile();
|
||||
const { collections } = useCollectionManager_deprecated();
|
||||
const customFields = [];
|
||||
for (const field in fields) {
|
||||
customFields.push({
|
||||
key: field,
|
||||
...fields[field],
|
||||
});
|
||||
}
|
||||
|
||||
const options = customFields
|
||||
.filter((value) => value?.props?.name.includes('custom.'))
|
||||
.map((custom) => {
|
||||
const value = custom?.props?.name.replace(/^custom\./, '');
|
||||
return {
|
||||
key: custom?.props?.name,
|
||||
value,
|
||||
label: custom.title,
|
||||
};
|
||||
});
|
||||
const result = useMemo(
|
||||
() => ({
|
||||
label: t('Current filter'),
|
||||
value: '$nFilter',
|
||||
key: '$nFilter',
|
||||
children: options,
|
||||
}),
|
||||
[options, t],
|
||||
);
|
||||
|
||||
if (!options.length) return null;
|
||||
|
||||
return result;
|
||||
};
|
@ -1,57 +0,0 @@
|
||||
import { Plugin, useCollection } from '@tachybase/client';
|
||||
|
||||
import { useFilterBlockActionProps } from '../../hooks/useFilterBlockActionProps';
|
||||
import { useFilterFormCustomProps } from '../../hooks/useFilterFormCustomProps';
|
||||
import { tval } from '../../locale';
|
||||
import { FilterFormItem, FilterFormItemCustom, FilterItemCustomDesigner } from '../../schema-initializer';
|
||||
import {
|
||||
EditDefaultValue,
|
||||
EditFormulaTitleField,
|
||||
FilterVariableInput,
|
||||
SetFilterScope,
|
||||
useFormulaTitleVisible,
|
||||
useSetFilterScopeVisible,
|
||||
} from '../../schema-settings';
|
||||
|
||||
export class PluginExtendedFilterForm extends Plugin {
|
||||
async load() {
|
||||
this.app.addScopes({
|
||||
useFilterBlockActionProps,
|
||||
useFilterFormCustomProps,
|
||||
});
|
||||
this.app.addComponents({
|
||||
FilterFormItem,
|
||||
FilterFormItemCustom,
|
||||
FilterItemCustomDesigner,
|
||||
FilterVariableInput,
|
||||
});
|
||||
this.schemaSettingsManager.addItem('fieldSettings:component:Select', 'formulatitleField', {
|
||||
Component: EditFormulaTitleField,
|
||||
useVisible: useFormulaTitleVisible,
|
||||
});
|
||||
this.schemaSettingsManager.addItem('fieldSettings:component:Select', 'editDefaultValue', {
|
||||
Component: EditDefaultValue,
|
||||
});
|
||||
const customItem = {
|
||||
title: tval('Custom filter field'),
|
||||
name: 'custom',
|
||||
type: 'item',
|
||||
Component: 'FilterFormItemCustom',
|
||||
};
|
||||
this.app.schemaInitializerManager.addItem('filterForm:configureFields', 'custom-item-divider', {
|
||||
type: 'divider',
|
||||
});
|
||||
this.app.schemaInitializerManager.addItem('filterForm:configureFields', customItem.name, customItem);
|
||||
|
||||
this.schemaSettingsManager.addItem('ActionSettings', 'Customize.setFilterScope', {
|
||||
Component: SetFilterScope,
|
||||
useVisible: useSetFilterScopeVisible,
|
||||
useComponentProps() {
|
||||
const collection = useCollection();
|
||||
return {
|
||||
collectionName: collection.name,
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
import {
|
||||
findFilterTargets,
|
||||
mergeFilter,
|
||||
transformToFilter,
|
||||
useCollection_deprecated,
|
||||
useCollectionManager_deprecated,
|
||||
useFilterBlock,
|
||||
} from '@tachybase/client';
|
||||
import { isEmpty, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||
|
||||
import flat from 'flat';
|
||||
|
||||
import { hasDuplicateKeys } from '../utils';
|
||||
|
||||
export const removeNullCondition = (filter, fieldSchema?) => {
|
||||
const filterSchema = fieldSchema ? fieldSchema['x-filter-rules'] : '';
|
||||
const filterSchemaItem = flat(filterSchema || '');
|
||||
const items = flat(filter || {});
|
||||
const values = {};
|
||||
const isCustomFilter = filterSchema?.$and?.length || filterSchema?.$or?.length;
|
||||
const isFilterCustom = isCustomFilter ? hasDuplicateKeys(items, filterSchemaItem) : false;
|
||||
if (!isFilterCustom) {
|
||||
if (isCustomFilter) {
|
||||
for (const filterKey in filterSchemaItem) {
|
||||
const match = filterSchemaItem[filterKey]?.slice(11, -2);
|
||||
const collection = match?.split('.')[0];
|
||||
const filterItems = Object.keys(items).filter((item) => item.includes(collection))[0];
|
||||
if (filterItems) {
|
||||
filterSchemaItem[filterKey] = items[filterItems];
|
||||
}
|
||||
}
|
||||
for (const item in items) {
|
||||
if (!item.includes('custom')) {
|
||||
values[item] = items[item];
|
||||
}
|
||||
}
|
||||
for (const item in filterSchemaItem) {
|
||||
if (filterSchemaItem[item].includes('$nFilter')) {
|
||||
delete filterSchemaItem[item];
|
||||
}
|
||||
}
|
||||
const flatValue = flat.unflatten(values);
|
||||
const flatFieldSchema = flat.unflatten(filterSchemaItem);
|
||||
flatValue['$and'] = flatValue['$and']?.filter(Boolean);
|
||||
flatFieldSchema['$and'] = flatFieldSchema['$and']?.filter(Boolean);
|
||||
return {
|
||||
$and: [flatValue, flatFieldSchema],
|
||||
};
|
||||
} else {
|
||||
for (const key in items) {
|
||||
const value = items[key];
|
||||
if (!key.includes('custom') && value != null && !isEmpty(value)) {
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
return flat.unflatten(values);
|
||||
}
|
||||
} else {
|
||||
return flat.unflatten(items);
|
||||
}
|
||||
};
|
||||
|
||||
export const useFilterBlockActionProps = () => {
|
||||
const form = useForm();
|
||||
const actionField = useField();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { getDataBlocks } = useFilterBlock();
|
||||
const { name } = useCollection_deprecated();
|
||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
|
||||
actionField.data = actionField.data || {};
|
||||
|
||||
return {
|
||||
async onClick() {
|
||||
const { targets = [], uid } = findFilterTargets(fieldSchema);
|
||||
|
||||
actionField.data.loading = true;
|
||||
try {
|
||||
// 收集 filter 的值
|
||||
await Promise.all(
|
||||
getDataBlocks().map(async (block) => {
|
||||
const target = targets.find((target) => target.uid === block.uid);
|
||||
if (!target) return;
|
||||
const param = block.service.params?.[0] || {};
|
||||
for (const key in form.values) {
|
||||
if (
|
||||
(typeof form.values[key] === 'object' &&
|
||||
(JSON.stringify(form.values[key]) === '{}' || JSON.stringify(form.values[key]) === '[]')) ||
|
||||
!form.values[key]
|
||||
) {
|
||||
delete form.values[key];
|
||||
}
|
||||
}
|
||||
// 保留原有的 filter
|
||||
const storedFilter = block.service.params?.[1]?.filters || {};
|
||||
storedFilter[uid] = removeNullCondition(
|
||||
transformToFilter(form.values, fieldSchema, getCollectionJoinField, name),
|
||||
fieldSchema,
|
||||
);
|
||||
if (block.defaultFilter) {
|
||||
getDataBlocks().forEach((getblock) => {
|
||||
if (getblock.uid !== block.uid && getblock.collection.name === block.collection.name) {
|
||||
getblock['defaultFilter'] = block.defaultFilter;
|
||||
}
|
||||
});
|
||||
}
|
||||
const mergedFilter = mergeFilter([
|
||||
...Object.values(storedFilter).map((filter) => removeNullCondition(filter, fieldSchema)),
|
||||
block.defaultFilter,
|
||||
]);
|
||||
return block.doFilter(
|
||||
{
|
||||
...param,
|
||||
page: 1,
|
||||
filter: mergedFilter,
|
||||
},
|
||||
{ filters: storedFilter },
|
||||
);
|
||||
}),
|
||||
);
|
||||
actionField.data.loading = false;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
actionField.data.loading = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import { EditTitleField, Plugin } from '@tachybase/client';
|
||||
import { Plugin, useFormulaTitleVisible } from '@tachybase/client';
|
||||
import { CodeMirror } from '@tachybase/components';
|
||||
import { autorun, isValid, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
@ -18,10 +18,8 @@ import { PluginAssistant } from './features/assistant';
|
||||
import { PluginGroupBlock } from './features/block-group';
|
||||
import { PluginContextMenu } from './features/context-menu';
|
||||
import { PluginCustomComponents } from './features/custom-components';
|
||||
import { PluginDemo } from './features/demo';
|
||||
import { DepartmentsPlugin } from './features/departments';
|
||||
import { EmbedPlugin } from './features/embed';
|
||||
import { PluginExtendedFilterForm } from './features/extended-filter-form';
|
||||
import { PluginFieldAppends } from './features/field-appends';
|
||||
import { PluginHeraVersion } from './features/hera-version';
|
||||
import { PluginOutbound } from './features/outbound';
|
||||
@ -45,14 +43,7 @@ import { AutoComplete } from './schema-components';
|
||||
import AssociationCascader from './schema-components/association-cascader/AssociationCascader';
|
||||
import { CreateSubmitActionInitializer, SettingBlockInitializer } from './schema-initializer';
|
||||
import { useCreateActionProps } from './schema-initializer/actions/hooks/useCreateActionProps';
|
||||
import {
|
||||
EditFormulaTitleField,
|
||||
EditTitle,
|
||||
IsTablePageSize,
|
||||
PageModeSetting,
|
||||
useFormulaTitleVisible,
|
||||
usePaginationVisible,
|
||||
} from './schema-settings';
|
||||
import { EditTitle, IsTablePageSize, PageModeSetting, usePaginationVisible } from './schema-settings';
|
||||
import { SchemaSettingsDatePickerType } from './schema-settings/SchemaSettingsDatePickerType';
|
||||
import {
|
||||
SchemaSettingsDatePresets,
|
||||
@ -77,7 +68,6 @@ export class PluginCoreClient extends Plugin {
|
||||
await this.app.pm.add(PluginContextMenu);
|
||||
await this.app.pm.add(PluginAssistant);
|
||||
await this.app.pm.add(PluginPDF);
|
||||
await this.app.pm.add(PluginExtendedFilterForm);
|
||||
await this.app.pm.add(PluginOutbound);
|
||||
// await this.app.pm.add(PluginModeHighlight);
|
||||
await this.app.pm.add(PluginFieldAppends);
|
||||
@ -108,10 +98,6 @@ export class PluginCoreClient extends Plugin {
|
||||
return v1 || v2;
|
||||
},
|
||||
});
|
||||
this.schemaSettingsManager.addItem('FormItemSettings', 'formulatitleField', {
|
||||
Component: EditFormulaTitleField,
|
||||
useVisible: useFormulaTitleVisible,
|
||||
});
|
||||
this.schemaSettingsManager.addItem('FormItemSettings', 'isTablePageSize', {
|
||||
Component: IsTablePageSize,
|
||||
useVisible: usePaginationVisible,
|
||||
@ -147,7 +133,6 @@ export class PluginCoreClient extends Plugin {
|
||||
CustomComponentStub,
|
||||
CustomField,
|
||||
EditTitle,
|
||||
EditTitleField,
|
||||
Expression,
|
||||
PageLayout,
|
||||
SettingBlock: SettingBlockInitializer,
|
||||
|
@ -10,7 +10,7 @@ import { fuzzysearch } from '../../utils';
|
||||
export const AutoComplete = connect((props) => {
|
||||
const { fieldNames, params: fieldFilter } = props;
|
||||
const fieldSchema = useFieldSchema();
|
||||
const targetKey = fieldNames.value;
|
||||
const targetKey = fieldNames?.value;
|
||||
const api = useAPIClient();
|
||||
const [defultOptions, setDefultOptions] = useState([]);
|
||||
const [options, setOptions] = useState([]);
|
||||
|
@ -1,3 +1,2 @@
|
||||
export * from './items/CustomFilterFormItemInitializer';
|
||||
export * from './actions/CreateSubmitActionInitializer';
|
||||
export * from './blocks/SettingBlockInitializer';
|
||||
|
@ -1,66 +0,0 @@
|
||||
import React, { FC } from 'react';
|
||||
import { SchemaSettingsItem, useFormActiveFields, useSchemaSettings } from '@tachybase/client';
|
||||
import { Field, ISchema, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||
|
||||
import { App, ModalFuncProps } from 'antd';
|
||||
|
||||
import { useTranslation } from '../locale';
|
||||
|
||||
export interface SchemaSettingsRemoveProps {
|
||||
confirm?: ModalFuncProps;
|
||||
removeParentsIfNoChildren?: boolean;
|
||||
breakRemoveOn?: ISchema | ((s: ISchema) => boolean);
|
||||
}
|
||||
export const SchemaSettingsRemove: FC<SchemaSettingsRemoveProps> = (props) => {
|
||||
const { confirm, removeParentsIfNoChildren, breakRemoveOn } = props;
|
||||
const { dn, template } = useSchemaSettings();
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const form = useForm();
|
||||
const { modal } = App.useApp();
|
||||
const { removeActiveFieldName } = useFormActiveFields() || {};
|
||||
return (
|
||||
<SchemaSettingsItem
|
||||
title="Delete"
|
||||
eventKey="remove"
|
||||
onClick={() => {
|
||||
modal.confirm({
|
||||
title: t('Delete block'),
|
||||
content: t('Are you sure you want to delete it?'),
|
||||
...confirm,
|
||||
async onOk() {
|
||||
const options = {
|
||||
removeParentsIfNoChildren,
|
||||
breakRemoveOn,
|
||||
};
|
||||
const name = fieldSchema.name as string;
|
||||
const fieldName = name.split('.')[1];
|
||||
const title = fieldSchema.title;
|
||||
if (field?.required) {
|
||||
field.required = false;
|
||||
fieldSchema['required'] = false;
|
||||
}
|
||||
await dn.remove(null, options);
|
||||
await confirm?.onOk?.();
|
||||
if (form.values['custom']) {
|
||||
delete form.values['custom'][fieldName];
|
||||
}
|
||||
for (const key in form.fields) {
|
||||
if (key.includes(name) && form.fields[key].title === title) {
|
||||
delete form.fields[key];
|
||||
}
|
||||
}
|
||||
removeActiveFieldName?.(fieldSchema.name as string);
|
||||
if (field?.setInitialValue && field?.reset) {
|
||||
field.setInitialValue(null);
|
||||
field.reset();
|
||||
}
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t('Delete')}
|
||||
</SchemaSettingsItem>
|
||||
);
|
||||
};
|
@ -1,23 +1,14 @@
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import {
|
||||
getShouldChange,
|
||||
SchemaComponent,
|
||||
SchemaSettingsModalItem,
|
||||
SchemaSettingsSelectItem,
|
||||
SchemaSettingsSwitchItem,
|
||||
useCollection_deprecated,
|
||||
useCollectionManager,
|
||||
useCollectionManager_deprecated,
|
||||
useCompile,
|
||||
useCurrentUserVariable,
|
||||
useDatetimeVariable,
|
||||
useDesignable,
|
||||
useFormBlockContext,
|
||||
useFormBlockType,
|
||||
useLocalVariables,
|
||||
useRecord,
|
||||
useSchemaTemplateManager,
|
||||
useVariables,
|
||||
VariableInput,
|
||||
VariableScopeProvider,
|
||||
} from '@tachybase/client';
|
||||
@ -26,227 +17,13 @@ import { Field, ISchema, useField, useFieldSchema } from '@tachybase/schema';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { FormFilterScope } from '../components/filter-form/FormFilterScope';
|
||||
import { useTranslation } from '../locale';
|
||||
import { useFieldComponents } from '../schema-initializer';
|
||||
|
||||
export const useFormulaTitleOptions = () => {
|
||||
const compile = useCompile();
|
||||
const { getCollectionJoinField, getCollectionFields } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const collectionManage = useCollectionManager_deprecated();
|
||||
const collectionManageField = collectionManage.collections.filter(
|
||||
(value) => value.name === fieldSchema['x-decorator-props'],
|
||||
)[0];
|
||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
let fields = [];
|
||||
if (collectionField) {
|
||||
fields = getCollectionFields(
|
||||
collectionField
|
||||
? collectionField.target
|
||||
? collectionField.target
|
||||
: collectionField.collectionName
|
||||
: fieldSchema['name'],
|
||||
);
|
||||
} else if (collectionManageField) {
|
||||
fields = collectionManageField['fields'];
|
||||
}
|
||||
const options = [];
|
||||
fields?.forEach((field) => {
|
||||
if (field.interface !== 'm2m') {
|
||||
if (field.uiSchema) {
|
||||
options.push({
|
||||
label: compile(field.uiSchema.title),
|
||||
value: field.name,
|
||||
children:
|
||||
getCollectionFields(field.target)
|
||||
?.filter((subField) => subField.uiSchema)
|
||||
.map((subField) => ({
|
||||
label: subField.uiSchema ? compile(subField.uiSchema.title) : '',
|
||||
value: subField.name,
|
||||
})) ?? [],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return options;
|
||||
};
|
||||
|
||||
export const useFormulaTitleVisible = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const options = useFormulaTitleOptions();
|
||||
// FIXME 这里现在只有当设置为 select,默认为 select 的时候看不到
|
||||
return (
|
||||
options.length > 0 &&
|
||||
(fieldSchema['x-component-props']?.mode === 'Select' || fieldSchema['x-component'] === 'CollectionField') &&
|
||||
fieldSchema['x-component-props']?.fieldNames?.value !== undefined
|
||||
);
|
||||
};
|
||||
|
||||
export const EditFormulaTitleField = () => {
|
||||
const { getCollectionJoinField, collections } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
|
||||
let collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
collectionField = collectionField
|
||||
? collectionField
|
||||
: collections.find((value) => value.name === fieldSchema['x-decorator-props'])?.fields;
|
||||
const options = useFormulaTitleOptions();
|
||||
const editTitle = async (formula) => {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
const fieldNames = {
|
||||
...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'],
|
||||
...field.componentProps.fieldNames,
|
||||
formula,
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps.fieldNames = fieldSchema['x-component-props'].fieldNames;
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
};
|
||||
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
key="edit-field-title"
|
||||
title={t('Custom option label')}
|
||||
schema={
|
||||
{
|
||||
type: 'object',
|
||||
title: t('Custom option label'),
|
||||
properties: {
|
||||
formula: {
|
||||
required: true,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Variable.TextArea',
|
||||
'x-component-props': {
|
||||
scope: options,
|
||||
},
|
||||
default: field?.componentProps?.fieldNames?.formula || '',
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
}
|
||||
onSubmit={({ formula }) => {
|
||||
if (formula) {
|
||||
editTitle(formula);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditDefaultValue = () => {
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const collectionName = fieldSchema['collectionName'];
|
||||
const title = fieldSchema.title;
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
key="set field default value"
|
||||
title={t('Set default value')}
|
||||
schema={{
|
||||
type: 'void',
|
||||
title: t('Set default value'),
|
||||
properties: {
|
||||
default: {
|
||||
title,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'FilterVariableInput',
|
||||
'x-component-props': {
|
||||
fieldSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
onSubmit={({ default: { value } }) => {
|
||||
field.setValue(value);
|
||||
fieldSchema['default'] = value;
|
||||
fieldSchema['x-component-props']['defaultValue'] = value;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
['x-component-props']: fieldSchema['x-component-props'],
|
||||
default: fieldSchema.default,
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const FilterVariableInput: React.FC<any> = (props) => {
|
||||
const { value, onChange, fieldSchema } = props;
|
||||
const { currentUserSettings } = useCurrentUserVariable({
|
||||
collectionField: { uiSchema: fieldSchema },
|
||||
uiSchema: fieldSchema,
|
||||
});
|
||||
const { datetimeSettings } = useDatetimeVariable({
|
||||
operator: fieldSchema['x-component-props']?.['filter-operator'],
|
||||
schema: fieldSchema,
|
||||
noDisabled: true,
|
||||
});
|
||||
const options = useMemo(
|
||||
() => [currentUserSettings, datetimeSettings].filter(Boolean),
|
||||
[datetimeSettings, currentUserSettings],
|
||||
);
|
||||
const schema = {
|
||||
...fieldSchema,
|
||||
'x-component': fieldSchema['x-component'] || 'Input',
|
||||
'x-decorator': '',
|
||||
title: '',
|
||||
name: 'value',
|
||||
};
|
||||
const componentProps = fieldSchema['x-component-props'] || {};
|
||||
const handleChange = useMemoizedFn(onChange);
|
||||
useEffect(() => {
|
||||
if (fieldSchema.default) {
|
||||
handleChange({ value: fieldSchema.default });
|
||||
}
|
||||
}, [fieldSchema.default, handleChange]);
|
||||
return (
|
||||
<VariableScopeProvider scope={options}>
|
||||
<VariableInput
|
||||
{...componentProps}
|
||||
renderSchemaComponent={() => <SchemaComponent schema={schema} />}
|
||||
fieldNames={{}}
|
||||
value={value?.value}
|
||||
scope={options}
|
||||
onChange={(v: any) => {
|
||||
onChange({ value: v });
|
||||
}}
|
||||
shouldChange={getShouldChange({} as any)}
|
||||
/>
|
||||
</VariableScopeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const usePaginationVisible = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return fieldSchema['x-component-props']?.mode === 'SubTable';
|
||||
};
|
||||
|
||||
export const useSetFilterScopeVisible = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return (
|
||||
fieldSchema['x-component-props']?.useProps === '{{ useFilterBlockActionProps }}' ||
|
||||
fieldSchema['x-use-component-props'] === 'useFilterBlockActionProps'
|
||||
);
|
||||
};
|
||||
|
||||
export const EditTitle = () => {
|
||||
const { getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
@ -294,64 +71,6 @@ export const EditTitle = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const EditTitleField = () => {
|
||||
const { getCollectionFields, getCollectionJoinField } = useCollectionManager_deprecated();
|
||||
const { getField } = useCollection_deprecated();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { t } = useTranslation();
|
||||
const { dn } = useDesignable();
|
||||
const compile = useCompile();
|
||||
const collectionManage = useCollectionManager_deprecated();
|
||||
const isCustomFilterItem = ((fieldSchema?.name as string) ?? '').startsWith('custom.');
|
||||
const collectionManageField = isCustomFilterItem
|
||||
? collectionManage.collections.filter((value) => value.name === fieldSchema['x-decorator-props'])[0]
|
||||
: {};
|
||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||
let targetFields = [];
|
||||
if (collectionField) {
|
||||
targetFields = collectionField?.target
|
||||
? getCollectionFields(collectionField?.target)
|
||||
: getCollectionFields(collectionField?.targetCollection) ?? [];
|
||||
} else if (collectionManageField) {
|
||||
targetFields = collectionManageField['fields'];
|
||||
}
|
||||
const options = targetFields
|
||||
.filter((field) => !field?.target && field.type !== 'boolean')
|
||||
.map((field) => ({
|
||||
value: field?.name,
|
||||
label: compile(field?.uiSchema?.title) || field?.name,
|
||||
}));
|
||||
|
||||
return options.length > 0 && (fieldSchema['x-component'] === 'CollectionField' || isCustomFilterItem) ? (
|
||||
<SchemaSettingsSelectItem
|
||||
key="title-field"
|
||||
title={t('Title field')}
|
||||
options={options}
|
||||
value={field?.componentProps?.fieldNames?.label}
|
||||
onChange={(label) => {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
const fieldNames = {
|
||||
...collectionField?.uiSchema?.['x-component-props']?.['fieldNames'],
|
||||
...field.componentProps.fieldNames,
|
||||
label,
|
||||
value: label,
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['fieldNames'] = fieldNames;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps.fieldNames = fieldSchema['x-component-props'].fieldNames;
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export const IsTablePageSize = () => {
|
||||
const { dn } = useDesignable();
|
||||
const fieldSchema = useFieldSchema();
|
||||
@ -382,141 +101,6 @@ export const IsTablePageSize = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const findGridSchema = (fieldSchema) => {
|
||||
return fieldSchema.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === 'FormV2') {
|
||||
const f = s.reduceProperties((buf, s) => {
|
||||
if (s['x-component'] === 'Grid' || s['x-component'] === 'BlockTemplate') {
|
||||
return s;
|
||||
}
|
||||
return buf;
|
||||
}, null);
|
||||
if (f) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}, null);
|
||||
};
|
||||
|
||||
export const useCollectionFilterOptions = (collectionName: string) => {
|
||||
const { getCollectionFields, getInterface } = useCollectionManager_deprecated();
|
||||
const fields = getCollectionFields(collectionName);
|
||||
const field2option = (field, depth) => {
|
||||
if (!field.interface) {
|
||||
return;
|
||||
}
|
||||
const fieldInterface = getInterface(field.interface);
|
||||
if (!fieldInterface?.filterable) {
|
||||
return;
|
||||
}
|
||||
const { nested, children, operators } = fieldInterface.filterable;
|
||||
const option = {
|
||||
name: field.name,
|
||||
title: field?.uiSchema?.title || field.name,
|
||||
schema: field?.uiSchema,
|
||||
operators:
|
||||
operators?.filter?.((operator) => {
|
||||
return !operator?.visible || operator.visible(field);
|
||||
}) || [],
|
||||
interface: field.interface,
|
||||
};
|
||||
if (field.target && depth > 2) {
|
||||
return;
|
||||
}
|
||||
if (depth > 2) {
|
||||
return option;
|
||||
}
|
||||
if (children?.length) {
|
||||
option['children'] = children;
|
||||
}
|
||||
if (nested) {
|
||||
const targetFields = getCollectionFields(field.target);
|
||||
const options = getOptions(targetFields, depth + 1).filter(Boolean);
|
||||
option['children'] = option['children'] || [];
|
||||
option['children'].push(...options);
|
||||
}
|
||||
return option;
|
||||
};
|
||||
const getOptions = (fields, depth) => {
|
||||
const options = [];
|
||||
fields.forEach((field) => {
|
||||
const option = field2option(field, depth);
|
||||
if (option) {
|
||||
options.push(option);
|
||||
}
|
||||
});
|
||||
return options;
|
||||
};
|
||||
const options = getOptions(fields, 1);
|
||||
return options;
|
||||
};
|
||||
|
||||
export const SetFilterScope = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField<Field>();
|
||||
const fields = field.form.fields;
|
||||
const { collectionName } = props;
|
||||
const gridSchema = findGridSchema(fieldSchema) || fieldSchema;
|
||||
const { form } = useFormBlockContext();
|
||||
const type = props?.type || ['Action', 'Action.Link'].includes(fieldSchema['x-component']) ? 'button' : 'field';
|
||||
const variables = useVariables();
|
||||
const localVariables = useLocalVariables();
|
||||
const record = useRecord();
|
||||
const { type: formBlockType } = useFormBlockType();
|
||||
const schema = useMemo<ISchema>(
|
||||
() => ({
|
||||
type: 'object',
|
||||
title: t('Custom filter'),
|
||||
properties: {
|
||||
fieldReaction: {
|
||||
'x-component': FormFilterScope,
|
||||
'x-component-props': {
|
||||
useProps: () => {
|
||||
const options = useCollectionFilterOptions(collectionName);
|
||||
return {
|
||||
options,
|
||||
defaultValues: gridSchema?.['x-filter-rules'] || fieldSchema?.['x-filter-rules'],
|
||||
type,
|
||||
collectionName,
|
||||
form,
|
||||
variables,
|
||||
localVariables,
|
||||
record,
|
||||
formBlockType,
|
||||
fields,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
const { getTemplateById } = useSchemaTemplateManager();
|
||||
const { dn } = useDesignable();
|
||||
const onSubmit = useCallback(
|
||||
(v) => {
|
||||
const rules = v.fieldReaction.condition;
|
||||
const templateId = gridSchema['x-component'] === 'BlockTemplate' && gridSchema['x-component-props'].templateId;
|
||||
const uid = (templateId && getTemplateById(templateId).uid) || gridSchema['x-uid'];
|
||||
const schema = {
|
||||
['x-uid']: uid,
|
||||
};
|
||||
|
||||
gridSchema['x-filter-rules'] = rules;
|
||||
schema['x-filter-rules'] = rules;
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
[dn, getTemplateById, gridSchema],
|
||||
);
|
||||
return <SchemaSettingsModalItem title={t('Custom filter')} width={770} schema={schema} onSubmit={onSubmit} />;
|
||||
};
|
||||
|
||||
// 添加跳转页面选项
|
||||
export const PageModeSetting = () => {
|
||||
const { dn } = useDesignable();
|
||||
@ -540,74 +124,3 @@ export const PageModeSetting = () => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const SchemaSettingComponent = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
const { options } = useFieldComponents();
|
||||
const { dn } = useDesignable();
|
||||
return (
|
||||
<SchemaSettingsSelectItem
|
||||
key="component-field"
|
||||
title="Field Component"
|
||||
options={options}
|
||||
value={fieldSchema['x-component']}
|
||||
onChange={(mode) => {
|
||||
field.component = mode;
|
||||
fieldSchema['x-component'] = mode;
|
||||
void dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
['x-component']: fieldSchema['x-component'],
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const SchemaSettingCollection = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const collections = useCollectionManager();
|
||||
const field = useField<Field>();
|
||||
const options = collections?.dataSource['options']?.collections.map((value) => {
|
||||
return {
|
||||
label: value.title,
|
||||
value: value.name,
|
||||
};
|
||||
});
|
||||
const cm = useCollectionManager();
|
||||
const { dn } = useDesignable();
|
||||
return (
|
||||
<SchemaSettingsSelectItem
|
||||
key="component-field"
|
||||
title="Edit Collection"
|
||||
options={options}
|
||||
value={fieldSchema['collectionName']}
|
||||
onChange={(name) => {
|
||||
field.setValue('');
|
||||
const titleField = cm.getCollection(name).titleField;
|
||||
fieldSchema['collectionName'] = name;
|
||||
fieldSchema.default = '';
|
||||
fieldSchema['x-component-props'] = {
|
||||
...fieldSchema['x-component-props'],
|
||||
fieldNames: {
|
||||
label: titleField,
|
||||
value: titleField,
|
||||
},
|
||||
defaultValue: '',
|
||||
};
|
||||
void dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
collectionName: fieldSchema['collectionName'],
|
||||
['x-component-props']: fieldSchema['x-component-props'],
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user