From e55fa6733f88e91dcb5320bd2448075093ffd0cd Mon Sep 17 00:00:00 2001 From: Ghislain B Date: Wed, 1 Nov 2023 23:11:21 -0400 Subject: [PATCH] feat: add sub-menus to all Menu extensions/plugins (#1103) - latest Slickgrid-Universal version brings sub-menus to all these extensions: CellMenu, Context, HeaderMenu & GridMenu --- package.json | 26 +-- src/examples/slickgrid/example24.ts | 80 +++++++++- src/examples/slickgrid/example8.ts | 47 +++++- src/examples/slickgrid/example9.ts | 41 ++++- test/cypress/e2e/example01.cy.ts | 6 +- test/cypress/e2e/example03.cy.ts | 2 +- test/cypress/e2e/example05.cy.ts | 2 +- test/cypress/e2e/example06.cy.ts | 26 +-- test/cypress/e2e/example07.cy.ts | 4 +- test/cypress/e2e/example08.cy.ts | 68 +++++++- test/cypress/e2e/example09.cy.ts | 159 ++++++++++++++++-- test/cypress/e2e/example12.cy.ts | 2 +- test/cypress/e2e/example15.cy.ts | 10 +- test/cypress/e2e/example16.cy.ts | 8 +- test/cypress/e2e/example19.cy.ts | 4 +- test/cypress/e2e/example20.cy.ts | 2 +- test/cypress/e2e/example23.cy.ts | 2 +- test/cypress/e2e/example24.cy.ts | 239 +++++++++++++++++++++++++++- test/cypress/e2e/example32.cy.ts | 2 +- yarn.lock | 196 +++++++++++------------ 20 files changed, 753 insertions(+), 173 deletions(-) diff --git a/package.json b/package.json index 7e9151d8a..017ca8166 100644 --- a/package.json +++ b/package.json @@ -58,12 +58,12 @@ "new-release": "npm run release, note that yarn is not supported with release-it and will throw an error" }, "dependencies": { - "@slickgrid-universal/common": "~3.3.2", - "@slickgrid-universal/custom-footer-component": "~3.3.2", - "@slickgrid-universal/empty-warning-component": "~3.3.2", - "@slickgrid-universal/event-pub-sub": "~3.3.2", - "@slickgrid-universal/pagination-component": "~3.3.2", - "@slickgrid-universal/row-detail-view-plugin": "~3.3.2", + "@slickgrid-universal/common": "~3.4.0", + "@slickgrid-universal/custom-footer-component": "~3.4.0", + "@slickgrid-universal/empty-warning-component": "~3.4.0", + "@slickgrid-universal/event-pub-sub": "~3.4.0", + "@slickgrid-universal/pagination-component": "~3.4.0", + "@slickgrid-universal/row-detail-view-plugin": "~3.4.0", "aurelia-event-aggregator": "^1.0.3", "aurelia-framework": "^1.4.1", "aurelia-i18n": "^4.0.4", @@ -77,13 +77,13 @@ "@fnando/sparkline": "^0.3.10", "@popperjs/core": "^2.11.8", "@release-it/conventional-changelog": "^7.0.2", - "@slickgrid-universal/composite-editor-component": "~3.3.2", - "@slickgrid-universal/custom-tooltip-plugin": "~3.3.2", - "@slickgrid-universal/excel-export": "~3.3.2", - "@slickgrid-universal/graphql": "~3.3.2", - "@slickgrid-universal/odata": "~3.3.2", - "@slickgrid-universal/rxjs-observable": "~3.3.2", - "@slickgrid-universal/text-export": "~3.3.2", + "@slickgrid-universal/composite-editor-component": "~3.4.0", + "@slickgrid-universal/custom-tooltip-plugin": "~3.4.0", + "@slickgrid-universal/excel-export": "~3.4.0", + "@slickgrid-universal/graphql": "~3.4.0", + "@slickgrid-universal/odata": "~3.4.0", + "@slickgrid-universal/rxjs-observable": "~3.4.0", + "@slickgrid-universal/text-export": "~3.4.0", "@types/bluebird": "^3.5.41", "@types/dompurify": "^3.0.4", "@types/fnando__sparkline": "^0.3.6", diff --git a/src/examples/slickgrid/example24.ts b/src/examples/slickgrid/example24.ts index 6b671e1b5..25f93bf55 100644 --- a/src/examples/slickgrid/example24.ts +++ b/src/examples/slickgrid/example24.ts @@ -216,7 +216,37 @@ export class Example24 { iconCssClass: 'fa fa-question-circle', positionOrder: 66, }, - { command: 'something', titleKey: 'DISABLED_COMMAND', disabled: true, positionOrder: 67, } + { command: 'something', titleKey: 'DISABLED_COMMAND', disabled: true, positionOrder: 67, }, + { command: '', divider: true, positionOrder: 98 }, + { + // we can also have multiple nested sub-menus + command: 'export', title: 'Exports', positionOrder: 99, + commandItems: [ + { command: 'exports-txt', title: 'Text (tab delimited)' }, + { + command: 'sub-menu', title: 'Excel', cssClass: 'green', subMenuTitle: 'available formats', subMenuTitleCssClass: 'text-italic orange', + commandItems: [ + { command: 'exports-csv', title: 'Excel (csv)' }, + { command: 'exports-xlsx', title: 'Excel (xlsx)' }, + ] + } + ] + }, + { + command: 'feedback', title: 'Feedback', positionOrder: 100, + commandItems: [ + { command: 'request-update', title: 'Request update from supplier', iconCssClass: 'mdi mdi-star', tooltip: 'this will automatically send an alert to the shipping team to contact the user for an update' }, + 'divider', + { + command: 'sub-menu', title: 'Contact Us', iconCssClass: 'mdi mdi-account', subMenuTitle: 'contact us...', subMenuTitleCssClass: 'italic', + commandItems: [ + { command: 'contact-email', title: 'Email us', iconCssClass: 'mdi mdi-pencil-outline' }, + { command: 'contact-chat', title: 'Chat with us', iconCssClass: 'mdi mdi-message-text-outline' }, + { command: 'contact-meeting', title: 'Book an appointment', iconCssClass: 'mdi mdi-coffee' }, + ] + } + ] + } ], optionTitleKey: 'CHANGE_COMPLETED_FLAG', optionItems: [ @@ -296,6 +326,16 @@ export class Example24 { const dataContext = args.dataContext; switch (command) { + case 'contact-email': + case 'contact-chat': + case 'contact-meeting': + alert('Command: ' + args?.command); + break; + case 'exports-csv': + case 'exports-txt': + case 'exports-xlsx': + alert(`Exporting as ${args.item.title}`); + break; case 'command1': alert('Command 1'); break; @@ -366,6 +406,36 @@ export class Example24 { } }, { command: 'something', titleKey: 'DISABLED_COMMAND', disabled: true, positionOrder: 65 }, + { command: '', divider: true, positionOrder: 98 }, + { + // we can also have multiple nested sub-menus + command: 'export', title: 'Exports', positionOrder: 99, + commandItems: [ + { command: 'exports-txt', title: 'Text (tab delimited)' }, + { + command: 'sub-menu', title: 'Excel', cssClass: 'green', subMenuTitle: 'available formats', subMenuTitleCssClass: 'text-italic orange', + commandItems: [ + { command: 'exports-csv', title: 'Excel (csv)' }, + { command: 'exports-xlsx', title: 'Excel (xlsx)' }, + ] + } + ] + }, + { + command: 'feedback', title: 'Feedback', positionOrder: 100, + commandItems: [ + { command: 'request-update', title: 'Request update from supplier', iconCssClass: 'mdi mdi-star', tooltip: 'this will automatically send an alert to the shipping team to contact the user for an update' }, + 'divider', + { + command: 'sub-menu', title: 'Contact Us', iconCssClass: 'mdi mdi-account', subMenuTitle: 'contact us...', subMenuTitleCssClass: 'italic', + commandItems: [ + { command: 'contact-email', title: 'Email us', iconCssClass: 'mdi mdi-pencil-outline' }, + { command: 'contact-chat', title: 'Chat with us', iconCssClass: 'mdi mdi-message-text-outline' }, + { command: 'contact-meeting', title: 'Book an appointment', iconCssClass: 'mdi mdi-coffee' }, + ] + } + ] + } ], // Options allows you to edit a column from an option chose a list @@ -401,6 +471,14 @@ export class Example24 { return (!dataContext.completed); } }, + { + // we can also have multiple nested sub-menus + option: null, title: 'Sub-Options (demo)', subMenuTitleKey: 'CHANGE_PRIORITY', optionItems: [ + { option: 1, iconCssClass: 'fa fa-star-o yellow', titleKey: 'LOW' }, + { option: 2, iconCssClass: 'fa fa-star-half-o orange', titleKey: 'MEDIUM' }, + { option: 3, iconCssClass: 'fa fa-star red', titleKey: 'HIGH' }, + ] + } ], // subscribe to Context Menu onBeforeMenuShow: ((_e, args) => { diff --git a/src/examples/slickgrid/example8.ts b/src/examples/slickgrid/example8.ts index 779724872..b6b58204a 100644 --- a/src/examples/slickgrid/example8.ts +++ b/src/examples/slickgrid/example8.ts @@ -69,7 +69,7 @@ export class Example8 { this.columnDefinitions.forEach((columnDef) => { columnDef.header = { menu: { - items: [ + commandItems: [ // add Custom Header Menu Item Commands which will be appended to the existing internal custom items // you cannot override an internal command but you can hide them and create your own // also note that the internal custom commands are in the positionOrder range of 50-60, @@ -106,6 +106,38 @@ export class Example8 { // you can use "divider" as a string too, but if you do then make sure it's the correct position in the list // (since there's no positionOrder when using 'divider') // 'divider', + { + // we can also have multiple nested sub-menus + command: 'custom-actions', title: 'Hello', positionOrder: 99, + commandItems: [ + { command: 'hello-world', title: 'Hello World' }, + { command: 'hello-slickgrid', title: 'Hello SlickGrid' }, + { + command: 'sub-menu', title: `Let's play`, cssClass: 'green', subMenuTitle: 'choose your game', subMenuTitleCssClass: 'text-italic salmon', + commandItems: [ + { command: 'sport-badminton', title: 'Badminton' }, + { command: 'sport-tennis', title: 'Tennis' }, + { command: 'sport-racquetball', title: 'Racquetball' }, + { command: 'sport-squash', title: 'Squash' }, + ] + } + ] + }, + { + command: 'feedback', title: 'Feedback', positionOrder: 100, + commandItems: [ + { command: 'request-update', title: 'Request update from supplier', iconCssClass: 'mdi mdi-star', tooltip: 'this will automatically send an alert to the shipping team to contact the user for an update' }, + 'divider', + { + command: 'sub-menu', title: 'Contact Us', iconCssClass: 'mdi mdi-account', subMenuTitle: 'contact us...', subMenuTitleCssClass: 'italic', + commandItems: [ + { command: 'contact-email', title: 'Email us', iconCssClass: 'mdi mdi-pencil-outline' }, + { command: 'contact-chat', title: 'Chat with us', iconCssClass: 'mdi mdi-message-text-outline' }, + { command: 'contact-meeting', title: 'Book an appointment', iconCssClass: 'mdi mdi-coffee' }, + ] + } + ] + } ] } }; @@ -123,12 +155,21 @@ export class Example8 { headerMenu: { hideSortCommands: false, hideColumnHideCommand: false, + subItemChevronClass: 'fa fa-chevron-right', // you can use the "onCommand" (in Grid Options) and/or the "action" callback (in Column Definition) onCommand: (_e, args) => { - if (args.command === 'help') { + // e.preventDefault(); // preventing default event would keep the menu open after the execution + const command = args.item?.command; + if (command.includes('hello-')) { + alert(args?.item.title); + } else if (command.includes('sport-')) { + alert('Just do it, play ' + args?.item?.title); + } else if (command.includes('contact-')) { + alert('Command: ' + args?.item?.command); + } else if (args.command === 'help') { alert('Please help!!!'); } - } + }, }, enableTranslate: true, i18n: this.i18n diff --git a/src/examples/slickgrid/example9.ts b/src/examples/slickgrid/example9.ts index e0b30d66f..3c5ce6665 100644 --- a/src/examples/slickgrid/example9.ts +++ b/src/examples/slickgrid/example9.ts @@ -112,6 +112,7 @@ export class Example9 { hideToggleFilterCommand: false, // show/hide internal custom commands menuWidth: 17, resizeOnShowHeaderRow: true, + subItemChevronClass: 'fa fa-chevron-right', commandItems: [ // add Custom Items Commands which will be appended to the existing internal custom items // you cannot override an internal items but you can hide them and create your own @@ -166,12 +167,48 @@ export class Example9 { disabled: true, command: 'disabled-command', positionOrder: 98 + }, + { command: '', divider: true, positionOrder: 98 }, + { + // we can also have multiple nested sub-menus + command: 'export', title: 'Exports', positionOrder: 99, + commandItems: [ + { command: 'exports-txt', title: 'Text (tab delimited)' }, + { + command: 'sub-menu', title: 'Excel', cssClass: 'green', subMenuTitle: 'available formats', subMenuTitleCssClass: 'text-italic orange', + commandItems: [ + { command: 'exports-csv', title: 'Excel (csv)' }, + { command: 'exports-xlsx', title: 'Excel (xlsx)' }, + ] + } + ] + }, + { + command: 'feedback', title: 'Feedback', positionOrder: 100, + commandItems: [ + { command: 'request-update', title: 'Request update from supplier', iconCssClass: 'mdi mdi-star', tooltip: 'this will automatically send an alert to the shipping team to contact the user for an update' }, + 'divider', + { + command: 'sub-menu', title: 'Contact Us', iconCssClass: 'mdi mdi-account', subMenuTitle: 'contact us...', subMenuTitleCssClass: 'italic', + commandItems: [ + { command: 'contact-email', title: 'Email us', iconCssClass: 'mdi mdi-pencil-outline' }, + { command: 'contact-chat', title: 'Chat with us', iconCssClass: 'mdi mdi-message-text-outline' }, + { command: 'contact-meeting', title: 'Book an appointment', iconCssClass: 'mdi mdi-coffee' }, + ] + } + ] } ], // you can use the "action" callback and/or use "onCallback" callback from the grid options, they both have the same arguments - onCommand: (_e, args) => { - if (args.command === 'help') { + onCommand: (_e: Event, args: any) => { + // e.preventDefault(); // preventing default event would keep the menu open after the execution + const command = args.item?.command; + if (command.includes('exports-')) { + alert('Exporting as ' + args?.item.title); + } else if (command.includes('contact-') || command === 'help') { alert('Command: ' + args.command); + } else { + console.log('onGridMenuCommand', args.command); } }, onColumnsChanged: (_e, args) => { diff --git a/test/cypress/e2e/example01.cy.ts b/test/cypress/e2e/example01.cy.ts index ebe61e39f..5b3d1049f 100644 --- a/test/cypress/e2e/example01.cy.ts +++ b/test/cypress/e2e/example01.cy.ts @@ -44,7 +44,7 @@ describe('Example 1 - Basic Grids', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') @@ -69,7 +69,7 @@ describe('Example 1 - Basic Grids', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(3)') .children('.slick-menu-content') @@ -97,7 +97,7 @@ describe('Example 1 - Basic Grids', { retries: 1 }, () => { .click(); cy.get('#grid2') - .find('.slick-header-menu') + .find('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .click(); diff --git a/test/cypress/e2e/example03.cy.ts b/test/cypress/e2e/example03.cy.ts index 11fbe2697..8ab5cc02d 100644 --- a/test/cypress/e2e/example03.cy.ts +++ b/test/cypress/e2e/example03.cy.ts @@ -168,7 +168,7 @@ describe('Example 3 - Grid with Editors', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') diff --git a/test/cypress/e2e/example05.cy.ts b/test/cypress/e2e/example05.cy.ts index a1a9f7217..a261a8792 100644 --- a/test/cypress/e2e/example05.cy.ts +++ b/test/cypress/e2e/example05.cy.ts @@ -727,7 +727,7 @@ describe('Example 5 - OData Grid', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') diff --git a/test/cypress/e2e/example06.cy.ts b/test/cypress/e2e/example06.cy.ts index a4c6b04de..293cfda0e 100644 --- a/test/cypress/e2e/example06.cy.ts +++ b/test/cypress/e2e/example06.cy.ts @@ -171,7 +171,7 @@ describe('Example 6 - GraphQL Grid', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') @@ -201,7 +201,7 @@ describe('Example 6 - GraphQL Grid', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') @@ -232,7 +232,7 @@ describe('Example 6 - GraphQL Grid', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') @@ -433,28 +433,28 @@ describe('Example 6 - GraphQL Grid', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(3)') .children('.slick-menu-content') .should('contain', 'Sort Ascending'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') .should('contain', 'Sort Descending'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') .should('contain', 'Remove Filter'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(7)') .children('.slick-menu-content') .should('contain', 'Remove Sort'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(8)') .children('.slick-menu-content') .should('contain', 'Hide Column'); @@ -541,28 +541,28 @@ describe('Example 6 - GraphQL Grid', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(3)') .children('.slick-menu-content') .should('contain', 'Trier par ordre croissant'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') .should('contain', 'Trier par ordre décroissant'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') .should('contain', 'Supprimer le filtre'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(7)') .children('.slick-menu-content') .should('contain', 'Supprimer le tri'); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item:nth-of-type(8)') .children('.slick-menu-content') .should('contain', 'Cacher la colonne'); diff --git a/test/cypress/e2e/example07.cy.ts b/test/cypress/e2e/example07.cy.ts index 065ddf275..a7a357e92 100644 --- a/test/cypress/e2e/example07.cy.ts +++ b/test/cypress/e2e/example07.cy.ts @@ -359,7 +359,7 @@ describe('Example 7 - Header Button Plugin', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('#grid7-2 .slick-header-menu') + cy.get('#grid7-2 .slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(6)') .children('.slick-menu-content') @@ -389,7 +389,7 @@ describe('Example 7 - Header Button Plugin', { retries: 1 }, () => { .children('.slick-header-menu-button') .click(); - cy.get('#grid7-2 .slick-header-menu') + cy.get('#grid7-2 .slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(3)') .children('.slick-menu-content') diff --git a/test/cypress/e2e/example08.cy.ts b/test/cypress/e2e/example08.cy.ts index fa612fb98..bf11d3582 100644 --- a/test/cypress/e2e/example08.cy.ts +++ b/test/cypress/e2e/example08.cy.ts @@ -89,7 +89,7 @@ describe('Example 8 - Header Menu Plugin', { retries: 1 }, () => { .invoke('show') .click({ force: true }); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('exist'); cy.get('.slick-menu-item .slick-menu-content') @@ -98,7 +98,7 @@ describe('Example 8 - Header Menu Plugin', { retries: 1 }, () => { }); it('should execute "Sort Descending" command from the menu left open and expect 2 sort icons afterward and "% Completed" to be descending with >80', () => { - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('exist'); cy.get('.slick-menu-item .slick-menu-content') @@ -151,6 +151,70 @@ describe('Example 8 - Header Menu Plugin', { retries: 1 }, () => { .children() .should('have.length', 5) .each(($child, index) => expect($child.text()).to.contain(newTitles[index])); + }); + describe('with sub-menus', () => { + it(`should open Hello sub-menu and expect 3 options, then open Feedback->ContactUs sub-menus and expect previous Hello menu to no longer exists`, () => { + const subCommands1 = ['Hello World', 'Hello SlickGrid', `Let's play`]; + const subCommands2 = ['Request update from supplier', '', 'Contact Us']; + const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment']; + + const stub = cy.stub(); + cy.on('window:alert', stub); + + cy.get('#grid8') + .find('.slick-header-column:nth(0)') + .trigger('mouseover') + .children('.slick-header-menu-button') + .should('be.hidden') + .invoke('show') + .click({ force: true }); + + cy.get('.slick-header-menu.slick-menu-level-0') + .find('.slick-menu-item.slick-menu-item') + .contains('Hello') + .should('exist') + .click(); + + cy.get('.slick-submenu').should('have.length', 1); + cy.get('.slick-header-menu.slick-menu-level-1.dropright') // right align + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + // click different sub-menu + cy.get('.slick-header-menu.slick-menu-level-0') + .find('.slick-menu-item.slick-menu-item') + .contains('Feedback') + .should('exist') + .click(); + + cy.get('.slick-submenu').should('have.length', 1); + cy.get('.slick-header-menu.slick-menu-level-1') + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands2[index])); + + // click on Feedback->ContactUs + cy.get('.slick-header-menu.slick-menu-level-1.dropright') // right align + .find('.slick-menu-item.slick-menu-item') + .contains('Contact Us') + .should('exist') + .trigger('mouseover'); // mouseover or click should work + + cy.get('.slick-submenu').should('have.length', 2); + cy.get('.slick-header-menu.slick-menu-level-2.dropleft') // left align + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands2_1[index])); + + cy.get('.slick-header-menu.slick-menu-level-2') + .find('.slick-menu-item') + .contains('Chat with us') + .click() + .then(() => expect(stub.getCall(0)).to.be.calledWith('Command: contact-chat')); + + cy.get('.slick-submenu').should('have.length', 0); + }); }); }); diff --git a/test/cypress/e2e/example09.cy.ts b/test/cypress/e2e/example09.cy.ts index 135781b80..f0101e844 100644 --- a/test/cypress/e2e/example09.cy.ts +++ b/test/cypress/e2e/example09.cy.ts @@ -55,7 +55,7 @@ describe('Example 9 - Grid Menu', { retries: 1 }, () => { .invoke('show') .trigger('click', { force: true }); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') @@ -187,7 +187,7 @@ describe('Example 9 - Grid Menu', { retries: 1 }, () => { .invoke('show') .trigger('click', { force: true }); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') @@ -223,12 +223,6 @@ describe('Example 9 - Grid Menu', { retries: 1 }, () => { .find('.slick-header-columns') .children() .each(($child, index) => expect($child.text()).to.eq(fullEnglishTitles[index])); - - cy.get('#grid9') - .get('.slick-grid-menu') - .find('.close') - .trigger('click', { force: true }) - .click({ force: true }); }); }); @@ -258,7 +252,7 @@ describe('Example 9 - Grid Menu', { retries: 1 }, () => { .invoke('show') .trigger('click', { force: true }); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') @@ -303,7 +297,7 @@ describe('Example 9 - Grid Menu', { retries: 1 }, () => { .invoke('show') .trigger('click', { force: true }); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') @@ -339,12 +333,151 @@ describe('Example 9 - Grid Menu', { retries: 1 }, () => { .find('.slick-header-columns') .children() .each(($child, index) => expect($child.text()).to.eq(fullFrenchTitles[index])); + }); + }); + + describe('Grid Menu with sub-menus', () => { + it('should switch locale back to English', () => { + cy.get('[data-test=language]') + .click({ force: true }); + + cy.get('[data-test=selected-locale]') + .should('contain', 'en.json'); cy.get('#grid9') - .get('.slick-grid-menu') - .find('.close') - .trigger('click', { force: true }) + .find('.slick-header-columns') + .children() + .each(($child, index) => expect($child.text()).to.eq(fullEnglishTitles[index])); + }); + + it('should be able to open Grid Menu and click on Export->Text and expect alert triggered with Text Export', () => { + const subCommands1 = ['Text', 'Excel']; + const stub = cy.stub(); + cy.on('window:alert', stub); + + cy.get('#grid9') + .find('button.slick-grid-menu-button') .click({ force: true }); + + cy.get('.slick-grid-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Exports') + .click(); + + cy.get('.slick-grid-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + cy.get('.slick-grid-menu.slick-menu-level-1 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Text (tab delimited)') + .click() + .then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Text (tab delimited)')); + }); + + it('should be able to open Grid Menu and click on Export->Excel->xlsx and expect alert triggered with Excel (xlsx) Export', () => { + const subCommands1 = ['Text', 'Excel']; + const subCommands2 = ['Excel (csv)', 'Excel (xlsx)']; + const stub = cy.stub(); + cy.on('window:alert', stub); + + cy.get('#grid9') + .find('button.slick-grid-menu-button') + .click({ force: true }); + + cy.get('.slick-grid-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Exports') + .click(); + + cy.get('.slick-grid-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + cy.get('.slick-submenu').should('have.length', 1); + cy.get('.slick-grid-menu.slick-menu-level-1 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Excel') + .click(); + + cy.get('.slick-grid-menu.slick-menu-level-2 .slick-menu-command-list').as('subMenuList2'); + + cy.get('@subMenuList2') + .find('.slick-menu-title') + .contains('available formats'); + + cy.get('@subMenuList2') + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands2[index])); + cy.get('.slick-submenu').should('have.length', 2); + + cy.get('.slick-grid-menu.slick-menu-level-2 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Excel (xlsx)') + .click() + .then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Excel (xlsx)')); + cy.get('.slick-submenu').should('have.length', 0); + }); + + it('should open Export->Excel context sub-menu then open Feedback->ContactUs sub-menus and expect previous Export menu to no longer exists', () => { + const subCommands1 = ['Text', 'Excel']; + const subCommands2 = ['Request update from supplier', '', 'Contact Us']; + const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment']; + + const stub = cy.stub(); + cy.on('window:alert', stub); + + cy.get('[data-test=external-gridmenu]') + .click(); + + cy.get('.slick-grid-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Export') + .click(); + + cy.get('.slick-grid-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + // click different sub-menu + cy.get('.slick-grid-menu.slick-menu-level-0') + .find('.slick-menu-item') + .contains('Feedback') + .should('exist') + .trigger('mouseover'); // mouseover or click should work + + cy.get('.slick-submenu').should('have.length', 1); + cy.get('.slick-grid-menu.slick-menu-level-1') + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands2[index])); + + // click on Feedback->ContactUs + cy.get('.slick-grid-menu.slick-menu-level-1.dropright') // right align + .find('.slick-menu-item') + .contains('Contact Us') + .should('exist') + .click(); + + cy.get('.slick-submenu').should('have.length', 2); + cy.get('.slick-grid-menu.slick-menu-level-2.dropright') // right align + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index])); + + cy.get('.slick-grid-menu.slick-menu-level-2'); + + cy.get('.slick-grid-menu.slick-menu-level-2 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Chat with us') + .click() + .then(() => expect(stub.getCall(0)).to.be.calledWith('Command: contact-chat')); + + cy.get('.slick-submenu').should('have.length', 0); }); }); }); diff --git a/test/cypress/e2e/example12.cy.ts b/test/cypress/e2e/example12.cy.ts index fd4667829..0cbc208cb 100644 --- a/test/cypress/e2e/example12.cy.ts +++ b/test/cypress/e2e/example12.cy.ts @@ -225,7 +225,7 @@ describe('Example 12: Localization (i18n)', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') diff --git a/test/cypress/e2e/example15.cy.ts b/test/cypress/e2e/example15.cy.ts index 05abc9127..fbc5cf2c9 100644 --- a/test/cypress/e2e/example15.cy.ts +++ b/test/cypress/e2e/example15.cy.ts @@ -174,7 +174,7 @@ describe('Example 15: Grid State & Presets using Local Storage', { retries: 1 }, .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(5)') .children('.slick-menu-content') @@ -401,7 +401,7 @@ describe('Example 15: Grid State & Presets using Local Storage', { retries: 1 }, .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(9)') .children('.slick-menu-content') @@ -423,7 +423,7 @@ describe('Example 15: Grid State & Presets using Local Storage', { retries: 1 }, .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(1)') .children('.slick-menu-content') @@ -533,7 +533,7 @@ describe('Example 15: Grid State & Presets using Local Storage', { retries: 1 }, .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(1)') .children('.slick-menu-content') @@ -564,7 +564,7 @@ describe('Example 15: Grid State & Presets using Local Storage', { retries: 1 }, .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(1)') .children('.slick-menu-content') diff --git a/test/cypress/e2e/example16.cy.ts b/test/cypress/e2e/example16.cy.ts index 9ed714e0b..24c31090b 100644 --- a/test/cypress/e2e/example16.cy.ts +++ b/test/cypress/e2e/example16.cy.ts @@ -205,7 +205,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', { retries .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item') .each(($child, index) => { const commandTitle = $child.text(); @@ -254,7 +254,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', { retries .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item') .each(($child, index) => { const commandTitle = $child.text(); @@ -299,7 +299,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', { retries .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item') .each(($child, index) => { const commandTitle = $child.text(); @@ -325,7 +325,7 @@ describe('Example 16 - Row Move & Checkbox Selector Selector Plugins', { retries .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .children('.slick-menu-item') .each(($child, index) => { const commandTitle = $child.text(); diff --git a/test/cypress/e2e/example19.cy.ts b/test/cypress/e2e/example19.cy.ts index daf78c4b1..5073037b3 100644 --- a/test/cypress/e2e/example19.cy.ts +++ b/test/cypress/e2e/example19.cy.ts @@ -198,7 +198,7 @@ describe('Example 19 - Row Detail View', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(4)') .children('.slick-menu-content') @@ -212,7 +212,7 @@ describe('Example 19 - Row Detail View', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(3)') .children('.slick-menu-content') diff --git a/test/cypress/e2e/example20.cy.ts b/test/cypress/e2e/example20.cy.ts index d30e93146..e6229ec1c 100644 --- a/test/cypress/e2e/example20.cy.ts +++ b/test/cypress/e2e/example20.cy.ts @@ -104,7 +104,7 @@ describe('Example 20 - Frozen Grid', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(8)') .children('.slick-menu-content') diff --git a/test/cypress/e2e/example23.cy.ts b/test/cypress/e2e/example23.cy.ts index 062dd5604..f8b2cd958 100644 --- a/test/cypress/e2e/example23.cy.ts +++ b/test/cypress/e2e/example23.cy.ts @@ -7,7 +7,7 @@ const presetMaxDuration = 88; const presetLowestDay = moment().add(-2, 'days').format('YYYY-MM-DD'); const presetHighestDay = moment().add(28, 'days').format('YYYY-MM-DD'); -describe('Example 23 - Range Filters', { retries: 0 }, () => { +describe('Example 23 - Range Filters', { retries: 1 }, () => { it('should display Example title', () => { cy.visit(`${Cypress.config('baseUrl')}/slickgrid/example23`); cy.get('h2').should('contain', 'Example 23: Filtering from Range of Search Values'); diff --git a/test/cypress/e2e/example24.cy.ts b/test/cypress/e2e/example24.cy.ts index 6da9b273f..9c3147897 100644 --- a/test/cypress/e2e/example24.cy.ts +++ b/test/cypress/e2e/example24.cy.ts @@ -1,4 +1,5 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { + const GRID_ROW_HEIGHT = 35; const fullEnglishTitles = ['#', 'Title', '% Complete', 'Start', 'Finish', 'Priority', 'Completed', 'Action']; const fullFrenchTitles = ['#', 'Titre', '% Achevée', 'Début', 'Fin', 'Priorité', 'Terminé', 'Action']; @@ -37,7 +38,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { }); it('should expect the Context Menu to not have the "Help" menu when there is Completed set to True', () => { - const commands = ['Copy', 'Export to Excel', '', 'Delete Row', '', 'Disabled Command']; + const commands = ['Copy', 'Export to Excel', '', 'Delete Row', '', 'Disabled Command', '', 'Exports', 'Feedback']; cy.get('#grid24') .find('.slick-row .slick-cell:nth(1)') @@ -118,7 +119,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { }); it('should expect the Context Menu now have the "Help" menu when Completed is set to False', () => { - const commands = ['Copy', 'Export to Excel', '', 'Delete Row', '', 'Help', 'Disabled Command']; + const commands = ['Copy', 'Export to Excel', '', 'Delete Row', '', 'Help', 'Disabled Command', '', 'Exports', 'Feedback']; cy.get('#grid24') .find('.slick-row .slick-cell:nth(1)') @@ -258,7 +259,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { }); it('should click on the "Show Action Commands Only" button and see both list when opening Context Menu', () => { - const commands = ['Command 1', 'Command 2', '', 'Delete Row', 'Help', 'Disabled Command']; + const commands = ['Command 1', 'Command 2', '', 'Delete Row', 'Help', 'Disabled Command', '', 'Exports', 'Feedback']; cy.get('[data-test=cell-menu-commands-and-options-false-button]') .click(); @@ -401,7 +402,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { }); it('should expect the Context Menu to not have the "Aide" menu when there is Completed set to False', () => { - const commands = ['Copier', 'Exporter vers Excel', '', 'Supprimer la ligne', '', 'Aide', 'Commande désactivée']; + const commands = ['Copier', 'Exporter vers Excel', '', 'Supprimer la ligne', '', 'Aide', 'Commande désactivée', '', 'Exports', 'Feedback']; cy.get('#grid24') .find('.slick-row .slick-cell:nth(1)') @@ -465,7 +466,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { }); it('should expect the Context Menu now have the "Aide" menu when Completed is set to False', () => { - const commands = ['Copier', 'Exporter vers Excel', '', 'Supprimer la ligne', '', 'Aide', 'Commande désactivée']; + const commands = ['Copier', 'Exporter vers Excel', '', 'Supprimer la ligne', '', 'Aide', 'Commande désactivée', '', 'Exports', 'Feedback']; cy.get('#grid24') .find('.slick-row .slick-cell:nth(1)') @@ -605,7 +606,7 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { }); it('should click on the "Show Action Commands Only" button and see both list when opening Context Menu', () => { - const commands = ['Command 1', 'Command 2', '', 'Supprimer la ligne', 'Aide', 'Commande désactivée']; + const commands = ['Command 1', 'Command 2', '', 'Supprimer la ligne', 'Aide', 'Commande désactivée', '', 'Exports', 'Feedback']; cy.get('[data-test=cell-menu-commands-and-options-false-button]') .click(); @@ -687,4 +688,230 @@ describe('Example 24 - Cell Menu & Context Menu Plugins', () => { .should('contain', 'en.json'); }); }); + + describe('with sub-menus', () => { + it('should reopen Context Menu hover "Priority" column then open options sub-menu & select "High" option and expect Task to be set to High in the UI', () => { + const subOptions = ['Low', 'Medium', 'High']; + + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] .slick-cell:nth(5)`) + .rightclick({ force: true }); + + cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-option-list') + .find('.slick-menu-item .slick-menu-content') + .contains('Sub-Options (demo)') + .click(); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-option-list').as('subMenuList'); + cy.get('@subMenuList').find('.slick-menu-title').contains('Change Priority'); + cy.get('@subMenuList') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.eq(subOptions[index])); + + cy.get('@subMenuList') + .find('.slick-menu-item .slick-menu-content') + .contains('High') + .click(); + + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] .slick-cell:nth(5)`) + .find('.fa-star.red'); + }); + + it('should be able to open Context Menu from any other cell and click on Export->Text and expect alert triggered with Text Export', () => { + const subCommands1 = ['Text', 'Excel']; + const stub = cy.stub(); + cy.on('window:alert', stub); + + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] .slick-cell:nth(1)`) + .should('contain', 'Task 2'); + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] .slick-cell:nth(1)`) + .rightclick({ force: true }); + + cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains(/^Exports$/) + .click(); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .find('.slick-menu-item') + .contains('Text') + .click() + .then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Text (tab delimited)')); + }); + + it('should be able to open Context Menu and click on Export->Excel-> sub-commands to see 1 context menu + 1 sub-menu then clicking on Text should call alert action', () => { + const subCommands1 = ['Text', 'Excel']; + const subCommands2 = ['Excel (csv)', 'Excel (xlsx)']; + const stub = cy.stub(); + cy.on('window:alert', stub); + + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] .slick-cell:nth(1)`).should('contain', 'Task 2'); + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] .slick-cell:nth(1)`) + .rightclick({ force: true }); + + cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains(/^Exports$/) + .click(); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains('Excel') + .click(); + + cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list').as('subMenuList2'); + + cy.get('@subMenuList2') + .find('.slick-menu-title') + .contains('available formats'); + + cy.get('@subMenuList2') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.contain(subCommands2[index])); + + cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains('Excel (xlsx)') + .click() + .then(() => expect(stub.getCall(0)).to.be.calledWith('Exporting as Excel (xlsx)')); + }); + + it('should click on the "Show Commands & Priority Options" button and see both list when opening Context Menu', () => { + cy.get('[data-test=context-menu-commands-and-priority-button]') + .click(); + + cy.get('#grid24') + .find('.slick-row .slick-cell:nth(5)') + .rightclick({ force: true }); + + cy.get('.slick-context-menu .slick-menu-option-list') + .should('exist') + .contains('High'); + + cy.get('.slick-context-menu .slick-menu-command-list') + .find('.slick-menu-item.red') + .find('.slick-menu-content.bold') + .should('exist') + .contains('Delete Row'); + + cy.get('.slick-context-menu button.close') + .click(); + }); + + it('should open Export->Excel sub-menu & open again Sub-Options on top and expect sub-menu to be recreated with that Sub-Options list instead of the Export->Excel list', () => { + const subCommands1 = ['Text', 'Excel']; + const subCommands2 = ['Excel (csv)', 'Excel (xlsx)']; + const subOptions = ['Low', 'Medium', 'High']; + + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(5)`); + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(5)`) + .rightclick({ force: true }); + + cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains(/^Exports$/) + .click(); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains('Excel') + .click(); + + cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.contain(subCommands2[index])); + + cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-option-list') + .find('.slick-menu-item .slick-menu-content') + .contains('Sub-Options') + .click(); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-option-list').as('optionSubList2'); + + cy.get('@optionSubList2') + .find('.slick-menu-title') + .contains('Change Priority'); + + cy.get('@optionSubList2') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($option, index) => expect($option.text()).to.contain(subOptions[index])); + }); + + it('should open Export->Excel context sub-menu then open Feedback->ContactUs sub-menus and expect previous Export menu to no longer exists', () => { + const subCommands1 = ['Text', 'Excel']; + const subCommands2 = ['Request update from supplier', '', 'Contact Us']; + const subCommands2_1 = ['Email us', 'Chat with us', 'Book an appointment']; + + const stub = cy.stub(); + cy.on('window:alert', stub); + + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(5)`); + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(5)`) + .rightclick({ force: true }); + + cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains(/^Exports$/) + .click(); + + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.contain(subCommands1[index])); + + // click different sub-menu + cy.get('.slick-context-menu.slick-menu-level-0 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains('Feedback') + .should('exist') + .click(); + + cy.get('.slick-submenu').should('have.length', 1); + cy.get('.slick-context-menu.slick-menu-level-1 .slick-menu-command-list') + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.contain(subCommands2[index])); + + // click on Feedback->ContactUs + cy.get('.slick-context-menu.slick-menu-level-1.dropleft') // left align + .find('.slick-menu-item .slick-menu-content') + .contains('Contact Us') + .should('exist') + .trigger('mouseover'); // mouseover or click should work + + cy.get('.slick-submenu').should('have.length', 2); + cy.get('.slick-context-menu.slick-menu-level-2.dropright') // right align + .should('exist') + .find('.slick-menu-item .slick-menu-content') + .each(($command, index) => expect($command.text()).to.eq(subCommands2_1[index])); + + cy.get('.slick-context-menu.slick-menu-level-2'); + + cy.get('.slick-context-menu.slick-menu-level-2 .slick-menu-command-list') + .find('.slick-menu-item .slick-menu-content') + .contains('Chat with us') + .click() + .then(() => expect(stub.getCall(0)).to.be.calledWith('Command: contact-chat')); + + cy.get('.slick-submenu').should('have.length', 0); + }); + }); }); diff --git a/test/cypress/e2e/example32.cy.ts b/test/cypress/e2e/example32.cy.ts index 4f86be141..0908e5b3f 100644 --- a/test/cypress/e2e/example32.cy.ts +++ b/test/cypress/e2e/example32.cy.ts @@ -80,7 +80,7 @@ describe('Example 32 - Columns Resize by Content', { retries: 1 }, () => { .invoke('show') .click(); - cy.get('.slick-header-menu') + cy.get('.slick-header-menu .slick-menu-command-list') .should('be.visible') .children('.slick-menu-item:nth-of-type(1)') .children('.slick-menu-content') diff --git a/yarn.lock b/yarn.lock index e26708a6f..a08f042a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1153,129 +1153,129 @@ dependencies: "@sinonjs/commons" "^2.0.0" -"@slickgrid-universal/binding@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/binding/-/binding-3.3.2.tgz#49874d066e792ef67185a25a77dac34e2ab95de3" - integrity sha512-fohlfzrEunud+e6EmdVwr5LeoYRVqwzwlr6KaxwBMS9n4Wy7/toezSwV+GjIU+GBk9EtJxOtr/0PMle1rOEgdg== - -"@slickgrid-universal/common@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/common/-/common-3.3.2.tgz#52de8c1762591d4fe8d47d776cac01915e6d654c" - integrity sha512-/rXZdR4h+clBkAPGMjRWTXJ8/71WGNjSa9JfNLS/zzVXDpxs5OgTYuu7ggUQXapDshDuQny6GjBCuAACFpgsSQ== - dependencies: - "@slickgrid-universal/event-pub-sub" "~3.3.2" - "@slickgrid-universal/utils" "~3.3.2" - autocompleter "^9.1.0" +"@slickgrid-universal/binding@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/binding/-/binding-3.4.0.tgz#241207fd036fcd7dfc803e05352c4bd94078abba" + integrity sha512-tzyMdx/sGcDXrjIiC0W7e0eFRtTrlPPq14Q4ZSxK61tUJ26rySQ5dTJ7vYcGQNauUQ+maeRJms0aFJAMiHfK9w== + +"@slickgrid-universal/common@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/common/-/common-3.4.0.tgz#52b5534b6f81448e4198fe72cf2faeacc0572972" + integrity sha512-P4LG+9SNQaubGfLDzl++Z8MTCNz1LZHpRqp0BOJv7wGRojFqqTQh8ufDyvRAT/wpBjK3SvmbxHGO++Zb6tBfcg== + dependencies: + "@slickgrid-universal/event-pub-sub" "~3.4.0" + "@slickgrid-universal/utils" "~3.4.0" + autocompleter "^9.1.1" dequal "^2.0.3" dompurify "^3.0.6" flatpickr "^4.6.13" moment-mini "^2.29.4" - multiple-select-vanilla "^0.4.10" - slickgrid "^4.0.1" + multiple-select-vanilla "^0.5.0" + slickgrid "^4.1.2" sortablejs "^1.15.0" un-flatten-tree "^2.0.12" -"@slickgrid-universal/composite-editor-component@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/composite-editor-component/-/composite-editor-component-3.3.2.tgz#dfdbb7bb93b621e600a810b6ff495976eec1da38" - integrity sha512-OovvuzIXzbdQwwHbRg8XALZvX+G7Zu/h8id+g0fJKudU3BxE5Pu1tztY9qY4VEyFfXaymVDLrfYxJBiitlEXyw== +"@slickgrid-universal/composite-editor-component@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/composite-editor-component/-/composite-editor-component-3.4.0.tgz#3d440605f0b3d420ffe62f337dd93769bf982196" + integrity sha512-rJooCc4XitSZ5oQoToH5+7HEY30qikTjbxBVEeiRdX0mYLRWU3JOv5M0tx5PItMRT6YLGIftPoTnvQwZ8qHWnA== dependencies: - "@slickgrid-universal/common" "~3.3.2" - "@slickgrid-universal/utils" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" + "@slickgrid-universal/utils" "~3.4.0" -"@slickgrid-universal/custom-footer-component@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-footer-component/-/custom-footer-component-3.3.2.tgz#0be6512ee05ba1482a21e92ef00a26c0f7a33829" - integrity sha512-TB5mmV8GjIjDbeZ0rDwfD8GW70gYI1J+ZAUrE5Kli/UDymNga523D0C5gUpGL3gL4PErppH322sg9qVO2dd+cA== +"@slickgrid-universal/custom-footer-component@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-footer-component/-/custom-footer-component-3.4.0.tgz#5fac3fa24856dadd43e358960ab6cb297bf2d80c" + integrity sha512-zQul8lDUVsz2AUhTwSYtCxbGt2cyHIPg4TorpZNgpz+6Yn+7Wy0fAneDUtodNmsph9TLrGiizF5gxUP1avjaJA== dependencies: - "@slickgrid-universal/binding" "~3.3.2" - "@slickgrid-universal/common" "~3.3.2" + "@slickgrid-universal/binding" "~3.4.0" + "@slickgrid-universal/common" "~3.4.0" moment-mini "^2.29.4" -"@slickgrid-universal/custom-tooltip-plugin@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-tooltip-plugin/-/custom-tooltip-plugin-3.3.2.tgz#fa71bb28a306ee900e68a206267794f8f9dc6811" - integrity sha512-r+ftWDtWH7cYRmXLoubtKkvLe4X2kSN017tgyqTt8BsVeW3//dRFuYmKo4gxNj6usVL7uDgp0rx4hm7c+KYdzA== +"@slickgrid-universal/custom-tooltip-plugin@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-tooltip-plugin/-/custom-tooltip-plugin-3.4.0.tgz#6ce33a5f2ee7bddd3d2831760f978f00760cf0fe" + integrity sha512-XO7yQwMu6gCD0T/9lgaOdhU52schAmJSu3JEQRyUAN45umyIshDHfKRyKPBPhx/jkjJgd/xO5sd6h/zz2uHQwg== dependencies: - "@slickgrid-universal/common" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" dompurify "^3.0.6" -"@slickgrid-universal/empty-warning-component@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/empty-warning-component/-/empty-warning-component-3.3.2.tgz#9fb0d345772dd54714f791c10f04d7e8a136c35a" - integrity sha512-uh2HHtb3ep7EWcZLZrgxwaCTJlqPDd0JYq8yjyYxxQEQEhTlLUDNjJ59y602e3uzScg2eOaeH9wz2NaSpqYdmg== +"@slickgrid-universal/empty-warning-component@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/empty-warning-component/-/empty-warning-component-3.4.0.tgz#f436ec68380a13093933a0220b30e11021d4bb4e" + integrity sha512-TC5WNRrJQ4zLvnMSoV0jOXKDJQCVygq2yKf+QUV+5xcvtjICOfxFStkMo+KyVq9O7T0T+Zc43X7DCjMs/RqE3A== dependencies: - "@slickgrid-universal/common" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" -"@slickgrid-universal/event-pub-sub@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/event-pub-sub/-/event-pub-sub-3.3.2.tgz#685fdd2a153fef738cbc8fd241b1aa19fe9e558f" - integrity sha512-dC+M7wfMQJoPiQV388+ABtZ2Eil9lAigW1pyEsAL+RMRBCadyeSkHJ5wktMF7Ze03wKbG78b2JKcdMQsAJyFDg== +"@slickgrid-universal/event-pub-sub@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/event-pub-sub/-/event-pub-sub-3.4.0.tgz#fefbebb6b2c96ffd0ff9272cee717adffd33497b" + integrity sha512-g+jeC+VRYt3PPh2BWVNpFivtGA1M8Cl0BUV9qs2dFwAhw9Lob3vfCmNs9xzuMUEf7/NTI6hcXgGMz4zfFhKcpw== dependencies: - "@slickgrid-universal/utils" "~3.3.2" + "@slickgrid-universal/utils" "~3.4.0" -"@slickgrid-universal/excel-export@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/excel-export/-/excel-export-3.3.2.tgz#fc26ee7bc1f8c37924a9339d713a7042ef255ac3" - integrity sha512-zr6GfhfzOzCoCUUmwVYkvuWyLsh92NQLyVIhjB33xDi6X7r4/pYZxbYZNWTT0X2ZSdTivF4XGnB4pDi+ZzUOow== +"@slickgrid-universal/excel-export@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/excel-export/-/excel-export-3.4.0.tgz#34ca67e45423d511533b70637d2e3569fb779ced" + integrity sha512-/5LviCJKT538Kl/AeUal2wmcewjdODQbl5I8pU9oBXHdsGxj+olZSVWXvlf+4PaaEbkJ2extytQuQg0VccLIXg== dependencies: - "@slickgrid-universal/common" "~3.3.2" - "@slickgrid-universal/utils" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" + "@slickgrid-universal/utils" "~3.4.0" excel-builder-webpacker "^2.1.8" moment-mini "^2.29.4" -"@slickgrid-universal/graphql@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/graphql/-/graphql-3.3.2.tgz#e78acebcd4c7ffcf1dbf9e6b9989d9998f469851" - integrity sha512-mnQ/7vX/IN575gYss+R8dWXa1MAnHpBf4s0dCA783SGExoJAG6YhlipAos7jOhIwUrgCTxzp2H6ac4CxGd5BlA== +"@slickgrid-universal/graphql@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/graphql/-/graphql-3.4.0.tgz#f6a8d8bec0df98519366a6b876714894ef30a75c" + integrity sha512-qoqQhjN9IZJvRf2P2vgKsdQeKGmQtECH1QCgTgQytQoDVwfbwRBw8zr8RNrK4v/dsDP4G+ClGjOYSCLa0B0GrA== dependencies: - "@slickgrid-universal/common" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" -"@slickgrid-universal/odata@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/odata/-/odata-3.3.2.tgz#5d30133ec84ff755a86127b253c79837277fb122" - integrity sha512-4Q3G/t9ndsCTqubTrDgOUWzF79lKxgKN/2P47UOOigYMNPwqLBgT5pCTmBVRMiw8GM5qFIQc0Hxfkj7mF+02Mw== +"@slickgrid-universal/odata@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/odata/-/odata-3.4.0.tgz#3eedcd40a131ac8b04c43eb3c8d4c223788716fb" + integrity sha512-EPdfwLm7/WYeUqESMrNo+Z1IZkByu8KAFyCuMCx7ipntnPBm0y/Oipmh9TIYc+iQjm2bwMWyAzE3SK7sSYeD1Q== dependencies: - "@slickgrid-universal/common" "~3.3.2" - "@slickgrid-universal/utils" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" + "@slickgrid-universal/utils" "~3.4.0" -"@slickgrid-universal/pagination-component@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/pagination-component/-/pagination-component-3.3.2.tgz#e92d2e41096c13bae20482cf1c16860df2bf164c" - integrity sha512-XoqZigRRW9+Esm/+gjG4KR2ElDAkMi7UNmWf2KR5zjHpYP6sTem4sCAMVJ7/vx+DifzEIAqBXch18upzQBUAXg== +"@slickgrid-universal/pagination-component@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/pagination-component/-/pagination-component-3.4.0.tgz#cf543034cbc40036585f1dd81038e34069a940d2" + integrity sha512-OfsC+yH/Vm6ujq8liFTL47m6NJT44xrhNeWYdSmOXR/zIvV/4M5WJLtt8heiIZrfXrJVntr+q01N3nXDYBER2A== dependencies: - "@slickgrid-universal/binding" "~3.3.2" - "@slickgrid-universal/common" "~3.3.2" + "@slickgrid-universal/binding" "~3.4.0" + "@slickgrid-universal/common" "~3.4.0" -"@slickgrid-universal/row-detail-view-plugin@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/row-detail-view-plugin/-/row-detail-view-plugin-3.3.2.tgz#060d9f595e0a28f777a20bb2dfa51b0e8a01cd56" - integrity sha512-ed+ksshbtI3nceab9uSZrkMNqKUYloWh8lzymCDcpqQ89KYHvryYDP7vlGyfiK5K8Oix5k4TzF2CTuJPetxH5A== +"@slickgrid-universal/row-detail-view-plugin@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/row-detail-view-plugin/-/row-detail-view-plugin-3.4.0.tgz#4d3da10b6e1a04eca47f813fa646211d70666b61" + integrity sha512-VIcVNTeA/ZZB4fQVNLHc6Yf6CP8Ad2LH1TkwQl2AvHyhxGL9HIVkcku8HSdoD33p62LH6Fvh3OGMQYnEcSXAsQ== dependencies: - "@slickgrid-universal/common" "~3.3.2" - "@slickgrid-universal/utils" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" + "@slickgrid-universal/utils" "~3.4.0" -"@slickgrid-universal/rxjs-observable@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/rxjs-observable/-/rxjs-observable-3.3.2.tgz#fa9552fa09b1bf04a256d5786d8096143e3c22df" - integrity sha512-ZMm/bdu6UjzXkCfabX0IJqoDnIFHjVWCl0cWRadkqQqMk1W49ZN95c/OZSKQ631EfP7qyV+Iqg8ColKMqTFbmA== +"@slickgrid-universal/rxjs-observable@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/rxjs-observable/-/rxjs-observable-3.4.0.tgz#349d3686d38fd98ce61e4a98c04b2e33a6b47fef" + integrity sha512-cLpAs9gqdNWLUiuKSk5eWJ0Hs9QiF8lUro33yyx9ZuJbBPLKvNJWcT1qVoPualvp2DBOrYaB/KC4mMs3T7NUdw== dependencies: - "@slickgrid-universal/common" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" rxjs "^7.8.1" -"@slickgrid-universal/text-export@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/text-export/-/text-export-3.3.2.tgz#9ae5de432db4c5dabacd4c5f491f8f8e5e895656" - integrity sha512-9gQWAI0t7YjJHHMeh2DYk4DT7jv38GwmtxFHvCzmfqfYVy/Jru+IUB+wnjSEZqWiWrQ177UOZjDEpB7yKlMVxQ== +"@slickgrid-universal/text-export@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/text-export/-/text-export-3.4.0.tgz#8aacc9bb08d17c135c93e4aca6e936fcde2cf407" + integrity sha512-Xg9Fc0Dz2micvag7eI6s+PKa0cPAgcnVpHbAMj6ym6kgpVoegi6VyNomnKWTr4GQUmVbg2hQ3l4iB3Rc8VHhIg== dependencies: - "@slickgrid-universal/common" "~3.3.2" - "@slickgrid-universal/utils" "~3.3.2" + "@slickgrid-universal/common" "~3.4.0" + "@slickgrid-universal/utils" "~3.4.0" text-encoding-utf-8 "^1.0.2" -"@slickgrid-universal/utils@~3.3.2": - version "3.3.2" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/utils/-/utils-3.3.2.tgz#af83a83952d1908a2ec89d19e691a8f60836e3e7" - integrity sha512-QfDFyVzlZTXCcekvqpLJSf5cg6Y8AY6xKIK34EI31om4jtSDgp6D+PwESvKTZwKMpZvymHM4e+q/eQO8q/Hgnw== +"@slickgrid-universal/utils@~3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/utils/-/utils-3.4.0.tgz#e5085f61001d2c9821b840197b65c284d221da89" + integrity sha512-nfOPaDrJW4g6moiutB/AASCK6cpEDXGDlkAvQ74ZMXnjs15fCQJMs7S+E2m7keScpVKY3brOnU/96l+oGTKofA== "@szmarczak/http-timer@^5.0.1": version "5.0.1" @@ -2887,10 +2887,10 @@ aurelia-webpack-plugin@^5.0.6: minimatch "^3.0.4" parse5 "^5.1.1" -autocompleter@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/autocompleter/-/autocompleter-9.1.0.tgz#c7248a8cc0c58376d0969734c40e29626d950f04" - integrity sha512-dwAYJTaLHj1MpzCZXFg8WLmk+tgQ85OEDFfBegGnA+uVUZyzW/PZAdjSXR3fOt0+q8ZeEfMDiHDqw60uoF1NDg== +autocompleter@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/autocompleter/-/autocompleter-9.1.1.tgz#6ec0d71b051428ae051d0b876c03b371fdaf7054" + integrity sha512-tfgWn/koqy3fxRQR1IDJZPHmEifmICA/VIT3Aj7x8/CQddBXQ58hciYQ8n7Zfh1IVr9oyjMwvTDFXLDNTFyopg== available-typed-arrays@^1.0.5: version "1.0.5" @@ -8541,10 +8541,10 @@ multicast-dns@^7.2.5: dns-packet "^5.2.2" thunky "^1.0.2" -multiple-select-vanilla@^0.4.10: - version "0.4.10" - resolved "https://registry.yarnpkg.com/multiple-select-vanilla/-/multiple-select-vanilla-0.4.10.tgz#bf02b97cb16218e8c182ed9e84ffb166f3fdc24c" - integrity sha512-Gp07Bo4v6MnzwBALzBGIw+LP5zpuPnonZeKebm2IWnbnK8GOCvSJbOXiAN4M0TvgJgXriw8qo0+Iv3yDrqaAcQ== +multiple-select-vanilla@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/multiple-select-vanilla/-/multiple-select-vanilla-0.5.0.tgz#1af3d410b45b62fd191cdfcaa707db76f0ea1b26" + integrity sha512-a1oKpzkJNNuen1zjW8EovQ+p6Gt9eGGTFDY0o3zvYPdXgQWhe3643cJGuD8vd3G7MU9KtRPRcdKRd5qbbP28Pw== mute-stdout@^1.0.0: version "1.0.1" @@ -10494,10 +10494,10 @@ slash@^4.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== -slickgrid@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/slickgrid/-/slickgrid-4.0.1.tgz#52c53c4af7e5dc760e5ba2e0c2f13c13e7eb9248" - integrity sha512-5eB8S7QnqUM+h2aVzVgeZ1HtlqNXV82M9WYrd5/sFgYErD50PMZ2gpzXhloemqg8z2eaDysvgzGREoLLp180Lg== +slickgrid@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/slickgrid/-/slickgrid-4.1.2.tgz#f8e60a4b9102118b2dd1ccc68686f0b5fc1ca104" + integrity sha512-yXS/4k6SVpI4FacpzbAQ7GXFQGSKT3w8kn64y9YQ2by2D9kOqDigXub+LNurunPkh3BEOYxBx0kkPjy/I8BYPg== dependencies: sortablejs "^1.15.0"