Skip to content

Commit

Permalink
Fixed validation
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Mar 17, 2021
1 parent 1522853 commit 98be185
Show file tree
Hide file tree
Showing 21 changed files with 300 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<a *ngFor="let route of routes$ | async"
href=""
class="dropdown-item"
[routerLink]="['../', 'edit', route.path]"
[routerLink]="['../', path, route.path]"
[ngClass]="{'active': (currentPage$ | async) === route.path}"
[attr.aria-label]="route.label"
role="button">
Expand All @@ -32,7 +32,7 @@
href=""
class="nav-link"
[ngClass]="{'active': (currentPage$ | async) === route.path}"
[routerLink]="['../', 'edit', route.path]"
[routerLink]="['../', path, route.path]"
role="button"
[attr.aria-label]="route.label">
<translate-i18n [key]="route.label"></translate-i18n>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export enum NAV_FORMATS {
export class EditorNavComponent {
@Input() format: string;
@Input() status: string[] = [];
@Input() path: string = 'edit';

@Output() onPageSelect: EventEmitter<string> = new EventEmitter();

Expand Down
10 changes: 8 additions & 2 deletions ui/src/app/metadata/filter/action/collection.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,19 @@ export class UpdateFilterConflict implements Action {
export class AddFilterRequest implements Action {
readonly type = FilterCollectionActionTypes.ADD_FILTER_REQUEST;

constructor(public payload: MetadataFilter) { }
constructor(public payload: {
filter: MetadataFilter,
providerId: string
}) { }
}

export class AddFilterSuccess implements Action {
readonly type = FilterCollectionActionTypes.ADD_FILTER_SUCCESS;

constructor(public payload: MetadataFilter) { }
constructor(public payload: {
filter: MetadataFilter,
providerId: string
}) { }
}

export class AddFilterFail implements Action {
Expand Down
8 changes: 0 additions & 8 deletions ui/src/app/metadata/filter/action/editor.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Action } from '@ngrx/store';

export enum EditorActionTypes {
UPDATE_STATUS = '[Filter Editor] Update Status',
SELECT_PROVIDER_TYPE = '[Filter Editor] Select Filter Type',
CLEAR = '[Filter Editor] Clear'
}

Expand All @@ -12,17 +11,10 @@ export class UpdateStatus implements Action {
constructor(public payload: { [key: string]: string }) { }
}

export class SelectFilterType implements Action {
readonly type = EditorActionTypes.SELECT_PROVIDER_TYPE;

constructor(public payload: string) { }
}

export class ClearEditor implements Action {
readonly type = EditorActionTypes.CLEAR;
}

export type EditorActionUnion =
| UpdateStatus
| SelectFilterType
| ClearEditor;
2 changes: 1 addition & 1 deletion ui/src/app/metadata/filter/action/filter.action.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FilterActionTypes, CancelCreateFilter, SelectId } from './filter.action

describe('Filter Actions', () => {
it('should provide actions', () => {
expect(new CancelCreateFilter().type).toBe(FilterActionTypes.CANCEL_CREATE_FILTER);
expect(new CancelCreateFilter('id').type).toBe(FilterActionTypes.CANCEL_CREATE_FILTER);
expect(new SelectId('foo').type).toBe(FilterActionTypes.SELECT_ID);
});
});
42 changes: 34 additions & 8 deletions ui/src/app/metadata/filter/container/edit-filter-step.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnDestroy } from '@angular/core';
import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core';
import { Store } from '@ngrx/store';
import { Subject, Observable, Subscription } from 'rxjs';

Expand All @@ -8,9 +8,10 @@ import { MetadataFilter } from '../../domain/model';
import { SchemaService } from '../../../schema-form/service/schema.service';
import { UpdateFilterChanges } from '../action/filter.action';
import { PreviewEntity } from '../../domain/action/entity.action';
import { shareReplay, map, withLatestFrom, filter, switchMap, takeUntil } from 'rxjs/operators';
import { map, withLatestFrom, filter, takeUntil, distinctUntilChanged, skip } from 'rxjs/operators';
import * as fromWizard from '../../../wizard/reducer';
import { LockEditor, UnlockEditor } from '../../../wizard/action/wizard.action';
import { UpdateStatus } from '../action/editor.action';

@Component({
selector: 'edit-filter-step-page',
Expand Down Expand Up @@ -44,12 +45,13 @@ export class EditFilterStepComponent implements OnDestroy {
actions: any;

defSub: Subscription;
currentPage: string;

constructor(
private store: Store<fromFilter.State>,
private schemaService: SchemaService
private ref: ChangeDetectorRef
) {
this.definition$ = this.store.select(fromWizard.getWizardDefinition).pipe(filter(d => !!d))
this.definition$ = this.store.select(fromWizard.getWizardDefinition).pipe(filter(d => !!d));

this.defSub = this.definition$.subscribe(d => this.definition = d);

Expand All @@ -70,13 +72,29 @@ export class EditFilterStepComponent implements OnDestroy {
this.model$ = this.store.select(fromFilter.getSelectedFilter);
this.type$ = this.model$.pipe(map(f => f && f.hasOwnProperty('@type') ? f['@type'] : ''));

this.valueChangeEmitted$.subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value)));
this.statusChangeEmitted$.subscribe(valid => {
this.isValid = valid.value ? valid.value.length === 0 : true;
});
this.valueChangeEmitted$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value)));

