From b9d00c3c45085d42e350b602829ea7e1efe21590 Mon Sep 17 00:00:00 2001 From: Kristela <77726350+kristelaK@users.noreply.github.com> Date: Fri, 22 Nov 2024 09:16:41 +0100 Subject: [PATCH 1/2] feature/show_Last_Service_Binding (#2) * Add 'Last Service Binding' column to grid view and list view * Rename the components to remove redundant 'Service' in the naming * replace ServiceInstanceLastOpComponent in the last service binding tests --- package-lock.json | 7 + package.json | 3 +- .../src/shared/cf-shared.module.ts | 196 +++++++++--------- .../cf-service-instances-list-config.base.ts | 7 + ...e-cell-last-service-binding.component.html | 3 + ...e-cell-last-service-binding.component.scss | 0 ...ell-last-service-binding.component.spec.ts | 58 ++++++ ...ble-cell-last-service-binding.component.ts | 21 ++ .../service-instance-card.component.html | 7 + ...stance-last-service-binding.component.html | 20 ++ ...stance-last-service-binding.component.scss | 21 ++ ...nce-last-service-binding.component.spec.ts | 53 +++++ ...instance-last-service-binding.component.ts | 18 ++ src/tsconfig.json | 46 ++-- 14 files changed, 351 insertions(+), 109 deletions(-) create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.html create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.scss create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.spec.ts create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.ts create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.html create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.scss create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.spec.ts create mode 100644 src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.ts diff --git a/package-lock.json b/package-lock.json index 75a8bbb2ab..6aeaa3d7c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,6 +66,7 @@ "@angular/language-service": "^14.2.12", "@cypress/request": "^3.0.0", "@schematics/angular": "^9.1.5", + "@types/hammerjs": "^2.0.46", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "~2.0.8", "@types/js-yaml": "^3.12.5", @@ -4355,6 +4356,12 @@ "@types/send": "*" } }, + "node_modules/@types/hammerjs": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", + "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", + "dev": true + }, "node_modules/@types/http-errors": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", diff --git a/package.json b/package.json index 3671b38bf0..d6b17e3aa4 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,9 @@ "@angular-devkit/schematics": "^14.2.12", "@angular/cli": "^14.2.12", "@angular/language-service": "^14.2.12", + "@cypress/request": "^3.0.0", "@schematics/angular": "^9.1.5", + "@types/hammerjs": "^2.0.46", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "~2.0.8", "@types/js-yaml": "^3.12.5", @@ -169,7 +171,6 @@ "protractor": "^7.0.0", "ps-node": "^0.1.6", "q": "^1.4.1", - "@cypress/request": "^3.0.0", "rxjs-tslint": "^0.1.8", "ts-node": "^8.8.2", "tslint": "~6.1.0", diff --git a/src/frontend/packages/cloud-foundry/src/shared/cf-shared.module.ts b/src/frontend/packages/cloud-foundry/src/shared/cf-shared.module.ts index 9b41ed7894..de38838e8e 100644 --- a/src/frontend/packages/cloud-foundry/src/shared/cf-shared.module.ts +++ b/src/frontend/packages/cloud-foundry/src/shared/cf-shared.module.ts @@ -203,11 +203,14 @@ import { AppNameUniqueDirective } from './directives/app-name-unique.directive/a import { CfUserPermissionDirective } from './directives/cf-user-permission/cf-user-permission.directive'; import { ApplicationStateService } from './services/application-state.service'; import { CloudFoundryUserProvidedServicesService } from './services/cloud-foundry-user-provided-services.service'; +import { TableCellLastServiceBindingComponent } from './components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component'; +import { ServiceInstanceLastServiceBindingComponent } from './components/service-instance-last-service-binding/service-instance-last-service-binding.component'; const cfListTableCells: Type>[] = [ TableCellServiceInstanceAppsAttachedComponent, TableCellServiceComponent, TableCellServiceLastOpComponent, + TableCellLastServiceBindingComponent, TableCellRouteAppsAttachedComponent, CfOrgPermissionCellComponent, CfSpacePermissionCellComponent, @@ -261,102 +264,103 @@ const cfListCards: Type>[] = [ ]; @NgModule({ - imports: [ - CommonModule, - CoreModule, - SharedModule, - ApplicationModule, - MaterialDesignFrameworkModule, - ], - declarations: [ - ServiceIconComponent, - CfEndpointDetailsComponent, - CliCommandComponent, - CliInfoComponent, - CfEndpointsMissingComponent, - CfRoleCheckboxComponent, - CfOrgSpaceLinksComponent, - SelectServiceComponent, - SpecifyDetailsStepComponent, - AddServiceInstanceComponent, - SelectPlanStepComponent, - NoServicePlansComponent, - BindAppsStepComponent, - SpecifyUserProvidedDetailsComponent, - AddServiceInstanceBaseStepComponent, - SchemaFormComponent, - CardAppStatusComponent, - CardAppInstancesComponent, - CardAppUsageComponent, - CardAppUptimeComponent, - CardCfInfoComponent, - CardCfUserInfoComponent, - CardCfOrgUserDetailsComponent, - CardCfSpaceDetailsComponent, - ServiceSummaryCardComponent, - ServiceBrokerCardComponent, - ServiceRecentInstancesCardComponent, - CompactServiceInstanceCardComponent, - RunningInstancesComponent, - ServicePlanPublicComponent, - ServicePlanPriceComponent, - CreateApplicationStep1Component, - EventTabActorIconPipe, - CloudFoundryEventsListComponent, - EventMetadataComponent, - ...cfListTableCells, - ...cfListCards, - ServiceInstanceLastOpComponent, - TableCellFeatureFlagDescriptionComponent, - AppNameUniqueDirective, - ApplicationInstanceChartComponent, - EnvVarViewComponent, - CfUserPermissionDirective - ], - exports: [ - ServiceIconComponent, - CfEndpointDetailsComponent, - CliCommandComponent, - CliInfoComponent, - CfEndpointsMissingComponent, - CfRoleCheckboxComponent, - CfOrgSpaceLinksComponent, - SelectServiceComponent, - SpecifyDetailsStepComponent, - AddServiceInstanceComponent, - SelectPlanStepComponent, - NoServicePlansComponent, - BindAppsStepComponent, - SpecifyUserProvidedDetailsComponent, - AddServiceInstanceBaseStepComponent, - CfServiceCardComponent, - SchemaFormComponent, - CardAppStatusComponent, - CardAppInstancesComponent, - CardAppUsageComponent, - CardAppUptimeComponent, - CardCfInfoComponent, - CardCfUserInfoComponent, - CardCfOrgUserDetailsComponent, - CardCfSpaceDetailsComponent, - ServiceSummaryCardComponent, - ServiceBrokerCardComponent, - ServiceRecentInstancesCardComponent, - CompactServiceInstanceCardComponent, - RunningInstancesComponent, - ServicePlanPublicComponent, - ServicePlanPriceComponent, - CreateApplicationStep1Component, - CloudFoundryEventsListComponent, - AppNameUniqueDirective, - ApplicationInstanceChartComponent, - EnvVarViewComponent, - CfUserPermissionDirective - ], - providers: [ - ApplicationStateService, - CloudFoundryUserProvidedServicesService - ] + imports: [ + CommonModule, + CoreModule, + SharedModule, + ApplicationModule, + MaterialDesignFrameworkModule, + ], + declarations: [ + ServiceIconComponent, + CfEndpointDetailsComponent, + CliCommandComponent, + CliInfoComponent, + CfEndpointsMissingComponent, + CfRoleCheckboxComponent, + CfOrgSpaceLinksComponent, + SelectServiceComponent, + SpecifyDetailsStepComponent, + AddServiceInstanceComponent, + SelectPlanStepComponent, + NoServicePlansComponent, + BindAppsStepComponent, + SpecifyUserProvidedDetailsComponent, + AddServiceInstanceBaseStepComponent, + SchemaFormComponent, + CardAppStatusComponent, + CardAppInstancesComponent, + CardAppUsageComponent, + CardAppUptimeComponent, + CardCfInfoComponent, + CardCfUserInfoComponent, + CardCfOrgUserDetailsComponent, + CardCfSpaceDetailsComponent, + ServiceSummaryCardComponent, + ServiceBrokerCardComponent, + ServiceRecentInstancesCardComponent, + CompactServiceInstanceCardComponent, + RunningInstancesComponent, + ServicePlanPublicComponent, + ServicePlanPriceComponent, + CreateApplicationStep1Component, + EventTabActorIconPipe, + CloudFoundryEventsListComponent, + EventMetadataComponent, + ...cfListTableCells, + ...cfListCards, + ServiceInstanceLastOpComponent, + ServiceInstanceLastServiceBindingComponent, + TableCellFeatureFlagDescriptionComponent, + AppNameUniqueDirective, + ApplicationInstanceChartComponent, + EnvVarViewComponent, + CfUserPermissionDirective + ], + exports: [ + ServiceIconComponent, + CfEndpointDetailsComponent, + CliCommandComponent, + CliInfoComponent, + CfEndpointsMissingComponent, + CfRoleCheckboxComponent, + CfOrgSpaceLinksComponent, + SelectServiceComponent, + SpecifyDetailsStepComponent, + AddServiceInstanceComponent, + SelectPlanStepComponent, + NoServicePlansComponent, + BindAppsStepComponent, + SpecifyUserProvidedDetailsComponent, + AddServiceInstanceBaseStepComponent, + CfServiceCardComponent, + SchemaFormComponent, + CardAppStatusComponent, + CardAppInstancesComponent, + CardAppUsageComponent, + CardAppUptimeComponent, + CardCfInfoComponent, + CardCfUserInfoComponent, + CardCfOrgUserDetailsComponent, + CardCfSpaceDetailsComponent, + ServiceSummaryCardComponent, + ServiceBrokerCardComponent, + ServiceRecentInstancesCardComponent, + CompactServiceInstanceCardComponent, + RunningInstancesComponent, + ServicePlanPublicComponent, + ServicePlanPriceComponent, + CreateApplicationStep1Component, + CloudFoundryEventsListComponent, + AppNameUniqueDirective, + ApplicationInstanceChartComponent, + EnvVarViewComponent, + CfUserPermissionDirective + ], + providers: [ + ApplicationStateService, + CloudFoundryUserProvidedServicesService + ] }) export class CloudFoundrySharedModule { } diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts index 4dcfd049b1..693716c53c 100644 --- a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts +++ b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-services/cf-service-instances-list-config.base.ts @@ -39,6 +39,7 @@ import { TableCellServiceLastOpComponent, } from '../cf-spaces-service-instances/table-cell-service-last-op/table-cell-service-last-op.component'; import { TableCellServiceComponent } from '../cf-spaces-service-instances/table-cell-service/table-cell-service.component'; +import { TableCellLastServiceBindingComponent } from '../cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component'; interface CanCache { [spaceGuid: string]: Observable; @@ -86,6 +87,12 @@ export class CfServiceInstancesListConfigBase implements IListConfig 'Last Service Binding', + cellComponent: TableCellLastServiceBindingComponent, + cellFlex: '2' + }, { columnId: 'dashboard', headerCell: () => 'Dashboard', diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.html b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.html new file mode 100644 index 0000000000..62d0f0b318 --- /dev/null +++ b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.html @@ -0,0 +1,3 @@ + +- \ No newline at end of file diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.scss b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.spec.ts b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.spec.ts new file mode 100644 index 0000000000..5351e685e5 --- /dev/null +++ b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.spec.ts @@ -0,0 +1,58 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { + BooleanIndicatorComponent, +} from '../../../../../../../../core/src/shared/components/boolean-indicator/boolean-indicator.component'; +import { BaseTestModulesNoShared } from '../../../../../../../../core/test-framework/core-test.helper'; +import { EntityMonitorFactory } from '../../../../../../../../store/src/monitors/entity-monitor.factory.service'; +import { ServiceInstanceLastServiceBindingComponent } from '../../../../service-instance-last-service-binding/service-instance-last-service-binding.component'; +import { TableCellLastServiceBindingComponent } from './table-cell-last-service-binding.component'; + +describe('TableCellLastServiceBindingComponent', () => { + let component: TableCellLastServiceBindingComponent + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ + TableCellLastServiceBindingComponent, + ServiceInstanceLastServiceBindingComponent, + BooleanIndicatorComponent + ], + imports: [...BaseTestModulesNoShared], + providers: [EntityMonitorFactory] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TableCellLastServiceBindingComponent); + component = fixture.componentInstance; + component.row = { + entity: { + service_plan_guid: '', + space_guid: '', + dashboard_url: '', + type: '', + service_guid: '', + service_plan_url: '', + service_bindings_url: '', + service_keys_url: '', + routes_url: '', + service_url: '', + }, + metadata: { + created_at: '', + guid: '', + updated_at: '', + url: '' + } + }; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); + diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.ts b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.ts new file mode 100644 index 0000000000..ac349f6b6f --- /dev/null +++ b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/cf-spaces-service-instances/table-cell-last-service-binding/table-cell-last-service-binding.component.ts @@ -0,0 +1,21 @@ +import { Component, Input, OnInit } from '@angular/core'; + +import { TableCellCustom } from '../../../../../../../../core/src/shared/components/list/list.types'; +import { APIResource } from '../../../../../../../../store/src/types/api.types'; +import { IServiceInstance } from '../../../../../../cf-api-svc.types'; +import { userProvidedServiceInstanceEntityType } from '../../../../../../cf-entity-types'; + +@Component({ + selector: 'app-table-cell-last-service-binding', + templateUrl: './table-cell-last-service-binding.component.html', + styleUrls: ['./table-cell-last-service-binding.component.scss'] +}) +export class TableCellLastServiceBindingComponent extends TableCellCustom> implements OnInit { + // tslint:disable-next-line:ban-types + isUserProvidedServiceInstance: Boolean; + + + ngOnInit() { + this.isUserProvidedServiceInstance = this.entityKey === userProvidedServiceInstanceEntityType; + } +} diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/services-wall/service-instance-card/service-instance-card.component.html b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/services-wall/service-instance-card/service-instance-card.component.html index 65a4475306..29e68c9116 100644 --- a/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/services-wall/service-instance-card/service-instance-card.component.html +++ b/src/frontend/packages/cloud-foundry/src/shared/components/list/list-types/services-wall/service-instance-card/service-instance-card.component.html @@ -45,6 +45,13 @@ + + Last Service Binding + + + + + Dashboard diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.html b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.html new file mode 100644 index 0000000000..1040319ed7 --- /dev/null +++ b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.html @@ -0,0 +1,20 @@ +
+
+
+
+ {{sb_lo.type | titlecase }} + + + + + +
+
{{ sb_lo.created_at | date:'medium' }}
+
+
+
+ +- + diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.scss b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.scss new file mode 100644 index 0000000000..e0259827b5 --- /dev/null +++ b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.scss @@ -0,0 +1,21 @@ +.last-service-op { + &--row1 { + align-items: center; + display: flex; + justify-content: flex-start; + padding-bottom: 5px; + } + &--item { + padding-right: 5px; + } +} + +.align-right { + .last-service-op--row1 { + justify-content: flex-end; + } + .last-service-op--item { + padding-left: 5px; + padding-right: 0; + } +} diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.spec.ts b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.spec.ts new file mode 100644 index 0000000000..1d404ed19b --- /dev/null +++ b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.spec.ts @@ -0,0 +1,53 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { + BooleanIndicatorComponent, +} from '../../../../../core/src/shared/components/boolean-indicator/boolean-indicator.component'; +import { BaseTestModulesNoShared } from '../../../../../core/test-framework/core-test.helper'; +import { ServiceInstanceLastServiceBindingComponent } from './service-instance-last-service-binding.component'; + +describe('ServiceInstanceLastServiceBindingComponent', () => { + let component: ServiceInstanceLastServiceBindingComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ + ServiceInstanceLastServiceBindingComponent, + BooleanIndicatorComponent, + ], + imports: [...BaseTestModulesNoShared] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ServiceInstanceLastServiceBindingComponent); + component = fixture.componentInstance; + component.serviceInstance = { + entity: { + service_plan_guid: '', + space_guid: '', + dashboard_url: '', + type: '', + service_guid: '', + service_plan_url: '', + service_bindings_url: '', + service_keys_url: '', + routes_url: '', + service_url: '', + }, + metadata: { + created_at: '', + guid: '', + updated_at: '', + url: '' + } + }; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.ts b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.ts new file mode 100644 index 0000000000..d464163f6f --- /dev/null +++ b/src/frontend/packages/cloud-foundry/src/shared/components/service-instance-last-service-binding/service-instance-last-service-binding.component.ts @@ -0,0 +1,18 @@ +import { Component, Input, OnInit } from '@angular/core'; + +import { APIResource } from '../../../../../store/src/types/api.types'; +import { IServiceInstance } from '../../../cf-api-svc.types'; + +@Component({ + selector: 'app-service-instance-last-service-binding', + templateUrl: './service-instance-last-service-binding.component.html', + styleUrls: ['./service-instance-last-service-binding.component.scss'] +}) +export class ServiceInstanceLastServiceBindingComponent implements OnInit { + @Input() serviceInstance: APIResource; + @Input() alignRight = false; + + ngOnInit() { + console.log(this.serviceInstance) + } +} diff --git a/src/tsconfig.json b/src/tsconfig.json index f91f9f8608..c5d82adb90 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -32,17 +32,39 @@ ], "preserveSymlinks": true, "paths": { - "@stratosui/core": ["frontend/packages/core/src/public-api.ts"], - "@stratosui/extension": ["frontend/packages/extension/src/public-api.ts"], - "@stratosui/store": ["frontend/packages/store/src/public-api.ts"], - "@stratosui/shared": ["frontend/packages/shared/src/public-api.ts"], - "@stratosui/store/testing": ["frontend/packages/store/testing/public-api.ts"], - "@stratosui/cloud-foundry": ["frontend/packages/cloud-foundry/src/public_api.ts"], - "@stratosui/cf-autoscaler": ["frontend/packages/cf-autoscaler/src/public_api.ts"], - "@example/extensions": ["frontend/packages/example-extensions/src/public-api.ts"], - "@stratosui/kubernetes": ["frontend/packages/kubernetes/src/public-api.ts"], - "@stratosui/desktop-extensions": ["frontend/packages/desktop-extensions/src/public-api.ts"], - "@stratosui/git": ["frontend/packages/git/src/public_api.ts"] + "@stratosui/core": [ + "frontend/packages/core/src/public-api.ts" + ], + "@stratosui/extension": [ + "frontend/packages/extension/src/public-api.ts" + ], + "@stratosui/store": [ + "frontend/packages/store/src/public-api.ts" + ], + "@stratosui/shared": [ + "frontend/packages/shared/src/public-api.ts" + ], + "@stratosui/store/testing": [ + "frontend/packages/store/testing/public-api.ts" + ], + "@stratosui/cloud-foundry": [ + "frontend/packages/cloud-foundry/src/public_api.ts" + ], + "@stratosui/cf-autoscaler": [ + "frontend/packages/cf-autoscaler/src/public_api.ts" + ], + "@example/extensions": [ + "frontend/packages/example-extensions/src/public-api.ts" + ], + "@stratosui/kubernetes": [ + "frontend/packages/kubernetes/src/public-api.ts" + ], + "@stratosui/desktop-extensions": [ + "frontend/packages/desktop-extensions/src/public-api.ts" + ], + "@stratosui/git": [ + "frontend/packages/git/src/public_api.ts" + ] } } -} +} \ No newline at end of file From 979899242a17f7b79d2b637c1bea5a1cd600c95a Mon Sep 17 00:00:00 2001 From: Tim Meier <115975772+tmeier-a9s@users.noreply.github.com> Date: Fri, 14 Feb 2025 10:49:47 +0100 Subject: [PATCH 2/2] Disable service binding per wizard by default (#3) Disallow service bind only on service wall mode --- .../add-service-instance.component.spec.ts | 332 ++++++++++-------- .../add-service-instance.component.ts | 10 +- .../add-service-instance/csi-mode.service.ts | 9 +- 3 files changed, 210 insertions(+), 141 deletions(-) diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.spec.ts b/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.spec.ts index 2c3d53fa61..d099af6e6c 100644 --- a/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.spec.ts +++ b/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.spec.ts @@ -1,148 +1,176 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { MaterialDesignFrameworkModule } from '@ajsf/material'; +import { MaterialDesignFrameworkModule } from "@ajsf/material"; +import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; -import { - ApplicationStateIconComponent, -} from '../../../../../../core/src/shared/components/application-state/application-state-icon/application-state-icon.component'; -import { - ApplicationStateIconPipe, -} from '../../../../../../core/src/shared/components/application-state/application-state-icon/application-state-icon.pipe'; -import { - BooleanIndicatorComponent, -} from '../../../../../../core/src/shared/components/boolean-indicator/boolean-indicator.component'; -import { CardStatusComponent } from '../../../../../../core/src/shared/components/cards/card-status/card-status.component'; -import { AppChipsComponent } from '../../../../../../core/src/shared/components/chips/chips.component'; -import { - CopyToClipboardComponent, -} from '../../../../../../core/src/shared/components/copy-to-clipboard/copy-to-clipboard.component'; -import { FocusDirective } from '../../../../../../core/src/shared/components/focus.directive'; -import { - MetaCardComponent, -} from '../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-base/meta-card.component'; -import { - MetaCardItemComponent, -} from '../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-item/meta-card-item.component'; -import { - MetaCardKeyComponent, -} from '../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-key/meta-card-key.component'; -import { - MetaCardTitleComponent, -} from '../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-title/meta-card-title.component'; -import { - MetaCardValueComponent, -} from '../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-value/meta-card-value.component'; -import { MetadataItemComponent } from '../../../../../../core/src/shared/components/metadata-item/metadata-item.component'; -import { - MultilineTitleComponent, -} from '../../../../../../core/src/shared/components/multiline-title/multiline-title.component'; -import { PageHeaderModule } from '../../../../../../core/src/shared/components/page-header/page-header.module'; -import { SteppersModule } from '../../../../../../core/src/shared/components/stepper/steppers.module'; -import { TabNavService } from '../../../../../../core/src/tab-nav.service'; -import { EntityMonitorFactory } from '../../../../../../store/src/monitors/entity-monitor.factory.service'; -import { InternalEventMonitorFactory } from '../../../../../../store/src/monitors/internal-event-monitor.factory'; -import { PaginationMonitorFactory } from '../../../../../../store/src/monitors/pagination-monitor.factory'; -import { generateCfBaseTestModulesNoShared } from '../../../../../test-framework/cloud-foundry-endpoint-service.helper'; -import { ServicesService } from '../../../../features/service-catalog/services.service'; -import { ServicesServiceMock } from '../../../../features/service-catalog/services.service.mock'; -import { CfOrgSpaceDataService } from '../../../data-services/cf-org-space-service.service'; -import { CloudFoundryService } from '../../../data-services/cloud-foundry.service'; -import { LongRunningCfOperationsService } from '../../../data-services/long-running-cf-op.service'; -import { AppNameUniqueDirective } from '../../../directives/app-name-unique.directive/app-name-unique.directive'; -import { CfOrgSpaceLinksComponent } from '../../cf-org-space-links/cf-org-space-links.component'; -import { - CreateApplicationStep1Component, -} from '../../create-application/create-application-step1/create-application-step1.component'; -import { CfServiceCardComponent } from '../../list/list-types/cf-services/cf-service-card/cf-service-card.component'; -import { - TableCellServiceActiveComponent, -} from '../../list/list-types/cf-services/table-cell-service-active/table-cell-service-active.component'; -import { - TableCellServiceBindableComponent, -} from '../../list/list-types/cf-services/table-cell-service-bindable/table-cell-service-bindable.component'; -import { - TableCellServiceCfBreadcrumbsComponent, -} from '../../list/list-types/cf-services/table-cell-service-cf-breadcrumbs/table-cell-service-cf-breadcrumbs.component'; -import { - TableCellServiceReferencesComponent, -} from '../../list/list-types/cf-services/table-cell-service-references/table-cell-service-references.component'; -import { - TableCellServiceTagsComponent, -} from '../../list/list-types/cf-services/table-cell-service-tags/table-cell-service-tags.component'; -import { SchemaFormComponent } from '../../schema-form/schema-form.component'; -import { SelectServiceComponent } from '../../select-service/select-service.component'; -import { ServiceIconComponent } from '../../service-icon/service-icon.component'; -import { ServicePlanPriceComponent } from '../../service-plan-price/service-plan-price.component'; -import { ServicePlanPublicComponent } from '../../service-plan-public/service-plan-public.component'; -import { BindAppsStepComponent } from '../bind-apps-step/bind-apps-step.component'; -import { SelectPlanStepComponent } from '../select-plan-step/select-plan-step.component'; -import { SpecifyDetailsStepComponent } from '../specify-details-step/specify-details-step.component'; -import { - SpecifyUserProvidedDetailsComponent, -} from '../specify-user-provided-details/specify-user-provided-details.component'; -import { AddServiceInstanceComponent } from './add-service-instance.component'; +import { By } from "@angular/platform-browser"; +import { ActivatedRoute } from "@angular/router"; +import { provideMockStore } from "@ngrx/store/testing"; +import { EntityCatalogEntityConfig } from "frontend/packages/store/src/entity-catalog/entity-catalog.types"; +import { getDefaultRequestState } from "frontend/packages/store/src/reducers/api-request-reducer/types"; +import { + createEntityStoreState, + TestStoreEntity +} from "frontend/packages/store/testing/src/store-test-helper"; +import { Observable } from "rxjs"; +import { ApplicationStateIconComponent } from "../../../../../../core/src/shared/components/application-state/application-state-icon/application-state-icon.component"; +import { ApplicationStateIconPipe } from "../../../../../../core/src/shared/components/application-state/application-state-icon/application-state-icon.pipe"; +import { BooleanIndicatorComponent } from "../../../../../../core/src/shared/components/boolean-indicator/boolean-indicator.component"; +import { CardStatusComponent } from "../../../../../../core/src/shared/components/cards/card-status/card-status.component"; +import { AppChipsComponent } from "../../../../../../core/src/shared/components/chips/chips.component"; +import { CopyToClipboardComponent } from "../../../../../../core/src/shared/components/copy-to-clipboard/copy-to-clipboard.component"; +import { FocusDirective } from "../../../../../../core/src/shared/components/focus.directive"; +import { MetaCardComponent } from "../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-base/meta-card.component"; +import { MetaCardItemComponent } from "../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-item/meta-card-item.component"; +import { MetaCardKeyComponent } from "../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-key/meta-card-key.component"; +import { MetaCardTitleComponent } from "../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-title/meta-card-title.component"; +import { MetaCardValueComponent } from "../../../../../../core/src/shared/components/list/list-cards/meta-card/meta-card-value/meta-card-value.component"; +import { MetadataItemComponent } from "../../../../../../core/src/shared/components/metadata-item/metadata-item.component"; +import { MultilineTitleComponent } from "../../../../../../core/src/shared/components/multiline-title/multiline-title.component"; +import { PageHeaderModule } from "../../../../../../core/src/shared/components/page-header/page-header.module"; +import { SteppersModule } from "../../../../../../core/src/shared/components/stepper/steppers.module"; +import { TabNavService } from "../../../../../../core/src/tab-nav.service"; +import { EntityMonitorFactory } from "../../../../../../store/src/monitors/entity-monitor.factory.service"; +import { InternalEventMonitorFactory } from "../../../../../../store/src/monitors/internal-event-monitor.factory"; +import { PaginationMonitorFactory } from "../../../../../../store/src/monitors/pagination-monitor.factory"; +import { generateCfBaseTestModulesNoShared } from "../../../../../test-framework/cloud-foundry-endpoint-service.helper"; +import { ServicesService } from "../../../../features/service-catalog/services.service"; +import { ServicesServiceMock } from "../../../../features/service-catalog/services.service.mock"; +import { CfOrgSpaceDataService } from "../../../data-services/cf-org-space-service.service"; +import { CloudFoundryService } from "../../../data-services/cloud-foundry.service"; +import { LongRunningCfOperationsService } from "../../../data-services/long-running-cf-op.service"; +import { AppNameUniqueDirective } from "../../../directives/app-name-unique.directive/app-name-unique.directive"; +import { CfOrgSpaceLinksComponent } from "../../cf-org-space-links/cf-org-space-links.component"; +import { CreateApplicationStep1Component } from "../../create-application/create-application-step1/create-application-step1.component"; +import { CfServiceCardComponent } from "../../list/list-types/cf-services/cf-service-card/cf-service-card.component"; +import { TableCellServiceActiveComponent } from "../../list/list-types/cf-services/table-cell-service-active/table-cell-service-active.component"; +import { TableCellServiceBindableComponent } from "../../list/list-types/cf-services/table-cell-service-bindable/table-cell-service-bindable.component"; +import { TableCellServiceCfBreadcrumbsComponent } from "../../list/list-types/cf-services/table-cell-service-cf-breadcrumbs/table-cell-service-cf-breadcrumbs.component"; +import { TableCellServiceReferencesComponent } from "../../list/list-types/cf-services/table-cell-service-references/table-cell-service-references.component"; +import { TableCellServiceTagsComponent } from "../../list/list-types/cf-services/table-cell-service-tags/table-cell-service-tags.component"; +import { SchemaFormComponent } from "../../schema-form/schema-form.component"; +import { SelectServiceComponent } from "../../select-service/select-service.component"; +import { ServiceIconComponent } from "../../service-icon/service-icon.component"; +import { ServicePlanPriceComponent } from "../../service-plan-price/service-plan-price.component"; +import { ServicePlanPublicComponent } from "../../service-plan-public/service-plan-public.component"; +import { BindAppsStepComponent } from "../bind-apps-step/bind-apps-step.component"; +import { SelectPlanStepComponent } from "../select-plan-step/select-plan-step.component"; +import { SpecifyDetailsStepComponent } from "../specify-details-step/specify-details-step.component"; +import { SpecifyUserProvidedDetailsComponent } from "../specify-user-provided-details/specify-user-provided-details.component"; +import { AddServiceInstanceComponent } from "./add-service-instance.component"; -describe('AddServiceInstanceComponent', () => { +describe("AddServiceInstanceComponent", () => { let component: AddServiceInstanceComponent; let fixture: ComponentFixture; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - AppNameUniqueDirective, - AddServiceInstanceComponent, - CopyToClipboardComponent, - SelectPlanStepComponent, - SpecifyDetailsStepComponent, - BindAppsStepComponent, - SelectServiceComponent, - CreateApplicationStep1Component, - CardStatusComponent, - MetadataItemComponent, - CfServiceCardComponent, - CfOrgSpaceLinksComponent, - MetaCardComponent, - ServiceIconComponent, - MetaCardTitleComponent, - MetaCardKeyComponent, - MetaCardItemComponent, - MetaCardComponent, - MetaCardValueComponent, - BooleanIndicatorComponent, - AppChipsComponent, - ApplicationStateIconComponent, - ApplicationStateIconPipe, - SchemaFormComponent, - MultilineTitleComponent, - ServicePlanPublicComponent, - ServicePlanPriceComponent, - FocusDirective, - SpecifyUserProvidedDetailsComponent, - TableCellServiceActiveComponent, - TableCellServiceBindableComponent, - TableCellServiceReferencesComponent, - TableCellServiceCfBreadcrumbsComponent, - TableCellServiceTagsComponent - ], - imports: [ - ...generateCfBaseTestModulesNoShared(), - PageHeaderModule, - SteppersModule, - MaterialDesignFrameworkModule, - ], - providers: [ - { provide: ServicesService, useClass: ServicesServiceMock }, - EntityMonitorFactory, - PaginationMonitorFactory, - CfOrgSpaceDataService, - InternalEventMonitorFactory, - CloudFoundryService, - TabNavService, - LongRunningCfOperationsService - ], + class EntityMonitorFactoryMock { + entity = { + entity: { + name: "test-app-entity", + space_guid: "populatePaginationFromParent-space", + space: { + entity: { + organization_guid: "populatePaginationFromParent-org" + }, + metadata: {} + } + }, + metadata: {} + }; + entityRequestInfo = getDefaultRequestState(); + + monitor = { + entity$: new Observable(subscriber => { + subscriber.next(this.entity); + subscriber.complete(); + }), + entityRequest$: new Observable(subscriber => { + subscriber.next(this.entityRequestInfo); + subscriber.complete(); + }) + }; + + create() { + return this.monitor; + } + } + + beforeEach( + waitForAsync(() => { + const entityMap = new Map< + EntityCatalogEntityConfig, + Array + >([]); + const store = { + createApplication: {}, + createServiceInstance: { + cfGuid: "populatePaginationFromParent-cf", + orgGuid: "populatePaginationFromParent-org", + spaceGuid: "populatePaginationFromParent-space", + name: "", + servicePlanGuid: "", + spaceScoped: false + } + }; + + TestBed.configureTestingModule({ + declarations: [ + AppNameUniqueDirective, + AddServiceInstanceComponent, + CopyToClipboardComponent, + SelectPlanStepComponent, + SpecifyDetailsStepComponent, + BindAppsStepComponent, + SelectServiceComponent, + CreateApplicationStep1Component, + CardStatusComponent, + MetadataItemComponent, + CfServiceCardComponent, + CfOrgSpaceLinksComponent, + MetaCardComponent, + ServiceIconComponent, + MetaCardTitleComponent, + MetaCardKeyComponent, + MetaCardItemComponent, + MetaCardComponent, + MetaCardValueComponent, + BooleanIndicatorComponent, + AppChipsComponent, + ApplicationStateIconComponent, + ApplicationStateIconPipe, + SchemaFormComponent, + MultilineTitleComponent, + ServicePlanPublicComponent, + ServicePlanPriceComponent, + FocusDirective, + SpecifyUserProvidedDetailsComponent, + TableCellServiceActiveComponent, + TableCellServiceBindableComponent, + TableCellServiceReferencesComponent, + TableCellServiceCfBreadcrumbsComponent, + TableCellServiceTagsComponent + ], + imports: [ + ...generateCfBaseTestModulesNoShared(), + PageHeaderModule, + SteppersModule, + MaterialDesignFrameworkModule + ], + providers: [ + { provide: ServicesService, useClass: ServicesServiceMock }, + { provide: EntityMonitorFactory, useClass: EntityMonitorFactoryMock }, + PaginationMonitorFactory, + CfOrgSpaceDataService, + InternalEventMonitorFactory, + CloudFoundryService, + TabNavService, + LongRunningCfOperationsService, + provideMockStore({ + initialState: { ...createEntityStoreState(entityMap), ...store } + }) + ] + }); }) - .compileComponents(); - })); + ); beforeEach(() => { fixture = TestBed.createComponent(AddServiceInstanceComponent); @@ -150,7 +178,33 @@ describe('AddServiceInstanceComponent', () => { fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); + + it("should not render bind services in service wall mode", () => { + expect(component.modeService.isServicesWallMode()).toBe(true); + expect( + fixture.debugElement.query(By.css(".steppers__headers")).nativeElement + .textContent + ).not.toContain("Bind App"); + }); + + it("should render bind services when in app services mode", () => { + const route = TestBed.inject(ActivatedRoute); + + route.snapshot.params.id = "xxx"; + route.snapshot.params.endpointId = "yyy"; + + fixture = TestBed.createComponent(AddServiceInstanceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + + expect(component.modeService.isAppServicesMode()).toBe(true); + + expect( + fixture.debugElement.query(By.css(".steppers__headers")).nativeElement + .textContent + ).toContain("Binding Params"); + }); }); diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.ts b/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.ts index 9d5809a14f..4643a96874 100644 --- a/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.ts +++ b/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/add-service-instance/add-service-instance.component.ts @@ -1,5 +1,5 @@ import { TitleCasePipe } from '@angular/common'; -import { AfterContentInit, Component, OnDestroy } from '@angular/core'; +import { AfterContentInit, ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Store } from '@ngrx/store'; import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; @@ -93,6 +93,7 @@ export class AddServiceInstanceComponent implements OnDestroy, AfterContentInit private cfOrgSpaceService: CfOrgSpaceDataService, private csiGuidsService: CsiGuidsService, public modeService: CsiModeService, + private changeDetectorRef: ChangeDetectorRef, route: ActivatedRoute ) { const cfGuid = getIdFromRoute(this.activatedRoute, 'endpointId'); @@ -122,6 +123,9 @@ export class AddServiceInstanceComponent implements OnDestroy, AfterContentInit this.title$ = observableOf(`Create Service Instance`); } + // Fix for title$ change error NG0100: Expression has changed after it was checked + this.changeDetectorRef.detectChanges(); + if (!this.initialisedService$) { this.initialisedService$ = observableOf(true); } @@ -140,6 +144,10 @@ export class AddServiceInstanceComponent implements OnDestroy, AfterContentInit publishReplay(1), refCount(), ); + + // Invoke the observable - required -> otherwise the pipe above won't trigger + this.apps$.subscribe() + this.skipApps$ = this.apps$.pipe( map(apps => apps.length === 0), publishReplay(1), diff --git a/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/csi-mode.service.ts b/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/csi-mode.service.ts index 588d129690..e024269ada 100644 --- a/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/csi-mode.service.ts +++ b/src/frontend/packages/cloud-foundry/src/shared/components/add-service-instance/csi-mode.service.ts @@ -127,7 +127,14 @@ export class CsiModeService { // Started stepper from the root service instance list if (!cfId) { this.mode = CreateServiceInstanceMode.SERVICES_WALL_MODE; - this.viewDetail = defaultViewDetail; + + // disable service binding -> if services are created asyncronously it breaks the user experience + // its assumed being asynchronously by default: + // https://github.com/cloudfoundry-community/stratos/blob/develop/src/frontend/packages/cloud-foundry/src/actions/service-instances.actions.ts#L150 + this.viewDetail = { + ...defaultViewDetail, + showBindApp: false + }; } // Started stepper from a space's service instance list