Add relations in workflow action fields (#12359)
This commit is contained in:
@ -14,6 +14,7 @@ import { FormRichTextV2FieldInput } from '@/object-record/record-field/form-type
|
|||||||
import { FormSelectFieldInput } from '@/object-record/record-field/form-types/components/FormSelectFieldInput';
|
import { FormSelectFieldInput } from '@/object-record/record-field/form-types/components/FormSelectFieldInput';
|
||||||
import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput';
|
import { FormTextFieldInput } from '@/object-record/record-field/form-types/components/FormTextFieldInput';
|
||||||
import { FormUuidFieldInput } from '@/object-record/record-field/form-types/components/FormUuidFieldInput';
|
import { FormUuidFieldInput } from '@/object-record/record-field/form-types/components/FormUuidFieldInput';
|
||||||
|
import { FormRelationToOneFieldInput } from '@/object-record/record-field/form-types/components/FormRelationToOneFieldInput';
|
||||||
import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent';
|
import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent';
|
||||||
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
|
||||||
import {
|
import {
|
||||||
@ -24,6 +25,8 @@ import {
|
|||||||
FieldMetadata,
|
FieldMetadata,
|
||||||
FieldMultiSelectValue,
|
FieldMultiSelectValue,
|
||||||
FieldPhonesValue,
|
FieldPhonesValue,
|
||||||
|
FieldRelationToOneValue,
|
||||||
|
FieldRelationValue,
|
||||||
FieldRichTextV2Value,
|
FieldRichTextV2Value,
|
||||||
FormFieldCurrencyValue,
|
FormFieldCurrencyValue,
|
||||||
} from '@/object-record/record-field/types/FieldMetadata';
|
} from '@/object-record/record-field/types/FieldMetadata';
|
||||||
@ -43,6 +46,7 @@ import { isFieldRichTextV2 } from '@/object-record/record-field/types/guards/isF
|
|||||||
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
|
import { isFieldSelect } from '@/object-record/record-field/types/guards/isFieldSelect';
|
||||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||||
import { isFieldUuid } from '@/object-record/record-field/types/guards/isFieldUuid';
|
import { isFieldUuid } from '@/object-record/record-field/types/guards/isFieldUuid';
|
||||||
|
import { isFieldRelationToOneObject } from '@/object-record/record-field/types/guards/isFieldRelationToOneObject';
|
||||||
import { JsonValue } from 'type-fest';
|
import { JsonValue } from 'type-fest';
|
||||||
|
|
||||||
type FormFieldInputProps = {
|
type FormFieldInputProps = {
|
||||||
@ -205,5 +209,14 @@ export const FormFieldInput = ({
|
|||||||
readonly={readonly}
|
readonly={readonly}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
|
) : isFieldRelationToOneObject(field) ? (
|
||||||
|
<FormRelationToOneFieldInput
|
||||||
|
label={field.label}
|
||||||
|
objectNameSingular={field.metadata.relationObjectMetadataNameSingular}
|
||||||
|
defaultValue={defaultValue as FieldRelationValue<FieldRelationToOneValue>}
|
||||||
|
onChange={onChange}
|
||||||
|
VariablePicker={VariablePicker}
|
||||||
|
readonly={readonly}
|
||||||
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent';
|
||||||
|
import { FormSingleRecordPicker } from '@/object-record/record-field/form-types/components/FormSingleRecordPicker';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { JsonValue } from 'type-fest';
|
||||||
|
import {
|
||||||
|
FieldRelationToOneValue,
|
||||||
|
FieldRelationValue,
|
||||||
|
} from '@/object-record/record-field/types/FieldMetadata';
|
||||||
|
|
||||||
|
export type FormRelationToOneFieldInputProps = {
|
||||||
|
label?: string;
|
||||||
|
objectNameSingular?: string;
|
||||||
|
defaultValue?: FieldRelationValue<FieldRelationToOneValue>;
|
||||||
|
onChange: (value: JsonValue) => void;
|
||||||
|
readonly?: boolean;
|
||||||
|
VariablePicker?: VariablePickerComponent;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FormRelationToOneFieldInput = ({
|
||||||
|
label,
|
||||||
|
objectNameSingular,
|
||||||
|
onChange,
|
||||||
|
defaultValue,
|
||||||
|
readonly,
|
||||||
|
VariablePicker,
|
||||||
|
}: FormRelationToOneFieldInputProps) => {
|
||||||
|
return (
|
||||||
|
isDefined(objectNameSingular) && (
|
||||||
|
<FormSingleRecordPicker
|
||||||
|
label={label}
|
||||||
|
defaultValue={defaultValue?.id}
|
||||||
|
onChange={(recordId) => {
|
||||||
|
onChange({
|
||||||
|
id: recordId,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
objectNameSingular={objectNameSingular}
|
||||||
|
disabled={readonly}
|
||||||
|
VariablePicker={VariablePicker}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -58,7 +58,7 @@ type FormSingleRecordPickerValue =
|
|||||||
|
|
||||||
export type FormSingleRecordPickerProps = {
|
export type FormSingleRecordPickerProps = {
|
||||||
label?: string;
|
label?: string;
|
||||||
defaultValue: RecordId | Variable;
|
defaultValue?: RecordId | Variable;
|
||||||
onChange: (value: RecordId | Variable) => void;
|
onChange: (value: RecordId | Variable) => void;
|
||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@ -95,7 +95,7 @@ export const FormSingleRecordPicker = ({
|
|||||||
: '',
|
: '',
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
withSoftDeleted: true,
|
withSoftDeleted: true,
|
||||||
skip: !isValidUuid(defaultValue),
|
skip: !isDefined(defaultValue) || !isValidUuid(defaultValue),
|
||||||
});
|
});
|
||||||
|
|
||||||
const dropdownId = `form-record-picker-${objectNameSingular}`;
|
const dropdownId = `form-record-picker-${objectNameSingular}`;
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|||||||
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
|
import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsFieldDefinition';
|
||||||
import { FormMultiSelectFieldInput } from '@/object-record/record-field/form-types/components/FormMultiSelectFieldInput';
|
import { FormMultiSelectFieldInput } from '@/object-record/record-field/form-types/components/FormMultiSelectFieldInput';
|
||||||
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { SUPPORTED_FIELD_METADATA_TYPES } from '@/workflow/constants/SupportedFieldMetadataTypes';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { useIcons } from 'twenty-ui/display';
|
import { useIcons } from 'twenty-ui/display';
|
||||||
|
import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField';
|
||||||
|
|
||||||
export const WorkflowFieldsMultiSelect = ({
|
export const WorkflowFieldsMultiSelect = ({
|
||||||
label,
|
label,
|
||||||
@ -24,11 +24,11 @@ export const WorkflowFieldsMultiSelect = ({
|
|||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
|
|
||||||
const inlineFieldMetadataItems = objectMetadataItem?.fields
|
const inlineFieldMetadataItems = objectMetadataItem?.fields
|
||||||
.filter(
|
.filter((fieldMetadataItem) =>
|
||||||
(fieldMetadataItem) =>
|
shouldDisplayFormField({
|
||||||
!fieldMetadataItem.isSystem &&
|
fieldMetadataItem,
|
||||||
fieldMetadataItem.isActive &&
|
actionType: 'UPDATE_RECORD',
|
||||||
SUPPORTED_FIELD_METADATA_TYPES.includes(fieldMetadataItem.type),
|
}),
|
||||||
)
|
)
|
||||||
.sort((fieldMetadataItemA, fieldMetadataItemB) =>
|
.sort((fieldMetadataItemA, fieldMetadataItemB) =>
|
||||||
fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name),
|
fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name),
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
import { FieldMetadataType } from 'twenty-shared/types';
|
|
||||||
|
|
||||||
export const SUPPORTED_FIELD_METADATA_TYPES = [
|
|
||||||
FieldMetadataType.TEXT,
|
|
||||||
FieldMetadataType.NUMBER,
|
|
||||||
FieldMetadataType.DATE,
|
|
||||||
FieldMetadataType.BOOLEAN,
|
|
||||||
FieldMetadataType.SELECT,
|
|
||||||
FieldMetadataType.MULTI_SELECT,
|
|
||||||
FieldMetadataType.EMAILS,
|
|
||||||
FieldMetadataType.LINKS,
|
|
||||||
FieldMetadataType.FULL_NAME,
|
|
||||||
FieldMetadataType.ADDRESS,
|
|
||||||
FieldMetadataType.PHONES,
|
|
||||||
FieldMetadataType.CURRENCY,
|
|
||||||
FieldMetadataType.DATE_TIME,
|
|
||||||
FieldMetadataType.RAW_JSON,
|
|
||||||
FieldMetadataType.UUID,
|
|
||||||
];
|
|
||||||
@ -17,7 +17,7 @@ import { HorizontalSeparator, useIcons } from 'twenty-ui/display';
|
|||||||
import { SelectOption } from 'twenty-ui/input';
|
import { SelectOption } from 'twenty-ui/input';
|
||||||
import { JsonValue } from 'type-fest';
|
import { JsonValue } from 'type-fest';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
import { FieldMetadataType } from '~/generated/graphql';
|
import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField';
|
||||||
|
|
||||||
type WorkflowEditActionCreateRecordProps = {
|
type WorkflowEditActionCreateRecordProps = {
|
||||||
action: WorkflowCreateRecordAction;
|
action: WorkflowCreateRecordAction;
|
||||||
@ -92,11 +92,8 @@ export const WorkflowEditActionCreateRecord = ({
|
|||||||
const viewFields = indexView?.viewFields ?? [];
|
const viewFields = indexView?.viewFields ?? [];
|
||||||
|
|
||||||
const inlineFieldMetadataItems = objectMetadataItem?.fields
|
const inlineFieldMetadataItems = objectMetadataItem?.fields
|
||||||
.filter(
|
.filter((fieldMetadataItem) =>
|
||||||
(fieldMetadataItem) =>
|
shouldDisplayFormField({ fieldMetadataItem, actionType: action.type }),
|
||||||
fieldMetadataItem.type !== FieldMetadataType.RELATION &&
|
|
||||||
!fieldMetadataItem.isSystem &&
|
|
||||||
fieldMetadataItem.isActive,
|
|
||||||
)
|
)
|
||||||
.map((fieldMetadataItem) => {
|
.map((fieldMetadataItem) => {
|
||||||
const viewField = viewFields.find(
|
const viewField = viewFields.find(
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { formatFieldMetadataItemAsFieldDefinition } from '@/object-metadata/util
|
|||||||
import { FormFieldInput } from '@/object-record/record-field/components/FormFieldInput';
|
import { FormFieldInput } from '@/object-record/record-field/components/FormFieldInput';
|
||||||
import { FormSingleRecordPicker } from '@/object-record/record-field/form-types/components/FormSingleRecordPicker';
|
import { FormSingleRecordPicker } from '@/object-record/record-field/form-types/components/FormSingleRecordPicker';
|
||||||
import { WorkflowFieldsMultiSelect } from '@/workflow/components/WorkflowEditUpdateEventFieldsMultiSelect';
|
import { WorkflowFieldsMultiSelect } from '@/workflow/components/WorkflowEditUpdateEventFieldsMultiSelect';
|
||||||
import { SUPPORTED_FIELD_METADATA_TYPES } from '@/workflow/constants/SupportedFieldMetadataTypes';
|
|
||||||
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
|
||||||
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader';
|
||||||
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
import { useActionHeaderTypeOrThrow } from '@/workflow/workflow-steps/workflow-actions/hooks/useActionHeaderTypeOrThrow';
|
||||||
@ -19,6 +18,7 @@ import { HorizontalSeparator, useIcons } from 'twenty-ui/display';
|
|||||||
import { SelectOption } from 'twenty-ui/input';
|
import { SelectOption } from 'twenty-ui/input';
|
||||||
import { JsonValue } from 'type-fest';
|
import { JsonValue } from 'type-fest';
|
||||||
import { useDebouncedCallback } from 'use-debounce';
|
import { useDebouncedCallback } from 'use-debounce';
|
||||||
|
import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField';
|
||||||
|
|
||||||
type WorkflowEditActionUpdateRecordProps = {
|
type WorkflowEditActionUpdateRecordProps = {
|
||||||
action: WorkflowUpdateRecordAction;
|
action: WorkflowUpdateRecordAction;
|
||||||
@ -84,11 +84,8 @@ export const WorkflowEditActionUpdateRecord = ({
|
|||||||
const objectNameSingular = selectedObjectMetadataItem?.nameSingular;
|
const objectNameSingular = selectedObjectMetadataItem?.nameSingular;
|
||||||
|
|
||||||
const inlineFieldMetadataItems = selectedObjectMetadataItem?.fields
|
const inlineFieldMetadataItems = selectedObjectMetadataItem?.fields
|
||||||
.filter(
|
.filter((fieldMetadataItem) =>
|
||||||
(fieldMetadataItem) =>
|
shouldDisplayFormField({ fieldMetadataItem, actionType: action.type }),
|
||||||
!fieldMetadataItem.isSystem &&
|
|
||||||
fieldMetadataItem.isActive &&
|
|
||||||
SUPPORTED_FIELD_METADATA_TYPES.includes(fieldMetadataItem.type),
|
|
||||||
)
|
)
|
||||||
.sort((fieldMetadataItemA, fieldMetadataItemB) =>
|
.sort((fieldMetadataItemA, fieldMetadataItemB) =>
|
||||||
fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name),
|
fieldMetadataItemA.name.localeCompare(fieldMetadataItemB.name),
|
||||||
|
|||||||
@ -0,0 +1,100 @@
|
|||||||
|
import { shouldDisplayFormField } from '@/workflow/workflow-steps/workflow-actions/utils/shouldDisplayFormField';
|
||||||
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
|
import { FieldMetadataType } from 'twenty-shared/types';
|
||||||
|
|
||||||
|
const baseField = {
|
||||||
|
name: 'testField',
|
||||||
|
label: 'Test Field',
|
||||||
|
type: FieldMetadataType.TEXT,
|
||||||
|
isSystem: false,
|
||||||
|
isActive: true,
|
||||||
|
settings: null,
|
||||||
|
} as FieldMetadataItem;
|
||||||
|
|
||||||
|
describe('shouldDisplayFormField', () => {
|
||||||
|
it('returns true for valid CREATE_RECORD field (non-relation)', () => {
|
||||||
|
const result = shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: baseField,
|
||||||
|
actionType: 'CREATE_RECORD',
|
||||||
|
});
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for CREATE_RECORD with RELATION not MANY_TO_ONE', () => {
|
||||||
|
const field = {
|
||||||
|
...baseField,
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
settings: { relationType: 'ONE_TO_MANY' },
|
||||||
|
} as FieldMetadataItem;
|
||||||
|
const result = shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: field,
|
||||||
|
actionType: 'CREATE_RECORD',
|
||||||
|
});
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for CREATE_RECORD with RELATION MANY_TO_ONE', () => {
|
||||||
|
const field = {
|
||||||
|
...baseField,
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
settings: { relationType: 'MANY_TO_ONE' },
|
||||||
|
} as FieldMetadataItem;
|
||||||
|
const result = shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: field,
|
||||||
|
actionType: 'CREATE_RECORD',
|
||||||
|
});
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true for UPDATE_RECORD with displayable type', () => {
|
||||||
|
const result = shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: baseField,
|
||||||
|
actionType: 'UPDATE_RECORD',
|
||||||
|
});
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for UPDATE_RECORD with RELATION not MANY_TO_ONE', () => {
|
||||||
|
const field = {
|
||||||
|
...baseField,
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
settings: { relationType: 'ONE_TO_MANY' },
|
||||||
|
} as FieldMetadataItem;
|
||||||
|
const result = shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: field,
|
||||||
|
actionType: 'UPDATE_RECORD',
|
||||||
|
});
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for UPDATE_RECORD with RELATION MANY_TO_ONE', () => {
|
||||||
|
const field = {
|
||||||
|
...baseField,
|
||||||
|
type: FieldMetadataType.RELATION,
|
||||||
|
settings: { relationType: 'MANY_TO_ONE' },
|
||||||
|
} as FieldMetadataItem;
|
||||||
|
const result = shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: field,
|
||||||
|
actionType: 'UPDATE_RECORD',
|
||||||
|
});
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for system field', () => {
|
||||||
|
const field = { ...baseField, isSystem: true };
|
||||||
|
const result = shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: field,
|
||||||
|
actionType: 'UPDATE_RECORD',
|
||||||
|
});
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws error on unsupported action', () => {
|
||||||
|
expect(() =>
|
||||||
|
shouldDisplayFormField({
|
||||||
|
fieldMetadataItem: baseField,
|
||||||
|
actionType: 'DELETE_RECORD',
|
||||||
|
}),
|
||||||
|
).toThrow('Action "DELETE_RECORD" is not supported');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
|
import { WorkflowActionType } from '@/workflow/types/Workflow';
|
||||||
|
import { FieldMetadataType } from '~/generated/graphql';
|
||||||
|
|
||||||
|
const DISPLAYABLE_FIELD_TYPES_FOR_UPDATE = [
|
||||||
|
FieldMetadataType.TEXT,
|
||||||
|
FieldMetadataType.NUMBER,
|
||||||
|
FieldMetadataType.DATE,
|
||||||
|
FieldMetadataType.BOOLEAN,
|
||||||
|
FieldMetadataType.SELECT,
|
||||||
|
FieldMetadataType.MULTI_SELECT,
|
||||||
|
FieldMetadataType.EMAILS,
|
||||||
|
FieldMetadataType.LINKS,
|
||||||
|
FieldMetadataType.FULL_NAME,
|
||||||
|
FieldMetadataType.ADDRESS,
|
||||||
|
FieldMetadataType.PHONES,
|
||||||
|
FieldMetadataType.CURRENCY,
|
||||||
|
FieldMetadataType.DATE_TIME,
|
||||||
|
FieldMetadataType.RAW_JSON,
|
||||||
|
FieldMetadataType.UUID,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const shouldDisplayFormField = ({
|
||||||
|
fieldMetadataItem,
|
||||||
|
actionType,
|
||||||
|
}: {
|
||||||
|
fieldMetadataItem: FieldMetadataItem;
|
||||||
|
actionType: WorkflowActionType;
|
||||||
|
}) => {
|
||||||
|
let isTypeAllowedForAction = false;
|
||||||
|
|
||||||
|
switch (actionType) {
|
||||||
|
case 'CREATE_RECORD':
|
||||||
|
isTypeAllowedForAction =
|
||||||
|
fieldMetadataItem.type !== FieldMetadataType.RELATION ||
|
||||||
|
fieldMetadataItem.settings?.['relationType'] === 'MANY_TO_ONE';
|
||||||
|
break;
|
||||||
|
case 'UPDATE_RECORD':
|
||||||
|
isTypeAllowedForAction =
|
||||||
|
DISPLAYABLE_FIELD_TYPES_FOR_UPDATE.includes(fieldMetadataItem.type) ||
|
||||||
|
fieldMetadataItem.settings?.['relationType'] === 'MANY_TO_ONE';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Action "${actionType}" is not supported`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
isTypeAllowedForAction &&
|
||||||
|
!fieldMetadataItem.isSystem &&
|
||||||
|
fieldMetadataItem.isActive
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user