From 392769b00f1819cbb389866aba6204880c5f8510 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Wed, 20 Mar 2019 17:25:23 +0000 Subject: [PATCH 1/7] Add a user provided service instance tab & list to the space page --- .../application-tabs-base.component.ts | 7 + .../cloud-foundry/cloud-foundry.module.ts | 4 + .../cloud-foundry/cloud-foundry.routing.ts | 7 + .../cloud-foundry-space-base.component.ts | 4 + ...pace-user-service-instances.component.html | 3 + ...pace-user-service-instances.component.scss | 0 ...e-user-service-instances.component.spec.ts | 30 +++ ...-space-user-service-instances.component.ts | 19 ++ .../add-service-instance/csi-mode.service.ts | 5 +- .../cf-service-instances-list-config.base.ts | 2 +- .../cf-user-service-instances-list-config.ts | 210 ++++++++++++++++++ ...aces-user-service-instances-data-source.ts | 46 ++++ .../actions/user-provided-service.actions.ts | 2 +- .../space-level/cf-space-level-e2e.spec.ts | 1 + .../space-level/cf-space-level-page.po.ts | 4 + 15 files changed, 341 insertions(+), 3 deletions(-) create mode 100644 src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.html create mode 100644 src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.scss create mode 100644 src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.spec.ts create mode 100644 src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.ts create mode 100644 src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts create mode 100644 src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts diff --git a/src/frontend/packages/core/src/features/applications/application/application-tabs-base/application-tabs-base.component.ts b/src/frontend/packages/core/src/features/applications/application/application-tabs-base/application-tabs-base.component.ts index 5f0e87b954..3a211e4f49 100644 --- a/src/frontend/packages/core/src/features/applications/application/application-tabs-base/application-tabs-base.component.ts +++ b/src/frontend/packages/core/src/features/applications/application/application-tabs-base/application-tabs-base.component.ts @@ -217,6 +217,13 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy { { value: space.entity.name, routerLink: `${baseOrgUrl}/spaces/${space.metadata.guid}/service-instances` } ] }, + { + key: 'space-user-services', + breadcrumbs: [ + ...baseSpaceBreadcrumbs, + { value: space.entity.name, routerLink: `${baseOrgUrl}/spaces/${space.metadata.guid}/user-service-instances` } + ] + }, { key: 'space-routes', breadcrumbs: [ diff --git a/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.module.ts b/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.module.ts index 5ac649661b..41c30c5715 100644 --- a/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.module.ts +++ b/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.module.ts @@ -71,6 +71,9 @@ import { import { CloudFoundrySpaceSummaryComponent, } from './tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-summary/cloud-foundry-space-summary.component'; +import { + CloudFoundrySpaceUserServiceInstancesComponent, +} from './tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component'; import { CloudFoundrySpaceUsersComponent, } from './tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-users/cloud-foundry-space-users.component'; @@ -143,6 +146,7 @@ import { UsersRolesComponent } from './users/manage-users/manage-users.component CloudFoundrySpaceBaseComponent, CloudFoundrySpaceAppsComponent, CloudFoundrySpaceServiceInstancesComponent, + CloudFoundrySpaceUserServiceInstancesComponent, CloudFoundrySpaceRoutesComponent, CloudFoundrySpaceUsersComponent, EditSpaceStepComponent, diff --git a/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.routing.ts b/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.routing.ts index 5f31e1aaaa..1b9fcfa92b 100644 --- a/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.routing.ts +++ b/src/frontend/packages/core/src/features/cloud-foundry/cloud-foundry.routing.ts @@ -50,6 +50,9 @@ import { import { CloudFoundrySpaceSummaryComponent, } from './tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-summary/cloud-foundry-space-summary.component'; +import { + CloudFoundrySpaceUserServiceInstancesComponent, +} from './tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component'; import { CloudFoundrySpaceUsersComponent, } from './tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-users/cloud-foundry-space-users.component'; @@ -297,6 +300,10 @@ const cloudFoundry: Routes = [{ path: 'service-instances', component: CloudFoundrySpaceServiceInstancesComponent }, + { + path: 'user-service-instances', + component: CloudFoundrySpaceUserServiceInstancesComponent + }, { path: 'routes', component: CloudFoundrySpaceRoutesComponent diff --git a/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/cloud-foundry-space-base/cloud-foundry-space-base.component.ts b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/cloud-foundry-space-base/cloud-foundry-space-base.component.ts index d30e16407d..681ac3bbc5 100644 --- a/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/cloud-foundry-space-base/cloud-foundry-space-base.component.ts +++ b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/cloud-foundry-space-base/cloud-foundry-space-base.component.ts @@ -53,6 +53,10 @@ export class CloudFoundrySpaceBaseComponent implements OnDestroy { link: 'service-instances', label: 'Service Instances' }, + { + link: 'user-service-instances', + label: 'User Service Instances' + }, { link: 'routes', label: 'Routes', diff --git a/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.html b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.html new file mode 100644 index 0000000000..4dd3e95951 --- /dev/null +++ b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.scss b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.spec.ts b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.spec.ts new file mode 100644 index 0000000000..b976c31ff5 --- /dev/null +++ b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.spec.ts @@ -0,0 +1,30 @@ +import { DatePipe } from '@angular/common'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BaseTestModules } from '../../../../../../../../test-framework/cloud-foundry-endpoint-service.helper'; +import { getCfSpaceServiceMock } from '../../../../../../../../test-framework/cloud-foundry-space.service.mock'; +import { CloudFoundrySpaceUserServiceInstancesComponent } from './cloud-foundry-space-user-service-instances.component'; + +describe('CloudFoundrySpaceUserServiceInstancesComponent', () => { + let component: CloudFoundrySpaceUserServiceInstancesComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [CloudFoundrySpaceUserServiceInstancesComponent], + imports: [...BaseTestModules], + providers: [getCfSpaceServiceMock, DatePipe] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CloudFoundrySpaceUserServiceInstancesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.ts b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.ts new file mode 100644 index 0000000000..c6c85a252a --- /dev/null +++ b/src/frontend/packages/core/src/features/cloud-foundry/tabs/cloud-foundry-organizations/cloud-foundry-organization-spaces/tabs/cloud-foundry-space-user-service-instances/cloud-foundry-space-user-service-instances.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; + +import { + CfUserServiceInstancesListConfigBase, +} from '../../../../../../../shared/components/list/list-types/cf-services/cf-user-service-instances-list-config'; +import { ListConfig } from '../../../../../../../shared/components/list/list.component.types'; + +@Component({ + selector: 'app-cloud-foundry-space-user-service-instances', + templateUrl: './cloud-foundry-space-user-service-instances.component.html', + styleUrls: ['./cloud-foundry-space-user-service-instances.component.scss'], + providers: [ + { + provide: ListConfig, + useClass: CfUserServiceInstancesListConfigBase + } + ] +}) +export class CloudFoundrySpaceUserServiceInstancesComponent { } diff --git a/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts b/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts index e5f02b1b38..a4d609e6cc 100644 --- a/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts +++ b/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts @@ -13,6 +13,7 @@ export enum CreateServiceInstanceMode { export const CANCEL_SPACE_ID_PARAM = 'space-guid'; export const CANCEL_ORG_ID_PARAM = 'org-guid'; +export const CANCEL_USER_PROVIDED = 'up'; interface ViewDetail { showSelectCf: boolean; @@ -47,6 +48,7 @@ export class CsiModeService { this.cancelUrl = `/services`; const spaceGuid = activatedRoute.snapshot.queryParams[CANCEL_SPACE_ID_PARAM]; const orgGuid = activatedRoute.snapshot.queryParams[CANCEL_ORG_ID_PARAM]; + const isUserProvided = activatedRoute.snapshot.queryParams[CANCEL_USER_PROVIDED]; const cfId = getIdFromRoute(activatedRoute, 'endpointId'); const id = getIdFromRoute(activatedRoute, 'id'); @@ -94,7 +96,8 @@ export class CsiModeService { } if (spaceGuid && orgGuid) { - this.cancelUrl = `/cloud-foundry/${cfId}/organizations/${orgGuid}/spaces/${spaceGuid}/service-instances`; + this.cancelUrl = + `/cloud-foundry/${cfId}/organizations/${orgGuid}/spaces/${spaceGuid}/${isUserProvided ? 'user-service-instances' : 'service-instances'}`; } } diff --git a/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts b/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts index 1ee1440b6f..19193c2b09 100644 --- a/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts +++ b/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts @@ -53,7 +53,7 @@ export class CfServiceInstancesListConfigBase implements IListConfig>[] = [ { columnId: 'name', - headerCell: () => 'Service Instances', + headerCell: () => 'Service Instance', cellDefinition: { getValue: (row) => `${row.entity.name}` }, diff --git a/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts b/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts new file mode 100644 index 0000000000..8fd10e6c67 --- /dev/null +++ b/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts @@ -0,0 +1,210 @@ +import { DatePipe } from '@angular/common'; +import { Injectable } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; + +import { ListView } from '../../../../../../../store/src/actions/list.actions'; +import { AppState } from '../../../../../../../store/src/app-state'; +import { APIResource } from '../../../../../../../store/src/types/api.types'; +import { IUserProvidedServiceInstance } from '../../../../../core/cf-api-svc.types'; +import { CurrentUserPermissions } from '../../../../../core/current-user-permissions.config'; +import { CurrentUserPermissionsService } from '../../../../../core/current-user-permissions.service'; +import { CloudFoundrySpaceService } from '../../../../../features/cloud-foundry/services/cloud-foundry-space.service'; +import { ServiceActionHelperService } from '../../../../data-services/service-action-helper.service'; +import { + CANCEL_ORG_ID_PARAM, + CANCEL_SPACE_ID_PARAM, + CANCEL_USER_PROVIDED, +} from '../../../add-service-instance/csi-mode.service'; +import { ListDataSource } from '../../data-sources-controllers/list-data-source'; +import { ITableColumn } from '../../list-table/table.types'; +import { defaultPaginationPageSizeOptionsTable, IListAction, IListConfig, ListViewTypes } from '../../list.component.types'; +import { + CfSpacesUserServiceInstancesDataSource, +} from '../cf-spaces-service-instances/cf-spaces-user-service-instances-data-source'; +import { + TableCellServiceInstanceAppsAttachedComponent, +} from '../cf-spaces-service-instances/table-cell-service-instance-apps-attached/table-cell-service-instance-apps-attached.component'; +import { + TableCellServiceInstanceTagsComponent, +} from '../cf-spaces-service-instances/table-cell-service-instance-tags/table-cell-service-instance-tags.component'; +import { + TableCellSpaceNameComponent, +} from '../cf-spaces-service-instances/table-cell-space-name/table-cell-space-name.component'; + +interface CanCache { + [spaceGuid: string]: Observable; +} + +@Injectable() +export class CfUserServiceInstancesListConfigBase implements IListConfig> { + viewType = ListViewTypes.TABLE_ONLY; + pageSizeOptions = defaultPaginationPageSizeOptionsTable; + dataSource: ListDataSource; + defaultView = 'table' as ListView; + text = { + title: null, + filter: null, + noEntries: 'There are no user provided service instances' + }; + + private canDetachCache: CanCache = {}; + private canDeleteCache: CanCache = {}; + + protected serviceInstanceColumns: ITableColumn>[] = [ + { + columnId: 'name', + headerCell: () => 'Service Instance', + cellDefinition: { + getValue: (row) => `${row.entity.name}` + }, + cellFlex: '2' + }, + { + columnId: 'space', + headerCell: () => 'Space', + cellComponent: TableCellSpaceNameComponent, + cellFlex: '1' + }, + // { + // columnId: 'service', + // headerCell: () => 'Service', + // cellComponent: TableCellServiceNameComponent, + // cellFlex: '1' + // }, + // { + // columnId: 'servicePlan', + // headerCell: () => 'Plan', + // cellComponent: TableCellServicePlanComponent, + // cellFlex: '1' + // }, + // { + // columnId: 'dashboard', + // headerCell: () => 'Dashboard', + // cellDefinition: { + // externalLink: true, + // getLink: (row: APIResource) => row.entity.dashboard_url, + // newTab: true, + // showShortLink: true + // }, + // cellFlex: '1' + // }, + { + columnId: 'tags', + headerCell: () => 'Tags', + cellComponent: TableCellServiceInstanceTagsComponent, + cellFlex: '2' + }, + { + columnId: 'attachedApps', + headerCell: () => 'Attached Applications', + cellComponent: TableCellServiceInstanceAppsAttachedComponent, + cellFlex: '3' + }, + { + columnId: 'creation', headerCell: () => 'Creation Date', + cellDefinition: { + getValue: (row: APIResource) => `${this.datePipe.transform(row.metadata.created_at, 'medium')}` + }, + sort: { + type: 'sort', + orderKey: 'creation', + field: 'metadata.created_at' + }, + cellFlex: '2' + }, + ]; + + private listActionDelete: IListAction = { + action: (item: APIResource) => this.deleteServiceInstance(item), + label: 'Delete', + description: 'Delete Service Instance', + createVisible: (row$: Observable>) => + row$.pipe( + switchMap( + row => this.can(this.canDeleteCache, CurrentUserPermissions.SERVICE_INSTANCE_DELETE, row.entity.cfGuid, row.entity.space_guid) + ) + ) + }; + + private listActionDetach: IListAction = { + action: (item: APIResource) => this.deleteServiceBinding(item), + label: 'Unbind', + description: 'Unbind Service Instance', + createEnabled: (row$: Observable>) => + row$.pipe(map(row => row.entity.service_bindings.length !== 0)), + createVisible: (row$: Observable>) => + row$.pipe( + switchMap( + row => this.can(this.canDetachCache, CurrentUserPermissions.SERVICE_BINDING_EDIT, row.entity.cfGuid, row.entity.space_guid) + ) + ) + }; + + private listActionEdit: IListAction = { + action: (item: APIResource) => + this.serviceActionHelperService.editServiceBinding(item.metadata.guid, item.entity.cfGuid, { + [CANCEL_SPACE_ID_PARAM]: item.entity.space_guid, + [CANCEL_ORG_ID_PARAM]: item.entity.space.entity.organization_guid, + [CANCEL_USER_PROVIDED]: true + }, true), + label: 'Edit', + description: 'Edit Service Instance', + createVisible: (row$: Observable>) => + row$.pipe( + switchMap( + row => this.can(this.canDetachCache, CurrentUserPermissions.SERVICE_BINDING_EDIT, row.entity.cfGuid, row.entity.space_guid) + ) + ) + }; + + private can(cache: CanCache, perm: CurrentUserPermissions, cfGuid: string, spaceGuid: string): Observable { + let can = cache[spaceGuid]; + if (!can) { + can = this.currentUserPermissionsService.can(perm, cfGuid, spaceGuid); + cache[spaceGuid] = can; + } + return can; + } + + constructor( + protected store: Store, + cfSpaceService: CloudFoundrySpaceService, + protected datePipe: DatePipe, + protected currentUserPermissionsService: CurrentUserPermissionsService, + private serviceActionHelperService: ServiceActionHelperService + ) { + this.dataSource = new CfSpacesUserServiceInstancesDataSource(cfSpaceService.cfGuid, cfSpaceService.spaceGuid, this.store, this); + this.serviceInstanceColumns.find(column => column.columnId === 'attachedApps').cellConfig = { + breadcrumbs: 'space-user-services' + }; + } + + deleteServiceInstance = (serviceInstance: APIResource) => + this.serviceActionHelperService.deleteServiceInstance( + serviceInstance.metadata.guid, + serviceInstance.entity.name, + serviceInstance.entity.cfGuid, + true + ) + + + deleteServiceBinding = (serviceInstance: APIResource) => { + this.serviceActionHelperService.detachServiceBinding( + serviceInstance.entity.service_bindings, + serviceInstance.metadata.guid, + serviceInstance.entity.cfGuid, + false, + true + ); + } + + getGlobalActions = () => []; + getMultiActions = () => []; + getSingleActions = () => [this.listActionEdit, this.listActionDetach, this.listActionDelete]; + getMultiFiltersConfigs = () => []; + getColumns = () => this.serviceInstanceColumns; + getDataSource = () => this.dataSource; + +} diff --git a/src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts b/src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts new file mode 100644 index 0000000000..491d3cb94d --- /dev/null +++ b/src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts @@ -0,0 +1,46 @@ +import { Store } from '@ngrx/store'; + +import { GetAllUserProvidedServices } from '../../../../../../../store/src/actions/user-provided-service.actions'; +import { AppState } from '../../../../../../../store/src/app-state'; +import { + applicationSchemaKey, + entityFactory, + organizationSchemaKey, + serviceBindingSchemaKey, + spaceSchemaKey, + spaceWithOrgKey, + userProvidedServiceInstanceSchemaKey, +} from '../../../../../../../store/src/helpers/entity-factory'; +import { + createEntityRelationKey, + createEntityRelationPaginationKey, +} from '../../../../../../../store/src/helpers/entity-relations/entity-relations.types'; +import { APIResource } from '../../../../../../../store/src/types/api.types'; +import { getRowMetadata } from '../../../../../features/cloud-foundry/cf.helpers'; +import { ListDataSource } from '../../data-sources-controllers/list-data-source'; +import { defaultPaginationPageSizeOptionsTable, IListConfig } from '../../list.component.types'; + +export class CfSpacesUserServiceInstancesDataSource extends ListDataSource { + constructor(cfGuid: string, spaceGuid: string, store: Store, listConfig?: IListConfig) { + const paginationKey = createEntityRelationPaginationKey(spaceSchemaKey, spaceGuid); + const action = new GetAllUserProvidedServices(cfGuid, [ + createEntityRelationKey(userProvidedServiceInstanceSchemaKey, spaceWithOrgKey), + createEntityRelationKey(spaceSchemaKey, organizationSchemaKey), + createEntityRelationKey(userProvidedServiceInstanceSchemaKey, serviceBindingSchemaKey), + createEntityRelationKey(serviceBindingSchemaKey, applicationSchemaKey) + ], true, spaceGuid); + action.initialParams['results-per-page'] = defaultPaginationPageSizeOptionsTable[0]; + action.initialParams['order-direction-field'] = 'creation'; + action.flattenPagination = false; + super({ + store, + action, + schema: entityFactory(userProvidedServiceInstanceSchemaKey), + getRowUniqueId: getRowMetadata, + paginationKey, + isLocal: false, + transformEntities: [], + listConfig + }); + } +} diff --git a/src/frontend/packages/store/src/actions/user-provided-service.actions.ts b/src/frontend/packages/store/src/actions/user-provided-service.actions.ts index 9d3518ecb1..ce5d36f56c 100644 --- a/src/frontend/packages/store/src/actions/user-provided-service.actions.ts +++ b/src/frontend/packages/store/src/actions/user-provided-service.actions.ts @@ -47,7 +47,7 @@ export class GetAllUserProvidedServices extends CFStartAction implements Paginat } } actions = getActions('User Provided Services', 'Get all User Provided Services'); - entity = entityFactory(userProvidedServiceInstanceSchemaKey); + entity = [entityFactory(userProvidedServiceInstanceSchemaKey)]; entityKey = userProvidedServiceInstanceSchemaKey; options: RequestOptions; initialParams = { diff --git a/src/test-e2e/cloud-foundry/space-level/cf-space-level-e2e.spec.ts b/src/test-e2e/cloud-foundry/space-level/cf-space-level-e2e.spec.ts index 08b41247f8..af3f250128 100644 --- a/src/test-e2e/cloud-foundry/space-level/cf-space-level-e2e.spec.ts +++ b/src/test-e2e/cloud-foundry/space-level/cf-space-level-e2e.spec.ts @@ -27,6 +27,7 @@ describe('CF - Space Level -', () => { function testTabs() { spacePage.goToAppsTab(); spacePage.goToSITab(); + spacePage.goToUPSITab(); spacePage.goToRoutesTab(); spacePage.goToUsersTab(); spacePage.goToSummaryTab(); diff --git a/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts b/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts index e7a2441318..a7f42defa1 100644 --- a/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts +++ b/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts @@ -39,6 +39,10 @@ export class CfSpaceLevelPage extends CFPage { return this.goToTab('Service Instances', 'service-instances'); } + goToUPSITab() { + return this.goToTab('Service Instances', 'user-service-instances'); + } + goToRoutesTab() { return this.goToTab('Routes', 'routes'); } From 332f3ad01cae7eadc90d40d4d0a50a5ef36845ba Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Wed, 20 Mar 2019 17:30:51 +0000 Subject: [PATCH 2/7] Add missing columns --- .../add-service-instance/csi-mode.service.ts | 1 + .../cf-user-service-instances-list-config.ts | 39 ++++++++----------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts b/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts index a4d609e6cc..3dc94b2089 100644 --- a/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts +++ b/src/frontend/packages/core/src/shared/components/add-service-instance/csi-mode.service.ts @@ -97,6 +97,7 @@ export class CsiModeService { if (spaceGuid && orgGuid) { this.cancelUrl = + // tslint:disable-next-line:max-line-length `/cloud-foundry/${cfId}/organizations/${orgGuid}/spaces/${spaceGuid}/${isUserProvided ? 'user-service-instances' : 'service-instances'}`; } diff --git a/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts b/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts index 8fd10e6c67..3df865ecea 100644 --- a/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts +++ b/src/frontend/packages/core/src/shared/components/list/list-types/cf-services/cf-user-service-instances-list-config.ts @@ -67,29 +67,22 @@ export class CfUserServiceInstancesListConfigBase implements IListConfig 'Service', - // cellComponent: TableCellServiceNameComponent, - // cellFlex: '1' - // }, - // { - // columnId: 'servicePlan', - // headerCell: () => 'Plan', - // cellComponent: TableCellServicePlanComponent, - // cellFlex: '1' - // }, - // { - // columnId: 'dashboard', - // headerCell: () => 'Dashboard', - // cellDefinition: { - // externalLink: true, - // getLink: (row: APIResource) => row.entity.dashboard_url, - // newTab: true, - // showShortLink: true - // }, - // cellFlex: '1' - // }, + { + columnId: 'route', + headerCell: () => 'Route Service URL', + cellDefinition: { + getValue: (row) => `${row.entity.route_service_url}` + }, + cellFlex: '2' + }, + { + columnId: 'syslog', + headerCell: () => 'Syslog Drain URL', + cellDefinition: { + getValue: (row) => `${row.entity.syslog_drain_url}` + }, + cellFlex: '2' + }, { columnId: 'tags', headerCell: () => 'Tags', From 8fe427df40e1677f337ea9deeed8fa3ab7f65cc3 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Fri, 22 Mar 2019 17:15:24 +0000 Subject: [PATCH 3/7] Fix late failing test --- .../list/list-types/endpoint/endpoint-list.helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/packages/core/src/shared/components/list/list-types/endpoint/endpoint-list.helpers.ts b/src/frontend/packages/core/src/shared/components/list/list-types/endpoint/endpoint-list.helpers.ts index a2e5ce482f..2c0d346363 100644 --- a/src/frontend/packages/core/src/shared/components/list/list-types/endpoint/endpoint-list.helpers.ts +++ b/src/frontend/packages/core/src/shared/components/list/list-types/endpoint/endpoint-list.helpers.ts @@ -162,7 +162,7 @@ export class EndpointListHelper { } destroyEndpointDetails(refs: EndpointDetailsContainerRefs) { - if (refs.componentRef) { + if (refs.componentRef && refs.componentRef.destroy) { refs.componentRef.destroy(); } if (refs.endpointDetails) { From 3ccfc0b479feb76fc3b8778caa855ea14b3591e6 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Mon, 25 Mar 2019 12:46:14 +0000 Subject: [PATCH 4/7] Improve unit test --- .../packages/core/test-framework/store-test-helper.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/frontend/packages/core/test-framework/store-test-helper.ts b/src/frontend/packages/core/test-framework/store-test-helper.ts index f1bb91526e..18e6746de9 100644 --- a/src/frontend/packages/core/test-framework/store-test-helper.ts +++ b/src/frontend/packages/core/test-framework/store-test-helper.ts @@ -2,7 +2,7 @@ import { ModuleWithProviders } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { AppState } from '../../store/src/app-state'; -import { addEntityToCache, EntitySchema } from '../../store/src/helpers/entity-factory'; +import { addEntityToCache, EntitySchema, userProvidedServiceInstanceSchemaKey } from '../../store/src/helpers/entity-factory'; import { appReducers } from '../../store/src/reducers.module'; import { registerAPIRequestEntity } from '../../store/src/reducers/api-request-reducers.generator'; import { getDefaultEndpointRoles, getDefaultRolesRequestState } from '../../store/src/types/current-user-roles.types'; @@ -611,7 +611,8 @@ function getDefaultInitialTestStoreState(): AppState { gitCommits: {}, domain: {}, metrics: {}, - servicePlan: {} + servicePlan: {}, + [userProvidedServiceInstanceSchemaKey]: {} }, dashboard: { sidenavOpen: true, @@ -3906,6 +3907,7 @@ function getDefaultInitialTestStoreState(): AppState { system: {}, private_domains: {}, space_quota_definition: {}, + [userProvidedServiceInstanceSchemaKey]: {} }, requestData: { userFavorites: {}, @@ -21794,7 +21796,8 @@ function getDefaultInitialTestStoreState(): AppState { } ], passwordLastModified: '' - } + }, + [userProvidedServiceInstanceSchemaKey]: {} }, actionHistory: [], lists: {}, From cd3dac4d66988c147bb2ee59cf779e27f4898a57 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Thu, 4 Apr 2019 12:10:50 +0100 Subject: [PATCH 5/7] Fix unit tests - not sure how these are broken on master, all PRs have been passing - fix is to ensure endpoint & home page component tests use pre-populated store - also improved typing --- .../dashboard-base/dashboard-base.component.ts | 4 ++-- .../features/dashboard/side-nav/side-nav.component.ts | 11 +++++++---- .../endpoints-page/endpoints-page.component.spec.ts | 9 +++------ .../features/home/home/home-page.component.spec.ts | 7 ++----- .../login/login-page/login-page.component.spec.ts | 2 +- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/frontend/packages/core/src/features/dashboard/dashboard-base/dashboard-base.component.ts b/src/frontend/packages/core/src/features/dashboard/dashboard-base/dashboard-base.component.ts index 3575e333b0..1c28dfeb88 100644 --- a/src/frontend/packages/core/src/features/dashboard/dashboard-base/dashboard-base.component.ts +++ b/src/frontend/packages/core/src/features/dashboard/dashboard-base/dashboard-base.component.ts @@ -4,7 +4,7 @@ import { MatDrawer } from '@angular/material'; import { ActivatedRoute, ActivatedRouteSnapshot, NavigationEnd, Route, Router } from '@angular/router'; import { Store } from '@ngrx/store'; import { Subscription } from 'rxjs'; -import { debounceTime, filter, withLatestFrom, map, startWith } from 'rxjs/operators'; +import { debounceTime, filter, startWith, withLatestFrom } from 'rxjs/operators'; import { GetCFInfo } from '../../../../../store/src/actions/cloud-foundry.actions'; import { ChangeSideNavMode, CloseSideNav, OpenSideNav } from '../../../../../store/src/actions/dashboard-actions'; @@ -148,7 +148,7 @@ export class DashboardBaseComponent implements OnInit, OnDestroy, AfterContentIn } return routes.reduce((nav, route) => { if (route.data && route.data.stratosNavigation) { - const item = { + const item: SideNavItem = { ...route.data.stratosNavigation, link: path + '/' + route.path }; diff --git a/src/frontend/packages/core/src/features/dashboard/side-nav/side-nav.component.ts b/src/frontend/packages/core/src/features/dashboard/side-nav/side-nav.component.ts index e47bca0ca6..5adba83618 100644 --- a/src/frontend/packages/core/src/features/dashboard/side-nav/side-nav.component.ts +++ b/src/frontend/packages/core/src/features/dashboard/side-nav/side-nav.component.ts @@ -1,11 +1,12 @@ - -import { filter, map, buffer, debounceTime } from 'rxjs/operators'; import { Component, Inject, InjectionToken, Input, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { BehaviorSubject, Observable } from 'rxjs'; -import { Customizations, CustomizationsMetadata } from '../../../core/customizations.types'; -import { AppState } from '../../../../../store/src/app-state'; +import { buffer, debounceTime, filter, map } from 'rxjs/operators'; + import { ActionHistoryDump } from '../../../../../store/src/actions/action-history.actions'; +import { AppState } from '../../../../../store/src/app-state'; +import { Customizations, CustomizationsMetadata } from '../../../core/customizations.types'; + export const SIDENAV_COPYRIGHT = new InjectionToken('Optional copyright string for side nav'); @@ -15,6 +16,8 @@ export interface SideNavItem { matIconFont?: string; link: string; hidden?: Observable; + requiresEndpointType?: string; + requiresPersistence?: boolean; } @Component({ diff --git a/src/frontend/packages/core/src/features/endpoints/endpoints-page/endpoints-page.component.spec.ts b/src/frontend/packages/core/src/features/endpoints/endpoints-page/endpoints-page.component.spec.ts index 4a12dddfad..bd7e13f019 100644 --- a/src/frontend/packages/core/src/features/endpoints/endpoints-page/endpoints-page.component.spec.ts +++ b/src/frontend/packages/core/src/features/endpoints/endpoints-page/endpoints-page.component.spec.ts @@ -2,11 +2,10 @@ import { CommonModule } from '@angular/common'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterTestingModule } from '@angular/router/testing'; -import { StoreModule } from '@ngrx/store'; +import { createBasicStoreModule } from '../../../../test-framework/store-test-helper'; import { CoreModule } from '../../../core/core.module'; import { SharedModule } from '../../../shared/shared.module'; -import { appReducers } from '../../../../../store/src/reducers.module'; import { EndpointsPageComponent } from './endpoints-page.component'; describe('EndpointsPageComponent', () => { @@ -17,14 +16,12 @@ describe('EndpointsPageComponent', () => { TestBed.configureTestingModule({ declarations: [EndpointsPageComponent], imports: [ + createBasicStoreModule(), CommonModule, CoreModule, SharedModule, RouterTestingModule, - BrowserAnimationsModule, - StoreModule.forRoot( - appReducers - ) + BrowserAnimationsModule ] }) .compileComponents(); diff --git a/src/frontend/packages/core/src/features/home/home/home-page.component.spec.ts b/src/frontend/packages/core/src/features/home/home/home-page.component.spec.ts index 445c306d87..c7731e1a6e 100644 --- a/src/frontend/packages/core/src/features/home/home/home-page.component.spec.ts +++ b/src/frontend/packages/core/src/features/home/home/home-page.component.spec.ts @@ -2,11 +2,10 @@ import { CommonModule } from '@angular/common'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterTestingModule } from '@angular/router/testing'; -import { StoreModule } from '@ngrx/store'; +import { createBasicStoreModule } from '../../../../test-framework/store-test-helper'; import { CoreModule } from '../../../core/core.module'; import { SharedModule } from '../../../shared/shared.module'; -import { appReducers } from '../../../../../store/src/reducers.module'; import { HomePageComponent } from './home-page.component'; describe('HomePageComponent', () => { @@ -22,9 +21,7 @@ describe('HomePageComponent', () => { SharedModule, RouterTestingModule, BrowserAnimationsModule, - StoreModule.forRoot( - appReducers - ) + createBasicStoreModule() ] }) .compileComponents(); diff --git a/src/frontend/packages/core/src/features/login/login-page/login-page.component.spec.ts b/src/frontend/packages/core/src/features/login/login-page/login-page.component.spec.ts index d03f2f0920..3c21c47f5e 100644 --- a/src/frontend/packages/core/src/features/login/login-page/login-page.component.spec.ts +++ b/src/frontend/packages/core/src/features/login/login-page/login-page.component.spec.ts @@ -4,9 +4,9 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouterTestingModule } from '@angular/router/testing'; import { StoreModule } from '@ngrx/store'; +import { appReducers } from '../../../../../store/src/reducers.module'; import { CoreModule } from '../../../core/core.module'; import { SharedModule } from '../../../shared/shared.module'; -import { appReducers } from '../../../../../store/src/reducers.module'; import { LoginPageComponent } from './login-page.component'; describe('LoginPageComponent', () => { From ce90fb40733bafc3728e0a9e8161a5448ac6fd0a Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Thu, 4 Apr 2019 15:07:49 +0100 Subject: [PATCH 6/7] fix e2e test --- .../cloud-foundry/space-level/cf-space-level-page.po.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts b/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts index a7f42defa1..2486e62043 100644 --- a/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts +++ b/src/test-e2e/cloud-foundry/space-level/cf-space-level-page.po.ts @@ -40,7 +40,7 @@ export class CfSpaceLevelPage extends CFPage { } goToUPSITab() { - return this.goToTab('Service Instances', 'user-service-instances'); + return this.goToTab('User Service Instances', 'user-service-instances'); } goToRoutesTab() { From 789c6f9a140448a4aa80eaba2803816104e9a9c4 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Thu, 4 Apr 2019 15:33:13 +0100 Subject: [PATCH 7/7] Fix after merge --- .../cf-spaces-user-service-instances-data-source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts b/src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts index 491d3cb94d..f0bc5bb52b 100644 --- a/src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts +++ b/src/frontend/packages/core/src/shared/components/list/list-types/cf-spaces-service-instances/cf-spaces-user-service-instances-data-source.ts @@ -23,7 +23,7 @@ import { defaultPaginationPageSizeOptionsTable, IListConfig } from '../../list.c export class CfSpacesUserServiceInstancesDataSource extends ListDataSource { constructor(cfGuid: string, spaceGuid: string, store: Store, listConfig?: IListConfig) { const paginationKey = createEntityRelationPaginationKey(spaceSchemaKey, spaceGuid); - const action = new GetAllUserProvidedServices(cfGuid, [ + const action = new GetAllUserProvidedServices(paginationKey, cfGuid, [ createEntityRelationKey(userProvidedServiceInstanceSchemaKey, spaceWithOrgKey), createEntityRelationKey(spaceSchemaKey, organizationSchemaKey), createEntityRelationKey(userProvidedServiceInstanceSchemaKey, serviceBindingSchemaKey),