Skip to content

Commit

Permalink
SHIBUI-914 Implemented dynamic wizard for sources
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed Oct 4, 2018
1 parent 5d8dbfa commit 6ab5c0d
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 53 deletions.
10 changes: 10 additions & 0 deletions ui/src/app/metadata/domain/model/wizards/metadata-source-wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ export class MetadataSourceWizard implements Wizard<MetadataResolver> {
label = 'Metadata Source';
type = '@MetadataProvider';
steps: WizardStep[] = [
{
index: 1,
id: 'common',
label: 'label.resolver-common-attributes',
schema: 'assets/schema/source/metadata-source.json',
fields: [
'serviceProviderName',
'entityId'
]
},
{
index: 2,
id: 'org-info',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export class ProviderWizardComponent implements OnDestroy {
constructor(
private store: Store<fromProvider.ProviderState>
) {



this.store
.select(fromWizard.getCurrentWizardSchema)
.subscribe(s => {
Expand Down
2 changes: 0 additions & 2 deletions ui/src/app/metadata/provider/provider.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ import { UnsavedProviderComponent } from './component/unsaved-provider.dialog';
import { ContentionModule } from '../../contention/contention.module';
import { DeleteFilterComponent } from './component/delete-filter.component';
import { I18nModule } from '../../i18n/i18n.module';
import { WidgetRegistry } from 'ngx-schema-form';
import { CustomWidgetRegistry } from '../../schema-form/registry';

@NgModule({
declarations: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<ng-container *ngIf="definition$ | async">
<sf-form
[schema]="schema$ | async"
[model]="model$ | async"
[validators]="validators$ | async"
(onChange)="valueChangeSubject.next($event)"
(onErrorChange)="statusChangeSubject.next($event)"></sf-form>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Component, OnDestroy } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { withLatestFrom, map, distinctUntilChanged, skipWhile } from 'rxjs/operators';
import { Store } from '@ngrx/store';

import * as fromResolver from '../reducer';
import * as fromWizard from '../../../wizard/reducer';

import { SetDefinition } from '../../../wizard/action/wizard.action';
import { UpdateStatus, UpdateChanges } from '../action/entity.action';
import { Wizard } from '../../../wizard/model';
import { MetadataResolver } from '../../domain/model';
import { pick } from '../../../shared/util';

@Component({
selector: 'resolver-wizard-step',
templateUrl: './resolver-wizard-step.component.html',
styleUrls: []
})

export class ResolverWizardStepComponent implements OnDestroy {
valueChangeSubject = new Subject<Partial<any>>();
private valueChangeEmitted$ = this.valueChangeSubject.asObservable();

statusChangeSubject = new Subject<Partial<any>>();
private statusChangeEmitted$ = this.statusChangeSubject.asObservable();

schema$: Observable<any>;
schema: any;
definition$: Observable<Wizard<MetadataResolver>>;
changes$: Observable<MetadataResolver>;
currentPage: string;
valid$: Observable<boolean>;
model$: Observable<any>;

namesList: string[] = [];

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

constructor(
private store: Store<fromResolver.ResolverState>,
) {
this.schema$ = this.store.select(fromWizard.getSchema);
this.definition$ = this.store.select(fromWizard.getWizardDefinition);
this.changes$ = this.store.select(fromResolver.getEntityChanges);

this.validators$ = this.definition$.pipe(
map((def) => def.getValidators())
);

this.model$ = this.schema$.pipe(
withLatestFrom(
this.store.select(fromWizard.getModel),
this.changes$,
this.definition$
),
map(([schema, model, changes, definition]) => ({
model: {
...model,
...changes
},
definition
})),
skipWhile(({ model, definition }) => !definition || !model),
map(({ model, definition }) => definition.formatter(model))
);

this.valueChangeEmitted$.pipe(
withLatestFrom(this.definition$),
skipWhile(([ changes, definition ]) => !definition || !changes),
map(([ changes, definition ]) => definition.parser(changes))
)
.subscribe(changes => this.store.dispatch(new UpdateChanges(changes)));

this.statusChangeEmitted$.pipe(distinctUntilChanged()).subscribe(errors => this.updateStatus(errors));

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() {
this.valueChangeSubject.complete();
}
}

Original file line number Diff line number Diff line change
@@ -1,42 +1,10 @@
<div class="container-fluid p-3" role="main">
<section class="section" *ngIf="resolver$ | async" tabindex="0" [attr.aria-label]="'Add a new metadata source wizard form - ' + (currentPage$ | async).label + ' ' + (resolver$ | async).serviceProviderName">
<div class="section-header bg-info p-2 text-white">
<div class="row justify-content-between">
<div class="col-md-12">
<span class="display-6" role="heading" aria-level="1">
<i class="fa fa-fw fa-plus-square"></i>
<translate-i18n key="message.add-new-md-resolver">Add a new metadata source</translate-i18n>
&ndash; {{ (currentPage$ | async).label | translate }} ({{ (resolver$ | async).serviceProviderName }})
<!--<span class="pull-right">
(<translate-i18n key="message.wizard-status" [params]="{ index: wizardIndex$ | async, length: wizard.length + 1 }">
Step {{ wizardIndex }} of {{ wizard.length + 1 }}
</translate-i18n>)
</span>-->
</span>
</div>
</div>
</div>
<div class="section-body p-4 border border-top-0 border-info" *ngIf="wizardIndex$ | async">
<wizard-nav [index]="wizardIndex$ | async"
<div class="container-fluid" role="main">
<!--<wizard-nav [index]="wizardIndex$ | async"
(onNext)="next($event)"
(onPrevious)="previous($event)"
(onSave)="save($event)"></wizard-nav>
<hr />
<div [ngSwitch]="wizardIndex$ | async" class="py-4">
<org-info-form *ngSwitchDefault [resolver]="resolver$ | async"></org-info-form>
<metadata-ui-form *ngSwitchCase="3" [resolver]="resolver$ | async"></metadata-ui-form>
<descriptor-info-form *ngSwitchCase="4" [resolver]="resolver$ | async"></descriptor-info-form>
<logout-form *ngSwitchCase="5" [resolver]="resolver$ | async"></logout-form>
<key-info-form *ngSwitchCase="6" [resolver]="resolver$ | async"></key-info-form>
<assertion-form *ngSwitchCase="7" [resolver]="resolver$ | async"></assertion-form>
<div class="row" *ngSwitchCase="8">
<relying-party-form [resolver]="resolver$ | async" class="col-xl-6"></relying-party-form>
</div>
<div class="row" *ngSwitchCase="9">
<attribute-release-form [resolver]="resolver$ | async" class="col-xl-6"></attribute-release-form>
</div>
<finish-form *ngSwitchCase="10" [resolver]="resolver$ | async"></finish-form>
</div>
</div>
</section>
(onSave)="save($event)"></wizard-nav>-->
<hr />
<div class="py-4">
<router-outlet></router-outlet>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,16 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat
});

this.store.dispatch(new SetDefinition(this.sourceWizard));
this.store.dispatch(new SetIndex(this.sourceWizard.steps[0].id));

this.store.select(fromWizard.getParsedSchema).subscribe(s => console.log(s));
this.route.params.subscribe(params => {
if (params.index) {
this.store.dispatch(new SetIndex(params.index));
} else {
this.store.dispatch(new SetIndex(this.sourceWizard.steps[0].id));
}
});

console.log('hi');
}

save(): void {
Expand Down Expand Up @@ -105,6 +112,8 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat
currentState: RouterStateSnapshot,
nextState: RouterStateSnapshot
): Observable<boolean> {
return of(true);
/*
if (nextState.url.match('wizard')) { return of(true); }
if (Object.keys(this.changes).length > 0) {
let modal = this.modalService.open(UnsavedDialogComponent);
Expand All @@ -115,5 +124,6 @@ export class ResolverWizardComponent implements OnDestroy, CanComponentDeactivat
);
}
return this.store.select(fromResolver.getEntityIsSaved);
*/
}
} /* istanbul ignore next */
}
12 changes: 9 additions & 3 deletions ui/src/app/metadata/resolver/resolver.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import { I18nModule } from '../../i18n/i18n.module';
import { MetadataSourceWizard } from '../domain/model/wizards/metadata-source-wizard';
import { METADATA_SOURCE_WIZARD } from './wizard-definition';
import { EntityEffects } from './effect/entity.effect';
import { ResolverWizardStepComponent } from './container/resolver-wizard-step.component';
import { WizardModule } from '../../wizard/wizard.module';
import { FormModule } from '../../schema-form/schema-form.module';

@NgModule({
declarations: [
Expand All @@ -44,9 +47,10 @@ import { EntityEffects } from './effect/entity.effect';
ResolverComponent,
DraftComponent,
EditorComponent,
ResolverWizardComponent,
WizardNavComponent,
UnsavedDialogComponent
UnsavedDialogComponent,
ResolverWizardComponent,
ResolverWizardStepComponent
],
entryComponents: [
UnsavedDialogComponent
Expand All @@ -61,7 +65,9 @@ import { EntityEffects } from './effect/entity.effect';
FormsModule,
ProviderEditorFormModule,
NgbDropdownModule,
I18nModule
I18nModule,
WizardModule,
FormModule
],
exports: [
ProviderEditorFormModule,
Expand Down
11 changes: 9 additions & 2 deletions ui/src/app/metadata/resolver/resolver.routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { ConfirmCopyComponent } from './container/confirm-copy.component';
import { CopyIsSetGuard } from './guard/copy-isset.guard';

import { CanDeactivateGuard } from '../../core/service/can-deactivate.guard';
import { ResolverWizardStepComponent } from './container/resolver-wizard-step.component';

export const ResolverRoutes: Routes = [
{
Expand All @@ -25,8 +26,14 @@ export const ResolverRoutes: Routes = [
{ path: '', redirectTo: 'blank', pathMatch: 'prefix' },
{
path: 'blank',
component: BlankResolverComponent,
canDeactivate: []
component: ResolverWizardComponent,
canDeactivate: [],
children: [
{
path: '',
component: ResolverWizardStepComponent
}
]
},
{
path: 'upload',
Expand Down
4 changes: 2 additions & 2 deletions ui/src/app/wizard/reducer/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ describe('wizard index selectors', () => {
describe('getSchema method', () => {
it('should return the schema by index name', () => {
expect(
selectors.getSchema('common', FileBackedHttpMetadataProviderWizard)
selectors.getSchemaPath('common', FileBackedHttpMetadataProviderWizard)
).toBe(FileBackedHttpMetadataProviderWizard.steps[0].schema);
});
it('should return nothing if no schema is found', () => {
expect(
selectors.getSchema('common', null)
selectors.getSchemaPath('common', null)
).toBeFalsy();
});
});
Expand Down
20 changes: 18 additions & 2 deletions ui/src/app/wizard/reducer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,27 @@ export const getWizardIsDisabled = createSelector(getState, fromWizard.getDisabl
export const getWizardDefinition = createSelector(getState, fromWizard.getDefinition);
export const getSchemaCollection = createSelector(getState, fromWizard.getCollection);

export const getSchema = (index: string, wizard: Wizard<any>) => {
export const getSchemaPath = (index: string, wizard: Wizard<any>) => {
if (!wizard) { return null; }
const step = wizard.steps.find(s => s.id === index);
return step ? step.schema : null;
};

export const getCurrentWizardSchema = createSelector(getWizardIndex, getWizardDefinition, getSchema);
export const getSplitSchema = (schema: any, step: WizardStep) => {
if (!schema || !step.fields || !step.fields.length) {
return schema;
}
const keys = Object.keys(schema.properties).filter(key => step.fields.indexOf(key) > -1);

return {
...schema,
properties: {
...keys.reduce( (properties, key) => ({ ...properties, [key]: schema.properties[key] }) , {})
}
};
};

export const getCurrentWizardSchema = createSelector(getWizardIndex, getWizardDefinition, getSchemaPath);

export const getPreviousFn = (index: string, wizard: Wizard<any>) => {
if (!wizard) { return null; }
Expand Down Expand Up @@ -96,3 +110,5 @@ export const getLocked = createSelector(getCurrent, getLockedStatus, getSchemaLo

export const getSchemaObject = createSelector(getState, fromWizard.getSchema);
export const getParsedSchema = createSelector(getSchemaObject, getLocked, getSchemaParseFn);

export const getSchema = createSelector(getParsedSchema, getCurrent, getSplitSchema);

0 comments on commit 6ab5c0d

Please sign in to comment.