diff --git a/examples/webpack-demo-vanilla-bundle/src/examples/example12.ts b/examples/webpack-demo-vanilla-bundle/src/examples/example12.ts
index c7fa25ee0..7dd228df1 100644
--- a/examples/webpack-demo-vanilla-bundle/src/examples/example12.ts
+++ b/examples/webpack-demo-vanilla-bundle/src/examples/example12.ts
@@ -141,7 +141,7 @@ export class Example12 {
initializeGrid() {
this.columnDefinitions = [
{
- id: 'title', name: 'Title', field: 'title', sortable: true, type: FieldType.string, minWidth: 75,
+ id: 'title', name: ' Title', field: 'title', sortable: true, type: FieldType.string, minWidth: 75,
filterable: true, columnGroup: 'Common Factor',
filter: { model: Filters.compoundInputText },
formatter: Formatters.multiple, params: { formatters: [Formatters.uppercase, Formatters.bold] },
@@ -943,29 +943,39 @@ export class Example12 {
// backdrop: null,
// viewColumnLayout: 2, // responsive layout, choose from 'auto', 1, 2, or 3 (defaults to 'auto')
showFormResetButton: true,
+
+ // you can validate each row item dataContext before apply Mass Update/Selection changes via this validation callback (returning false would skip the change)
+ // validateMassUpdateChange: (fieldName, dataContext, formValues) => {
+ // const levelComplex = this.complexityLevelList.find(level => level.label === 'Complex');
+ // if (fieldName === 'duration' && (dataContext.complexity === levelComplex?.value || formValues.complexity === levelComplex?.value) && formValues.duration < 5) {
+ // // not good, do not apply the change because when it's "Complex", we assume the user has to be choose at least 5 days of work (duration)
+ // return false;
+ // }
+ // return true;
+ // },
+
// showResetButtonOnEachEditor: true,
onClose: () => Promise.resolve(confirm('You have unsaved changes, are you sure you want to close this window?')),
onError: (error) => alert(error.message),
- onSave: (formValues, _selection, dataContext) => {
+ onSave: (formValues, _selection, dataContextOrUpdatedDatasetPreview) => {
const serverResponseDelay = 50;
- // simulate a backend server call which will reject if the "% Complete" is below 50%
// when processing a mass update or mass selection
if (modalType === 'mass-update' || modalType === 'mass-selection') {
+ console.log(`${modalType} dataset preview`, dataContextOrUpdatedDatasetPreview);
+
+ // simulate a backend server call which will reject if the "% Complete" is below 50%
return new Promise((resolve, reject) => {
- setTimeout(() => {
- if (formValues.percentComplete >= 50) {
- resolve(true);
- } else {
- reject('Unfortunately we only accept a minimum of 50% Completion...');
- }
- }, serverResponseDelay);
+ setTimeout(
+ () => (formValues.percentComplete >= 50) ? resolve(true) : reject('Unfortunately we only accept a minimum of 50% Completion...'),
+ serverResponseDelay
+ );
});
} else {
// also simulate a server cal for any other modal type (create/clone/edit)
// we'll just apply the change without any rejection from the server and
// note that we also have access to the "dataContext" which is only available for these modal
- console.log(`${modalType} item data context`, dataContext);
+ console.log(`${modalType} item data context`, dataContextOrUpdatedDatasetPreview);
return new Promise(resolve => setTimeout(() => resolve(true), serverResponseDelay));
}
}
diff --git a/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts b/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts
index 4bcbb7d0f..e33ec7866 100644
--- a/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts
+++ b/packages/common/src/interfaces/compositeEditorOpenDetailOption.interface.ts
@@ -65,6 +65,13 @@ export interface CompositeEditorOpenDetailOption {
/** Optionally provide a CSS class by the form reset button */
resetFormButtonIconCssClass?: string;
+ /**
+ * Defaults to false, do we want to provide a preview of what the dataset with the applied Mass changes (works for both Mass Update and/or Mass Selection)?
+ * If set to true, then it would provide a 4th argument to the `onSave` callback even before sending the data to the server.
+ * This could be useful to actually use this dataset preview to send directly to the backend server.
+ */
+ shouldPreviewMassChangeDataset?: boolean;
+
/** Defaults to true, do we want the close button outside the modal (true) or inside the header modal (false)? */
showCloseButtonOutside?: boolean;
@@ -84,6 +91,10 @@ export interface CompositeEditorOpenDetailOption {
*/
viewColumnLayout?: 1 | 2 | 3 | 'auto';
+ // ---------
+ // Methods
+ // ---------
+
/** onBeforeOpen callback allows the user to optionally execute something before opening the modal (for example cancel any batch edits, or change/reset some validations in column definitions) */
onBeforeOpen?: () => void;
@@ -107,7 +118,23 @@ export interface CompositeEditorOpenDetailOption {
/** current selection of row indexes & data context Ids */
selection: CompositeEditorSelection,
- /** optional item data context that is returned, this is only provided when the modal type is (clone, create or edit) */
- dataContext?: any
+ /**
+ * optional item data context when the modal type is (clone, create or edit)
+ * OR a preview of the updated dataset when modal type is (mass-update or mass-selection).
+ * NOTE: the later requires `shouldPreviewMassChangeDataset` to be enabled since it could be resource heavy with large dataset.
+ */
+ dataContextOrUpdatedDatasetPreview?: any | any[],
) => Promise;
+
+ /**
+ * Optional callback that the user can add before applying the change to all item rows,
+ * if this callback returns False then the change will NOT be applied to the given field,
+ * or if on the other end it returns True or `undefined` then it assumes that it is valid and it should apply the change to the item dataContext.
+ * This callback works for both Mass Selection & Mass Update.
+ * @param {String} fieldName - field property name being validated
+ * @param {*} dataContext - item object data context
+ * @param {*} formValues - all form input and values that were changed
+ * @returns {Boolean} - returning False means we can't apply the change, else we go ahead and apply the change
+ */
+ validateMassUpdateChange?: (fieldName: string, dataContext: any, formValues: any) => boolean;
}
diff --git a/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts b/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts
index 4f4064703..6280f8bb4 100644
--- a/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts
+++ b/packages/composite-editor-component/src/slick-composite-editor.component.spec.ts
@@ -1,3 +1,4 @@
+import 'jest-extended';
import {
Column,
CompositeEditorOpenDetailOption,
@@ -336,7 +337,8 @@ describe('CompositeEditorService', () => {
expect(compositeContainerElm).toBeFalsy();
});
- it('should make sure Slick-Composite-Editor is being created and rendered with 1 column layout', () => {
+ it('should make sure Slick-Composite-Editor is being created and rendered with 1 column layout & also expect column name html to be rendered as well', () => {
+ columnsMock[2].name = ' Field 3'; // add tooltip
const mockProduct = { id: 222, address: { zip: 123456 }, productName: 'Product ABC', price: 12.55 };
jest.spyOn(gridStub, 'getDataItem').mockReturnValue(mockProduct);
@@ -361,7 +363,7 @@ describe('CompositeEditorService', () => {
expect(compositeContainerElm).toBeTruthy();
expect(compositeHeaderElm).toBeTruthy();
expect(productNameLabelElm.textContent).toBe('Product'); // regular, without column group
- expect(field3LabelElm.textContent).toBe('Group Name - Field 3'); // with column group
+ expect(field3LabelElm.innerHTML).toBe('Group Name - Field 3'); // with column group
expect(compositeTitleElm).toBeTruthy();
expect(compositeTitleElm.textContent).toBe('Details');
expect(compositeBodyElm).toBeTruthy();
@@ -369,6 +371,9 @@ describe('CompositeEditorService', () => {
expect(compositeFooterCancelBtnElm).toBeTruthy();
expect(compositeFooterSaveBtnElm).toBeTruthy();
expect(productNameDetailContainerElm).toBeTruthy();
+
+ // reset Field 3 column name
+ columnsMock[2].name = 'Field 3';
});
it('should make sure Slick-Composite-Editor is being created and expect form inputs to be in specific order when user provides column def "compositeEditorFormOrder"', () => {
@@ -546,7 +551,7 @@ describe('CompositeEditorService', () => {
});
it('should execute "onClose" callback when user confirms the closing of the modal when "onClose" callback is defined', (done) => {
- const mockProduct = { id: 222, address: { zip: 123456 }, productName: 'Product ABC', price: 12.55 };
+ const mockProduct = { id: 222, address: { zip: 123456 }, productName: 'Product ABC', price: 12.55, field2: 'Test' };
jest.spyOn(gridStub, 'getDataItem').mockReturnValue(mockProduct);
const getEditSpy = jest.spyOn(gridStub, 'getEditController');
const cancelSpy = jest.spyOn(gridStub.getEditController(), 'cancelCurrentEdit');
@@ -1183,6 +1188,11 @@ describe('CompositeEditorService', () => {
});
describe('Form Logics', () => {
+ beforeEach(() => {
+ // reset Field 3 column name
+ columnsMock[2].name = 'Field 3';
+ });
+
it('should make sure Slick-Composite-Editor is being created and then call "changeFormInputValue" to change dynamically any of the form input value', () => {
const mockEditor = { setValue: jest.fn(), disable: jest.fn(), } as unknown as Editor;
const mockProduct = { id: 222, address: { zip: 123456 }, productName: 'Product ABC', price: 12.55 };
@@ -1782,6 +1792,64 @@ describe('CompositeEditorService', () => {
});
});
+ it('should handle saving and expect a dataset preview of the change when "shouldPreviewMassChangeDataset" is enabled and grid changes when "Mass Update" save button is clicked and user provides a custom "onSave" async function', (done) => {
+ const mockProduct1 = { id: 222, field3: 'something', address: { zip: 123456 }, product: { name: 'Product ABC', price: 12.55 } };
+ const mockProduct2 = { id: 333, field3: 'else', address: { zip: 789123 }, product: { name: 'Product XYZ', price: 33.44 } };
+ const currentEditorMock = { validate: jest.fn() };
+ jest.spyOn(dataViewStub, 'getItems').mockReturnValue([mockProduct1, mockProduct2]);
+ jest.spyOn(gridStub, 'getCellEditor').mockReturnValue(currentEditorMock as any);
+ jest.spyOn(currentEditorMock, 'validate').mockReturnValue({ valid: true, msg: null });
+ jest.spyOn(gridStateServiceStub, 'getCurrentRowSelections').mockReturnValue({ gridRowIndexes: [0], dataContextIds: [222] });
+ const getEditSpy = jest.spyOn(gridStub, 'getEditController');
+ const cancelCommitSpy = jest.spyOn(gridStub.getEditController(), 'cancelCurrentEdit');
+ const setActiveCellSpy = jest.spyOn(gridStub, 'setActiveCell');
+ const clearSelectionSpy = jest.spyOn(gridStub, 'setSelectedRows');
+ const setItemsSpy = jest.spyOn(dataViewStub, 'setItems');
+
+ const mockOnSave = jest.fn();
+ mockOnSave.mockResolvedValue(Promise.resolve(true));
+ const mockModalOptions = { headerTitle: 'Details', modalType: 'mass-update', onSave: mockOnSave, shouldClearRowSelectionAfterMassAction: false, shouldPreviewMassChangeDataset: true } as CompositeEditorOpenDetailOption;
+ component = new SlickCompositeEditorComponent();
+ component.init(gridStub, container);
+ component.openDetails(mockModalOptions);
+
+ const compositeContainerElm = document.querySelector('div.slick-editor-modal.slickgrid_123456') as HTMLSelectElement;
+ const compositeFooterSaveBtnElm = compositeContainerElm.querySelector('.btn-save') as HTMLSelectElement;
+ const compositeHeaderElm = document.querySelector('.slick-editor-modal-header') as HTMLSelectElement;
+ const compositeTitleElm = compositeHeaderElm.querySelector('.slick-editor-modal-title') as HTMLSelectElement;
+ const compositeBodyElm = document.querySelector('.slick-editor-modal-body') as HTMLSelectElement;
+ const field3DetailContainerElm = compositeBodyElm.querySelector('.item-details-container.editor-field3.slick-col-medium-12') as HTMLSelectElement;
+ const field3LabelElm = field3DetailContainerElm.querySelector('.item-details-label.editor-field3') as HTMLSelectElement;
+ const validationSummaryElm = compositeContainerElm.querySelector('.validation-summary') as HTMLSelectElement;
+
+ gridStub.onCompositeEditorChange.notify({ row: 0, cell: 0, column: columnsMock[0], item: mockProduct1, formValues: { field3: 'test' }, editors: {}, grid: gridStub });
+
+ compositeFooterSaveBtnElm.click();
+
+ setTimeout(() => {
+ expect(component).toBeTruthy();
+ expect(component.constructor).toBeDefined();
+ expect(compositeContainerElm).toBeTruthy();
+ expect(compositeHeaderElm).toBeTruthy();
+ expect(compositeTitleElm).toBeTruthy();
+ expect(compositeTitleElm.textContent).toBe('Details');
+ expect(field3LabelElm.textContent).toBe('Group Name - Field 3');
+ expect(getEditSpy).toHaveBeenCalledTimes(2);
+ expect(mockOnSave).toHaveBeenCalledWith(
+ { field3: 'test' },
+ { gridRowIndexes: [0], dataContextIds: [222] },
+ [{ address: { zip: 123456 }, field3: 'test', id: 222, product: { name: 'Product ABC', price: 12.55 } }, { address: { zip: 789123 }, field3: 'test', id: 333, product: { name: 'Product XYZ', price: 33.44 } }]
+ );
+ expect(setItemsSpy).toHaveBeenCalled();
+ expect(cancelCommitSpy).toHaveBeenCalled();
+ expect(setActiveCellSpy).toHaveBeenCalledWith(0, 0, false);
+ expect(validationSummaryElm.style.display).toBe('none');
+ expect(validationSummaryElm.textContent).toBe('');
+ expect(clearSelectionSpy).not.toHaveBeenCalled(); // shouldClearRowSelectionAfterMassAction is false
+ done();
+ });
+ });
+
it('should show a validation summary when clicking "Mass Update" save button and the custom "onSave" async function throws an error', (done) => {
const mockProduct1 = { id: 222, field3: 'something', address: { zip: 123456 }, product: { name: 'Product ABC', price: 12.55 } };
const mockProduct2 = { id: 333, field3: 'else', address: { zip: 789123 }, product: { name: 'Product XYZ', price: 33.44 } };
diff --git a/packages/composite-editor-component/src/slick-composite-editor.component.ts b/packages/composite-editor-component/src/slick-composite-editor.component.ts
index a31975555..86a0d114e 100644
--- a/packages/composite-editor-component/src/slick-composite-editor.component.ts
+++ b/packages/composite-editor-component/src/slick-composite-editor.component.ts
@@ -44,8 +44,14 @@ const DEFAULT_ON_ERROR = (error: OnErrorOption) => console.log(error.message);
type ApplyChangesCallbackFn = (
formValues: { [columnId: string]: any; } | null,
- selection: { gridRowIndexes: number[]; dataContextIds: Array; }
-) => void;
+ selection: { gridRowIndexes: number[]; dataContextIds: Array; },
+ applyToDataview?: boolean,
+) => any[] | void | undefined;
+
+type DataSelection = {
+ gridRowIndexes: number[];
+ dataContextIds: Array;
+};
export class SlickCompositeEditorComponent implements ExternalResource {
protected _bindEventService: BindingEventService;
@@ -454,7 +460,7 @@ export class SlickCompositeEditorComponent implements ExternalResource {
const templateItemLabelElm = createDomElement('div', {
className: `item-details-label editor-${columnDef.id}`,
- textContent: this.getColumnLabel(columnDef) || 'n/a'
+ innerHTML: sanitizeTextByAvailableSanitizer(this.gridOptions, this.getColumnLabel(columnDef) || 'n/a')
});
const templateItemEditorElm = createDomElement('div', {
className: 'item-details-editor-container slick-cell',
@@ -565,15 +571,16 @@ export class SlickCompositeEditorComponent implements ExternalResource {
// ----------------
/** Apply Mass Update Changes (form values) to the entire dataset */
- protected applySaveMassUpdateChanges(formValues: any) {
- const data = this.dataView.getItems();
+ protected applySaveMassUpdateChanges(formValues: any, _selection: DataSelection, applyToDataview = true): any[] {
+ // not applying to dataView means that we're doing a preview of dataset and we should use a deep copy of it instead of applying changes directly to it
+ const data = applyToDataview ? this.dataView.getItems() : deepCopy(this.dataView.getItems());
// from the "lastCompositeEditor" object that we kept as reference, it contains all the changes inside the "formValues" property
// we can loop through these changes and apply them on the selected row indexes
for (const itemProp in formValues) {
if (itemProp in formValues) {
- data.forEach(dataContext => {
- if (itemProp in formValues) {
+ data.forEach((dataContext: any) => {
+ if (itemProp in formValues && (this._options?.validateMassUpdateChange === undefined || this._options.validateMassUpdateChange(itemProp, dataContext, formValues) !== false)) {
dataContext[itemProp] = formValues[itemProp];
}
});
@@ -581,21 +588,27 @@ export class SlickCompositeEditorComponent implements ExternalResource {
}
// change the entire dataset with our updated dataset
- this.dataView.setItems(data, this.gridOptions.datasetIdPropertyName);
- this.grid.invalidate();
+ if (applyToDataview) {
+ this.dataView.setItems(data, this.gridOptions.datasetIdPropertyName);
+ this.grid.invalidate();
+ }
+ return data;
}
/** Apply Mass Changes to the Selected rows in the grid (form values) */
- protected applySaveMassSelectionChanges(formValues: any, selection: { gridRowIndexes: number[]; dataContextIds: Array; }) {
+ protected applySaveMassSelectionChanges(formValues: any, selection: DataSelection, applyToDataview = true): any[] {
const selectedItemIds = selection?.dataContextIds ?? [];
- const selectedItems = selectedItemIds.map(itemId => this.dataView.getItemById(itemId));
+ const selectedTmpItems = selectedItemIds.map(itemId => this.dataView.getItemById(itemId));
+
+ // not applying to dataView means that we're doing a preview of dataset and we should use a deep copy of it instead of applying changes directly to it
+ const selectedItems = applyToDataview ? selectedTmpItems : deepCopy(selectedTmpItems);
// from the "lastCompositeEditor" object that we kept as reference, it contains all the changes inside the "formValues" property
// we can loop through these changes and apply them on the selected row indexes
for (const itemProp in formValues) {
if (itemProp in formValues) {
- selectedItems.forEach(dataContext => {
- if (itemProp in formValues) {
+ selectedItems.forEach((dataContext: any) => {
+ if (itemProp in formValues && (this._options?.validateMassUpdateChange === undefined || this._options.validateMassUpdateChange(itemProp, dataContext, formValues) !== false)) {
dataContext[itemProp] = formValues[itemProp];
}
});
@@ -603,7 +616,10 @@ export class SlickCompositeEditorComponent implements ExternalResource {
}
// update all items in the grid with the grid service
- this.gridService?.updateItems(selectedItems);
+ if (applyToDataview) {
+ this.gridService?.updateItems(selectedItems);
+ }
+ return selectedItems;
}
/**
@@ -675,7 +691,7 @@ export class SlickCompositeEditorComponent implements ExternalResource {
* @param {Function} applyChangesCallback - first callback to apply the changes into the grid (this could be a user custom callback)
* @param {Function} executePostCallback - second callback to execute right after the "onSave"
* @param {Function} beforeClosingCallback - third and last callback to execute after Saving but just before closing the modal window
- * @param {Object} itemDataContext - item data context, only provided for modal type (create/clone/edit)
+ * @param {Object} itemDataContext - item data context when modal type is (create/clone/edit)
*/
protected async executeOnSave(applyChangesCallback: ApplyChangesCallbackFn, executePostCallback: PlainFunc, beforeClosingCallback?: PlainFunc, itemDataContext?: any) {
try {
@@ -687,11 +703,19 @@ export class SlickCompositeEditorComponent implements ExternalResource {
this._modalSaveButtonElm.disabled = true;
if (typeof this._options?.onSave === 'function') {
+ const isMassChange = (this._options.modalType === 'mass-update' || this._options.modalType === 'mass-selection');
+
+ // apply the changes in the grid early when that option is enabled (that is before the await of `onSave`)
+ let updatedDataset;
+ if (isMassChange && this._options?.shouldPreviewMassChangeDataset) {
+ updatedDataset = applyChangesCallback(this.formValues, this.getCurrentRowSelections(), false) as any[];
+ }
// call the custon onSave callback when defined and note that the item data context will only be filled for create/clone/edit
- const successful = await this._options?.onSave(this.formValues, this.getCurrentRowSelections(), itemDataContext);
+ const dataContextOrUpdatedDatasetPreview = isMassChange ? updatedDataset : itemDataContext;
+ const successful = await this._options?.onSave(this.formValues, this.getCurrentRowSelections(), dataContextOrUpdatedDatasetPreview);
if (successful) {
- // apply the changes in the grid
+ // apply the changes in the grid (if it's not yet applied)
applyChangesCallback(this.formValues, this.getCurrentRowSelections());
// once we're done doing the mass update, we can cancel the current editor since we don't want to add any new row
diff --git a/packages/vanilla-force-bundle/dist-grid-bundle-zip/slickgrid-vanilla-bundle.zip b/packages/vanilla-force-bundle/dist-grid-bundle-zip/slickgrid-vanilla-bundle.zip
index 7038c204b..dc4bcfc9a 100644
Binary files a/packages/vanilla-force-bundle/dist-grid-bundle-zip/slickgrid-vanilla-bundle.zip and b/packages/vanilla-force-bundle/dist-grid-bundle-zip/slickgrid-vanilla-bundle.zip differ
diff --git a/packages/vanilla-force-bundle/src/salesforce-global-grid-options.ts b/packages/vanilla-force-bundle/src/salesforce-global-grid-options.ts
index 8df42d9fb..42ec48f26 100644
--- a/packages/vanilla-force-bundle/src/salesforce-global-grid-options.ts
+++ b/packages/vanilla-force-bundle/src/salesforce-global-grid-options.ts
@@ -10,12 +10,9 @@ export const SalesforceGlobalGridOptions = {
cellValueCouldBeUndefined: true,
eventNamingStyle: EventNamingStyle.lowerCaseWithoutOnPrefix,
compositeEditorOptions: {
- labels: {
- massSelectionButton: 'Apply to Selected & Save',
- massUpdateButton: 'Apply to All & Save'
- },
resetEditorButtonCssClass: 'mdi mdi-refresh mdi-15px mdi-v-align-text-top',
- resetFormButtonIconCssClass: 'mdi mdi-refresh mdi-16px mdi-flip-h mdi-v-align-text-top'
+ resetFormButtonIconCssClass: 'mdi mdi-refresh mdi-16px mdi-flip-h mdi-v-align-text-top',
+ shouldPreviewMassChangeDataset: true,
},
datasetIdPropertyName: 'Id',
emptyDataWarning: {
diff --git a/test/cypress/integration/example12.spec.js b/test/cypress/integration/example12.spec.js
index fed65e344..730f0ee50 100644
--- a/test/cypress/integration/example12.spec.js
+++ b/test/cypress/integration/example12.spec.js
@@ -3,7 +3,7 @@ import { changeTimezone, zeroPadding } from '../plugins/utilities';
describe('Example 12 - Composite Editor Modal', { retries: 1 }, () => {
const fullPreTitles = ['', 'Common Factor', 'Analysis', 'Period', 'Item', ''];
- const fullTitles = ['', 'Title', 'Duration', 'Cost', '% Complete', 'Complexity', 'Start', 'Completed', 'Finish', 'Product', 'Country of Origin', 'Action'];
+ const fullTitles = ['', ' Title', 'Duration', 'Cost', '% Complete', 'Complexity', 'Start', 'Completed', 'Finish', 'Product', 'Country of Origin', 'Action'];
const GRID_ROW_HEIGHT = 33;
const UNSAVED_RGB_COLOR = 'rgb(221, 219, 218)';
@@ -336,14 +336,14 @@ describe('Example 12 - Composite Editor Modal', { retries: 1 }, () => {
cy.get('.item-details-container.editor-origin .modified').should('have.length', 1);
cy.get('.item-details-container.editor-origin .autocomplete').invoke('val').then(text => expect(text).to.eq('Belgium'));
- cy.get('.btn-save').contains('Apply to All & Save').click();
+ cy.get('.btn-save').contains('Apply Mass Update').click();
cy.get('.validation-summary').contains('Unfortunately we only accept a minimum of 50% Completion...');
cy.get('.item-details-editor-container .slider-editor-input.editor-percentComplete').as('range').invoke('val', 5).trigger('change');
cy.get('.item-details-editor-container .slider-editor-input.editor-percentComplete').as('range').invoke('val', 51).trigger('change');
cy.get('.item-details-editor-container .input-group-text').contains('51');
- cy.get('.btn-save').contains('Apply to All & Save').click();
+ cy.get('.btn-save').contains('Apply Mass Update').click();
cy.get('.slick-editor-modal').should('not.exist');
});
@@ -448,12 +448,12 @@ describe('Example 12 - Composite Editor Modal', { retries: 1 }, () => {
cy.get('.item-details-container.editor-origin .modified').should('have.length', 1);
cy.get('.item-details-container.editor-origin .autocomplete').invoke('val').then(text => expect(text).to.eq('Belize'));
- cy.get('.btn-save').contains('Apply to Selected & Save').click();
+ cy.get('.btn-save').contains('Update Selection').click();
cy.get('.validation-summary').contains('Unfortunately we only accept a minimum of 50% Completion...');
cy.get('.item-details-editor-container .slider-editor-input.editor-percentComplete').as('range').invoke('val', 77).trigger('change');
cy.get('.item-details-editor-container .input-group-text').contains('77');
- cy.get('.btn-save').contains('Apply to Selected & Save').click();
+ cy.get('.btn-save').contains('Update Selection').click();
cy.get('.slick-editor-modal').should('not.exist');
});