refactor
This commit is contained in:
360
fields.js
360
fields.js
@@ -1,160 +1,224 @@
|
||||
import {
|
||||
FIELD_TYPES,
|
||||
LAYOUT_TYPES,
|
||||
OPTION_SORTABLE_TYPES,
|
||||
EXCLUDED_GROUP_TYPES
|
||||
} from './constants.js';
|
||||
|
||||
/**
|
||||
* Sorts field options by index for fields that support options
|
||||
* @param {Object} field - Field object
|
||||
* @returns {Array} Sorted option labels
|
||||
*/
|
||||
const sortFieldOptions = (field) => {
|
||||
if (!field.options) return [];
|
||||
return Object.values(field.options)
|
||||
.sort((a, b) => Number(a.index) - Number(b.index))
|
||||
.map(option => option.label);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a field should have its options sorted
|
||||
* @param {string} fieldType - Type of the field
|
||||
* @returns {boolean} True if options should be sorted
|
||||
*/
|
||||
const shouldSortOptions = (fieldType) => OPTION_SORTABLE_TYPES.includes(fieldType);
|
||||
|
||||
/**
|
||||
* Adds system status fields to the fields array if they are enabled
|
||||
* @param {Array} properties - All property objects
|
||||
* @param {Array} fields - Array to add fields to
|
||||
*/
|
||||
const addSystemStatusFields = (properties, fields) => {
|
||||
const propertyList = Object.values(properties);
|
||||
|
||||
[FIELD_TYPES.STATUS, FIELD_TYPES.STATUS_ASSIGNEE, FIELD_TYPES.CATEGORY].forEach(type => {
|
||||
const field = propertyList.find(f => f.type === type);
|
||||
if (field && field.enabled) {
|
||||
fields.push(field);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Processes fields in a regular row layout
|
||||
* @param {Array} rowFields - Fields in the row
|
||||
* @param {Object} properties - Property mapping
|
||||
* @param {Array} fields - Array to add processed fields to
|
||||
* @param {Array} spacers - Array to add spacer elements to
|
||||
*/
|
||||
const processRowFields = (rowFields, properties, fields, spacers) => {
|
||||
for (const field of rowFields) {
|
||||
if ([LAYOUT_TYPES.LABEL, LAYOUT_TYPES.HR].includes(field.type)) continue;
|
||||
|
||||
if (field.type === LAYOUT_TYPES.SPACER) {
|
||||
spacers.push(field);
|
||||
continue;
|
||||
}
|
||||
|
||||
const fieldProperty = properties[field.code];
|
||||
if ([FIELD_TYPES.SUBTABLE, FIELD_TYPES.GROUP].includes(fieldProperty.type)) continue;
|
||||
|
||||
const fieldToAdd = shouldSortOptions(fieldProperty.type)
|
||||
? { ...fieldProperty, sortedOptions: sortFieldOptions(fieldProperty) }
|
||||
: fieldProperty;
|
||||
|
||||
fields.push(fieldToAdd);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Processes subtable fields
|
||||
* @param {Object} layout - Subtable layout object
|
||||
* @param {Object} properties - Property mapping
|
||||
* @param {Array} fields - Array to add processed fields to
|
||||
*/
|
||||
const processSubtableFields = (layout, properties, fields) => {
|
||||
const tableCode = layout.code;
|
||||
const tableField = properties[tableCode];
|
||||
|
||||
if (tableField.type !== FIELD_TYPES.SUBTABLE) return;
|
||||
|
||||
const tableFields = {};
|
||||
|
||||
layout.fields.forEach(({ code: fieldCode }) => {
|
||||
const subField = tableField.fields[fieldCode];
|
||||
const processedField = shouldSortOptions(subField.type)
|
||||
? { ...subField, table: tableCode, sortedOptions: sortFieldOptions(subField) }
|
||||
: { ...subField, table: tableCode };
|
||||
|
||||
tableFields[fieldCode] = processedField;
|
||||
fields.push(processedField);
|
||||
});
|
||||
|
||||
fields.push({ ...tableField, fields: tableFields });
|
||||
};
|
||||
|
||||
/**
|
||||
* Processes group fields
|
||||
* @param {Object} layout - Group layout object
|
||||
* @param {Object} properties - Property mapping
|
||||
* @param {Array} fields - Array to add processed fields to
|
||||
* @param {Array} spacers - Array to add spacer elements to
|
||||
*/
|
||||
const processGroupFields = (layout, properties, fields, spacers) => {
|
||||
const groupCode = layout.code;
|
||||
const groupField = properties[groupCode];
|
||||
|
||||
if (groupField.type !== FIELD_TYPES.GROUP) return;
|
||||
|
||||
const groupFields = {};
|
||||
|
||||
layout.layout.forEach(row => {
|
||||
row.fields.forEach(field => {
|
||||
if ([LAYOUT_TYPES.LABEL, LAYOUT_TYPES.HR].includes(field.type)) return;
|
||||
|
||||
if (field.type === LAYOUT_TYPES.SPACER) {
|
||||
spacers.push({ ...field, group: groupCode });
|
||||
return;
|
||||
}
|
||||
|
||||
const groupSubField = properties[field.code];
|
||||
|
||||
if (EXCLUDED_GROUP_TYPES.includes(groupSubField.type)) return;
|
||||
|
||||
const processedField = shouldSortOptions(groupSubField.type)
|
||||
? { ...groupSubField, group: groupCode, sortedOptions: sortFieldOptions(groupSubField) }
|
||||
: { ...groupSubField, group: groupCode };
|
||||
|
||||
groupFields[field.code] = processedField;
|
||||
fields.push(processedField);
|
||||
});
|
||||
});
|
||||
|
||||
fields.push({ ...groupField, fields: groupFields });
|
||||
};
|
||||
|
||||
/**
|
||||
* Marks lookup copy fields in the fields array
|
||||
* @param {Array} fields - Array of fields to process
|
||||
*/
|
||||
const markLookupCopies = (fields) => {
|
||||
const lookupCopyTypes = [
|
||||
FIELD_TYPES.SINGLE_LINE_TEXT, FIELD_TYPES.NUMBER, FIELD_TYPES.MULTI_LINE_TEXT,
|
||||
FIELD_TYPES.RICH_TEXT, FIELD_TYPES.LINK, FIELD_TYPES.CHECK_BOX,
|
||||
FIELD_TYPES.RADIO_BUTTON, FIELD_TYPES.DROP_DOWN, FIELD_TYPES.MULTI_SELECT,
|
||||
FIELD_TYPES.DATE, FIELD_TYPES.TIME, FIELD_TYPES.DATETIME,
|
||||
FIELD_TYPES.USER_SELECT, FIELD_TYPES.ORGANIZATION_SELECT,
|
||||
FIELD_TYPES.GROUP_SELECT, FIELD_TYPES.CALC, FIELD_TYPES.RECORD_NUMBER
|
||||
];
|
||||
|
||||
fields.forEach(field => {
|
||||
if (field.lookup && Array.isArray(field.lookup.fieldMappings)) {
|
||||
field.lookup.fieldMappings.forEach(mapping => {
|
||||
const targetField = fields.find(f =>
|
||||
lookupCopyTypes.includes(f.type) && f.code === mapping.field
|
||||
);
|
||||
if (targetField) {
|
||||
targetField.isLookupCopy = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds system fields that aren't already in the fields array
|
||||
* @param {Array} properties - Property objects
|
||||
* @param {Array} fields - Array to add fields to
|
||||
*/
|
||||
const addSystemFields = (properties, fields) => {
|
||||
const propertyList = Object.values(properties);
|
||||
const systemFieldTypes = [
|
||||
FIELD_TYPES.RECORD_NUMBER,
|
||||
FIELD_TYPES.CREATOR,
|
||||
FIELD_TYPES.CREATED_TIME,
|
||||
FIELD_TYPES.MODIFIER,
|
||||
FIELD_TYPES.UPDATED_TIME
|
||||
];
|
||||
|
||||
systemFieldTypes.forEach(type => {
|
||||
const field = propertyList.find(f => f.type === type);
|
||||
if (field && !fields.some(f => f.type === type)) {
|
||||
fields.push(field);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const kintonePrettyFields = {
|
||||
/**
|
||||
* Generates processed field and spacer arrays from form properties and layout
|
||||
* @param {Object} properties - Field properties object
|
||||
* @param {Array} layouts - Layout definitions
|
||||
* @returns {Object} Object containing fields and spacers arrays
|
||||
*/
|
||||
generateFields: (properties, layouts) => {
|
||||
const fields = [];
|
||||
const spacers = [];
|
||||
|
||||
const isStatus = field => field.type === "STATUS";
|
||||
const isStatusAssignee = field => field.type === "STATUS_ASSIGNEE";
|
||||
const isCategory = field => field.type === "CATEGORY";
|
||||
// Add system status fields first
|
||||
addSystemStatusFields(properties, fields);
|
||||
|
||||
const propertyList = Object.values(properties)
|
||||
|
||||
const statusField = propertyList.find(isStatus);
|
||||
if (statusField && statusField.enabled) {
|
||||
fields.push(statusField);
|
||||
}
|
||||
|
||||
const statusAssigneeField = propertyList.find(isStatusAssignee);
|
||||
if (statusAssigneeField && statusAssigneeField.enabled) {
|
||||
fields.push(statusAssigneeField);
|
||||
}
|
||||
|
||||
const categoryField = propertyList.find(isCategory);
|
||||
if (categoryField && categoryField.enabled) {
|
||||
fields.push(categoryField);
|
||||
}
|
||||
|
||||
for (const r of layouts) {
|
||||
if (r.type === "ROW") {
|
||||
for (const f of r.fields) {
|
||||
if (f.type === "LABEL" || f.type === "HR") continue;
|
||||
if (f.type === "SPACER") {
|
||||
spacers.push(f);
|
||||
continue;
|
||||
}
|
||||
const ee = properties[f.code];
|
||||
if (ee.type !== "SUBTABLE" && ee.type !== "GROUP") {
|
||||
if (ee.type === "CHECK_BOX" || ee.type === "DROP_DOWN" || ee.type === "MULTI_SELECT" || ee.type === "RADIO_BUTTON") {
|
||||
const sortedOptions = Object.values(ee.options).sort((a, b) => Number(a.index) - Number(b.index)).map(o => o.label);
|
||||
fields.push({
|
||||
...ee,
|
||||
sortedOptions
|
||||
});
|
||||
continue;
|
||||
}
|
||||
fields.push(ee);
|
||||
}
|
||||
}
|
||||
} else if (r.type === "SUBTABLE") {
|
||||
const tableCode = r.code;
|
||||
const tableField = properties[tableCode];
|
||||
if (tableField.type !== "SUBTABLE") continue;
|
||||
const tableFields = {};
|
||||
for (const { code: fieldCode } of r.fields) {
|
||||
const subf = tableField.fields[fieldCode];
|
||||
if (subf.type === "CHECK_BOX" || subf.type === "DROP_DOWN" || subf.type === "MULTI_SELECT" || subf.type === "RADIO_BUTTON") {
|
||||
const sortedOptions = Object.values(subf.options).sort((a, b) => Number(a.index) - Number(b.index)).map(o => o.label);
|
||||
tableFields[fieldCode] = {
|
||||
...subf,
|
||||
table: tableCode,
|
||||
sortedOptions
|
||||
};
|
||||
fields.push({
|
||||
...subf,
|
||||
table: tableCode,
|
||||
sortedOptions
|
||||
});
|
||||
continue;
|
||||
}
|
||||
tableFields[fieldCode] = {
|
||||
...subf,
|
||||
table: tableCode
|
||||
};
|
||||
fields.push({
|
||||
...subf,
|
||||
table: tableCode
|
||||
});
|
||||
}
|
||||
fields.push({
|
||||
...tableField,
|
||||
fields: tableFields
|
||||
});
|
||||
} else if (r.type === "GROUP") {
|
||||
const groupCode = r.code;
|
||||
const groupField = properties[groupCode];
|
||||
if (groupField.type !== "GROUP") continue;
|
||||
const groupFields = {};
|
||||
for (const row of r.layout) {
|
||||
for (const f of row.fields) {
|
||||
if (f.type === "LABEL" || f.type === "HR") continue;
|
||||
if (f.type === "SPACER") {
|
||||
spacers.push({
|
||||
...f,
|
||||
group: groupCode
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const gSubf = properties[f.code];
|
||||
if (gSubf.type !== "CATEGORY" && gSubf.type !== "STATUS" && gSubf.type !== "STATUS_ASSIGNEE" && gSubf.type !== "SUBTABLE" && gSubf.type !== "GROUP") {
|
||||
if (gSubf.type === "CHECK_BOX" || gSubf.type === "DROP_DOWN" || gSubf.type === "MULTI_SELECT" || gSubf.type === "RADIO_BUTTON") {
|
||||
const sortedOptions = Object.values(gSubf.options).sort((a, b) => Number(a.index) - Number(b.index)).map(o => o.label);
|
||||
groupFields[f.code] = {
|
||||
...gSubf,
|
||||
group: groupCode,
|
||||
sortedOptions
|
||||
};
|
||||
fields.push({
|
||||
...gSubf,
|
||||
group: groupCode,
|
||||
sortedOptions
|
||||
});
|
||||
continue;
|
||||
}
|
||||
groupFields[f.code] = {
|
||||
...gSubf,
|
||||
group: groupCode
|
||||
};
|
||||
fields.push({
|
||||
...gSubf,
|
||||
group: groupCode
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
fields.push({
|
||||
...groupField,
|
||||
fields: groupFields
|
||||
});
|
||||
// Process each layout item
|
||||
layouts.forEach(layout => {
|
||||
switch (layout.type) {
|
||||
case LAYOUT_TYPES.ROW:
|
||||
processRowFields(layout.fields, properties, fields, spacers);
|
||||
break;
|
||||
case LAYOUT_TYPES.SUBTABLE:
|
||||
processSubtableFields(layout, properties, fields);
|
||||
break;
|
||||
case LAYOUT_TYPES.GROUP:
|
||||
processGroupFields(layout, properties, fields, spacers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// lookup copy
|
||||
const flatFields = fields;
|
||||
for (const f of flatFields) {
|
||||
if ('lookup' in f && f.lookup !== null) {
|
||||
for (const mapping of f.lookup.fieldMappings) {
|
||||
const target = flatFields.find(ee => ["SINGLE_LINE_TEXT", "NUMBER", "MULTI_LINE_TEXT", "RICH_TEXT", "LINK", "CHECK_BOX", "RADIO_BUTTON", "DROP_DOWN", "MULTI_SELECT", "DATE", "TIME", "DATETIME", "USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT", "CALC", "RECORD_NUMBER"].includes(ee.type) && ee.code === mapping.field);
|
||||
if (target) {
|
||||
target.isLookupCopy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mark lookup copy fields
|
||||
markLookupCopies(fields);
|
||||
|
||||
const recordNumberField = propertyList.find(f => f.type === "RECORD_NUMBER");
|
||||
if (recordNumberField && !fields.some(f => f.type === "RECORD_NUMBER")) fields.push(recordNumberField);
|
||||
|
||||
const creatorField = propertyList.find(f => f.type === "CREATOR");
|
||||
if (creatorField && !fields.some(f => f.type === "CREATOR")) fields.push(creatorField);
|
||||
|
||||
const createdTimeField = propertyList.find(f => f.type === "CREATED_TIME");
|
||||
if (createdTimeField && !fields.some(f => f.type === "CREATED_TIME")) fields.push(createdTimeField);
|
||||
|
||||
const modifierField = propertyList.find(f => f.type === "MODIFIER");
|
||||
if (modifierField && !fields.some(f => f.type === "MODIFIER")) fields.push(modifierField);
|
||||
|
||||
const updatedTimeField = propertyList.find(f => f.type === "UPDATED_TIME");
|
||||
if (updatedTimeField && !fields.some(f => f.type === "UPDATED_TIME")) fields.push(updatedTimeField);
|
||||
// Add any missing system fields
|
||||
addSystemFields(properties, fields);
|
||||
|
||||
return { fields, spacers };
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user