From b18816f1771d3778db3885c9599c36f8495bde09 Mon Sep 17 00:00:00 2001 From: Dmytro Borzenko <51016717+dmitriy-borzenko@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:10:04 +0300 Subject: [PATCH] Added navigation over stages of SetPollingSource editing wizard (#110) * Add navigator. * Remove material warning. * Add descriptions for steps. * Added validation when the user moves to the next step. * Increase unit tests coverage --- CHANGELOG.md | 4 + .../add-polling-source.component.html | 214 +++++++++++------- .../add-polling-source.component.sass | 10 + .../add-polling-source.component.spec.ts | 17 ++ .../add-polling-source.component.ts | 24 +- .../steps/base-step/base-step.component.html | 1 + .../steps/base-step/base-step.component.ts | 1 + .../prepare-step/prepare-step.component.html | 11 +- .../preprocess-step.component.html | 1 + .../preprocess-step.component.ts | 2 + .../stepper-navigation.component.html | 6 +- .../stepper-navigation.component.spec.ts | 1 + .../stepper-navigation.component.ts | 1 + .../metadata-component.spec.ts | 27 +++ src/app/dataset-view/dataset.module.ts | 2 + src/styles.sass | 14 ++ 16 files changed, 246 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5ad3bf04..d0fb597b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The ability to edit SetPollingSource event - Editing SetWaterMark event - Editing SetTransform event +- Support defining initial polling source information for the root datasets interactively (SetPollingSource event): + - Prepare step(optional) + - Preprocess step(optional) +- Create a navigator to display the state of the interactive input for the SetPollingSource event ## [0.6.0] - 2023-02-27 diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.html b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.html index 131fabe5e..b74eb861f 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.html +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.html @@ -2,93 +2,139 @@
- - - - - - - - - - - - - - - - - - - + - + + +
+ + - - + Prepare +
+ + +
+
+ + +
+ Read
+
+ + +
+
+ + Preprocess +
+ + +
+
+ + Merge +
+ + + +
+
+
diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.sass b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.sass index 2c2ec5714..97cedfe71 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.sass +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.sass @@ -1,4 +1,7 @@ +.container-step + margin-top: 40px + .layout max-width: 1200px width: 100% @@ -6,3 +9,10 @@ margin-left: auto padding: 0 30px 100px position: relative + +.stepper-header-overlay + position: absolute + top: 0 + left: 0 + width: 100% + height: 100% diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts index 3fec8e175..ddf604c07 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.spec.ts @@ -22,6 +22,7 @@ import { PollingSourceFormComponentsModule } from "../form-components/polling-so import { of } from "rxjs"; import { mockDatasetHistoryResponse } from "src/app/search/mock.data"; import { + DatasetKind, DatasetPageInfoFragment, MetadataBlockFragment, } from "src/app/api/kamu.graphql.interface"; @@ -66,6 +67,7 @@ describe("AddPollingSourceComponent", () => { createDatasetService = TestBed.inject(AppDatasetCreateService); modalRef = modalService.open(FinalYamlModalComponent); component = fixture.componentInstance; + component.showPreprocessStep = false; component.currentStep = SetPollingSourceSection.FETCH; component.history = { history: mockDatasetHistoryResponse.datasets.byOwnerAndName @@ -76,6 +78,7 @@ describe("AddPollingSourceComponent", () => { component.pollingSourceForm = new FormGroup({ fetch: new FormGroup({ kind: new FormControl("url"), + url: new FormControl(""), order: new FormControl("NONE"), eventTime: new FormGroup({ kind: new FormControl("fromMetadata"), @@ -149,4 +152,18 @@ describe("AddPollingSourceComponent", () => { createDatasetService.errorCommitEventChanges(errorMessage); expect(component.errorMessage).toBe(errorMessage); }); + + it("should check init dataset kind", () => { + expect(component.datasetKind).toBeUndefined(); + editService.changeKindChanges(DatasetKind.Root); + editService.onKindChanges.subscribe(() => { + expect(component.datasetKind).toEqual(DatasetKind.Root); + }); + }); + + it("should check change showPreprocessStep property", () => { + expect(component.showPreprocessStep).toEqual(false); + component.onShowPreprcessStep(true); + expect(component.showPreprocessStep).toEqual(true); + }); }); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts index 6993d0514..ccab2b920 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/add-polling-source.component.ts @@ -36,12 +36,19 @@ import { DatasetHistoryUpdate } from "src/app/dataset-view/dataset.subscriptions import { EditPollingSourceService } from "./edit-polling-source.service"; import { MaybeNull } from "src/app/common/app.types"; import { SupportedEvents } from "src/app/dataset-block/metadata-block/components/event-details/supported.events"; +import { STEPPER_GLOBAL_OPTIONS } from "@angular/cdk/stepper"; @Component({ selector: "app-add-polling-source", templateUrl: "./add-polling-source.component.html", styleUrls: ["./add-polling-source.component.sass"], changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: STEPPER_GLOBAL_OPTIONS, + useValue: { showError: true }, + }, + ], }) export class AddPollingSourceComponent extends BaseComponent implements OnInit { public currentStep: SetPollingSourceSection = SetPollingSourceSection.FETCH; @@ -171,8 +178,9 @@ export class AddPollingSourceComponent extends BaseComponent implements OnInit { FinalYamlModalComponent, { size: "lg" }, ); + const instance = modalRef.componentInstance as FinalYamlModalComponent; this.processFormService.transformForm(this.pollingSourceForm); - (modalRef.componentInstance as FinalYamlModalComponent).yamlTemplate = + instance.yamlTemplate = this.yamlEventService.buildYamlSetPollingSourceEvent( this.pollingSourceForm.value as Omit< SetPollingSource, @@ -180,8 +188,7 @@ export class AddPollingSourceComponent extends BaseComponent implements OnInit { >, this.showPreprocessStep ? this.preprocessStepValue : null, ); - (modalRef.componentInstance as FinalYamlModalComponent).datasetInfo = - this.getDatasetInfoFromUrl(); + instance.datasetInfo = this.getDatasetInfoFromUrl(); } public onShowPreprcessStep(showPreprocessStep: boolean): void { @@ -195,4 +202,15 @@ export class AddPollingSourceComponent extends BaseComponent implements OnInit { }), ); } + + public onShowErrors(): void { + const elems = + document.querySelectorAll("input.ng-invalid"); + elems.forEach((element: HTMLInputElement) => { + setTimeout(() => { + element.focus(); + element.blur(); + }); + }); + } } diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/base-step/base-step.component.html b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/base-step/base-step.component.html index aa74d2c61..2d5967d34 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/base-step/base-step.component.html +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/base-step/base-step.component.html @@ -2,6 +2,7 @@

