725 lines
24 KiB
TypeScript
725 lines
24 KiB
TypeScript
///
|
|
/// Copyright © 2016-2024 The Thingsboard Authors
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
|
|
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
|
|
import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models';
|
|
import { deepClone, isDefinedAndNotNull, isString } from '@core/utils';
|
|
import { JsonSchema, JsonSettingsSchema } from '@shared/models/widget.models';
|
|
import JsonFormUtils from '@shared/components/json-form/react/json-form-utils';
|
|
import { JsonFormData, KeyLabelItem } from '@shared/components/json-form/react/json-form.models';
|
|
import { constantColor, Font } from '@shared/models/widget-settings.models';
|
|
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
|
|
|
export enum FormPropertyType {
|
|
text = 'text',
|
|
number = 'number',
|
|
password = 'password',
|
|
textarea = 'textarea',
|
|
switch = 'switch',
|
|
select = 'select',
|
|
radios = 'radios',
|
|
datetime = 'datetime',
|
|
image = 'image',
|
|
javascript = 'javascript',
|
|
json = 'json',
|
|
html = 'html',
|
|
css = 'css',
|
|
markdown = 'markdown',
|
|
color = 'color',
|
|
color_settings = 'color_settings',
|
|
font = 'font',
|
|
units = 'units',
|
|
icon = 'icon',
|
|
fieldset = 'fieldset',
|
|
array = 'array',
|
|
htmlSection = 'htmlSection'
|
|
}
|
|
|
|
export const formPropertyTypes = Object.keys(FormPropertyType) as FormPropertyType[];
|
|
|
|
export const formPropertyTypeTranslations = new Map<FormPropertyType, string>(
|
|
[
|
|
[FormPropertyType.text, 'dynamic-form.property.type-text'],
|
|
[FormPropertyType.number, 'dynamic-form.property.type-number'],
|
|
[FormPropertyType.password, 'dynamic-form.property.type-password'],
|
|
[FormPropertyType.textarea, 'dynamic-form.property.type-textarea'],
|
|
[FormPropertyType.switch, 'dynamic-form.property.type-switch'],
|
|
[FormPropertyType.select, 'dynamic-form.property.type-select'],
|
|
[FormPropertyType.radios, 'dynamic-form.property.type-radios'],
|
|
[FormPropertyType.datetime, 'dynamic-form.property.type-datetime'],
|
|
[FormPropertyType.image, 'dynamic-form.property.type-image'],
|
|
[FormPropertyType.javascript, 'dynamic-form.property.type-javascript'],
|
|
[FormPropertyType.json, 'dynamic-form.property.type-json'],
|
|
[FormPropertyType.html, 'dynamic-form.property.type-html'],
|
|
[FormPropertyType.css, 'dynamic-form.property.type-css'],
|
|
[FormPropertyType.markdown, 'dynamic-form.property.type-markdown'],
|
|
[FormPropertyType.color, 'dynamic-form.property.type-color'],
|
|
[FormPropertyType.color_settings, 'dynamic-form.property.type-color-settings'],
|
|
[FormPropertyType.font, 'dynamic-form.property.type-font'],
|
|
[FormPropertyType.units, 'dynamic-form.property.type-units'],
|
|
[FormPropertyType.icon, 'dynamic-form.property.type-icon'],
|
|
[FormPropertyType.fieldset, 'dynamic-form.property.type-fieldset'],
|
|
[FormPropertyType.array, 'dynamic-form.property.type-array'],
|
|
[FormPropertyType.htmlSection, 'dynamic-form.property.type-html-section']
|
|
]
|
|
);
|
|
|
|
export const formPropertyRowClasses =
|
|
['column', 'column-xs', 'column-lt-md', 'align-start', 'no-border', 'no-gap', 'no-padding', 'same-padding'];
|
|
|
|
export const formPropertyFieldClasses =
|
|
['medium-width', 'flex', 'flex-xs', 'flex-lt-md'];
|
|
|
|
export type PropertyConditionFunction = (property: FormProperty, model: any) => boolean;
|
|
|
|
export interface FormPropertyBase {
|
|
id: string;
|
|
name: string;
|
|
group?: string;
|
|
type: FormPropertyType;
|
|
default: any;
|
|
required?: boolean;
|
|
subLabel?: string;
|
|
divider?: boolean;
|
|
fieldSuffix?: string;
|
|
disableOnProperty?: string;
|
|
condition?: string;
|
|
conditionFunction?: PropertyConditionFunction;
|
|
disabled?: boolean;
|
|
visible?: boolean;
|
|
rowClass?: string;
|
|
fieldClass?: string;
|
|
}
|
|
|
|
export interface FormTextareaProperty extends FormPropertyBase {
|
|
rows?: number;
|
|
}
|
|
|
|
export interface FormNumberProperty extends FormPropertyBase {
|
|
min?: number;
|
|
max?: number;
|
|
step?: number;
|
|
}
|
|
|
|
export interface FormFieldSetProperty extends FormPropertyBase {
|
|
properties?: FormProperty[];
|
|
}
|
|
|
|
export interface FormArrayProperty extends FormPropertyBase {
|
|
arrayItemName?: string;
|
|
arrayItemType?: FormPropertyType;
|
|
}
|
|
|
|
export interface FormSelectItem {
|
|
value: any;
|
|
label: string;
|
|
}
|
|
|
|
export interface FormSelectProperty extends FormPropertyBase {
|
|
multiple?: boolean;
|
|
allowEmptyOption?: boolean;
|
|
items?: FormSelectItem[];
|
|
}
|
|
|
|
export type FormPropertyDirection = 'row' | 'column';
|
|
|
|
export interface FormRadiosProperty extends FormPropertyBase {
|
|
direction?: FormPropertyDirection;
|
|
items?: FormSelectItem[];
|
|
}
|
|
|
|
export type FormPropertyDateTimeType = 'date' | 'time' | 'datetime';
|
|
|
|
export interface FormDateTimeProperty extends FormPropertyBase {
|
|
allowClear?: boolean;
|
|
dateTimeType?: FormPropertyDateTimeType;
|
|
}
|
|
|
|
export interface FormJavascriptProperty extends FormPropertyBase {
|
|
helpId?: string;
|
|
}
|
|
|
|
export interface FormMarkdownProperty extends FormPropertyBase {
|
|
helpId?: string;
|
|
}
|
|
|
|
export interface FormHtmlSection extends FormPropertyBase {
|
|
htmlClassList?: string[];
|
|
htmlContent?: string;
|
|
}
|
|
|
|
export type FormProperty = FormPropertyBase & FormTextareaProperty & FormNumberProperty & FormSelectProperty & FormRadiosProperty
|
|
& FormDateTimeProperty & FormJavascriptProperty & FormMarkdownProperty & FormFieldSetProperty & FormArrayProperty & FormHtmlSection;
|
|
|
|
export enum FormPropertyContainerType {
|
|
field = 'field',
|
|
row = 'row',
|
|
fieldset = 'fieldset',
|
|
array = 'array',
|
|
htmlSection = 'htmlSection'
|
|
}
|
|
|
|
export interface FormPropertyContainerBase {
|
|
type: FormPropertyContainerType;
|
|
label: string;
|
|
visible: boolean;
|
|
}
|
|
|
|
export interface FormPropertyRow extends FormPropertyContainerBase {
|
|
properties?: FormProperty[];
|
|
switch?: FormProperty;
|
|
rowClass?: string;
|
|
propertiesRowClass?: string;
|
|
}
|
|
|
|
export interface FormPropertyField extends FormPropertyContainerBase {
|
|
property?: FormProperty;
|
|
}
|
|
|
|
export interface FormPropertyFieldset extends FormPropertyContainerBase {
|
|
property?: FormProperty;
|
|
properties?: FormProperty[];
|
|
}
|
|
|
|
export interface FormPropertyArray extends FormPropertyContainerBase {
|
|
property?: FormProperty;
|
|
arrayItemProperty?: FormProperty;
|
|
}
|
|
|
|
export interface FormPropertyHtml extends FormPropertyContainerBase {
|
|
property?: FormProperty;
|
|
safeHtml?: SafeHtml;
|
|
htmlClass?: string;
|
|
}
|
|
|
|
export type FormPropertyContainer = FormPropertyField & FormPropertyRow & FormPropertyFieldset & FormPropertyHtml;
|
|
|
|
export interface FormPropertyGroup {
|
|
title?: string;
|
|
containers: FormPropertyContainer[];
|
|
visible: boolean;
|
|
}
|
|
|
|
export const toPropertyGroups = (properties: FormProperty[],
|
|
isArrayItem: boolean,
|
|
customTranslate: CustomTranslatePipe,
|
|
sanitizer: DomSanitizer): FormPropertyGroup[] => {
|
|
const groups: {title: string, properties: FormProperty[]}[] = [];
|
|
for (let property of properties) {
|
|
if (!property.group) {
|
|
let group = groups.length ? groups[groups.length - 1] : null;
|
|
if (group && !group.title) {
|
|
group.properties.push(property);
|
|
} else {
|
|
groups.push({
|
|
title: null,
|
|
properties: [property]
|
|
});
|
|
}
|
|
} else {
|
|
let propertyGroup = groups.find(g => g.title === property.group);
|
|
if (!propertyGroup) {
|
|
propertyGroup = {
|
|
title: property.group,
|
|
properties: []
|
|
};
|
|
groups.push(propertyGroup);
|
|
}
|
|
propertyGroup.properties.push(property);
|
|
}
|
|
}
|
|
return groups.map(g => ({
|
|
title: g.title,
|
|
containers: toPropertyContainers(g.properties, isArrayItem, customTranslate, sanitizer),
|
|
visible: true
|
|
}));
|
|
};
|
|
|
|
const toPropertyContainers = (properties: FormProperty[],
|
|
isArrayItem: boolean,
|
|
customTranslate: CustomTranslatePipe,
|
|
sanitizer: DomSanitizer): FormPropertyContainer[] => {
|
|
const result: FormPropertyContainer[] = [];
|
|
for (let property of properties) {
|
|
if (property.type === FormPropertyType.array) {
|
|
const propertyArray: FormPropertyArray = {
|
|
property,
|
|
label: property.name,
|
|
type: FormPropertyContainerType.array,
|
|
visible: true
|
|
};
|
|
const arrayItemProperty = deepClone(property);
|
|
arrayItemProperty.name = property.arrayItemName;
|
|
arrayItemProperty.type = property.arrayItemType;
|
|
arrayItemProperty.required = true;
|
|
delete arrayItemProperty.disableOnProperty;
|
|
delete arrayItemProperty.condition;
|
|
delete arrayItemProperty.conditionFunction;
|
|
delete arrayItemProperty.group;
|
|
propertyArray.arrayItemProperty = arrayItemProperty;
|
|
result.push(propertyArray);
|
|
} else if (property.type === FormPropertyType.fieldset) {
|
|
const propertyFieldset: FormPropertyFieldset = {
|
|
property,
|
|
label: property.name,
|
|
type: FormPropertyContainerType.fieldset,
|
|
properties: property.properties,
|
|
visible: true
|
|
};
|
|
result.push(propertyFieldset);
|
|
} else if (property.type === FormPropertyType.htmlSection) {
|
|
const propertyHtml: FormPropertyHtml = {
|
|
property,
|
|
label: property.name,
|
|
type: FormPropertyContainerType.htmlSection,
|
|
htmlClass: property.htmlClassList ? property.htmlClassList.join(' ') : '',
|
|
safeHtml: sanitizer.bypassSecurityTrustHtml(property.htmlContent),
|
|
visible: true
|
|
};
|
|
result.push(propertyHtml);
|
|
} else if (isSingleFieldPropertyType(property.type) || isArrayItem) {
|
|
const propertyField: FormPropertyField = {
|
|
property,
|
|
label: property.name,
|
|
type: FormPropertyContainerType.field,
|
|
visible: true
|
|
};
|
|
result.push(propertyField);
|
|
} else {
|
|
let propertyRow =
|
|
result.find(r => r.type === FormPropertyContainerType.row && r.label === property.name);
|
|
if (!propertyRow) {
|
|
propertyRow = {
|
|
label: property.name,
|
|
type: FormPropertyContainerType.row,
|
|
properties: [],
|
|
rowClass: property.rowClass,
|
|
propertiesRowClass: 'row flex-end align-center',
|
|
visible: true
|
|
};
|
|
result.push(propertyRow);
|
|
}
|
|
if (property.type === FormPropertyType.switch) {
|
|
propertyRow.switch = property;
|
|
} else {
|
|
propertyRow.properties.push(property);
|
|
}
|
|
}
|
|
}
|
|
for (let container of result.filter(c =>
|
|
c.type === FormPropertyContainerType.row && !c.switch && c.properties?.length === 1)) {
|
|
const property = container.properties[0];
|
|
if (isInputFieldPropertyType(property.type)) {
|
|
const labelText = customTranslate.transform(property.name);
|
|
if (property.type !== FormPropertyType.number && labelText.length > 40) {
|
|
container.type = FormPropertyContainerType.field;
|
|
container.property = property;
|
|
delete container.properties;
|
|
delete container.rowClass;
|
|
} else {
|
|
if (!container.rowClass) {
|
|
container.rowClass = 'column-xs';
|
|
container.propertiesRowClass = 'gt-xs:align-center xs:flex-col gt-xs:flex-row gt-xs:justify-end';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export const isPropertyTypeAllowedForRow = (type: FormPropertyType): boolean => {
|
|
return !isSingleFieldPropertyType(type) && ![FormPropertyType.fieldset, FormPropertyType.array, FormPropertyType.htmlSection].includes(type);
|
|
}
|
|
|
|
export const isSingleFieldPropertyType = (type: FormPropertyType): boolean => {
|
|
return [FormPropertyType.radios, FormPropertyType.textarea, FormPropertyType.image, FormPropertyType.javascript, FormPropertyType.json, FormPropertyType.html,
|
|
FormPropertyType.css, FormPropertyType.markdown].includes(type);
|
|
}
|
|
|
|
export const isInputFieldPropertyType = (type: FormPropertyType): boolean => {
|
|
return [FormPropertyType.text, FormPropertyType.password, FormPropertyType.number, FormPropertyType.select, FormPropertyType.datetime,
|
|
FormPropertyType.textarea].includes(type);
|
|
}
|
|
|
|
export const defaultFormProperties = (properties: FormProperty[]): {[id: string]: any} => {
|
|
const formProperties: {[id: string]: any} = {};
|
|
for (const property of properties) {
|
|
if (property.type !== FormPropertyType.htmlSection) {
|
|
formProperties[property.id] = defaultFormPropertyValue(property);
|
|
}
|
|
}
|
|
return formProperties;
|
|
};
|
|
|
|
export const defaultFormPropertyValue = (property: FormProperty): any => {
|
|
if (property.type === FormPropertyType.array) {
|
|
return [];
|
|
} else if (property.type === FormPropertyType.fieldset) {
|
|
const propertyValue: {[id: string]: any} = {};
|
|
for (const childProperty of property.properties) {
|
|
if (childProperty.type !== FormPropertyType.htmlSection) {
|
|
propertyValue[childProperty.id] = defaultFormPropertyValue(childProperty);
|
|
}
|
|
}
|
|
return propertyValue;
|
|
} else {
|
|
return property.default;
|
|
}
|
|
}
|
|
|
|
export const propertyValid = (property: FormProperty): boolean =>
|
|
!(!property.id || !property.name || !property.type || (property.type === FormPropertyType.array && !property.arrayItemType));
|
|
|
|
export const defaultPropertyValue = (type: FormPropertyType): any => {
|
|
switch (type) {
|
|
case FormPropertyType.text:
|
|
case FormPropertyType.textarea:
|
|
case FormPropertyType.password:
|
|
case FormPropertyType.javascript:
|
|
case FormPropertyType.json:
|
|
case FormPropertyType.html:
|
|
case FormPropertyType.css:
|
|
case FormPropertyType.markdown:
|
|
return '';
|
|
case FormPropertyType.number:
|
|
return 0;
|
|
case FormPropertyType.switch:
|
|
return false;
|
|
case FormPropertyType.color:
|
|
return '#000';
|
|
case FormPropertyType.color_settings:
|
|
return constantColor('#000');
|
|
case FormPropertyType.font:
|
|
return {
|
|
size: 12,
|
|
sizeUnit: 'px',
|
|
family: 'Roboto',
|
|
weight: 'normal',
|
|
style: 'normal',
|
|
lineHeight: '1'
|
|
} as Font;
|
|
case FormPropertyType.units:
|
|
return '';
|
|
case FormPropertyType.icon:
|
|
return 'star';
|
|
case FormPropertyType.fieldset:
|
|
case FormPropertyType.array:
|
|
case FormPropertyType.select:
|
|
case FormPropertyType.radios:
|
|
case FormPropertyType.datetime:
|
|
case FormPropertyType.htmlSection:
|
|
case FormPropertyType.image:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
export const formPropertyCompletions = (properties: FormProperty[], customTranslate: CustomTranslatePipe): TbEditorCompletions => {
|
|
const propertiesCompletions: TbEditorCompletions = {};
|
|
for (const property of properties) {
|
|
if (property.type !== FormPropertyType.htmlSection) {
|
|
propertiesCompletions[property.id] = formPropertyCompletion(property, customTranslate);
|
|
}
|
|
}
|
|
return propertiesCompletions;
|
|
}
|
|
|
|
export const formPropertyCompletion = (property: FormProperty, customTranslate: CustomTranslatePipe): TbEditorCompletion => {
|
|
let description = customTranslate.transform(property.name, property.name);
|
|
if (property.subLabel) {
|
|
description += ` <small>${customTranslate.transform(property.subLabel, property.subLabel)}</small>`;
|
|
}
|
|
const isArray = property.type === FormPropertyType.array;
|
|
const type = isArray ? property.arrayItemType : property.type;
|
|
if (type === FormPropertyType.select) {
|
|
if (property.multiple || isArray) {
|
|
description += '<br/><br/><code class="title"><b>Possible values of array element:</b></code>';
|
|
} else {
|
|
description += '<br/><br/><code class="title"><b>Possible values:</b></code>';
|
|
}
|
|
description += `<ul>${property.items.map(item => `<li>${item.value} <code style="font-size: 11px;">${typeof item.value}</code></li>`).join('\n')}</ul>`;
|
|
}
|
|
if (type === FormPropertyType.datetime) {
|
|
if (isArray) {
|
|
description += '<br/><br/><code class="title">Stores array of time values in milliseconds since midnight, January 1, 1970 UTC.</code>';
|
|
} else {
|
|
description += '<br/><br/><code class="title">Stores time value in milliseconds since midnight, January 1, 1970 UTC.</code>';
|
|
}
|
|
}
|
|
const completion: TbEditorCompletion = {
|
|
meta: 'property',
|
|
description,
|
|
type: formPropertyCompletionType(property)
|
|
};
|
|
if (type === FormPropertyType.fieldset && !isArray) {
|
|
completion.children = {};
|
|
for (const childProperty of property.properties) {
|
|
if (childProperty.type !== FormPropertyType.htmlSection) {
|
|
completion.children[childProperty.id] = formPropertyCompletion(childProperty, customTranslate);
|
|
}
|
|
}
|
|
}
|
|
return completion;
|
|
};
|
|
|
|
const formPropertyCompletionType = (property: FormProperty): string => {
|
|
const isArray = property.type === FormPropertyType.array;
|
|
const type = isArray ? property.arrayItemType : property.type;
|
|
let typeStr: string;
|
|
switch (type) {
|
|
case FormPropertyType.text:
|
|
case FormPropertyType.password:
|
|
case FormPropertyType.textarea:
|
|
typeStr = 'string';
|
|
break;
|
|
case FormPropertyType.number:
|
|
typeStr = 'number';
|
|
break;
|
|
case FormPropertyType.switch:
|
|
typeStr = 'boolean';
|
|
break;
|
|
case FormPropertyType.datetime:
|
|
typeStr = 'number';
|
|
break;
|
|
case FormPropertyType.image:
|
|
typeStr = 'image URL string';
|
|
break;
|
|
case FormPropertyType.select:
|
|
case FormPropertyType.radios:
|
|
const items = property.items || [];
|
|
const types: string[] = [];
|
|
items.forEach(item => {
|
|
const type = typeof item.value;
|
|
if (!types.includes(type)) {
|
|
types.push(type);
|
|
}
|
|
});
|
|
const typesString = types.length ? types.join(' | ') : 'string';
|
|
if (property.type === FormPropertyType.select && property.multiple) {
|
|
typeStr = `Array<${typesString}>`;
|
|
} else {
|
|
typeStr = typesString;
|
|
}
|
|
break;
|
|
case FormPropertyType.color:
|
|
typeStr = 'color string';
|
|
break;
|
|
case FormPropertyType.color_settings:
|
|
typeStr = 'ColorProcessor';
|
|
break;
|
|
case FormPropertyType.font:
|
|
typeStr = 'Font';
|
|
break;
|
|
case FormPropertyType.units:
|
|
typeStr = 'units string';
|
|
break;
|
|
case FormPropertyType.icon:
|
|
typeStr = 'icon string';
|
|
break;
|
|
case FormPropertyType.fieldset:
|
|
typeStr = 'object';
|
|
break;
|
|
case FormPropertyType.javascript:
|
|
typeStr = 'JavaScript function body string';
|
|
break;
|
|
case FormPropertyType.json:
|
|
typeStr = 'JSON string';
|
|
break;
|
|
case FormPropertyType.html:
|
|
typeStr = 'HTML string';
|
|
break;
|
|
case FormPropertyType.css:
|
|
typeStr = 'CSS string';
|
|
break;
|
|
case FormPropertyType.markdown:
|
|
typeStr = 'Markdown string';
|
|
break;
|
|
default:
|
|
typeStr = 'unknown';
|
|
break;
|
|
}
|
|
if (isArray) {
|
|
typeStr = `Array<${typeStr}>`;
|
|
}
|
|
return typeStr;
|
|
};
|
|
|
|
|
|
export const jsonFormSchemaToFormProperties = (rawSchema: string | any) : FormProperty[] => {
|
|
const properties: FormProperty[] = [];
|
|
let settingsSchema: JsonSettingsSchema;
|
|
if (!rawSchema || rawSchema === '') {
|
|
settingsSchema = {};
|
|
} else {
|
|
settingsSchema = isString(rawSchema) ? JSON.parse(rawSchema) : rawSchema;
|
|
}
|
|
if (settingsSchema.schema) {
|
|
const schema = settingsSchema.schema;
|
|
const form = settingsSchema.form || ['*'];
|
|
const groupInfoes = settingsSchema.groupInfoes || [];
|
|
if (form.length > 0) {
|
|
if (groupInfoes.length) {
|
|
for (const info of groupInfoes) {
|
|
const theForm: any[] = form[info.formIndex];
|
|
properties.push(...schemaFormToProperties(schema, theForm, info.GroupTitle));
|
|
}
|
|
} else {
|
|
properties.push(...schemaFormToProperties(schema, form));
|
|
}
|
|
}
|
|
}
|
|
return properties;
|
|
}
|
|
|
|
const schemaFormToProperties = (schema: JsonSchema, theForm: any[], groupTitle?: string): FormProperty[] => {
|
|
const merged = JsonFormUtils.merge(schema, theForm, {}, {
|
|
formDefaults: {
|
|
startEmpty: true
|
|
}
|
|
});
|
|
return merged.map((form: JsonFormData) => jsonFormDataToProperty(form, 0, groupTitle)).filter(p => p != null);
|
|
}
|
|
|
|
const jsonFormDataToProperty = (form: JsonFormData, level: number, groupTitle?: string): FormProperty => {
|
|
if (form.key && form.key.length > level) {
|
|
const id = form.key[level] + '';
|
|
let property: FormProperty = {
|
|
id,
|
|
name: form.title || id,
|
|
group: groupTitle,
|
|
type: null,
|
|
default: form.schema?.default || null,
|
|
required: isDefinedAndNotNull(form.required) ? form.required : false
|
|
};
|
|
if (form.condition?.length) {
|
|
property.condition = `return ${form.condition};`;
|
|
}
|
|
switch (form.type) {
|
|
case 'number':
|
|
property.type = FormPropertyType.number;
|
|
break;
|
|
case 'text':
|
|
property.type = FormPropertyType.text;
|
|
property.fieldClass = 'flex';
|
|
break;
|
|
case 'password':
|
|
property.type = FormPropertyType.password;
|
|
property.fieldClass = 'flex';
|
|
break;
|
|
case 'textarea':
|
|
property.type = FormPropertyType.textarea;
|
|
property.rows = form.rows || form.rowsMax || 2;
|
|
break;
|
|
case 'checkbox':
|
|
property.type = FormPropertyType.switch;
|
|
break;
|
|
case 'rc-select':
|
|
property.type = FormPropertyType.select;
|
|
if (form.items?.length) {
|
|
property.items = (form.items as KeyLabelItem[]).map(item => ({value: item.value, label: item.label}));
|
|
} else {
|
|
property.items = [];
|
|
}
|
|
property.multiple = form.multiple;
|
|
property.fieldClass = 'flex';
|
|
property.allowEmptyOption = isDefinedAndNotNull(form.allowClear) ? form.allowClear : false;
|
|
break;
|
|
case 'select':
|
|
property.type = FormPropertyType.select;
|
|
if (form.titleMap?.length) {
|
|
property.items = form.titleMap.map(item => ({value: item.value, label: item.name}));
|
|
} else {
|
|
property.items = [];
|
|
}
|
|
property.multiple = false;
|
|
property.fieldClass = 'flex';
|
|
property.allowEmptyOption = false;
|
|
break;
|
|
case 'radios':
|
|
property.type = FormPropertyType.radios;
|
|
if (form.titleMap?.length) {
|
|
property.items = form.titleMap.map(item => ({value: item.value, label: item.name}));
|
|
} else {
|
|
property.items = [];
|
|
}
|
|
property.direction = form.direction === 'row' ? 'row' : 'column';
|
|
break;
|
|
case 'date':
|
|
property.type = FormPropertyType.datetime;
|
|
property.dateTimeType = 'date';
|
|
property.fieldClass = 'flex';
|
|
property.allowClear = true;
|
|
break;
|
|
case 'image':
|
|
property.type = FormPropertyType.image;
|
|
break;
|
|
case 'color':
|
|
property.type = FormPropertyType.color;
|
|
break;
|
|
case 'icon':
|
|
property.type = FormPropertyType.icon;
|
|
break;
|
|
case 'fieldset':
|
|
property.type = FormPropertyType.fieldset;
|
|
property.properties = form.items ? (form.items as JsonFormData[]).map(item =>
|
|
jsonFormDataToProperty(item, level+1)).filter(p => p !== null) : [];
|
|
break;
|
|
case 'javascript':
|
|
property.type = FormPropertyType.javascript;
|
|
property.helpId = form.helpId;
|
|
break;
|
|
case 'json':
|
|
property.type = FormPropertyType.json;
|
|
break;
|
|
case 'html':
|
|
property.type = FormPropertyType.html;
|
|
break;
|
|
case 'css':
|
|
property.type = FormPropertyType.css;
|
|
break;
|
|
case 'markdown':
|
|
property.type = FormPropertyType.markdown;
|
|
break;
|
|
case 'help':
|
|
property.type = FormPropertyType.htmlSection;
|
|
property.htmlContent = form.description || '';
|
|
property.htmlClassList = form.htmlClass ? form.htmlClass.split(' ') : [];
|
|
break;
|
|
case 'array':
|
|
if (form.items?.length) {
|
|
const item: JsonFormData = form.items[0] as JsonFormData;
|
|
if (item.type !== 'array') {
|
|
const arrayProperty = jsonFormDataToProperty(item, 0);
|
|
arrayProperty.arrayItemType = arrayProperty.type;
|
|
arrayProperty.arrayItemName = arrayProperty.name;
|
|
arrayProperty.id = property.id;
|
|
arrayProperty.name = property.name;
|
|
arrayProperty.group = property.group;
|
|
arrayProperty.condition = property.condition;
|
|
arrayProperty.required = property.required;
|
|
property = arrayProperty;
|
|
property.type = FormPropertyType.array;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (!property.type) {
|
|
return null;
|
|
}
|
|
return property;
|
|
}
|
|
return null;
|
|
}
|