this.statusChangeEmitted$
.pipe(
skip(1),
takeUntil(this.ngUnsubscribe),
withLatestFrom(this.model$),
distinctUntilChanged()
)
.subscribe(([errors, model]) => {
this.updateStatus(errors);
});

this.status$ = this.store.select(fromFilter.getInvalidEditorForms);

this.status$.pipe(takeUntil(this.ngUnsubscribe)).subscribe(() => {
this.ref.detach();
setTimeout(() => {
this.ref.detectChanges();
this.ref.reattach();
}, 250);
})

this.validators$ = this.store.select(fromFilter.getFilterNames).pipe(
takeUntil(this.ngUnsubscribe),
withLatestFrom(
Expand All @@ -90,13 +108,21 @@ export class EditFilterStepComponent implements OnDestroy {

this.store
.select(fromFilter.getFilter)
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(filter => this.filter = filter);

this.actions = {
preview: (property: any, parameters: any) => {
this.preview(parameters.filterId);
}
};

this.store.select(fromWizard.getWizardIndex).pipe(takeUntil(this.ngUnsubscribe)).subscribe(i => this.currentPage = i);
}

updateStatus(errors: any): void {
const status = { [this.currentPage]: !(errors.value) ? 'VALID' : 'INVALID' };
this.store.dispatch(new UpdateStatus(status));
}

ngOnDestroy(): void {
Expand Down
26 changes: 12 additions & 14 deletions ui/src/app/metadata/filter/container/edit-filter.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,18 @@
</div>
</div>
<div class="py-2">
<ng-container>
<button (click)="this.save()" type="submit" class="btn btn-primary" [disabled]="(!isInvalid$ | async) || (isSaving$ | async)">
<i class="fa fa-fw fa-lg" [ngClass]="{
'fa-save': !(isSaving$ | async),
'fa-spinner': (isSaving$ | async),
'fa-pulse': (isSaving$ | async)
}"></i>
<translate-i18n key="action.save">Save</translate-i18n>
</button>
&nbsp;
<button (click)="this.cancel()" type="reset" class="btn btn-secondary" [disabled]="isSaving$ | async">
<translate-i18n key="action.cancel">Cancel</translate-i18n>
</button>
</ng-container>
<button (click)="this.save()" type="submit" class="btn btn-primary" [disabled]="cantSave$ | async">
<i class="fa fa-fw fa-lg" [ngClass]="{
'fa-save': !(isSaving$ | async),
'fa-spinner': (isSaving$ | async),
'fa-pulse': (isSaving$ | async)
}"></i>
<translate-i18n key="action.save">Save</translate-i18n>
</button>
&nbsp;
<button (click)="this.cancel($event)" type="button" class="btn btn-secondary" [disabled]="isSaving$ | async">
<translate-i18n key="action.cancel">Cancel</translate-i18n>
</button>
</div>
</div>
<hr />
Expand Down
15 changes: 9 additions & 6 deletions ui/src/app/metadata/filter/container/edit-filter.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, OnDestroy } from '@angular/core';
import { Store } from '@ngrx/store';
import { Subject, Observable, Subscription } from 'rxjs';
import { Subject, Observable, Subscription, combineLatest } from 'rxjs';