{{ title }}

+

{{ description }}

= null; private editFormValue: EditFormType; diff --git a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/prepare-step/prepare-step.component.html b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/prepare-step/prepare-step.component.html index 5619675f0..409f8440a 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/prepare-step/prepare-step.component.html +++ b/src/app/dataset-view/additional-components/metadata-component/components/add-polling-source/steps/prepare-step/prepare-step.component.html @@ -24,9 +24,16 @@

Prepare

>

Pipe

- +
- + +
Preprocess +

Pre-processing query that shapes the data.

@@ -11,6 +13,8 @@ *ngIf="nextStep" type="button" class="btn btn-primary" + mat-button + matStepperNext [disabled]="!validStep" data-test-id="next-button" (click)="changeStep(nextStep)" @@ -23,7 +27,7 @@ (click)="saveEvent()" class="button-save" data-test-id="save-button" - [disabled]="!validStep" + [disabled]="!validStep || !validAllSteps" > Save diff --git a/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.spec.ts index 34e1acb3a..2de8c70b1 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.spec.ts @@ -45,6 +45,7 @@ describe("StepperNavigationComponent", () => { component.prevStep = SetPollingSourceSection.READ; component.validStep = true; component.nextStep = null; + component.validAllSteps = true; fixture.detectChanges(); emitClickOnElementByDataTestId(fixture, "save-button"); expect(changeStepEmitterSpy).toHaveBeenCalledWith(); diff --git a/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.ts b/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.ts index 5957d3a21..6d43f4b99 100644 --- a/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.ts +++ b/src/app/dataset-view/additional-components/metadata-component/components/stepper-navigation/stepper-navigation.component.ts @@ -18,6 +18,7 @@ export class StepperNavigationComponent { @Input() public nextStep: MaybeNull = null; @Input() public prevStep: MaybeNull = null; @Input() public validStep?: boolean; + @Input() public validAllSteps? = false; @Output() public changeStepEmitter = new EventEmitter(); @Output() public saveEventEmitter = new EventEmitter(); diff --git a/src/app/dataset-view/additional-components/metadata-component/metadata-component.spec.ts b/src/app/dataset-view/additional-components/metadata-component/metadata-component.spec.ts index 713e724a7..0f4fce33c 100644 --- a/src/app/dataset-view/additional-components/metadata-component/metadata-component.spec.ts +++ b/src/app/dataset-view/additional-components/metadata-component/metadata-component.spec.ts @@ -12,11 +12,13 @@ import { MatIconModule } from "@angular/material/icon"; import { MetadataBlockModule } from "src/app/dataset-block/metadata-block/metadata-block.module"; import { HIGHLIGHT_OPTIONS } from "ngx-highlightjs"; import { SharedTestModule } from "src/app/common/shared-test.module"; +import { NavigationService } from "src/app/services/navigation.service"; describe("MetadataComponent", () => { let component: MetadataComponent; let fixture: ComponentFixture; let appDatasetSubsService: AppDatasetSubscriptionsService; + let navigationService: NavigationService; beforeEach(async () => { await TestBed.configureTestingModule({ @@ -53,6 +55,7 @@ describe("MetadataComponent", () => { fixture = TestBed.createComponent(MetadataComponent); appDatasetSubsService = TestBed.inject(AppDatasetSubscriptionsService); + navigationService = TestBed.inject(NavigationService); component = fixture.componentInstance; component.datasetBasics = mockDatasetBasicsFragment; fixture.detectChanges(); @@ -95,4 +98,28 @@ describe("MetadataComponent", () => { component.onPageChange(pageNumber); expect(pageChangeEmitSpy).toHaveBeenCalledWith(pageNumber); }); + + it("should check navigate to edit SetPollingSource event", () => { + const navigateToAddPollingSourceSpy = spyOn( + navigationService, + "navigateToAddPollingSource", + ); + component.navigateToEditPollingSource(); + expect(navigateToAddPollingSourceSpy).toHaveBeenCalledWith({ + accountName: mockDatasetBasicsFragment.owner.name, + datasetName: mockDatasetBasicsFragment.name as string, + }); + }); + + it("should check navigate to edit SetTransform event", () => { + const navigateToSetTransformSpy = spyOn( + navigationService, + "navigateToSetTransform", + ); + component.navigateToEditSetTransform(); + expect(navigateToSetTransformSpy).toHaveBeenCalledWith({ + accountName: mockDatasetBasicsFragment.owner.name, + datasetName: mockDatasetBasicsFragment.name as string, + }); + }); }); diff --git a/src/app/dataset-view/dataset.module.ts b/src/app/dataset-view/dataset.module.ts index 289300246..d8c2dabe8 100644 --- a/src/app/dataset-view/dataset.module.ts +++ b/src/app/dataset-view/dataset.module.ts @@ -59,6 +59,7 @@ import { EngineSectionComponent } from "./additional-components/metadata-compone import { QueriesSectionComponent } from "./additional-components/metadata-component/components/set-transform/components/queries-section/queries-section.component"; import { PageNotFoundComponent } from "../components/page-not-found/page-not-found.component"; import { AddPollingSourceComponent } from "./additional-components/metadata-component/components/add-polling-source/add-polling-source.component"; +import { MatStepperModule } from "@angular/material/stepper"; @NgModule({ imports: [ CommonModule, @@ -99,6 +100,7 @@ import { AddPollingSourceComponent } from "./additional-components/metadata-comp OwlNativeDateTimeModule, OwlMomentDateTimeModule, MatTreeModule, + MatStepperModule, ], exports: [ DatasetViewHeaderComponent, diff --git a/src/styles.sass b/src/styles.sass index 4cf55c29b..4863e0e18 100644 --- a/src/styles.sass +++ b/src/styles.sass @@ -1,10 +1,21 @@ + @import '@angular/material/theming' +@include mat-core() @import "bootstrap-icons/font/bootstrap-icons.css" /* Importing Bootstrap SCSS file. */ @import 'bootstrap/scss/bootstrap' @import "assets/styles/var" @import "@danielmoncada/angular-datetime-picker/assets/style/picker.min.css" +// Use the desired palette +$palette: mat-palette($mat-indigo) +// Create the theme +$theme: mat-light-theme($palette, $palette) + +// Or wrap inside another selector to scope the styles to only one specific component +app-add-polling-source + @include mat-stepper-theme($theme) + body font-size: 14px overflow-x: hidden @@ -1063,3 +1074,6 @@ pre cursor: pointer &:enabled color: blue + +input.ng-invalid.ng-touched, input.ng-invalid.ng-dirty + border-color: #dc3545