From 57a0260b51255645ff3eb298632014938bb801cd Mon Sep 17 00:00:00 2001 From: Volha Mardvilka Date: Mon, 10 Mar 2025 12:55:04 +0000 Subject: [PATCH] 396678430: (feat) [GM3] add download result options --- .../download-options.component.html | 83 ++++++------ .../download-options.component.scss | 118 +++++++++--------- .../download-options.component.spec.ts | 91 +++----------- .../download-options.component.ts | 53 +++----- .../app/pages/testrun/testrun.component.html | 24 +--- .../app/pages/testrun/testrun.component.scss | 22 +--- .../pages/testrun/testrun.component.spec.ts | 8 +- .../app/pages/testrun/testrun.component.ts | 7 +- 8 files changed, 150 insertions(+), 256 deletions(-) diff --git a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.html b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.html index eb4062de5..cb93d62c3 100644 --- a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.html +++ b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.html @@ -13,38 +13,51 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - lab_profile - - {{ DownloadOption.PDF }} - - - - - archive - - {{ DownloadOption.ZIP }} - - - - +
+ + + + archive + + {{ DownloadOption.ZIP }} + + +
diff --git a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.scss b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.scss index 31f34c50f..5e8f7da54 100644 --- a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.scss +++ b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.scss @@ -17,79 +17,75 @@ @use 'node_modules/@angular/material/index' as mat; @use 'm3-theme' as *; @use 'colors'; +@use 'variables'; -$option-width: 170px; -$option-height: 36px; - -.download-options-field { - width: $option-width; - background: mat.get-theme-color($light-theme, primary, 95); - - ::ng-deep.mat-mdc-text-field-wrapper { - padding: 0 16px; - } - - ::ng-deep.mat-mdc-form-field-subscript-wrapper { - display: none; - } - - ::ng-deep.mat-mdc-form-field-infix { - padding: 6px 0; - width: $option-width; - min-height: $option-height; - } - - ::ng-deep.mat-mdc-select-placeholder { - color: mat.get-theme-color($light-theme, primary, 30); - font-size: 14px; - font-style: normal; - font-weight: 500; - line-height: 20px; - letter-spacing: 0.25px; - } +.download-actions { + position: fixed; + right: 40px; + bottom: 32px; + display: flex; + flex-direction: column; + align-items: flex-end; + justify-content: flex-end; + gap: 4px; +} - ::ng-deep.mat-mdc-select-arrow { - color: mat.get-theme-color($light-theme, primary, 30); - } +.download-button { + padding: 26px; + border-radius: variables.$corner-large; + font-weight: 400; + font-size: 22px; + line-height: 28px; + height: 80px; + margin-top: 4px; - ::ng-deep .mat-mdc-text-field-wrapper .mdc-notched-outline > * { - border-color: mat.get-theme-color($light-theme, primary, 95); - } - - ::ng-deep - .mat-mdc-text-field-wrapper.mdc-text-field--focused - .mdc-notched-outline - > * { - border-color: #000000de; + mat-icon { + font-size: 28px; + width: 28px; + height: 28px; } +} - &:has(.download-options-select[aria-expanded='true']) - ::ng-deep - .mat-mdc-text-field-wrapper.mdc-text-field--focused - .mdc-notched-outline - > * { - border: none; - } +.download-button.download-button-opened { + min-width: 56px; + height: 56px; + border-radius: 50%; + padding: 16px; - ::ng-deep - .mat-mdc-text-field-wrapper.mdc-text-field--outlined:hover - .mdc-notched-outline - > * { - border: none; + mat-icon { + font-size: 20px; + width: 20px; + height: 20px; + margin: 0; } } .download-option { - ::ng-deep .mat-mdc-focus-indicator { - display: none; + display: flex; + height: 56px; + box-sizing: border-box; + padding: 16px 24px; + justify-content: flex-end; + align-items: center; + flex-shrink: 0; + gap: 8px; + border-radius: 28px; + background: colors.$primary-container; + color: colors.$on-primary-container; + font-size: 16px; + font-weight: 500; + line-height: 24px; + + mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; } } -.download-option { - min-height: 32px; - color: colors.$grey-800; - &.zip app-download-report-zip { - display: flex; - align-items: center; +button { + ::ng-deep .mat-focus-indicator { + display: none; } } diff --git a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.spec.ts b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.spec.ts index 2b370485f..a9be3de24 100644 --- a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.spec.ts +++ b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.spec.ts @@ -15,17 +15,13 @@ */ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - DownloadOption, - DownloadOptionsComponent, -} from './download-options.component'; +import { DownloadOptionsComponent } from './download-options.component'; import { MOCK_PROGRESS_DATA_CANCELLED, MOCK_PROGRESS_DATA_COMPLIANT, MOCK_PROGRESS_DATA_NON_COMPLIANT, } from '../../../../mocks/testrun.mock'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { MatOptionSelectionChange } from '@angular/material/core'; import { TestRunService } from '../../../../services/test-run.service'; interface GAEvent { @@ -63,43 +59,33 @@ describe('DownloadOptionsComponent', () => { expect(downloadReportZipComponent).toBeDefined(); }); - it('#onSelected should call getReportTitle', () => { + it('#downloadPdf should call getReportTitle', () => { const spyGetReportTitle = spyOn(component, 'getReportTitle'); - const mockEvent = { - source: {}, - isUserInput: true, - } as MatOptionSelectionChange; - - component.onSelected( - mockEvent, - MOCK_PROGRESS_DATA_COMPLIANT, - DownloadOption.PDF - ); + component.downloadPdf(MOCK_PROGRESS_DATA_COMPLIANT); expect(spyGetReportTitle).toHaveBeenCalled(); }); - it('#onSelected should call getZipLink when using for zip report', () => { - const spyGetZipLink = spyOn(component, 'getZipLink'); + it('#getReportTitle should return data for title of link', () => { + const expectedResult = 'delta_03-din-cpu_1.2.2_complete_22_jun_2023_9:20'; - const mockEvent = { - source: {}, - isUserInput: true, - } as MatOptionSelectionChange; + const result = component.getReportTitle(MOCK_PROGRESS_DATA_COMPLIANT); - component.onSelected( - mockEvent, - MOCK_PROGRESS_DATA_COMPLIANT, - DownloadOption.ZIP - ); + expect(result).toEqual(expectedResult); + }); + + it('#openDownloadOptions should change isOpenDownloadOptions', () => { + component.openDownloadOptions(); + expect(component.isOpenDownloadOptions).toBeTrue(); - expect(spyGetZipLink).toHaveBeenCalled(); + component.openDownloadOptions(); + expect(component.isOpenDownloadOptions).toBeFalse(); }); describe('#sendGAEvent', () => { it('should send download_report_pdf when type is pdf', () => { - component.sendGAEvent(MOCK_PROGRESS_DATA_CANCELLED, DownloadOption.PDF); + component.sendGAEvent(MOCK_PROGRESS_DATA_CANCELLED); expect( // @ts-expect-error data layer should be defined @@ -109,8 +95,8 @@ describe('DownloadOptionsComponent', () => { ).toBeTruthy(); }); - it('should send download_report_pdf_compliant when type is pdf and status is compliant', () => { - component.sendGAEvent(MOCK_PROGRESS_DATA_COMPLIANT, DownloadOption.PDF); + it('should send download_report_pdf_compliant when status is compliant', () => { + component.sendGAEvent(MOCK_PROGRESS_DATA_COMPLIANT); expect( // @ts-expect-error data layer should be defined @@ -120,11 +106,8 @@ describe('DownloadOptionsComponent', () => { ).toBeTruthy(); }); - it('should send download_report_pdf_non_compliant when type is pdf and status is not compliant', () => { - component.sendGAEvent( - MOCK_PROGRESS_DATA_NON_COMPLIANT, - DownloadOption.PDF - ); + it('should send download_report_pdf_non_compliant when status is not compliant', () => { + component.sendGAEvent(MOCK_PROGRESS_DATA_NON_COMPLIANT); expect( // @ts-expect-error data layer should be defined @@ -133,41 +116,5 @@ describe('DownloadOptionsComponent', () => { ) ).toBeTruthy(); }); - - it('should send download_report_zip when type is zip', () => { - component.sendGAEvent(MOCK_PROGRESS_DATA_CANCELLED, DownloadOption.ZIP); - - expect( - // @ts-expect-error data layer should be defined - window.dataLayer.some( - (item: GAEvent) => item.event === 'download_report_zip' - ) - ).toBeTruthy(); - }); - - it('should send download_report_zip_compliant when type is pdf and status is compliant', () => { - component.sendGAEvent(MOCK_PROGRESS_DATA_COMPLIANT, DownloadOption.ZIP); - - expect( - // @ts-expect-error data layer should be defined - window.dataLayer.some( - (item: GAEvent) => item.event === 'download_report_zip_compliant' - ) - ).toBeTruthy(); - }); - - it('should send download_report_zip_non_compliant when type is zip and status is not compliant', () => { - component.sendGAEvent( - MOCK_PROGRESS_DATA_NON_COMPLIANT, - DownloadOption.ZIP - ); - - expect( - // @ts-expect-error data layer should be defined - window.dataLayer.some( - (item: GAEvent) => item.event === 'download_report_zip_non_compliant' - ) - ).toBeTruthy(); - }); }); }); diff --git a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.ts b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.ts index 21e28f145..87e13e098 100644 --- a/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.ts +++ b/modules/ui/src/app/pages/testrun/components/download-options/download-options.component.ts @@ -16,23 +16,18 @@ import { ChangeDetectionStrategy, Component, - ElementRef, Input, - viewChild, inject, } from '@angular/core'; -import { FormsModule } from '@angular/forms'; -import { MatFormFieldModule } from '@angular/material/form-field'; -import { MatSelectModule } from '@angular/material/select'; import { CommonModule, DatePipe } from '@angular/common'; import { MatIconModule } from '@angular/material/icon'; import { ResultOfTestrun, TestrunStatus, } from '../../../../model/testrun-status'; -import { MatOptionSelectionChange } from '@angular/material/core'; import { DownloadReportZipComponent } from '../../../../components/download-report-zip/download-report-zip.component'; import { Profile } from '../../../../model/profile'; +import { MatButtonModule } from '@angular/material/button'; export enum DownloadOption { PDF = 'PDF Report', @@ -44,10 +39,8 @@ export enum DownloadOption { styleUrl: './download-options.component.scss', imports: [ CommonModule, - FormsModule, + MatButtonModule, MatIconModule, - MatFormFieldModule, - MatSelectModule, DownloadReportZipComponent, ], providers: [DatePipe], @@ -55,49 +48,27 @@ export enum DownloadOption { }) export class DownloadOptionsComponent { private datePipe = inject(DatePipe); - - readonly downloadReportZip = - viewChild.required('downloadReportZip'); + isOpenDownloadOptions: boolean = false; @Input() profiles: Profile[] = []; @Input() data!: TestrunStatus; DownloadOption = DownloadOption; - onSelected( - event: MatOptionSelectionChange, - data: TestrunStatus, - type: string - ) { - if (event.isUserInput) { - this.createLink(data, type); - this.sendGAEvent(data, type); - } - } - - onZipSelected(event: MatOptionSelectionChange) { - if (event.isUserInput) { - const uploadCertificatesButton = document.querySelector( - '#downloadReportZip' - ) as HTMLElement; - uploadCertificatesButton.dispatchEvent(new MouseEvent('click')); - } + downloadPdf(data: TestrunStatus) { + this.createLink(data); + this.sendGAEvent(data); } - createLink(data: TestrunStatus, type: string) { + createLink(data: TestrunStatus) { if (!data.report) { return; } const link = document.createElement('a'); - link.href = - type === DownloadOption.PDF ? data.report : this.getZipLink(data); + link.href = data.report; link.target = '_blank'; link.download = this.getReportTitle(data); link.dispatchEvent(new MouseEvent('click')); } - getZipLink(data: TestrunStatus): string { - return data.export || data.report.replace('report', 'export'); - } - getReportTitle(data: TestrunStatus) { if (!data.device) { return ''; @@ -113,8 +84,8 @@ export class DownloadOptionsComponent { return date ? this.datePipe.transform(date, 'd MMM y H:mm') : ''; } - sendGAEvent(data: TestrunStatus, type: string) { - let event = `download_report_${type === DownloadOption.PDF ? 'pdf' : 'zip'}`; + sendGAEvent(data: TestrunStatus) { + let event = 'download_report_pdf'; if (data.result === ResultOfTestrun.Compliant) { event += '_compliant'; } else if (data.result === ResultOfTestrun.NonCompliant) { @@ -125,4 +96,8 @@ export class DownloadOptionsComponent { event: event, }); } + + openDownloadOptions(): void { + this.isOpenDownloadOptions = !this.isOpenDownloadOptions; + } } diff --git a/modules/ui/src/app/pages/testrun/testrun.component.html b/modules/ui/src/app/pages/testrun/testrun.component.html index f38eebbb1..fd00314ff 100644 --- a/modules/ui/src/app/pages/testrun/testrun.component.html +++ b/modules/ui/src/app/pages/testrun/testrun.component.html @@ -72,28 +72,10 @@ Stop - + [data]="data" + [profiles]="vm.profiles"> diff --git a/modules/ui/src/app/pages/testrun/testrun.component.scss b/modules/ui/src/app/pages/testrun/testrun.component.scss index 1c58ca01c..a5d4713b1 100644 --- a/modules/ui/src/app/pages/testrun/testrun.component.scss +++ b/modules/ui/src/app/pages/testrun/testrun.component.scss @@ -145,11 +145,11 @@ } } -.stop-button, -.download-button { +.stop-button { position: fixed; right: 40px; bottom: 32px; + background-color: colors.$error; padding: 26px; border-radius: variables.$corner-large; font-weight: 400; @@ -164,24 +164,6 @@ } } -.stop-button { - background-color: colors.$error; -} - -.download-button.download-button-opened { - min-width: 56px; - height: 56px; - border-radius: 50%; - padding: 16px; - - mat-icon { - font-size: 20px; - width: 20px; - height: 20px; - margin: 0; - } -} - ::ng-deep .stop-testrun app-simple-dialog { width: 329px; } diff --git a/modules/ui/src/app/pages/testrun/testrun.component.spec.ts b/modules/ui/src/app/pages/testrun/testrun.component.spec.ts index 29b523323..61d531747 100644 --- a/modules/ui/src/app/pages/testrun/testrun.component.spec.ts +++ b/modules/ui/src/app/pages/testrun/testrun.component.spec.ts @@ -498,10 +498,12 @@ describe('TestrunComponent', () => { expect(startBtn).toBeNull(); }); - it('should have "Download" button', () => { - const downloadButton = compiled.querySelector('.download-button'); + it('should have "Download" options', () => { + const downloadOptionsComp = compiled.querySelector( + 'app-download-options' + ); - expect(downloadButton).not.toBeNull(); + expect(downloadOptionsComp).not.toBeNull(); }); }); diff --git a/modules/ui/src/app/pages/testrun/testrun.component.ts b/modules/ui/src/app/pages/testrun/testrun.component.ts index db5e79a9e..02dc95505 100644 --- a/modules/ui/src/app/pages/testrun/testrun.component.ts +++ b/modules/ui/src/app/pages/testrun/testrun.component.ts @@ -48,6 +48,7 @@ import { SpinnerComponent } from '../../components/spinner/spinner.component'; import { MatTooltipModule } from '@angular/material/tooltip'; import { TestrunTableComponent } from './components/testrun-table/testrun-table.component'; import { TestrunStatusCardComponent } from './components/testrun-status-card/testrun-status-card.component'; +import { DownloadOptionsComponent } from './components/download-options/download-options.component'; @Component({ selector: 'app-progress', @@ -68,6 +69,7 @@ import { TestrunStatusCardComponent } from './components/testrun-status-card/tes MatTooltipModule, TestrunTableComponent, TestrunStatusCardComponent, + DownloadOptionsComponent, ], providers: [ LoaderService, @@ -76,7 +78,6 @@ import { TestrunStatusCardComponent } from './components/testrun-status-card/tes ], }) export class TestrunComponent implements OnInit, OnDestroy { - isOpenDownloadOptions: boolean = false; private readonly testRunService = inject(TestRunService); dialog = inject(MatDialog); private readonly focusManagerService = inject(FocusManagerService); @@ -194,8 +195,4 @@ export class TestrunComponent implements OnInit, OnDestroy { resultIsEmpty(tests: TestsResponse | undefined) { return this.testrunStore.resultIsEmpty(tests); } - - openDownloadOptions(): void { - this.isOpenDownloadOptions = !this.isOpenDownloadOptions; - } }