From 60c080d71280a0689e2b08589603fe76f2d515e9 Mon Sep 17 00:00:00 2001 From: RehanY147 <rehanyousaf147@gmail.com> Date: Thu, 12 Sep 2024 16:17:41 +0500 Subject: [PATCH] NAS-130854 / 25.04 / Refactor `trackBy` for `ix-table-body` (#10604) --- src/app/core/testing/utils/fake-job.utils.ts | 1 + .../ix-cell-actions.component.html | 26 +-- .../ix-cell-actions.component.ts | 2 +- .../ix-cell-checkbox.component.html | 4 +- .../ix-cell-checkbox.component.spec.ts | 9 +- .../ix-cell-checkbox.component.ts | 4 +- .../ix-cell-date/ix-cell-date.component.html | 4 +- .../ix-cell-date.component.spec.ts | 4 +- .../ix-cell-date/ix-cell-date.component.ts | 2 +- .../ix-cell-relative-date.component.html | 2 +- .../ix-cell-relative-date.component.spec.ts | 2 +- .../ix-cell-relative-date.component.ts | 2 +- .../ix-cell-schedule.component.html | 2 +- .../ix-cell-schedule.component.spec.ts | 2 +- .../ix-cell-schedule.component.ts | 2 +- .../ix-cell-size/ix-cell-size.component.html | 2 +- .../ix-cell-size.component.spec.ts | 2 +- .../ix-cell-size/ix-cell-size.component.ts | 2 +- .../ix-cell-state-button.component.html | 8 +- .../ix-cell-state-button.component.spec.ts | 38 +++- .../ix-cell-state-button.component.ts | 163 +++++++++++------- .../ix-cell-template.component.ts | 2 +- .../ix-cell-text/ix-cell-text.component.html | 2 +- .../ix-cell-text.component.spec.ts | 2 +- .../ix-cell-text/ix-cell-text.component.ts | 6 +- .../ix-cell-toggle.component.html | 10 +- .../ix-cell-toggle.component.spec.ts | 9 +- .../ix-cell-toggle.component.ts | 4 +- .../ix-cell-yes-no.component.html | 2 +- .../ix-cell-yes-no.component.spec.ts | 2 +- .../ix-cell-yes-no.component.ts | 2 +- .../ix-table-body.component.html | 9 +- .../ix-table-body.component.spec.ts | 2 +- .../ix-table-body/ix-table-body.component.ts | 15 +- ...x-table-columns-selector.component.spec.ts | 4 +- .../ix-table-columns-selector.component.ts | 2 +- .../ix-table-details-row.component.ts | 2 +- .../ix-header-cell-checkbox.component.ts | 2 +- .../ix-header-cell-text.component.ts | 2 +- .../ix-table-head.component.spec.ts | 2 +- .../ix-table-head/ix-table-head.component.ts | 2 +- .../directives/ix-body-cell.directive.ts | 28 ++- .../directives/ix-header-cell.directive.ts | 5 +- .../interfaces/column-component.class.ts | 40 +++++ .../interfaces/table-column.interface.ts | 35 ---- src/app/modules/ix-table/utils.ts | 18 +- .../groups/group-list/group-list.component.ts | 2 +- .../privilege-list.component.ts | 2 +- .../users/user-list/user-list.component.ts | 2 +- .../api-key-list/api-key-list.component.ts | 2 +- .../docker-images-list.component.ts | 2 +- .../audit/components/audit/audit.component.ts | 2 +- .../cloud-credentials-card.component.ts | 2 +- .../ssh-connection-card.component.ts | 2 +- .../ssh-keypair-card.component.ts | 2 +- .../acme-dns-authenticator-list.component.ts | 2 +- .../certificate-authority-list.component.ts | 2 +- .../certificate-list.component.ts | 2 +- .../csr-list/csr-list.component.ts | 2 +- .../cloud-backup-card.component.spec.ts | 15 ++ .../cloud-backup-card.component.ts | 2 +- .../cloud-backup-snapshots.component.ts | 2 +- .../cloud-backup-list.component.spec.ts | 10 ++ .../cloud-backup-list.component.ts | 2 +- .../cloudsync-list.component.spec.ts | 10 ++ .../cloudsync-list.component.ts | 4 +- .../cloudsync-task-card.component.ts | 3 +- .../replication-list.component.spec.ts | 6 +- .../replication-list.component.ts | 6 +- .../replication-task-card.component.ts | 2 +- .../rsync-task-card.component.ts | 2 +- .../rsync-task-list.component.spec.ts | 18 +- .../rsync-task-list.component.ts | 2 +- .../scrub-list/scrub-list.component.ts | 2 +- .../scrub-task-card.component.ts | 2 +- .../smart-task-card.component.ts | 2 +- .../smart-task-list.component.ts | 2 +- .../snapshot-task-card.component.ts | 2 +- .../snapshot-task-list.component.ts | 4 +- .../vmware-snapshot-list.component.ts | 2 +- .../dataset-quotas-list.component.ts | 2 +- .../snapshot-list/snapshot-list.component.ts | 2 +- .../idmap-list/idmap-list.component.ts | 2 +- .../kerberos-keytabs-list.component.ts | 2 +- .../kerberos-realms-list.component.ts | 2 +- .../jobs/jobs-list/jobs-list.component.ts | 2 +- .../interfaces-card.component.ts | 9 +- .../ip-addresses-cell.component.spec.ts | 4 +- .../ip-addresses-cell.component.ts | 22 ++- .../ipmi-card/ipmi-card.component.ts | 2 +- .../static-routes-card.component.ts | 2 +- src/app/pages/network/tests/checkin.spec.ts | 4 - .../reporting-exporters-list.component.ts | 2 +- src/app/pages/services/services.component.ts | 2 +- .../iscsi-card/iscsi-card.component.ts | 2 +- .../nfs-card/nfs-card.component.ts | 2 +- .../smb-card/smb-card.component.ts | 2 +- .../associated-target-list.component.ts | 2 +- .../authorized-access-list.component.ts | 2 +- .../extent-list/extent-list.component.ts | 2 +- .../initiator-list.component.ts | 2 +- .../portal-list/portal-list.component.ts | 2 +- .../target-list/target-list.component.ts | 2 +- .../nfs/nfs-list/nfs-list.component.ts | 2 +- .../nfs-session-list.component.ts | 6 +- .../smb/smb-list/smb-list.component.ts | 2 +- .../smb-lock-list/smb-lock-list.component.ts | 2 +- .../smb-notification-list.component.ts | 2 +- .../smb-open-files.component.ts | 2 +- .../smb-session-list.component.ts | 2 +- .../smb-share-list.component.ts | 2 +- .../disk-list/disk-list.component.ts | 4 +- .../smart-test-result-list.component.spec.ts | 4 +- .../smart-test-result-list.component.ts | 4 +- .../access-card/access-card.component.ts | 2 +- .../allowed-addresses-card.component.ts | 2 +- .../cron/cron-card/cron-card.component.ts | 2 +- .../cron/cron-list/cron-list.component.ts | 4 +- .../init-shutdown-card.component.ts | 2 +- .../init-shutdown-list.component.ts | 2 +- .../sysctl-card/sysctl-card.component.ts | 2 +- .../tunable-list/tunable-list.component.ts | 2 +- .../alert-service-list.component.ts | 2 +- .../bootenv-list/bootenv-list.component.ts | 2 +- .../jbof-list/jbof-list.component.ts | 2 +- .../elements-page/elements-page.component.ts | 2 +- .../ntp-server-card.component.ts | 2 +- .../device-list/device-list.component.ts | 2 +- src/app/pages/vm/vm-list/vm-list.component.ts | 4 +- tsconfig.strictNullChecks.json | 2 +- 130 files changed, 462 insertions(+), 301 deletions(-) create mode 100644 src/app/modules/ix-table/interfaces/column-component.class.ts delete mode 100644 src/app/modules/ix-table/interfaces/table-column.interface.ts diff --git a/src/app/core/testing/utils/fake-job.utils.ts b/src/app/core/testing/utils/fake-job.utils.ts index f181250d917..e8e2f5a4d6f 100644 --- a/src/app/core/testing/utils/fake-job.utils.ts +++ b/src/app/core/testing/utils/fake-job.utils.ts @@ -13,6 +13,7 @@ export function fakeSuccessfulJob<T = void, A = unknown[]>( exception: '', id: 0, result: jobResult, + time_finished: { $date: 12345678900 }, state: JobState.Success, } as Job<T, A>; } diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.html index fb2fb0d6764..96d4f8abeed 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.html @@ -1,15 +1,15 @@ <div class="actions"> @for (action of actions; track action) { @if (action.requiredRoles?.length || action.dynamicRequiredRoles) { - <div [matTooltip]="action.dynamicTooltip ? (action.dynamicTooltip(row) | async) : action.tooltip || ''"> - @if (action.hidden ? !(action.hidden(row) | async) : true) { + <div [matTooltip]="action.dynamicTooltip ? (action.dynamicTooltip(row()) | async) : action.tooltip || ''"> + @if (action.hidden ? !(action.hidden(row()) | async) : true) { <button - *ixRequiresRoles="action?.dynamicRequiredRoles ? (action.dynamicRequiredRoles(row) | async) : action.requiredRoles" + *ixRequiresRoles="action?.dynamicRequiredRoles ? (action.dynamicRequiredRoles(row()) | async) : action.requiredRoles" mat-icon-button - [ixTest]="[rowTestId(row), action.iconName, 'row-action']" - [attr.aria-label]="(action.dynamicTooltip ? (action.dynamicTooltip(row) | async) : action.tooltip || '') + ' ' + getAriaLabel(row)" - [disabled]="action.disabled ? (action.disabled(row) | async) : false" - (click)="$event.stopPropagation(); action.onClick(row)" + [ixTest]="[uniqueRowTag(row()), action.iconName, 'row-action']" + [attr.aria-label]="(action.dynamicTooltip ? (action.dynamicTooltip(row()) | async) : action.tooltip || '') + ' ' + getAriaLabel(row())" + [disabled]="action.disabled ? (action.disabled(row()) | async) : false" + (click)="$event.stopPropagation(); action.onClick(row())" > <ix-icon [name]="action.iconName"></ix-icon> </button> @@ -18,15 +18,15 @@ } @if (!action.requiredRoles?.length && !action.dynamicRequiredRoles) { <div - [matTooltip]="action.dynamicTooltip ? (action.dynamicTooltip(row) | async) : action.tooltip || ''" + [matTooltip]="action.dynamicTooltip ? (action.dynamicTooltip(row()) | async) : action.tooltip || ''" > - @if (action.hidden ? !(action.hidden(row) | async) : true) { + @if (action.hidden ? !(action.hidden(row()) | async) : true) { <button mat-icon-button - [ixTest]="[rowTestId(row), action.iconName, 'row-action']" - [attr.aria-label]="(action.dynamicTooltip ? (action.dynamicTooltip(row) | async) : action.tooltip || '') + ' ' + getAriaLabel(row)" - [disabled]="action.disabled ? (action.disabled(row) | async) : false" - (click)="$event.stopPropagation(); action.onClick(row)" + [ixTest]="[uniqueRowTag(row()), action.iconName, 'row-action']" + [attr.aria-label]="(action.dynamicTooltip ? (action.dynamicTooltip(row()) | async) : action.tooltip || '') + ' ' + getAriaLabel(row())" + [disabled]="action.disabled ? (action.disabled(row()) | async) : false" + (click)="$event.stopPropagation(); action.onClick(row())" > <ix-icon [name]="action.iconName"></ix-icon> </button> diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.ts index 3b100e6199c..8b54f5038a5 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/ix-cell-actions.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { Role } from 'app/enums/role.enum'; import { IconActionConfig } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-actions/icon-action-config.interface'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-actions', diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.html index 83165205af1..781d6328f51 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.html @@ -1,8 +1,8 @@ <mat-checkbox color="primary" - [ixTest]="[title, rowTestId(row), 'row-checkbox']" + [ixTest]="[title, uniqueRowTag(row()), 'row-checkbox']" [checked]="checked" - [aria-label]="(checked ? ('Uncheck' | translate) : ('Check' | translate)) + ' ' + getAriaLabel(row)" + [aria-label]="(checked ? ('Uncheck' | translate) : ('Check' | translate)) + ' ' + getAriaLabel(row())" (change)="onCheckboxChange($event)" (click)="$event.stopPropagation()" ></mat-checkbox> diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.spec.ts index 9136029e6a3..d9c8a0b3d46 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.spec.ts @@ -22,7 +22,7 @@ describe('IxCellCheckboxComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'booleanField'; spectator.component.setRow({ booleanField: true }); - spectator.component.rowTestId = (row) => 'checkbox-' + row.booleanField.toString(); + spectator.component.uniqueRowTag = (row) => 'checkbox-' + row.booleanField.toString(); spectator.component.ariaLabels = () => ['Label 1', 'Label 2']; spectator.detectChanges(); @@ -40,8 +40,9 @@ describe('IxCellCheckboxComponent', () => { expect(spectator.component.onRowCheck).toHaveBeenCalledWith({ booleanField: true }, false); }); - it('gets aria label correctly', () => { - const ariaLabel = spectator.component.getAriaLabel(spectator.component.getRow()); - expect(ariaLabel).toBe('Label 1 Label 2'); + it('gets aria label correctly', async () => { + const checkbox = await loader.getHarness(MatCheckboxHarness); + const ariaLabel = await checkbox.getAriaLabel(); + expect(ariaLabel).toBe('Uncheck Label 1 Label 2'); }); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.ts index 3c323aef325..c5fcf39aede 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { MatCheckboxChange } from '@angular/material/checkbox'; import { IxHeaderCellCheckboxComponent } from 'app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-checkbox/ix-header-cell-checkbox.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-checkbox', @@ -16,7 +16,7 @@ export class IxCellCheckboxComponent<T> extends ColumnComponent<T> { } onCheckboxChange(event: MatCheckboxChange): void { - this.onRowCheck(this.row, event.checked); + this.onRowCheck(this.row(), event.checked); } } diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.html index 5ea825404fb..c658679f1d2 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.html @@ -1,10 +1,10 @@ @if (date) { <ix-date - [ixTest]="[title, rowTestId(row), 'row-date']" + [ixTest]="[title, uniqueRowTag(row()), 'row-date']" [date]="date" ></ix-date> } @else { - <span [ixTest]="[title, rowTestId(row), 'row-date']"> + <span [ixTest]="[title, uniqueRowTag(row()), 'row-date']"> {{ 'N/A' | translate }} </span> } diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.spec.ts index a556d0a7ab6..07fce5a8b9a 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.spec.ts @@ -30,7 +30,7 @@ describe('IxCellDateComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'dateField'; spectator.component.setRow({ dateField: new Date('2023-07-12 09:10:00') }); - spectator.component.rowTestId = () => ''; + spectator.component.uniqueRowTag = () => ''; spectator.detectChanges(); }); @@ -44,7 +44,7 @@ describe('IxCellDateComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'dateField'; spectator.component.setRow({ dateField: null }); - spectator.component.rowTestId = () => ''; + spectator.component.uniqueRowTag = () => ''; spectator.detectChanges(); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.ts index edf992eceae..d0fecb64752 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-date/ix-cell-date.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ApiTimestamp } from 'app/interfaces/api-date.interface'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-date', diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.html index 0b1122b6111..644787db15c 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.html @@ -1,4 +1,4 @@ <span [matTooltip]="dateTooltip" - [ixTest]="[title, rowTestId(row), 'row-relative-date']" + [ixTest]="[title, uniqueRowTag(row()), 'row-relative-date']" >{{ date }}</span> diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.spec.ts index 0704fc23746..6e4116690b8 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.spec.ts @@ -28,7 +28,7 @@ describe('IxCellRelativeDateComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'dateField'; spectator.component.setRow({ dateField: new Date(new Date().getTime() - (oneDayMillis * 10)) }); - spectator.component.rowTestId = () => ''; + spectator.component.uniqueRowTag = () => ''; spectator.detectChanges(); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.ts index 06c0046810d..7d03a6ca2f5 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-relative-date/ix-cell-relative-date.component.ts @@ -3,7 +3,7 @@ import { TranslateService } from '@ngx-translate/core'; import { isValid } from 'date-fns'; import { utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz'; import { formatDistanceToNowShortened } from 'app/helpers/format-distance-to-now-shortened'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; import { FormatDateTimePipe } from 'app/modules/pipes/format-date-time/format-datetime.pipe'; import { LocaleService } from 'app/services/locale.service'; diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.html index 77978067dab..9fd84cc937d 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.html @@ -1,3 +1,3 @@ <span - [ixTest]="[title, rowTestId(row), 'row-schedule']" + [ixTest]="[title, uniqueRowTag(row()), 'row-schedule']" >{{ value | scheduleToCrontab }}</span> diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.spec.ts index 3256893dc56..0ed060df033 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.spec.ts @@ -26,7 +26,7 @@ describe('IxCellScheduleComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'scheduleField'; spectator.component.setRow({ scheduleField: schedule }); - spectator.component.rowTestId = () => ''; + spectator.component.uniqueRowTag = () => ''; spectator.detectChanges(); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.ts index 789a48a4c06..914a69c94df 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-schedule/ix-cell-schedule.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-schedule', diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.html index 08a64f578d6..5bc73c19d30 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.html @@ -1,3 +1,3 @@ <span - [ixTest]="[title, rowTestId(row), 'row-size']" + [ixTest]="[title, uniqueRowTag(row()), 'row-size']" >{{ size | ixFileSize }}</span> \ No newline at end of file diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.spec.ts index 89e9695a20f..ea64480abbb 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.spec.ts @@ -18,7 +18,7 @@ describe('IxCellSizeComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'numberField'; spectator.component.setRow({ numberField: 5 * 1024 * 1024 * 1024 }); - spectator.component.rowTestId = () => ''; + spectator.component.uniqueRowTag = () => ''; spectator.detectChanges(); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.ts index 1ea31e2baff..9dff82e564e 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-size/ix-cell-size.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-size', diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.html index b91ba2efc03..56a27b3f5a9 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.html @@ -1,15 +1,15 @@ -@if (state) { +@if (state()) { <button mat-stroked-button class="state-button" matTooltipPosition="above" - [ixTest]="[title, rowTestId(row), 'row-state']" + [ixTest]="[title, uniqueRowTag(row()), 'row-state']" [ngClass]="getButtonClass()" [matTooltip]="tooltip" - [attr.aria-label]="getAriaLabel(row)" + [attr.aria-label]="getAriaLabel(row())" (click)="$event.stopPropagation(); onButtonClick()" > - {{ state }} + {{ state() }} @if (warnings?.length > 0) { <div class="label-warning-icon"> <ix-icon name="mdi-alert"></ix-icon> diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.spec.ts index ecc6a20c70c..2b6bcd9e465 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.spec.ts @@ -4,12 +4,16 @@ import { MatButtonHarness } from '@angular/material/button/testing'; import { MatDialog } from '@angular/material/dialog'; import { Spectator } from '@ngneat/spectator'; import { createComponentFactory, mockProvider } from '@ngneat/spectator/jest'; +import { provideMockStore } from '@ngrx/store/testing'; +import { of } from 'rxjs'; import { JobState } from 'app/enums/job-state.enum'; import { Job } from 'app/interfaces/job.interface'; import { ShowLogsDialogComponent } from 'app/modules/dialog/components/show-logs-dialog/show-logs-dialog.component'; +import { DialogService } from 'app/modules/dialog/dialog.service'; import { IxIconHarness } from 'app/modules/ix-icon/ix-icon.harness'; import { IxCellStateButtonComponent } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component'; import { IxTableModule } from 'app/modules/ix-table/ix-table.module'; +import { selectJobs } from 'app/modules/jobs/store/job.selectors'; interface TestTableData { state: JobState; @@ -26,9 +30,28 @@ describe('IxCellStateButtonComponent', () => { imports: [IxTableModule], detectChanges: false, providers: [ + provideMockStore({ + selectors: [ + { + selector: selectJobs, + value: [{ + id: 123456, + logs_excerpt: 'completed', + state: JobState.Success, + } as Job], + }, + ], + }), mockProvider(MatDialog, { open: jest.fn(), }), + mockProvider(DialogService, { + jobDialog: jest.fn(() => { + return { + afterClosed: jest.fn(() => of()), + }; + }), + }), ], }); @@ -37,12 +60,18 @@ describe('IxCellStateButtonComponent', () => { spectator.component.propertyName = 'state'; spectator.component.setRow({ state: JobState.Success, - job: { id: 123456, logs_excerpt: 'completed' }, + job: { id: 123456, logs_excerpt: 'completed', state: JobState.Success }, warnings: [{}, {}], } as TestTableData); spectator.component.getJob = (row) => row.job; - spectator.component.rowTestId = () => ''; + spectator.component.uniqueRowTag = () => ''; spectator.component.ariaLabels = () => ['Label 1', 'Label 2']; + spectator.component.job.set({ + id: 123456, + logs_excerpt: 'completed', + state: JobState.Success, + } as Job); + spectator.component.ngOnInit(); spectator.detectChanges(); loader = TestbedHarnessEnvironment.loader(spectator.fixture); @@ -51,6 +80,7 @@ describe('IxCellStateButtonComponent', () => { it('shows status text', async () => { const button = await loader.getHarness(MatButtonHarness); expect(await button.getText()).toBe(JobState.Success); + expect(await (await button.host()).hasClass('fn-theme-green')).toBeTruthy(); }); it('sets class', async () => { @@ -89,7 +119,7 @@ describe('IxCellStateButtonComponent', () => { }); it('gets aria label correctly', () => { - const ariaLabel = spectator.component.getAriaLabel(spectator.component.getRow()); - expect(ariaLabel).toBe('Label 1 Label 2'); + const button = spectator.query('button'); + expect(button.getAttribute('aria-label')).toBe('Label 1 Label 2'); }); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.ts index 73dcd3d8b9f..80014d780c2 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component.ts @@ -1,9 +1,13 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { + ChangeDetectionStrategy, Component, effect, inject, OnInit, signal, +} from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { UntilDestroy } from '@ngneat/until-destroy'; -import { select, Store } from '@ngrx/store'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { Store } from '@ngrx/store'; import { TranslateService } from '@ngx-translate/core'; -import { catchError, EMPTY, Observable } from 'rxjs'; +import { + catchError, EMPTY, Observable, tap, +} from 'rxjs'; import { JobState } from 'app/enums/job-state.enum'; import { observeJob } from 'app/helpers/operators/observe-job.operator'; import { helptextGlobal } from 'app/helptext/global-helptext'; @@ -11,7 +15,7 @@ import { ApiJobMethod, ApiJobResponse } from 'app/interfaces/api/api-job-directo import { Job } from 'app/interfaces/job.interface'; import { ShowLogsDialogComponent } from 'app/modules/dialog/components/show-logs-dialog/show-logs-dialog.component'; import { DialogService } from 'app/modules/dialog/dialog.service'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; import { JobSlice, selectJob } from 'app/modules/jobs/store/job.selectors'; import { ErrorHandlerService } from 'app/services/error-handler.service'; @@ -31,31 +35,60 @@ interface RowState { styleUrls: ['./ix-cell-state-button.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class IxCellStateButtonComponent<T> extends ColumnComponent<T> { +export class IxCellStateButtonComponent<T> extends ColumnComponent<T> implements OnInit { matDialog: MatDialog = inject(MatDialog); translate: TranslateService = inject(TranslateService); dialogService: DialogService = inject(DialogService); errorHandler: ErrorHandlerService = inject(ErrorHandlerService); - private store$: Store<JobSlice> = inject<Store<JobSlice>>(Store<JobSlice>); + private readonly rowUpdateEffect = effect(() => { + const row = this.row(); + const job = !row || !this.getJob ? undefined : this.getJob(row); - getWarnings?: (row: T) => unknown[]; - getJob?: (row: T) => Job; + if (!job) { + return; + } - protected get warnings(): unknown[] { - return this.getWarnings ? this.getWarnings(this.row) : []; - } + this.state.set(job.state); + }, { + allowSignalWrites: true, + }); + + getJob: (row: T) => Job; + private store$: Store<JobSlice> = inject<Store<JobSlice>>(Store<JobSlice>); + job = signal<Job>(null); + jobUpdates$: Observable<Job<ApiJobResponse<ApiJobMethod>>>; + state = signal<JobState>(null); - protected get job(): Job { - return this.getJob ? this.getJob(this.row) : undefined; + ngOnInit(): void { + if (this.getJob) { + const job = this.getJob(this.row()); + this.job.set(job); + if (job?.state) { + this.state.set(job.state); + } + } + if (!this.job()) { + this.state.set(this.value as JobState); + return; + } + const jobId = this.getJob(this.row()).id; + this.jobUpdates$ = this.store$.select(selectJob(jobId)).pipe( + tap((job) => { + this.job.set(job); + this.state.set(job.state); + }), + ) as Observable<Job<ApiJobResponse<ApiJobMethod>>>; } - protected get state(): JobState { - return this.value as JobState; + getWarnings?: (row: T) => unknown[]; + + protected get warnings(): unknown[] { + return this.getWarnings ? this.getWarnings(this.row()) : []; } protected get tooltip(): string { - if (this.job?.logs_path && this.job?.logs_excerpt) { + if (this.job()?.logs_path && this.job()?.logs_excerpt) { return this.translate.instant('Show Logs'); } @@ -63,52 +96,62 @@ export class IxCellStateButtonComponent<T> extends ColumnComponent<T> { } protected onButtonClick(): void { - let state = (this.row as RowState).state; + const state: RowState['state'] = { + state: this.state(), + error: this.job()?.error, + } as RowState['state']; - if (this.job?.state && !state) { - state = { - state: this.job.state, - error: this.job.error, - } as RowState['state']; + if (!state.state) { + this.dialogService.warn(helptextGlobal.noLogDialog.title, helptextGlobal.noLogDialog.message); + return; } - if (this.job && state) { - if (this.job.state === JobState.Running) { - this.dialogService.jobDialog( - this.store$.pipe( - select(selectJob(this.job.id)), - observeJob(), - ) as Observable<Job<ApiJobResponse<ApiJobMethod>>>, - { - title: this.translate.instant('Task is running'), - canMinimize: true, - }, - ).afterClosed().pipe( - catchError((error) => { - this.errorHandler.showErrorModal(error); - return EMPTY; - }), - // TODO: Remove this ignore eslint lint line and add takeUntil (untilDestroyed) - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - ).subscribe(); - } else if (state.state === JobState.Hold) { - this.dialogService.info(this.translate.instant('Task is on hold'), state.reason); - } else if (state.warnings?.length > 0) { - let list = ''; - state.warnings.forEach((warning: string) => { - list += warning + '\n'; - }); - this.dialogService.error({ title: state.state, message: `<pre>${list}</pre>` }); - } else if (state.error) { - this.dialogService.error({ title: state.state, message: `<pre>${state.error}</pre>` }); - } else if (!this.job.logs_excerpt) { - this.dialogService.warn(helptextGlobal.noLogDialog.title, helptextGlobal.noLogDialog.message); - } else { - this.matDialog.open(ShowLogsDialogComponent, { data: this.job }); - } - } else { - this.dialogService.warn(helptextGlobal.noLogDialog.title, helptextGlobal.noLogDialog.message); + if (state.state === JobState.Running) { + this.showJobDialog(); + return; + } + + if (state.state === JobState.Hold) { + this.dialogService.info(this.translate.instant('Task is on hold'), state.reason); + return; } + + if (state.warnings?.length > 0) { + let list = ''; + state.warnings.forEach((warning: string) => { + list += warning + '\n'; + }); + this.dialogService.error({ title: state.state, message: `<pre>${list}</pre>` }); + return; + } + + if (state.error) { + this.dialogService.error({ title: state.state, message: `<pre>${state.error}</pre>` }); + return; + } + + if (this.job()?.logs_excerpt) { + this.matDialog.open(ShowLogsDialogComponent, { data: this.job() }); + return; + } + + this.dialogService.warn(helptextGlobal.noLogDialog.title, helptextGlobal.noLogDialog.message); + } + + showJobDialog(): void { + this.dialogService.jobDialog( + this.jobUpdates$.pipe(observeJob()), + { + title: this.translate.instant('Task is running'), + canMinimize: true, + }, + ).afterClosed().pipe( + catchError((error) => { + this.errorHandler.showErrorModal(error); + return EMPTY; + }), + untilDestroyed(this), + ).subscribe(); } protected getButtonClass(): string { @@ -117,7 +160,7 @@ export class IxCellStateButtonComponent<T> extends ColumnComponent<T> { return 'fn-theme-orange'; } - switch (this.state) { + switch (this.state()) { case JobState.Pending: case JobState.Aborted: case JobState.Running: diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-template/ix-cell-template.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-template/ix-cell-template.component.ts index 9a4b75ece9a..1a6fb18205a 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-template/ix-cell-template.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-template/ix-cell-template.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-template', diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.html index a4e3fe7c579..8635ae8b5d4 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.html @@ -1,4 +1,4 @@ <span [matTooltip]="value?.toString() | translate" - [ixTest]="[title, rowTestId(row), 'row-text']" + [ixTest]="[title, uniqueRowTag(row()), 'row-text']" >{{ value }}</span> diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.spec.ts index 40e82270c28..5702104f1e2 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.spec.ts @@ -18,7 +18,7 @@ describe('IxCellTextComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'stringField'; spectator.component.setRow({ stringField: 'text in cell' }); - spectator.component.rowTestId = (row) => 'text-' + row.stringField.toString(); + spectator.component.uniqueRowTag = (row) => 'text-' + row.stringField.toString(); spectator.detectChanges(); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.ts index c8c8f7d8898..53bd00410cb 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component.ts @@ -1,5 +1,7 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { + ChangeDetectionStrategy, Component, +} from '@angular/core'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-text', diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.html index 6f89cf46faa..4b466f794ef 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.html @@ -1,8 +1,8 @@ @if (!requiredRoles?.length && !dynamicRequiredRoles) { <mat-slide-toggle color="primary" - [aria-label]="(checked ? ('Disable' | translate) : ('Enable' | translate)) + ' ' + getAriaLabel(row)" - [ixTest]="[title, rowTestId(row), 'row-toggle']" + [aria-label]="(checked ? ('Disable' | translate) : ('Enable' | translate)) + ' ' + getAriaLabel(row())" + [ixTest]="[title, uniqueRowTag(row()), 'row-toggle']" [checked]="checked" (change)="onSlideToggleChanged($event)" (click)="$event.stopPropagation()" @@ -10,10 +10,10 @@ } @if (requiredRoles?.length || dynamicRequiredRoles) { <mat-slide-toggle - *ixRequiresRoles="dynamicRequiredRoles ? (dynamicRequiredRoles(row) | async) : requiredRoles" + *ixRequiresRoles="dynamicRequiredRoles ? (dynamicRequiredRoles(row()) | async) : requiredRoles" color="primary" - [aria-label]="(checked ? ('Disable' | translate) : ('Enable' | translate)) + ' ' + getAriaLabel(row)" - [ixTest]="[title, rowTestId(row), 'row-toggle']" + [aria-label]="(checked ? ('Disable' | translate) : ('Enable' | translate)) + ' ' + getAriaLabel(row())" + [ixTest]="[title, uniqueRowTag(row()), 'row-toggle']" [checked]="checked" (change)="onSlideToggleChanged($event)" (click)="$event.stopPropagation()" diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.spec.ts index 948f6993470..d3b9b5b0e6a 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.spec.ts @@ -23,7 +23,7 @@ describe('IxCellToggleComponent', () => { spectator.component.propertyName = 'booleanField'; spectator.component.setRow({ booleanField: true }); spectator.component.onRowToggle = jest.fn(); - spectator.component.rowTestId = (row) => row.booleanField.toString(); + spectator.component.uniqueRowTag = (row) => row.booleanField.toString(); spectator.component.ariaLabels = () => ['Label 1', 'Label 2']; spectator.detectChanges(); @@ -41,8 +41,9 @@ describe('IxCellToggleComponent', () => { expect(spectator.component.onRowToggle).toHaveBeenCalledWith({ booleanField: true }, false); }); - it('gets aria label correctly', () => { - const ariaLabel = spectator.component.getAriaLabel(spectator.component.getRow()); - expect(ariaLabel).toBe('Label 1 Label 2'); + it('gets aria label correctly', async () => { + const toggle = await loader.getHarness(MatSlideToggleHarness); + + expect(await toggle.getAriaLabel()).toBe('Disable Label 1 Label 2'); }); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.ts index 7969b892e84..224016bde40 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import { Observable } from 'rxjs'; import { Role } from 'app/enums/role.enum'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-toggle', @@ -19,7 +19,7 @@ export class IxCellToggleComponent<T> extends ColumnComponent<T> { } onSlideToggleChanged(event: MatSlideToggleChange): void { - this.onRowToggle(this.row, event.checked); + this.onRowToggle(this.row(), event.checked); } } diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.html b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.html index 48869c69be0..3fba405adbf 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.html @@ -1,3 +1,3 @@ <span - [ixTest]="[title, rowTestId(row), 'row-yesno']" + [ixTest]="[title, uniqueRowTag(row()), 'row-yesno']" >{{ value | yesNo | translate }}</span> diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.spec.ts index 31287db43c0..feeaebf93f3 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.spec.ts @@ -18,7 +18,7 @@ describe('IxCellYesNoComponent', () => { spectator = createComponent(); spectator.component.propertyName = 'yesNoField'; spectator.component.setRow({ yesNoField: true }); - spectator.component.rowTestId = (row) => row.yesNoField.toString(); + spectator.component.uniqueRowTag = (row) => row.yesNoField.toString(); spectator.detectChanges(); }); diff --git a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.ts b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.ts index f457327fc85..0ade9bdaaf0 100644 --- a/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent, Column } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-cell-yesno', diff --git a/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.html b/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.html index c81c60d81c2..e463ad13820 100644 --- a/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.html +++ b/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.html @@ -1,16 +1,17 @@ -@for (row of dataProvider.currentPage$ | async; track trackByIdentity(row)) { +@for (row of dataProvider.currentPage$ | async; track trackRowByIdentity(row)) { <tr class="row" tabindex="0" - [ixTest]="getTestAttr(row)" - [ixUiSearch]="{ anchor: getTestAttr(row) }" + [ixTest]="getRowTag(row)" + [ixUiSearch]="{ anchor: getRowTag(row) }" [ngStyle]="{ cursor: detailsTemplate ? 'pointer' : null }" [class.expanded]="isExpanded(row)" [class.hidden]="isLoading" (click)="onToggle(row)" (keydown.enter)="onToggle(row)" > - @for (column of displayedColumns; track trackByIdentity(column); let idx = $index) { + + @for (column of displayedColumns; track trackColumnByIdentity(column); let idx = $index) { <td [ngClass]="column.cssClass || ''"> @if (getTemplateByColumnIndex(idx); as template) { <ng-container diff --git a/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.spec.ts b/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.spec.ts index eafecd95d49..64ef9bf11df 100644 --- a/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.spec.ts @@ -52,7 +52,7 @@ const columns = createTable<TestTableData>([ onRowToggle: () => jest.fn(), }), ], { - rowTestId: (row) => 'row-' + row.numberField.toString(), + uniqueRowTag: (row) => 'row-' + row.numberField.toString(), ariaLabels: (row) => ['Column', row.stringField], }); diff --git a/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.ts b/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.ts index a7e0e966958..ba2d538ba18 100644 --- a/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.ts +++ b/src/app/modules/ix-table/components/ix-table-body/ix-table-body.component.ts @@ -12,8 +12,8 @@ import { import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { IxTableCellDirective } from 'app/modules/ix-table/directives/ix-table-cell.directive'; import { IxTableDetailsRowDirective } from 'app/modules/ix-table/directives/ix-table-details-row.directive'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { DataProvider } from 'app/modules/ix-table/interfaces/data-provider.interface'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; @UntilDestroy() @Component({ @@ -61,8 +61,8 @@ export class IxTableBodyComponent<T> implements AfterViewInit { }); } - getTestAttr(row: T): string { - return this.columns[0]?.rowTestId(row) ?? ''; + getRowTag(row: T): string { + return this.columns[0]?.uniqueRowTag(row) ?? ''; } getTemplateByColumnIndex(idx: number): TemplateRef<{ $implicit: T }> | undefined { @@ -79,8 +79,11 @@ export class IxTableBodyComponent<T> implements AfterViewInit { && (this.dataProvider?.expandedRow?.[this.detailsRowIdentifier] === row?.[this.detailsRowIdentifier]); } - // TODO: Come up with a proper identifier - protected trackByIdentity<X>(item: X): X { - return item; + protected trackRowByIdentity(item: T): string { + return this.getRowTag(item); + } + + protected trackColumnByIdentity(column: Column<T, ColumnComponent<T>>): Column<T, ColumnComponent<T>> { + return column; } } diff --git a/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.spec.ts b/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.spec.ts index 62a81a3f7eb..dc9b505f9d9 100644 --- a/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.spec.ts @@ -7,7 +7,7 @@ import { createComponentFactory } from '@ngneat/spectator/jest'; import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; import { yesNoColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component'; import { IxTableColumnsSelectorComponent } from 'app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { CronjobRow } from 'app/pages/system/advanced/cron/cron-list/cronjob-row.interface'; @@ -40,7 +40,7 @@ describe('IxTableColumnsSelectorComponent', () => { hidden: true, }), ], { - rowTestId: (row: CronjobRow) => 'cronjob-' + row.id.toString(), + uniqueRowTag: (row: CronjobRow) => 'cronjob-' + row.id.toString(), ariaLabels: (row) => ['Column', row.id.toString()], }) as Column<unknown, ColumnComponent<unknown>>[]; diff --git a/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.ts b/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.ts index 2c6a406c95b..ec0f6b6e8a0 100644 --- a/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.ts +++ b/src/app/modules/ix-table/components/ix-table-columns-selector/ix-table-columns-selector.component.ts @@ -5,7 +5,7 @@ import { import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import * as _ from 'lodash-es'; import { IxSimpleChanges } from 'app/interfaces/simple-changes.interface'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @UntilDestroy() @Component({ diff --git a/src/app/modules/ix-table/components/ix-table-details-row/ix-table-details-row.component.ts b/src/app/modules/ix-table/components/ix-table-details-row/ix-table-details-row.component.ts index a092d42edd5..21a69dcd43f 100644 --- a/src/app/modules/ix-table/components/ix-table-details-row/ix-table-details-row.component.ts +++ b/src/app/modules/ix-table/components/ix-table-details-row/ix-table-details-row.component.ts @@ -1,7 +1,7 @@ import { Component, ChangeDetectionStrategy, input, } from '@angular/core'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-table-details-row', diff --git a/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-checkbox/ix-header-cell-checkbox.component.ts b/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-checkbox/ix-header-cell-checkbox.component.ts index ae80943b874..60b603244ee 100644 --- a/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-checkbox/ix-header-cell-checkbox.component.ts +++ b/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-checkbox/ix-header-cell-checkbox.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { MatCheckboxChange } from '@angular/material/checkbox'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { map, Observable } from 'rxjs'; -import { ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @UntilDestroy() @Component({ diff --git a/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-text/ix-header-cell-text.component.ts b/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-text/ix-header-cell-text.component.ts index e5c42641386..4dfe2b3d560 100644 --- a/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-text/ix-header-cell-text.component.ts +++ b/src/app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-text/ix-header-cell-text.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-header-cell-text', diff --git a/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.spec.ts b/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.spec.ts index a84e05d6c0f..982d4a21c74 100644 --- a/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.spec.ts +++ b/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.spec.ts @@ -28,7 +28,7 @@ const columns = createTable<TestTableData>([ disableSorting: true, }), ], { - rowTestId: (row) => 'row' + row.numberField.toString(), + uniqueRowTag: (row) => 'row' + row.numberField.toString(), ariaLabels: (row) => ['Column', row.stringField], }); diff --git a/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.ts b/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.ts index 15f4023fee6..2dc1b9477d2 100644 --- a/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.ts +++ b/src/app/modules/ix-table/components/ix-table-head/ix-table-head.component.ts @@ -3,8 +3,8 @@ import { } from '@angular/core'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { SortDirection } from 'app/modules/ix-table/enums/sort-direction.enum'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { DataProvider } from 'app/modules/ix-table/interfaces/data-provider.interface'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; @UntilDestroy() @Component({ diff --git a/src/app/modules/ix-table/directives/ix-body-cell.directive.ts b/src/app/modules/ix-table/directives/ix-body-cell.directive.ts index 17039456cd6..b4654831a25 100644 --- a/src/app/modules/ix-table/directives/ix-body-cell.directive.ts +++ b/src/app/modules/ix-table/directives/ix-body-cell.directive.ts @@ -1,19 +1,23 @@ import { AfterViewInit, ChangeDetectorRef, + ComponentRef, Directive, Input, + OnChanges, ViewContainerRef, } from '@angular/core'; import { IxCellTextComponent } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent, ColumnKeys } from 'app/modules/ix-table/interfaces/column-component.class'; @Directive({ selector: '[ix-body-cell]', }) -export class IxTableBodyCellDirective<T> implements AfterViewInit { +export class IxTableBodyCellDirective<T> implements AfterViewInit, OnChanges { @Input() row: T; @Input() column: Column<T, ColumnComponent<T>>; + private componentRef: ComponentRef<ColumnComponent<T>>; + constructor( private viewContainer: ViewContainerRef, private cdr: ChangeDetectorRef, @@ -23,19 +27,29 @@ export class IxTableBodyCellDirective<T> implements AfterViewInit { this.createComponent(); } + ngOnChanges(): void { + if (!this.componentRef) { + return; + } + this.setComponentProps(); + } + createComponent(): void { if (!this.column.type) { this.column.type = IxCellTextComponent; } this.viewContainer.clear(); - const componentRef = this.viewContainer.createComponent( + this.componentRef = this.viewContainer.createComponent( this.column.type, ); - componentRef.instance.setRow(this.row); - Object.keys(this.column).forEach((key: keyof ColumnComponent<T>) => { - // TODO: Replace never. - componentRef.instance[key] = this.column[key] as never; + this.setComponentProps(); + } + + private setComponentProps(): void { + this.componentRef.instance.setRow(this.row); + Object.keys(this.column).forEach((key: ColumnKeys<T>) => { + this.componentRef.instance[key] = this.column[key] as never; }); this.cdr.detectChanges(); diff --git a/src/app/modules/ix-table/directives/ix-header-cell.directive.ts b/src/app/modules/ix-table/directives/ix-header-cell.directive.ts index a500d356b81..f65f2ffba44 100644 --- a/src/app/modules/ix-table/directives/ix-header-cell.directive.ts +++ b/src/app/modules/ix-table/directives/ix-header-cell.directive.ts @@ -5,8 +5,8 @@ import { ViewContainerRef, } from '@angular/core'; import { IxHeaderCellTextComponent } from 'app/modules/ix-table/components/ix-table-head/head-cells/ix-header-cell-text/ix-header-cell-text.component'; +import { Column, ColumnComponent, ColumnKeys } from 'app/modules/ix-table/interfaces/column-component.class'; import { DataProvider } from 'app/modules/ix-table/interfaces/data-provider.interface'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; @Directive({ selector: '[ix-header-cell]', @@ -31,7 +31,8 @@ export class IxTableHeaderCellDirective<T> implements AfterViewInit { ); componentRef.instance.dataProvider = this.dataProvider; - Object.keys(this.column).forEach((key: keyof ColumnComponent<T>) => { + Object.keys(this.column).forEach((key: ColumnKeys<T>) => { + // TODO: replace never componentRef.instance[key] = this.column[key] as never; }); } diff --git a/src/app/modules/ix-table/interfaces/column-component.class.ts b/src/app/modules/ix-table/interfaces/column-component.class.ts new file mode 100644 index 00000000000..f8982b69478 --- /dev/null +++ b/src/app/modules/ix-table/interfaces/column-component.class.ts @@ -0,0 +1,40 @@ +import { signal, WritableSignal } from '@angular/core'; +import { MutableKeys } from 'utility-types'; +import { DataProvider } from 'app/modules/ix-table/interfaces/data-provider.interface'; + +export abstract class ColumnComponent<T> { + propertyName?: keyof T; + title?: string; + cssClass?: string; + uniqueRowTag: (row: T) => string; + ariaLabels: (row: T) => string[]; + sortBy?: (row: T) => string | number; + disableSorting?: boolean; + dataProvider?: DataProvider<T>; + getValue?: (row: T) => unknown; + hidden = false; + + get value(): unknown { + if (this.getValue) { + return this.getValue(this.row()); + } + return this.propertyName ? this.row()[this.propertyName] : ''; + } + + protected row: WritableSignal<T> = signal(null as T); + + setRow = (row: T): void => { + this.row.set(row); + }; + + getAriaLabel = (row: T): string => { + return this.ariaLabels(row)?.join(' ') || (this.title ? this.title : ''); + }; +} + +export type Column<T, C extends ColumnComponent<T>> = { + type?: new () => C; + headerType?: new () => C; +} & Partial<C>; + +export type ColumnKeys<T> = MutableKeys<ColumnComponent<T>>; diff --git a/src/app/modules/ix-table/interfaces/table-column.interface.ts b/src/app/modules/ix-table/interfaces/table-column.interface.ts deleted file mode 100644 index bffb9bf694f..00000000000 --- a/src/app/modules/ix-table/interfaces/table-column.interface.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DataProvider } from 'app/modules/ix-table/interfaces/data-provider.interface'; - -export abstract class ColumnComponent<T> { - propertyName: keyof T; - title: string; - cssClass?: string; - rowTestId: (row: T) => string; - ariaLabels: (row: T) => string[]; - sortBy?: (row: T) => string | number; - disableSorting?: boolean; - getValue?: (row: T) => unknown; - hidden = false; - - protected get value(): unknown { - return this.getValue ? this.getValue(this.row) : this.row[this.propertyName]; - } - - protected row: T; - - getRow(): T { - return this.row; - } - setRow(row: T): void { - this.row = row; - } - getAriaLabel(row: T): string { - return this.ariaLabels(row)?.join(' ') || this.title; - } - dataProvider?: DataProvider<T>; -} - -export type Column<T, C extends ColumnComponent<T>> = { - type?: new () => C; - headerType?: new () => C; -} & Partial<C>; diff --git a/src/app/modules/ix-table/utils.ts b/src/app/modules/ix-table/utils.ts index 7c27a23a316..100d7f27282 100644 --- a/src/app/modules/ix-table/utils.ts +++ b/src/app/modules/ix-table/utils.ts @@ -1,5 +1,5 @@ import { get } from 'lodash-es'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { TableFilter } from 'app/modules/ix-table/interfaces/table-filter.interface'; function convertStringToId(inputString: string): string { @@ -14,13 +14,17 @@ function convertStringToId(inputString: string): string { export function createTable<T>( columns: Column<T, ColumnComponent<T>>[], - config: { rowTestId: (row: T) => string; ariaLabels: (row: T) => string[] }, + config: { uniqueRowTag: (row: T) => string; ariaLabels: (row: T) => string[] }, ): Column<T, ColumnComponent<T>>[] { - return columns.map((column) => ({ - ...column, - rowTestId: (row) => convertStringToId(config.rowTestId(row)), - ariaLabels: (row) => config.ariaLabels(row), - })); + return columns.map((column) => { + const uniqueRowTag = (row: T): string => convertStringToId(config.uniqueRowTag(row)); + const ariaLabels = (row: T): string[] => config.ariaLabels(row); + return { + ...column, + uniqueRowTag, + ariaLabels, + }; + }); } export function filterTableRows<T>(filter: TableFilter<T>): T[] { diff --git a/src/app/pages/account/groups/group-list/group-list.component.ts b/src/app/pages/account/groups/group-list/group-list.component.ts index a7660314f53..83f31bd9dbb 100644 --- a/src/app/pages/account/groups/group-list/group-list.component.ts +++ b/src/app/pages/account/groups/group-list/group-list.component.ts @@ -69,7 +69,7 @@ export class GroupListComponent implements OnInit { .join(', ') || this.translate.instant('N/A'), }), ], { - rowTestId: (row) => 'group-' + row.group, + uniqueRowTag: (row) => 'group-' + row.group, ariaLabels: (row) => [row.group, this.translate.instant('Group')], }); diff --git a/src/app/pages/account/groups/privilege/privilege-list/privilege-list.component.ts b/src/app/pages/account/groups/privilege/privilege-list/privilege-list.component.ts index 47ad5d51b36..525d2ce25ec 100644 --- a/src/app/pages/account/groups/privilege/privilege-list/privilege-list.component.ts +++ b/src/app/pages/account/groups/privilege/privilege-list/privilege-list.component.ts @@ -86,7 +86,7 @@ export class PrivilegeListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'privilege-' + row.name, + uniqueRowTag: (row) => 'privilege-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Privilege')], }); diff --git a/src/app/pages/account/users/user-list/user-list.component.ts b/src/app/pages/account/users/user-list/user-list.component.ts index 8a64bc508f2..14790974abd 100644 --- a/src/app/pages/account/users/user-list/user-list.component.ts +++ b/src/app/pages/account/users/user-list/user-list.component.ts @@ -63,7 +63,7 @@ export class UserListComponent implements OnInit { .join(', ') || this.translate.instant('N/A'), }), ], { - rowTestId: (row) => 'user-' + row.username, + uniqueRowTag: (row) => 'user-' + row.username, ariaLabels: (row) => [row.username, this.translate.instant('User')], }); diff --git a/src/app/pages/api-keys/components/api-key-list/api-key-list.component.ts b/src/app/pages/api-keys/components/api-key-list/api-key-list.component.ts index 7aad3d1551e..5ce180992a7 100644 --- a/src/app/pages/api-keys/components/api-key-list/api-key-list.component.ts +++ b/src/app/pages/api-keys/components/api-key-list/api-key-list.component.ts @@ -66,7 +66,7 @@ export class ApiKeyListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'api-key-' + row.name + '-' + row.created_at.$date, + uniqueRowTag: (row) => 'api-key-' + row.name + '-' + row.created_at.$date, ariaLabels: (row) => [row.name, this.translate.instant('Api Key')], }); diff --git a/src/app/pages/apps/components/docker-images/docker-images-list/docker-images-list.component.ts b/src/app/pages/apps/components/docker-images/docker-images-list/docker-images-list.component.ts index b29f7dbe66b..ead3666b43e 100644 --- a/src/app/pages/apps/components/docker-images/docker-images-list/docker-images-list.component.ts +++ b/src/app/pages/apps/components/docker-images/docker-images-list/docker-images-list.component.ts @@ -92,7 +92,7 @@ export class DockerImagesListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'container-image-' + row.id, + uniqueRowTag: (row) => 'container-image-' + row.id, ariaLabels: (row) => [row.id, this.translate.instant('Docker Image')], }); diff --git a/src/app/pages/audit/components/audit/audit.component.ts b/src/app/pages/audit/components/audit/audit.component.ts index bb1b61968ed..ea5072adf3a 100644 --- a/src/app/pages/audit/components/audit/audit.component.ts +++ b/src/app/pages/audit/components/audit/audit.component.ts @@ -97,7 +97,7 @@ export class AuditComponent implements OnInit, OnDestroy { getValue: (row) => this.translate.instant(this.getEventDataForLog(row)), }), ], { - rowTestId: (row) => 'audit-' + row.service + '-' + row.username + '-' + row.event, + uniqueRowTag: (row) => 'audit-' + row.service + '-' + row.username + '-' + row.event, ariaLabels: (row) => [row.service, row.username, row.event, this.translate.instant('Audit Entry')], }); diff --git a/src/app/pages/credentials/backup-credentials/cloud-credentials-card/cloud-credentials-card.component.ts b/src/app/pages/credentials/backup-credentials/cloud-credentials-card/cloud-credentials-card.component.ts index f33a9db7eed..b8836c48a22 100644 --- a/src/app/pages/credentials/backup-credentials/cloud-credentials-card/cloud-credentials-card.component.ts +++ b/src/app/pages/credentials/backup-credentials/cloud-credentials-card/cloud-credentials-card.component.ts @@ -60,7 +60,7 @@ export class CloudCredentialsCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'cloud-cred-' + row.name, + uniqueRowTag: (row) => 'cloud-cred-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Cloud Credential')], }); diff --git a/src/app/pages/credentials/backup-credentials/ssh-connection-card/ssh-connection-card.component.ts b/src/app/pages/credentials/backup-credentials/ssh-connection-card/ssh-connection-card.component.ts index a69a9ae900d..a72bd201fb1 100644 --- a/src/app/pages/credentials/backup-credentials/ssh-connection-card/ssh-connection-card.component.ts +++ b/src/app/pages/credentials/backup-credentials/ssh-connection-card/ssh-connection-card.component.ts @@ -53,7 +53,7 @@ export class SshConnectionCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'ssh-con-' + row.name, + uniqueRowTag: (row) => 'ssh-con-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('SSH Connection')], }); diff --git a/src/app/pages/credentials/backup-credentials/ssh-keypair-card/ssh-keypair-card.component.ts b/src/app/pages/credentials/backup-credentials/ssh-keypair-card/ssh-keypair-card.component.ts index 3f244b2110f..d68a8e9a5b7 100644 --- a/src/app/pages/credentials/backup-credentials/ssh-keypair-card/ssh-keypair-card.component.ts +++ b/src/app/pages/credentials/backup-credentials/ssh-keypair-card/ssh-keypair-card.component.ts @@ -61,7 +61,7 @@ export class SshKeypairCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'ssh-keypair-' + row.name, + uniqueRowTag: (row) => 'ssh-keypair-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('SSH Key Pair')], }); diff --git a/src/app/pages/credentials/certificates-dash/acme-dns-authenticator-list/acme-dns-authenticator-list.component.ts b/src/app/pages/credentials/certificates-dash/acme-dns-authenticator-list/acme-dns-authenticator-list.component.ts index 6e3ed645f6f..6a4cd02cb69 100644 --- a/src/app/pages/credentials/certificates-dash/acme-dns-authenticator-list/acme-dns-authenticator-list.component.ts +++ b/src/app/pages/credentials/certificates-dash/acme-dns-authenticator-list/acme-dns-authenticator-list.component.ts @@ -57,7 +57,7 @@ export class AcmeDnsAuthenticatorListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'amce-dns-' + row.name, + uniqueRowTag: (row) => 'amce-dns-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('ACME DNS Authenticator')], }); diff --git a/src/app/pages/credentials/certificates-dash/certificate-authority-list/certificate-authority-list.component.ts b/src/app/pages/credentials/certificates-dash/certificate-authority-list/certificate-authority-list.component.ts index 726faa732b3..95b92deb927 100644 --- a/src/app/pages/credentials/certificates-dash/certificate-authority-list/certificate-authority-list.component.ts +++ b/src/app/pages/credentials/certificates-dash/certificate-authority-list/certificate-authority-list.component.ts @@ -102,7 +102,7 @@ export class CertificateAuthorityListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'ca-' + row.name, + uniqueRowTag: (row) => 'ca-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Certificate Authority')], }); diff --git a/src/app/pages/credentials/certificates-dash/certificate-list/certificate-list.component.ts b/src/app/pages/credentials/certificates-dash/certificate-list/certificate-list.component.ts index 8124a5db923..5d30fa77ef5 100644 --- a/src/app/pages/credentials/certificates-dash/certificate-list/certificate-list.component.ts +++ b/src/app/pages/credentials/certificates-dash/certificate-list/certificate-list.component.ts @@ -98,7 +98,7 @@ export class CertificateListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'cert-' + row.name, + uniqueRowTag: (row) => 'cert-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Certificate')], }); diff --git a/src/app/pages/credentials/certificates-dash/csr-list/csr-list.component.ts b/src/app/pages/credentials/certificates-dash/csr-list/csr-list.component.ts index 656d0dceb7f..8b8178d6511 100644 --- a/src/app/pages/credentials/certificates-dash/csr-list/csr-list.component.ts +++ b/src/app/pages/credentials/certificates-dash/csr-list/csr-list.component.ts @@ -87,7 +87,7 @@ export class CertificateSigningRequestsListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'csr-' + row.name, + uniqueRowTag: (row) => 'csr-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('CSR')], }); diff --git a/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.spec.ts b/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.spec.ts index d7a48c03e79..5a689d302a2 100644 --- a/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.spec.ts +++ b/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.spec.ts @@ -4,6 +4,7 @@ import { MatButtonHarness } from '@angular/material/button/testing'; import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing'; import { Router } from '@angular/router'; import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; +import { provideMockStore } from '@ngrx/store/testing'; import { of } from 'rxjs'; import { mockAuth } from 'app/core/testing/utils/mock-auth.utils'; import { mockCall, mockWebSocket } from 'app/core/testing/utils/mock-websocket.utils'; @@ -14,6 +15,7 @@ import { IxSlideInRef } from 'app/modules/forms/ix-forms/components/ix-slide-in/ import { IxIconHarness } from 'app/modules/ix-icon/ix-icon.harness'; import { IxTableHarness } from 'app/modules/ix-table/components/ix-table/ix-table.harness'; import { IxTableModule } from 'app/modules/ix-table/ix-table.module'; +import { selectJobs } from 'app/modules/jobs/store/job.selectors'; import { AppLoaderModule } from 'app/modules/loader/app-loader.module'; import { CloudBackupCardComponent, @@ -68,6 +70,19 @@ describe('CloudBackupCardComponent', () => { response: true, })), }), + provideMockStore({ + selectors: [ + { + selector: selectJobs, + value: [{ + state: JobState.Finished, + time_finished: { + $date: new Date().getTime() - 50000, + }, + }], + }, + ], + }), ], }); diff --git a/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.ts b/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.ts index 40cb5581e19..61a390c4467 100644 --- a/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.ts +++ b/src/app/pages/data-protection/cloud-backup/cloud-backup-card/cloud-backup-card.component.ts @@ -106,7 +106,7 @@ export class CloudBackupCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'cloud-backup-' + row.description, + uniqueRowTag: (row) => 'cloud-backup-' + row.description, ariaLabels: (row) => [row.description, this.translate.instant('Cloud Backup')], }); diff --git a/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-snapshots/cloud-backup-snapshots.component.ts b/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-snapshots/cloud-backup-snapshots.component.ts index 5d029730201..cd2a492f8ec 100644 --- a/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-snapshots/cloud-backup-snapshots.component.ts +++ b/src/app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-snapshots/cloud-backup-snapshots.component.ts @@ -68,7 +68,7 @@ export class CloudBackupSnapshotsComponent implements OnChanges { ], }), ], { - rowTestId: (row) => 'cloud-backup-snapshot-' + row.hostname, + uniqueRowTag: (row) => 'cloud-backup-snapshot-' + row.hostname, ariaLabels: (row) => [row.hostname, this.translate.instant('Cloud Backup Snapshot')], }); diff --git a/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.spec.ts b/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.spec.ts index e8e43315384..f69871781f9 100644 --- a/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.spec.ts +++ b/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.spec.ts @@ -18,6 +18,7 @@ import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provi import { IxTableHarness } from 'app/modules/ix-table/components/ix-table/ix-table.harness'; import { SortDirection } from 'app/modules/ix-table/enums/sort-direction.enum'; import { IxTableModule } from 'app/modules/ix-table/ix-table.module'; +import { selectJobs } from 'app/modules/jobs/store/job.selectors'; import { AppLoaderModule } from 'app/modules/loader/app-loader.module'; import { PageHeaderModule } from 'app/modules/page-header/page-header.module'; import { CloudBackupDetailsComponent } from 'app/pages/data-protection/cloud-backup/cloud-backup-details/cloud-backup-details.component'; @@ -92,6 +93,15 @@ describe('CloudBackupListComponent', () => { selector: selectAdvancedConfig, value: {}, }, + { + selector: selectJobs, + value: [{ + state: JobState.Finished, + time_finished: { + $date: new Date().getTime() - 50000, + }, + }], + }, ], }), ], diff --git a/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.ts b/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.ts index 07e221340ac..c957d398e71 100644 --- a/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.ts +++ b/src/app/pages/data-protection/cloud-backup/cloud-backup-list/cloud-backup-list.component.ts @@ -104,7 +104,7 @@ export class CloudBackupListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'cloud-backup-' + row.description, + uniqueRowTag: (row) => 'cloud-backup-' + row.description, ariaLabels: (row) => [row.description, this.translate.instant('Cloud Backup')], }); diff --git a/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.spec.ts b/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.spec.ts index c78f8aa6f7d..6b38aa850f3 100644 --- a/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.spec.ts +++ b/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.spec.ts @@ -4,6 +4,7 @@ import { MatButtonHarness } from '@angular/material/button/testing'; import { MatDialog } from '@angular/material/dialog'; import { Spectator } from '@ngneat/spectator'; import { createComponentFactory, mockProvider } from '@ngneat/spectator/jest'; +import { provideMockStore } from '@ngrx/store/testing'; import { MockModule } from 'ng-mocks'; import { of } from 'rxjs'; import { fakeSuccessfulJob } from 'app/core/testing/utils/fake-job.utils'; @@ -15,6 +16,7 @@ import { IxSlideInRef } from 'app/modules/forms/ix-forms/components/ix-slide-in/ import { SearchInput1Component } from 'app/modules/forms/search-input1/search-input1.component'; import { IxTableHarness } from 'app/modules/ix-table/components/ix-table/ix-table.harness'; import { IxTableModule } from 'app/modules/ix-table/ix-table.module'; +import { selectJob } from 'app/modules/jobs/store/job.selectors'; import { AppLoaderModule } from 'app/modules/loader/app-loader.module'; import { PageHeaderModule } from 'app/modules/page-header/page-header.module'; import { SnackbarService } from 'app/modules/snackbar/services/snackbar.service'; @@ -118,6 +120,14 @@ describe('CloudSyncListComponent', () => { getTaskNextTime: jest.fn(() => new Date(new Date().getTime() + (25 * 60 * 60 * 1000))), }), mockProvider(SnackbarService), + provideMockStore({ + selectors: [ + { + selector: selectJob(1), + value: fakeSuccessfulJob(), + }, + ], + }), ], }); diff --git a/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.ts b/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.ts index 8bacde1e09e..484c2a4c5a8 100644 --- a/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.ts +++ b/src/app/pages/data-protection/cloudsync/cloudsync-list/cloudsync-list.component.ts @@ -21,7 +21,7 @@ import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provi import { stateButtonColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component'; import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; import { yesNoColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { selectJob } from 'app/modules/jobs/store/job.selectors'; import { scheduleToCrontab } from 'app/modules/scheduler/utils/schedule-to-crontab.utils'; @@ -121,7 +121,7 @@ export class CloudSyncListComponent implements OnInit { propertyName: 'enabled', }), ], { - rowTestId: (row) => 'cloudsync-task-' + row.description, + uniqueRowTag: (row) => 'cloudsync-task-' + row.description, ariaLabels: (row) => [row.description, this.translate.instant('Cloud Sync Task')], }); diff --git a/src/app/pages/data-protection/cloudsync/cloudsync-task-card/cloudsync-task-card.component.ts b/src/app/pages/data-protection/cloudsync/cloudsync-task-card/cloudsync-task-card.component.ts index 3e26b88abae..8a286b32f55 100644 --- a/src/app/pages/data-protection/cloudsync/cloudsync-task-card/cloudsync-task-card.component.ts +++ b/src/app/pages/data-protection/cloudsync/cloudsync-task-card/cloudsync-task-card.component.ts @@ -77,7 +77,6 @@ export class CloudSyncTaskCardComponent implements OnInit { stateButtonColumn({ title: this.translate.instant('State'), getValue: (row) => row.state.state, - getJob: (row) => row.job, cssClass: 'state-button', }), actionsColumn({ @@ -123,7 +122,7 @@ export class CloudSyncTaskCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-cloudsync-task-' + row.description, + uniqueRowTag: (row) => 'card-cloudsync-task-' + row.description, ariaLabels: (row) => [row.description, this.translate.instant('Cloud Sync Task')], }); diff --git a/src/app/pages/data-protection/replication/replication-list/replication-list.component.spec.ts b/src/app/pages/data-protection/replication/replication-list/replication-list.component.spec.ts index 5c10f368730..f8b645f62de 100644 --- a/src/app/pages/data-protection/replication/replication-list/replication-list.component.spec.ts +++ b/src/app/pages/data-protection/replication/replication-list/replication-list.component.spec.ts @@ -25,7 +25,7 @@ import { IxSlideInRef } from 'app/modules/forms/ix-forms/components/ix-slide-in/ import { SearchInput1Component } from 'app/modules/forms/search-input1/search-input1.component'; import { IxTableHarness } from 'app/modules/ix-table/components/ix-table/ix-table.harness'; import { IxTableModule } from 'app/modules/ix-table/ix-table.module'; -import { selectJob } from 'app/modules/jobs/store/job.selectors'; +import { selectJobs } from 'app/modules/jobs/store/job.selectors'; import { AppLoaderModule } from 'app/modules/loader/app-loader.module'; import { PageHeaderModule } from 'app/modules/page-header/page-header.module'; import { ReplicationFormComponent } from 'app/pages/data-protection/replication/replication-form/replication-form.component'; @@ -122,8 +122,8 @@ describe('ReplicationListComponent', () => { provideMockStore({ selectors: [ { - selector: selectJob(1), - value: {} as Job, + selector: selectJobs, + value: [{ id: 2, state: JobState.Success } as Job], }, { selector: selectSystemConfigState, diff --git a/src/app/pages/data-protection/replication/replication-list/replication-list.component.ts b/src/app/pages/data-protection/replication/replication-list/replication-list.component.ts index 851ceea6bbe..d6135d8015a 100644 --- a/src/app/pages/data-protection/replication/replication-list/replication-list.component.ts +++ b/src/app/pages/data-protection/replication/replication-list/replication-list.component.ts @@ -23,7 +23,7 @@ import { } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component'; import { yesNoColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-yes-no/ix-cell-yes-no.component'; import { SortDirection } from 'app/modules/ix-table/enums/sort-direction.enum'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { AppLoaderService } from 'app/modules/loader/app-loader.service'; import { SnackbarService } from 'app/modules/snackbar/services/snackbar.service'; @@ -113,8 +113,8 @@ export class ReplicationListComponent implements OnInit { stateButtonColumn({ title: this.translate.instant('State'), getValue: (row) => row.state.state, - getJob: (row) => row.job, cssClass: 'state-button', + getJob: (row) => row.job, }), toggleColumn({ title: this.translate.instant('Enabled'), @@ -131,7 +131,7 @@ export class ReplicationListComponent implements OnInit { }, }), ], { - rowTestId: (row) => 'replication-task-' + row.name, + uniqueRowTag: (row) => 'replication-task-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Replication Task')], }); diff --git a/src/app/pages/data-protection/replication/replication-task-card/replication-task-card.component.ts b/src/app/pages/data-protection/replication/replication-task-card/replication-task-card.component.ts index 039f2da4bef..cc50fe12c39 100644 --- a/src/app/pages/data-protection/replication/replication-task-card/replication-task-card.component.ts +++ b/src/app/pages/data-protection/replication/replication-task-card/replication-task-card.component.ts @@ -120,7 +120,7 @@ export class ReplicationTaskCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'replication-task-' + row.name, + uniqueRowTag: (row) => 'replication-task-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Replication Task')], }); diff --git a/src/app/pages/data-protection/rsync-task/rsync-task-card/rsync-task-card.component.ts b/src/app/pages/data-protection/rsync-task/rsync-task-card/rsync-task-card.component.ts index 289bdb3daa4..2effcd46b39 100644 --- a/src/app/pages/data-protection/rsync-task/rsync-task-card/rsync-task-card.component.ts +++ b/src/app/pages/data-protection/rsync-task/rsync-task-card/rsync-task-card.component.ts @@ -104,7 +104,7 @@ export class RsyncTaskCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-rsync-task-' + row.path + '-' + row.remotehost, + uniqueRowTag: (row) => 'card-rsync-task-' + row.path + '-' + row.remotehost, ariaLabels: (row) => [row.path, row.remotehost, this.translate.instant('Rsync Task')], }); diff --git a/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.spec.ts b/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.spec.ts index 7bdd38ca48d..03eb030778b 100644 --- a/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.spec.ts +++ b/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.spec.ts @@ -16,6 +16,7 @@ import { SearchInput1Component } from 'app/modules/forms/search-input1/search-in import { IxIconHarness } from 'app/modules/ix-icon/ix-icon.harness'; import { IxTableHarness } from 'app/modules/ix-table/components/ix-table/ix-table.harness'; import { IxTableModule } from 'app/modules/ix-table/ix-table.module'; +import { selectJobs } from 'app/modules/jobs/store/job.selectors'; import { PageHeaderModule } from 'app/modules/page-header/page-header.module'; import { RsyncTaskFormComponent } from 'app/pages/data-protection/rsync-task/rsync-task-form/rsync-task-form.component'; import { RsyncTaskListComponent } from 'app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component'; @@ -48,11 +49,12 @@ describe('RsyncTaskListComponent', () => { }, user: 'bob', job: { + id: 1, state: JobState.Running, } as Job, }, { - id: 1, + id: 2, enabled: false, desc: 'Second task', direction: Direction.Push, @@ -68,6 +70,7 @@ describe('RsyncTaskListComponent', () => { }, user: 'peter', job: { + id: 2, state: JobState.Finished, } as Job, }, @@ -112,6 +115,19 @@ describe('RsyncTaskListComponent', () => { selector: selectPreferences, value: {}, }, + { + selector: selectJobs, + value: [ + { + id: 1, + state: JobState.Running, + }, + { + id: 2, + state: JobState.Finished, + }, + ], + }, ], }), ], diff --git a/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.ts b/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.ts index eb0129edf23..8b17d6a33dc 100644 --- a/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.ts +++ b/src/app/pages/data-protection/rsync-task/rsync-task-list/rsync-task-list.component.ts @@ -152,7 +152,7 @@ export class RsyncTaskListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'rsync-task-' + row.path + '-' + row.remotehost, + uniqueRowTag: (row) => 'rsync-task-' + row.path + '-' + row.remotehost, ariaLabels: (row) => [row.path, row.remotehost, this.translate.instant('Rsync Task')], }); diff --git a/src/app/pages/data-protection/scrub-task/scrub-list/scrub-list.component.ts b/src/app/pages/data-protection/scrub-task/scrub-list/scrub-list.component.ts index f97bc185dbc..1266872e549 100644 --- a/src/app/pages/data-protection/scrub-task/scrub-list/scrub-list.component.ts +++ b/src/app/pages/data-protection/scrub-task/scrub-list/scrub-list.component.ts @@ -92,7 +92,7 @@ export class ScrubListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'scrub-task-' + row.pool + '-' + row.description, + uniqueRowTag: (row) => 'scrub-task-' + row.pool + '-' + row.description, ariaLabels: (row) => [row.pool_name, row.description, this.translate.instant('Scrub Task')], }); diff --git a/src/app/pages/data-protection/scrub-task/scrub-task-card/scrub-task-card.component.ts b/src/app/pages/data-protection/scrub-task/scrub-task-card/scrub-task-card.component.ts index 381b1eb8d14..437f6fa395f 100644 --- a/src/app/pages/data-protection/scrub-task/scrub-task-card/scrub-task-card.component.ts +++ b/src/app/pages/data-protection/scrub-task/scrub-task-card/scrub-task-card.component.ts @@ -74,7 +74,7 @@ export class ScrubTaskCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-scrub-task-' + row.pool + '-' + row.description, + uniqueRowTag: (row) => 'card-scrub-task-' + row.pool + '-' + row.description, ariaLabels: (row) => [row.pool.toString(), row.description, this.translate.instant('Scrub Task')], }); diff --git a/src/app/pages/data-protection/smart-task/smart-task-card/smart-task-card.component.ts b/src/app/pages/data-protection/smart-task/smart-task-card/smart-task-card.component.ts index 3f8ab7305c2..874580465ca 100644 --- a/src/app/pages/data-protection/smart-task/smart-task-card/smart-task-card.component.ts +++ b/src/app/pages/data-protection/smart-task/smart-task-card/smart-task-card.component.ts @@ -76,7 +76,7 @@ export class SmartTaskCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'smart-task-' + row.type + '-' + row.disks.join(','), + uniqueRowTag: (row) => 'smart-task-' + row.type + '-' + row.disks.join(','), ariaLabels: (row) => [row.type, row.disks.join(','), this.translate.instant('Smart Task')], }); diff --git a/src/app/pages/data-protection/smart-task/smart-task-list/smart-task-list.component.ts b/src/app/pages/data-protection/smart-task/smart-task-list/smart-task-list.component.ts index 82f5e4aed70..d445a54410f 100644 --- a/src/app/pages/data-protection/smart-task/smart-task-list/smart-task-list.component.ts +++ b/src/app/pages/data-protection/smart-task/smart-task-list/smart-task-list.component.ts @@ -80,7 +80,7 @@ export class SmartTaskListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'smart-task-' + row.type + '-' + row.disks.join(','), + uniqueRowTag: (row) => 'smart-task-' + row.type + '-' + row.disks.join(','), ariaLabels: (row) => [row.type, row.disks.join(','), this.translate.instant('Smart Task')], }); diff --git a/src/app/pages/data-protection/snapshot-task/snapshot-task-card/snapshot-task-card.component.ts b/src/app/pages/data-protection/snapshot-task/snapshot-task-card/snapshot-task-card.component.ts index a70ffa73832..42de73f8285 100644 --- a/src/app/pages/data-protection/snapshot-task/snapshot-task-card/snapshot-task-card.component.ts +++ b/src/app/pages/data-protection/snapshot-task/snapshot-task-card/snapshot-task-card.component.ts @@ -88,7 +88,7 @@ export class SnapshotTaskCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'snapshot-task-' + row.dataset + '-' + row.state.state, + uniqueRowTag: (row) => 'snapshot-task-' + row.dataset + '-' + row.state.state, ariaLabels: (row) => [row.dataset, this.translate.instant('Snapshot Task')], }); diff --git a/src/app/pages/data-protection/snapshot-task/snapshot-task-list/snapshot-task-list.component.ts b/src/app/pages/data-protection/snapshot-task/snapshot-task-list/snapshot-task-list.component.ts index 575067474e7..a7c16d62e75 100644 --- a/src/app/pages/data-protection/snapshot-task/snapshot-task-list/snapshot-task-list.component.ts +++ b/src/app/pages/data-protection/snapshot-task/snapshot-task-list/snapshot-task-list.component.ts @@ -15,7 +15,7 @@ import { EmptyService } from 'app/modules/empty/empty.service'; import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provider/async-data-provider'; import { stateButtonColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component'; import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { extractActiveHoursFromCron, scheduleToCrontab } from 'app/modules/scheduler/utils/schedule-to-crontab.utils'; import { SnapshotTaskFormComponent } from 'app/pages/data-protection/snapshot-task/snapshot-task-form/snapshot-task-form.component'; @@ -124,7 +124,7 @@ export class SnapshotTaskListComponent implements OnInit { cssClass: 'state-button', }), ], { - rowTestId: (row) => 'snapshot-task-' + row.dataset + '-' + row.naming_schema, + uniqueRowTag: (row) => 'snapshot-task-' + row.dataset + '-' + row.naming_schema, ariaLabels: (row) => [row.dataset, this.translate.instant('Snapshot Task')], }); diff --git a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-snapshot-list.component.ts b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-snapshot-list.component.ts index 8da59023221..1341b110da4 100644 --- a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-snapshot-list.component.ts +++ b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-snapshot-list.component.ts @@ -54,7 +54,7 @@ export class VmwareSnapshotListComponent implements OnInit { propertyName: 'state', }), ], { - rowTestId: (row) => 'vmware-snapshot-' + row.hostname, + uniqueRowTag: (row) => 'vmware-snapshot-' + row.hostname, ariaLabels: (row) => [row.hostname, this.translate.instant('VMware Snapshot')], }); diff --git a/src/app/pages/datasets/components/dataset-quotas/dataset-quotas-list/dataset-quotas-list.component.ts b/src/app/pages/datasets/components/dataset-quotas/dataset-quotas-list/dataset-quotas-list.component.ts index 4ae88e9568c..b12e07bb3cb 100644 --- a/src/app/pages/datasets/components/dataset-quotas/dataset-quotas-list/dataset-quotas-list.component.ts +++ b/src/app/pages/datasets/components/dataset-quotas/dataset-quotas-list/dataset-quotas-list.component.ts @@ -140,7 +140,7 @@ export class DatasetQuotasListComponent implements OnInit { ], }), ], { - rowTestId: (row) => `${this.helpTextKey}-quota-` + row.name + this.emptyValue + row.obj_quota, + uniqueRowTag: (row) => `${this.helpTextKey}-quota-` + row.name + this.emptyValue + row.obj_quota, ariaLabels: (row) => [row.name, this.translate.instant('Dataset Quota')], }); diff --git a/src/app/pages/datasets/modules/snapshots/snapshot-list/snapshot-list.component.ts b/src/app/pages/datasets/modules/snapshots/snapshot-list/snapshot-list.component.ts index 2d17a2bbf08..243a6e5bd72 100644 --- a/src/app/pages/datasets/modules/snapshots/snapshot-list/snapshot-list.component.ts +++ b/src/app/pages/datasets/modules/snapshots/snapshot-list/snapshot-list.component.ts @@ -124,7 +124,7 @@ export class SnapshotListComponent implements OnInit { getValue: (row) => row?.properties?.referenced?.parsed, }), ], { - rowTestId: (row) => 'snapshot-' + row.id, + uniqueRowTag: (row) => 'snapshot-' + row.id, ariaLabels: (row) => [row.name, this.translate.instant('Snapshot')], }); diff --git a/src/app/pages/directory-service/components/idmap-list/idmap-list.component.ts b/src/app/pages/directory-service/components/idmap-list/idmap-list.component.ts index fdeb6fa021a..9cfd1886431 100644 --- a/src/app/pages/directory-service/components/idmap-list/idmap-list.component.ts +++ b/src/app/pages/directory-service/components/idmap-list/idmap-list.component.ts @@ -109,7 +109,7 @@ export class IdmapListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'idmap-' + row.name, + uniqueRowTag: (row) => 'idmap-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Idmap')], }); diff --git a/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-list/kerberos-keytabs-list.component.ts b/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-list/kerberos-keytabs-list.component.ts index bcad3e36f15..fc3908d0882 100644 --- a/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-list/kerberos-keytabs-list.component.ts +++ b/src/app/pages/directory-service/components/kerberos-keytabs/kerberos-keytabs-list/kerberos-keytabs-list.component.ts @@ -78,7 +78,7 @@ export class KerberosKeytabsListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'kerberos-keytab-' + row.name, + uniqueRowTag: (row) => 'kerberos-keytab-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Kerberos Keytab')], }); diff --git a/src/app/pages/directory-service/components/kerberos-realms/kerberos-realms-list.component.ts b/src/app/pages/directory-service/components/kerberos-realms/kerberos-realms-list.component.ts index bb3ceaed1e6..5bd70b2bbc9 100644 --- a/src/app/pages/directory-service/components/kerberos-realms/kerberos-realms-list.component.ts +++ b/src/app/pages/directory-service/components/kerberos-realms/kerberos-realms-list.component.ts @@ -93,7 +93,7 @@ export class KerberosRealmsListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'kerberos-realm-' + row.realm, + uniqueRowTag: (row) => 'kerberos-realm-' + row.realm, ariaLabels: (row) => [row.realm, this.translate.instant('Kerberos Realm')], }); diff --git a/src/app/pages/jobs/jobs-list/jobs-list.component.ts b/src/app/pages/jobs/jobs-list/jobs-list.component.ts index f2b8e346eae..49a4941f78d 100644 --- a/src/app/pages/jobs/jobs-list/jobs-list.component.ts +++ b/src/app/pages/jobs/jobs-list/jobs-list.component.ts @@ -75,7 +75,7 @@ export class JobsListComponent implements OnInit { sortBy: (job) => +job.time_finished, }), ], { - rowTestId: (row) => 'job-' + row.id, + uniqueRowTag: (row) => 'job-' + row.id, ariaLabels: (row) => [row.description, this.translate.instant('Job')], }); diff --git a/src/app/pages/network/components/interfaces-card/interfaces-card.component.ts b/src/app/pages/network/components/interfaces-card/interfaces-card.component.ts index aa8794a1039..338adbfcbdb 100644 --- a/src/app/pages/network/components/interfaces-card/interfaces-card.component.ts +++ b/src/app/pages/network/components/interfaces-card/interfaces-card.component.ts @@ -26,7 +26,7 @@ import { AppLoaderService } from 'app/modules/loader/app-loader.service'; import { InterfaceFormComponent } from 'app/pages/network/components/interface-form/interface-form.component'; import { interfacesCardElements } from 'app/pages/network/components/interfaces-card/interfaces-card.elements'; import { - IpAddressesCellComponent, + ipAddressesColumn, } from 'app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component'; import { InterfacesStore } from 'app/pages/network/stores/interfaces.store'; import { ErrorHandlerService } from 'app/services/error-handler.service'; @@ -65,11 +65,10 @@ export class InterfacesCardComponent implements OnInit, OnChanges { title: this.translate.instant('Name'), propertyName: 'name', }), - { - type: IpAddressesCellComponent, + ipAddressesColumn({ title: this.translate.instant('IP Addresses'), sortBy: (row) => row.aliases.map((alias) => alias.address).join(', '), - }, + }), actionsColumn({ actions: [ { @@ -98,7 +97,7 @@ export class InterfacesCardComponent implements OnInit, OnChanges { ], }), ], { - rowTestId: (row) => 'interface-' + row.name, + uniqueRowTag: (row) => 'interface-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Interface')], }); diff --git a/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.spec.ts b/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.spec.ts index 5bf63cc411c..35215cdccab 100644 --- a/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.spec.ts +++ b/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.spec.ts @@ -6,9 +6,9 @@ import { } from 'app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component'; describe('IpAddressesCellComponent', () => { - let spectator: Spectator<IpAddressesCellComponent>; + let spectator: Spectator<IpAddressesCellComponent<NetworkInterface>>; const createComponent = createComponentFactory({ - component: IpAddressesCellComponent, + component: IpAddressesCellComponent<NetworkInterface>, }); beforeEach(() => { diff --git a/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.ts b/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.ts index a44294ec34f..c47ab1ebfaf 100644 --- a/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.ts +++ b/src/app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component.ts @@ -1,10 +1,11 @@ import { - ChangeDetectionStrategy, Component, + ChangeDetectionStrategy, ChangeDetectorRef, Component, + inject, } from '@angular/core'; import * as _ from 'lodash-es'; import { NetworkInterfaceAliasType } from 'app/enums/network-interface.enum'; import { NetworkInterface, NetworkInterfaceAlias } from 'app/interfaces/network-interface.interface'; -import { ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; @Component({ selector: 'ix-ip-addresses-cell', @@ -12,12 +13,15 @@ import { ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.in styleUrls: ['./ip-addresses-cell.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class IpAddressesCellComponent extends ColumnComponent<NetworkInterface> { +export class IpAddressesCellComponent<T> extends ColumnComponent<T> { protected addresses: string[] = []; + private readonly cdr = inject(ChangeDetectorRef); - override setRow(row: NetworkInterface): void { - this.addresses = this.extractAddresses(row); - } + override setRow = (row: T): void => { + this.row.set(row); + this.addresses = this.extractAddresses(row as NetworkInterface); + this.cdr.markForCheck(); + }; extractAddresses(row: NetworkInterface): string[] { const addresses = this.aliasesToAddress(row.aliases); @@ -44,3 +48,9 @@ export class IpAddressesCellComponent extends ColumnComponent<NetworkInterface> .map((alias) => `${alias.address}/${alias.netmask}`); } } + +export function ipAddressesColumn<T>( + options: Partial<IpAddressesCellComponent<T>>, +): Column<T, IpAddressesCellComponent<T>> { + return { type: IpAddressesCellComponent, ...options }; +} diff --git a/src/app/pages/network/components/ipmi-card/ipmi-card.component.ts b/src/app/pages/network/components/ipmi-card/ipmi-card.component.ts index d118cf330ca..df35c377565 100644 --- a/src/app/pages/network/components/ipmi-card/ipmi-card.component.ts +++ b/src/app/pages/network/components/ipmi-card/ipmi-card.component.ts @@ -50,7 +50,7 @@ export class IpmiCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'ipmi-' + row.channel + '-' + row.ip_address, + uniqueRowTag: (row) => 'ipmi-' + row.channel + '-' + row.ip_address, ariaLabels: (row) => [row.ip_address, this.translate.instant('IPMI')], }); diff --git a/src/app/pages/network/components/static-routes-card/static-routes-card.component.ts b/src/app/pages/network/components/static-routes-card/static-routes-card.component.ts index 57d644d3fd9..88cd38bc702 100644 --- a/src/app/pages/network/components/static-routes-card/static-routes-card.component.ts +++ b/src/app/pages/network/components/static-routes-card/static-routes-card.component.ts @@ -59,7 +59,7 @@ export class StaticRoutesCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'static-route-' + row.destination + '-' + row.gateway, + uniqueRowTag: (row) => 'static-route-' + row.destination + '-' + row.gateway, ariaLabels: (row) => [row.description, this.translate.instant('Static Route')], }); diff --git a/src/app/pages/network/tests/checkin.spec.ts b/src/app/pages/network/tests/checkin.spec.ts index 247189bd81f..c92afb7699d 100644 --- a/src/app/pages/network/tests/checkin.spec.ts +++ b/src/app/pages/network/tests/checkin.spec.ts @@ -29,9 +29,6 @@ import { IxTableHarness } from 'app/modules/ix-table/components/ix-table/ix-tabl import { IxTableModule } from 'app/modules/ix-table/ix-table.module'; import { InterfaceFormComponent } from 'app/pages/network/components/interface-form/interface-form.component'; import { InterfacesCardComponent } from 'app/pages/network/components/interfaces-card/interfaces-card.component'; -import { - IpAddressesCellComponent, -} from 'app/pages/network/components/interfaces-card/ip-addresses-cell/ip-addresses-cell.component'; import { IpmiCardComponent } from 'app/pages/network/components/ipmi-card/ipmi-card.component'; import { NetworkConfigurationCardComponent, @@ -70,7 +67,6 @@ describe('NetworkComponent', () => { StaticRoutesCardComponent, IpmiCardComponent, InterfaceStatusIconComponent, - IpAddressesCellComponent, ), ], providers: [ diff --git a/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-list/reporting-exporters-list.component.ts b/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-list/reporting-exporters-list.component.ts index bb467e29f2a..579615718f1 100644 --- a/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-list/reporting-exporters-list.component.ts +++ b/src/app/pages/reports-dashboard/components/exporters/reporting-exporters-list/reporting-exporters-list.component.ts @@ -86,7 +86,7 @@ export class ReportingExporterListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'reporting-exporter-' + row.name, + uniqueRowTag: (row) => 'reporting-exporter-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Reporting Exporter')], }); diff --git a/src/app/pages/services/services.component.ts b/src/app/pages/services/services.component.ts index 1cd6b67cc42..e3f34c4e780 100644 --- a/src/app/pages/services/services.component.ts +++ b/src/app/pages/services/services.component.ts @@ -94,7 +94,7 @@ export class ServicesComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'service-' + row.name.replace(/\./g, ''), + uniqueRowTag: (row) => 'service-' + row.name.replace(/\./g, ''), ariaLabels: (row) => [row.name, this.translate.instant('Service')], }); diff --git a/src/app/pages/sharing/components/shares-dashboard/iscsi-card/iscsi-card.component.ts b/src/app/pages/sharing/components/shares-dashboard/iscsi-card/iscsi-card.component.ts index a13003ec2aa..6a6077e5f6a 100644 --- a/src/app/pages/sharing/components/shares-dashboard/iscsi-card/iscsi-card.component.ts +++ b/src/app/pages/sharing/components/shares-dashboard/iscsi-card/iscsi-card.component.ts @@ -68,7 +68,7 @@ export class IscsiCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-iscsi-target-' + row.name, + uniqueRowTag: (row) => 'card-iscsi-target-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('iSCSI Target')], }); diff --git a/src/app/pages/sharing/components/shares-dashboard/nfs-card/nfs-card.component.ts b/src/app/pages/sharing/components/shares-dashboard/nfs-card/nfs-card.component.ts index 6db05087fef..3d636b88f70 100644 --- a/src/app/pages/sharing/components/shares-dashboard/nfs-card/nfs-card.component.ts +++ b/src/app/pages/sharing/components/shares-dashboard/nfs-card/nfs-card.component.ts @@ -67,7 +67,7 @@ export class NfsCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-nfs-share-' + row.path + '-' + row.comment, + uniqueRowTag: (row) => 'card-nfs-share-' + row.path + '-' + row.comment, ariaLabels: (row) => [row.path, this.translate.instant('NFS Share')], }); diff --git a/src/app/pages/sharing/components/shares-dashboard/smb-card/smb-card.component.ts b/src/app/pages/sharing/components/shares-dashboard/smb-card/smb-card.component.ts index 4c3d243e2ba..817752dd389 100644 --- a/src/app/pages/sharing/components/shares-dashboard/smb-card/smb-card.component.ts +++ b/src/app/pages/sharing/components/shares-dashboard/smb-card/smb-card.component.ts @@ -101,7 +101,7 @@ export class SmbCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-smb-share-' + row.name, + uniqueRowTag: (row) => 'card-smb-share-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('SMB Share')], }); diff --git a/src/app/pages/sharing/iscsi/associated-target/associated-target-list/associated-target-list.component.ts b/src/app/pages/sharing/iscsi/associated-target/associated-target-list/associated-target-list.component.ts index 22f3bf1c385..ed72d344835 100644 --- a/src/app/pages/sharing/iscsi/associated-target/associated-target-list/associated-target-list.component.ts +++ b/src/app/pages/sharing/iscsi/associated-target/associated-target-list/associated-target-list.component.ts @@ -113,7 +113,7 @@ export class AssociatedTargetListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'iscsi-associated-target-' + row.target + '-' + row.extent, + uniqueRowTag: (row) => 'iscsi-associated-target-' + row.target + '-' + row.extent, ariaLabels: (row) => [row.target.toString(), this.translate.instant('ISCSI Associated Target')], }); diff --git a/src/app/pages/sharing/iscsi/authorized-access/authorized-access-list/authorized-access-list.component.ts b/src/app/pages/sharing/iscsi/authorized-access/authorized-access-list/authorized-access-list.component.ts index cad511ff6c9..58210686cc1 100644 --- a/src/app/pages/sharing/iscsi/authorized-access/authorized-access-list/authorized-access-list.component.ts +++ b/src/app/pages/sharing/iscsi/authorized-access/authorized-access-list/authorized-access-list.component.ts @@ -87,7 +87,7 @@ export class AuthorizedAccessListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'iscsi-authorized-access-' + row.user + '-' + row.peeruser, + uniqueRowTag: (row) => 'iscsi-authorized-access-' + row.user + '-' + row.peeruser, ariaLabels: (row) => [row.user, this.translate.instant('Authorized Access')], }); diff --git a/src/app/pages/sharing/iscsi/extent/extent-list/extent-list.component.ts b/src/app/pages/sharing/iscsi/extent/extent-list/extent-list.component.ts index f0f113fc752..c7909c152dc 100644 --- a/src/app/pages/sharing/iscsi/extent/extent-list/extent-list.component.ts +++ b/src/app/pages/sharing/iscsi/extent/extent-list/extent-list.component.ts @@ -89,7 +89,7 @@ export class ExtentListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'iscsi-extent-' + row.name, + uniqueRowTag: (row) => 'iscsi-extent-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('iSCSI Extent')], }); diff --git a/src/app/pages/sharing/iscsi/initiator/initiator-list/initiator-list.component.ts b/src/app/pages/sharing/iscsi/initiator/initiator-list/initiator-list.component.ts index bd917604e1c..3b7209d740b 100644 --- a/src/app/pages/sharing/iscsi/initiator/initiator-list/initiator-list.component.ts +++ b/src/app/pages/sharing/iscsi/initiator/initiator-list/initiator-list.component.ts @@ -86,7 +86,7 @@ export class InitiatorListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'iscsi-initiator-' + row.id, + uniqueRowTag: (row) => 'iscsi-initiator-' + row.id, ariaLabels: (row) => [row.id.toString(), this.translate.instant('iSCSI Initiator')], }); diff --git a/src/app/pages/sharing/iscsi/portal/portal-list/portal-list.component.ts b/src/app/pages/sharing/iscsi/portal/portal-list/portal-list.component.ts index 409eb66e5af..c944c357bb9 100644 --- a/src/app/pages/sharing/iscsi/portal/portal-list/portal-list.component.ts +++ b/src/app/pages/sharing/iscsi/portal/portal-list/portal-list.component.ts @@ -102,7 +102,7 @@ export class PortalListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'iscsi-portal-' + row.comment, + uniqueRowTag: (row) => 'iscsi-portal-' + row.comment, ariaLabels: (row) => [row.comment, this.translate.instant('Portal')], }); diff --git a/src/app/pages/sharing/iscsi/target/target-list/target-list.component.ts b/src/app/pages/sharing/iscsi/target/target-list/target-list.component.ts index 64ece3c904d..49b4b11b02f 100644 --- a/src/app/pages/sharing/iscsi/target/target-list/target-list.component.ts +++ b/src/app/pages/sharing/iscsi/target/target-list/target-list.component.ts @@ -94,7 +94,7 @@ export class TargetListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'iscsi-target-' + row.name, + uniqueRowTag: (row) => 'iscsi-target-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Target')], }); diff --git a/src/app/pages/sharing/nfs/nfs-list/nfs-list.component.ts b/src/app/pages/sharing/nfs/nfs-list/nfs-list.component.ts index 8356a0884cf..d4657b110b7 100644 --- a/src/app/pages/sharing/nfs/nfs-list/nfs-list.component.ts +++ b/src/app/pages/sharing/nfs/nfs-list/nfs-list.component.ts @@ -122,7 +122,7 @@ export class NfsListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'nfs-share-' + row.path + '-' + row.comment, + uniqueRowTag: (row) => 'nfs-share-' + row.path + '-' + row.comment, ariaLabels: (row) => [row.path, this.translate.instant('NFS Share')], }); diff --git a/src/app/pages/sharing/nfs/nfs-session-list/nfs-session-list.component.ts b/src/app/pages/sharing/nfs/nfs-session-list/nfs-session-list.component.ts index 3318158a73a..f4b964ddb3d 100644 --- a/src/app/pages/sharing/nfs/nfs-session-list/nfs-session-list.component.ts +++ b/src/app/pages/sharing/nfs/nfs-session-list/nfs-session-list.component.ts @@ -10,7 +10,7 @@ import { Nfs3Session, Nfs4Session, NfsType } from 'app/interfaces/nfs-share.inte import { EmptyService } from 'app/modules/empty/empty.service'; import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provider/async-data-provider'; import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { nfsSessionListElements } from 'app/pages/sharing/nfs/nfs-session-list/nfs-session-list.elements'; import { WebSocketService } from 'app/services/ws.service'; @@ -39,7 +39,7 @@ export class NfsSessionListComponent implements OnInit { propertyName: 'export', }), ], { - rowTestId: (row) => 'nfs3-session-' + row.export + '-' + row.ip, + uniqueRowTag: (row) => 'nfs3-session-' + row.export + '-' + row.ip, ariaLabels: (row) => [row.ip, this.translate.instant('NFS3 Session')], }); @@ -91,7 +91,7 @@ export class NfsSessionListComponent implements OnInit { hidden: true, }), ], { - rowTestId: (row) => 'nfs4-session-' + row.address + '-' + row.clientid, + uniqueRowTag: (row) => 'nfs4-session-' + row.address + '-' + row.clientid, ariaLabels: (row) => [row.name, this.translate.instant('NFS4 Session')], }); diff --git a/src/app/pages/sharing/smb/smb-list/smb-list.component.ts b/src/app/pages/sharing/smb/smb-list/smb-list.component.ts index cfdb2c43a4d..81038f7ee06 100644 --- a/src/app/pages/sharing/smb/smb-list/smb-list.component.ts +++ b/src/app/pages/sharing/smb/smb-list/smb-list.component.ts @@ -165,7 +165,7 @@ export class SmbListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'smb-' + row.name, + uniqueRowTag: (row) => 'smb-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('SMB Share')], }); diff --git a/src/app/pages/sharing/smb/smb-status/components/smb-lock-list/smb-lock-list.component.ts b/src/app/pages/sharing/smb/smb-status/components/smb-lock-list/smb-lock-list.component.ts index cc5d637bf97..c1e3de11842 100644 --- a/src/app/pages/sharing/smb/smb-status/components/smb-lock-list/smb-lock-list.component.ts +++ b/src/app/pages/sharing/smb/smb-status/components/smb-lock-list/smb-lock-list.component.ts @@ -46,7 +46,7 @@ export class SmbLockListComponent implements OnInit { propertyName: 'num_pending_deletes', }), ], { - rowTestId: (row) => 'smb-lock-' + row.filename + '-' + row.fileid.devid + '-' + row.fileid.extid, + uniqueRowTag: (row) => 'smb-lock-' + row.filename + '-' + row.fileid.devid + '-' + row.fileid.extid, ariaLabels: (row) => [row.filename, this.translate.instant('SMB Lock')], }); diff --git a/src/app/pages/sharing/smb/smb-status/components/smb-notification-list/smb-notification-list.component.ts b/src/app/pages/sharing/smb/smb-status/components/smb-notification-list/smb-notification-list.component.ts index 679589c5cd6..0ae5a601871 100644 --- a/src/app/pages/sharing/smb/smb-status/components/smb-notification-list/smb-notification-list.component.ts +++ b/src/app/pages/sharing/smb/smb-status/components/smb-notification-list/smb-notification-list.component.ts @@ -29,7 +29,7 @@ export class SmbNotificationListComponent implements OnInit { textColumn({ title: this.translate.instant('Subdir Filter'), propertyName: 'subdir_filter' }), textColumn({ title: this.translate.instant('Creation Time'), propertyName: 'creation_time' }), ], { - rowTestId: (row) => 'smb-notification-' + row.creation_time + '-' + row.server_id.unique_id, + uniqueRowTag: (row) => 'smb-notification-' + row.creation_time + '-' + row.server_id.unique_id, ariaLabels: (row) => [row.creation_time, this.translate.instant('SMB Notification')], }); diff --git a/src/app/pages/sharing/smb/smb-status/components/smb-open-files/smb-open-files.component.ts b/src/app/pages/sharing/smb/smb-status/components/smb-open-files/smb-open-files.component.ts index 08affa20e08..362f15449a8 100644 --- a/src/app/pages/sharing/smb/smb-status/components/smb-open-files/smb-open-files.component.ts +++ b/src/app/pages/sharing/smb/smb-status/components/smb-open-files/smb-open-files.component.ts @@ -41,7 +41,7 @@ export class SmbOpenFilesComponent implements OnChanges { }), textColumn({ title: this.translate.instant('Opened at'), propertyName: 'opened_at' }), ], { - rowTestId: (row) => 'smb-open-file-' + row.username + '-' + row.uid, + uniqueRowTag: (row) => 'smb-open-file-' + row.username + '-' + row.uid, ariaLabels: (row) => [row.username, this.translate.instant('SMB Open File')], }); diff --git a/src/app/pages/sharing/smb/smb-status/components/smb-session-list/smb-session-list.component.ts b/src/app/pages/sharing/smb/smb-status/components/smb-session-list/smb-session-list.component.ts index dec78b3b9c7..74df17c20ba 100644 --- a/src/app/pages/sharing/smb/smb-status/components/smb-session-list/smb-session-list.component.ts +++ b/src/app/pages/sharing/smb/smb-status/components/smb-session-list/smb-session-list.component.ts @@ -43,7 +43,7 @@ export class SmbSessionListComponent implements OnInit { getValue: (row) => row.signing.cipher, }), ], { - rowTestId: (row) => 'smb-session-' + row.session_id, + uniqueRowTag: (row) => 'smb-session-' + row.session_id, ariaLabels: (row) => [row.hostname, this.translate.instant('SMB Session')], }); diff --git a/src/app/pages/sharing/smb/smb-status/components/smb-share-list/smb-share-list.component.ts b/src/app/pages/sharing/smb/smb-status/components/smb-share-list/smb-share-list.component.ts index 99f9fedeffd..7bc81edf707 100644 --- a/src/app/pages/sharing/smb/smb-status/components/smb-share-list/smb-share-list.component.ts +++ b/src/app/pages/sharing/smb/smb-status/components/smb-share-list/smb-share-list.component.ts @@ -39,7 +39,7 @@ export class SmbShareListComponent implements OnInit { getValue: (row) => row.signing.cipher, }), ], { - rowTestId: (row) => 'smb-share-' + row.server_id.unique_id + '-' + row.machine, + uniqueRowTag: (row) => 'smb-share-' + row.server_id.unique_id + '-' + row.machine, ariaLabels: (row) => [row.machine, this.translate.instant('SMB Share')], }); diff --git a/src/app/pages/storage/modules/disks/components/disk-list/disk-list.component.ts b/src/app/pages/storage/modules/disks/components/disk-list/disk-list.component.ts index 82bee551760..aa3a521b2fd 100644 --- a/src/app/pages/storage/modules/disks/components/disk-list/disk-list.component.ts +++ b/src/app/pages/storage/modules/disks/components/disk-list/disk-list.component.ts @@ -19,7 +19,7 @@ import { IxSlideInRef } from 'app/modules/forms/ix-forms/components/ix-slide-in/ import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provider/async-data-provider'; import { checkboxColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-checkbox/ix-cell-checkbox.component'; import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { DiskBulkEditComponent } from 'app/pages/storage/modules/disks/components/disk-bulk-edit/disk-bulk-edit.component'; import { DiskFormComponent } from 'app/pages/storage/modules/disks/components/disk-form/disk-form.component'; @@ -133,7 +133,7 @@ export class DiskListComponent implements OnInit { hidden: true, }), ], { - rowTestId: (row) => `disk-${row.name}`, + uniqueRowTag: (row) => `disk-${row.name}`, ariaLabels: (row) => [row.name, this.translate.instant('Disk')], }); diff --git a/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.spec.ts b/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.spec.ts index 5841035b72e..a1a6de95200 100644 --- a/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.spec.ts +++ b/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.spec.ts @@ -43,7 +43,7 @@ describe('SmartTestResultListComponent', () => { remaining: null, }, { - num: 1, + num: 3, description: 'Background short', status_verbose: 'Completed', segment_number: null, @@ -75,7 +75,7 @@ describe('SmartTestResultListComponent', () => { remaining: null, }, { - num: 1, + num: 3, description: 'Background short', status_verbose: 'Completed', segment_number: null, diff --git a/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.ts b/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.ts index dd811393b92..c66ce98f64a 100644 --- a/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.ts +++ b/src/app/pages/storage/modules/disks/components/smart-test-result-list/smart-test-result-list.component.ts @@ -16,7 +16,7 @@ import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provi import { stateButtonColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-state-button/ix-cell-state-button.component'; import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; import { SortDirection } from 'app/modules/ix-table/enums/sort-direction.enum'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { WebSocketService } from 'app/services/ws.service'; @@ -70,7 +70,7 @@ export class SmartTestResultListComponent implements OnInit { }, }), ], { - rowTestId: (row) => `smart-test-result-${row.disk}-${row.num}`, + uniqueRowTag: (row) => `smart-test-result-${row.disk}-${row.num}`, ariaLabels: (row) => [row.disk, this.translate.instant('Smart Test Result')], }); diff --git a/src/app/pages/system/advanced/access/access-card/access-card.component.ts b/src/app/pages/system/advanced/access/access-card/access-card.component.ts index 8df4b0aebdc..396504f7ccd 100644 --- a/src/app/pages/system/advanced/access/access-card/access-card.component.ts +++ b/src/app/pages/system/advanced/access/access-card/access-card.component.ts @@ -88,7 +88,7 @@ export class AccessCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'session-' + this.getUsername(row) + '-' + row.origin, + uniqueRowTag: (row) => 'session-' + this.getUsername(row) + '-' + row.origin, ariaLabels: (row) => [this.getUsername(row), this.translate.instant('Session')], }); diff --git a/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-card/allowed-addresses-card.component.ts b/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-card/allowed-addresses-card.component.ts index 87006ec1ab5..3947d7998d7 100644 --- a/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-card/allowed-addresses-card.component.ts +++ b/src/app/pages/system/advanced/allowed-addresses/allowed-addresses-card/allowed-addresses-card.component.ts @@ -56,7 +56,7 @@ export class AllowedAddressesCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'allowed-address-' + row.address, + uniqueRowTag: (row) => 'allowed-address-' + row.address, ariaLabels: (row) => [row.address, this.translate.instant('Allowed Address')], }); diff --git a/src/app/pages/system/advanced/cron/cron-card/cron-card.component.ts b/src/app/pages/system/advanced/cron/cron-card/cron-card.component.ts index 1e49e7404fc..e04f1a4eef2 100644 --- a/src/app/pages/system/advanced/cron/cron-card/cron-card.component.ts +++ b/src/app/pages/system/advanced/cron/cron-card/cron-card.component.ts @@ -94,7 +94,7 @@ export class CronCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-cron-' + row.command + '-' + row.user, + uniqueRowTag: (row) => 'card-cron-' + row.command + '-' + row.user, ariaLabels: (row) => [row.command, this.translate.instant('Cron Job')], }); diff --git a/src/app/pages/system/advanced/cron/cron-list/cron-list.component.ts b/src/app/pages/system/advanced/cron/cron-list/cron-list.component.ts index dd9fc335530..b485b4c1526 100644 --- a/src/app/pages/system/advanced/cron/cron-list/cron-list.component.ts +++ b/src/app/pages/system/advanced/cron/cron-list/cron-list.component.ts @@ -13,7 +13,7 @@ import { DialogService } from 'app/modules/dialog/dialog.service'; import { EmptyService } from 'app/modules/empty/empty.service'; import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provider/async-data-provider'; import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-text/ix-cell-text.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { scheduleToCrontab } from 'app/modules/scheduler/utils/schedule-to-crontab.utils'; import { CronDeleteDialogComponent } from 'app/pages/system/advanced/cron/cron-delete-dialog/cron-delete-dialog.component'; @@ -87,7 +87,7 @@ export class CronListComponent implements OnInit { hidden: true, }), ], { - rowTestId: (row) => 'cron-' + row.command + '-' + row.description, + uniqueRowTag: (row) => 'cron-' + row.command + '-' + row.description, ariaLabels: (row) => [row.command, this.translate.instant('Cron Job')], }); diff --git a/src/app/pages/system/advanced/init-shutdown/init-shutdown-card/init-shutdown-card.component.ts b/src/app/pages/system/advanced/init-shutdown/init-shutdown-card/init-shutdown-card.component.ts index 19a2f397a87..1600fe52b3e 100644 --- a/src/app/pages/system/advanced/init-shutdown/init-shutdown-card/init-shutdown-card.component.ts +++ b/src/app/pages/system/advanced/init-shutdown/init-shutdown-card/init-shutdown-card.component.ts @@ -78,7 +78,7 @@ export class InitShutdownCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'card-init-shutdown-' + row.command + '-' + row.when, + uniqueRowTag: (row) => 'card-init-shutdown-' + row.command + '-' + row.when, ariaLabels: (row) => [row.command, this.translate.instant('Init/Shutdown Script')], }); diff --git a/src/app/pages/system/advanced/init-shutdown/init-shutdown-list/init-shutdown-list.component.ts b/src/app/pages/system/advanced/init-shutdown/init-shutdown-list/init-shutdown-list.component.ts index 2fc74537715..1d2254ff86e 100644 --- a/src/app/pages/system/advanced/init-shutdown/init-shutdown-list/init-shutdown-list.component.ts +++ b/src/app/pages/system/advanced/init-shutdown/init-shutdown-list/init-shutdown-list.component.ts @@ -85,7 +85,7 @@ export class InitShutdownListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'init-shutdown-' + row.command + '-' + row.type, + uniqueRowTag: (row) => 'init-shutdown-' + row.command + '-' + row.type, ariaLabels: (row) => [row.command, this.translate.instant('Init/Shutdown Script')], }); diff --git a/src/app/pages/system/advanced/sysctl/sysctl-card/sysctl-card.component.ts b/src/app/pages/system/advanced/sysctl/sysctl-card/sysctl-card.component.ts index b9958023506..8b5d32b3c62 100644 --- a/src/app/pages/system/advanced/sysctl/sysctl-card/sysctl-card.component.ts +++ b/src/app/pages/system/advanced/sysctl/sysctl-card/sysctl-card.component.ts @@ -67,7 +67,7 @@ export class SysctlCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'sysctl-' + row.var + '-' + row.value, + uniqueRowTag: (row) => 'sysctl-' + row.var + '-' + row.value, ariaLabels: (row) => [row.var, this.translate.instant('Sysctl')], }); diff --git a/src/app/pages/system/advanced/sysctl/tunable-list/tunable-list.component.ts b/src/app/pages/system/advanced/sysctl/tunable-list/tunable-list.component.ts index 00de6e345b0..f859441ed2a 100644 --- a/src/app/pages/system/advanced/sysctl/tunable-list/tunable-list.component.ts +++ b/src/app/pages/system/advanced/sysctl/tunable-list/tunable-list.component.ts @@ -75,7 +75,7 @@ export class TunableListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'tunable-' + row.var + '-' + row.value, + uniqueRowTag: (row) => 'tunable-' + row.var + '-' + row.value, ariaLabels: (row) => [row.var, this.translate.instant('Tunable')], }); diff --git a/src/app/pages/system/alert-service/alert-service-list/alert-service-list.component.ts b/src/app/pages/system/alert-service/alert-service-list/alert-service-list.component.ts index 4aad635f339..0f356266a20 100644 --- a/src/app/pages/system/alert-service/alert-service-list/alert-service-list.component.ts +++ b/src/app/pages/system/alert-service/alert-service-list/alert-service-list.component.ts @@ -75,7 +75,7 @@ export class AlertServiceListComponent implements OnInit { ], }), ], { - rowTestId: (row) => `disk-${row.name}`, + uniqueRowTag: (row) => `disk-${row.name}`, ariaLabels: (row) => [row.name, this.translate.instant('Disk')], }); diff --git a/src/app/pages/system/bootenv/bootenv-list/bootenv-list.component.ts b/src/app/pages/system/bootenv/bootenv-list/bootenv-list.component.ts index 7df85938ea6..1b19cf43cd9 100644 --- a/src/app/pages/system/bootenv/bootenv-list/bootenv-list.component.ts +++ b/src/app/pages/system/bootenv/bootenv-list/bootenv-list.component.ts @@ -156,7 +156,7 @@ export class BootEnvironmentListComponent implements OnInit { cssClass: 'actions-column', }), ], { - rowTestId: (row) => `bootenv-${row.name}`, + uniqueRowTag: (row) => `bootenv-${row.name}`, ariaLabels: (row) => [row.name, this.translate.instant('Boot Environment')], }); diff --git a/src/app/pages/system/enclosure/components/jbof-list/jbof-list.component.ts b/src/app/pages/system/enclosure/components/jbof-list/jbof-list.component.ts index 9b5321e1749..05d4eea33e8 100644 --- a/src/app/pages/system/enclosure/components/jbof-list/jbof-list.component.ts +++ b/src/app/pages/system/enclosure/components/jbof-list/jbof-list.component.ts @@ -66,7 +66,7 @@ export class JbofListComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'jbof-' + row.mgmt_username, + uniqueRowTag: (row) => 'jbof-' + row.mgmt_username, ariaLabels: (row) => [row.mgmt_username, this.translate.instant('JBOF')], }); diff --git a/src/app/pages/system/enclosure/components/pages/elements-page/elements-page.component.ts b/src/app/pages/system/enclosure/components/pages/elements-page/elements-page.component.ts index 6da96ae8df6..402226abd3b 100644 --- a/src/app/pages/system/enclosure/components/pages/elements-page/elements-page.component.ts +++ b/src/app/pages/system/enclosure/components/pages/elements-page/elements-page.component.ts @@ -61,7 +61,7 @@ export class ElementsPageComponent { }), ], { - rowTestId: (element) => element.descriptor, + uniqueRowTag: (element) => element.descriptor, ariaLabels: (row) => [row.descriptor, this.translate.instant('Element')], }, ); diff --git a/src/app/pages/system/general-settings/ntp-server/ntp-server-card/ntp-server-card.component.ts b/src/app/pages/system/general-settings/ntp-server/ntp-server-card/ntp-server-card.component.ts index 2c1f0ec11d8..5d1d68bbc97 100644 --- a/src/app/pages/system/general-settings/ntp-server/ntp-server-card/ntp-server-card.component.ts +++ b/src/app/pages/system/general-settings/ntp-server/ntp-server-card/ntp-server-card.component.ts @@ -73,7 +73,7 @@ export class NtpServerCardComponent implements OnInit { ], }), ], { - rowTestId: (row) => 'ntp-server-' + row.address + '-' + row.minpoll + '-' + row.maxpoll, + uniqueRowTag: (row) => 'ntp-server-' + row.address + '-' + row.minpoll + '-' + row.maxpoll, ariaLabels: (row) => [row.address, this.translate.instant('NTP Server')], }); diff --git a/src/app/pages/vm/devices/device-list/device-list/device-list.component.ts b/src/app/pages/vm/devices/device-list/device-list/device-list.component.ts index 0b5c24003ef..e4076421f10 100644 --- a/src/app/pages/vm/devices/device-list/device-list/device-list.component.ts +++ b/src/app/pages/vm/devices/device-list/device-list/device-list.component.ts @@ -55,7 +55,7 @@ export class DeviceListComponent implements OnInit { }), actionsColumn({}), ], { - rowTestId: (row) => 'vm-device-' + row.dtype + '-' + row.order, + uniqueRowTag: (row) => 'vm-device-' + row.dtype + '-' + row.order, ariaLabels: (row) => [row.dtype, this.translate.instant('Device')], }); diff --git a/src/app/pages/vm/vm-list/vm-list.component.ts b/src/app/pages/vm/vm-list/vm-list.component.ts index dbdaae0f917..ae48e2efb2f 100644 --- a/src/app/pages/vm/vm-list/vm-list.component.ts +++ b/src/app/pages/vm/vm-list/vm-list.component.ts @@ -19,7 +19,7 @@ import { textColumn } from 'app/modules/ix-table/components/ix-table-body/cells/ import { toggleColumn, } from 'app/modules/ix-table/components/ix-table-body/cells/ix-cell-toggle/ix-cell-toggle.component'; -import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/table-column.interface'; +import { Column, ColumnComponent } from 'app/modules/ix-table/interfaces/column-component.class'; import { createTable } from 'app/modules/ix-table/utils'; import { FileSizePipe } from 'app/modules/pipes/file-size/file-size.pipe'; import { vmListElements } from 'app/pages/vm/vm-list/vm-list.elements'; @@ -121,7 +121,7 @@ export class VmListComponent implements OnInit { getValue: (row) => `${row.shutdown_timeout} seconds`, }), ], { - rowTestId: (row) => 'virtual-machine-' + row.name, + uniqueRowTag: (row) => 'virtual-machine-' + row.name, ariaLabels: (row) => [row.name, this.translate.instant('Virtual Machine')], }); diff --git a/tsconfig.strictNullChecks.json b/tsconfig.strictNullChecks.json index 8ce81127317..07732aac95a 100644 --- a/tsconfig.strictNullChecks.json +++ b/tsconfig.strictNullChecks.json @@ -500,7 +500,7 @@ "./src/app/modules/ix-table/directives/ix-table-details-row.directive.ts", "./src/app/modules/ix-table/enums/sort-direction.enum.ts", "./src/app/modules/ix-table/interfaces/data-provider.interface.ts", - "./src/app/modules/ix-table/interfaces/table-column.interface.ts", + "./src/app/modules/ix-table/interfaces/column-component.class.ts", "./src/app/modules/ix-table/interfaces/table-pagination.interface.ts", "./src/app/modules/ix-table/interfaces/table-sort.interface.ts", "./src/app/modules/ix-table/utils.ts",