From f18d24558a2f0d45e17c80016ff2ea37638bf5f2 Mon Sep 17 00:00:00 2001 From: zyjiaobj Date: Sun, 31 Mar 2019 21:44:24 +0800 Subject: [PATCH] [autoscaler] add autoscaler extension tab --- .../autoscaler-tab-extension.component.html | 265 ++++++++++++++++ .../autoscaler-tab-extension.component.scss | 65 ++++ .../autoscaler-tab-extension.component.ts | 283 ++++++++++++++++++ .../frontend/app/custom/custom.module.spec.ts | 13 + .../frontend/app/custom/custom.module.ts | 18 ++ .../src/core/extension/extension-service.ts | 1 + .../application-tabs-base.component.ts | 26 +- .../autoscaler-metric-page.component.ts | 2 +- ...autoscaler-scale-history-page.component.ts | 2 +- .../edit-autoscaler-policy.component.ts | 2 +- .../list/list-cards/cards.component.ts | 2 +- .../src/actions/app-autoscaler.actions.ts | 1 + .../store/src/effects/autoscaler.effects.ts | 7 +- 13 files changed, 671 insertions(+), 16 deletions(-) create mode 100644 custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.html create mode 100644 custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.scss create mode 100644 custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.ts create mode 100644 custom-src/frontend/app/custom/custom.module.spec.ts create mode 100644 custom-src/frontend/app/custom/custom.module.ts diff --git a/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.html b/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.html new file mode 100644 index 0000000000..394a44b742 --- /dev/null +++ b/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.html @@ -0,0 +1,265 @@ + +
+ + + + + + Status + + + + + + + + + + + + + + + Status + + + + + + + + + + + + + + + + Latest Metrics + + + + + + + + + + +
+ + + + + Scaling Rules + + + + + + + + + + + + + + Scheduled Limit Rules + + in {{policy.schedules.timezone}} + + + + + +
+ +
+ + + +
+
+
+
+ + + + + Latest Events + + + + + + + + + + +
+
\ No newline at end of file diff --git a/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.scss b/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.scss new file mode 100644 index 0000000000..c6a01d2eaf --- /dev/null +++ b/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.scss @@ -0,0 +1,65 @@ +.app-auto-scaler { + display: flex; + position: relative; + width: 100%; + &__actions { + bottom: 24px; + padding-top: 0; + position: absolute; + right: 24px; + text-align: right; + } + } + + .app-metadata { + display: flex; + flex-direction: row; + &__two-cols { + flex: 1; + app-metadata-item:first-child { + margin-top: 0; + } + } + &__actions { + bottom: 24px; + padding-top: 0; + position: absolute; + right: 24px; + text-align: right; + } + app-metadata-item { + margin-bottom: 0; + } + } + + app-tile-grid { + width: 100%; + } + + table { + width: 100%; + } + + .app-auto-scaler-policy-left { + flex: 0 0 40%; + } + + .app-auto-scaler-tile { + &-1of2 { + flex: 0 0 50%; + } + &-1of3 { + flex: 0 0 30%; + } + &-1of6 { + flex: 0 0 16.78%; + } + } + + .app-auto-scaler-limit { + display: inherit; + mat-card { + width: 50%; + } + } + \ No newline at end of file diff --git a/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.ts b/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.ts new file mode 100644 index 0000000000..218cb93c7a --- /dev/null +++ b/custom-src/frontend/app/custom/autoscaler-tab-extension/autoscaler-tab-extension.component.ts @@ -0,0 +1,283 @@ +import { StratosTab, StratosTabType } from '../../core/extension/extension-service'; +import { ApplicationService } from '../../features/applications/application.service'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { MatSnackBar, MatSnackBarRef, SimpleSnackBar } from '@angular/material'; +import { Store } from '@ngrx/store'; +import { Observable, Subscription } from 'rxjs'; +import { distinctUntilChanged, filter, first, map, publishReplay, refCount } from 'rxjs/operators'; +import { + DetachAppAutoscalerPolicyAction, + GetAppAutoscalerAppMetricAction, + GetAppAutoscalerPolicyAction, + GetAppAutoscalerHealthAction, + GetAppAutoscalerScalingHistoryAction, + UpdateAppAutoscalerPolicyAction, +} from '../../../../store/src/actions/app-autoscaler.actions'; +import { RouterNav } from '../../../../store/src/actions/router.actions'; +import { AppState } from '../../../../store/src/app-state'; +import { MetricTypes } from '../../../../store/src/helpers/autoscaler/autoscaler-util'; +import { + appAutoscalerHealthSchemaKey, + appAutoscalerAppMetricSchemaKey, + appAutoscalerPolicySchemaKey, + appAutoscalerScalingHistorySchemaKey, + entityFactory, +} from '../../../../store/src/helpers/entity-factory'; +import { ActionState } from '../../../../store/src/reducers/api-request-reducer/types'; +import { + getPaginationObservables, +} from '../../../../store/src/reducers/pagination-reducer/pagination-reducer.helper'; +import { selectUpdateInfo } from '../../../../store/src/selectors/api.selectors'; +import { + AppAutoscalerAppMetric, + AppAutoscalerPolicy, + AppAutoscalerScalingHistory, +} from '../../../../store/src/types/app-autoscaler.types'; +import { EntityService } from '../../core/entity-service'; +import { EntityServiceFactory } from '../../core/entity-service-factory.service'; +import { ConfirmationDialogConfig } from '../../shared/components/confirmation-dialog.config'; +import { ConfirmationDialogService } from '../../shared/components/confirmation-dialog.service'; +import { PaginationMonitorFactory } from '../../shared/monitors/pagination-monitor.factory'; + +@StratosTab({ + type: StratosTabType.Application, + label: 'Autoscale', + link: 'autoscale', + action: new GetAppAutoscalerHealthAction(window.location.pathname.split('/')[3], window.location.pathname.split('/')[2]) +}) +@Component({ + selector: 'app-autoscaler-tab-extension', + templateUrl: './autoscaler-tab-extension.component.html', + styleUrls: ['./autoscaler-tab-extension.component.scss'], +}) +export class AutoscalerTabExtensionComponent implements OnInit, OnDestroy { + + scalingRuleColumns: string[] = ['metric', 'condition', 'action']; + specificDateColumns: string[] = ['from', 'to', 'init', 'min', 'max']; + recurringScheduleColumns: string[] = ['effect', 'repeat', 'from', 'to', 'init', 'min', 'max']; + scalingHistoryColumns: string[] = ['event', 'trigger', 'date', 'error']; + metricTypes: string[] = MetricTypes; + + appAutoscalerHealthService: EntityService; + appAutoscalerPolicyService: EntityService; + appAutoscalerScalingHistoryService: EntityService; + appAutoscalerEnablement$: Observable; + appAutoscalerPolicy$: Observable; + appAutoscalerScalingHistory$: Observable; + + private appAutoscalerPolicyErrorSub: Subscription; + private appAutoscalerScalingHistoryErrorSub: Subscription; + private appAutoscalerPolicySnackBarRef: MatSnackBarRef; + private appAutoscalerScalingHistorySnackBarRef: MatSnackBarRef; + + private detachConfirmOk = 0; + + appAutoscalerAppMetrics = {}; + appAutoscalerInsMetrics = {}; + appAutoscalerAppMetricNames = []; + + paramsMetrics = { + 'start-time': 0, + 'end-time': (new Date()).getTime().toString() + '000000', + page: '1', + 'results-per-page': '1', + order: 'desc' + }; + paramsHistory = { + 'start-time': 0, + 'end-time': (new Date()).getTime().toString() + '000000', + page: '1', + 'results-per-page': '5', + order: 'desc' + }; + + ngOnDestroy(): void { + if (this.appAutoscalerPolicySnackBarRef) { + this.appAutoscalerPolicySnackBarRef.dismiss(); + } + if (this.appAutoscalerScalingHistorySnackBarRef) { + this.appAutoscalerScalingHistorySnackBarRef.dismiss(); + } + if (this.appAutoscalerPolicyErrorSub) { + this.appAutoscalerPolicyErrorSub.unsubscribe(); + } + if (this.appAutoscalerScalingHistoryErrorSub) { + this.appAutoscalerScalingHistoryErrorSub.unsubscribe(); + } + } + + constructor( + private store: Store, + private applicationService: ApplicationService, + private entityServiceFactory: EntityServiceFactory, + private paginationMonitorFactory: PaginationMonitorFactory, + private appAutoscalerPolicySnackBar: MatSnackBar, + private appAutoscalerScalingHistorySnackBar: MatSnackBar, + private confirmDialog: ConfirmationDialogService, + ) { } + + ngOnInit() { + // this.appAutoscalerHealthService = this.entityServiceFactory.create( + // appAutoscalerHealthSchemaKey, + // entityFactory(appAutoscalerHealthSchemaKey), + // this.applicationService.appGuid, + // new GetAppAutoscalerHealthAction(this.applicationService.appGuid, this.applicationService.cfGuid), + // false + // ); + // this.appAutoscalerEnablement$ = this.appAutoscalerHealthService.entityObs$.pipe( + // map(({ entity }) => { + // if (entity && entity.entity && entity.entity.uptime > 0) { + // console.log(true) + // return true; + // } else { + // console.log(false) + // return false; + // } + // }), + // publishReplay(1), + // refCount() + // ); + this.appAutoscalerPolicyService = this.entityServiceFactory.create( + appAutoscalerPolicySchemaKey, + entityFactory(appAutoscalerPolicySchemaKey), + this.applicationService.appGuid, + new GetAppAutoscalerPolicyAction(this.applicationService.appGuid, this.applicationService.cfGuid), + false + ); + this.appAutoscalerPolicy$ = this.appAutoscalerPolicyService.entityObs$.pipe( + map(({ entity }) => { + if (entity && entity.entity) { + this.appAutoscalerAppMetricNames = Object.keys(entity.entity.scaling_rules_map); + this.loadLatestMetricsUponPolicy(entity.entity); + } + return entity && entity.entity; + }), + publishReplay(1), + refCount() + ); + this.appAutoscalerScalingHistoryService = this.entityServiceFactory.create( + appAutoscalerScalingHistorySchemaKey, + entityFactory(appAutoscalerScalingHistorySchemaKey), + this.applicationService.appGuid, + new GetAppAutoscalerScalingHistoryAction('', this.applicationService.appGuid, + this.applicationService.cfGuid, true, this.paramsHistory), + false + ); + this.appAutoscalerScalingHistory$ = this.appAutoscalerScalingHistoryService.entityObs$.pipe( + map(({ entity }) => entity && entity.entity) + ); + this.initErrorSub(); + } + + getAppMetric(metricName: string, trigger: any, params: any) { + const action = new GetAppAutoscalerAppMetricAction(this.applicationService.appGuid, + this.applicationService.cfGuid, metricName, true, trigger, params); + return getPaginationObservables({ + store: this.store, + action, + paginationMonitor: this.paginationMonitorFactory.create( + action.paginationKey, + entityFactory(appAutoscalerAppMetricSchemaKey) + ) + }, false).entities$; + } + + loadLatestMetricsUponPolicy(policyEntity) { + if (policyEntity.scaling_rules_map) { + this.appAutoscalerAppMetrics = {}; + Object.keys(policyEntity.scaling_rules_map).map((metricName) => { + this.appAutoscalerAppMetrics[metricName] = + this.getAppMetric(metricName, policyEntity.scaling_rules_map[metricName], this.paramsMetrics); + }); + } + } + + initErrorSub() { + this.appAutoscalerPolicyErrorSub = this.appAutoscalerPolicyService.entityMonitor.entityRequest$.pipe( + filter(request => !!request.error), + map(request => request.message), + distinctUntilChanged(), + ).subscribe(errorMessage => { + if (this.appAutoscalerPolicySnackBarRef) { + this.appAutoscalerPolicySnackBarRef.dismiss(); + } + this.appAutoscalerPolicySnackBarRef = this.appAutoscalerPolicySnackBar.open(errorMessage, 'Dismiss'); + }); + + this.appAutoscalerScalingHistoryErrorSub = this.appAutoscalerScalingHistoryService.entityMonitor.entityRequest$.pipe( + filter(request => !!request.error), + map(request => request.message), + distinctUntilChanged(), + ).subscribe(errorMessage => { + if (this.appAutoscalerScalingHistorySnackBarRef) { + this.appAutoscalerScalingHistorySnackBarRef.dismiss(); + } + this.appAutoscalerScalingHistorySnackBarRef = this.appAutoscalerScalingHistorySnackBar.open(errorMessage, 'Dismiss'); + }); + } + + diableAutoscaler() { + const confirmation = new ConfirmationDialogConfig( + 'Detach And Delete Policy', + 'Are you sure you want to detach and delete the policy?', + 'Detach and Delete', + true + ); + this.detachConfirmOk = this.detachConfirmOk === 1 ? 0 : 1; + this.confirmDialog.open(confirmation, () => { + this.detachConfirmOk = 2; + const doUpdate = () => this.detachPolicy(); + doUpdate().pipe( + first(), + ).subscribe(actionState => { + if (actionState.error) { + this.appAutoscalerPolicySnackBarRef = + this.appAutoscalerPolicySnackBar.open(`Failed to detach policy: ${actionState.message}`, 'Dismiss'); + } + }); + }); + } + + detachPolicy(): Observable { + this.store.dispatch( + new DetachAppAutoscalerPolicyAction(this.applicationService.appGuid, this.applicationService.cfGuid) + ); + const actionState = selectUpdateInfo(appAutoscalerPolicySchemaKey, + this.applicationService.appGuid, + UpdateAppAutoscalerPolicyAction.updateKey); + return this.store.select(actionState).pipe(filter(item => !!item)); + } + + updatePolicyPage = () => { + this.store.dispatch(new RouterNav({ + path: [ + 'applications', + this.applicationService.cfGuid, + this.applicationService.appGuid, + 'edit-autoscaler-policy' + ] + })); + } + + metricChartPage() { + this.store.dispatch(new RouterNav({ + path: [ + 'applications', + this.applicationService.cfGuid, + this.applicationService.appGuid, + 'app-autoscaler-metric-page' + ] + })); + } + + scaleHistoryPage() { + this.store.dispatch(new RouterNav({ + path: [ + 'applications', + this.applicationService.cfGuid, + this.applicationService.appGuid, + 'app-autoscaler-scale-history-page' + ] + })); + } +} diff --git a/custom-src/frontend/app/custom/custom.module.spec.ts b/custom-src/frontend/app/custom/custom.module.spec.ts new file mode 100644 index 0000000000..cef2dc7211 --- /dev/null +++ b/custom-src/frontend/app/custom/custom.module.spec.ts @@ -0,0 +1,13 @@ +import { CustomModule } from './custom.module'; + +describe('CustomModule', () => { + let customModule: CustomModule; + + beforeEach(() => { + customModule = new CustomModule(); + }); + + it('should create an instance', () => { + expect(customModule).toBeTruthy(); + }); +}); diff --git a/custom-src/frontend/app/custom/custom.module.ts b/custom-src/frontend/app/custom/custom.module.ts new file mode 100644 index 0000000000..c92b231f5c --- /dev/null +++ b/custom-src/frontend/app/custom/custom.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { AutoscalerTabExtensionComponent } from './autoscaler-tab-extension/autoscaler-tab-extension.component'; +import { SharedModule } from '../shared/shared.module'; +import { MDAppModule } from '../core/md.module'; +import { NgxChartsModule } from '@swimlane/ngx-charts'; + +@NgModule({ + imports: [ + CommonModule, + SharedModule, + MDAppModule, + NgxChartsModule + ], + declarations: [AutoscalerTabExtensionComponent], + entryComponents: [AutoscalerTabExtensionComponent] +}) +export class CustomModule { } diff --git a/src/frontend/packages/core/src/core/extension/extension-service.ts b/src/frontend/packages/core/src/core/extension/extension-service.ts index 60febeabbf..b98335e682 100644 --- a/src/frontend/packages/core/src/core/extension/extension-service.ts +++ b/src/frontend/packages/core/src/core/extension/extension-service.ts @@ -30,6 +30,7 @@ export interface StratosTabMetadata { type: StratosTabType; label: string; link: string; + action: any; } // The different types of Action 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 39c1691c9e..f87da8c9a1 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 @@ -134,13 +134,13 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy { }), first() ); - this.applicationService.waitForAppAutoscalerHealth$ - .pipe(first()) - .subscribe(entity => { - if (entity && entity.entity && entity.entity.entity && entity.entity.entity.uptime > 0) { - this.tabLinks.push({ link: 'auto-scaler', label: 'Autoscale' }); - } - }); + // this.applicationService.waitForAppAutoscalerHealth$ + // .pipe(first()) + // .subscribe(entity => { + // if (entity && entity.entity && entity.entity.entity && entity.entity.entity.uptime > 0) { + // this.tabLinks.push({ link: 'auto-scaler', label: 'Autoscale' }); + // } + // }); this.endpointsService.hasMetrics(applicationService.cfGuid).subscribe(hasMetrics => { if (hasMetrics) { @@ -152,7 +152,17 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy { }); // Add any tabs from extensions - this.tabLinks = this.tabLinks.concat(getTabsFromExtensions(StratosTabType.Application)); + const tabs = getTabsFromExtensions(StratosTabType.Application); + tabs.map((extensionTab) => { + if (extensionTab.action) { + extensionTab.action.onSucceed = () => { + this.tabLinks.push(extensionTab); + }; + this.store.dispatch(extensionTab.action); + } else { + this.tabLinks.push(extensionTab); + } + }); // Ensure Git SCM tab gets updated if the app is redeployed from a different SCM Type this.stratosProjectSub = this.applicationService.applicationStratProject$ diff --git a/src/frontend/packages/core/src/features/applications/autoscaler-metric-page/autoscaler-metric-page.component.ts b/src/frontend/packages/core/src/features/applications/autoscaler-metric-page/autoscaler-metric-page.component.ts index fe9e543323..a69552d55e 100644 --- a/src/frontend/packages/core/src/features/applications/autoscaler-metric-page/autoscaler-metric-page.component.ts +++ b/src/frontend/packages/core/src/features/applications/autoscaler-metric-page/autoscaler-metric-page.component.ts @@ -19,7 +19,7 @@ import { }) export class AutoscalerMetricPageComponent { - parentUrl = `/applications/${this.applicationService.cfGuid}/${this.applicationService.appGuid}/auto-scaler`; + parentUrl = `/applications/${this.applicationService.cfGuid}/${this.applicationService.appGuid}/autoscale`; constructor( public applicationService: ApplicationService, diff --git a/src/frontend/packages/core/src/features/applications/autoscaler-scale-history-page/autoscaler-scale-history-page.component.ts b/src/frontend/packages/core/src/features/applications/autoscaler-scale-history-page/autoscaler-scale-history-page.component.ts index a12c836e86..9dd85df071 100644 --- a/src/frontend/packages/core/src/features/applications/autoscaler-scale-history-page/autoscaler-scale-history-page.component.ts +++ b/src/frontend/packages/core/src/features/applications/autoscaler-scale-history-page/autoscaler-scale-history-page.component.ts @@ -16,7 +16,7 @@ import { ListConfig } from '../../../shared/components/list/list.component.types }) export class AutoscalerScaleHistoryPageComponent { - parentUrl = `/applications/${this.applicationService.cfGuid}/${this.applicationService.appGuid}/auto-scaler`; + parentUrl = `/applications/${this.applicationService.cfGuid}/${this.applicationService.appGuid}/autoscale`; constructor( public applicationService: ApplicationService, diff --git a/src/frontend/packages/core/src/features/applications/edit-autoscaler-policy/edit-autoscaler-policy.component.ts b/src/frontend/packages/core/src/features/applications/edit-autoscaler-policy/edit-autoscaler-policy.component.ts index 5b8be6a490..f97709edf5 100644 --- a/src/frontend/packages/core/src/features/applications/edit-autoscaler-policy/edit-autoscaler-policy.component.ts +++ b/src/frontend/packages/core/src/features/applications/edit-autoscaler-policy/edit-autoscaler-policy.component.ts @@ -49,7 +49,7 @@ import * as moment from 'moment-timezone'; }) export class EditAutoscalerPolicyComponent implements OnInit, OnDestroy { - parentUrl = `/applications/${this.applicationService.cfGuid}/${this.applicationService.appGuid}/auto-scaler`; + parentUrl = `/applications/${this.applicationService.cfGuid}/${this.applicationService.appGuid}/autoscale`; alertInvalidPolicyMinimumRange = 'The Minimum Instance Count must be a integer less than the Maximum Instance Count.'; alertInvalidPolicyMaximumRange = 'The Maximum Instance Count must be a integer greater than the Minimum Instance Count.'; diff --git a/src/frontend/packages/core/src/shared/components/list/list-cards/cards.component.ts b/src/frontend/packages/core/src/shared/components/list/list-cards/cards.component.ts index 3231118444..c3e5c8193e 100644 --- a/src/frontend/packages/core/src/shared/components/list/list-cards/cards.component.ts +++ b/src/frontend/packages/core/src/shared/components/list/list-cards/cards.component.ts @@ -31,7 +31,7 @@ export class CardsComponent { return this.dataSource.trackBy(index, item.entity); } return this.dataSource.trackBy(index, item); - } + }; } public isMultiActionItem(component: any | MultiActionListEntity) { diff --git a/src/frontend/packages/store/src/actions/app-autoscaler.actions.ts b/src/frontend/packages/store/src/actions/app-autoscaler.actions.ts index 9b1c714a69..40458374c7 100644 --- a/src/frontend/packages/store/src/actions/app-autoscaler.actions.ts +++ b/src/frontend/packages/store/src/actions/app-autoscaler.actions.ts @@ -48,6 +48,7 @@ export class GetAppAutoscalerHealthAction implements IRequestAction { public appGuid: string, public cfGuid: string, ) { } + onSucceed: any; type = APP_AUTOSCALER_HEALTH; entityKey = appAutoscalerHealthSchemaKey; } diff --git a/src/frontend/packages/store/src/effects/autoscaler.effects.ts b/src/frontend/packages/store/src/effects/autoscaler.effects.ts index 1a7e1190f7..9a6ac56029 100644 --- a/src/frontend/packages/store/src/effects/autoscaler.effects.ts +++ b/src/frontend/packages/store/src/effects/autoscaler.effects.ts @@ -3,8 +3,6 @@ import { Headers, Http, Request, RequestOptions, URLSearchParams } from '@angula import { Actions, Effect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { catchError, mergeMap, withLatestFrom } from 'rxjs/operators'; - -import { LoggerService } from '../../../core/src/core/logger.service'; import { environment } from '../../../core/src/environments/environment.prod'; import { APP_AUTOSCALER_HEALTH, @@ -54,7 +52,6 @@ export class AutoscalerEffects { private http: Http, private actions$: Actions, private store: Store, - private logger: LoggerService, ) { } @Effect() @@ -81,6 +78,9 @@ export class AutoscalerEffects { result: [] } as NormalizedResponse; this.transformData(action.entityKey, mappedData, action.appGuid, healthInfo); + if (healthInfo.uptime > 0 && action.onSucceed) { + action.onSucceed(); + } return [ new WrapperRequestActionSuccess(mappedData, apiAction, actionType) ]; @@ -165,7 +165,6 @@ export class AutoscalerEffects { })); })); - @Effect() detachAppAutoscalerPolicy$ = this.actions$.pipe( ofType(DETACH_APP_AUTOSCALER_POLICY),