Skip to content

Commit

Permalink
Multiple User Provided Service Instance Create/Update Fixes (#4117)
Browse files Browse the repository at this point in the history
- On transistion from list to edit stepper user can now supply just tags to enable form
- Fixed error handling on create and update flows
- Ensure we update service instance list after creating user provided service instance
  • Loading branch information
richard-cox authored Feb 4, 2020
1 parent a62b0fc commit f96f8c7
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
selectCreateServiceInstance,
} from '../../../../../../cloud-foundry/src/store/selectors/create-service-instance.selectors';
import { IUserProvidedServiceInstance } from '../../../../../../core/src/core/cf-api-svc.types';
import { entityCatalog } from '../../../../../../store/src/entity-catalog/entity-catalog.service';
import { safeUnsubscribe, urlValidationExpression } from '../../../../../../core/src/core/utils.service';
import { environment } from '../../../../../../core/src/environments/environment';
import {
Expand All @@ -34,6 +33,7 @@ import { isValidJsonValidator } from '../../../../../../core/src/shared/form-val
import {
CloudFoundryUserProvidedServicesService,
} from '../../../../../../core/src/shared/services/cloud-foundry-user-provided-services.service';
import { entityCatalog } from '../../../../../../store/src/entity-catalog/entity-catalog.service';
import { APIResource } from '../../../../../../store/src/types/api.types';
import { CF_ENDPOINT_TYPE } from '../../../../cf-types';
import { CreateServiceFormMode, CsiModeService } from './../csi-mode.service';
Expand Down Expand Up @@ -124,6 +124,17 @@ export class SpecifyUserProvidedDetailsComponent implements OnDestroy {
),
map(valid => this.validAndChanged(valid)),
);
this.subscriptions.push(this.tagsChanged.subscribe(() => {
if (this.formMode === CreateServiceFormMode.CreateServiceInstance) {
this.createEditServiceInstance.markAsTouched();
this.createEditServiceInstance.markAsDirty();
this.createEditServiceInstance.updateValueAndValidity();
} else {
this.bindExistingInstance.markAsTouched();
this.bindExistingInstance.markAsDirty();
this.bindExistingInstance.updateValueAndValidity();
}
}));
this.subscriptions.push(obs.subscribe(valid => this.valid.next(valid)));
}

