diff --git a/force-app/main/default/lwc/odDatatable/odDatatable.js b/force-app/main/default/lwc/odDatatable/odDatatable.js index 2a5094e..ed7e604 100644 --- a/force-app/main/default/lwc/odDatatable/odDatatable.js +++ b/force-app/main/default/lwc/odDatatable/odDatatable.js @@ -4,12 +4,17 @@ import { FlowNavigationNextEvent } from 'lightning/flowSupport'; import CSSStyles from '@salesforce/resourceUrl/OD_DatatableCSS'; import getFieldsForObject from '@salesforce/apex/OD_ConfigurationEditorController.getFieldsForObject'; import saveRecords from '@salesforce/apex/OD_ConfigurationEditorController.saveRecords'; -import { YES_NO, EMPTY_STRING, EVENTS, ROW_BUTTON_CONFIGURATION, INLINE_FLOW } from 'c/odDatatableConstants'; +import { + YES_NO, + EMPTY_STRING, + EVENTS, + ROW_BUTTON_CONFIGURATION, + INLINE_FLOW, + ROW_BUTTON_TYPE, +} from 'c/odDatatableConstants'; import { reduceErrors, getFieldType, getPrecision, generateRandomNumber } from 'c/odDatatableUtils'; import OdDatatableFlow from 'c/odDatatableFlow'; -const ROW_BUTTON_TYPE = 'rowButtonType'; - export default class ODDatatable extends LightningElement { // internal use @api uniqueTableName; @@ -478,7 +483,7 @@ export default class ODDatatable extends LightningElement { this._doUpdateOutputs(newRecord, EVENTS.ADD); } - async _doOpenFlow(record = undefined) { + _doAddEditWithFlow(record = undefined) { const modalProps = { size: 'small', label: 'Edit or Add from a flow', @@ -493,7 +498,30 @@ export default class ODDatatable extends LightningElement { // this is an edit modalProps.flowName = this.editFlowName; modalProps.inputVariables = this.editFlowInputVariables ? JSON.parse(this.editFlowInputVariables) : []; + } + + this._doOpenFlow(modalProps, record); + } + _doOpenFlowButton(fieldName, record) { + const modalProps = { + size: 'small', + label: 'Flow Button', + }; + + const column = this.columnsToShow.find((cl) => cl.fieldName === fieldName); + + // this is an edit + modalProps.flowName = column.typeAttributes.config.flowName; + modalProps.inputVariables = column.typeAttributes.config.flowInputVariables + ? JSON.parse(column.typeAttributes.config.flowInputVariables) + : []; + + this._doOpenFlow(modalProps, record); + } + + async _doOpenFlow(modalProps, record = undefined) { + if (record) { modalProps.inputVariables.unshift({ name: 'recordId', type: 'String', @@ -685,7 +713,7 @@ export default class ODDatatable extends LightningElement { break; case EVENTS.CHANGE: if (this._editWithFlow) { - this._doOpenFlow(record); + this._doAddEditWithFlow(record); } else { this._doChangeField(recordIndex, fieldName, value); @@ -696,6 +724,9 @@ export default class ODDatatable extends LightningElement { record = this.recordsToShow[recordIndex]; } + break; + case EVENTS.OPEN_FLOW: + this._doOpenFlowButton(fieldName, record); break; default: break; @@ -710,7 +741,7 @@ export default class ODDatatable extends LightningElement { handleAdd() { // add the record to the table with the defaults if inline, otherwise open the flow to add if (this._addWithFlow) { - this._doOpenFlow(); + this._doAddEditWithFlow(); } else { this._doAddRecord(); } diff --git a/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.html b/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.html index de6943f..8631e63 100644 --- a/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.html +++ b/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.html @@ -14,9 +14,13 @@ Select the columns you want to add to the table and configure each one +
+ + +
diff --git a/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.js b/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.js index 458a54a..e4f46a1 100644 --- a/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.js +++ b/force-app/main/default/lwc/odDatatableConfigurationColumns/odDatatableConfigurationColumns.js @@ -7,18 +7,28 @@ import { sortArrayByProperty, getFieldType, getPrecision, + generateRandomNumber, } from 'c/odDatatableUtils'; -import { FIELD_TYPES, DATE_FIELDS, NUMERIC_FIELDS, FORMATTED_TYPE_TO_SHOW } from 'c/odDatatableConstants'; +import { + FIELD_TYPES, + DATE_FIELDS, + NUMERIC_FIELDS, + FORMATTED_TYPE_TO_SHOW, + BUTTON_TYPES, + ROW_BUTTON_TYPE, + ROW_BUTTON_CONFIGURATION, +} from 'c/odDatatableConstants'; export default class OdConfigurationColumns extends LightningElement { @api objectName; @api columns; @api builderContext; + @api flows; @track fieldsToDisplayTable = []; @track fields = []; - selectedFields = []; + @track selectedFields = []; popupHeight; isSelectFieldsOpened = false; isLoading = true; @@ -32,6 +42,11 @@ export default class OdConfigurationColumns extends LightningElement { lookupObjectName; lookupFieldName; + // flow input varianles + showFlowInputVariables = false; + flowInputs; + flowFieldName; + // private variables _alreadyRendered = false; _allFields; @@ -148,6 +163,11 @@ export default class OdConfigurationColumns extends LightningElement { result += `(${field.parentObjectLabel})`; } + // options + if (formattedType.options?.length > 0) { + result = formattedType.options; + } + return result; } @@ -208,19 +228,30 @@ export default class OdConfigurationColumns extends LightningElement { parsedColumns.forEach((col) => { // get the field from the fields api - const fieldIndex = this._allFields.findIndex((fl) => fl.value === col.fieldName); + const fieldIndex = col.typeAttributes.config.isCustom + ? 0 + : this._allFields.findIndex((fl) => fl.value === col.fieldName); - // get the field - const field = this._allFields[fieldIndex]; + if (fieldIndex !== -1) { + // get the field + const field = col.typeAttributes.config.isCustom + ? { type: FIELD_TYPES.CUSTOM, value: col.fieldName } + : this._allFields[fieldIndex]; - const type = getFieldType(field.type); + const type = getFieldType(field.type); + const typeSpec = this._buildTypeSpec(type, field); + + const selectedCustom = Array.isArray(typeSpec) + ? typeSpec.find((ts) => ts.value === col.typeAttributes.config.customType) + : {}; - if (fieldIndex !== -1) { result.push({ + ...selectedCustom, ...field, + label: col.typeAttributes.config.isCustom ? `Custom: ${col.tableLabel}` : col.tableLabel || field.label, type: type, tableLabel: col.tableLabel, - typeSpec: this._buildTypeSpec(type, field), + typeSpec: typeSpec, precision: getPrecision(field), isMulti: this._isMulti(type), isEditable: col.typeAttributes.editable, @@ -233,6 +264,11 @@ export default class OdConfigurationColumns extends LightningElement { options: type === FIELD_TYPES.LOOKUP ? this._buildOptionsFromFlow(FIELD_TYPES.STRING) : field.options, order: col.order, lookupConfig: col.typeAttributes.config.lookupConfig, + isCustom: col.typeAttributes.config.isCustom, + isFieldColumn: !col.typeAttributes.config.isCustom, + customType: col.typeAttributes.config.customType, + flowName: col.typeAttributes.config.flowName, + flowInputVariables: col.typeAttributes.config.flowInputVariables, }); } }); @@ -242,7 +278,7 @@ export default class OdConfigurationColumns extends LightningElement { } _addDataAndOrderFields(fields) { - const result = sortArrayByProperty(fields, 'order'); + let result = sortArrayByProperty(fields, 'order'); const elementsWithOrder = result.filter((fl) => fl.order); let lastElement; @@ -253,20 +289,41 @@ export default class OdConfigurationColumns extends LightningElement { } let iteration = 1; - result - .filter((fl) => !fl.order) - .forEach((fl) => { - fl.order = lastElement.order + 10 * iteration; - fl.tableLabel = fl.label; - fl.typeSpec = this._buildTypeSpec(fl.type, fl); - fl.precision = getPrecision(fl); - fl.isMulti = this._isMulti(fl.type); - fl.type = getFieldType(fl.type); - fl.isLookup = fl.type === FIELD_TYPES.LOOKUP; - fl.typeForDefault = fl.isLookup ? FIELD_TYPES.SELECT : fl.type; - fl.options = fl.isLookup ? this._buildOptionsFromFlow(FIELD_TYPES.STRING) : fl.options; + result = result.map((fl) => { + if (!fl.order) { + const typeSpec = this._buildTypeSpec(fl.type, fl); + + let newField = {}; + + newField.order = lastElement.order + 10 * iteration; + newField.isCustom = fl.type === FIELD_TYPES.CUSTOM; + newField.isFieldColumn = !newField.isCustom; + newField.tableLabel = fl.label; + newField.typeSpec = typeSpec; + newField.precision = getPrecision(fl); + newField.isMulti = this._isMulti(fl.type); + newField.type = getFieldType(fl.type); + newField.isLookup = fl.type === FIELD_TYPES.LOOKUP; + newField.typeForDefault = newField.isLookup ? FIELD_TYPES.SELECT : fl.type; + newField.options = newField.isLookup ? this._buildOptionsFromFlow(FIELD_TYPES.STRING) : fl.options; + + // if typespec is an array + if (Array.isArray(typeSpec)) { + // eslint-disable-next-line no-unused-vars + const { value, label, ...other } = typeSpec[0]; + newField.customType = value; + + newField = { + ...newField, + ...other, + }; + } iteration++; - }); + + return { ...fl, ...newField }; + } + return fl; + }); return result; } @@ -282,21 +339,23 @@ export default class OdConfigurationColumns extends LightningElement { this.isSelectFieldsOpened = false; } - handleDefaultOnFocusDropdown(e) { + handleColumnsOnFocusDropdown(e) { const value = e.target.dataset.value; + const fieldName = e.detail.fieldName; this.fieldsToDisplayTable.forEach((fl) => { if (fl.value === value) { - fl.opened = true; + fl[`opened_${fieldName}`] = true; } else { - fl.opened = false; + fl[`opened_${fieldName}`] = false; } }); } - handleDefaultOnBlurDropdown() { + handleColumnsOnBlurDropdown(e) { + const fieldName = e.detail.fieldName; this.fieldsToDisplayTable.forEach((fl) => { - fl.opened = false; + fl[`opened_${fieldName}`] = false; }); } @@ -309,19 +368,45 @@ export default class OdConfigurationColumns extends LightningElement { handleUpdateField(event) { const { fieldName, value, ...other } = event.detail; const fieldAPIName = event.target.dataset.value; + const isCustom = event.target.dataset.custom === 'true'; + + let objectToUpdate = { + [fieldName]: value, + }; + + if (event.target.dataset.field) { + objectToUpdate[event.target.dataset.field] = value; + } // update the right field in the arrays // selected fields array const fieldIndexSelected = this.selectedFields.findIndex((fl) => fl.value === fieldAPIName); + + // if custom search to determine the options + if (isCustom && this.selectedFields[fieldIndexSelected].typeSpec.length > 0) { + const { + // eslint-disable-next-line no-unused-vars + label, + // eslint-disable-next-line no-unused-vars + value: theValue, + // eslint-disable-next-line no-shadow + ...other + } = this.selectedFields[fieldIndexSelected].typeSpec.find((ts) => ts.value === value); + objectToUpdate = { + ...objectToUpdate, + ...other, + }; + } + this.selectedFields[fieldIndexSelected] = { ...this.selectedFields[fieldIndexSelected], - [fieldName]: value, + ...objectToUpdate, ...other, }; // fields to display table array const fieldIndex = this.fieldsToDisplayTable.findIndex((fl) => fl.value === fieldAPIName); - this.fieldsToDisplayTable[fieldIndex] = { ...this.fieldsToDisplayTable[fieldIndex], [fieldName]: value, ...other }; + this.fieldsToDisplayTable[fieldIndex] = { ...this.fieldsToDisplayTable[fieldIndex], ...objectToUpdate, ...other }; } handleClose() { @@ -334,42 +419,87 @@ export default class OdConfigurationColumns extends LightningElement { const result = []; + // common properties this.fieldsToDisplayTable.forEach((field) => { - const fieldToAdd = { + let fieldToAdd = { label: `${field.required ? '* ' : ''}${field.tableLabel}`, tableLabel: field.tableLabel, order: field.order, fieldName: field.value, wrapText: true, hideDefaultActions: true, - type: 'inputGeneric', typeAttributes: { type: field.type, recordId: { fieldName: '_id' }, record: { fieldName: '_originalRecord' }, - editable: field.isEditable, - required: field.required, fieldName: field.value, isNew: { fieldName: 'isNew' }, isDeleted: { fieldName: 'isDeleted' }, - config: { - maxLength: field.maxLength, - defaultValue: field.defaultValue, - parentObjectName: field.parentObjectName, - options: field.isLookup ? [] : field.options, - scale: field.scale, - precision: field.precision, - isHTML: field.isHTML, - isMulti: field.isMulti, - lookupConfig: field.lookupConfig, - hidden: field.hidden, - }, value: { fieldName: field.value, }, }, }; + // for object field columns + if (field.isFieldColumn) { + fieldToAdd = { + ...fieldToAdd, + type: 'inputGeneric', + typeAttributes: { + ...fieldToAdd.typeAttributes, + editable: field.isEditable, + required: field.required, + config: { + ...fieldToAdd.typeAttributes.config, + maxLength: field.maxLength, + defaultValue: field.defaultValue, + parentObjectName: field.parentObjectName, + options: field.isLookup ? [] : field.options, + scale: field.scale, + precision: field.precision, + isHTML: field.isHTML, + isMulti: field.isMulti, + lookupConfig: field.lookupConfig, + hidden: field.hidden, + }, + }, + }; + } else { + // custom columns + fieldToAdd = { + ...fieldToAdd, + typeAttributes: { + ...fieldToAdd.typeAttributes, + disableIfDeleted: true, + label: field.tableLabel, + config: { + ...fieldToAdd.typeAttributes.config, + isCustom: field.isCustom, + customType: field.customType, + }, + }, + }; + + // for button types specifically + if (BUTTON_TYPES.includes(field.customType)) { + fieldToAdd = { + ...fieldToAdd, + cellAttributes: { alignment: 'center' }, + type: ROW_BUTTON_TYPE, + typeAttributes: { + ...fieldToAdd.typeAttributes, + name: ROW_BUTTON_CONFIGURATION.OPEN_FLOW.action, + config: { + ...fieldToAdd.typeAttributes.config, + flowName: field.flowName, + flowInputVariables: field.flowInputVariables, + }, + }, + }; + } + } + // add the initial width if (field.initialWidth) { fieldToAdd.initialWidth = field.initialWidth; @@ -385,7 +515,8 @@ export default class OdConfigurationColumns extends LightningElement { } handleReorder() { - this.fieldsToDisplayTable = sortArrayByProperty(this.fieldsToDisplayTable, 'order'); + this.selectedFields = sortArrayByProperty(this.fieldsToDisplayTable, 'order'); + this.fieldsToDisplayTable = JSON.parse(JSON.stringify(this.selectedFields)); } handleOpenLookupConfiguration(event) { @@ -406,4 +537,53 @@ export default class OdConfigurationColumns extends LightningElement { this.handleCloseLookupConfiguration(); } + + handleAddNonObjectColumn() { + const fieldsPlusCustom = JSON.parse(JSON.stringify(this.selectedFields)); + + fieldsPlusCustom.push({ + label: 'Custom Column', + type: FIELD_TYPES.CUSTOM, + value: generateRandomNumber(36, 2, 10), + isEditable: false, + required: false, + canEdit: false, + hidden: false, + defaultValue: null, + initialWidth: 80, + }); + + this.handleSelectField({ detail: { value: fieldsPlusCustom } }); + } + + handleOpenFlowInputVariables(event) { + this.flowFieldName = event.target.dataset.value; + const configuration = this.selectedFields.find((fl) => fl.value === this.flowFieldName); + this.flowInputs = configuration.flowInputVariables || null; + this.showFlowInputVariables = true; + } + + handleCloseFlowInputVariables() { + this.flowInputs = null; + this.flowFieldName = null; + this.showFlowInputVariables = false; + } + + handleSaveFlowInputVariables(event) { + if (event && event.detail) { + this.handleUpdateField({ + target: { + dataset: { + value: this.flowFieldName, + }, + }, + detail: { + fieldName: 'flowInputVariables', + value: event.detail.value, + }, + }); + + this.handleCloseFlowInputVariables(); + } + } } diff --git a/force-app/main/default/lwc/odDatatableConfigurationEditor/odDatatableConfigurationEditor.html b/force-app/main/default/lwc/odDatatableConfigurationEditor/odDatatableConfigurationEditor.html index 0e7d136..9ddb71d 100644 --- a/force-app/main/default/lwc/odDatatableConfigurationEditor/odDatatableConfigurationEditor.html +++ b/force-app/main/default/lwc/odDatatableConfigurationEditor/odDatatableConfigurationEditor.html @@ -427,6 +427,7 @@

diff --git a/force-app/main/default/lwc/odDatatableConfigurationFlowInputVariables/odDatatableConfigurationFlowInputVariables.html b/force-app/main/default/lwc/odDatatableConfigurationFlowInputVariables/odDatatableConfigurationFlowInputVariables.html index 22e28b8..b2c8f54 100644 --- a/force-app/main/default/lwc/odDatatableConfigurationFlowInputVariables/odDatatableConfigurationFlowInputVariables.html +++ b/force-app/main/default/lwc/odDatatableConfigurationFlowInputVariables/odDatatableConfigurationFlowInputVariables.html @@ -2,8 +2,8 @@
Configure Flow Input Variables
diff --git a/force-app/main/default/lwc/odDatatableConstants/odDatatableConstants.js b/force-app/main/default/lwc/odDatatableConstants/odDatatableConstants.js index 2526fe9..aea3f73 100644 --- a/force-app/main/default/lwc/odDatatableConstants/odDatatableConstants.js +++ b/force-app/main/default/lwc/odDatatableConstants/odDatatableConstants.js @@ -22,6 +22,7 @@ export const FIELD_TYPES = { TEXTAREA: 'textarea', TOGGLE: 'toggle', URL: 'url', + CUSTOM: 'custom', }; export const TEXT_FIELDS = [ @@ -43,6 +44,12 @@ export const SERVER_SIDE_SEARCH = [FIELD_TYPES.LOOKUP]; export const FIELDS_STRING = [...TEXT_FIELDS, ...LOCAL_SIDE_SEARCH, ...SERVER_SIDE_SEARCH]; +export const CUSTOM_TYPES = { + SCREEN_FLOW: 'ScreenFlow', +}; + +export const BUTTON_TYPES = [CUSTOM_TYPES.SCREEN_FLOW]; + export const FORMATTED_TYPE_TO_SHOW = { address: { label: 'Address', @@ -119,6 +126,16 @@ export const FORMATTED_TYPE_TO_SHOW = { label: 'URL', maxLength: true, }, + custom: { + label: '', + options: [ + { + value: CUSTOM_TYPES.SCREEN_FLOW, + label: 'Screen Flow', + flow: true, + }, + ], + }, }; export const YES_NO = { @@ -136,11 +153,17 @@ export const EMPTY_STRING = '--empty--'; export const EVENTS = { ADD: 'add', CHANGE: 'change', + OPEN_FLOW: 'openFlow', DELETE: 'delete', UNDELETE: 'undelete', }; +export const ROW_BUTTON_TYPE = 'rowButtonType'; + export const ROW_BUTTON_CONFIGURATION = { + OPEN_FLOW: { + action: EVENTS.OPEN_FLOW, + }, EDIT: { _editAction: EVENTS.CHANGE, }, diff --git a/force-app/main/default/lwc/odDatatableCustom/odDatatableCustom.js b/force-app/main/default/lwc/odDatatableCustom/odDatatableCustom.js index 9fa59bf..1590cc4 100644 --- a/force-app/main/default/lwc/odDatatableCustom/odDatatableCustom.js +++ b/force-app/main/default/lwc/odDatatableCustom/odDatatableCustom.js @@ -23,7 +23,16 @@ export default class ODCustomDatatable extends LightningDatatable { rowButtonType: { template: rowButtonTemplate, standardCellLayout: false, - typeAttributes: ['recordId', 'iconName', 'tooltip', 'name', 'label', 'isDeleted', 'disableIfDeleted'], + typeAttributes: [ + 'recordId', + 'iconName', + 'tooltip', + 'name', + 'label', + 'isDeleted', + 'disableIfDeleted', + 'fieldName', + ], }, }; } diff --git a/force-app/main/default/lwc/odDatatableCustom/rowButtonType.html b/force-app/main/default/lwc/odDatatableCustom/rowButtonType.html index bf01c3c..1fb503e 100644 --- a/force-app/main/default/lwc/odDatatableCustom/rowButtonType.html +++ b/force-app/main/default/lwc/odDatatableCustom/rowButtonType.html @@ -7,6 +7,7 @@ tooltip={typeAttributes.tooltip} name={typeAttributes.name} label={typeAttributes.label} + field-name={typeAttributes.fieldName} > diff --git a/force-app/main/default/lwc/odDatatableRowButton/odDatatableRowButton.js b/force-app/main/default/lwc/odDatatableRowButton/odDatatableRowButton.js index adb7bad..87d41cc 100644 --- a/force-app/main/default/lwc/odDatatableRowButton/odDatatableRowButton.js +++ b/force-app/main/default/lwc/odDatatableRowButton/odDatatableRowButton.js @@ -6,6 +6,7 @@ export default class OdDatatableRowButton extends LightningElement { @api tooltip; @api name; @api label; + @api fieldName; @api isDeleted; @api disableIfDeleted; @@ -26,6 +27,7 @@ export default class OdDatatableRowButton extends LightningElement { cancelable: true, detail: { recordId: this.recordId, + fieldName: this.fieldName, action: this.name, }, });