From 0deede2db72881a579b68a3a60d947c92fe0ccd0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 07:16:05 +0000 Subject: [PATCH 1/5] Initial plan From f4764e31155cd45b5bfc351890f5aaf4f5daa9a1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 07:29:35 +0000 Subject: [PATCH 2/5] Migrate HTML templates and WDIO page objects to actions menu pattern Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- .../e2e/Page objects/DeviceUsers.page.ts | 27 +++++++- eform-client/e2e/Page objects/Sites.page.ts | 26 +++++++- .../Page objects/UserAdministration.page.ts | 26 +++++++- eform-client/e2e/Page objects/Workers.page.ts | 19 +++++- .../users-page/users-page.component.html | 64 ++++++++++--------- .../sites/sites/sites.component.html | 46 +++++++------ .../workers/workers/workers.component.html | 46 +++++++------ .../device-users-page.component.html | 46 +++++++------ .../email-recipients-page.component.html | 44 +++++++------ .../security-page.component.html | 56 ++++++++++++++++ .../security-page/security-page.component.ts | 39 +---------- 11 files changed, 286 insertions(+), 153 deletions(-) diff --git a/eform-client/e2e/Page objects/DeviceUsers.page.ts b/eform-client/e2e/Page objects/DeviceUsers.page.ts index 6034a53efd..426cf8807c 100644 --- a/eform-client/e2e/Page objects/DeviceUsers.page.ts +++ b/eform-client/e2e/Page objects/DeviceUsers.page.ts @@ -139,7 +139,12 @@ class DeviceUsersPage extends PageWithNavbarPage { name = '', surname = '' ) { - deviceUser.editBtn.click(); + await deviceUser.openRowMenu(); + const index = deviceUser.index - 1; + const editBtn = await $(`#editDeviceUserBtn${index}`); + await editBtn.waitForDisplayed({ timeout: 5000 }); + await editBtn.waitForClickable({ timeout: 5000 }); + await editBtn.click(); // browser.pause(5000); await (await $('#firstName')).waitForDisplayed({ timeout: 40000 }); if (name != null) { @@ -164,6 +169,7 @@ export default deviceUsersPage; export class DeviceUsersRowObject { constructor() {} + index: number; siteId: number; firstName: string; lastName: string; @@ -171,6 +177,7 @@ export class DeviceUsersRowObject { deleteBtn; async getRow(rowNum: number) { + this.index = rowNum; if ((await $$('#deviceUserId'))[rowNum - 1]) { this.siteId = +(await (await $$('#deviceUserId')[rowNum - 1]).getText()); try { @@ -189,9 +196,23 @@ export class DeviceUsersRowObject { return this; } + async openRowMenu() { + const index = this.index - 1; + const menuBtn = await $(`#action-items-${index} #actionMenu`); + await menuBtn.waitForDisplayed({ timeout: 5000 }); + await menuBtn.waitForClickable({ timeout: 5000 }); + await menuBtn.scrollIntoView(); + await menuBtn.click(); + await browser.pause(200); + } + async delete() { - this.deleteBtn.waitForClickable({ timeout: 40000 }); - this.deleteBtn.click(); + const index = this.index - 1; + await this.openRowMenu(); + const deleteBtn = await $(`#deleteDeviceUserBtn${index}`); + await deleteBtn.waitForDisplayed({ timeout: 5000 }); + await deleteBtn.waitForClickable({ timeout: 5000 }); + await deleteBtn.click(); await (await deviceUsersPage.saveDeleteBtn()).waitForClickable({ timeout: 40000, }); diff --git a/eform-client/e2e/Page objects/Sites.page.ts b/eform-client/e2e/Page objects/Sites.page.ts index 15f5a7a277..705b651d7b 100644 --- a/eform-client/e2e/Page objects/Sites.page.ts +++ b/eform-client/e2e/Page objects/Sites.page.ts @@ -139,6 +139,7 @@ export default sitesPage; export class SitesRowObject { constructor() {} + index: number; element: WebdriverIO.Element; siteId: number; units: string; @@ -148,6 +149,7 @@ export class SitesRowObject { deleteBtn: WebdriverIO.Element; async getRow(rowNum): Promise { + this.index = rowNum; this.element = (await $$('tbody > tr'))[rowNum - 1]; if (this.element) { this.siteId = +(await this.element.$('#siteUUId')).getText(); @@ -173,8 +175,23 @@ export class SitesRowObject { return this; } + async openRowMenu() { + const index = this.index - 1; + const menuBtn = await $(`#action-items-${index} #actionMenu`); + await menuBtn.waitForDisplayed({ timeout: 5000 }); + await menuBtn.waitForClickable({ timeout: 5000 }); + await menuBtn.scrollIntoView(); + await menuBtn.click(); + await browser.pause(200); + } + async openEditModal(site?: { name?: string; tags?: string[] }) { - this.editBtn.click(); + await this.openRowMenu(); + const index = this.index - 1; + const editBtn = await $(`#editSiteBtn${index}`); + await editBtn.waitForDisplayed({ timeout: 5000 }); + await editBtn.waitForClickable({ timeout: 5000 }); + await editBtn.click(); await browser.pause(500); await (await sitesPage.siteEditCancelBtn()).waitForDisplayed({ timeout: 40000 }); if (site) { @@ -209,7 +226,12 @@ export class SitesRowObject { } async openDeleteModal() { - await this.deleteBtn.click(); + await this.openRowMenu(); + const index = this.index - 1; + const deleteBtn = await $(`#deleteSiteBtn${index}`); + await deleteBtn.waitForDisplayed({ timeout: 5000 }); + await deleteBtn.waitForClickable({ timeout: 5000 }); + await deleteBtn.click(); await browser.pause(500); await (await sitesPage.siteDeleteCancelBtn()).waitForClickable({ timeout: 40000 }); } diff --git a/eform-client/e2e/Page objects/UserAdministration.page.ts b/eform-client/e2e/Page objects/UserAdministration.page.ts index 802c1eb0a2..1edb271c4d 100644 --- a/eform-client/e2e/Page objects/UserAdministration.page.ts +++ b/eform-client/e2e/Page objects/UserAdministration.page.ts @@ -196,6 +196,7 @@ export default userAdministration; export class UserAdministrationRowObject { constructor() {} + index: number; element; id: number; email: string; @@ -205,6 +206,7 @@ export class UserAdministrationRowObject { deleteBtn; async getRow(rowNum: number): Promise { + this.index = rowNum; rowNum = rowNum - 1; this.id = +await (await $('#userAdministrationId-'+rowNum)).getText(); this.email = await (await $('#userAdministrationEmail-'+rowNum)).getText(); @@ -215,8 +217,23 @@ export class UserAdministrationRowObject { return this; } + async openRowMenu() { + const index = this.index - 1; + const menuBtn = await $(`#action-items-${index} #actionMenu`); + await menuBtn.waitForDisplayed({ timeout: 5000 }); + await menuBtn.waitForClickable({ timeout: 5000 }); + await menuBtn.scrollIntoView(); + await menuBtn.click(); + await browser.pause(200); + } + public async openEdit(user: UserAdministrationObject) { - await this.editBtn.click(); + await this.openRowMenu(); + const index = this.index - 1; + const editBtn = await $(`#userAdministrationEditBtn-${index}`); + await editBtn.waitForDisplayed({ timeout: 5000 }); + await editBtn.waitForClickable({ timeout: 5000 }); + await editBtn.click(); await (await userAdministration.editFirstName()).waitForDisplayed({ timeout: 40000 }); if (user.firstName) { await (await userAdministration.editFirstName()).clearValue(); @@ -278,7 +295,12 @@ export class UserAdministrationRowObject { } public async openDelete() { - await this.deleteBtn.click(); + await this.openRowMenu(); + const index = this.index - 1; + const deleteBtn = await $(`#userAdministrationDeleteBtn-${index}`); + await deleteBtn.waitForDisplayed({ timeout: 5000 }); + await deleteBtn.waitForClickable({ timeout: 5000 }); + await deleteBtn.click(); await (await userAdministration.userDeleteCancelBtn()).waitForDisplayed({ timeout: 40000 }); } diff --git a/eform-client/e2e/Page objects/Workers.page.ts b/eform-client/e2e/Page objects/Workers.page.ts index 9bbf10e6b4..80286dabd4 100644 --- a/eform-client/e2e/Page objects/Workers.page.ts +++ b/eform-client/e2e/Page objects/Workers.page.ts @@ -56,7 +56,12 @@ export class Workers extends PageWithNavbarPage { // browser.pause(16000); } public async editWorker(worker: WorkersRowObject, firstName: string, lastName: string) { - await worker.editBtn.click(); + await worker.openRowMenu(); + const index = worker.index - 1; + const editBtn = await $(`#workerEditBtn${index}`); + await editBtn.waitForDisplayed({ timeout: 5000 }); + await editBtn.waitForClickable({ timeout: 5000 }); + await editBtn.click(); // browser.pause(8000); await (await $('#firstNameEdit')).waitForDisplayed({timeout: 8000}); await (await this.firstNameEditBox()).clearValue(); @@ -74,6 +79,7 @@ export default workers; export class WorkersRowObject { constructor(rowNumber) { + this.index = rowNumber + 1; this.siteId = +$$('#workerUID')[rowNumber + 1].getText(); this.firstName = $$('#workerFirstName')[rowNumber + 1].getText(); this.lastName = $$('#workerLastName')[rowNumber + 1].getText(); @@ -81,9 +87,20 @@ export class WorkersRowObject { this.deleteBtn = $$('#workerDeleteBtn')[rowNumber + 1]; } + index: number; siteId: number; firstName; lastName; editBtn; deleteBtn; + + async openRowMenu() { + const index = this.index - 1; + const menuBtn = await $(`#action-items-${index} #actionMenu`); + await menuBtn.waitForDisplayed({ timeout: 5000 }); + await menuBtn.waitForClickable({ timeout: 5000 }); + await menuBtn.scrollIntoView(); + await menuBtn.click(); + await browser.pause(200); + } } diff --git a/eform-client/src/app/modules/account-management/components/users/users-page/users-page.component.html b/eform-client/src/app/modules/account-management/components/users/users-page/users-page.component.html index e2fe666364..aee37fa060 100644 --- a/eform-client/src/app/modules/account-management/components/users/users-page/users-page.component.html +++ b/eform-client/src/app/modules/account-management/components/users/users-page/users-page.component.html @@ -60,36 +60,42 @@ -
- - - + + + + + + + +
diff --git a/eform-client/src/app/modules/advanced/components/sites/sites/sites.component.html b/eform-client/src/app/modules/advanced/components/sites/sites/sites.component.html index ed226ffbdb..2b47a44e01 100644 --- a/eform-client/src/app/modules/advanced/components/sites/sites/sites.component.html +++ b/eform-client/src/app/modules/advanced/components/sites/sites/sites.component.html @@ -42,27 +42,33 @@ - -
- - + + + + + +
diff --git a/eform-client/src/app/modules/advanced/components/workers/workers/workers.component.html b/eform-client/src/app/modules/advanced/components/workers/workers/workers.component.html index 7f81b3c917..751f45e63b 100644 --- a/eform-client/src/app/modules/advanced/components/workers/workers/workers.component.html +++ b/eform-client/src/app/modules/advanced/components/workers/workers/workers.component.html @@ -21,26 +21,32 @@ [rowStriped]="true" [showColumnMenuButton]="false"> - -
- - + + + + + +
diff --git a/eform-client/src/app/modules/device-users/components/device-users-page/device-users-page.component.html b/eform-client/src/app/modules/device-users/components/device-users-page/device-users-page.component.html index 3b66cd315b..f67101341a 100644 --- a/eform-client/src/app/modules/device-users/components/device-users-page/device-users-page.component.html +++ b/eform-client/src/app/modules/device-users/components/device-users-page/device-users-page.component.html @@ -74,27 +74,33 @@ N/A - -
- - + + + + + +
diff --git a/eform-client/src/app/modules/email-recipients/components/email-recipients-page/email-recipients-page.component.html b/eform-client/src/app/modules/email-recipients/components/email-recipients-page/email-recipients-page.component.html index 9d53824c9d..5ff5bff28a 100644 --- a/eform-client/src/app/modules/email-recipients/components/email-recipients-page/email-recipients-page.component.html +++ b/eform-client/src/app/modules/email-recipients/components/email-recipients-page/email-recipients-page.component.html @@ -56,24 +56,32 @@ (sortChange)="onSortTable($event)" /> - - - + + diff --git a/eform-client/src/app/modules/security/components/security-page/security-page.component.html b/eform-client/src/app/modules/security/components/security-page/security-page.component.html index 946e7d2ca1..a2b564c6a7 100644 --- a/eform-client/src/app/modules/security/components/security-page/security-page.component.html +++ b/eform-client/src/app/modules/security/components/security-page/security-page.component.html @@ -30,6 +30,7 @@ + +
+ + + + + + + + + + + + + +
+
+ this.router.navigate(['update-group', record.id], {relativeTo: this.route}), - }, - { - color: 'primary', - type: 'icon', - icon: 'summarize', - tooltip: this.translateService.stream('eForms permissions'), - click: (record) => this.router.navigate([`group/${record.id}/eforms-permissions`], {relativeTo: this.route}), - }, - { - color: 'primary', - type: 'icon', - icon: 'lock_open', - tooltip: this.translateService.stream('General Permissions'), - click: (record) => this.router.navigate([`group/${record.id}/general-permissions`], {relativeTo: this.route}), - }, - { - color: 'accent', - type: 'icon', - icon: 'settings', - tooltip: this.translateService.stream('Group settings'), - click: (record) => this.openSettingsModal(record), - }, - { - color: 'warn', - type: 'icon', - icon: 'delete', - tooltip: this.translateService.stream('Delete Group'), - click: (record) => this.openDeleteModal(record), - }, - ] }, ]; securityGroups: Paged = new Paged(); From 77d32992a779dd0c0b89669197cdab0692f2bc8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 07:33:25 +0000 Subject: [PATCH 3/5] Update Cypress page objects to use actions menu pattern Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- eform-client/cypress/e2e/DeviceUsers.page.ts | 16 ++++++++-- eform-client/cypress/e2e/Sites.page.ts | 31 +++++++++---------- .../cypress/e2e/UserAdministration.page.ts | 16 ++++++++-- eform-client/cypress/e2e/Workers.page.ts | 12 ++++++- 4 files changed, 54 insertions(+), 21 deletions(-) diff --git a/eform-client/cypress/e2e/DeviceUsers.page.ts b/eform-client/cypress/e2e/DeviceUsers.page.ts index 1ee58276a9..ab10c5052d 100644 --- a/eform-client/cypress/e2e/DeviceUsers.page.ts +++ b/eform-client/cypress/e2e/DeviceUsers.page.ts @@ -156,7 +156,9 @@ class DeviceUsersPage extends PageWithNavbarPage{ name = '', surname = '' ): void { - deviceUser.editBtn().should('be.visible').click(); + const index = deviceUser.index - 1; + deviceUser.openRowMenu(); + cy.get(`#editDeviceUserBtn${index}`).should('be.visible').click(); // @ts-ignore cy.get('#firstName').should('be.visible'); if (name !== '') { @@ -178,6 +180,7 @@ const deviceUsersPage = new DeviceUsersPage(); export default deviceUsersPage; export class DeviceUsersRowObject { + index: number; siteId: number; firstName: string; lastName: string; @@ -187,6 +190,7 @@ export class DeviceUsersRowObject { deleteBtn: Cypress.Chainable>; getRow(rowNum: number) { + this.index = rowNum; // @ts-ignore if (cy.get('#deviceUserId').eq(rowNum - 1).should('exist')) { // @ts-ignore @@ -203,8 +207,16 @@ export class DeviceUsersRowObject { return this; } + openRowMenu() { + const index = this.index - 1; + cy.get(`#action-items-${index} #actionMenu`).should('be.visible').click(); + cy.wait(200); + } + delete() { - this.deleteBtn.should('be.visible').click(); + const index = this.index - 1; + this.openRowMenu(); + cy.get(`#deleteDeviceUserBtn${index}`).should('be.visible').click(); deviceUsersPage.saveDeleteBtn().should('be.visible').click(); // @ts-ignore cy.get('#spinner-animation').should('not.exist', { timeout: 40000 }); diff --git a/eform-client/cypress/e2e/Sites.page.ts b/eform-client/cypress/e2e/Sites.page.ts index 6e4a64c4d5..c23197b64b 100644 --- a/eform-client/cypress/e2e/Sites.page.ts +++ b/eform-client/cypress/e2e/Sites.page.ts @@ -125,6 +125,7 @@ export default sitesPage; export class SitesRowObject { constructor() {} + index: number; element: Cypress.Chainable>; siteId: number; units: string; @@ -134,6 +135,7 @@ export class SitesRowObject { deleteBtn: Cypress.Chainable>; getRow(rowNum): Promise { + this.index = rowNum; this.element = cy.get('tbody > tr').eq(rowNum - 1); if (this.element) { this.siteId = +(this.element.find('#siteUUId').invoke('text')); @@ -146,6 +148,13 @@ export class SitesRowObject { } return this; } + + openRowMenu() { + const index = this.index - 1; + cy.get(`#action-items-${index} #actionMenu`).should('be.visible').click(); + cy.wait(200); + } + closeEditModal(clickCancel = false) { if (clickCancel) { sitesPage.siteEditCancelBtn().click(); @@ -156,22 +165,10 @@ export class SitesRowObject { sitesPage.sitesManageTagsBtn().should('be.visible', { timeout: 40000 }); } - getRow(rowNum): Promise { - this.element = Cypress.$$('tbody > tr').eq(rowNum - 1); - if (this.element) { - this.siteId = +this.element.find('#siteUUId').text(); - this.units = this.element.find('#units').text(); - this.siteName = this.element.find('#siteName').text(); - const list = this.element.find('mat-chip-list mat-chip > span'); - this.tags = Promise.all(list.map((_, element) => Cypress.$(element).text())); - this.editBtn = this.element.find('#editSiteBtn'); - this.deleteBtn = this.element.find('#deleteSiteBtn'); - } - return this; - } - openEditModal(site?: { name?: string; tags?: string[] }) { - this.editBtn.click(); + const index = this.index - 1; + this.openRowMenu(); + cy.get(`#editSiteBtn${index}`).should('be.visible').click(); cy.wait(500); sitesPage.siteEditCancelBtn().should('be.visible', {timeout: 40000}); if (site) { @@ -196,7 +193,9 @@ export class SitesRowObject { } openDeleteModal() { - this.deleteBtn.click(); + const index = this.index - 1; + this.openRowMenu(); + cy.get(`#deleteSiteBtn${index}`).should('be.visible').click(); cy.wait(500); sitesPage.siteDeleteCancelBtn().should('be.visible', {timeout: 40000}).click(); } diff --git a/eform-client/cypress/e2e/UserAdministration.page.ts b/eform-client/cypress/e2e/UserAdministration.page.ts index 330b2cb3bc..b8087d4c29 100644 --- a/eform-client/cypress/e2e/UserAdministration.page.ts +++ b/eform-client/cypress/e2e/UserAdministration.page.ts @@ -170,6 +170,7 @@ const userAdministrationPage = new UserAdministrationPage(); export default userAdministrationPage; export class UserAdministrationRowObject { + index: number; id: number; email: string; fullName: string; @@ -178,6 +179,7 @@ export class UserAdministrationRowObject { deleteBtn: Cypress.Chainable>; getRow(rowNum: number) { + this.index = rowNum; const index = rowNum - 1; cy.get(`#userAdministrationId-${index}`).invoke('text').then(text => { @@ -199,8 +201,16 @@ export class UserAdministrationRowObject { return this; } + openRowMenu() { + const index = this.index - 1; + cy.get(`#action-items-${index} #actionMenu`).should('be.visible').click(); + cy.wait(200); + } + edit(user: UserAdministrationObject, clickCancel = false) { - this.editBtn.should('be.visible').click(); + const index = this.index - 1; + this.openRowMenu(); + cy.get(`#userAdministrationEditBtn-${index}`).should('be.visible').click(); cy.get('#editFirstName').should('be.visible'); if (user.firstName) { @@ -257,7 +267,9 @@ export class UserAdministrationRowObject { } delete(clickCancel = false) { - this.deleteBtn.should('be.visible').click(); + const index = this.index - 1; + this.openRowMenu(); + cy.get(`#userAdministrationDeleteBtn-${index}`).should('be.visible').click(); cy.get('#userDeleteCancelBtn').should('be.visible'); if (clickCancel) { diff --git a/eform-client/cypress/e2e/Workers.page.ts b/eform-client/cypress/e2e/Workers.page.ts index 485c56750c..a203730681 100644 --- a/eform-client/cypress/e2e/Workers.page.ts +++ b/eform-client/cypress/e2e/Workers.page.ts @@ -127,7 +127,9 @@ class WorkersPage extends PageWithNavbarPage { firstName = '', lastName = '' ): void { - worker.editBtn().should('be.visible').click(); + const index = worker.index - 1; + worker.openRowMenu(); + cy.get(`#workerEditBtn${index}`).should('be.visible').click(); // @ts-ignore cy.get('#firstNameEdit').should('be.visible'); if (firstName !== '') { @@ -152,6 +154,7 @@ const workersPage = new WorkersPage(); export default workersPage; export class WorkersRowObject { + index: number; siteId: number; firstName: string; lastName: string; @@ -161,6 +164,7 @@ export class WorkersRowObject { deleteBtn: Cypress.Chainable>; getRow(rowNum: number) { + this.index = rowNum; // @ts-ignore if (cy.get('#workerUID').eq(rowNum - 1).should('exist')) { // @ts-ignore @@ -176,4 +180,10 @@ export class WorkersRowObject { } return this; } + + openRowMenu() { + const index = this.index - 1; + cy.get(`#action-items-${index} #actionMenu`).should('be.visible').click(); + cy.wait(200); + } } From a0a92193f1e1e74ff8ca4804b1e607d2e0e541f6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 08:02:30 +0000 Subject: [PATCH 4/5] Add missing MatMenu imports to module files Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- .../modules/account-management/account-management.module.ts | 4 ++++ .../src/app/modules/device-users/device-users.module.ts | 4 ++++ .../app/modules/email-recipients/email-recipients.module.ts | 4 ++++ eform-client/src/app/modules/security/security.module.ts | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/eform-client/src/app/modules/account-management/account-management.module.ts b/eform-client/src/app/modules/account-management/account-management.module.ts index 776499bbb9..9c49b03f07 100644 --- a/eform-client/src/app/modules/account-management/account-management.module.ts +++ b/eform-client/src/app/modules/account-management/account-management.module.ts @@ -24,6 +24,7 @@ import {MatInputModule} from '@angular/material/input'; import {MatIconModule} from '@angular/material/icon'; import {FileUploadModule} from "ng2-file-upload"; import {MatPasswordStrengthModule} from '@angular-material-extensions/password-strength'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; @NgModule({ imports: [ @@ -46,6 +47,9 @@ import {MatPasswordStrengthModule} from '@angular-material-extensions/password-s MatIconModule, FileUploadModule, MatPasswordStrengthModule, + MatMenu, + MatMenuItem, + MatMenuTrigger, ], declarations: [ ChangePasswordComponent, diff --git a/eform-client/src/app/modules/device-users/device-users.module.ts b/eform-client/src/app/modules/device-users/device-users.module.ts index fd476aaf26..731ba04fba 100644 --- a/eform-client/src/app/modules/device-users/device-users.module.ts +++ b/eform-client/src/app/modules/device-users/device-users.module.ts @@ -19,6 +19,7 @@ import {MatInputModule} from '@angular/material/input'; import {MtxGridModule} from '@ng-matero/extensions/grid'; import {MatIconModule} from '@angular/material/icon'; import {MatDialogModule} from '@angular/material/dialog'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; @NgModule({ imports: [ @@ -36,6 +37,9 @@ import {MatDialogModule} from '@angular/material/dialog'; MtxGridModule, MatIconModule, MatDialogModule, + MatMenu, + MatMenuItem, + MatMenuTrigger, ], declarations: [ DeviceUsersPageComponent, diff --git a/eform-client/src/app/modules/email-recipients/email-recipients.module.ts b/eform-client/src/app/modules/email-recipients/email-recipients.module.ts index 71e28484dd..27577ab9f3 100644 --- a/eform-client/src/app/modules/email-recipients/email-recipients.module.ts +++ b/eform-client/src/app/modules/email-recipients/email-recipients.module.ts @@ -21,6 +21,7 @@ import {MatInputModule} from '@angular/material/input'; import {MtxSelectModule} from '@ng-matero/extensions/select'; import {MtxGridModule} from '@ng-matero/extensions/grid'; import {MatDialogModule} from '@angular/material/dialog'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; @NgModule({ declarations: [ @@ -47,6 +48,9 @@ import {MatDialogModule} from '@angular/material/dialog'; MtxSelectModule, MtxGridModule, MatDialogModule, + MatMenu, + MatMenuItem, + MatMenuTrigger, ], }) export class EmailRecipientsModule { diff --git a/eform-client/src/app/modules/security/security.module.ts b/eform-client/src/app/modules/security/security.module.ts index d745518fc9..9aababcf89 100644 --- a/eform-client/src/app/modules/security/security.module.ts +++ b/eform-client/src/app/modules/security/security.module.ts @@ -26,6 +26,8 @@ import {MatDialogModule} from '@angular/material/dialog'; import {MatCardModule} from '@angular/material/card'; import {MtxGridModule} from '@ng-matero/extensions/grid'; import {MtxSelectModule} from '@ng-matero/extensions/select'; +import {MatIconModule} from '@angular/material/icon'; +import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu'; @NgModule({ imports: [ @@ -43,6 +45,10 @@ import {MtxSelectModule} from '@ng-matero/extensions/select'; MatDialogModule, MatCardModule, MtxSelectModule, + MatIconModule, + MatMenu, + MatMenuItem, + MatMenuTrigger, ], declarations: [ SecurityPageComponent, From e85f51c82a85281557a538272cc06c36f8a3a903 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 16 Nov 2025 09:48:20 +0000 Subject: [PATCH 5/5] Fix WDIO device users tests to use actions menu pattern Co-authored-by: renemadsen <76994+renemadsen@users.noreply.github.com> --- .../device-users/device-users.delete.spec.ts | 16 +++++++++++----- .../Tests/device-users/device-users.edit.spec.ts | 7 ++++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/eform-client/e2e/Tests/device-users/device-users.delete.spec.ts b/eform-client/e2e/Tests/device-users/device-users.delete.spec.ts index 9023f5e43d..da3ebcaa22 100644 --- a/eform-client/e2e/Tests/device-users/device-users.delete.spec.ts +++ b/eform-client/e2e/Tests/device-users/device-users.delete.spec.ts @@ -15,9 +15,12 @@ describe('Device users page', function () { const rowNumBeforeDelete = await deviceUsersPage.rowNum(); await $('#deviceUserId').waitForDisplayed({ timeout: 40000 }); const lastDeviceUser = await deviceUsersPage.getDeviceUser(rowNumBeforeDelete); - await lastDeviceUser.deleteBtn.waitForDisplayed({ timeout: 5000 }); - await lastDeviceUser.deleteBtn.waitForClickable({ timeout: 40000 }); - await lastDeviceUser.deleteBtn.click(); + await lastDeviceUser.openRowMenu(); + const index = lastDeviceUser.index - 1; + const deleteBtn = await $(`#deleteDeviceUserBtn${index}`); + await deleteBtn.waitForDisplayed({ timeout: 5000 }); + await deleteBtn.waitForClickable({ timeout: 5000 }); + await deleteBtn.click(); await (await deviceUsersPage.cancelDeleteBtn()).click(); await myEformsPage.Navbar.goToDeviceUsersPage(); const rowNumAfterCancelDelete = await deviceUsersPage.rowNum(); @@ -28,8 +31,11 @@ describe('Device users page', function () { const rowNumBeforeDelete = await deviceUsersPage.rowNum(); await (await $('#deviceUserId')).waitForDisplayed({ timeout: 40000 }); const lastDeviceUser = await deviceUsersPage.getDeviceUser(rowNumBeforeDelete); - await lastDeviceUser.deleteBtn.waitForDisplayed({ timeout: 5000 }); - await lastDeviceUser.deleteBtn.click(); + await lastDeviceUser.openRowMenu(); + const index = lastDeviceUser.index - 1; + const deleteBtn = await $(`#deleteDeviceUserBtn${index}`); + await deleteBtn.waitForDisplayed({ timeout: 5000 }); + await deleteBtn.click(); await (await deviceUsersPage.saveDeleteBtn()).click(); await myEformsPage.Navbar.goToDeviceUsersPage(); const rowNumAfterDelete = await deviceUsersPage.rowNum(); diff --git a/eform-client/e2e/Tests/device-users/device-users.edit.spec.ts b/eform-client/e2e/Tests/device-users/device-users.edit.spec.ts index 2c9eac177a..54843dc30f 100644 --- a/eform-client/e2e/Tests/device-users/device-users.edit.spec.ts +++ b/eform-client/e2e/Tests/device-users/device-users.edit.spec.ts @@ -91,7 +91,12 @@ describe('Device users page', function () { const lastDeviceUserBeforeEdit = await deviceUsersPage.getDeviceUser( rowNumBeforeEdit ); - await lastDeviceUserBeforeEdit.editBtn.click(); + await lastDeviceUserBeforeEdit.openRowMenu(); + const index = lastDeviceUserBeforeEdit.index - 1; + const editBtn = await $(`#editDeviceUserBtn${index}`); + await editBtn.waitForDisplayed({ timeout: 5000 }); + await editBtn.waitForClickable({ timeout: 5000 }); + await editBtn.click(); // browser.pause(4000); await (await $('#firstName')).waitForDisplayed({ timeout: 10000 }); await (await deviceUsersPage.editFirstNameInput()).click();