import * as fromFilter from '../reducer';
import { FormDefinition } from '../../../wizard/model';
Expand All @@ -9,7 +9,7 @@ import { UpdateFilterRequest } from '../action/collection.action';
import { CancelCreateFilter } from '../action/filter.action';
import { PreviewEntity } from '../../domain/action/entity.action';
import { NAV_FORMATS } from '../../domain/component/editor-nav.component';
import { map, filter } from 'rxjs/operators';
import { map, filter, takeUntil, withLatestFrom, skip } from 'rxjs/operators';
import * as fromWizard from '../../../wizard/reducer';
import { ActivatedRoute } from '@angular/router';
import { LoadSchemaRequest, SetIndex } from '../../../wizard/action/wizard.action';
Expand All @@ -31,6 +31,7 @@ export class EditFilterComponent implements OnDestroy {
filter: MetadataFilter;
isValid$: Observable<boolean>;
isInvalid$: Observable<boolean>;
cantSave$: Observable<boolean>;
type$: Observable<string>;

status$: Observable<any>;
Expand All @@ -40,6 +41,7 @@ export class EditFilterComponent implements OnDestroy {
defSub: Subscription;

formats = NAV_FORMATS;
currentPage

constructor(
private store: Store<fromFilter.State>,
Expand All @@ -52,7 +54,7 @@ export class EditFilterComponent implements OnDestroy {

this.store
.select(fromWizard.getCurrentWizardSchema)
.pipe(filter(s => !!s))
.pipe(filter(s => !!s), takeUntil(this.ngUnsubscribe))
.subscribe(s => {
if (s) {
this.store.dispatch(new LoadSchemaRequest(s));
Expand All @@ -61,16 +63,16 @@ export class EditFilterComponent implements OnDestroy {

let startIndex$ = this.route.firstChild.params.pipe(map(p => p.form || 'filters'));
startIndex$.subscribe(index => this.store.dispatch(new SetIndex(index)));


this.isSaving$ = this.store.select(fromFilter.getCollectionSaving);
this.model$ = this.store.select(fromFilter.getSelectedFilter);
this.type$ = this.model$.pipe(map(f => f && f.hasOwnProperty('@type') ? f['@type'] : ''));

this.status$ = this.store.select(fromFilter.getInvalidEditorForms);

this.isValid$ = this.store.select(fromFilter.getEditorIsValid);
this.isValid$ = this.store.select(fromFilter.getFilterIsValid);
this.isInvalid$ = this.isValid$.pipe(map(v => !v));
this.cantSave$ = this.store.select(fromFilter.cantSaveFilter).pipe(skip(1));

this.store
.select(fromFilter.getFilter)
Expand All @@ -96,7 +98,8 @@ export class EditFilterComponent implements OnDestroy {
}));
}

cancel(): void {
cancel(event: MouseEvent): void {
event.preventDefault();
this.store.dispatch(new CancelCreateFilter(this.route.snapshot.params.providerId));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<ng-container *ngIf="(definition$ | async) && (step$ | async)">
<div class="alert alert-danger d-flex justify-content-between font-weight-bold mb-3" *ngIf="(step$ | async).locked">
<span class="d-flex justify-content-between">
<toggle-switch id="toggle" [formControl]="lock"></toggle-switch>
<span class="p-1">{{ lock.value ? 'Locked' : 'Unlocked' }}</span>
</span>
<span class="p-1">For Advanced Knowledge Only</span>
</div>
<sf-form
[schema]="schema$ | async"
[model]="model"
[validators]="validators$ | async"
(onChange)="valueChangeSubject.next($event)"
(onErrorChange)="statusChangeSubject.next($event)"></sf-form>
</ng-container>
104 changes: 104 additions & 0 deletions ui/src/app/metadata/filter/container/new-filter-step.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { FormBuilder } from '@angular/forms';
import { Subject, Observable } from 'rxjs';

import { takeUntil, shareReplay, withLatestFrom, map, switchMap, filter, distinctUntilChanged } from 'rxjs/operators';


import * as fromFilter from '../reducer';
import { FormDefinition, WizardStep } from '../../../wizard/model';
import { MetadataFilter } from '../../domain/model';
import { SchemaService } from '../../../schema-form/service/schema.service';
import { UpdateFilterChanges } from '../action/filter.action';
import { ActivatedRoute } from '@angular/router';
import * as fromWizard from '../../../wizard/reducer';
import { SetIndex } from '../../../wizard/action/wizard.action';
import { UpdateStatus } from '../action/editor.action';

@Component({
selector: 'new-filter-step-page',
templateUrl: './new-filter-step.component.html'
})
export class NewFilterStepComponent implements OnDestroy, OnInit {

private ngUnsubscribe: Subject<void> = new Subject<void>();

valueChangeSubject = new Subject<Partial<any>>();
private valueChangeEmitted$ = this.valueChangeSubject.asObservable();

statusChangeSubject = new Subject<{ value: any[] }>();
private statusChangeEmitted$ = this.statusChangeSubject.asObservable();

definition$: Observable<FormDefinition<MetadataFilter>>;
schema$: Observable<any>;

changes$: Observable<MetadataFilter>;
isSaving$: Observable<boolean>;
filter: MetadataFilter;

validators$: Observable<{ [key: string]: any }>;

options$: Observable<FormDefinition<MetadataFilter>[]>;

step$: Observable<WizardStep>;

currentPage: string;

constructor(
private store: Store<fromFilter.State>,
private schemaService: SchemaService,
private fb: FormBuilder,
private route: ActivatedRoute
) {
this.isSaving$ = this.store.select(fromFilter.getCollectionSaving);
this.changes$ = this.store.select(fromFilter.getFilter);
this.step$ = this.store.select(fromWizard.getCurrent);
this.definition$ = this.store.select(fromWizard.getWizardDefinition).pipe(filter(d => !!d));
this.schema$ = this.store.select(fromWizard.getSchema);

this.validators$ = this.definition$.pipe(
takeUntil(this.ngUnsubscribe),
withLatestFrom(this.store.select(fromFilter.getFilterNames)),
map(([definition, names]) => definition.getValidators(names))
);

let startIndex$ = this.route.params.pipe(map(p => p.form || 'filters'));
startIndex$.subscribe(index => this.store.dispatch(new SetIndex(index)));
}

ngOnInit(): void {
this.valueChangeEmitted$
.pipe(takeUntil(this.ngUnsubscribe))
.subscribe(changes => this.store.dispatch(new UpdateFilterChanges(changes.value)));
this.statusChangeEmitted$
.pipe(
takeUntil(this.ngUnsubscribe),
distinctUntilChanged()
)
.subscribe(errors => {
this.updateStatus(errors);
});

this.store
.select(fromFilter.getFilter)
.pipe(
takeUntil(this.ngUnsubscribe),
withLatestFrom(this.definition$),
map(([filter, definition]) => definition.parser(filter))
)
.subscribe(filter => this.filter = filter);

this.store.select(fromWizard.getWizardIndex).subscribe(i => this.currentPage = i);
}

updateStatus(errors: any): void {
const status = { [this.currentPage]: !(errors.value) ? 'VALID' : 'INVALID' };
this.store.dispatch(new UpdateStatus(status));
}

ngOnDestroy(): void {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
Loading

0 comments on commit 98be185

Please sign in to comment.