From 6187c942bedebeb2f452ed0856652f90cd5c5772 Mon Sep 17 00:00:00 2001 From: Idan Amit Date: Sun, 15 Apr 2018 19:19:08 +0300 Subject: New observable notify design in pubsub Implemented the new subscription mechanism for the pub sub notify function Change-Id: I5e6484adf1a0413d48b54b55048cda1a59b387ee Issue-ID: SDC-1178 Signed-off-by: Idan Amit --- catalog-ui/src/app/models/base-pubsub.ts | 81 ++++++++++++++-------- catalog-ui/src/app/models/plugin-pubsub.ts | 29 ++++++++ .../components/ui/plugin/plugin-frame.component.ts | 13 ++-- .../src/app/ng2/services/event-bus.service.ts | 17 ++++- .../app/services/components/component-service.ts | 17 +---- .../app/services/components/resource-service.ts | 9 +-- .../src/app/services/components/service-service.ts | 9 +-- .../app/utils/change-lifecycle-state-handler.ts | 30 +++++--- .../view-models/workspace/workspace-view-model.ts | 81 +++++++++++----------- 9 files changed, 174 insertions(+), 112 deletions(-) create mode 100644 catalog-ui/src/app/models/plugin-pubsub.ts diff --git a/catalog-ui/src/app/models/base-pubsub.ts b/catalog-ui/src/app/models/base-pubsub.ts index ca313b15f5..b9ff788a57 100644 --- a/catalog-ui/src/app/models/base-pubsub.ts +++ b/catalog-ui/src/app/models/base-pubsub.ts @@ -5,10 +5,12 @@ export class BasePubSub { subscribers: Map; eventsCallbacks: Array; clientId: string; + eventsToWait: Map>; constructor(pluginId: string) { this.subscribers = new Map(); - this.eventsCallbacks = new Array(); + this.eventsCallbacks = []; + this.eventsToWait = new Map>(); this.clientId = pluginId; this.onMessage = this.onMessage.bind(this); @@ -29,7 +31,13 @@ export class BasePubSub { } public on(callback: Function) { - this.eventsCallbacks.push(callback); + let functionExists = this.eventsCallbacks.find((func: Function) => { + return callback.toString() == func.toString() + }); + + if (!functionExists) { + this.eventsCallbacks.push(callback); + } } public off(callback: Function) { @@ -44,9 +52,49 @@ export class BasePubSub { originId: this.clientId } as IPubSubEvent; - this.subscribers.forEach( (subscriber: ISubscriber, id: string) => { - subscriber.window.postMessage(eventObj, subscriber.locationUrl) + this.subscribers.forEach( (subscriber: ISubscriber, subscriberId: string) => { + subscriber.window.postMessage(eventObj, subscriber.locationUrl); + }); + + return { + subscribe: function(callbackFn) { + + if(this.subscribers.size !== 0) { + let subscribersToNotify = Array.from(this.subscribers.keys()); + + const checkNotifyComplete = (subscriberId: string) => { + + let index = subscribersToNotify.indexOf(subscriberId); + subscribersToNotify.splice(index, 1); + + if (subscribersToNotify.length === 0) { + callbackFn(); + } + }; + + this.subscribers.forEach((subscriber: ISubscriber, subscriberId: string) => { + if (this.eventsToWait.has(subscriberId) && this.eventsToWait.get(subscriberId).indexOf(eventType) !== -1) { + + const actionCompletedFunction = (eventData, subId = subscriberId) => { + if (eventData.type == "ACTION_COMPLETED") { + checkNotifyComplete(subId); + } + this.off(actionCompletedFunction); + + }; + this.on(actionCompletedFunction); + } + else { + checkNotifyComplete(subscriberId); + } + }); + } + else { + callbackFn(); + } + }.bind(this) + } } protected onMessage(event: any) { @@ -58,31 +106,6 @@ export class BasePubSub { } } -export class PluginPubSub extends BasePubSub { - - constructor(pluginId: string, parentUrl: string) { - super(pluginId); - this.register('sdc-hub', window.parent, parentUrl); - this.subscribe(); - } - - public subscribe() { - const registerData = { - pluginId: this.clientId - }; - - this.notify('PLUGIN_REGISTER', registerData); - } - - public unsubscribe() { - const unregisterData = { - pluginId: this.clientId - }; - - this.notify('PLUGIN_UNREGISTER', unregisterData); - } -} - export interface IPubSubEvent { type: string; originId: string; diff --git a/catalog-ui/src/app/models/plugin-pubsub.ts b/catalog-ui/src/app/models/plugin-pubsub.ts new file mode 100644 index 0000000000..3a34de99cc --- /dev/null +++ b/catalog-ui/src/app/models/plugin-pubsub.ts @@ -0,0 +1,29 @@ +import {BasePubSub} from "./base-pubsub"; + +declare const window: Window; + +export class PluginPubSub extends BasePubSub { + + constructor(pluginId: string, parentUrl: string, eventsToWait?: Array) { + super(pluginId); + this.register('sdc-hub', window.parent, parentUrl); + this.subscribe(eventsToWait); + } + + public subscribe(eventsToWait?: Array) { + const registerData = { + pluginId: this.clientId, + eventsToWait: eventsToWait || [] + }; + + this.notify('PLUGIN_REGISTER', registerData); + } + + public unsubscribe() { + const unregisterData = { + pluginId: this.clientId + }; + + this.notify('PLUGIN_UNREGISTER', unregisterData); + } +} diff --git a/catalog-ui/src/app/ng2/components/ui/plugin/plugin-frame.component.ts b/catalog-ui/src/app/ng2/components/ui/plugin/plugin-frame.component.ts index 2ba784727f..4759721034 100644 --- a/catalog-ui/src/app/ng2/components/ui/plugin/plugin-frame.component.ts +++ b/catalog-ui/src/app/ng2/components/ui/plugin/plugin-frame.component.ts @@ -43,13 +43,16 @@ export class PluginFrameComponent implements OnInit { this.pluginUrl += this.urlSearchParams.toString(); } - this.eventBusService.on((eventData) => { + let readyEvent = (eventData) => { if (eventData.originId === this.plugin.pluginId) { if (eventData.type == "READY") { this.onLoadingDone.emit(); + this.eventBusService.off(readyEvent) } } - }); + }; + + this.eventBusService.on(readyEvent); // Listening to the stateChangeStart event in order to notify the plugin about it being closed // before moving to a new state @@ -58,11 +61,11 @@ export class PluginFrameComponent implements OnInit { if (!this.isClosed) { event.preventDefault(); - this.eventBusService.notify("WINDOW_OUT"); + this.eventBusService.notify("WINDOW_OUT").subscribe(() => { + this.isClosed = true; - this.isClosed = true; + this.eventBusService.unregister(this.plugin.pluginId); - setTimeout(() => { this.$state.go(toState.name, toParams); }); } diff --git a/catalog-ui/src/app/ng2/services/event-bus.service.ts b/catalog-ui/src/app/ng2/services/event-bus.service.ts index 7730a77f41..438437d193 100644 --- a/catalog-ui/src/app/ng2/services/event-bus.service.ts +++ b/catalog-ui/src/app/ng2/services/event-bus.service.ts @@ -11,6 +11,18 @@ export class EventBusService extends BasePubSub { protected handlePluginRegistration(eventData: IPubSubEvent, event: any) { if (eventData.type === 'PLUGIN_REGISTER') { this.register(eventData.data.pluginId, event.source, event.origin); + + let newEventsList = []; + + if (this.eventsToWait.has(eventData.data.pluginId)) { + newEventsList = _.union(this.eventsToWait.get(eventData.data.pluginId), eventData.data.eventsToWait); + } + else { + newEventsList = eventData.data.eventsToWait; + } + + this.eventsToWait.set(eventData.data.pluginId, newEventsList); + } else if (eventData.type === 'PLUGIN_UNREGISTER') { this.unregister(eventData.data.pluginId); } @@ -21,8 +33,9 @@ export class EventBusService extends BasePubSub { pluginId: pluginId }; - this.notify('PLUGIN_CLOSE', unregisterData); - super.unregister(pluginId); + this.notify('PLUGIN_CLOSE', unregisterData).subscribe(() => { + super.unregister(pluginId); + }); } protected onMessage(event: any) { diff --git a/catalog-ui/src/app/services/components/component-service.ts b/catalog-ui/src/app/services/components/component-service.ts index 8331bdbfb6..0b68c8be30 100644 --- a/catalog-ui/src/app/services/components/component-service.ts +++ b/catalog-ui/src/app/services/components/component-service.ts @@ -24,7 +24,6 @@ import {ArtifactModel, IFileDownload, InstancesInputsPropertiesMap, InputModel, import {ComponentInstanceFactory, CommonUtils} from "app/utils"; import {SharingService} from "../sharing-service"; import {ComponentMetadata} from "../../models/component-metadata"; -import {EventBusService} from "../../ng2/services/event-bus.service"; export interface IComponentService { @@ -82,16 +81,14 @@ export class ComponentService implements IComponentService { 'sdcConfig', 'Sdc.Services.SharingService', '$q', - '$base64', - 'EventBusService' + '$base64' ]; constructor(protected restangular:restangular.IElement, protected sdcConfig:IAppConfigurtaion, protected sharingService:SharingService, protected $q:ng.IQService, - protected $base64:any, - protected eventBusService:EventBusService + protected $base64:any ) { this.restangular.setBaseUrl(sdcConfig.api.root + sdcConfig.api.component_api_root); @@ -230,16 +227,6 @@ export class ComponentService implements IComponentService { deferred.reject(err); }); - // Notifying about events before executing the actual actions - switch (state) { - case "lifecycleState/CHECKIN": - this.eventBusService.notify("CHECK_IN"); - break; - case "lifecycleState/certificationRequest": - this.eventBusService.notify("SUBMIT_FOR_TESTING"); - break; - } - return deferred.promise; }; diff --git a/catalog-ui/src/app/services/components/resource-service.ts b/catalog-ui/src/app/services/components/resource-service.ts index aabc14f8bd..15ef51e475 100644 --- a/catalog-ui/src/app/services/components/resource-service.ts +++ b/catalog-ui/src/app/services/components/resource-service.ts @@ -26,7 +26,6 @@ import * as _ from "lodash"; import {IComponentService, ComponentService} from "./component-service"; import {PropertyModel, IAppConfigurtaion, Resource, Component} from "../../models"; import {SharingService} from "../sharing-service"; -import {EventBusService} from "../../ng2/services/event-bus.service"; export interface IResourceService extends IComponentService { updateResourceGroupProperties(uniqueId:string, groupId:string, properties:Array):ng.IPromise> @@ -39,18 +38,16 @@ export class ResourceService extends ComponentService implements IResourceServic 'sdcConfig', 'Sdc.Services.SharingService', '$q', - '$base64', - 'EventBusService' + '$base64' ]; constructor(protected restangular:restangular.IElement, protected sdcConfig:IAppConfigurtaion, protected sharingService:SharingService, protected $q:ng.IQService, - protected $base64:any, - protected eventBusService:EventBusService + protected $base64:any ) { - super(restangular, sdcConfig, sharingService, $q, $base64, eventBusService); + super(restangular, sdcConfig, sharingService, $q, $base64); this.restangular = restangular.one("resources"); } diff --git a/catalog-ui/src/app/services/components/service-service.ts b/catalog-ui/src/app/services/components/service-service.ts index ee3a02371a..cce0759613 100644 --- a/catalog-ui/src/app/services/components/service-service.ts +++ b/catalog-ui/src/app/services/components/service-service.ts @@ -26,7 +26,6 @@ import * as _ from "lodash"; import {IComponentService, ComponentService} from "./component-service"; import {Distribution, DistributionComponent, Service, PropertyModel, Component, IAppConfigurtaion} from "app/models"; import {SharingService} from "../sharing-service"; -import {EventBusService} from "../../ng2/services/event-bus.service"; export interface IServiceService extends IComponentService { getDistributionsList(uuid:string):ng.IPromise>; @@ -42,8 +41,7 @@ export class ServiceService extends ComponentService implements IServiceService 'sdcConfig', 'Sdc.Services.SharingService', '$q', - '$base64', - 'EventBusService' + '$base64' ]; public distribution:string = "distribution"; @@ -52,9 +50,8 @@ export class ServiceService extends ComponentService implements IServiceService protected sdcConfig:IAppConfigurtaion, protected sharingService:SharingService, protected $q:ng.IQService, - protected $base64:any, - protected eventBusService:EventBusService) { - super(restangular, sdcConfig, sharingService, $q, $base64, eventBusService); + protected $base64:any) { + super(restangular, sdcConfig, sharingService, $q, $base64); this.restangular = restangular.one("services"); } diff --git a/catalog-ui/src/app/utils/change-lifecycle-state-handler.ts b/catalog-ui/src/app/utils/change-lifecycle-state-handler.ts index d32730d630..f1c6544351 100644 --- a/catalog-ui/src/app/utils/change-lifecycle-state-handler.ts +++ b/catalog-ui/src/app/utils/change-lifecycle-state-handler.ts @@ -7,9 +7,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,6 +24,7 @@ import {IEmailModalModel, IEmailModalModel_Email, IEmailModalModel_Data} from ". import {AsdcComment} from "../models/comments"; import {ModalsHandler} from "./modals-handler"; import {ServiceServiceNg2} from "../ng2/services/component-services/service.service"; +import {EventBusService} from "../ng2/services/event-bus.service"; /** * Created by obarda on 2/11/2016. @@ -37,7 +38,8 @@ export class ChangeLifecycleStateHandler { 'ComponentFactory', '$filter', 'ModalsHandler', - 'ServiceServiceNg2' + 'ServiceServiceNg2', + 'EventBusService' ]; constructor(private sdcConfig:IAppConfigurtaion, @@ -45,7 +47,8 @@ export class ChangeLifecycleStateHandler { private ComponentFactory:ComponentFactory, private $filter:ng.IFilterService, private ModalsHandler:ModalsHandler, - private ServiceServiceNg2:ServiceServiceNg2) { + private ServiceServiceNg2:ServiceServiceNg2, + private eventBusService:EventBusService) { } @@ -101,7 +104,12 @@ export class ChangeLifecycleStateHandler { let onOk = (confirmationText):void => { comment.userRemarks = confirmationText; scope.isLoading = true; - component.changeLifecycleState(data.url, comment).then(onSuccess, onError); + + if (data.url === "lifecycleState/CHECKIN") { + this.eventBusService.notify("CHECK_IN").subscribe(() => { + component.changeLifecycleState(data.url, comment).then(onSuccess, onError); + }); + } }; let onCancel = ():void => { @@ -118,10 +126,14 @@ export class ChangeLifecycleStateHandler { // Show email dialog if defined in menu.json //------------------------------------------------- let onOk = (resource):void => { - if (resource) { - onSuccess(resource); - } else { - onError("Error changing life cycle state"); + if (data.url === "lifecycleState/certificationRequest") { + this.eventBusService.notify("SUBMIT_FOR_TESTING").subscribe(() => { + if (resource) { + onSuccess(resource); + } else { + onError("Error changing life cycle state"); + } + }); } }; diff --git a/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts b/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts index 5d83c34db8..7fa25177f5 100644 --- a/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/workspace-view-model.ts @@ -283,15 +283,14 @@ export class WorkspaceViewModel { version: this.$scope.changeVersion.selectedVersion.versionNumber }; - this.eventBusService.notify("VERSION_CHANGED", eventData); - - this.$state.go(this.$state.current.name, { - id: selectedId, - type: this.$scope.componentType.toLowerCase(), - mode: WorkspaceMode.VIEW, - components: this.$state.params['components'] - }, {reload: true}); - + this.eventBusService.notify("VERSION_CHANGED", eventData).subscribe(() => { + this.$state.go(this.$state.current.name, { + id: selectedId, + type: this.$scope.componentType.toLowerCase(), + mode: WorkspaceMode.VIEW, + components: this.$state.params['components'] + }, {reload: true}); + }); }; this.$scope.getLatestVersion = ():void => { @@ -472,36 +471,38 @@ export class WorkspaceViewModel { switch (url) { case 'lifecycleState/CHECKOUT': - // only checkOut get the full component from server - // this.$scope.component = component; - // Work around to change the csar version - if (this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { - (this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); - } - - //when checking out a minor version uuid remains - const bcIdx = _.findIndex(this.components, (item) => { - return item.uuid === component.uuid; - }); - if (bcIdx !== -1) { - this.components[bcIdx] = component; - } else { - //when checking out a major(certified) version - this.components.unshift(component); - } - // this.$state.go(this.$state.current.name, { - // id: component.uniqueId, - // type: component.componentType.toLowerCase(), - // components: this.components - // }); - this.$scope.mode = this.initViewMode(); - this.initChangeLifecycleStateButtons(); - this.initVersionObject(); - this.$scope.isLoading = false; - this.EventListenerService.notifyObservers(EVENTS.ON_CHECKOUT, component); - this.Notification.success({ - message: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TEXT"), - title: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TITLE") + this.eventBusService.notify("CHECK_OUT", eventData).subscribe(() => { + // only checkOut get the full component from server + // this.$scope.component = component; + // Work around to change the csar version + if (this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG)) { + (this.$scope.component).csarVersion = this.cacheService.get(CHANGE_COMPONENT_CSAR_VERSION_FLAG); + } + + //when checking out a minor version uuid remains + const bcIdx = _.findIndex(this.components, (item) => { + return item.uuid === component.uuid; + }); + if (bcIdx !== -1) { + this.components[bcIdx] = component; + } else { + //when checking out a major(certified) version + this.components.unshift(component); + } + // this.$state.go(this.$state.current.name, { + // id: component.uniqueId, + // type: component.componentType.toLowerCase(), + // components: this.components + // }); + this.$scope.mode = this.initViewMode(); + this.initChangeLifecycleStateButtons(); + this.initVersionObject(); + this.$scope.isLoading = false; + this.EventListenerService.notifyObservers(EVENTS.ON_CHECKOUT, component); + this.Notification.success({ + message: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TEXT"), + title: this.$filter('translate')("CHECKOUT_SUCCESS_MESSAGE_TITLE") + }); }); break; case 'lifecycleState/CHECKIN': @@ -512,7 +513,7 @@ export class WorkspaceViewModel { }); break; case 'lifecycleState/UNDOCHECKOUT': - setTimeout(() => { + this.eventBusService.notify("UNDO_CHECK_OUT", eventData).subscribe(() => { defaultActionAfterChangeLifecycleState(); this.Notification.success({ message: this.$filter('translate')("DELETE_SUCCESS_MESSAGE_TEXT"), -- cgit 1.2.3-korg