Expand Down Expand Up @@ -252,10 +263,10 @@ export class SpecifyUserProvidedDetailsComponent implements OnDestroy {
).pipe(
combineLatest(this.store.select(selectCreateServiceInstance)),
switchMap(([request, state]) => {
const newGuid = request.response.result[0];
const success = !request.error;
const redirect = !request.error;
if (!!state.bindAppGuid && success) {
const newGuid = request.response.result[0];
return this.createApplicationServiceBinding(newGuid, state);
}
return observableOf({
Expand Down Expand Up @@ -293,7 +304,7 @@ export class SpecifyUserProvidedDetailsComponent implements OnDestroy {
);
}

private onNextUpdate() {
private onNextUpdate(): Observable<StepOnNextResult> {
const updateData = this.getServiceData();
return this.upsService.updateUserProvidedService(
this.cfGuid,
Expand All @@ -302,7 +313,8 @@ export class SpecifyUserProvidedDetailsComponent implements OnDestroy {
).pipe(
map(er => ({
success: !er.updating[UpdateUserProvidedServiceInstance.updateServiceInstance].error,
redirect: !er.updating[UpdateUserProvidedServiceInstance.updateServiceInstance].error
redirect: !er.updating[UpdateUserProvidedServiceInstance.updateServiceInstance].error,
message: `Failed to update service instance: ${er.updating[UpdateUserProvidedServiceInstance.updateServiceInstance].message}`
}))
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { combineLatest, Observable } from 'rxjs';
import { debounceTime, filter, map } from 'rxjs/operators';
import { filter, first, map, pairwise, tap } from 'rxjs/operators';

import { CF_ENDPOINT_TYPE } from '../../../../cloud-foundry/src/cf-types';
import {
CreateUserProvidedServiceInstance,
getUserProvidedServiceInstanceRelations,
Expand All @@ -17,22 +16,24 @@ import {
spaceEntityType,
userProvidedServiceInstanceEntityType,
} from '../../../../cloud-foundry/src/cf-entity-types';
import { CF_ENDPOINT_TYPE } from '../../../../cloud-foundry/src/cf-types';
import {
UserProvidedServiceActionBuilder,
} from '../../../../cloud-foundry/src/entity-action-builders/user-provided-service.action-builders';
import { createEntityRelationPaginationKey } from '../../../../cloud-foundry/src/entity-relations/entity-relations.types';
import { fetchTotalResults } from '../../../../cloud-foundry/src/features/cloud-foundry/cf.helpers';
import { selectCfRequestInfo } from '../../../../cloud-foundry/src/store/selectors/api.selectors';
import { QParam, QParamJoiners } from '../../../../cloud-foundry/src/shared/q-param';
import { selectCfRequestInfo } from '../../../../cloud-foundry/src/store/selectors/api.selectors';
import { ClearPaginationOfType } from '../../../../store/src/actions/pagination.actions';
import { entityCatalog } from '../../../../store/src/entity-catalog/entity-catalog.service';
import { EntityCatalogEntityConfig, IEntityMetadata } from '../../../../store/src/entity-catalog/entity-catalog.types';
import { EntityServiceFactory } from '../../../../store/src/entity-service-factory.service';
import { PaginationMonitorFactory } from '../../../../store/src/monitors/pagination-monitor.factory';
import { RequestInfoState } from '../../../../store/src/reducers/api-request-reducer/types';
import { getPaginationObservables } from '../../../../store/src/reducers/pagination-reducer/pagination-reducer.helper';
import { APIResource } from '../../../../store/src/types/api.types';
import { PaginatedAction } from '../../../../store/src/types/pagination.types';
import { IUserProvidedServiceInstance } from '../../core/cf-api-svc.types';
import { entityCatalog } from '../../../../store/src/entity-catalog/entity-catalog.service';
import { EntityCatalogEntityConfig, IEntityMetadata } from '../../../../store/src/entity-catalog/entity-catalog.types';
import { EntityServiceFactory } from '../../../../store/src/entity-service-factory.service';
import { PaginationMonitorFactory } from '../../../../store/src/monitors/pagination-monitor.factory';


@Injectable()
Expand All @@ -43,6 +44,11 @@ export class CloudFoundryUserProvidedServicesService {
entityType: serviceInstancesEntityType
};

private userProvidedServiceInstancesEntityConfig: EntityCatalogEntityConfig = {
endpointType: CF_ENDPOINT_TYPE,
entityType: userProvidedServiceInstanceEntityType
};

private userProvidedServiceEntity = entityCatalog.getEntity<IEntityMetadata, any, UserProvidedServiceActionBuilder>(
CF_ENDPOINT_TYPE,
userProvidedServiceInstanceEntityType
Expand Down Expand Up @@ -114,12 +120,21 @@ export class CloudFoundryUserProvidedServicesService {
guid: string,
data: IUserProvidedServiceInstanceData
): Observable<RequestInfoState> {
const action = new CreateUserProvidedServiceInstance(cfGuid, guid, data, this.serviceInstancesEntityConfig);
const action = new CreateUserProvidedServiceInstance(cfGuid, guid, data, this.userProvidedServiceInstancesEntityConfig);
const create$ = this.store.select(selectCfRequestInfo(userProvidedServiceInstanceEntityType, guid));
this.store.dispatch(action);
return create$.pipe(
debounceTime(250),
filter(a => !a.creating),
pairwise(),
filter(([oldV, newV]) => oldV.creating && !newV.creating),
map(([, newV]) => newV),
first(),
tap(v => {
if (!v.error) {
// Problem - Lists with multiple actions aren't updated following the creation of an entity based on secondary action
// Here the service instance list (1st action SI, 2nd action UPSI) isn't updated so manually do so
this.store.dispatch(new ClearPaginationOfType(this.serviceInstancesEntityConfig));
}
})
);
}

Expand All @@ -132,16 +147,18 @@ export class CloudFoundryUserProvidedServicesService {
guid,
cfGuid,
data,
this.serviceInstancesEntityConfig
this.userProvidedServiceInstancesEntityConfig
);
return this.userProvidedServiceEntity.getEntityMonitor(
this.store,
guid
).entityRequest$.pipe(
filter(
er => er.updating[UpdateUserProvidedServiceInstance.updateServiceInstance] &&
er.updating[UpdateUserProvidedServiceInstance.updateServiceInstance].busy
)
filter(v => !!v.updating[UpdateUserProvidedServiceInstance.updateServiceInstance]),
pairwise(),
filter(([oldV, newV]) =>
oldV.updating[UpdateUserProvidedServiceInstance.updateServiceInstance].busy &&
!newV.updating[UpdateUserProvidedServiceInstance.updateServiceInstance].busy),
map(([, newV]) => newV)
);
}

Expand Down

0 comments on commit f96f8c7

Please sign in to comment.