diff --git a/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.css b/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.css index 624c5d5..66fdfbb 100644 --- a/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.css +++ b/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.css @@ -106,114 +106,4 @@ th { .slds-card__header { padding-top: 0px; -} - -.mainwrapper { - position: relative; -} - -.button-short { - line-height: inherit; -} - -.toastMessage.forceActionsText { - white-space: pre-line !important; -} - -.dataSpinnerHolder { - position: relative; - display: inline-block; - margin-left: 30px; - vertical-align: middle; - white-space: nowrap; -} - -.pageSpinnerHolder { - position: absolute; - min-height: 180px; - min-width: 180px; - z-index: 100; -} - -.applistscrollwrapper { - width: 100%; - overflow-y: auto; - max-height: 60vh; -} - -.virtualapplistscrollwrapper { - width: 100%; - overflow-y: auto; - border-top: red solid 4px; - max-height: 60vh; -} - -.tablehorizontalscroll { - width: max-content; -} - -.tablenohorizontalscroll { - width: auto; - min-width: 100%; -} - -.relatedlistscrollwrapper { - width: 100%; - min-height: 80px; - max-height: 300px; - border-bottom: 1px solid #ddd; - border-left: 1px solid #ddd; - overflow: auto; -} - -.relatedlistdisplayallwrapper { - width: 100%; - min-height: 80px; - border-bottom: 1px solid #ddd; - border-left: 1px solid #ddd; - overflow: auto; -} - -.splitviewscrollwrapper { - width: 100%; - min-height: 80px; - max-height: 67vh; - border-bottom: 1px solid #ddd; - border-left: 1px solid #ddd; - overflow: auto; -} - -.splitviewobjectlistdropdown { - width: 100%; - padding-bottom: 5px; - padding-left: 5px; - padding-right: 5px; -} - -.regularobjectlistdropdown { - min-width: 20%; - padding-left: 5px; - padding-right: 5px; -} - -.splitviewlistviewdropdown { - width: 70%; - padding-left: 5px; -} - -.regularlistviewdropdown { - min-width: 20%; -} - -thead th { - position: sticky; - top: 0; -} - -th { - z-index: 1; -} - -.slds-card__header { - padding-top: 0px; -} +} \ No newline at end of file diff --git a/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.html b/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.html index 20dffdb..07ee1c4 100644 --- a/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.html +++ b/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.html @@ -682,11 +682,9 @@

- diff --git a/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.js b/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.js index 5390cb3..c0d1045 100644 --- a/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.js +++ b/force-app/main/default/lwc/simpliUIListViews/simpliUIListViews.js @@ -7,6 +7,8 @@ import { subscribe, unsubscribe, publish, APPLICATION_SCOPE, MessageContext } fr import { encodeDefaultFieldValues } from 'lightning/pageReferenceUtils'; import currentUserId from '@salesforce/user/Id'; import * as SLVHelper from 'c/simpliUIListViewsHelper'; + + import Rows from '@salesforce/label/c.Rows'; import Selected from '@salesforce/label/c.Selected'; import Select_Action from '@salesforce/label/c.Select_Action'; @@ -29,6 +31,7 @@ import Reset_All_Data from '@salesforce/label/c.Reset_All_Data'; import Save_Row_Data from '@salesforce/label/c.Save_Row_Data'; import Search_List_Dot from '@salesforce/label/c.Search_List_Dot'; import Reset_Row_Data from '@salesforce/label/c.Reset_Row_Data'; + import hasModifyAll from '@salesforce/apex/ListViewController.hasModifyAll'; import hasEnterprise from '@salesforce/apex/ListViewController.hasEnterprise'; import getListViewObjects from '@salesforce/apex/ListViewController.getListViewObjects'; @@ -47,10 +50,13 @@ import getListViewId from '@salesforce/apex/ListViewController.getListViewId'; import updateRecord from '@salesforce/apex/ListViewController.updateRecord'; import updateRecords from '@salesforce/apex/ListViewController.updateRecords'; import getListViewConfigParameter from '@salesforce/apex/ListViewController.getListViewConfigParameter'; + import { loadScript } from 'lightning/platformResourceLoader'; import JSPDF from '@salesforce/resourceUrl/JSPDF'; import JSPDF_AUTO_TABLE from '@salesforce/resourceUrl/JSPDF_AUTOTABLE'; + export default class simpliUIListViews extends NavigationMixin(LightningElement) { + //----------- //API FIELDS //----------- @@ -89,6 +95,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) @api displayAllRelatedRecords = false; //Related List View Mode Only: Indicates whether all records should be displayed or scrolling should be used. @api objectList = undefined; //holds the list of objects from which a user can choose one. @api listViewList = undefined; //holds the set of list views for the chosen object + @api set actionList(value) //if in STANDALONE or VIRTUAL mode used when passing actions directly into the component { this.objectActionList = value; @@ -98,6 +105,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) get actionList() { return this.objectActionList; } + @api columnData; //DEPRECATED _rowData; @api set rowData(value) //if in STANDALONE or VIRTUAL mode used when passing data rows directly into the component @@ -107,6 +115,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) get rowData() { return this._rowData; } + @api set recordId(value) //used when component on standard record page. Record page injects record id into component. { this.relatedRecordId = value; @@ -124,6 +133,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) get singleListViewObject2() { return this.singleListViewObject; } + @api set singleListViewApiName2(value) //used where orgs are HUGE and singleListViewApiName needs to be entered manually. { this.singleListViewApiName = value; @@ -138,8 +148,9 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) get joinCriteria() { return this.joinData; } + @api set canReprocess(value) { - console.log('canReprocess= ', value); + } get canReprocess() { if (SLVHelper.toBool(this.displayReprocess) === true && this.isCoreListView @@ -148,6 +159,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) } return false; } + @api eventRequest(requestData) { if (this.hasEnterprise && requestData !== undefined && requestData !== '') { console.log('Event request received (' + this.eventCount + ') - ' + JSON.stringify(requestData)); @@ -156,16 +168,19 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) console.log('Empty event request'); } } + //--------------- //GET FIELDS //--------------- get hasTitle() { return SLVHelper.toBool(this.hasMainTitle); } get isNoSorting() { return SLVHelper.toBool(this.noSorting); } + //--------------- //TRACKED FIELDS //--------------- @track isCoreListView = false; @track isCustomListView = false; + @track isModeSplitView = false; //indicates whether the current mode is SPLIT_VIEW @track isModeRelatedRecord = false; //indicates over and above being a related list view whether the page is a RECORD PAGE @track isModeRelated = false; //indicates whether the current mode is RELATED LIST VIEW @@ -173,6 +188,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) @track isModeApp = false; //indicates whether the current mode is APP PAGE @track isModeSingleObject = false; //indicates whether the current mode is SINGLE OBJECT. This displays list views from a single specified object @track isModeStandAlone = false; //indicates whether the current mode is STANDALONE. This indicates that data is passed into the component at initialization + @track listviewdropdownstyle = 'regularlistviewdropdown'; @track objectlistdropdownstyle = 'regularobjectlistdropdown'; @track listwrapperstyle = 'applistscrollwrapper'; @@ -226,6 +242,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) @track headerCanWrap = false; //indicates whether the header row can wrap @track calloutCount = 1; //indicates the number of callouts made for this component @track eventCount = 0; //indicates the number of events requested by the enterprise user + @track showQuickDataModal = false; //indicates whether the quick data modal should be displayed @track quickDataHeading = 'Test Heading'; @track quickDataFieldType = 'richtext'; @@ -236,9 +253,11 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) @track quickDataObjectName; @track quickDataComponentId; //the HTML field name that called the quick data modal. Used to set the focus back on the component @track quickDataOldFieldValue; + @track offset = -1; @track rowLimit = -1; @track refreshRate = ''; //the refresh rate in seconds if the list view is auto refreshing. + //for handling hover changes @track hoverSFDCId; @track hoverAPIName; @@ -247,21 +266,26 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) @track hoverPositionLeft; @track hoverPositionTop; hoverErrorTypes = ''; //holds those types for which an error is returned when attempting to create the popover + //for handling column width changes @track mouseStart; @track oldWidth; @track parentObj; @track mouseDownColumn; + //for handling sorting @track listViewSortData = new Map(); @track columnSortData = new Map(); @track columnSortDataStr = ''; + //for type-ahead functionality for searching list views @track whereClauseListView; @track whereClauseObject; + //for handling edited records updatedRowData = new Map(); rowDataStr = ''; + //for tracking list view init process @track isInitialized = true; //indicates whether the list views have been initialized for the first time or not. @track isInitializedCheck = false; //indicates whether the list views have been initialized BY THE ADMIN @@ -269,31 +293,39 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) @track batchId = ''; //indicates the batch Id of the list view batch process. @track isInitializing = true; //indicates whether we are initializing the page or not. @track inRenderedCallback = false; //indicates whether the rendered callback method is processing + @track refreshTitle = 'Click to perform full list view refresh'; + //for message channel handlers subscription = null; receivedMessage; + label = { Rows, Selected, Select_Action, Export_All, Export_Selected, Loading, Select_Object, Object, Select_List_View, List_View, Go_To_Original, Unpin_List_View, Pin_List_View, Stop_Auto_Refresh, Refresh, List_View_Admin, Sort_By, Save_All_Data, Reset_All_Data, Save_Row_Data, Search_List_Dot, Reset_Row_Data }; + /* * Method which gets called after the class has been instantiated * but before it is rendered. We do have access to variables in this method. */ async renderedCallback() { + if (this.pageName === '') { this.dispatchEvent(SLVHelper.createToast('error', '', 'List View Configuration Error', 'A page/component name must be provided for all simpli list view components.', false)); return; } console.log('Starting simpliUIListViews.renderedCallback for ' + this.pageName); console.log('Record id - ' + this.recordId); + //this ensures we only call this once for each page load if (this.mode !== undefined && this.componentConfig === undefined && this.isInitialized === true && this.inRenderedCallback === false) { this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'rendering', status: 'started' } })); + this.inRenderedCallback = true; + loadScript(this, JSPDF) .then(() => { console.log('then'); @@ -306,80 +338,104 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) }); //turn spinner on this.spinnerOn('renderedCallback'); + //create unique component Id. Used for sending messages to other components. let num = Math.floor(Math.random() * 1000000); this.uniqueComponentId = this.pageName + ':' + num.toString(); + //subscribe to message channel this.subscribeMC(); + console.log('Component Id created - ' + this.uniqueComponentId); console.log('Ltn page name - ' + this.pageName + ' for ' + this.pageName); console.log('Page Mode - ' + this.mode + ' for ' + this.pageName); console.log('User config undefined for ' + this.pageName); + //get component config console.log(this.pageName + ' CALLOUT - getComponentConfig - ' + this.calloutCount++); this.componentConfig = await getComponentConfig({ compName: this.pageName }); this.hasEnterprise = await hasEnterprise({}); this.hasModifyAll = await hasModifyAll({}); + this.handleComponentConfig(); + //get user sort config console.log(this.pageName + ' CALLOUT - getUserSortConfigs - ' + this.calloutCount++); this.userSortConfigs = await getUserSortConfigs({ compName: this.pageName }); + this.handleUserSortConfigs(); + this.handleTypeAheadWhereClauses(); + if (this.mode === 'Stand Alone') { this.isModeStandAlone = true; this.spinnerOff('renderedCallback'); + } else if (this.mode === 'App Page') { this.isModeApp = true; this.canPin = true; this.displayObjectNames = true; this.displayListViewNames = true; this.getObjectsList(); + } else if (this.mode === 'Single Object List View') { + if (SLVHelper.isEmpty(this.singleListViewObject)) { this.dispatchEvent(SLVHelper.createToast('error', '', 'Single Object List View Configuration Error', 'If using Single Object List View mode the list view object must be provided.', false)); this.spinnerOff('renderedCallback'); return; } + this.canPin = true; this.isModeSingleObject = true; this.displayObjectNames = false; this.displayListViewNames = true; + let event = { detail: { selectedValue: this.singleListViewObject }, target: { value: this.singleListViewObject } }; //faking an event this.handleObjectChange(event); this.getListViewsForObject(); + } else if (this.mode === 'Single List View') { + if (this.singleListViewObject === '' || this.singleListViewApiName === '') { this.dispatchEvent(SLVHelper.createToast('error', '', 'Single List View Configuration Error', 'If using Single List View mode the list view object and API name must be provided.', false)); this.spinnerOff('renderedCallback'); return; + } else { + + this.isModeSingle = true; + this.selectedObject = this.singleListViewObject; + this.selectedListView = this.singleListViewApiName; + + this.refreshAllListViewData(); } - this.isModeSingle = true; - this.selectedObject = this.singleListViewObject; - this.selectedListView = this.singleListViewApiName; - this.refreshAllListViewData(); + } else if (this.mode === 'Related List View') { + if (this.singleListViewObject === '' || this.singleListViewApiName === '' || this.joinFieldName === '') { this.dispatchEvent(SLVHelper.createToast('error', '', 'Related List View Configuration Error', 'If using Related List View mode the list view object, list view API name and join field name must be provided.', false)); this.spinnerOff('renderedCallback'); return; - } - this.isModeRelated = true; - if (this.displayAllRelatedRecords) { - this.listwrapperstyle = 'relatedlistdisplayallwrapper'; - } else { - this.listwrapperstyle = 'relatedlistscrollwrapper'; - } - this.selectedObject = this.singleListViewObject; - this.selectedListView = this.singleListViewApiName; - if (this.joinData !== '') //only set list view data if there is join data. - { - this.refreshAllListViewData(); } else { - this.isInitializing = false; - this.spinnerOff('renderedCallback'); + this.isModeRelated = true; + if (this.displayAllRelatedRecords) { + this.listwrapperstyle = 'relatedlistdisplayallwrapper'; + } else { + this.listwrapperstyle = 'relatedlistscrollwrapper'; + } + this.selectedObject = this.singleListViewObject; + this.selectedListView = this.singleListViewApiName; + + if (this.joinData !== '') //only set list view data if there is join data. + { + this.refreshAllListViewData(); + } else { + this.isInitializing = false; + this.spinnerOff('renderedCallback'); + } } } else if (this.mode === 'Split View') { + this.canPin = true; this.isModeSplitView = true; this.displayListViewNames = true; @@ -406,6 +462,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.displayObjectNames = true; this.objectlistdropdownstyle = 'splitviewobjectlistdropdown'; await this.getObjectsList(); + //if we have a pinned list then getting the object will get the list views if (this.selectedListView !== undefined) { this.refreshAllListViewData(); @@ -413,18 +470,23 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.isInitializing = false; this.spinnerOff('renderedCallback'); } + //OBJECT EXISTS } else { this.selectedObject = this.singleListViewObject; + if (this.singleListViewApiName !== '') this.selectedListView = this.singleListViewApiName; + //get the object list. Even if we are not displaying the list we get it in case //we have a pinned list view which is handled in getObjectsList() await this.getObjectsList(); + //if we do not have a pinned list then the list views will not be populated //so populate them. if (this.pinnedObject === undefined) this.getListViewsForObject(); + //get data if we have object + list view if (this.selectedListView !== undefined) { this.refreshAllListViewData(); @@ -433,7 +495,9 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) } } } + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'rendering', status: 'finished' } })); + } else { console.log('No page initialization needed for ' + this.pageName); if (this.virtual) { @@ -444,17 +508,21 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) } handleStandAloneRowData(rows) { + console.log('Rows - ' + rows); if (rows === undefined || rows === '') { this.spinnerOff('handleStandAloneRowData(No Data)'); return; } console.log('Rows - ' + JSON.stringify(rows)); + if (rows.columns === undefined || rows.data === undefined) { this.dispatchEvent(SLVHelper.createToast('error', '', 'StandAlone Component Config Error', 'The row-data property must be set when using standalone mode and must contain both columns and data', false)); } + this._columnData = JSON.parse(JSON.stringify(rows.columns)); //make the objects writable this._rowData = JSON.parse(JSON.stringify(rows.data)); + this.listViewData = {}; this.listViewData.isCoreListView = false; this.listViewData.isDefaultSort = true; @@ -462,6 +530,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.listViewData.userTimeZone = 'America/Chicago'; this.listViewData.fieldMetaData = this._columnData; this.listViewData.uIColumnCount = this._columnData.length; + let listview = {}; listview.defaultSortOrder = ''; listview.isNonEditable = true; @@ -472,6 +541,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) listview.offset = -1; listview.rowLimit = 10000; this.listViewData.listView = listview; + this.listViewDataRows = this.rowData; let index = 1; this.listViewDataRows.forEach(row => { @@ -487,6 +557,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) row.rowId = row.sfdcId + ':' + index; row.checkBoxId = 'checkbox:' + row.rowId; //row.isEditable = true; + let fieldIndex = 1; row.fields.forEach(field => { let column = this._columnData[fieldIndex - 1]; @@ -502,32 +573,54 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) }); index++; }); + index = 0; - if (this.listViewData?.fieldMetaData?.length) { - this.listViewData.fieldMetaData.forEach(column => { - if (column.columnWidth !== undefined) column.columnWidth = 'width: ' + column.columnWidth + ';'; //CSS - if (column.sortDir === undefined) column.sortDir = false; - if (column.sortIndex === undefined) column.sortIndex = index; - if (column.sortIndexDisplay === undefined) column.sortIndexDisplay = index + 1; - if (column.columnIndex === undefined) column.sortIndex = index + 1; - if (column.sortable === undefined) column.sortable = false; - if (column.sortingTooltip === undefined) column.sortingTooltip = ''; - index++; - }); - } + this.listViewData.fieldMetaData.forEach(column => { + if (column.columnWidth !== undefined) column.columnWidth = 'width: ' + column.columnWidth + ';'; //CSS + if (column.sortDir === undefined) column.sortDir = false; + if (column.sortIndex === undefined) column.sortIndex = index; + if (column.sortIndexDisplay === undefined) column.sortIndexDisplay = index + 1; + if (column.columnIndex === undefined) column.sortIndex = index + 1; + if (column.sortable === undefined) column.sortable = false; + if (column.sortingTooltip === undefined) column.sortingTooltip = ''; + index++; + }); + + this.listViewDataRowsSize = this.rowData.length; this.hasListViewDataRows = true; + if (this.virtual) { this.listwrapperstyle = 'virtualapplistscrollwrapper'; } + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'standAloneRendering', status: 'finished' } })); + this.spinnerOff('handleStandAloneRowData'); } + + // getHeadColumnCss(columnWidth, mainContainer) { + // let cssResult = 'widht: auto;' + // if (columnWidth) { + // cssResult = `${columnWidth}`; + // } + // if (!this.allowHorizontalScrolling && this.listViewData?.fieldMetaData?.length) { + // const mainContainerWidth = mainContainer.offsetWidth; + // const actionBtnsWidth = this.isEdited ? 60 : 0; + // const maxColumnWidth = ((mainContainerWidth - 32 - actionBtnsWidth) / this.listViewData.fieldMetaData.length).toFixed(0); + // cssResult += ` max-width: ${maxColumnWidth}px;` + // } + // return cssResult; + // } + handleComponentConfig() { + try { console.log('Component configs retrieved successfully - ' + JSON.stringify(this.componentConfig) + ' size ' + this.componentConfig.length); + let pinnedListView = this.componentConfig.pinnedListView; console.log('Pinned list view string - ' + pinnedListView); + if (SLVHelper.toBool(this.componentConfig.AllowAdmin) === false) { if (this.hasModifyAll === true) this.allowAdmin = true; @@ -550,7 +643,9 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) if (SLVHelper.toBool(this.componentConfig.AllowInlineEditing) === false) { this.allowInlineEditing = false; } if (SLVHelper.toBool(this.componentConfig.AllowHorizontalScrolling) === false) { this.allowHorizontalScrolling = false; } if (SLVHelper.toBool(this.componentConfig.DisplayRecordPopovers) === false) { this.displayRecordPopovers = false; } + this.excludedRecordPopoverTypes = this.excludedRecordPopoverTypes + this.componentConfig.ExcludedRecordPopoverTypes; + if (this.allowHorizontalScrolling === true) { this.tablestyle = 'slds-table slds-table_bordered slds-table_fixed-layout slds-table_resizable-cols tablehorizontalscroll'; //the style applied to the list view table } @@ -559,34 +654,42 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.isPinned = true; this.pinnedObject = pinnedListView.substring(0, pinnedListView.lastIndexOf(':')); this.pinnedListView = pinnedListView.substring(pinnedListView.lastIndexOf(':') + 1); + } else { this.isInitializing = false; } } catch (error) { this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving User Config', 'Error retrieving the user config.', true)); } + } + handleUserSortConfigs() { try { console.log('User sort configs retrieved successful - ' + this.userSortConfigs + ' for ' + this.pageName); - const listViewSortFields = JSON.parse(this.userSortConfigs); + + var listViewSortFields = JSON.parse(this.userSortConfigs); console.log('List view sort fields size - ' + listViewSortFields.listviews.length); + //EXAMPLE JSON - {"listviews": [{"name": "Account:Simpli_LV_Acct_1","fields": [{"sortIndex": "0", "fieldName": "Name", "sortDirection": "true"},{"sortIndex": "1", "fieldName": "BillingState", "sortDirection": "false"}]}, {"name": "Account:PlatinumandGoldSLACustomers","fields": [{"sortIndex": "0", "fieldName": "Name", "sortDirection": "true"},{"sortIndex": "1", "fieldName": "BillingState", "sortDirection": "false"},{"sortIndex": "2", "fieldName": "Id", "sortDirection": "false"}]}]} - // eslint-disable-next-line guard-for-in - for (let m in listViewSortFields.listviews) { + for (var m in listViewSortFields.listviews) { + let listviewSorting = listViewSortFields.listviews[m]; //if we are working with the current list view if (listviewSorting.name === this.pinnedObject + ':' + this.pinnedListView || listviewSorting.name === this.selectedObject + ':' + this.selectedListView || listviewSorting.name === this.singleListViewObject + ':' + this.singleListViewApiName) { console.log('Found sorting for current list view'); - for (let i = 0; i < listviewSorting.fields.length; i++) { + for (var i = 0; i < listviewSorting.fields.length; i++) { + let sortDirection = listviewSorting.fields[i].sortDirection; + if (sortDirection === undefined || sortDirection === '') { sortDirection = true; } else { sortDirection = SLVHelper.toBool(sortDirection) } + let columnData = [Number(listviewSorting.fields[i].sortIndex), listviewSorting.fields[i].fieldName, sortDirection]; this.columnSortData.set(Number(listviewSorting.fields[i].sortIndex), columnData); } @@ -594,30 +697,41 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.columnSortDataStr = JSON.stringify(Array.from(this.columnSortData)); console.log('XXXX Column Sort Data Str - ' + this.columnSortDataStr); this.listViewSortData.set(listviewSorting.name, this.columnSortData); + //for all other list views } else { let columnSortData = new Map(); - for (let index = 0; index < listviewSorting.fields.length; index++) { + + for (var index = 0; index < listviewSorting.fields.length; index++) { + let sortDirection = listviewSorting.fields[index].sortDirection; + if (sortDirection === undefined || sortDirection === '') { sortDirection = true; } else { sortDirection = SLVHelper.toBool(sortDirection) } + let columnData = [Number(listviewSorting.fields[index].sortIndex), listviewSorting.fields[index].fieldName, sortDirection]; columnSortData.set(Number(listviewSorting.fields[index].sortIndex), columnData); } + this.listViewSortData.set(listviewSorting.name, columnSortData); + } } } catch (error) { this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving User Sorting', 'Error retrieving the user sorting config.', true)); } } + createWhereClause(field, operator, values) { - return { field: field, operator: operator, values: values }; + let whereClause = { field: field, operator: operator, values: values }; + return whereClause; } + handleTypeAheadWhereClauses() { + if (!SLVHelper.isEmpty(this.includedObjects)) { this.whereClauseObject = this.createWhereClause('simpli_lv__Object_Name__c', 'IN', this.includedObjects); console.log('whereClauseObject - ' + JSON.stringify(this.whereClauseObject)); @@ -625,64 +739,80 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.whereClauseObject = this.createWhereClause('simpli_lv__Object_Name__c', 'NOT IN', this.excludedObjects); console.log('whereClauseObject - ' + JSON.stringify(this.whereClauseObject)); } + + if (this.mode === 'Single Object List View' && this.singleListViewObject !== '') { this.whereClauseListView = this.createWhereClause('simpli_lv__Object_Name__c', '=', this.selectedObject); console.log('whereClauseListView - ' + JSON.stringify(this.whereClauseListView)); } + } + /* * Used for handling the message channel */ @wire(MessageContext) messageContext; + + + handleInitializedCheck(event) { - try { - const { detail } = event; - this.isInitialized = detail; - this.isInitializedCheck = true; - if (this.isInitialized === false) { - this.spinner = false; //a special case where we set it directly. - } - } catch (error) { - SLVHelper.showErrorMessage(error); + this.isInitialized = event.detail; + this.isInitializedCheck = true; + if (this.isInitialized === false) { + this.spinner = false; //a special case where we set it directly. } } + getListViewActions() { console.log('Starting getListViewActions'); + if (this.virtual) { this.dispatchEvent(new CustomEvent('getactions', { detail: { pageName: this.pageName, compType: this.mode, objectName: this.selectedObject, listViewName: this.selectedListView } })); } else { console.log(this.pageName + ' CALLOUT - getListViewActions - ' + this.calloutCount++); - getListViewActions({ objectType: this.selectedObject, listViewName: this.selectedListView, componentName: this.pageName }).then(result => { - console.log(this.pageName + ' CALLOUT - getListViewActions - ' + this.calloutCount++); - this.objectActionList = result; - this.handleListViewActions(0); - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'refreshActions', status: 'finished', listView: this.selectedListView, object: this.selectedObject, count: this.displayedActionList.length } })); - }).catch(error => { - this.objectActionList = undefined; - this.spinnerOff('getObjectsList'); - this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving Actions', 'Error retrieving the list view actions.', true)); - }); + getListViewActions({ objectType: this.selectedObject, listViewName: this.selectedListView, componentName: this.pageName }) + .then(result => { + console.log(this.pageName + ' CALLOUT - getListViewActions - ' + this.calloutCount++); + this.objectActionList = result; + this.handleListViewActions(0); + this.dispatchEvent(new CustomEvent('eventresponse', { detail: {type: 'refreshActions', status: 'finished', listView: this.selectedListView, object: this.selectedObject, count: this.displayedActionList.length}})); + }) + .catch(error => { + this.objectActionList = undefined; + this.spinnerOff('getObjectsList'); + this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving Actions', 'Error retrieving the list view actions.', true)); + }); } } + handleListViewActions(numSelectedRecords) { + if (this.objectActionList.length === 0 || this.displayActions === false) { this.canDisplayActions = false; } else if (SLVHelper.toBool(this.displayActions) === true) { this.canDisplayActions = true; + this.displayedActionList = []; + this.objectActionList.forEach(action => { if (action.selectedRecVisibility === 'Always displayed') this.displayedActionList[this.displayedActionList.length] = action; + else if (numSelectedRecords === 0) { + if (action.selectedRecVisibility === 'Displayed if no records are selected' || action.selectedRecVisibility === 'Displayed if zero or one record is selected') this.displayedActionList[this.displayedActionList.length] = action; + } else if (numSelectedRecords === 1) { + if (action.selectedRecVisibility === 'Displayed if one or more records are selected' || action.selectedRecVisibility === 'Displayed if one record is selected') this.displayedActionList[this.displayedActionList.length] = action; + } else if (numSelectedRecords > 1) { + if (action.selectedRecVisibility === 'Displayed if multiple records are selected' || action.selectedRecVisibility === 'Displayed if one or more records are selected') this.displayedActionList[this.displayedActionList.length] = action; @@ -690,23 +820,21 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) }); } } + async refreshAllListViewData() { - try { - this.offset = -1; - this.selectedRecordCount = 0; - this.isEdited = false; - this.hoverIsDisplayed = false; - let selectedRows = this.template.querySelectorAll('lightning-input'); - if (selectedRows) { - selectedRows.forEach((element) => { element.checked = false }); - } - await this.getListViewDataPage(); - await this.getListViewActions(); - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.offset = -1; + this.selectedRecordCount = 0; + this.isEdited = false; + this.hoverIsDisplayed = false; + let selectedRows = this.template.querySelectorAll('lightning-input'); + selectedRows.forEach(element => element.checked = false); + + this.getListViewDataPage(); + this.getListViewActions(); } + async getListViewDataPage() { + try { console.log(this.pageName + ' CALLOUT - getListViewData(' + this.pageName + ', ' + this.mode + ', ' + this.selectedObject + ', ' + this.selectedListView + ', ' + this.columnSortDataStr + ', ' + this.joinFieldName + ', ' + this.joinData + ', ' + this.offset + ', ' + this.textSearchText + ')'); if (this.virtual) { @@ -725,50 +853,63 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving List View Data', 'Error retrieving the list view data.', true)); this.spinnerOff('getListViewDataPage'); } + this.refreshTime = Date.now(); } handleListViewDataPage(listViewDataResult) { + console.log('JSON Result - ' + JSON.stringify(listViewDataResult)); console.log('List View Query - ' + listViewDataResult.queryString); console.log('Starting refreshListViewData - ' + this.pageName + ' - ' + this.selectedObject + ' - ' + this.selectedListView + ' - ' + this.joinFieldName + ' - ' + this.offset + ' for ' + this.pageName); + //if this is the first time we are initializing the list view data OR we are refreshing the data. if (this.listViewData === undefined || this.listViewData.coreListId !== listViewDataResult.coreListId || this.offset === -1 || (this.offset === this.listViewData.listView.offset && this.offset === -1)) { //initialize list view info this.listViewData = listViewDataResult; + //initialize list view row data this.listViewDataRows = listViewDataResult.rows; + //else add the new data to the existing data } else { this.listViewDataRows = this.listViewDataRows.concat(listViewDataResult.rows); } + let oldDataRowsSize = this.listViewDataRowsSize; //update the data rows size. this.listViewDataRowsSize = this.listViewDataRows.length; + if (this.listViewData.hasTotalsRow) { this.listViewDataRowsSize--; if (this.isModeSplitView === true) this.listViewDataRows.pop(); } + if (this.listViewDataRowsSize === 0) this.hasListViewDataRows = false; else this.hasListViewDataRows = true; + //this is to fix a weird issue where width of table gets reduced if there are no rows. if (this.allowHorizontalScrolling === true && this.hasListViewDataRows === true) { this.tablestyle = 'slds-table slds-table_bordered slds-table_fixed-layout slds-table_resizable-cols tablehorizontalscroll'; } else { this.tablestyle = 'slds-table slds-table_bordered slds-table_fixed-layout slds-table_resizable-cols tablenohorizontalscroll'; } + + console.log('this.listViewDataRows.length - ' + this.listViewDataRows.length + ' for ' + this.pageName); console.log('listViewDataResult.listView.rowLimit - ' + listViewDataResult.listView.rowLimit + ' for ' + this.pageName); console.log('this.offset - ' + this.offset + ' for ' + this.pageName); console.log('listViewDataResult.listView.offset - ' + listViewDataResult.listView.offset + ' for ' + this.pageName); + //if we have not reached our max limit if (this.listViewDataRows.length < listViewDataResult.listView.rowLimit) { //if the offset has not changed or the row size has not changed then we are done. if (this.offset === listViewDataResult.listView.offset || oldDataRowsSize === this.listViewDataRowsSize) { this.dataSpinnerOff(); + //update offset (which will trigger another request for data) } else { this.dataSpinnerOn(); @@ -776,17 +917,21 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.rowLimit = listViewDataResult.listView.rowLimit; this.getListViewDataPage(); } + //if we have reached our max limit } else { this.dataSpinnerOff(); } + console.log('List view data retrieval successful - ' + this.offset + ' of ' + this.rowLimit + ' records retrieved for ' + this.pageName); + //sets the last modified text if the component has been configured to show the data. if (this.displayModified === true) { this.modifiedText = this.listViewData.listView.lastModifiedText; } else { this.modifiedText = ''; } + if (this.listViewData.listView.listViewType === 'Core') { this.isCoreListView = true; this.isCustomListView = false; @@ -794,122 +939,156 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.isCoreListView = false; this.isCustomListView = true; } + this.displayTextSearch = false; if (this.canDisplayTextSearch === true && this.listViewData.canTextSearch === true) { this.displayTextSearch = true; } + this.refreshTitle = 'Click to perform list view refresh on current list view'; this.isInitializing = false; } + async getObjectsList() { if (this.objectList === undefined) //only get the list views if we have not retrieved them before { console.log('Starting getObjectsList'); console.log(this.pageName + ' CALLOUT - getListViewObjects - ' + this.calloutCount++); this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'refreshObjects', status: 'started' } })); - await getListViewObjects({ includedObjects: this.includedObjects, excludedObjects: this.excludedObjects }).then(result => { - this.objectList = result; - if (this.objectList !== undefined && this.objectList.length > 0) { - console.log('Object list has been populated with size - ' + this.objectList.length + ' for ' + this.pageName); - if (this.pinnedObject !== undefined) { - //check if we have an object that matches the users pinned object. (could be stale) - const found = this.objectList.find(element => element.value === this.pinnedObject); - //if we do have an object then set it and get the pinned list view. - if (found !== undefined) { - console.log('Object IS in the object list for ' + this.pageName); - this.selectedObject = this.pinnedObject; - this.getListViewsForObject(); - } else { - this.spinner = false; //cannot use spinnerOff() here as we might be initializing + await getListViewObjects({ includedObjects: this.includedObjects, excludedObjects: this.excludedObjects }) + .then(result => { + this.objectList = result; + + if (this.objectList !== undefined && this.objectList.length > 0) { + console.log('Object list has been populated with size - ' + this.objectList.length + ' for ' + this.pageName); + + if (this.pinnedObject !== undefined) { + //check if we have an object that matches the users pinned object. (could be stale) + var found = this.objectList.find(element => element.value === this.pinnedObject); + + //if we do have an object then set it and get the pinned list view. + if (found !== undefined) { + console.log('Object IS in the object list for ' + this.pageName); + this.selectedObject = this.pinnedObject; + this.getListViewsForObject(); + } else { + this.spinner = false; //cannot use spinnerOff() here as we might be initializing + } + this.pinnedObject = undefined; + } else if (this.isInitializing === false) { + this.spinnerOff('getObjectsList'); } - this.pinnedObject = undefined; - } else if (this.isInitializing === false) { - this.spinnerOff('getObjectsList'); + + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'refreshObjects', status: 'finished', count: this.objectList.length } })); + } - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'refreshObjects', status: 'finished', count: this.objectList.length } })); - } - }).catch(error => { - this.spinnerOff('getObjectsList'); - this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving List View Objects', 'Error retrieving the list view objects.', true)); - }); + }) + .catch(error => { + this.spinnerOff('getObjectsList'); + this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving List View Objects', 'Error retrieving the list view objects.', true)); + }); + } } + async getListViewsForObject() { if (this.listViewListObject !== this.selectedObject && this.typeAheadListSearch === false) //only get the list views if its for a new object and we are not doing type ahead { this.listViewListObject = this.selectedObject; + console.log(this.pageName + ' CALLOUT - getObjectListViews(' + this.selectedObject + ') - ' + this.calloutCount++); this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'refreshListViews', status: 'started', object: this.selectedObject } })); - await getObjectListViews({ objectName: this.selectedObject }).then(result => { - console.log('Object list view retrieval successful for ' + this.pageName); - this.listViewList = result; - console.log('Object list view size - ' + this.listViewList.length + ' for ' + this.pageName); - console.log('Pinned list view - ' + this.pinnedListView + ' for ' + this.pageName); - console.log('First List View Get - ' + this.firstListViewGet + ' for ' + this.pageName); - //if we have no list views to display then either the object name is bad or the user does not have access to the object. - if (this.listViewList.length === 0) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Retrieving Object List Views', 'No list views available as the user does not have access to this object.', false)); - } else if (this.urlListView !== undefined) { - this.selectedListView = this.urlListView; - this.selectedListViewExportName = this.selectedListView + '.csv'; - } else if (this.pinnedListView !== undefined && this.firstListViewGet === true) { - console.log('We have a pinned list view for ' + this.pageName); - //check if we have the list view in the list. (it could be a stale pinning) - const found = this.listViewList.find(element => element.value === this.pinnedListView); - //if we have a valid list view name - if (found !== undefined) { - console.log('Found a list view with the pinned list view name for ' + this.pageName); - this.selectedListView = this.pinnedListView; + await getObjectListViews({ objectName: this.selectedObject }) + .then(result => { + console.log('Object list view retrieval successful for ' + this.pageName); + this.listViewList = result; + console.log('Object list view size - ' + this.listViewList.length + ' for ' + this.pageName); + console.log('Pinned list view - ' + this.pinnedListView + ' for ' + this.pageName); + console.log('First List View Get - ' + this.firstListViewGet + ' for ' + this.pageName); + + //if we have no list views to display then either the object name is bad or the user does not have access to the object. + if (this.listViewList.length === 0) { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Retrieving Object List Views', 'No list views available as the user does not have access to this object.', false)); + } else if (this.urlListView !== undefined) { + this.selectedListView = this.urlListView; this.selectedListViewExportName = this.selectedListView + '.csv'; - this.refreshAllListViewData(); - //if we do not then bail. - } else { - console.log('Did NOT find a list view with the pinned list view name for ' + this.pageName); - this.isInitializing = false; + } else if (this.pinnedListView !== undefined && this.firstListViewGet === true) { + + console.log('We have a pinned list view for ' + this.pageName); + //check if we have the list view in the list. (it could be a stale pinning) + const found = this.listViewList.find(element => element.value === this.pinnedListView); + + //if we have a valid list view name + if (found !== undefined) { + console.log('Found a list view with the pinned list view name for ' + this.pageName); + this.selectedListView = this.pinnedListView; + this.selectedListViewExportName = this.selectedListView + '.csv'; + this.refreshAllListViewData(); + + //if we do not then bail. + } else { + console.log('Did NOT find a list view with the pinned list view name for ' + this.pageName); + this.isInitializing = false; + } + + this.firstListViewGet = false; } - this.firstListViewGet = false; - } - this.refreshTitle = 'Click to perform a refresh on all ' + this.selectedObject + ' list views'; - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'refreshListViews', status: 'finished', count: this.listViewList.length, object: this.selectedObject } })); - this.spinnerOff('getListViewsForObject'); - }).catch(error => { - this.spinnerOff('getListViewsForObject'); - this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving Object List Views', 'Error retrieving ' + this.selectedObject + ' list views data. This usually indicates the user does not have read access to the object. if you believe this to be an error', true)); - }); + + this.refreshTitle = 'Click to perform a refresh on all ' + this.selectedObject + ' list views'; + + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'refreshListViews', status: 'finished', count: this.listViewList.length, object: this.selectedObject } })); + + this.spinnerOff('getListViewsForObject'); + }) + .catch(error => { + this.spinnerOff('getListViewsForObject'); + this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Retrieving Object List Views', 'Error retrieving ' + this.selectedObject + ' list views data. This usually indicates the user does not have read access to the object. if you believe this to be an error', true)); + }); + //if we } else if (this.typeAheadListSearch === true) { + if (this.pinnedListView !== undefined && this.firstListViewGet === true) { + console.log('We have a pinned list view for ' + this.pageName); + //check for list view name validity (it could be a stale pinning) - await getListViewId({ objectName: this.selectedObject, listViewName: this.pinnedListView }).then(result => { - console.log('Is valid list view request successful for ' + this.pageName); - //if we have a valid list view name - if (result !== '') { - console.log('Found a list view with the pinned list view name for ' + this.pageName); - this.selectedListView = this.pinnedListView; - this.selectedListViewExportName = this.selectedListView + '.csv'; - this.selectedListViewId = result; - this.whereClauseListView = this.createWhereClause('simpli_lv__Object_Name__c', '=', this.selectedObject); - this.refreshAllListViewData(); - //if we do not then bail. - } else { - console.log('Did NOT find a list view with the pinned list view name for ' + this.pageName); - this.isInitializing = false; - this.spinner = false; - } - this.firstListViewGet = false; - }).catch(error => { - this.spinnerOff('isValidListView'); - this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Checking For Valid List View', 'Error checking for a valid list view with name ' + this.pinnedListView + ' for object ' + this.selectedObject + '.', true)); - }); + await getListViewId({ objectName: this.selectedObject, listViewName: this.pinnedListView }) + .then(result => { + console.log('Is valid list view request successful for ' + this.pageName); + + //if we have a valid list view name + if (result !== '') { + console.log('Found a list view with the pinned list view name for ' + this.pageName); + this.selectedListView = this.pinnedListView; + this.selectedListViewExportName = this.selectedListView + '.csv'; + this.selectedListViewId = result; + this.whereClauseListView = this.createWhereClause('simpli_lv__Object_Name__c', '=', this.selectedObject); + this.refreshAllListViewData(); + + //if we do not then bail. + } else { + console.log('Did NOT find a list view with the pinned list view name for ' + this.pageName); + this.isInitializing = false; + this.spinner = false; + } + + this.firstListViewGet = false; + }).catch(error => { + this.spinnerOff('isValidListView'); + this.dispatchEvent(SLVHelper.createToast('error', error, 'Error Checking For Valid List View', 'Error checking for a valid list view with name ' + this.pinnedListView + ' for object ' + this.selectedObject + '.', true)); + }); + } else { this.refreshTitle = 'Click to perform a refresh on all ' + this.selectedObject + ' list views'; + this.spinnerOff('getListViewsForObject'); } } else { this.spinner = false; //cannot use spinnerOff() here as we might be initializing } } + /* * Method which subscribes this component to a defined message channel. This subscription * allows the components to send messages to each other. @@ -926,6 +1105,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) { scope: APPLICATION_SCOPE } ); } + /* * Method which unsubscribes this component from any channels. * This method will be called automatically by the SFDC framework. @@ -934,20 +1114,27 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) unsubscribe(this.subscription); this.subscription = null; } + /* * called when a component within the same APP as this component sends a message that records * have just been selected by that component. */ handleMessage(message) { + this.receivedMessage = message; console.log(this.uniqueComponentId + ' received a message from ' + this.receivedMessage.uniqueComponentId + ' for ' + this.pageName); + console.log('message recordIds - ' + this.receivedMessage.recordIds); console.log('message objectType - ' + this.receivedMessage.objectType); console.log('message uniqueComponentId - ' + this.receivedMessage.uniqueComponentId); + if (this.receivedMessage.uniqueComponentId === this.uniqueComponentId) { return; } + + if (this.receivedMessage.type === 'selectrecordupdate') { + //if we have no record Id and its a NON-RECORD page RELATED LIST then set rows to 0 if (this.receivedMessage.recordIds === '' && this.isModeRelated === true @@ -959,6 +1146,7 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.hasListViewDataRows = false; return; } + console.log('selectedObject - ' + this.selectedObject); console.log('isModeRelatedRecord - ' + this.isModeRelatedRecord); console.log('joinFieldName - ' + this.joinFieldName); @@ -971,43 +1159,56 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) console.log('Record ids from message - ' + this.receivedMessage.recordIds + ' for ' + this.pageName); this.joinData = JSON.stringify(message); console.log('Join Data JSON - ' + this.joinData + ' for ' + this.pageName); + this.spinnerOn('handleMessage'); + if (!this.virtual) { //we need to check and see if this message is valid for this component. //I think we need to get rid of this.......causes data reload to take too long. console.log(this.pageName + ' CALLOUT - isValidListViewDataRequest - ' + this.calloutCount++); - isValidListViewDataRequest({ objectName: this.selectedObject, joinFieldName: this.joinFieldName, joinData: this.joinData }).then(result => { - console.log('isValidListViewDataRequest returned - ' + result + ' for ' + this.pageName); - if (result === 'success') { - this.refreshAllListViewData(); - } else { - this.spinnerOff('handleMessage'); - } - }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the list view.', true)); - }); + isValidListViewDataRequest({ objectName: this.selectedObject, joinFieldName: this.joinFieldName, joinData: this.joinData }) + .then(result => { + console.log('isValidListViewDataRequest returned - ' + result + ' for ' + this.pageName); + + if (result === 'success') { + this.refreshAllListViewData(); + } else { + this.spinnerOff('handleMessage'); + } + + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the list view.', true)); + }); } } else { console.log('Page names are the same or we do not have a joined field name so ignoring message! for ' + this.uniqueComponentId); } } } + handleAutoRefreshData() { + console.log('Refreshing data for ' + this.pageName); + if (this.isRefreshing) { + let mills = (Date.now() - this.refreshTime); if (mills > 5000) this.refreshAllListViewData(); + //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind //look at its use with setTimeout down the page! - // eslint-disable-next-line @lwc/lwc/no-async-operation setTimeout(this.handleAutoRefreshData.bind(this), this.refreshRate * 1000); //change to milliseconds + } } - async handleAutoRefreshButtonClick() { + + async handleAutoRefreshButtonClick(event) { console.log('Refresh button clicked for ' + this.pageName); console.log('Auto refresh was set to ' + this.isRefreshing + ' for ' + this.pageName); console.log('Refresh time was ' + this.refreshTime + ' for ' + this.pageName); + //if we do not have the single/double click refresh setting then get it if (this.singleClickAutoRefresh === undefined) { console.log(this.pageName + ' CALLOUT - getListViewConfigParameter(SingleClickAutoDataRefresh) - ' + this.calloutCount++); @@ -1016,15 +1217,19 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.singleClickAutoRefresh = 'false'; } } + let mills = (Date.now() - this.refreshTime); + //we are refreshing automatically and someone stops it. if (this.isRefreshing === true) { this.isRefreshing = false; this.dispatchEvent(SLVHelper.createToast('success', '', 'Auto Refresh Stopped', '', false)); this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'autoRefreshOff', status: 'finished' } })); + //if someone has clicked the refresh button again within 5 seconds } else if (this.singleClickAutoRefresh === 'true' || (mills < 5000 && this.isRefreshing === false)) { this.isRefreshing = true; + //if we do not have the refresh rate then get it if (this.refreshRate === '') { console.log(this.pageName + ' CALLOUT - getListViewConfigParameter(RefreshRate) - ' + this.calloutCount++); @@ -1033,75 +1238,90 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) this.refreshRate = '45'; //default to 45s if nothing returned } } + this.dispatchEvent(SLVHelper.createToast('success', '', 'Auto Refresh Started', 'Refreshing every ' + this.refreshRate + 's', false)); this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'autoRefreshOn', status: 'finished' } })); console.log('Refresh now set to ' + this.isRefreshing + ' @ ' + this.refreshRate + 's for ' + this.pageName); this.handleAutoRefreshData(); + //if someone clicked the refresh button for the first time } else { this.refreshAllListViewData(); this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'autoRefreshOnce', status: 'finished' } })); this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Refreshed', 'Click within 5 seconds of data loading to auto refresh.', false)); } + } + async getConfigParameter(paramName) { return getListViewConfigParameter({ objectName: this.selectedObject, listViewName: this.selectedListView, paramName: paramName }); } + /* * Called when the user clicks the data download button. * This returns the data for the current list view in CSV format. */ - handleDownloadData() { + handleDownloadData(event) { console.log('Data export button clicked for ' + this.pageName); + //get the header values let dataStr = this.listViewData.headersAsCSVString; - if (this.listViewDataRows?.length) { - this.listViewDataRows.forEach(element => { - dataStr = dataStr + element.dataAsCSVString; - }); - } + + this.listViewDataRows.forEach(element => { + dataStr = dataStr + element.dataAsCSVString; + }); + + const data = new Blob([dataStr], { type: 'text/plain' }); + let downloadElement = document.createElement('a'); downloadElement.href = URL.createObjectURL(data); downloadElement.setAttribute("download", "download"); downloadElement.download = this.selectedListViewExportName; downloadElement.click(); + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'downloadData', status: 'finished', data: dataStr, object: this.selectedObject, listView: this.selectedListView } })); + } + /* * Called when the user clicks the SELECTED data download button. * This returns the data for the current list view in CSV format. */ - handleSelectedDownloadData() { + handleSelectedDownloadData(event) { console.log('Selected data export button clicked for ' + this.pageName); + //get the header values - let dataStr = this.listViewData.headersAsCSVString; + var dataStr = this.listViewData.headersAsCSVString; + //get the selected record Ids - const selectedRecords = new Set(); + var selectedRecords = new Set(); let selectedRows = this.template.querySelectorAll('lightning-input'); - if (selectedRows?.length) { - selectedRows.forEach(element => { - if (element.checked === true && element.value !== 'all') { - selectedRecords.add(element.value); - } - }); - } - if (this.listViewDataRows?.length) { - this.listViewDataRows.forEach(element => { - if (selectedRecords.has(element.rowId)) { - dataStr = dataStr + element.dataAsCSVString; - } - }); - } + selectedRows.forEach(element => { + if (element.checked === true && element.value !== 'all') { + selectedRecords.add(element.value); + } + }); + + this.listViewDataRows.forEach(element => { + if (selectedRecords.has(element.rowId)) { + dataStr = dataStr + element.dataAsCSVString; + } + }); + //turn string into blob - const data = new Blob([dataStr], { type: 'text/plain' }); + var data = new Blob([dataStr], { type: 'text/plain' }); + let downloadElement = document.createElement('a'); downloadElement.href = URL.createObjectURL(data); downloadElement.setAttribute("download", "download"); downloadElement.download = this.selectedListViewExportName; downloadElement.click(); + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'downloadSelectedData', status: 'finished', data: dataStr, object: this.selectedObject, listView: this.selectedListView } })); + } + /* * Called when a user checks a box next to a record for * selection to be processed. This method is really for @@ -1111,226 +1331,230 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) */ handleRecordSelectChange(event) { this.spinnerOn('handleRecordSelectChange'); - try { - const { target } = event; - const { checked, value } = target; - console.log('Record selected - ' + checked + ': ' + value + ' for ' + this.pageName); - //get all checkbox components - let selectedRows = this.template.querySelectorAll('lightning-input'); - //if we have selected "All" then run through all components setting them true or false. - if (value === 'all') { - selectedRows.forEach((element) => { element.checked = checked }); - if (checked === true) { - this.selectedRecordCount = this.listViewDataRowsSize; - } else { - this.selectedRecordCount = 0; - } + console.log('Record selected - ' + event.target.checked + ': ' + event.target.value + ' for ' + this.pageName); + + //get all checkbox components + let selectedRows = this.template.querySelectorAll('lightning-input'); + + //if we have selected "All" then run through all components setting them true or false. + if (event.target.value === 'all') { + const checked = event.target.checked + selectedRows.forEach(element => element.checked = checked); + + if (event.target.checked === true) { + this.selectedRecordCount = this.listViewDataRowsSize; } else { - if (checked === true) { - this.selectedRecordCount++; - } else { - this.selectedRecordCount--; - } - } - this.handleListViewActions(this.selectedRecordCount); - console.log('Sending to message channel for ' + this.uniqueComponentId); - //run through all the checkbox components again now that they have been set - let recordIds = ''; - if (selectedRows?.length) { - selectedRows.forEach(element => { - if (element.checked === true && element.value !== 'all') { - //the value includes the row number so remove that from the end as we only want the Ids - const indexOf = element.value.indexOf(':'); - const recordId = element.value.substring(0, indexOf); - if (recordId !== '' && recordId !== undefined) //if we clicked "All" then the first one is blank. - recordIds = recordIds + recordId + ','; - } - }); + this.selectedRecordCount = 0; } - //remove the last comma if there is one. - if (recordIds?.length > 0) { - recordIds = recordIds.substring(0, recordIds.lastIndexOf(',')); - } - //if we are sending the selection to other components. - if (SLVHelper.toBool(this.useMessageChannel) === true) { - const message = { - type: 'selectrecordupdate', - recordIds: recordIds, - objectType: this.selectedObject, - uniqueComponentId: this.uniqueComponentId - }; - publish(this.messageContext, LISTVIEW_MC, message); + + } else { + if (event.target.checked === true) { + this.selectedRecordCount++; } else { - console.log('NOT sending to message channel for ' + this.uniqueComponentId); + this.selectedRecordCount--; } - this.dispatchEvent(new CustomEvent('rowselectupdate', { detail: { recordIds: recordIds } })); - } catch (error) { - SLVHelper.showErrorMessage(error); - } finally { - this.spinnerOff('handleRecordSelectChange'); } + + this.handleListViewActions(this.selectedRecordCount); + + console.log('Sending to message channel for ' + this.uniqueComponentId); + //run through all the checkbox components again now that they have been set + var recordIds = ''; + + selectedRows.forEach(element => { + if (element.checked === true && element.value !== 'all') { + //the value includes the row number so remove that from the end as we only want the Ids + const indexOf = element.value.indexOf(':'); + var recordId = element.value.substring(0, indexOf); + if (recordId !== '' && recordId !== undefined) //if we clicked "All" then the first one is blank. + recordIds = recordIds + recordId + ','; + } + }); + + //remove the last comma if there is one. + if (recordIds.length > 0) { + recordIds = recordIds.substring(0, recordIds.lastIndexOf(',')); + } + + //if we are sending the selection to other components. + if (SLVHelper.toBool(this.useMessageChannel) === true) { + + const message = { + type: 'selectrecordupdate', + recordIds: recordIds, + objectType: this.selectedObject, + uniqueComponentId: this.uniqueComponentId + }; + publish(this.messageContext, LISTVIEW_MC, message); + + } else { + console.log('NOT sending to message channel for ' + this.uniqueComponentId); + } + this.dispatchEvent(new CustomEvent('rowselectupdate', { detail: { recordIds: recordIds } })); + + this.spinnerOff('handleRecordSelectChange'); } + /* * Called when a user is selecting a list view and * they have changed the object of the list view. */ handleObjectChange(event) { - try { - this.spinnerOn('handleObjectChange'); - const { detail, target } = event; - if (this.typeAheadObjectSearch === true) { - this.selectedObject = detail?.selectedValue ?? ''; - } else { - this.selectedObject = target?.value ?? ''; - } - this.selectedListView = undefined; - this.selectedListViewId = undefined; - this.selectedListViewExportName = undefined; - this.whereClauseListView = this.createWhereClause('simpli_lv__Object_Name__c', '=', this.selectedObject); - this.listViewList = undefined; - this.listViewData = undefined; - this.listViewDataRows = undefined; - this.objectActionList = undefined; - this.displayedActionList = []; - this.columnSortDataStr = ''; - this.columnSortData = new Map(); - this.modifiedText = ''; - this.textSearchText = ''; - this.isCoreListView = true; //this is not necessarily true since we haven't chosen a list view but we set it to true because we want to display the resource refresh button for the object - console.log('Object selected - ' + this.selectedObject + ' for ' + this.pageName); - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'objectSelected', status: 'finished', object: this.selectedObject } })); - this.getListViewsForObject(); - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.spinnerOn('handleObjectChange'); + + if (this.typeAheadObjectSearch === true) { + this.selectedObject = event.detail.selectedValue; + } else { + this.selectedObject = event.target.value; + } + this.selectedListView = undefined; + this.selectedListViewId = undefined; + this.selectedListViewExportName = undefined; + this.whereClauseListView = this.createWhereClause('simpli_lv__Object_Name__c', '=', this.selectedObject); + this.listViewList = undefined; + this.listViewData = undefined; + this.listViewDataRows = undefined; + this.objectActionList = undefined; + this.displayedActionList = []; + this.columnSortDataStr = ''; + this.columnSortData = new Map(); + this.modifiedText = ''; + this.textSearchText = ''; + this.isCoreListView = true; //this is not necessarily true since we haven't chosen a list view but we set it to true because we want to display the resource refresh button for the object + console.log('Object selected - ' + this.selectedObject + ' for ' + this.pageName); + + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'objectSelected', status: 'finished', object: this.selectedObject } })); + + this.getListViewsForObject(); } + /* * Called when a user changed a list view, used * to retrieve record data. */ handleListViewChanged(event) { - try { - const { detail, target } = event; - const { value } = target; - const { selectedValue } = detail; - console.log('Old list view - ' + this.selectedListView + ' for ' + this.pageName); - console.log('Sort data - ' + this.listViewSortData + ' for ' + this.pageName); - this.spinnerOn('handleListViewChanged'); - this.textSearchText = ''; - //set the old column sort information into the list view sort data for caching otherwise it disappears. - if (this.columnSortDataStr !== '') { - this.listViewSortData.set(this.selectedObject + ':' + this.selectedListView, this.columnSortData); - } - //set the new selected list view (COMBO BOX) - this.selectedListView = value; - //set the new selected list view (TYPE AHEAD) - if (selectedValue !== undefined) - this.selectedListView = selectedValue; - console.log('New list view - ' + this.selectedListView + ' for ' + this.pageName); - this.selectedListViewExportName = this.selectedListView + '.csv'; - //set the column sort information for the NEW list view - if (this.listViewSortData.get(this.selectedObject + ':' + this.selectedListView) !== undefined) { - this.columnSortData = this.listViewSortData.get(this.selectedObject + ':' + this.selectedListView); - this.columnSortDataStr = JSON.stringify(Array.from(this.columnSortData)); - } else { - this.columnSortDataStr = ''; - this.columnSortData = new Map(); - } - //if we are not in the construction of the page and we change the list view and its the pinned list view - if (this.componentConfig !== undefined && this.pinnedObject === this.selectedObject && this.pinnedListView === this.selectedListView) { - this.isPinned = true; - } else { - this.isPinned = false; - } - this.refreshTitle = 'Click to perform list view refresh on current list view'; - console.log('Starting ListView Data Refresh for ' + this.pageName); - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'listViewSelected', status: 'finished', object: this.selectedObject, listView: this.selectedListView } })); - this.refreshAllListViewData(); - } catch (error) { - SLVHelper.showErrorMessage(error); + + console.log('Old list view - ' + this.selectedListView + ' for ' + this.pageName); + console.log('Sort data - ' + this.listViewSortData + ' for ' + this.pageName); + this.spinnerOn('handleListViewChanged'); + this.textSearchText = ''; + + //set the old column sort information into the list view sort data for caching otherwise it disappears. + if (this.columnSortDataStr !== '') { + this.listViewSortData.set(this.selectedObject + ':' + this.selectedListView, this.columnSortData); + } + + //set the new selected list view (COMBO BOX) + this.selectedListView = event.target.value; + + //set the new selected list view (TYPE AHEAD) + if (event.detail.selectedValue !== undefined) + this.selectedListView = event.detail.selectedValue; + + console.log('New list view - ' + this.selectedListView + ' for ' + this.pageName); + this.selectedListViewExportName = this.selectedListView + '.csv'; + + //set the column sort information for the NEW list view + if (this.listViewSortData.get(this.selectedObject + ':' + this.selectedListView) !== undefined) { + this.columnSortData = this.listViewSortData.get(this.selectedObject + ':' + this.selectedListView); + this.columnSortDataStr = JSON.stringify(Array.from(this.columnSortData)); + + } else { + this.columnSortDataStr = ''; + this.columnSortData = new Map(); } + + //if we are not in the construction of the page and we change the list view and its the pinned list view + if (this.componentConfig !== undefined && this.pinnedObject === this.selectedObject && this.pinnedListView === this.selectedListView) { + this.isPinned = true; + } else { + this.isPinned = false; + } + this.refreshTitle = 'Click to perform list view refresh on current list view'; + + console.log('Starting ListView Data Refresh for ' + this.pageName); + + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'listViewSelected', status: 'finished', object: this.selectedObject, listView: this.selectedListView } })); + + this.refreshAllListViewData(); } + /* * Method for handling when a user pins a given list view. */ - handlePinningClick() { + handlePinningClick(event) { this.isPinned = true; + console.log(this.pageName + ' CALLOUT - updateUserConfig(pinnedListView) - ' + this.calloutCount++); - updateUserConfig({ compName: this.pageName, configName: 'pinnedListView', value: this.selectedObject + ':' + this.selectedListView }).then(() => { - this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Pinned', 'List view successfully pinned.', false)); - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'pinListView', status: 'finished', object: this.selectedObject, listView: this.selectedListView } })); - }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Pinning Error', 'Error during user configuration update.', true)); - }); + updateUserConfig({ compName: this.pageName, configName: 'pinnedListView', value: this.selectedObject + ':' + this.selectedListView }) + .then(result => { + this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Pinned', 'List view successfully pinned.', false)); + + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'pinListView', status: 'finished', object: this.selectedObject, listView: this.selectedListView } })); + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Pinning Error', 'Error during user configuration update.', true)); + }); + } + /* * Method for handling when a user UNPINS a given list view. */ - handleUnpinningClick() { + handleUnpinningClick(event) { + console.log(this.pageName + ' CALLOUT - updateUserConfig(pinnedListView) - ' + this.calloutCount++); - updateUserConfig({ compName: this.pageName, configName: 'pinnedListView', value: '' }).then(result => { - console.log('RESULT - ' + result); - if (result === 'success') { - this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Unpinned', 'List view successfully unpinned.', false)); - this.isPinned = false; - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'unpinListView', status: 'finished', object: this.selectedObject, listView: this.selectedListView } })); - } else { - console.log('List view unpinning NOT successful for ' + this.pageName); - this.dispatchEvent(SLVHelper.createToast('error', '', 'Unpinning Error', 'There was a problem unpinning the list view. This might be due to user permissions.', false)); - } - }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Unpinning Error', 'There was a problem unpinning the list view. This might be due to user permissions.', true)); - }); + updateUserConfig({ compName: this.pageName, configName: 'pinnedListView', value: '' }) + .then(result => { + console.log('RESULT - ' + result); + if (result === 'success') { + this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Unpinned', 'List view successfully unpinned.', false)); + this.isPinned = false; + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'unpinListView', status: 'finished', object: this.selectedObject, listView: this.selectedListView } })); + + } else { + console.log('List view unpinning NOT successful for ' + this.pageName); + this.dispatchEvent(SLVHelper.createToast('error', '', 'Unpinning Error', 'There was a problem unpinning the list view. This might be due to user permissions.', false)); + } + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Unpinning Error', 'There was a problem unpinning the list view. This might be due to user permissions.', true)); + }); } + /* * Called when a URL on the pages table data is clicked */ handleURLClick(event) { - try { - const target = event.target.target; - //this is the URL - console.log('URL clicked - ' + event.target.href + ' for ' + this.pageName); - console.log('URL target - ' + target + ' for ' + this.pageName); - //hack to get the record Id from the URL - const chars = event.target.href.split('/'); - console.log('Id - ' + chars[5] + ' for ' + this.pageName); - //stop the link from doing its usual thing as we will be doing our thing. - event.preventDefault(); - event.stopPropagation(); - SLVHelper.invokeWorkspaceAPI('isConsoleNavigation').then(isConsole => { - if (isConsole) { - SLVHelper.invokeWorkspaceAPI('getFocusedTabInfo').then(focusedTab => { - if (focusedTab !== undefined && focusedTab.tabId !== undefined) { - SLVHelper.invokeWorkspaceAPI('openSubtab', { - parentTabId: focusedTab.tabId, - recordId: chars[5], - focus: true - }).then(tabId => { - console.log("Newly opened tab id - ", tabId); - }); - } else { - // Navigate to record page - this[NavigationMixin.Navigate]({ - type: 'standard__recordPage', - attributes: { - recordId: chars[5], - actionName: 'view', - }, - }); - } - }); - } else { - //if we are opening a up a new window then use the whole URL as is. - if (target === '_blank') { - // Navigate to a URL - this[NavigationMixin.Navigate]({ - type: 'standard__webPage', - attributes: { - url: event.target.href - } - }, true); - //if we are using the same window then get the Id of the URL + + var target = event.target.target; + //this is the URL + console.log('URL clicked - ' + event.target.href + ' for ' + this.pageName); + console.log('URL target - ' + target + ' for ' + this.pageName); + + //hack to get the record Id from the URL + const chars = event.target.href.split('/'); + console.log('Id - ' + chars[5] + ' for ' + this.pageName); + + //stop the link from doing its usual thing as we will be doing our thing. + event.preventDefault(); + event.stopPropagation(); + + SLVHelper.invokeWorkspaceAPI('isConsoleNavigation').then(isConsole => { + if (isConsole) { + SLVHelper.invokeWorkspaceAPI('getFocusedTabInfo').then(focusedTab => { + + if (focusedTab !== undefined && focusedTab.tabId !== undefined) { + SLVHelper.invokeWorkspaceAPI('openSubtab', { + parentTabId: focusedTab.tabId, + recordId: chars[5], + focus: true + }).then(tabId => { + console.log("Newly opened tab id - ", tabId); + }); + } else { + // Navigate to record page this[NavigationMixin.Navigate]({ type: 'standard__recordPage', @@ -1339,19 +1563,47 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) actionName: 'view', }, }); + } + }); + + } else { + + //if we are opening a up a new window then use the whole URL as is. + if (target === '_blank') { + // Navigate to a URL + this[NavigationMixin.Navigate]({ + type: 'standard__webPage', + attributes: { + url: event.target.href + } + }, + true); + + //if we are using the same window then get the Id of the URL + } else { + // Navigate to record page + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + recordId: chars[5], + actionName: 'view', + }, + }); } - }); - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'urlClicked', status: 'finished', url: event.target.href } })); - } catch (error) { - SLVHelper.showErrorMessage(error); - } + + } + }); + + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'urlClicked', status: 'finished', url: event.target.href } })); } + dataSpinnerOn() { this.dataSpinner = true; this.canDisplayActions = false; console.log('Data Spinner ON for ' + this.pageName); } + dataSpinnerOff() { this.dataSpinner = false; if (this.objectActionList !== undefined && this.objectActionList.length > 0 && SLVHelper.toBool(this.displayActions) === true) { @@ -1359,739 +1611,844 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) } console.log('Data Spinner OFF for ' + this.pageName); } + spinnerOn(message) { this.spinner = true; console.log('Spinner ON - ' + message + ' - ' + this.pageName); } + spinnerOff(message) { if (this.isInitializing === false) { this.spinner = false; console.log('Spinner OFF - ' + message + ' - ' + this.pageName); } } + handleProcessListViewsButtonClick(event) { + this.spinnerOn('handleProcessListViewsButtonClick'); console.log('Listview process button clicked for ' + this.pageName); console.log('selectedObject - ' + this.selectedObject + ' for ' + this.pageName); console.log('selectedListView - ' + this.selectedListView + ' for ' + this.pageName); console.log('DATA - ' + event.currentTarget.dataset.type); + //if we need to initialize after install or upgrade if (event.currentTarget.dataset.type !== undefined && event.currentTarget.dataset.type === 'full' && this.isInitialized === false) { this.selectedObject = undefined; this.selectedListView = undefined; } + //if we have selected a specific list view to update if (this.selectedObject !== undefined && this.selectedListView !== undefined && this.isInitialized === true) { console.log('Updating SINGLE list view for ' + this.pageName); + console.log(this.pageName + ' CALLOUT - updateSingleListView - ' + this.calloutCount++); - updateSingleListView({ objectType: this.selectedObject, listViewName: this.selectedListView }).then(result => { - if (result === 'success') { - this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Updated Successfully', 'List view has been updated and refreshed successfully.', false)); - this.dispatchEvent(new CustomEvent('processlistviewclick')); - this.refreshAllListViewData(); - } else { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Processing Error', 'Error processing the list view.', false)); - this.spinnerOff('handleProcessListViewsButtonClick1'); - } - }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the list view.', true)); - this.spinnerOff('handleProcessListViewsButtonClick2'); - }); + updateSingleListView({ objectType: this.selectedObject, listViewName: this.selectedListView }) + .then(result => { + + if (result === 'success') { + this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Updated Successfully', 'List view has been updated and refreshed successfully.', false)); + this.dispatchEvent(new CustomEvent('processlistviewclick')); + this.refreshAllListViewData(); + + } else { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Processing Error', 'Error processing the list view.', false)); + this.spinnerOff('handleProcessListViewsButtonClick1'); + } + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the list view.', true)); + this.spinnerOff('handleProcessListViewsButtonClick2'); + }); + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'processSingleListView', status: 'finished', object: this.selectedObject, listView: this.selectedListView } })); + } + //if we have selected an objects list views to update else if (this.selectedObject !== undefined && this.selectedListView === undefined && this.isInitialized === true) { console.log('Updating OBJECT list views for ' + this.pageName); + console.log(this.pageName + ' CALLOUT - updateObjectListViews - ' + this.calloutCount++); - updateObjectListViews({ objectType: this.selectedObject }).then(result => { - if (result === 'success') { - this.dispatchEvent(SLVHelper.createToast('success', '', this.selectedObject + ' List Views Updated', this.selectedObject + ' list views have been updated successfully.', false)); - this.dispatchEvent(new CustomEvent('processlistviewclick')); - this.getListViewsForObject(); - this.spinnerOff('handleProcessListViewsButtonClick3'); - } else { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Processing Error', 'Error processing the ' + this.selectedObject + ' list views.', false)); - this.spinnerOff('handleProcessListViewsButtonClick4'); - } - }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the ' + this.selectedObject + ' list views.', true)); - this.spinnerOff('handleProcessListViewsButtonClick5'); - }); + updateObjectListViews({ objectType: this.selectedObject }) + .then(result => { + + if (result === 'success') { + this.dispatchEvent(SLVHelper.createToast('success', '', this.selectedObject + ' List Views Updated', this.selectedObject + ' list views have been updated successfully.', false)); + this.dispatchEvent(new CustomEvent('processlistviewclick')); + this.getListViewsForObject(); + this.spinnerOff('handleProcessListViewsButtonClick3'); + + } else { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Processing Error', 'Error processing the ' + this.selectedObject + ' list views.', false)); + this.spinnerOff('handleProcessListViewsButtonClick4'); + } + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the ' + this.selectedObject + ' list views.', true)); + this.spinnerOff('handleProcessListViewsButtonClick5'); + }); + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'processObjectListViews', status: 'finished', object: this.selectedObject } })); + } + //if we have selected ALL list views to update else if (this.selectedObject === undefined && this.selectedListView === undefined || this.isInitialized === false) { console.log('Updating ALL list views for ' + this.pageName); + console.log(this.pageName + ' CALLOUT - updateAllListViews - ' + this.calloutCount++); - updateAllListViews().then(result => { - if (result === 'failed') { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Processing Error', 'Error processing the list views.', false)); - this.spinnerOff('handleProcessListViewsButtonClick6'); + updateAllListViews({}) + .then(result => { + + if (result === 'failed') { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Processing Error', 'Error processing the list views.', false)); + this.spinnerOff('handleProcessListViewsButtonClick6'); + + } else { + this.batchId = result; + this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Processing', 'List view processing has started for all list views. Refresh page after completion to see changes.', false)); + this.dispatchEvent(new CustomEvent('processlistviewclick')); + this.spinnerOff('handleProcessListViewsButtonClick7'); + } + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the list views.', true)); + this.spinnerOff('handleProcessListViewsButtonClick8'); + }); - } else { - this.batchId = result; - this.dispatchEvent(SLVHelper.createToast('success', '', 'List View Processing', 'List view processing has started for all list views. Refresh page after completion to see changes.', false)); - this.dispatchEvent(new CustomEvent('processlistviewclick')); - this.spinnerOff('handleProcessListViewsButtonClick7'); - } - }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Processing Error', 'Error processing the list views.', true)); - this.spinnerOff('handleProcessListViewsButtonClick8'); - }); this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'processAllListViews', status: 'finished' } })); } + } + calculateWidth(event) { - try { - const { target, clientX } = event; - const childObj = target; - let parObj = childObj.parentNode; - const mouseStart = clientX; - this.mouseDownColumn = event.currentTarget.dataset.index; - while (parObj.tagName !== 'TH') { - parObj = parObj.parentNode; - } - this.mouseStart = mouseStart; - this.oldWidth = parObj.offsetWidth; - this.parentObj = parObj; - console.log('Mouse start - ' + this.mouseStart); - console.log('Old Width - ' + this.oldWidth); - if (event.stopPropagation) event.stopPropagation(); - if (event.preventDefault) event.preventDefault(); - event.cancelBubble = true; - event.returnValue = false; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + var childObj = event.target + var parObj = childObj.parentNode; + var mouseStart = event.clientX; + this.mouseDownColumn = event.currentTarget.dataset.index; + while (parObj.tagName !== 'TH') { + parObj = parObj.parentNode; + } + this.mouseStart = mouseStart; + this.oldWidth = parObj.offsetWidth; + this.parentObj = parObj; + + console.log('Mouse start - ' + this.mouseStart); + console.log('Old Width - ' + this.oldWidth); + + if (event.stopPropagation) event.stopPropagation(); + if (event.preventDefault) event.preventDefault(); + event.cancelBubble = true; + event.returnValue = false; } + setNewWidth(event) { - try { - if (this.mouseStart === undefined) return; - const { clientX } = event; - console.log('event.clientX - ' + clientX); - let newWidth = clientX - parseFloat(this.mouseStart) + parseFloat(this.oldWidth); - console.log('New width - ' + newWidth); - this.parentObj.style.width = newWidth + 'px'; - this.mouseStart = undefined; - this.saveColumnWidth(newWidth, this.mouseDownColumn); - } catch (error) { - SLVHelper.showErrorMessage(error); - } + + if (this.mouseStart === undefined) return; + + console.log('event.clientX - ' + event.clientX); + let newWidth = event.clientX - parseFloat(this.mouseStart) + parseFloat(this.oldWidth); + + console.log('New width - ' + newWidth); + + // const mainContainer = this.template.querySelector('.applistscrollwrapper'); + // if (!this.allowHorizontalScrolling && this.listViewData.fieldMetaData.length) { + // const mainContainerWidth = mainContainer.offsetWidth; + // const actionBtnsWidth = this.isEdited ? 60 : 0; + // const maxColumnWidth = ((mainContainerWidth - 32 - actionBtnsWidth) / this.listViewData.fieldMetaData.length).toFixed(0); + // if (newWidth >= maxColumnWidth) { + // newWidth = maxColumnWidth; + // } + // } + + this.parentObj.style.width = newWidth + 'px'; + + this.mouseStart = undefined; + + this.saveColumnWidth(newWidth, this.mouseDownColumn); } + saveColumnWidth(newWidth, columnIndex) { console.log(this.pageName + ' CALLOUT - updateUserConfigListViewWidth(columnWidth) - ' + this.calloutCount++); + let configName = 'columnWidths:' + this.selectedObject + ':' + this.selectedListView; console.log('Config width string - ' + configName); - updateUserConfigListViewWidth({ compName: this.pageName, configName: configName, columnIndex: columnIndex, width: newWidth }).then(() => { }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Width Save Error', 'Error during user configuration update.', true)); - }); + updateUserConfigListViewWidth({ compName: this.pageName, configName: configName, columnIndex: columnIndex, width: newWidth }) + .then(result => { + + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Width Save Error', 'Error during user configuration update.', true)); + }); + } + sortColumns(event) { this.spinnerOn('sortColumns'); - try { - const { currentTarget } = event; - const { dataset } = currentTarget; - const { name, sortdir, sortindex } = dataset; - //get all values from the event - let fieldName = name; - let sortDirection = sortdir; - let sortIndex = sortindex; - if (sortIndex === undefined || sortIndex === '') { - sortIndex = this.columnSortData.size; - } - sortIndex = Number(sortIndex); - if (sortDirection === undefined || sortDirection === '') { - sortDirection = true; + + //get all values from the event + let fieldName = event.currentTarget.dataset.name; + let sortDirection = event.currentTarget.dataset.sortdir; + let sortIndex = event.currentTarget.dataset.sortindex; + + if (sortIndex === undefined || sortIndex === '') { + sortIndex = this.columnSortData.size; + } + sortIndex = Number(sortIndex); + + if (sortDirection === undefined || sortDirection === '') { + sortDirection = true; + } else { + sortDirection = SLVHelper.toBool(sortDirection) + } + + let columnData; + + if (this.useSimpleSorting === true) { + if (this.columnSortData.has(sortIndex)) { + columnData = this.columnSortData.get(sortIndex); + + columnData[2] = !columnData[2]; + columnData[0] = 0; + + this.columnSortData = new Map(); + this.columnSortData.set(0, columnData); + //first time clicking on column just add the column for sorting. } else { - sortDirection = SLVHelper.toBool(sortDirection) + columnData = [0, fieldName, sortDirection]; + this.columnSortData = new Map(); + this.columnSortData.set(0, columnData); } - let columnData; - if (this.useSimpleSorting === true) { - if (this.columnSortData.has(sortIndex)) { - columnData = this.columnSortData.get(sortIndex); - columnData[2] = !columnData[2]; - columnData[0] = 0; - this.columnSortData = new Map(); - this.columnSortData.set(0, columnData); - //first time clicking on column just add the column for sorting. + } else { + //clicked on a column already being sorted then switch the direction + if (this.columnSortData.has(sortIndex)) { + columnData = this.columnSortData.get(sortIndex); + + //the second click on the column switch the column. + if (columnData[2] === true) { + columnData[2] = false; + this.columnSortData.set(sortIndex, columnData); + + //third click on the column reset all sorting data. } else { - columnData = [0, fieldName, sortDirection]; this.columnSortData = new Map(); - this.columnSortData.set(0, columnData); } + + //first time clicking on a column then add the column for sorting. } else { - //clicked on a column already being sorted then switch the direction - if (this.columnSortData.has(sortIndex)) { - columnData = this.columnSortData.get(sortIndex); - //the second click on the column switch the column. - if (columnData[2] === true) { - columnData[2] = false; - this.columnSortData.set(sortIndex, columnData); - //third click on the column reset all sorting data. - } else { - this.columnSortData = new Map(); - } - //first time clicking on a column then add the column for sorting. - } else { - columnData = [sortIndex, fieldName, sortDirection]; - this.columnSortData.set(sortIndex, columnData); - } + columnData = [sortIndex, fieldName, sortDirection]; + this.columnSortData.set(sortIndex, columnData); } - } catch (error) { - SLVHelper.showErrorMessage(error); - } finally { - this.columnSortDataStr = JSON.stringify(Array.from(this.columnSortData)); - this.listViewSortData.set(this.selectedObject + ':' + this.selectedListView, this.columnSortData); - this.refreshAllListViewData(); + } + + + this.columnSortDataStr = JSON.stringify(Array.from(this.columnSortData)); + this.listViewSortData.set(this.selectedObject + ':' + this.selectedListView, this.columnSortData); + this.refreshAllListViewData(); } + //ACTIONS + //called when a user selects an action for processing. async handleActionSelect(event) { - try { - this.selectedRecordIds = new Set(); - let selectedRowId = ''; - const { target } = event; - const { value } = target - this.selectedActionKey = value; - console.log('Chosen Action - ' + this.selectedActionKey + ' for ' + this.pageName); - //get the ACTION - if (this.displayedActionList?.length) { - this.displayedActionList.forEach(action => { - if (action.value === this.selectedActionKey) { - this.selectedAction = action; - } - }); + this.selectedRecordIds = new Set(); + var selectedRowId = ''; + + this.selectedActionKey = event.target.value; + + console.log('Chosen Action - ' + this.selectedActionKey + ' for ' + this.pageName); + + //get the ACTION + this.displayedActionList.forEach(action => { + if (action.value === this.selectedActionKey) { + this.selectedAction = action; } - //get the SELECTED RECORD IDs - let selectedRows = this.template.querySelectorAll('lightning-input'); - if (selectedRows?.length) { - selectedRows.forEach(element => { - if (element.checked === true && element.value !== 'all') { - selectedRowId = element.value.substring(0, element.value.indexOf(':')); - if (selectedRowId !== '') - this.selectedRecordIds.add(selectedRowId); - } - }); + }); + + //get the SELECTED RECORD IDs + let selectedRows = this.template.querySelectorAll('lightning-input'); + selectedRows.forEach(element => { + if (element.checked === true && element.value !== 'all') { + selectedRowId = element.value.substring(0, element.value.indexOf(':')); + if (selectedRowId !== '') + this.selectedRecordIds.add(selectedRowId); } - this.selectedRecordIdsStr = JSON.stringify(Array.from(this.selectedRecordIds)); - //HYPERLINK - if (this.selectedAction.isHyperlink === true) { - let hyperlink = this.selectedAction.hyperlink; - let recordIdStr = ''; - this.selectedRecordIds.forEach(recordId => { - recordIdStr = recordIdStr + recordId + '%2C'; //%2C = encoded comma - }); - recordIdStr = recordIdStr.slice(0, -3); //remove last "%2C" - if (this.selectedRecordIds.size > 1) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'Multiple rows cannot be selected for this action', false)); - } else { - //go through the action parameters checking for field substitutions - this.selectedAction.allParameters.forEach(param => { - let key = '$' + param.aPIName + '$'; - if (hyperlink.includes(key)) { - //get the ROW - let row; - this.listViewDataRows.forEach(element => { - if (element.isDeleted === false && element.salesforceId === recordIdStr) { - row = element; - } - }); - if (row === undefined) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'A row must be selected for this action', false)); - hyperlink = ''; + }); - } else if (param.value === 'Id') { - hyperlink = hyperlink.replace(key, row.salesforceId); - } else { - //get the FIELD value and substitute into hyperlink - row.fields.forEach(element => { - if (element.name === param.value) { - hyperlink = hyperlink.replace(key, element.value); - } - }); + this.selectedRecordIdsStr = JSON.stringify(Array.from(this.selectedRecordIds)); + + //HYPERLINK + if (this.selectedAction.isHyperlink === true) { + let hyperlink = this.selectedAction.hyperlink; + let recordIdStr = ''; + this.selectedRecordIds.forEach(recordId => { + recordIdStr = recordIdStr + recordId + '%2C'; //%2C = encoded comma + }); + recordIdStr = recordIdStr.slice(0, -3); //remove last "%2C" + + if (this.selectedRecordIds.size > 1) { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'Multiple rows cannot be selected for this action', false)); + } else { + + //go through the action parameters checking for field substitutions + this.selectedAction.allParameters.forEach(param => { + let key = '$' + param.aPIName + '$'; + if (hyperlink.includes(key)) { + //get the ROW + let row; + this.listViewDataRows.forEach(element => { + if (element.isDeleted === false && element.salesforceId === recordIdStr) { + row = element; } - } - }); - console.log('Hyperlink - ' + hyperlink); - if (hyperlink !== '') { - this[NavigationMixin.Navigate]({ - type: 'standard__webPage', - attributes: { - url: hyperlink, - }, }); + + if (row === undefined) { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'A row must be selected for this action', false)); + hyperlink = ''; + + } else if (param.value === 'Id') { + hyperlink = hyperlink.replace(key, row.salesforceId); + } else { + + //get the FIELD value and substitute into hyperlink + row.fields.forEach(element => { + if (element.name === param.value) { + hyperlink = hyperlink.replace(key, element.value); + } + }); + } } - } - //GENERATE PDF - } else if (this.selectedAction.className === 'ListViewActionPDF') { - this.spinnerOn('ListViewActionPDF'); - console.log('We are generating a PDF for ' + this.pageName); - console.log(this.pageName + ' CALLOUT - getListViewConfigParameter(PDFTheme) - ' + this.calloutCount++); - let theme = await this.getConfigParameter('PDFTheme'); - if (theme === undefined || theme === null || theme === '') { - theme = 'striped'; //default to striped if nothing returned - } - console.log(this.pageName + ' CALLOUT - updateAllListViews(PDFOrientationPortrait) - ' + this.calloutCount++); - let orientation = await this.getConfigParameter('PDFOrientationPortrait'); - if (orientation === undefined || orientation === null || orientation === '') { - orientation = 'true'; //default to striped if nothing returned - } else if (orientation === 'false') { //true = portrait, false = landscape - orientation = 'landscape'; - } - const { jsPDF } = window.jspdf; - let doc = new jsPDF(orientation); - doc.autoTable({ - head: SLVHelper.headRows(this.listViewData.fieldMetaData), - body: SLVHelper.bodyRows(this.selectedRecordIds, this.listViewDataRows), - theme: theme, - margin: { top: 5, right: 5, bottom: 5, left: 5 }, }); - this.selectedListViewExportName = this.selectedListView + '.pdf'; - doc.save(this.selectedListViewExportName); - this.spinnerOff('ListViewActionPDF'); - //SCREEN FLOW (AUTOMATED FLOWS HAPPEN IN CUSTOM) - } else if (this.selectedAction.isFlow === true && this.selectedAction.flowType === 'Screen Flow' && !this.virtual) { - this.selectedActionLabel = 'Label ' + this.selectedAction.label; - this.showFlowModal = true; - //CREATE/NEW - } else if (this.selectedAction.className === 'ListViewActionCreate' && !this.virtual) { - let navLocation = 'DETAIL'; - let defaultValues = {}; - if (this.isModeRelated) { - defaultValues[this.joinFieldName] = this.recordId; - navLocation = 'RELATED_LIST'; - } - //go through the action parameters checking for field substitutions - this.selectedAction.allParameters.forEach(param => { - if (param.aPIName === 'UserField') - defaultValues[param.value] = currentUserId; - if (param.aPIName === 'NoRedirect' && param.value === 'true') - navLocation = 'RELATED_LIST'; - }); - defaultValues = encodeDefaultFieldValues(defaultValues); - try { - this[NavigationMixin.Navigate]({ - type: 'standard__objectPage', - attributes: { - objectApiName: this.selectedObject, - actionName: 'new', - }, - state: { - useRecordTypeCheck: 1, - defaultFieldValues: defaultValues, - navigationLocation: navLocation, - } - }).then(() => { - this.refreshAllListViewData(); - }); - } catch (error) { - SLVHelper.showErrorMessage(error); - } - //CLONE - } else if (this.selectedAction.className === 'ListViewActionClone' && !this.virtual) { - if (this.selectedRecordIds.size !== 1) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'A single row must be selected for cloning', false)); - } else { - console.log('We are cloning the following id - ' + selectedRowId + ' for ' + this.pageName); - this[NavigationMixin.Navigate]({ - type: 'standard__recordPage', - attributes: { - objectApiName: this.selectedObject, - actionName: 'clone', - recordId: selectedRowId, - }, - }); - this.dispatchEvent(new CustomEvent('processclick')); - } - //EDIT - } else if (this.selectedAction.className === 'ListViewActionEdit' && !this.virtual) { - if (this.selectedRecordIds.size !== 1) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'A single row must be selected for editing', false)); - } else { - console.log('We are editing the following id - ' + selectedRowId + ' for ' + this.pageName); + + console.log('Hyperlink - ' + hyperlink); + + if (hyperlink !== '') { this[NavigationMixin.Navigate]({ - type: 'standard__recordPage', + type: 'standard__webPage', attributes: { - objectApiName: this.selectedObject, - actionName: 'edit', - recordId: selectedRowId, + url: hyperlink, }, }); - this.dispatchEvent(new CustomEvent('processclick')); } - //EDIT All - } else if (this.selectedAction.className === 'ListViewActionEditAll' && !this.virtual) { - console.log('We are editing all records for ' + this.pageName); - if (this.listViewDataRows.length > 101) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Too Many Rows!', 'Inline editing only available for up to 100 rows', false)); - } else { - this.setAllRowsEdited(); - } - //MASS CREATE - } else if (this.selectedAction.className === 'ListViewActionMassCreate' && !this.virtual) { - console.log('We are mass creating records for ' + this.pageName); - if (this.selectedAction.massCreateListViewName !== undefined) - this.massCreateListView = this.selectedAction.massCreateListViewName - else - this.massCreateListView = this.selectedListView; - this.showMassCreateModal = true; - //EMAIL USING TEMPLATE - } else if (this.selectedAction.className === 'ListViewActionEmail' && this.selectedAction.emailTemplateFolder !== '' && this.selectedRecordIds.size > 0 && !this.virtual) { - console.log('We are creating emails from a template for ' + this.pageName); - this.showEmailTemplateModal = true; - this.emailTemplateFolder = this.selectedAction.emailTemplateFolder; - this.emailTemplateWhatIdField = this.selectedAction.emailTemplateWhatIdField; - this.spinnerOff('ListViewActionEmailTemplate'); - //CUSTOM + } + + //GENERATE PDF + } else if (this.selectedAction.className === 'ListViewActionPDF') { + this.spinnerOn('ListViewActionPDF'); + console.log('We are generating a PDF for ' + this.pageName); + + console.log(this.pageName + ' CALLOUT - getListViewConfigParameter(PDFTheme) - ' + this.calloutCount++); + var theme = await this.getConfigParameter('PDFTheme'); + if (theme === undefined || theme === null || theme === '') { + theme = 'striped'; //default to striped if nothing returned + } + + + console.log(this.pageName + ' CALLOUT - updateAllListViews(PDFOrientationPortrait) - ' + this.calloutCount++); + var orientation = await this.getConfigParameter('PDFOrientationPortrait'); + if (orientation === undefined || orientation === null || orientation === '') { + orientation = 'true'; //default to striped if nothing returned + } else if (orientation === 'false') { //true = portrait, false = landscape + orientation = 'landscape'; + } + + const { jsPDF } = window.jspdf; + var doc = new jsPDF(orientation); + + doc.autoTable({ + head: SLVHelper.headRows(this.listViewData.fieldMetaData), + body: SLVHelper.bodyRows(this.selectedRecordIds, this.listViewDataRows), + theme: theme, + margin: { top: 5, right: 5, bottom: 5, left: 5 }, + }); + + this.selectedListViewExportName = this.selectedListView + '.pdf'; + + doc.save(this.selectedListViewExportName); + this.spinnerOff('ListViewActionPDF'); + + //SCREEN FLOW (AUTOMATED FLOWS HAPPEN IN CUSTOM) + } else if (this.selectedAction.isFlow === true && this.selectedAction.flowType === 'Screen Flow' && !this.virtual) { + this.selectedActionLabel = 'Label ' + this.selectedAction.label; + + this.showFlowModal = true; + + //CREATE/NEW + } else if (this.selectedAction.className === 'ListViewActionCreate' && !this.virtual) { + let navLocation = 'DETAIL'; + + var defaultValues = {}; + if (this.isModeRelated) { + defaultValues[this.joinFieldName] = this.recordId; + navLocation = 'RELATED_LIST'; + } + + //go through the action parameters checking for field substitutions + this.selectedAction.allParameters.forEach(param => { + if (param.aPIName === 'UserField') + defaultValues[param.value] = currentUserId; + if (param.aPIName === 'NoRedirect' && param.value === 'true') + navLocation = 'RELATED_LIST'; + }); + + defaultValues = encodeDefaultFieldValues(defaultValues); + + try { + this[NavigationMixin.Navigate]({ + type: 'standard__objectPage', + attributes: { + objectApiName: this.selectedObject, + actionName: 'new', + }, + state: { + useRecordTypeCheck: 1, + defaultFieldValues: defaultValues, + navigationLocation: navLocation, + } + }).then(result => { + this.refreshAllListViewData(); + }); + } catch (e) { + console.log('EXCEPTION THROWN - ' + JSON.stringify(e)); + } + + //CLONE + } else if (this.selectedAction.className === 'ListViewActionClone' && !this.virtual) { + + if (this.selectedRecordIds.size !== 1) { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'A single row must be selected for cloning', false)); + } else { + console.log('We are cloning the following id - ' + selectedRowId + ' for ' + this.pageName); + + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + objectApiName: this.selectedObject, + actionName: 'clone', + recordId: selectedRowId, + }, + }); + this.dispatchEvent(new CustomEvent('processclick')); + } + + //EDIT + } else if (this.selectedAction.className === 'ListViewActionEdit' && !this.virtual) { + + if (this.selectedRecordIds.size !== 1) { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Error Processing Action', 'A single row must be selected for editing', false)); + } else { + + console.log('We are editing the following id - ' + selectedRowId + ' for ' + this.pageName); + + this[NavigationMixin.Navigate]({ + type: 'standard__recordPage', + attributes: { + objectApiName: this.selectedObject, + actionName: 'edit', + recordId: selectedRowId, + }, + }); + this.dispatchEvent(new CustomEvent('processclick')); + } + + //EDIT All + } else if (this.selectedAction.className === 'ListViewActionEditAll' && !this.virtual) { + + console.log('We are editing all records for ' + this.pageName); + + if (this.listViewDataRows.length > 101) { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Too Many Rows!', 'Inline editing only available for up to 100 rows', false)); + } else { + this.setAllRowsEdited(); + } + + //MASS CREATE + } else if (this.selectedAction.className === 'ListViewActionMassCreate' && !this.virtual) { + + console.log('We are mass creating records for ' + this.pageName); + if (this.selectedAction.massCreateListViewName !== undefined) + this.massCreateListView = this.selectedAction.massCreateListViewName + else + this.massCreateListView = this.selectedListView; + + this.showMassCreateModal = true; + + //EMAIL USING TEMPLATE + } else if (this.selectedAction.className === 'ListViewActionEmail' && this.selectedAction.emailTemplateFolder !== '' && this.selectedRecordIds.size > 0 && !this.virtual) { + console.log('We are creating emails from a template for ' + this.pageName); + this.showEmailTemplateModal = true; + this.emailTemplateFolder = this.selectedAction.emailTemplateFolder; + this.emailTemplateWhatIdField = this.selectedAction.emailTemplateWhatIdField; + this.spinnerOff('ListViewActionEmailTemplate'); + + //CUSTOM + } else { + + if (this.selectedAction.hasDisplayParameters) { + + this.selectedActionLabel = 'Label ' + this.selectedAction.label; // <-- This to be fixed. + + console.log('Action Label selected - ' + this.selectedActionLabel + ' for ' + this.pageName); + console.log('Action name - ' + this.selectedAction.value + ' for ' + this.pageName); + console.log('Action Record Ids - ' + this.selectedRecordIdsStr + ' for ' + this.pageName); + + this.showActionModal = true; + + } else if (this.virtual) { + this.dispatchEvent(new CustomEvent('runaction', { detail: { action: this.selectedAction } })); + this.resetActionComboBox(); + return; + } else { - if (this.selectedAction.hasDisplayParameters) { - this.selectedActionLabel = 'Label ' + this.selectedAction.label; // <-- This to be fixed. - console.log('Action Label selected - ' + this.selectedActionLabel + ' for ' + this.pageName); - console.log('Action name - ' + this.selectedAction.value + ' for ' + this.pageName); - console.log('Action Record Ids - ' + this.selectedRecordIdsStr + ' for ' + this.pageName); - this.showActionModal = true; - } else if (this.virtual) { - this.dispatchEvent(new CustomEvent('runaction', { detail: { action: this.selectedAction } })); - this.resetActionComboBox(); - return; - } else { - this.selectedActionLabel = 'Label ' + this.selectedAction.label; // <-- This to be fixed. - console.log('Action Label selected - ' + this.selectedActionLabel + ' for ' + this.pageName); - console.log('Action name - ' + this.selectedAction.value + ' for ' + this.pageName); - console.log('Action Record Ids - ' + this.selectedRecordIdsStr + ' for ' + this.pageName); - this.showActionModal = true; - } + + this.selectedActionLabel = 'Label ' + this.selectedAction.label; // <-- This to be fixed. + + console.log('Action Label selected - ' + this.selectedActionLabel + ' for ' + this.pageName); + console.log('Action name - ' + this.selectedAction.value + ' for ' + this.pageName); + console.log('Action Record Ids - ' + this.selectedRecordIdsStr + ' for ' + this.pageName); + + this.showActionModal = true; } - this.resetActionComboBox(); - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'runAction', status: 'finished', action: this.selectedActionKey, listView: this.selectedListView, object: this.selectedObject } })); - } catch (error) { - SLVHelper.showErrorMessage(error); } + + this.resetActionComboBox(); + + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'runAction', status: 'finished', action: this.selectedActionKey, listView: this.selectedListView, object: this.selectedObject } })); + } + resetActionComboBox() { this.template.querySelectorAll('lightning-combobox').forEach(combobox => { if (combobox.name === 'Action List') combobox.value = undefined; }); } + handleCancelButtonClick(event) { - try { - const { target } = event; - const { label } = target; - const action = label; - if (action === 'Cancel') { - this.outputStr = this.action; - } - } catch (error) { - SLVHelper.showErrorMessage(error); + var action = event.target.label; + if (action === 'Cancel') { + this.outputStr = this.action; } } + handleMassCreateModalClose() { this.showMassCreateModal = false; } + handleEmailTemplateModalClose() { this.showEmailTemplateModal = false; } + cancelActionModal() { this.resetActionComboBox(); this.showActionModal = false; } + processActionModal() { + this.showActionModal = false; this.selectedAction = ''; + this.refreshAllListViewData(); } + processActionModalRunAction(event) { - try { - const { detail } = event; - const { action, valuesMap } = detail; - this.showActionModal = false; - this.dispatchEvent(new CustomEvent('runaction', { detail: { action: action, valuesMap: valuesMap } })); - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.showActionModal = false; + this.dispatchEvent(new CustomEvent('runaction', { detail: { action: event.detail.action, valuesMap: event.detail.valuesMap } })); } + //ADMIN - handleAdminButtonClick() { + + handleAdminButtonClick(event) { console.log('Admin button clicked for ' + this.pageName); + this.showAdminModal = true; } + async processAdminModal(event) { - try { - const { detail } = event; - this.showAdminModal = false; - if (detail === true) { - this.refreshRate = await this.getConfigParameter('RefreshRate'); - this.singleClickAutoRefresh = await this.getConfigParameter('SingleClickAutoDataRefresh'); - this.handleComponentConfig(); - refreshApex(this.wiredListViewConfigResult); - this.refreshAllListViewData(); - } - } catch (error) { - SLVHelper.showErrorMessage(error); + this.showAdminModal = false; + + if (event.detail === true) { + this.refreshRate = await this.getConfigParameter('RefreshRate'); + this.singleClickAutoRefresh = await this.getConfigParameter('SingleClickAutoDataRefresh'); + + this.handleComponentConfig(); + + refreshApex(this.wiredListViewConfigResult); + this.refreshAllListViewData(); } } + //FLOW + cancelFlowModal() { this.resetActionComboBox(); this.showFlowModal = false; } + finishFlowModal() { + //reset the selected record Ids let selectedRows = this.template.querySelectorAll('lightning-input'); selectedRows.forEach(element => { element.checked = false; }); this.selectedRecordCount = 0; this.showFlowModal = false; + this.refreshAllListViewData(); } + //INLINE EDITING + setAllRowsEdited() { if (SLVHelper.toBool(this.allowInlineEditing) === true) { this.isEdited = true; this.listViewData.isEdited = true; - if (this.listViewDataRows?.length) { - this.listViewDataRows.forEach(element => { - if (element.isDeleted === false) { - element.isEdited = true; - } - }); - } + this.listViewDataRows.forEach(element => { + if (element.isDeleted === false) { + element.isEdited = true; + } + }); } else { this.dispatchEvent(SLVHelper.createToast('info', '', 'Editing Not Available', 'Inline editing is not available for this list view.', false)); } } + setRowEdited(event) { - try { - console.log('Row set to be edited - ' + event.target.id + ' for ' + this.pageName); - const rowId = event.target.id.split('-')[0]; - if (SLVHelper.toBool(this.allowInlineEditing) === true) { - this.isEdited = true; - this.listViewData.isEdited = true; - if (this.listViewDataRows?.length) { - this.listViewDataRows.forEach(element => { - if (element.rowId === rowId && element.isEditable) { - if (element.isDeleted === false) { - element.isEdited = true; - } else { - this.dispatchEvent(SLVHelper.createToast('warning', '', 'Warning', 'This row has already been deleted. No updates can be made.', false)); - } - } - }); + console.log('Row set to be edited - ' + event.target.id + ' for ' + this.pageName); + const rowId = event.target.id.split('-')[0]; + + if (SLVHelper.toBool(this.allowInlineEditing) === true) { + this.isEdited = true; + this.listViewData.isEdited = true; + this.listViewDataRows.forEach(element => { + if (element.rowId === rowId && element.isEditable) { + if (element.isDeleted === false) { + element.isEdited = true; + } else { + this.dispatchEvent(SLVHelper.createToast('info', '', 'Warning', 'This row has already been deleted. No updates can be made.', false)); + } } - } else { - this.dispatchEvent(SLVHelper.createToast('info', '', 'Editing Not Available', 'Inline editing is not available for this list view.', false)); - } - } catch (error) { - SLVHelper.showErrorMessage(error); + }); + } else { + this.dispatchEvent(SLVHelper.createToast('info', '', 'Editing Not Available', 'Inline editing is not available for this list view.', false)); } } + handleRowDataSave(event) { - try { - const { target } = event; - const { value } = target; - console.log('Row data saved for ' + this.pageName); - let rowId = value; - let rowData = this.updatedRowData.get(rowId); - if (rowData !== undefined) { - this.spinnerOn('handleRowDataSave'); - let rowDataStr = JSON.stringify(Array.from(rowData)); //map objects cannot be stringified - console.log('SAVE RESULT - ' + rowDataStr); - if (this.virtual) { - this.dispatchEvent(new CustomEvent('savedatarow', { detail: { rowId: rowId, rowData: rowDataStr } })); - this.spinnerOff('handleRowDataSave'); - } else { - console.log(this.pageName + ' CALLOUT - updateRecord - ' + this.calloutCount++); - updateRecord({ rowId: rowId, rowData: rowDataStr }).then(result => { + console.log('Row data saved for ' + this.pageName); + + let rowId = event.target.value; + + let rowData = this.updatedRowData.get(rowId); + + if (rowData !== undefined) { + this.spinnerOn('handleRowDataSave'); + let rowDataStr = JSON.stringify(Array.from(rowData)); //map objects cannot be stringified + console.log('SAVE RESULT - ' + rowDataStr); + + if (this.virtual) { + this.dispatchEvent(new CustomEvent('savedatarow', { detail: { rowId: rowId, rowData: rowDataStr } })); + this.spinnerOff('handleRowDataSave'); + } else { + + console.log(this.pageName + ' CALLOUT - updateRecord - ' + this.calloutCount++); + updateRecord({ rowId: rowId, rowData: rowDataStr }) + .then(result => { console.log('Record update response - ' + result); + if (result === '') { this.dispatchEvent(SLVHelper.createToast('success', '', 'Success', 'Record saved successfully.', false)); - if (this.listViewDataRows?.length) { - this.listViewDataRows.forEach(element => { - if (element.rowId === rowId) { - element.isEdited = false; - } - }); - } + + this.listViewDataRows.forEach(element => { + if (element.rowId === rowId) { + element.isEdited = false; + } + }); + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'dataSaved', status: 'finished', rowId: rowId, listView: this.selectedListView, object: this.selectedObject } })); + this.refreshAllListViewData(); } else { this.dispatchEvent(SLVHelper.createToast('error', '', 'Error', 'There was a validation exception - ' + result, false)); } - }).catch(error => { + }) + .catch(error => { this.dispatchEvent(SLVHelper.createToast('error', error, 'Error', 'Error saving the record.', true)); this.spinnerOff('handleRowDataSave'); }); - } - } else { - this.dispatchEvent(SLVHelper.createToast('warning', '', 'Warning', 'There was no updated data to save.', false)); - this.spinnerOff('handleAllRowDataSave'); } - } catch (error) { - SLVHelper.showErrorMessage(error); + } else { + this.dispatchEvent(SLVHelper.createToast('info', '', 'Warning', 'There was no updated data to save.', false)); + this.spinnerOff('handleAllRowDataSave'); } } - handleAllRowDataSave() { + + handleAllRowDataSave(event) { this.spinnerOn('handleAllRowDataSave'); let rowData = this.updatedRowData; //map of maps + if (rowData !== undefined) { if (rowData.size > 0) { let rowDataStr = '{' rowData.forEach((element, key) => { rowDataStr = rowDataStr + '"' + key + '":' + JSON.stringify(Array.from(element)) + ','; }); + rowDataStr = rowDataStr.slice(0, -1) + '}'; + console.log('SAVE RESULT - ' + rowDataStr + ' for ' + this.pageName); + if (this.virtual) { this.dispatchEvent(new CustomEvent('savedatarows', { detail: { rowData: rowDataStr } })); this.spinnerOff('handleAllRowDataSave'); } else { + console.log(this.pageName + ' CALLOUT - updateRecords - ' + this.calloutCount++); - updateRecords({ rowData: rowDataStr }).then(() => { - console.log('Save successful for ' + this.pageName); - let rowCount = 0; - if (this.updatedRowData !== undefined) { - rowCount = this.updatedRowData.size; - } - if (rowCount > 0) { - this.dispatchEvent(SLVHelper.createToast('success', '', 'Success', rowCount + ' record(s) saved successfully.', false)); - this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'dataSaved', status: 'finished', object: this.selectedObject, listView: this.selectedListView, rowCount: rowCount } })); - } - this.refreshAllListViewData(); - if (this.listViewDataRows?.length) { + updateRecords({ rowData: rowDataStr }) + .then(result => { + console.log('Save successful for ' + this.pageName); + let rowCount = 0; + if (this.updatedRowData !== undefined) { + rowCount = this.updatedRowData.size; + } + + if (rowCount > 0) { + this.dispatchEvent(SLVHelper.createToast('success', '', 'Success', rowCount + ' record(s) saved successfully.', false)); + this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: 'dataSaved', status: 'finished', object: this.selectedObject, listView: this.selectedListView, rowCount: rowCount } })); + } + + this.refreshAllListViewData(); + this.listViewDataRows.forEach(element => { element.isEdited = false; }); - } - this.updatedRowData = new Map(); - this.isEdited = false; - }).catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Error', 'Error saving the records.', true)); - this.spinnerOff('handleAllRowDataSave'); - }); + + this.updatedRowData = new Map(); + this.isEdited = false; + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Error', 'Error saving the records.', true)); + this.spinnerOff('handleAllRowDataSave'); + }); } } else { - this.dispatchEvent(SLVHelper.createToast('warning', '', 'Warning', 'There was no updated data to save.', false)); + this.dispatchEvent(SLVHelper.createToast('info', '', 'Warning', 'There was no updated data to save.', false)); this.spinnerOff('handleAllRowDataSave'); } } + } + handleRowDataReset(event) { - try { - console.log('Row data reset for ' + this.pageName); - const { target } = event; - const { value } = target; - let rowId = value; - this.updatedRowData.delete(rowId); - let editedCount = 0; - if (this.listViewDataRows?.length) { - this.listViewDataRows.forEach(element => { - if (element.rowId === rowId) { - element.isEdited = false; - } else { - if (element.isEdited === true) - editedCount++; - } - }); - } - //set form to not editing if no rows are processing. - if (editedCount === 0) { - this.isEdited = false; + console.log('Row data reset for ' + this.pageName); + + let rowId = event.target.value; + + this.updatedRowData.delete(rowId); + + let editedCount = 0; + this.listViewDataRows.forEach(element => { + if (element.rowId === rowId) { + element.isEdited = false; + } else { + if (element.isEdited === true) + editedCount++; } - } catch (error) { - SLVHelper.showErrorMessage(error); + }); + + //set form to not editing if no rows are processing. + if (editedCount === 0) { + this.isEdited = false; } + } - handleAllRowDataReset() { - if (this.listViewDataRows?.length) { - this.listViewDataRows.forEach(element => { - element.isEdited = false; - }); - } + + handleAllRowDataReset(event) { + + this.listViewDataRows.forEach(element => { + element.isEdited = false; + }); + this.isEdited = false; } + handleFieldDataChange(event) { - try { - console.log('Field changed for ' + this.pageName); - const { detail, currentTarget, target } = event; - const { value, checked } = target; - const { selectedValue, field } = detail; - const { dataset } = currentTarget; - const { type } = dataset; - //if data is coming in from a component - let fieldValue = ''; - let rowId = ''; - let fieldName = ''; - //if data is coming in from a component - if (type === undefined) { - fieldValue = selectedValue; - rowId = detail?.rowId ?? ""; - fieldName = field; - } else { - if (type === 'boolean') { - if (checked === true) { - fieldValue = 'true'; //have to turn boolean into string - } else { - fieldValue = 'false' - } - rowId = dataset?.rowId; - fieldName = dataset?.field; + console.log('Field changed for ' + this.pageName); + + //if data is coming in from a component + let fieldValue = ''; + let rowId = ''; + let fieldName = ''; + + //if data is coming in from a component + if (event.currentTarget.dataset.type === undefined) { + fieldValue = event.detail.selectedValue; + rowId = event.detail.rowId; + fieldName = event.detail.field; + + } else { + if (event.currentTarget.dataset.type === 'boolean') { + if (event.target.checked === true) { + fieldValue = 'true'; //have to turn boolean into string } else { - fieldValue = value; - rowId = dataset?.rowId; - fieldName = dataset?.field; + fieldValue = 'false' } + rowId = event.currentTarget.dataset.rowId; + fieldName = event.currentTarget.dataset.field; + } else { + fieldValue = event.target.value; + rowId = event.currentTarget.dataset.rowId; + fieldName = event.currentTarget.dataset.field; } - console.log('fieldValue - ' + fieldValue + ' for ' + this.pageName); - console.log('rowId - ' + rowId + ' for ' + this.pageName); - console.log('fieldName - ' + fieldName + ' for ' + this.pageName); - let rowData = this.updatedRowData.get(rowId); - if (rowData === undefined) { - rowData = new Map(); - this.updatedRowData.set(rowId, rowData); - } - rowData.set(fieldName, fieldValue); - } catch (error) { - SLVHelper.showErrorMessage(error); } + + console.log('fieldValue - ' + fieldValue + ' for ' + this.pageName); + console.log('rowId - ' + rowId + ' for ' + this.pageName); + console.log('fieldName - ' + fieldName + ' for ' + this.pageName); + + let rowData = this.updatedRowData.get(rowId); + + if (rowData === undefined) { + rowData = new Map(); + this.updatedRowData.set(rowId, rowData); + } + + rowData.set(fieldName, fieldValue); + } + //QUICK DATA + handleQuickDataClicked(event) { this.handleQuickDataDisplay(event); } + handleQuickDataKeyDown(event) { - try { - const { keyCode } = event; - if (keyCode === 32 || keyCode === 13) this.handleQuickDataDisplay(event); //if space or enter then quick display - } catch (error) { - SLVHelper.showErrorMessage(error); - } + var keyCode = event.keyCode; + if (keyCode === 32 || keyCode === 13) this.handleQuickDataDisplay(event); //if space or enter then quick display } + handleQuickDataDisplay(event) { - try { - const { currentTarget, target } = event; - const { value, name } = target; - const { dataset } = currentTarget; - const { rowId, type, field, object } = dataset; - this.quickDataHeading = 'Test Heading'; - this.quickDataFieldLabel = 'Field Label'; - this.quickDataRowId = rowId; - this.quickDataFieldType = type - this.quickDataFieldValue = value; - this.quickDataFieldName = field; - this.quickDataComponentId = name; - this.quickDataOldFieldValue = value; - this.quickDataObjectName = object; - this.showQuickDataModal = true; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + + this.quickDataHeading = 'Test Heading'; + this.quickDataFieldLabel = 'Field Label'; + this.quickDataRowId = event.currentTarget.dataset.rowId; + this.quickDataFieldType = event.currentTarget.dataset.type + this.quickDataFieldValue = event.target.value; + this.quickDataFieldName = event.currentTarget.dataset.field; + this.quickDataComponentId = event.target.name; + this.quickDataOldFieldValue = event.target.value; + this.quickDataObjectName = event.currentTarget.dataset.object; + this.showQuickDataModal = true; } + handleQuickDataCancelled() { this.showQuickDataModal = false; - // eslint-disable-next-line @lwc/lwc/no-async-operation setTimeout(() => this.setQuickDataComponentFocus(this.quickDataOldFieldValue), 200); } + setQuickDataComponentFocus(fieldValue) { this.template.querySelectorAll('lightning-input').forEach(element => { if (element.name === this.quickDataComponentId) { @@ -2102,124 +2459,112 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) } }); } + handleQuickDataChange(event) { - try { - const { detail } = event; - const { fieldDataId, value, fieldName } = detail; - this.showQuickDataModal = false; - let rowId = fieldDataId; - let fieldValue = value - let rowData = this.updatedRowData.get(rowId); - if (rowData === undefined) { - rowData = new Map(); - this.updatedRowData.set(rowId, rowData); - } - rowData.set(fieldName, fieldValue); - // eslint-disable-next-line @lwc/lwc/no-async-operation - setTimeout(() => this.setQuickDataComponentFocus(fieldValue), 200); - } catch (error) { - SLVHelper.showErrorMessage(error); + + this.showQuickDataModal = false; + + let rowId = event.detail.fieldDataId; + let fieldValue = event.detail.value + let fieldName = event.detail.fieldName; + + let rowData = this.updatedRowData.get(rowId); + + if (rowData === undefined) { + rowData = new Map(); + this.updatedRowData.set(rowId, rowData); } + + rowData.set(fieldName, fieldValue); + + setTimeout(() => this.setQuickDataComponentFocus(fieldValue), 200); } + + handleTextSearchChange(event) { - try { - const { target } = event; - const { value } = target; - this.textSearchText = value; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.textSearchText = event.target.value; } + handleTextSearch(event) { - try { - const { code, key, target } = event; - const keyCode = code || key; - const { value } = target; - let searchStr = value; - console.log('handleTextSearch called - ' + searchStr + ' for ' + this.pageName); - if (keyCode === 'Enter' && (searchStr.length > 2 || searchStr.length === 0)) { - //CUSTOM list views can only do CLIENT SIDE - if (this.isCustomListView === true) { - this.listViewDataRows.forEach(element => { - if (searchStr === '') { + + var keyCode = event.code || event.key; + + let searchStr = event.target.value; + console.log('handleTextSearch called - ' + searchStr + ' for ' + this.pageName); + + if (keyCode === 'Enter' && (searchStr.length > 2 || searchStr.length === 0)) { + //CUSTOM list views can only do CLIENT SIDE + if (this.isCustomListView === true) { + this.listViewDataRows.forEach(element => { + if (searchStr === '') { + element.isDisplayed = true; + } else { + if (element.dataAsCSVString.toLowerCase().includes(searchStr.toLowerCase())) { element.isDisplayed = true; } else { - if (element.dataAsCSVString.toLowerCase().includes(searchStr.toLowerCase())) { - element.isDisplayed = true; - } else { - element.isDisplayed = undefined; - } + element.isDisplayed = undefined; } - }); - //CORE list views can do SERVER SIDE - } else { - this.textSearchText = searchStr; - this.refreshAllListViewData(); - } + } + }); + + //CORE list views can do SERVER SIDE + } else { + this.textSearchText = searchStr; + this.refreshAllListViewData(); } - } catch (error) { - SLVHelper.showErrorMessage(error); } + } + setJoinCriteria(value) { if (value !== '' && value !== undefined) this.joinData = '{"recordIds":"' + value + '"}'; else this.joinData = ''; + if (!this.isInitializing && this.joinData !== '') this.refreshAllListViewData(); else this.listViewData = undefined; } + displayHoverDetails(event) { - try { - const { currentTarget, pageY, pageX } = event; - const { dataset } = currentTarget; - const { sfdcId, apiName, labelName } = dataset; - if (this.displayRecordPopovers === true) { - this.hoverSFDCId = sfdcId; - this.hoverAPIName = apiName; - this.hoverLabelName = labelName; - this.hoverIsDisplayed = true; - this.hoverPositionTop = pageY - 170; - this.hoverPositionLeft = pageX + 10; - } - } catch (error) { - SLVHelper.showErrorMessage(error); + if (this.displayRecordPopovers === true) { + this.hoverSFDCId = event.currentTarget.dataset.sfdcId; + this.hoverAPIName = event.currentTarget.dataset.apiName; + this.hoverLabelName = event.currentTarget.dataset.labelName; + this.hoverIsDisplayed = true; + this.hoverPositionTop = event.pageY - 170; + this.hoverPositionLeft = event.pageX + 10; } } - hideHoverDetails() { + + hideHoverDetails(event) { this.hoverIsDisplayed = false; } + processHoverError(event) { - try { - const { detail } = event; - this.hideHoverDetails(event); - if (!this.hoverErrorTypes.includes(detail)) { - this.hoverErrorTypes = this.hoverErrorTypes + ',' + detail; - } - } catch (error) { - SLVHelper.showErrorMessage(error); + this.hideHoverDetails(event); + if (!this.hoverErrorTypes.includes(event.detail)) { + this.hoverErrorTypes = this.hoverErrorTypes + ',' + event.detail; } } + handleSplitViewClick(event) { - try { - const { currentTarget } = event; - const { dataset } = currentTarget; - const { rowId } = dataset; - let recordId = rowId; - const message = { - type: 'selectrecordupdate', - recordIds: recordId, - objectType: this.selectedObject, - uniqueComponentId: this.uniqueComponentId - }; - publish(this.messageContext, LISTVIEW_MC, message); - } catch (error) { - SLVHelper.showErrorMessage(error); - } + let recordId = event.currentTarget.dataset.rowId; + + const message = { + type: 'selectrecordupdate', + recordIds: recordId, + objectType: this.selectedObject, + uniqueComponentId: this.uniqueComponentId + }; + publish(this.messageContext, LISTVIEW_MC, message); + } + handleEvent(type, requestData) { + try { if (type === 'refreshActions') this.getListViewActions(); @@ -2262,9 +2607,11 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) console.log('Error in handleEvent: ' + error.message); this.dispatchEvent(new CustomEvent('eventresponse', { detail: { type: type, response: 'failed', error: error.message } })); } + console.log('Event response posted (' + this.eventCount + ')'); this.eventCount++; } + handleUpdateSettingEvent(name, value) { switch (name) { case 'hasMainTitle': this.hasMainTitle = SLVHelper.toBool(value); break; @@ -2287,4 +2634,5 @@ export default class simpliUIListViews extends NavigationMixin(LightningElement) default: break; } } + } \ No newline at end of file diff --git a/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/SimpliUIListViewsActionCreateWizardModal.css b/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/SimpliUIListViewsActionCreateWizardModal.css index b1c920d..7accac6 100644 --- a/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/SimpliUIListViewsActionCreateWizardModal.css +++ b/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/SimpliUIListViewsActionCreateWizardModal.css @@ -2,6 +2,6 @@ overflow: auto; } -.pageSpinnerHolder { +.pageSpinnerHolder{ position: absolute; -} +} \ No newline at end of file diff --git a/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/simpliUIListViewsActionCreateWizardModal.js b/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/simpliUIListViewsActionCreateWizardModal.js index 436c90d..7f95150 100644 --- a/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/simpliUIListViewsActionCreateWizardModal.js +++ b/force-app/main/default/lwc/simpliUIListViewsActionCreateWizardModal/simpliUIListViewsActionCreateWizardModal.js @@ -1,5 +1,4 @@ -/* eslint-disable no-console */ -import { LightningElement, track, api } from 'lwc'; +import { LightningElement, track, api } from 'lwc'; import * as SLVHelper from 'c/simpliUIListViewsHelper'; //------------------------ LABELS ------------------------ @@ -55,50 +54,50 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE get isStepTwo() { return this.currentStep === "2"; } get isStepThree() { return this.currentStep === "3"; } get isStepFour() { return this.currentStep === "4"; } - get isEnableNext() { return this.currentStep !== "4"; } - get isEnablePrev() { return this.currentStep !== "1"; } + get isEnableNext() { return this.currentStep != "4"; } + get isEnablePrev() { return this.currentStep != "1"; } get isEnableSave() { return this.currentStep === "4"; } - get strIsActive() { return this.booleanToYesNo(this.selectedActionIsActive); } - get strActionHasObject() { return this.booleanToYesNo(this.selectedActionHasObject); } - get strSpecificToLtn() { return this.booleanToYesNo(this.selectedActionHasComponent); } + get strIsActive() { return this.booleanToYesNo(this.selectedActionIsActive);} + get strActionHasObject() { return this.booleanToYesNo(this.selectedActionHasObject);} + get strSpecificToLtn() { return this.booleanToYesNo(this.selectedActionHasComponent);} booleanToYesNo(value) { if (value === 'true') return 'Yes'; - return 'No'; + else return 'No'; } get actionRecordTypes() { return [ { label: 'Core', value: 'Core' }, { label: 'Custom', value: 'Custom' }, - ]; + ]; } get booleanList() { return [ - { label: 'Yes', value: 'true' }, - { label: 'No', value: 'false' }, + { label: 'Yes', value: 'true'}, + { label: 'No', value: 'false'}, ]; } get userPermissionsList() { return [ - { label: 'Read', value: 'Read' }, - { label: 'Create', value: 'Create' }, - { label: 'Edit', value: 'Edit' }, - { label: 'Delete', value: 'Delete' }, + { label: 'Read', value: 'Read'}, + { label: 'Create', value: 'Create'}, + { label: 'Edit', value: 'Edit'}, + { label: 'Delete', value: 'Delete'}, ]; } get recVisibleList() { return [ - { label: 'Always Displayed', value: 'Always Displayed' }, - { label: 'Displayed if multiple records are selected', value: 'Displayed if multiple records are selected' }, - { label: 'Displayed if no records are selected', value: 'Displayed if no records are selected' }, - { label: 'Displayed if one or more records are selected', value: 'Displayed if one or more records are selected' }, - { label: 'Displayed if one record is selected', value: 'Displayed if one record is selected' }, - { label: 'Displayed if zero or one record is selected', value: 'Displayed if zero or one record is selected' }, + { label: 'Always Displayed', value: 'Always Displayed'}, + { label: 'Displayed if multiple records are selected', value: 'Displayed if multiple records are selected'}, + { label: 'Displayed if no records are selected', value: 'Displayed if no records are selected'}, + { label: 'Displayed if one or more records are selected', value: 'Displayed if one or more records are selected'}, + { label: 'Displayed if one record is selected', value: 'Displayed if one record is selected'}, + { label: 'Displayed if zero or one record is selected', value: 'Displayed if zero or one record is selected'}, ]; } @@ -144,7 +143,7 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE } get massUpdateRowIndexes() { - return [2, 3, 4, 5, 6, 7, 8]; + return [2,3,4,5,6,7,8]; } label = { Close }; @@ -155,35 +154,36 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE } renderedCallback() { - if (this.showModal === true && this.inRenderedCallback === false) { + if (this.showModal === true && this.inRenderedCallback === false) + { this.inRenderedCallback = true; } } - + //----------------------------------------------------------------------------- // HANDLERS FOR MOVEMENT TO EACH STAGE //----------------------------------------------------------------------------- - handleNext() { - if (this.currentStep === "1") { + handleNext(){ + if(this.currentStep === "1"){ if (this.validateStepOne()) this.handleGoToStepTwo(); - } else if (this.currentStep === "2") { + } else if(this.currentStep === "2"){ if (this.validateStepTwo()) this.handleGoToStepThree(); - } else if (this.currentStep === "3") { + } else if(this.currentStep === "3"){ if (this.validateStepThree()) this.handleGoToStepFour(); } console.log('Moved current step to - ' + this.currentStep); } - handlePrev() { - if (this.currentStep === "4") + handlePrev(){ + if(this.currentStep === "4") this.handleGoToStepThree(); - else if (this.currentStep === "3") + else if(this.currentStep === "3") this.handleGoToStepTwo(); - else if (this.currentStep === "2") + else if(this.currentStep === "2") this.handleGoToStepOne(); } @@ -191,19 +191,22 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE this.currentStep = "1"; this.headerLabel = 'Basic Action Details'; } - + validateStepOne() { + if (this.selectedActionRecordType === '' || this.selectedActionType === '' || this.selectedActionLabel === '' - || this.selectedActionIsActive === '') { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); + || this.selectedActionIsActive === '') + { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); return false; } - if (this.selectedActionType === 'ManageData' && this.selectedActionSubType === '') { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); - return false; + if (this.selectedActionType === 'ManageData' && this.selectedActionSubType === '') + { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); + return false; } return true; @@ -220,24 +223,28 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE } validateStepTwo() { - if ((this.selectedActionType === 'Hyperlink' && this.actionParams.get('hyperlinkURL') === undefined) - || (this.selectedActionType === 'EmailTemplate' && this.actionParams.get('sendEmailTemplateFolderName') === undefined) - || (this.selectedActionType === 'LaunchFlow' && this.actionParams.get('launchFlowAPIName') === undefined) - || (this.selectedActionType === 'ScreenFlow' && this.actionParams.get('screenFlowAPIName') === undefined) - || (this.selectedActionType === 'Custom' && this.actionParams.get('customApexClassName') === undefined) - ) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); + + if ( (this.selectedActionType === 'Hyperlink' && this.actionParams.get('hyperlinkURL') === undefined) + || (this.selectedActionType === 'EmailTemplate' && this.actionParams.get('sendEmailTemplateFolderName') === undefined) + || (this.selectedActionType === 'LaunchFlow' && this.actionParams.get('launchFlowAPIName') === undefined) + || (this.selectedActionType === 'ScreenFlow' && this.actionParams.get('screenFlowAPIName') === undefined) + || (this.selectedActionType === 'Custom' && this.actionParams.get('customApexClassName') === undefined) + ) + { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); return false; } + return true; } - + handleGoToStepThree() { this.currentStep = "3"; this.headerLabel = 'Accessibility'; - if (this.selectedActionRecordType === 'Custom') { + if (this.selectedActionRecordType === 'Custom') + { this.selectedActionHasObject = 'true'; this.actionHasObject = true; this.selectedActionHasObjectDisabled = true; @@ -247,25 +254,28 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE } validateStepThree() { + if (this.selectedActionHasObject === '' || this.selectedActionHasComponent === '' - || this.selectedActionRecordVisible === '') { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); + || this.selectedActionRecordVisible === '') + { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); return false; } - if ((this.selectedActionHasObject === 'true' && this.selectedActionObjectType === '') - || (this.selectedActionHasComponent === 'true' && this.selectedActionComponentName === '')) { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); - return false; + if ( (this.selectedActionHasObject === 'true' && this.selectedActionObjectType === '') + || (this.selectedActionHasComponent === 'true' && this.selectedActionComponentName === '') ) + { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Required Field Missing', 'A required field is missing', false)); + return false; } return true; } - + handleGoToStepFour() { this.currentStep = "4"; - this.headerLabel = 'Review And Save'; + this.headerLabel = 'Review And Save';; this.actionParams.set('actionHasObject', this.selectedActionHasObject); this.actionParams.set('actionObjectType', this.selectedActionObjectType); this.actionParams.set('actionHasComponent', this.selectedActionHasComponent); @@ -273,28 +283,30 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE this.actionParams.set('actionRecordVisible', this.selectedActionRecordVisible); this.actionParams.set('actionUserPermissions', this.selectedActionUserPermissions); } - - handleSave() { + + handleSave(){ let params = JSON.stringify(Array.from(this.actionParams)); this.spinnerOn(); console.log('All params - ' + params); console.log(this.pageName + ' CALLOUT - createAction - ' + this.calloutCount++); - createAction({ actionFields: params }) - .then(result => { - console.log('RESULT - ' + result); - if (result === 'success') { - this.clearData(); - this.dispatchEvent(new CustomEvent('finished')); - this.dispatchEvent(SLVHelper.createToast('success', '', 'Action Created', 'Action successfully created.', false)); - } else { - this.dispatchEvent(SLVHelper.createToast('error', '', 'Action Create Error', 'There was a problem creating the action - ' + result, false)); - } - }) - .catch(error => { - this.dispatchEvent(SLVHelper.createToast('error', error, 'Action Create Error', 'There was a problem creating the action.', true)); - }).finally(() => { + createAction({actionFields: params }) + .then(result => { + console.log('RESULT - ' + result); + if (result === 'success') + { + this.clearData(); + this.dispatchEvent(new CustomEvent('finished')); + this.dispatchEvent(SLVHelper.createToast('success', '', 'Action Created', 'Action successfully created.', false)); this.spinnerOff(); - }); + } else { + this.dispatchEvent(SLVHelper.createToast('error', '', 'Action Create Error', 'There was a problem creating the action - ' + result, false)); + this.spinnerOff(); + } + }) + .catch(error => { + this.dispatchEvent(SLVHelper.createToast('error', error, 'Action Create Error', 'There was a problem creating the action.', true)); + this.spinnerOff(); + }); } handleCancelClick() { @@ -310,164 +322,111 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE //----------------------------------------------------------------------------- // HANDLERS FOR EACH FIELD UPDATE //----------------------------------------------------------------------------- - + handleActionRecordTypeSelected(event) { - try { - const { target } = event; - this.selectedActionRecordType = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionRecordType = event.target.value; } handleActionIsActiveSelected(event) { - try { - const { target } = event; - this.selectedActionIsActive = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionIsActive = event.target.value; } handleActionLabelSelected(event) { - try { - const { target } = event; - this.selectedActionLabel = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionLabel = event.target.value; } handleActionTypeSelected(event) { - try { - const { target } = event; - this.selectedActionType = target?.value ?? ''; - this.hasActionType = true; + this.selectedActionType = event.target.value; + this.hasActionType = true; - if (this.selectedActionType === 'ManageData') - this.showSubType = true; - else - this.showSubType = false; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + if (this.selectedActionType === 'ManageData') + this.showSubType = true; + else + this.showSubType = false; } handleActionSubTypeSelected(event) { - try { - const { target } = event; - this.selectedActionSubType = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionSubType = event.target.value; } handleActionHasObjectSelected(event) { - try { - const { target } = event; - this.selectedActionHasObject = target?.value ?? ''; - if (this.selectedActionHasObject === 'true') - this.actionHasObject = true; - else - this.actionHasObject = false; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionHasObject = event.target.value; + if (this.selectedActionHasObject === 'true') + this.actionHasObject = true; + else + this.actionHasObject = false; } handleActionObjectTypeSelected(event) { - try { - const { target } = event; - this.selectedActionObjectType = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionObjectType = event.target.value; } handleActionRecordVisibleSelected(event) { - try { - const { target } = event; - this.selectedActionRecordVisible = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionRecordVisible = event.target.value; } handleActionHasComponentSelected(event) { - try { - const { target } = event; - this.selectedActionHasComponent = target?.value ?? ''; - if (this.selectedActionHasComponent === 'true') - this.actionHasComponent = true; - else - this.actionHasComponent = false; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionHasComponent = event.target.value; + if (this.selectedActionHasComponent === 'true') + this.actionHasComponent = true; + else + this.actionHasComponent = false; } handleActionComponentNameSelected(event) { - try { - const { target } = event; - this.selectedActionComponentName = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionComponentName = event.target.value; + + } + + handleActionRecordVisibleSelected(event) { + this.selectedActionRecordVisible = event.target.value; } handleActionUserPermissionsSelected(event) { - try { - const { target } = event; - this.selectedActionUserPermissions = target?.value ?? ''; - } catch (error) { - SLVHelper.showErrorMessage(error); - } + this.selectedActionUserPermissions = event.target.value; } - - + + handleActionParameterAdded(event) { - try { - const { currentTarget, detail, target } = event; - if (currentTarget?.dataset?.paramName === undefined) { - let fieldValue = detail?.selectedValue ?? ''; - let rowId = detail?.rowId ?? ''; - let paramName = detail?.field ?? ''; - if (paramName === 'simpli_lv__Type__c') //this field uses picklist widget so data comes in differently - paramName = 'manageDataMassUpdateType' + rowId; - else - paramName = paramName + rowId; - this.actionParams.set(paramName, fieldValue); - console.log('Action param name/value - ' + paramName + '/' + fieldValue); + if (event.currentTarget.dataset.paramName === undefined) + { + let fieldValue = event.detail.selectedValue; + let rowId = event.detail.rowId; + let paramName = event.detail.field; + if (paramName === 'simpli_lv__Type__c') //this field uses picklist widget so data comes in differently + paramName = 'manageDataMassUpdateType' + rowId; + else + paramName = paramName + rowId; + + this.actionParams.set(paramName, fieldValue); + console.log('Action param name/value - ' + paramName + '/' + fieldValue); - } else { - let paramName = currentTarget?.dataset?.paramName ?? ''; - let fieldValue = target?.value ?? ''; - if (paramName === 'manageDataCreateRedirectField') //this field is a boolean so is handled differently - { - if (target?.checked === true) - fieldValue = 'true'; - else - fieldValue = 'false'; - } - if (currentTarget.dataset.paramRowIndex !== undefined) - paramName = paramName + currentTarget.dataset.paramRowIndex; - this.actionParams.set(paramName, fieldValue); - console.log('Action param name/value - ' + paramName + '/' + fieldValue); + } else { + let paramName = event.currentTarget.dataset.paramName; + let fieldValue = event.target.value; + if (paramName === 'manageDataCreateRedirectField') //this field is a boolean so is handled differently + { + if (event.target.checked === true) + fieldValue = 'true'; + else + fieldValue = 'false'; } - } catch (error) { - SLVHelper.showErrorMessage(error); + if (event.currentTarget.dataset.paramRowIndex !== undefined) + paramName = paramName + event.currentTarget.dataset.paramRowIndex; + this.actionParams.set(paramName, fieldValue); + console.log('Action param name/value - ' + paramName + '/' + fieldValue); } } //----------------------------------------------------------------------------- // HELPER METHODS //----------------------------------------------------------------------------- - + clearData() { this.currentStep = '1'; this.headerLabel = 'Basic Action Details'; - + this.selectedActionRecordType = ''; this.selectedActionHasObject = ''; this.selectedActionType = ''; @@ -495,4 +454,6 @@ export default class SimpliUIListViewsActionCreateWizardModal extends LightningE this.spinner = false; console.log('Spinner OFF for SimpliUIListViewsActionCreateWizardModal'); } + + } \ No newline at end of file diff --git a/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.css b/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.css index 09f307a..e2bf689 100644 --- a/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.css +++ b/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.css @@ -2,6 +2,6 @@ position: relative; } -.pageSpinnerHolder { +.pageSpinnerHolder{ position: relative; -} +} \ No newline at end of file diff --git a/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.html b/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.html index 6b89754..7e09114 100644 --- a/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.html +++ b/force-app/main/default/lwc/simpliUIListViewsActionModal/simpliUIListViewsActionModal.html @@ -50,7 +50,7 @@