From 36fe15573d7ee1289bee20a8f72219d94ee57fe4 Mon Sep 17 00:00:00 2001 From: Alex Karpov Date: Mon, 1 Jul 2024 09:17:57 +0300 Subject: [PATCH] NAS-129788 / 24.10 / Cloud Backup | Snapshots list is not updating after Job Run (#10257) * NAS-129788: Cloud Backup | Snapshots list is not updating after Job Run * NAS-129788: PR update * NAS-129788: PR update --- .../cloud-backup-list.component.spec.ts | 46 ++++++++++++++++++- .../cloud-backup-list.component.ts | 6 ++- 2 files changed, 50 insertions(+), 2 deletions(-) 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 f1cb2df74f4..e8e43315384 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 @@ -7,14 +7,16 @@ import { provideMockStore } from '@ngrx/store/testing'; import { MockComponents, MockModule } from 'ng-mocks'; 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'; +import { mockCall, mockJob, mockWebSocket } from 'app/core/testing/utils/mock-websocket.utils'; import { JobState } from 'app/enums/job-state.enum'; import { CloudBackup } from 'app/interfaces/cloud-backup.interface'; import { DialogService } from 'app/modules/dialog/dialog.service'; import { IxSlideInRef } from 'app/modules/forms/ix-forms/components/ix-slide-in/ix-slide-in-ref'; import { SearchInput1Component } from 'app/modules/forms/search-input1/search-input1.component'; import { IxIconHarness } from 'app/modules/ix-icon/ix-icon.harness'; +import { AsyncDataProvider } from 'app/modules/ix-table/classes/async-data-provider/async-data-provider'; 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 { AppLoaderModule } from 'app/modules/loader/app-loader.module'; import { PageHeaderModule } from 'app/modules/page-header/page-header.module'; @@ -69,6 +71,7 @@ describe('CloudBackupListComponent', () => { mockCall('cloud_backup.query', cloudBackups), mockCall('cloud_backup.delete'), mockCall('cloud_backup.update'), + mockJob('cloud_backup.sync'), ]), mockProvider(DialogService, { confirm: jest.fn(() => of(true)), @@ -133,6 +136,7 @@ describe('CloudBackupListComponent', () => { }); expect(spectator.inject(WebSocketService).job).toHaveBeenCalledWith('cloud_backup.sync', [1]); + expect(spectator.component.dataProvider.expandedRow).toEqual({ ...cloudBackups[0] }); }); it('deletes a Cloud Backup with confirmation when Delete button is pressed', async () => { @@ -159,4 +163,44 @@ describe('CloudBackupListComponent', () => { [1, { enabled: true }], ); }); + + it('closes mobile details view and updates dataProvider expandedRow', () => { + spectator.component.showMobileDetails = true; + spectator.component.dataProvider.expandedRow = cloudBackups[0]; + + spectator.component.closeMobileDetails(); + + expect(spectator.component.showMobileDetails).toBe(false); + expect(spectator.component.dataProvider.expandedRow).toBeNull(); + }); + + it('sets the default sort for dataProvider', () => { + spectator.component.dataProvider = { + setSorting: jest.fn(), + } as unknown as AsyncDataProvider; + + spectator.component.setDefaultSort(); + + expect(spectator.component.dataProvider.setSorting).toHaveBeenCalledWith({ + active: 1, + direction: SortDirection.Asc, + propertyName: 'description', + }); + }); + + it('filters the list of cloud backups based on the query string', () => { + spectator.component.dataProvider = { + setFilter: jest.fn(), + } as unknown as AsyncDataProvider; + + const queryString = 'UA'; + spectator.component.onListFiltered(queryString); + + expect(spectator.component.filterString).toBe(queryString.toLowerCase()); + + expect(spectator.component.dataProvider.setFilter).toHaveBeenCalledWith({ + query: queryString, + columnKeys: ['description'], + }); + }); }); 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 98326455701..d343d6e19e7 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 @@ -162,12 +162,16 @@ export class CloudBackupListComponent implements OnInit { }).pipe( filter(Boolean), tap(() => this.updateRowJob(row, { ...row.job, state: JobState.Running })), + tap(() => this.snackbar.success(this.translate.instant('Cloud Backup «{name}» has started.', { name: row.description }))), switchMap(() => this.ws.job('cloud_backup.sync', [row.id])), untilDestroyed(this), ).subscribe({ next: (job: Job) => { - this.snackbar.success(this.translate.instant('Cloud Backup «{name}» has started.', { name: row.description })); this.updateRowJob(row, job); + // Update expanded row to call child ngOnChanges method & update snapshots list + if (job.state === JobState.Success && this.dataProvider.expandedRow?.id === row.id) { + this.dataProvider.expandedRow = { ...row }; + } this.cdr.markForCheck(); }, error: (error: unknown) => {