Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a user provided service instance tab & list to the space page #3443

Merged
merged 12 commits into from
Apr 4, 2019
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -143,6 +146,7 @@ import { UsersRolesComponent } from './users/manage-users/manage-users.component
CloudFoundrySpaceBaseComponent,
CloudFoundrySpaceAppsComponent,
CloudFoundrySpaceServiceInstancesComponent,
CloudFoundrySpaceUserServiceInstancesComponent,
CloudFoundrySpaceRoutesComponent,
CloudFoundrySpaceUsersComponent,
EditSpaceStepComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -297,6 +300,10 @@ const cloudFoundry: Routes = [{
path: 'service-instances',
component: CloudFoundrySpaceServiceInstancesComponent
},
{
path: 'user-service-instances',
component: CloudFoundrySpaceUserServiceInstancesComponent
},
{
path: 'routes',
component: CloudFoundrySpaceRoutesComponent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="spaces-service-instances">
<app-list></app-list>
</div>
Original file line number Diff line number Diff line change
@@ -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<CloudFoundrySpaceUserServiceInstancesComponent>;

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();
});
});
Original file line number Diff line number Diff line change
@@ -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 { }
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const enum CreateServiceFormMode {

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;
Expand Down Expand Up @@ -59,6 +60,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');

Expand Down Expand Up @@ -106,7 +108,9 @@ export class CsiModeService {
}

if (spaceGuid && orgGuid) {
this.cancelUrl = `/cloud-foundry/${cfId}/organizations/${orgGuid}/spaces/${spaceGuid}/service-instances`;
this.cancelUrl =
// tslint:disable-next-line:max-line-length
`/cloud-foundry/${cfId}/organizations/${orgGuid}/spaces/${spaceGuid}/${isUserProvided ? 'user-service-instances' : 'service-instances'}`;
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class CfServiceInstancesListConfigBase implements IListConfig<APIResource
protected serviceInstanceColumns: ITableColumn<APIResource<IServiceInstance>>[] = [
{
columnId: 'name',
headerCell: () => 'Service Instances',
headerCell: () => 'Service Instance',
cellDefinition: {
getValue: (row) => `${row.entity.name}`
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
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<boolean>;
}

@Injectable()
export class CfUserServiceInstancesListConfigBase implements IListConfig<APIResource<IUserProvidedServiceInstance>> {
viewType = ListViewTypes.TABLE_ONLY;
pageSizeOptions = defaultPaginationPageSizeOptionsTable;
dataSource: ListDataSource<APIResource>;
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<APIResource<IUserProvidedServiceInstance>>[] = [
{
columnId: 'name',
headerCell: () => 'Service Instance',
cellDefinition: {
getValue: (row) => `${row.entity.name}`
},
cellFlex: '2'
},
{
columnId: 'space',
headerCell: () => 'Space',
cellComponent: TableCellSpaceNameComponent,
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',
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<APIResource> = {
action: (item: APIResource) => this.deleteServiceInstance(item),
label: 'Delete',
description: 'Delete Service Instance',
createVisible: (row$: Observable<APIResource<IUserProvidedServiceInstance>>) =>
row$.pipe(
switchMap(
row => this.can(this.canDeleteCache, CurrentUserPermissions.SERVICE_INSTANCE_DELETE, row.entity.cfGuid, row.entity.space_guid)
)
)
};

private listActionDetach: IListAction<APIResource> = {
action: (item: APIResource) => this.deleteServiceBinding(item),
label: 'Unbind',
description: 'Unbind Service Instance',
createEnabled: (row$: Observable<APIResource<IUserProvidedServiceInstance>>) =>
row$.pipe(map(row => row.entity.service_bindings.length !== 0)),
createVisible: (row$: Observable<APIResource<IUserProvidedServiceInstance>>) =>
row$.pipe(
switchMap(
row => this.can(this.canDetachCache, CurrentUserPermissions.SERVICE_BINDING_EDIT, row.entity.cfGuid, row.entity.space_guid)
)
)
};

private listActionEdit: IListAction<APIResource> = {
action: (item: APIResource<IUserProvidedServiceInstance>) =>
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<APIResource<IUserProvidedServiceInstance>>) =>
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<boolean> {
let can = cache[spaceGuid];
if (!can) {
can = this.currentUserPermissionsService.can(perm, cfGuid, spaceGuid);
cache[spaceGuid] = can;
}
return can;
}

constructor(
protected store: Store<AppState>,
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<IUserProvidedServiceInstance>) =>
this.serviceActionHelperService.deleteServiceInstance(
serviceInstance.metadata.guid,
serviceInstance.entity.name,
serviceInstance.entity.cfGuid,
true
)


deleteServiceBinding = (serviceInstance: APIResource<IUserProvidedServiceInstance>) => {
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;

}
Loading