From 1d2dac87c4b5da33896244c951d509db04809927 Mon Sep 17 00:00:00 2001 From: aarora4 Date: Wed, 26 Jun 2019 11:55:49 -0400 Subject: [PATCH 01/27] UI Changes and min max Signed-off-by: aarora4 --- base/src/dispatcher/dispatcher.ts | 21 +++++++++++++++++---- interface/src/index.d.ts | 1 + interface/src/mvd-window-management.d.ts | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index ab0052c..0b1cd54 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -22,6 +22,7 @@ // + const IFRAME_LOAD_TIMEOUT = 180000; //3 minutes class ActionTarget { @@ -79,8 +80,10 @@ export class Dispatcher implements ZLUX.Dispatcher { postMessageCallback: any = null; public readonly constants:DispatcherConstants = new DispatcherConstants(); private log:ZLUX.ComponentLogger; - - constructor(logger: ZLUX.Logger){ + private windowManager: any; + constructor( + logger: ZLUX.Logger, + ){ /* dispatcher created early on - refering to logger from window object as a result */ this.log = logger.makeComponentLogger("ZLUX.Dispatcher"); this.runHeartbeat(); @@ -176,6 +179,7 @@ export class Dispatcher implements ZLUX.Dispatcher { registerPluginInstance(plugin: ZLUX.Plugin, applicationInstanceId: MVDHosting.InstanceId, isIframe:boolean, isEmbedded?:boolean): void { this.log.info("Registering plugin="+plugin+" id="+applicationInstanceId); let instanceWrapper = new ApplicationInstanceWrapper(applicationInstanceId,isIframe); + let key = plugin.getKey(); if (!this.instancesForTypes.get(key)){ this.instancesForTypes.set(key,[instanceWrapper]); @@ -555,11 +559,11 @@ export class Dispatcher implements ZLUX.Dispatcher { invokeAction(action:Action, eventContext: any):any{ this.log.info("dispatcher.invokeAction on context "+JSON.stringify(eventContext)); this.getActionTarget(action,eventContext).then( (target: ActionTarget) => { - const wrapper = target.wrapper; + const wrapper = target.wrapper; + var targetId = eventContext.data.target || this.windowManager.nextId - 1; switch (action.type) { case ActionType.Launch: if (!target.preexisting) { - this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); break; } //else fall-through case ActionType.Message: @@ -575,14 +579,23 @@ export class Dispatcher implements ZLUX.Dispatcher { } break; case ActionType.Minimize: + this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); + this.windowManager.minimize(targetId); + break; case ActionType.Maximize: + this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); + this.windowManager.maximize(targetId); this.log.warn('Max/Min not supported at this time. Concern if apps should be able to control other apps visibility.'); + break; default: this.log.warn("Unhandled action type = "+action.type); }; }); } + setWindowManager(windowManager:any) { + this.windowManager = windowManager; + } } export class RecognitionRule { diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 1ca137c..7535428 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -41,6 +41,7 @@ declare namespace ZLUX { registerApplicationCallbacks(plugin: Plugin, applicationInstanceId: any, callbacks: ApplicationCallbacks): void; clear(): void; iframeLoaded(instanceId: MVDHosting.InstanceId, identifier: string); + setWindowManager(windowManager: any); constants: DispatcherConstants; } diff --git a/interface/src/mvd-window-management.d.ts b/interface/src/mvd-window-management.d.ts index 4db712a..a91d24d 100644 --- a/interface/src/mvd-window-management.d.ts +++ b/interface/src/mvd-window-management.d.ts @@ -25,6 +25,8 @@ declare namespace MVDWindowManagement { showWindow(windowId: MVDWindowManagement.WindowId): void; closeWindow(windowId: MVDWindowManagement.WindowId): void; closeAllWindows():void; + maximize(windowId: MVDWindowManagement.WindowId): void; + } } From 0febf91681d4b2b0817d578f23f07f48427e3570 Mon Sep 17 00:00:00 2001 From: aarora4 Date: Wed, 26 Jun 2019 13:16:08 -0400 Subject: [PATCH 02/27] more secure dispatcher access Signed-off-by: aarora4 --- base/src/dispatcher/dispatcher.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index 0b1cd54..1bddfeb 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -560,7 +560,7 @@ export class Dispatcher implements ZLUX.Dispatcher { this.log.info("dispatcher.invokeAction on context "+JSON.stringify(eventContext)); this.getActionTarget(action,eventContext).then( (target: ActionTarget) => { const wrapper = target.wrapper; - var targetId = eventContext.data.target || this.windowManager.nextId - 1; + var targetId = eventContext.data.target || this.windowManager.nextId() - 1; switch (action.type) { case ActionType.Launch: if (!target.preexisting) { @@ -581,6 +581,7 @@ export class Dispatcher implements ZLUX.Dispatcher { case ActionType.Minimize: this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); this.windowManager.minimize(targetId); + console.log(targetId); break; case ActionType.Maximize: this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); From a69eea61c45e44e1a2b1d574f109c77528748647 Mon Sep 17 00:00:00 2001 From: aarora4 Date: Wed, 26 Jun 2019 13:56:08 -0400 Subject: [PATCH 03/27] removed maximize from interface Signed-off-by: aarora4 --- interface/src/mvd-window-management.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/mvd-window-management.d.ts b/interface/src/mvd-window-management.d.ts index a91d24d..ee031ca 100644 --- a/interface/src/mvd-window-management.d.ts +++ b/interface/src/mvd-window-management.d.ts @@ -25,7 +25,6 @@ declare namespace MVDWindowManagement { showWindow(windowId: MVDWindowManagement.WindowId): void; closeWindow(windowId: MVDWindowManagement.WindowId): void; closeAllWindows():void; - maximize(windowId: MVDWindowManagement.WindowId): void; } } From f9ee896e54a905913fa9c677af5b48dc5e7911b6 Mon Sep 17 00:00:00 2001 From: aarora4 Date: Mon, 8 Jul 2019 12:17:15 -0400 Subject: [PATCH 04/27] changes to windowmanager assignment and max/min Signed-off-by: aarora4 --- base/src/dispatcher/dispatcher.ts | 25 +++++++++++++++---------- interface/src/index.d.ts | 4 ++-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index 1bddfeb..f6bf888 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -556,11 +556,10 @@ export class Dispatcher implements ZLUX.Dispatcher { } } - invokeAction(action:Action, eventContext: any):any{ + invokeAction(action:Action, eventContext: any, targetId?: number):any{ this.log.info("dispatcher.invokeAction on context "+JSON.stringify(eventContext)); this.getActionTarget(action,eventContext).then( (target: ActionTarget) => { const wrapper = target.wrapper; - var targetId = eventContext.data.target || this.windowManager.nextId() - 1; switch (action.type) { case ActionType.Launch: if (!target.preexisting) { @@ -579,14 +578,16 @@ export class Dispatcher implements ZLUX.Dispatcher { } break; case ActionType.Minimize: - this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); - this.windowManager.minimize(targetId); - console.log(targetId); + if (targetId) { + this.log.info("the targetID is " + targetId); + this.windowManager.minimize(targetId); + + } break; case ActionType.Maximize: - this.log.debug("invoke Launch, which means do nothing if wrapper found: "+wrapper); - this.windowManager.maximize(targetId); - this.log.warn('Max/Min not supported at this time. Concern if apps should be able to control other apps visibility.'); + if (targetId) { + this.windowManager.maximize(targetId); + } break; default: this.log.warn("Unhandled action type = "+action.type); @@ -594,8 +595,12 @@ export class Dispatcher implements ZLUX.Dispatcher { }); } - setWindowManager(windowManager:any) { - this.windowManager = windowManager; + attachWindowManager(windowManager:any): boolean{ + if (!this.windowManager) { + this.windowManager = windowManager; + return true; + } + return false; } } diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 7535428..33390c4 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -36,12 +36,12 @@ declare namespace ZLUX { addRecognizer(predicate: RecognitionClause, actionID: string): void; registerAction(action: Action): void; getAction(recognizer: any): Action | undefined; - invokeAction(action: Action, eventContext: any): any; + invokeAction(action: Action, eventContext: any, targetId?: number): any; makeAction(id: string, defaultName: string, targetMode: ActionTargetMode, type: ActionType, targetPluginID: string, primaryArgument: any): Action; registerApplicationCallbacks(plugin: Plugin, applicationInstanceId: any, callbacks: ApplicationCallbacks): void; clear(): void; iframeLoaded(instanceId: MVDHosting.InstanceId, identifier: string); - setWindowManager(windowManager: any); + attachWindowManager(windowManager: any); constants: DispatcherConstants; } From 381aa311cfc54ed47ad4d7002a9389a650548598 Mon Sep 17 00:00:00 2001 From: aarora4 Date: Mon, 8 Jul 2019 12:24:59 -0400 Subject: [PATCH 05/27] removed unneeded logging Signed-off-by: aarora4 --- base/src/dispatcher/dispatcher.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index f6bf888..ef8c7b8 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -579,7 +579,6 @@ export class Dispatcher implements ZLUX.Dispatcher { break; case ActionType.Minimize: if (targetId) { - this.log.info("the targetID is " + targetId); this.windowManager.minimize(targetId); } From 35efa9cadfeaf47dd7cb6c5e77f6c667cecd4a0c Mon Sep 17 00:00:00 2001 From: Todd Wellman Date: Wed, 10 Jul 2019 10:49:49 -0400 Subject: [PATCH 06/27] Add custom events that are used for cross app communication Signed-off-by: Todd Wellman --- base/src/dispatcher/dispatcher.ts | 192 ++++++++++++++++++++++++- base/src/dispatcher/event-registrar.ts | 85 +++++++++++ interface/src/index.d.ts | 7 +- 3 files changed, 276 insertions(+), 8 deletions(-) create mode 100644 base/src/dispatcher/event-registrar.ts diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index ab0052c..2e0799a 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -22,6 +22,8 @@ // +import { EventRegistrar } from './event-registrar' + const IFRAME_LOAD_TIMEOUT = 180000; //3 minutes class ActionTarget { @@ -79,11 +81,15 @@ export class Dispatcher implements ZLUX.Dispatcher { postMessageCallback: any = null; public readonly constants:DispatcherConstants = new DispatcherConstants(); private log:ZLUX.ComponentLogger; + private eventRegistry:EventRegistrar = new EventRegistrar(); constructor(logger: ZLUX.Logger){ /* dispatcher created early on - refering to logger from window object as a result */ this.log = logger.makeComponentLogger("ZLUX.Dispatcher"); this.runHeartbeat(); + this.registerEventListener("Launch", this.launchApp, "Dispatcher"); + window.addEventListener("message", this.iframeMessageHandler, false); + } @@ -143,7 +149,7 @@ export class Dispatcher implements ZLUX.Dispatcher { let context = contexts.shift(); if (context) { this.log.debug(`Sending postmessage of type launch to ${identifier} instance=${instanceId}`,context.data); - this.postMessageCallback(instanceId,{dispatchType: 'launch', dispatchData: {launchMetadata: context.data}}); + this.postMessageCallback(instanceId,{dispatchType: 'launch', dispatchData: {launchMetadata: context.data, instanceId: instanceId}}); } } } @@ -474,12 +480,7 @@ export class Dispatcher implements ZLUX.Dispatcher { return null; } - private createAsync(plugin:ZLUX.Plugin, action:Action, eventContext: any):Promise{ - //let appPromise:Promise - if (!this.launchCallback){ - return Promise.reject("no launch callback established"); - } - let launchMetadata = this.buildObjectFromTemplate(action.primaryArgument, eventContext); + private addPendingIframe(plugin:ZLUX.Plugin, launchMetadata: any) { if (this.postMessageCallback && plugin.getWebContent().framework === 'iframe') { let contexts = this.pendingIframes.get(plugin.getIdentifier()); if (!contexts) { @@ -503,6 +504,15 @@ export class Dispatcher implements ZLUX.Dispatcher { } },IFRAME_LOAD_TIMEOUT+1); } + } + + private createAsync(plugin:ZLUX.Plugin, action:Action, eventContext: any):Promise{ + //let appPromise:Promise + if (!this.launchCallback){ + return Promise.reject("no launch callback established"); + } + let launchMetadata = this.buildObjectFromTemplate(action.primaryArgument, eventContext); + this.addPendingIframe(plugin, launchMetadata) let appPromise = this.launchCallback(plugin, launchMetadata).then( (newAppID:MVDHosting.InstanceId) => { let wrapper = this.getAppInstanceWrapper(plugin,newAppID); @@ -583,6 +593,174 @@ export class Dispatcher implements ZLUX.Dispatcher { }); } + launchApp = (evt: CustomEvent) => { + var action = evt.detail.data.action; + var data = evt.detail.data.argumentData; + let plugin:ZLUX.Plugin = ZoweZLUX.pluginManager.getPlugin(action.targetPluginID); + this.createAsync(plugin, action, data); + } + + callInstance(eventName: string, appInstanceId:string, data: Object) { + var pluginId = this.findPluginIdFromInstanceId(appInstanceId); + return this.call(eventName, pluginId, appInstanceId, data); + } + + callAny(eventName: string, pluginId:string, data: Object) { + return this.call(eventName, pluginId, null, data, true); + } + + callAll(eventName: string, pluginId:string, data: Object) { + return this.call(eventName, pluginId, null, data); + } + + callEveryone(eventName: string, data: Object) { + return this.call(eventName, null, null, data); + } + + call(eventName: string, pluginId:string | null, appInstanceId:string | null, data: Object, singleEvent: boolean = false) { + return new Promise((resolve, reject) => { + let effectiveEventNames = this.eventRegistry.findEventCodes(eventName, pluginId, appInstanceId); + if (effectiveEventNames) { + var evt: CustomEvent | any = null + var resultList:Event[] = [] + var promises:Promise[] = [] + for (var i = 0; i < effectiveEventNames.length; i++) { + var eventDetail = { + data: data, + return: null + } + if (this.isIframe(effectiveEventNames[i].split("-")[effectiveEventNames[i].split("-").length-2])){ + promises.push(this.postMessageCallbackWrapper(effectiveEventNames[i], eventDetail)) + } else { + evt = new CustomEvent(effectiveEventNames[i], { + detail: eventDetail + }); + window.dispatchEvent(evt); + resultList.push(evt.detail.return) + } + if (singleEvent) { + break; + } + } + Promise.all(promises).then((results) => { + results.forEach((element) => { + resultList.push(element) + }) + resolve((resultList.length === 1 ? resultList[0] : resultList)) + }).catch((err) => { + reject(err) + }) + } else { + reject("The event \"" + eventName + "\" is not registered and could not be dispatched") + } + }) + } + + findPluginIdFromInstanceId(instanceId: string) { + let result = null; + if (instanceId === "Dispatcher") { + result = "Dispatcher"; + } else { + this.instancesForTypes.forEach((value, key) => { + value.forEach((element) => { + if (element.applicationInstanceId === parseInt(instanceId)) { + result = key.slice(0, key.indexOf("@")); + } + }); + }); + } + return result; + } + + isIframe(instanceId: string) { + let result = false; + this.instancesForTypes.forEach((value) => { + value.forEach((element) => { + if (element.applicationInstanceId === parseInt(instanceId)) { + result = element.isIframe + } + }); + }); + return result; + } + + registerEventListener(eventName: string, callback: EventListenerOrEventListenerObject | null, appId: string) { + var pluginId = this.findPluginIdFromInstanceId(appId); + if (pluginId) { + this.eventRegistry.registerEvent(eventName, pluginId, appId); + let effectiveEventNames = this.eventRegistry.findEventCodes(eventName, pluginId, appId); + if (effectiveEventNames) { + effectiveEventNames.forEach((element: string) => { + if (!this.isIframe(appId) && callback) { + window.addEventListener(element, callback); + } + }); + } else { + this.log.warn("The event \"" + eventName + "\" is not registered and listener could not be made"); + } + } + } + + deregisterEventListener(eventName: string, callback: EventListenerOrEventListenerObject | null, appId: string, pluginId:string) { + // the appid may have already been removed from the list of instances when this is called so the plugin id has to be passed in + if (pluginId) { + let effectiveEventNames = this.eventRegistry.findEventCodes(eventName, pluginId, appId); + if (effectiveEventNames) { + effectiveEventNames.forEach((element: string) => { + if (!this.isIframe(appId) && callback) { + window.removeEventListener(element, callback); + } + }); + } else { + this.log.warn("The event \"" + eventName + "\" is not registered and listener could not unregister"); + } + this.eventRegistry.deregisterEvent(eventName, pluginId, appId); + } + } + + postMessageCallbackWrapper = (fullEventName:string, eventPayload: any) => { + return new Promise((fullresolve) => { + let nameList:Array = fullEventName.split("-") + let instanceId = nameList[nameList.length-2]; + + var returnListener: EventListenerOrEventListenerObject; + new Promise((resolve) => { + returnListener = (evt: MessageEvent) => { + if (evt.data.messageType === "return" && evt.data.arguments.appId === instanceId){ + resolve(evt.data.arguments.returnValue) + } + } + window.addEventListener("message", returnListener) + }).then((data) => { + eventPayload.return = data + window.removeEventListener("message", returnListener) + fullresolve(data) + }) + this.postMessageCallback(parseInt(instanceId), {dispatchType: 'event', dispatchData: {launchMetadata: eventPayload}}) + }) + } + + iframeMessageHandler = (evt: any) => { + if (evt.data.messageType && evt.data.arguments) { + let args = evt.data.arguments; + switch (evt.data.messageType) { + case "RegisterEventListener": + this.registerEventListener(args.eventName, null, args.appId); + break; + case "DeregisterEventListener": + this.deregisterEventListener(args.eventName, null, args.appId, args.pluginId); + break; + case "CallEvent": + var context = this + this.call(args.eventName, args.pluginId, args.appId, args.data, args.singleEvent).then((results) => { + if (context.postMessageCallback) { + context.postMessageCallback(evt.source.instanceId, {dispatchType: 'return', dispatchData: {return: results}}) + } + }); + break; + } + } + } } export class RecognitionRule { diff --git a/base/src/dispatcher/event-registrar.ts b/base/src/dispatcher/event-registrar.ts new file mode 100644 index 0000000..5388928 --- /dev/null +++ b/base/src/dispatcher/event-registrar.ts @@ -0,0 +1,85 @@ + + +export class EventRegistrar { + private eventsList: Map>> = new Map(); + + createFullEventName(eventName:string, instanceId: string, length: number) { + let result = `${instanceId}-${eventName}-`; + let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (var i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; + } + + findIndexOfEventName(eventName:string, appInstanceId: string, eventNameList: Array) { + for (var i = 0; i < eventNameList.length; i++) { + if (eventNameList[i].startsWith(`${eventName}-${appInstanceId}-`)) { + return i; + } + } + return null; + } + + registerEvent(eventName: string, pluginId:string, appInstanceId: string) { + let name = this.createFullEventName(appInstanceId, eventName, 5); + if (this.eventsList.has(eventName)) { + let hold = this.eventsList.get(eventName); + if (hold) { + var listenerNames = hold.get(pluginId); + if (listenerNames) { + listenerNames.push(name); + } else { + hold.set(pluginId, [name]); + } + } + } else { + var newMap = new Map(); + newMap.set(pluginId, [name]); + this.eventsList.set(eventName, newMap); + } + } + + deregisterEvent(eventName: string, pluginId:string, appInstanceId: string) { + var hold = this.eventsList.get(eventName); + if (hold) { + let listenerNames = hold.get(pluginId); + if (listenerNames) { + var index = this.findIndexOfEventName(eventName, appInstanceId, listenerNames); + if (index != null) { + listenerNames.splice(index, 1); + } + if (listenerNames.length == 0) { + hold.delete(pluginId); + } + } + if (hold.size == 0) { + this.eventsList.delete(eventName); + } + } + } + + findEventCodes(eventName: string, pluginId: string | null, appInstanceId: string | null): string[] { + let event = this.eventsList.get(eventName); + if (event) { + if (pluginId) { + let plugin = event.get(pluginId); + if (plugin) { + if (appInstanceId) { + var index = this.findIndexOfEventName(eventName, appInstanceId, plugin); + return (index != null? [plugin[index]] : []); + } else { + return plugin; + } + } + } else { + var result:string[] = []; + event.forEach((value) => { + result = result.concat(value); + }); + return result; + } + } + return []; + } +} \ No newline at end of file diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 511641c..d085f09 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -37,6 +37,12 @@ declare namespace ZLUX { registerAction(action: Action): void; getAction(recognizer: any): Action | undefined; invokeAction(action: Action, eventContext: any): any; + callInstance(eventName: string, appInstanceId:string, data: Object): Promise; + callAny(eventName: string, pluginId:string, data: Object): Promise; + callAll(eventName: string, pluginId:string, data: Object): Promise; + callEveryone(eventName: string, data: Object): Promise; + registerEventListener(eventName: string, callback: EventListenerOrEventListenerObject | null, appId: string): void; + deregisterEventListener(eventName: string, callback: EventListenerOrEventListenerObject | null, appId: string, pluginId:string): void; makeAction(id: string, defaultName: string, targetMode: ActionTargetMode, type: ActionType, targetPluginID: string, primaryArgument: any): Action; registerApplicationCallbacks(plugin: Plugin, applicationInstanceId: any, callbacks: ApplicationCallbacks): void; clear(): void; @@ -147,7 +153,6 @@ declare namespace ZLUX { targetEncoding?: string | undefined, newName?: string | undefined, forceOverwrite?: boolean | undefined, sessionID?: number | undefined, lastChunk?: boolean | undefined, responseType?: string): string; - omvsSegmentUri(): string; rasUri(uri: string): string; serverRootUri(uri: string): string; pluginResourceUri(pluginDefinition: Plugin, relativePath: string): string; From 20606e5f672619a72916d59dc62d939a77382d2e Mon Sep 17 00:00:00 2001 From: aarora4 Date: Mon, 15 Jul 2019 11:08:32 -0400 Subject: [PATCH 07/27] added logger warnings Signed-off-by: aarora4 --- base/src/dispatcher/dispatcher.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index ef8c7b8..1392060 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -578,14 +578,17 @@ export class Dispatcher implements ZLUX.Dispatcher { } break; case ActionType.Minimize: - if (targetId) { + if (targetId && this.windowManager) { this.windowManager.minimize(targetId); - + }else { + this.log.warn('Target ID not provided or windowManager not initialized'); } break; case ActionType.Maximize: - if (targetId) { + if (targetId && this.windowManager) { this.windowManager.maximize(targetId); + }else { + this.log.warn('Target ID not provided or windowManager not initialized'); } break; default: @@ -599,7 +602,9 @@ export class Dispatcher implements ZLUX.Dispatcher { this.windowManager = windowManager; return true; } + this.log.warn('windowManager has already been initialized'); return false; + } } From 5b259dfda5f7204193fe091d4e462c7cc441e796 Mon Sep 17 00:00:00 2001 From: Todd Wellman Date: Fri, 19 Jul 2019 11:49:33 -0400 Subject: [PATCH 08/27] add custom event messaging Signed-off-by: Todd Wellman --- base/src/dispatcher/dispatcher.ts | 2 +- interface/src/index.d.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index 2e0799a..782cae1 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -480,7 +480,7 @@ export class Dispatcher implements ZLUX.Dispatcher { return null; } - private addPendingIframe(plugin:ZLUX.Plugin, launchMetadata: any) { + addPendingIframe(plugin:ZLUX.Plugin, launchMetadata: any) { if (this.postMessageCallback && plugin.getWebContent().framework === 'iframe') { let contexts = this.pendingIframes.get(plugin.getIdentifier()); if (!contexts) { diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index d085f09..fda4ead 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -37,6 +37,7 @@ declare namespace ZLUX { registerAction(action: Action): void; getAction(recognizer: any): Action | undefined; invokeAction(action: Action, eventContext: any): any; + addPendingIframe(plugin:ZLUX.Plugin, launchMetadata: any): void; callInstance(eventName: string, appInstanceId:string, data: Object): Promise; callAny(eventName: string, pluginId:string, data: Object): Promise; callAll(eventName: string, pluginId:string, data: Object): Promise; From f03a4686007ffafd279bf24d961fc4c8ac6eb85b Mon Sep 17 00:00:00 2001 From: 1000TurquoisePogs Date: Thu, 1 Aug 2019 16:29:39 -0400 Subject: [PATCH 09/27] instanceRemoved was never called on logout due to clear function not informing watchers of the clearing Signed-off-by: 1000TurquoisePogs --- base/src/dispatcher/dispatcher.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index ab0052c..cf5abfb 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -97,6 +97,23 @@ export class Dispatcher implements ZLUX.Dispatcher { static dispatcherHeartbeatInterval:number = 60000; /* one minute */ clear(): void { + let typesIt = this.instancesForTypes.keys(); + let type = typesIt.next(); + while (!type.done) { + let plugin = type.value; + let instancesArray = this.instancesForTypes.get(plugin) || []; + for (let j = 0; j < instancesArray.length; j++) { + let instance = instancesArray[j]; + let watchers = this.pluginWatchers.get(plugin); + if (watchers) { + for (let k = 0; k < watchers.length; k++) { + watchers[k].instanceRemoved(instance.applicationInstanceId); + } + } + return; + } + type = typesIt.next(); + } this.instancesForTypes.clear(); this.indexedRecognizers.clear(); this.recognizers = []; From 29d61d4dde6eb40b053d52afb04d6f0854b23738 Mon Sep 17 00:00:00 2001 From: Timothy Gerstel Date: Fri, 16 Aug 2019 09:22:30 -0400 Subject: [PATCH 10/27] Updated datasetMetadataUri definition to reflect new ZSS endpoint Signed-off-by: Timothy Gerstel --- interface/src/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 511641c..8b8f8db 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -136,7 +136,7 @@ declare namespace ZLUX { interface UriBroker { desktopRootUri(): string; datasetMetadataHlqUri(updateCache?: boolean, types?: string, workAreaSize?: number, resumeName?: string, resumeCatalogName?: string): string; - datasetMetadataUri(dsn: string, detail?: string, types?: string, listMembers?: boolean, workAreaSize?: number, includeMigrated?: boolean, includeUnprintable?: boolean, resumeName?: string, resumeCatalogName?: string): string; + datasetMetadataUri(dsn: string, detail?: string, types?: string, listMembers?: boolean, addQualifiers?: string, workAreaSize?: number, includeMigrated?: boolean, includeUnprintable?: boolean, resumeName?: string, resumeCatalogName?: string): string; datasetContentsUri(dsn: string): string; VSAMdatasetContentsUri(dsn: string, closeAfter?: boolean): string; /*TODO: for breaking change, we need to change this into a passed object so that its way cleaner and From 66863cc65ce60530dfd0438a0b342b87b74a7826 Mon Sep 17 00:00:00 2001 From: Timothy Gerstel Date: Fri, 16 Aug 2019 14:16:54 -0400 Subject: [PATCH 11/27] Changed order of arguments for backwards compatibility Signed-off-by: Timothy Gerstel --- interface/src/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 8b8f8db..8c339cd 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -136,7 +136,7 @@ declare namespace ZLUX { interface UriBroker { desktopRootUri(): string; datasetMetadataHlqUri(updateCache?: boolean, types?: string, workAreaSize?: number, resumeName?: string, resumeCatalogName?: string): string; - datasetMetadataUri(dsn: string, detail?: string, types?: string, listMembers?: boolean, addQualifiers?: string, workAreaSize?: number, includeMigrated?: boolean, includeUnprintable?: boolean, resumeName?: string, resumeCatalogName?: string): string; + datasetMetadataUri(dsn: string, detail?: string, types?: string, listMembers?: boolean, workAreaSize?: number, includeMigrated?: boolean, includeUnprintable?: boolean, resumeName?: string, resumeCatalogName?: string, addQualifiers?: string): string; datasetContentsUri(dsn: string): string; VSAMdatasetContentsUri(dsn: string, closeAfter?: boolean): string; /*TODO: for breaking change, we need to change this into a passed object so that its way cleaner and From 506fc4ae89c73224c6644e3cdf993233bc5f17f4 Mon Sep 17 00:00:00 2001 From: Leanid Astrakou Date: Thu, 22 Aug 2019 15:56:52 -0400 Subject: [PATCH 12/27] Added ability for logger to instantiate with id<--->message map Signed-off-by: Leanid Astrakou --- interface/src/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 511641c..dea2726 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -110,7 +110,7 @@ declare namespace ZLUX { } interface Logger { - makeComponentLogger(componentName: string): ComponentLogger; + makeComponentLogger(componentName: string, messages?: any): ComponentLogger; setLogLevelForComponentName(componentName: string, level: number): void; } From f7d7b816e4bbdbad12d05276fc63eba756807440 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Fri, 23 Aug 2019 10:38:17 -0400 Subject: [PATCH 13/27] Initial commit for notifications Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 111 ++++++++++++++++-- base/src/notification-manager/notification.ts | 15 ++- base/src/plugin-manager/plugin-manager.ts | 4 + base/src/plugin-manager/plugin.ts | 3 +- interface/src/index.d.ts | 5 +- interface/src/mvd-hosting.d.ts | 24 ++-- 6 files changed, 135 insertions(+), 27 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index 31f7882..59a75ec 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -9,24 +9,110 @@ Copyright Contributors to the Zowe Project. */ +import { ZoweNotification } from './notification'; +// import { PluginManager } from '../../../../zlux-app-manager/virtual-desktop/src/app/plugin-manager/shared/plugin-manager' +// import { Plugin } from '../plugin-manager/plugin' -export class NotificationManager implements MVDHosting.NotificationManagerInterface { +export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManagerInterface { private notificationCache: any[]; - private handlers: MVDHosting.NotificationWatcher[]; + private handlers: MVDHosting.ZoweNotificationWatcher[]; + private ws: WebSocket; + public url: string; + host: any; + port: any; + securityType: any; + connectionSettings: any; + modType: any; + row: any; + column: any; + selectedCodepage: any; + + constructor() { - this.notificationCache = new Array(); - this.handlers = new Array(); + this.notificationCache = new Array(); + this.handlers = new Array(); + // console.log(ZoweZLUX) + // let test: MVDHosting.DesktopPluginDefinition; + + const myHost = window.location.host; + const protocol = window.location.protocol; + const wsProtocol = (protocol === 'https:') ? 'wss:' : 'ws:'; + let computedURL:string = `${wsProtocol}//${myHost}/plugins/org.zowe.zlux.bootstrap/services/adminnotificationsdata/`; + console.log(computedURL) + this.connectionSettings = { + host: this.host, + port: this.port, + security: { + type: this.securityType + }, + deviceType: Number(this.modType), + alternateHeight: this.row, + alternateWidth: this.column, + charsetName: this.selectedCodepage + } + } + + setURL(url: string){ + this.url = url; + this.ws = new WebSocket(url); + console.log("hey123") + var _this = this; + this.ws.onmessage = function(message) { + console.log("123hey") + console.log(message) + _this.updateStuff(message); + } + // this.ws.send("test") + } + + updateStuff(message: MessageEvent) { + console.log(message) + for (let i = 0; i < this.handlers.length; i++) { + this.handlers[i].handleMessageAddedTest(message.data); + } + } + + getURL() { + return this.url; } - push(notification: Notification): void { + ngOnInit() { + + console.log("yyya") + this.ws.onmessage = function () { + console.log("test") + // Do something? + } + + + this.ws.onerror = function () { + this.close(); + } + } + + // sendmessage(notification: ZoweNotification): void { + + // } + + push(notification: ZoweNotification): void { + // let pluginTest = new Plugin() + // console.log(pluginTest) + // let pluginTest: ZLUX.PluginType = ZLUX.PluginType.Desktop + // console.log(ZoweZLUX.uriBroker.pluginListUri(pluginTest)) + // }; + // console.log(ZoweZLUX.pluginManager.getDesktopPlugin()) + //.findPluginDefinition("org.zowe.zlux.bootstrap") + // console.log(ZoweZLUX.uriBroker.pluginWSUri(plugin, 'adminnotificationdata', '')) + console.log(this.handlers) this.notificationCache.push(notification); for (let i = 0; i < this.handlers.length; i++) { this.handlers[i].handleMessageAdded(); } + this.ws.send("message") } - pop(): Notification | void { + pop(): ZoweNotification | void { let n = this.notificationCache.pop(); for (let i = 0; i < this.handlers.length; i++) { this.handlers[i].handleMessageAdded(); @@ -34,8 +120,8 @@ export class NotificationManager implements MVDHosting.NotificationManagerInterf return n; } - getAll(): Notification[] { - let copy: Notification[] = this.notificationCache.slice(0); + getAll(): ZoweNotification[] { + let copy: ZoweNotification[] = this.notificationCache.slice(0); /* NgFor is going from first element. We need to start from the end to show the most recent notifications first. It would make more sense to just pop all elements from notification cache, but if we closed the app, they'd all be gone. @@ -45,8 +131,8 @@ export class NotificationManager implements MVDHosting.NotificationManagerInterf return copy; } - getAllByCategory(type: MVDHosting.NotificationType): Notification[] { - var filtered: Notification[] = []; + getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] { + var filtered: ZoweNotification[] = []; var i: number; for (i = 0; i < this.notificationCache.length; i++) { @@ -71,7 +157,10 @@ export class NotificationManager implements MVDHosting.NotificationManagerInterf return this.notificationCache.length; } - addMessageHandler(object: MVDHosting.NotificationWatcher) { + getCountTest(): void { + } + + addMessageHandler(object: MVDHosting.ZoweNotificationWatcher) { this.handlers.push(object); } } diff --git a/base/src/notification-manager/notification.ts b/base/src/notification-manager/notification.ts index c253738..bdd13d2 100644 --- a/base/src/notification-manager/notification.ts +++ b/base/src/notification-manager/notification.ts @@ -10,15 +10,17 @@ */ -export class Notification { +export class ZoweNotification { private message: string; private date: Date; - private type: MVDHosting.NotificationType; + private type: MVDHosting.ZoweNotificationType; + private plugin: string; - constructor(message: string, type: MVDHosting.NotificationType) { + constructor(message: string, type: MVDHosting.ZoweNotificationType, plugin: string) { this.message = message; this.type = type; this.date = new Date(); + this.plugin = plugin; } getMessage(): string { @@ -29,9 +31,14 @@ export class Notification { return this.date; } - getType(): MVDHosting.NotificationType { + getType(): MVDHosting.ZoweNotificationType { return this.type; } + + getPlugin(): string { + return this.plugin; + + } } diff --git a/base/src/plugin-manager/plugin-manager.ts b/base/src/plugin-manager/plugin-manager.ts index e8879d4..148671d 100644 --- a/base/src/plugin-manager/plugin-manager.ts +++ b/base/src/plugin-manager/plugin-manager.ts @@ -17,6 +17,7 @@ export class PluginManager { private static pluginsById:Map = new Map(); private static parsePluginDefinitions(pluginData: any): Plugin[] { + console.log(pluginData) if (pluginData["pluginDefinitions"] != null) { const pluginDefinitions: any[] = pluginData["pluginDefinitions"]; const plugins = pluginDefinitions.map(definition => { @@ -41,10 +42,12 @@ export class PluginManager { } static getPlugin(id:string):ZLUX.Plugin|undefined { + console.log(this.pluginsById) return PluginManager.pluginsById.get(id); } static loadPlugins(pluginType?: ZLUX.PluginType): Promise { + // console.log(pluginType) return new Promise((resolve, reject) => { var request = new XMLHttpRequest(); request.onreadystatechange = function () { @@ -66,6 +69,7 @@ export class PluginManager { } } }; + // request.open("GET", ZoweZLUX.uriBroker.pluginListUri(), true); request.open("GET", ZoweZLUX.uriBroker.pluginListUri(pluginType), true); request.send(); }); diff --git a/base/src/plugin-manager/plugin.ts b/base/src/plugin-manager/plugin.ts index 9582349..baea09d 100644 --- a/base/src/plugin-manager/plugin.ts +++ b/base/src/plugin-manager/plugin.ts @@ -18,6 +18,8 @@ function parsePluginType(value: string): ZLUX.PluginType | null { return ZLUX.PluginType.Desktop; case "application": return ZLUX.PluginType.Application; + case "bootstrap": + return ZLUX.PluginType.Bootstrap; default: return null; } @@ -32,7 +34,6 @@ export abstract class Plugin implements ZLUX.Plugin { static parsePluginDefinition(definition: any): Plugin { const apiVersion = new SemanticVersion(definition.apiVersion); - switch (apiVersion.major) { case 0://beta return new Plugin_0(definition); diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 511641c..9ca4864 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -180,7 +180,8 @@ declare namespace ZLUX { const enum PluginType { Desktop = "desktop", - Application = "application" + Application = "application", + Bootstrap = "bootstrap" } interface Plugin { @@ -716,7 +717,7 @@ declare class ZoweZLUXResources { static logger: ZLUX.Logger; static registry: ZLUX.Registry; //previously was NotificationManager - static notificationManager: any; + static zoweNotificationManager: any; static globalization: ZLUX.Globalization; } diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index cc5cfa5..ff2e15c 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -18,10 +18,12 @@ declare namespace MVDHosting { ApplicationManagerToken = "com.rs.mvd.hosting.application-manager", ViewportManagerToken = "com.rs.mvd.hosting.viewport-manager", PluginManagerToken = "com.rs.mvd.hosting.plugin-manager", - AuthenticationManagerToken = "com.rs.mvd.hosting.authentication-manager" + AuthenticationManagerToken = "com.rs.mvd.hosting.authentication-manager", + ZoweNotificationManagerToken = "com.rs.mvd.hosting.zowe-notification-manager", + } - export const enum NotificationType { + export const enum ZoweNotificationType { System = 1, Application = 2 } @@ -89,17 +91,21 @@ declare namespace MVDHosting { performLogin(username: string, password: string): Observable; } - export interface NotificationManagerInterface { - push(notification: Notification): void; - pop(): Notification | void; - getAll(): Notification[] | void; - getAllByCategory(type: MVDHosting.NotificationType): Notification[] | void; + export interface ZoweNotificationManagerInterface { + setURL(url: string): void; + getURL(): string; + push(notification: ZoweNotification): void; + pop(): ZoweNotification | void; + getAll(): ZoweNotification[] | void; + getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; - addMessageHandler(object: NotificationWatcher): void; + getCountTest(): void; + addMessageHandler(object: ZoweNotificationWatcher): void; } - export interface NotificationWatcher { + export interface ZoweNotificationWatcher { handleMessageAdded(): void; + handleMessageAddedTest(data: any): void; } } From 7af7ae6178a78df8fc6d79cebcb0f04ceafbf650 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Mon, 26 Aug 2019 16:37:42 -0400 Subject: [PATCH 14/27] commiting to test on z Signed-off-by: Suneeth Keerthy --- base/src/notification-manager/notification-manager.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index 59a75ec..0c650c2 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -61,15 +61,15 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag this.ws.onmessage = function(message) { console.log("123hey") console.log(message) - _this.updateStuff(message); + _this.updateStuff(JSON.parse(message.data)); } // this.ws.send("test") } - updateStuff(message: MessageEvent) { + updateStuff(message: any) { console.log(message) for (let i = 0; i < this.handlers.length; i++) { - this.handlers[i].handleMessageAddedTest(message.data); + this.handlers[i].handleMessageAddedTest(message); } } @@ -109,7 +109,7 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag for (let i = 0; i < this.handlers.length; i++) { this.handlers[i].handleMessageAdded(); } - this.ws.send("message") + this.ws.send(JSON.stringify(notification)) } pop(): ZoweNotification | void { From d8860b4296852f15fce339a98698ea5f7965cce2 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Wed, 28 Aug 2019 14:18:37 -0400 Subject: [PATCH 15/27] Fixed things for notification manager Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 79 ++++++------------- base/src/notification-manager/notification.ts | 9 ++- base/src/plugin-manager/plugin-manager.ts | 4 - base/src/plugin-manager/plugin.ts | 1 + interface/src/mvd-hosting.d.ts | 8 +- 5 files changed, 35 insertions(+), 66 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index 0c650c2..e8b1e9e 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -15,61 +15,31 @@ import { ZoweNotification } from './notification'; export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManagerInterface { private notificationCache: any[]; + private testCache: any[]; private handlers: MVDHosting.ZoweNotificationWatcher[]; private ws: WebSocket; public url: string; - host: any; - port: any; - securityType: any; - connectionSettings: any; - modType: any; - row: any; - column: any; - selectedCodepage: any; - - constructor() { this.notificationCache = new Array(); + this.testCache = new Array(); this.handlers = new Array(); - // console.log(ZoweZLUX) - // let test: MVDHosting.DesktopPluginDefinition; - - const myHost = window.location.host; - const protocol = window.location.protocol; - const wsProtocol = (protocol === 'https:') ? 'wss:' : 'ws:'; - let computedURL:string = `${wsProtocol}//${myHost}/plugins/org.zowe.zlux.bootstrap/services/adminnotificationsdata/`; - console.log(computedURL) - this.connectionSettings = { - host: this.host, - port: this.port, - security: { - type: this.securityType - }, - deviceType: Number(this.modType), - alternateHeight: this.row, - alternateWidth: this.column, - charsetName: this.selectedCodepage - } } setURL(url: string){ this.url = url; this.ws = new WebSocket(url); - console.log("hey123") var _this = this; this.ws.onmessage = function(message) { - console.log("123hey") console.log(message) + _this.testCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) _this.updateStuff(JSON.parse(message.data)); } - // this.ws.send("test") } updateStuff(message: any) { - console.log(message) for (let i = 0; i < this.handlers.length; i++) { - this.handlers[i].handleMessageAddedTest(message); + this.handlers[i].handleMessageAddedTest(message, this.testCache.length -1); } } @@ -79,9 +49,7 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag ngOnInit() { - console.log("yyya") this.ws.onmessage = function () { - console.log("test") // Do something? } @@ -91,28 +59,19 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } } - // sendmessage(notification: ZoweNotification): void { - - // } - push(notification: ZoweNotification): void { - // let pluginTest = new Plugin() - // console.log(pluginTest) - // let pluginTest: ZLUX.PluginType = ZLUX.PluginType.Desktop - // console.log(ZoweZLUX.uriBroker.pluginListUri(pluginTest)) - // }; - // console.log(ZoweZLUX.pluginManager.getDesktopPlugin()) - //.findPluginDefinition("org.zowe.zlux.bootstrap") - // console.log(ZoweZLUX.uriBroker.pluginWSUri(plugin, 'adminnotificationdata', '')) - console.log(this.handlers) - this.notificationCache.push(notification); - for (let i = 0; i < this.handlers.length; i++) { - this.handlers[i].handleMessageAdded(); - } + // this.notificationCache.push(notification); + // for (let i = 0; i < this.handlers.length; i++) { + // this.handlers[i].handleMessageAdded(); + // } + // let index = this.notificationCache.indexOf(notification) + // console.log(index) + // console.log({'index': index, notification}) this.ws.send(JSON.stringify(notification)) } pop(): ZoweNotification | void { + console.log('does this ever get called?') let n = this.notificationCache.pop(); for (let i = 0; i < this.handlers.length; i++) { this.handlers[i].handleMessageAdded(); @@ -120,8 +79,14 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag return n; } + removeFromCache(index: number): void{ + console.log('doesnt this work') + // this.notificationCache.splice(index, 1) + this.testCache.splice(index, 1) + } + getAll(): ZoweNotification[] { - let copy: ZoweNotification[] = this.notificationCache.slice(0); + let copy: ZoweNotification[] = this.testCache.slice(0); /* NgFor is going from first element. We need to start from the end to show the most recent notifications first. It would make more sense to just pop all elements from notification cache, but if we closed the app, they'd all be gone. @@ -154,10 +119,12 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } getCount(): number { - return this.notificationCache.length; + return this.testCache.length; } - getCountTest(): void { + test(): void { + console.log(this.notificationCache) + console.log(this.testCache) } addMessageHandler(object: MVDHosting.ZoweNotificationWatcher) { diff --git a/base/src/notification-manager/notification.ts b/base/src/notification-manager/notification.ts index bdd13d2..a41579e 100644 --- a/base/src/notification-manager/notification.ts +++ b/base/src/notification-manager/notification.ts @@ -15,12 +15,16 @@ export class ZoweNotification { private date: Date; private type: MVDHosting.ZoweNotificationType; private plugin: string; + private config: any; - constructor(message: string, type: MVDHosting.ZoweNotificationType, plugin: string) { + constructor(message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { this.message = message; this.type = type; this.date = new Date(); this.plugin = plugin; + if (config) { + this.config = config + } } getMessage(): string { @@ -37,7 +41,10 @@ export class ZoweNotification { getPlugin(): string { return this.plugin; + } + getConfig(): any { + return this.config } } diff --git a/base/src/plugin-manager/plugin-manager.ts b/base/src/plugin-manager/plugin-manager.ts index 148671d..e8879d4 100644 --- a/base/src/plugin-manager/plugin-manager.ts +++ b/base/src/plugin-manager/plugin-manager.ts @@ -17,7 +17,6 @@ export class PluginManager { private static pluginsById:Map = new Map(); private static parsePluginDefinitions(pluginData: any): Plugin[] { - console.log(pluginData) if (pluginData["pluginDefinitions"] != null) { const pluginDefinitions: any[] = pluginData["pluginDefinitions"]; const plugins = pluginDefinitions.map(definition => { @@ -42,12 +41,10 @@ export class PluginManager { } static getPlugin(id:string):ZLUX.Plugin|undefined { - console.log(this.pluginsById) return PluginManager.pluginsById.get(id); } static loadPlugins(pluginType?: ZLUX.PluginType): Promise { - // console.log(pluginType) return new Promise((resolve, reject) => { var request = new XMLHttpRequest(); request.onreadystatechange = function () { @@ -69,7 +66,6 @@ export class PluginManager { } } }; - // request.open("GET", ZoweZLUX.uriBroker.pluginListUri(), true); request.open("GET", ZoweZLUX.uriBroker.pluginListUri(pluginType), true); request.send(); }); diff --git a/base/src/plugin-manager/plugin.ts b/base/src/plugin-manager/plugin.ts index baea09d..e114d0a 100644 --- a/base/src/plugin-manager/plugin.ts +++ b/base/src/plugin-manager/plugin.ts @@ -34,6 +34,7 @@ export abstract class Plugin implements ZLUX.Plugin { static parsePluginDefinition(definition: any): Plugin { const apiVersion = new SemanticVersion(definition.apiVersion); + switch (apiVersion.major) { case 0://beta return new Plugin_0(definition); diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index ff2e15c..02e8a31 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -18,9 +18,7 @@ declare namespace MVDHosting { ApplicationManagerToken = "com.rs.mvd.hosting.application-manager", ViewportManagerToken = "com.rs.mvd.hosting.viewport-manager", PluginManagerToken = "com.rs.mvd.hosting.plugin-manager", - AuthenticationManagerToken = "com.rs.mvd.hosting.authentication-manager", - ZoweNotificationManagerToken = "com.rs.mvd.hosting.zowe-notification-manager", - + AuthenticationManagerToken = "com.rs.mvd.hosting.authentication-manager" } export const enum ZoweNotificationType { @@ -99,13 +97,13 @@ declare namespace MVDHosting { getAll(): ZoweNotification[] | void; getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; - getCountTest(): void; + test(): void; addMessageHandler(object: ZoweNotificationWatcher): void; } export interface ZoweNotificationWatcher { handleMessageAdded(): void; - handleMessageAddedTest(data: any): void; + handleMessageAddedTest(data: any, index: number): void; } } From 72dd009b8ac98dcebcad427664570c3af1ed0b4d Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Wed, 28 Aug 2019 15:20:15 -0400 Subject: [PATCH 16/27] Cleaned some stuff up Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 31 ++++--------------- base/src/plugin-manager/plugin.ts | 1 - interface/src/mvd-hosting.d.ts | 4 +-- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index e8b1e9e..5cfe405 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -10,19 +10,15 @@ */ import { ZoweNotification } from './notification'; -// import { PluginManager } from '../../../../zlux-app-manager/virtual-desktop/src/app/plugin-manager/shared/plugin-manager' -// import { Plugin } from '../plugin-manager/plugin' export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManagerInterface { private notificationCache: any[]; - private testCache: any[]; private handlers: MVDHosting.ZoweNotificationWatcher[]; private ws: WebSocket; public url: string; constructor() { this.notificationCache = new Array(); - this.testCache = new Array(); this.handlers = new Array(); } @@ -32,14 +28,14 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag var _this = this; this.ws.onmessage = function(message) { console.log(message) - _this.testCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) + _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) _this.updateStuff(JSON.parse(message.data)); } } updateStuff(message: any) { for (let i = 0; i < this.handlers.length; i++) { - this.handlers[i].handleMessageAddedTest(message, this.testCache.length -1); + this.handlers[i].handleMessageAdded(message, this.notificationCache.length -1); } } @@ -60,33 +56,23 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } push(notification: ZoweNotification): void { - // this.notificationCache.push(notification); - // for (let i = 0; i < this.handlers.length; i++) { - // this.handlers[i].handleMessageAdded(); - // } - // let index = this.notificationCache.indexOf(notification) - // console.log(index) - // console.log({'index': index, notification}) this.ws.send(JSON.stringify(notification)) } pop(): ZoweNotification | void { - console.log('does this ever get called?') let n = this.notificationCache.pop(); for (let i = 0; i < this.handlers.length; i++) { - this.handlers[i].handleMessageAdded(); + // this.handlers[i].handleMessageAdded(); } return n; } removeFromCache(index: number): void{ - console.log('doesnt this work') - // this.notificationCache.splice(index, 1) - this.testCache.splice(index, 1) + this.notificationCache.splice(index, 1) } getAll(): ZoweNotification[] { - let copy: ZoweNotification[] = this.testCache.slice(0); + let copy: ZoweNotification[] = this.notificationCache.slice(0); /* NgFor is going from first element. We need to start from the end to show the most recent notifications first. It would make more sense to just pop all elements from notification cache, but if we closed the app, they'd all be gone. @@ -119,12 +105,7 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } getCount(): number { - return this.testCache.length; - } - - test(): void { - console.log(this.notificationCache) - console.log(this.testCache) + return this.notificationCache.length; } addMessageHandler(object: MVDHosting.ZoweNotificationWatcher) { diff --git a/base/src/plugin-manager/plugin.ts b/base/src/plugin-manager/plugin.ts index e114d0a..baea09d 100644 --- a/base/src/plugin-manager/plugin.ts +++ b/base/src/plugin-manager/plugin.ts @@ -34,7 +34,6 @@ export abstract class Plugin implements ZLUX.Plugin { static parsePluginDefinition(definition: any): Plugin { const apiVersion = new SemanticVersion(definition.apiVersion); - switch (apiVersion.major) { case 0://beta return new Plugin_0(definition); diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index 02e8a31..e001055 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -97,13 +97,11 @@ declare namespace MVDHosting { getAll(): ZoweNotification[] | void; getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; - test(): void; addMessageHandler(object: ZoweNotificationWatcher): void; } export interface ZoweNotificationWatcher { - handleMessageAdded(): void; - handleMessageAddedTest(data: any, index: number): void; + handleMessageAdded(data: any, index: number): void; } } From 328f2cbddc8beac06fe2bb35961c67793acb6ad9 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Fri, 30 Aug 2019 09:09:12 -0400 Subject: [PATCH 17/27] commit to test on z Signed-off-by: Suneeth Keerthy --- base/src/notification-manager/notification-manager.ts | 11 ++++++++++- base/src/notification-manager/notification.ts | 8 +++++++- interface/src/mvd-hosting.d.ts | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index 5cfe405..c8e737e 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -22,8 +22,10 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag this.handlers = new Array(); } - setURL(url: string){ + _setURL(url: string){ + //set url only once this.url = url; + console.log("@@@@@@@@@@@@@@@@@@@@@@@2") this.ws = new WebSocket(url); var _this = this; this.ws.onmessage = function(message) { @@ -31,6 +33,12 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) _this.updateStuff(JSON.parse(message.data)); } + this.ws.onclose = function() { + _this.ws = new WebSocket(this.url) + } + this.ws.onerror = function() { + _this.ws = new WebSocket(this.url) + } } updateStuff(message: any) { @@ -56,6 +64,7 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } push(notification: ZoweNotification): void { + console.log(notification) this.ws.send(JSON.stringify(notification)) } diff --git a/base/src/notification-manager/notification.ts b/base/src/notification-manager/notification.ts index a41579e..a0abd4e 100644 --- a/base/src/notification-manager/notification.ts +++ b/base/src/notification-manager/notification.ts @@ -16,8 +16,10 @@ export class ZoweNotification { private type: MVDHosting.ZoweNotificationType; private plugin: string; private config: any; + private title: string; - constructor(message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { + constructor(title: string, message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { + this.title = title; this.message = message; this.type = type; this.date = new Date(); @@ -27,6 +29,10 @@ export class ZoweNotification { } } + getTitle(): string { + return this.title; + } + getMessage(): string { return this.message; } diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index e001055..d293952 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -90,7 +90,7 @@ declare namespace MVDHosting { } export interface ZoweNotificationManagerInterface { - setURL(url: string): void; + _setURL(url: string): void; getURL(): string; push(notification: ZoweNotification): void; pop(): ZoweNotification | void; From 12267c18b4455f39c37a81b5eb05a6d9e3012e5f Mon Sep 17 00:00:00 2001 From: Leanid Astrakou Date: Fri, 30 Aug 2019 13:28:39 -0400 Subject: [PATCH 18/27] Added requestWindowFocus method to interface Signed-off-by: Leanid Astrakou --- interface/src/mvd-window-management.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/mvd-window-management.d.ts b/interface/src/mvd-window-management.d.ts index 4db712a..60a8fca 100644 --- a/interface/src/mvd-window-management.d.ts +++ b/interface/src/mvd-window-management.d.ts @@ -25,6 +25,7 @@ declare namespace MVDWindowManagement { showWindow(windowId: MVDWindowManagement.WindowId): void; closeWindow(windowId: MVDWindowManagement.WindowId): void; closeAllWindows():void; + requestWindowFocus(windowId: MVDWindowManagement.WindowId): boolean; } } From 809cffb41551e99306693efc9ae265efb98f94ee Mon Sep 17 00:00:00 2001 From: Todd Wellman Date: Thu, 5 Sep 2019 12:02:49 -0400 Subject: [PATCH 19/27] address review comments and add option for fail on promise error or not Signed-off-by: Todd Wellman --- base/src/dispatcher/dispatcher.ts | 44 ++++++++++++++++--------- base/src/dispatcher/event-registrar.ts | 45 ++++++++++++++------------ interface/src/index.d.ts | 4 +-- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/base/src/dispatcher/dispatcher.ts b/base/src/dispatcher/dispatcher.ts index 782cae1..b0c48ab 100644 --- a/base/src/dispatcher/dispatcher.ts +++ b/base/src/dispatcher/dispatcher.ts @@ -87,7 +87,7 @@ export class Dispatcher implements ZLUX.Dispatcher { /* dispatcher created early on - refering to logger from window object as a result */ this.log = logger.makeComponentLogger("ZLUX.Dispatcher"); this.runHeartbeat(); - this.registerEventListener("Launch", this.launchApp, "Dispatcher"); + this.registerEventListener("Launch", this.launchApp, "ZLUX.Dispatcher"); window.addEventListener("message", this.iframeMessageHandler, false); } @@ -602,22 +602,22 @@ export class Dispatcher implements ZLUX.Dispatcher { callInstance(eventName: string, appInstanceId:string, data: Object) { var pluginId = this.findPluginIdFromInstanceId(appInstanceId); - return this.call(eventName, pluginId, appInstanceId, data); + return this.call(eventName, pluginId, appInstanceId, data, true, true); } callAny(eventName: string, pluginId:string, data: Object) { - return this.call(eventName, pluginId, null, data, true); + return this.call(eventName, pluginId, null, data, true, true); } - callAll(eventName: string, pluginId:string, data: Object) { - return this.call(eventName, pluginId, null, data); + callAll(eventName: string, pluginId:string, data: Object, failOnError: boolean = false) { + return this.call(eventName, pluginId, null, data, false, failOnError); } - callEveryone(eventName: string, data: Object) { - return this.call(eventName, null, null, data); + callEveryone(eventName: string, data: Object, failOnError: boolean = false) { + return this.call(eventName, null, null, data, false, failOnError); } - call(eventName: string, pluginId:string | null, appInstanceId:string | null, data: Object, singleEvent: boolean = false) { + call(eventName: string, pluginId:string | null, appInstanceId:string | null, data: Object, singleEvent: boolean, failOnError: boolean) { return new Promise((resolve, reject) => { let effectiveEventNames = this.eventRegistry.findEventCodes(eventName, pluginId, appInstanceId); if (effectiveEventNames) { @@ -629,7 +629,7 @@ export class Dispatcher implements ZLUX.Dispatcher { data: data, return: null } - if (this.isIframe(effectiveEventNames[i].split("-")[effectiveEventNames[i].split("-").length-2])){ + if (this.isIframe(effectiveEventNames[i].split("_")[effectiveEventNames[i].split("_").length-2])){ promises.push(this.postMessageCallbackWrapper(effectiveEventNames[i], eventDetail)) } else { evt = new CustomEvent(effectiveEventNames[i], { @@ -642,9 +642,13 @@ export class Dispatcher implements ZLUX.Dispatcher { break; } } - Promise.all(promises).then((results) => { + this.allSettled(promises).then((results) => { results.forEach((element) => { - resultList.push(element) + if (element.state === 'fulfilled') { + resultList.push(element.value) + } else if(failOnError) { + reject(element.value) + } }) resolve((resultList.length === 1 ? resultList[0] : resultList)) }).catch((err) => { @@ -656,10 +660,18 @@ export class Dispatcher implements ZLUX.Dispatcher { }) } + allSettled(promises: Promise[]) { + let wrappedPromises = promises.map(p => Promise.resolve(p) + .then( + val => ({ state: 'fulfilled', value: val }), + err => ({ state: 'rejected', value: err }))); + return Promise.all(wrappedPromises); +} + findPluginIdFromInstanceId(instanceId: string) { let result = null; - if (instanceId === "Dispatcher") { - result = "Dispatcher"; + if (instanceId === "ZLUX.Dispatcher") { + result = "ZLUX.Dispatcher"; } else { this.instancesForTypes.forEach((value, key) => { value.forEach((element) => { @@ -720,13 +732,13 @@ export class Dispatcher implements ZLUX.Dispatcher { postMessageCallbackWrapper = (fullEventName:string, eventPayload: any) => { return new Promise((fullresolve) => { - let nameList:Array = fullEventName.split("-") + let nameList:Array = fullEventName.split("_") let instanceId = nameList[nameList.length-2]; var returnListener: EventListenerOrEventListenerObject; new Promise((resolve) => { returnListener = (evt: MessageEvent) => { - if (evt.data.messageType === "return" && evt.data.arguments.appId === instanceId){ + if (evt.data.messageType === "return" && evt.data.arguments.appId.toString() === instanceId){ resolve(evt.data.arguments.returnValue) } } @@ -752,7 +764,7 @@ export class Dispatcher implements ZLUX.Dispatcher { break; case "CallEvent": var context = this - this.call(args.eventName, args.pluginId, args.appId, args.data, args.singleEvent).then((results) => { + this.call(args.eventName, args.pluginId, args.appId, args.data, args.singleEvent, args.failOnError).then((results) => { if (context.postMessageCallback) { context.postMessageCallback(evt.source.instanceId, {dispatchType: 'return', dispatchData: {return: results}}) } diff --git a/base/src/dispatcher/event-registrar.ts b/base/src/dispatcher/event-registrar.ts index 5388928..7bc9c59 100644 --- a/base/src/dispatcher/event-registrar.ts +++ b/base/src/dispatcher/event-registrar.ts @@ -2,50 +2,53 @@ export class EventRegistrar { private eventsList: Map>> = new Map(); + private DEFAULT_UNIQUE_ID_LENGTH: number = 5; + private chars:string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + private charsLength: number = 62; - createFullEventName(eventName:string, instanceId: string, length: number) { - let result = `${instanceId}-${eventName}-`; - let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + createFullEventId(eventType:string, instanceId: string, length: number) { + let result = `${eventType}_${instanceId}_`; + for (var i = 0; i < length; i++) { - result += chars.charAt(Math.floor(Math.random() * chars.length)); + result += this.chars.charAt(Math.floor(Math.random() * this.charsLength)); } return result; } - findIndexOfEventName(eventName:string, appInstanceId: string, eventNameList: Array) { + findIndexOfEvent(eventType:string, appInstanceId: string, eventNameList: Array) { for (var i = 0; i < eventNameList.length; i++) { - if (eventNameList[i].startsWith(`${eventName}-${appInstanceId}-`)) { + if (eventNameList[i].startsWith(`${eventType}_${appInstanceId}_`)) { return i; } } return null; } - registerEvent(eventName: string, pluginId:string, appInstanceId: string) { - let name = this.createFullEventName(appInstanceId, eventName, 5); - if (this.eventsList.has(eventName)) { - let hold = this.eventsList.get(eventName); + registerEvent(eventType: string, pluginId:string, appInstanceId: string) { + let eventId = this.createFullEventId(eventType, appInstanceId, this.DEFAULT_UNIQUE_ID_LENGTH); + if (this.eventsList.has(eventType)) { + let hold = this.eventsList.get(eventType); if (hold) { var listenerNames = hold.get(pluginId); if (listenerNames) { - listenerNames.push(name); + listenerNames.push(eventId); } else { - hold.set(pluginId, [name]); + hold.set(pluginId, [eventId]); } } } else { var newMap = new Map(); - newMap.set(pluginId, [name]); - this.eventsList.set(eventName, newMap); + newMap.set(pluginId, [eventId]); + this.eventsList.set(eventType, newMap); } } - deregisterEvent(eventName: string, pluginId:string, appInstanceId: string) { - var hold = this.eventsList.get(eventName); + deregisterEvent(eventType: string, pluginId:string, appInstanceId: string) { + var hold = this.eventsList.get(eventType); if (hold) { let listenerNames = hold.get(pluginId); if (listenerNames) { - var index = this.findIndexOfEventName(eventName, appInstanceId, listenerNames); + var index = this.findIndexOfEvent(eventType, appInstanceId, listenerNames); if (index != null) { listenerNames.splice(index, 1); } @@ -54,19 +57,19 @@ export class EventRegistrar { } } if (hold.size == 0) { - this.eventsList.delete(eventName); + this.eventsList.delete(eventType); } } } - findEventCodes(eventName: string, pluginId: string | null, appInstanceId: string | null): string[] { - let event = this.eventsList.get(eventName); + findEventCodes(eventType: string, pluginId: string | null, appInstanceId: string | null): string[] { + let event = this.eventsList.get(eventType); if (event) { if (pluginId) { let plugin = event.get(pluginId); if (plugin) { if (appInstanceId) { - var index = this.findIndexOfEventName(eventName, appInstanceId, plugin); + var index = this.findIndexOfEvent(eventType, appInstanceId, plugin); return (index != null? [plugin[index]] : []); } else { return plugin; diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index fda4ead..f2db96f 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -40,8 +40,8 @@ declare namespace ZLUX { addPendingIframe(plugin:ZLUX.Plugin, launchMetadata: any): void; callInstance(eventName: string, appInstanceId:string, data: Object): Promise; callAny(eventName: string, pluginId:string, data: Object): Promise; - callAll(eventName: string, pluginId:string, data: Object): Promise; - callEveryone(eventName: string, data: Object): Promise; + callAll(eventName: string, pluginId:string, data: Object, failOnError: boolean): Promise; + callEveryone(eventName: string, data: Object, failOnError: boolean): Promise; registerEventListener(eventName: string, callback: EventListenerOrEventListenerObject | null, appId: string): void; deregisterEventListener(eventName: string, callback: EventListenerOrEventListenerObject | null, appId: string, pluginId:string): void; makeAction(id: string, defaultName: string, targetMode: ActionTargetMode, type: ActionType, targetPluginID: string, primaryArgument: any): Action; From c9ab12b515f9b967e7330272eed6c81e65311236 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Thu, 5 Sep 2019 16:10:05 -0400 Subject: [PATCH 20/27] Cleaned up some stuff Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 17 +++++++---------- interface/src/index.d.ts | 2 +- interface/src/mvd-hosting.d.ts | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index c8e737e..ae47c1f 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -25,11 +25,9 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag _setURL(url: string){ //set url only once this.url = url; - console.log("@@@@@@@@@@@@@@@@@@@@@@@2") this.ws = new WebSocket(url); var _this = this; this.ws.onmessage = function(message) { - console.log(message) _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) _this.updateStuff(JSON.parse(message.data)); } @@ -64,17 +62,16 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } push(notification: ZoweNotification): void { - console.log(notification) this.ws.send(JSON.stringify(notification)) } - pop(): ZoweNotification | void { - let n = this.notificationCache.pop(); - for (let i = 0; i < this.handlers.length; i++) { - // this.handlers[i].handleMessageAdded(); - } - return n; - } + // pop(): ZoweNotification | void { + // let n = this.notificationCache.pop(); + // for (let i = 0; i < this.handlers.length; i++) { + // // this.handlers[i].handleMessageAdded(); + // } + // return n; + // } removeFromCache(index: number): void{ this.notificationCache.splice(index, 1) diff --git a/interface/src/index.d.ts b/interface/src/index.d.ts index 9ca4864..e2569ac 100644 --- a/interface/src/index.d.ts +++ b/interface/src/index.d.ts @@ -717,7 +717,7 @@ declare class ZoweZLUXResources { static logger: ZLUX.Logger; static registry: ZLUX.Registry; //previously was NotificationManager - static zoweNotificationManager: any; + static notificationManager: any; static globalization: ZLUX.Globalization; } diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index d293952..523cfc3 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -93,7 +93,7 @@ declare namespace MVDHosting { _setURL(url: string): void; getURL(): string; push(notification: ZoweNotification): void; - pop(): ZoweNotification | void; + // pop(): ZoweNotification | void; getAll(): ZoweNotification[] | void; getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; From b329c5f3a39f148fd6a5e74a15f5b3989ff1c810 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Fri, 6 Sep 2019 13:25:05 -0400 Subject: [PATCH 21/27] Cleaning up some stuff Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 29 +++---------------- interface/src/mvd-hosting.d.ts | 3 +- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index ae47c1f..490b697 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -15,21 +15,20 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag private notificationCache: any[]; private handlers: MVDHosting.ZoweNotificationWatcher[]; private ws: WebSocket; - public url: string; + private url: string; constructor() { this.notificationCache = new Array(); this.handlers = new Array(); } - _setURL(url: string){ - //set url only once + _setURL(url: string): void { this.url = url; this.ws = new WebSocket(url); var _this = this; this.ws.onmessage = function(message) { _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) - _this.updateStuff(JSON.parse(message.data)); + _this.updateHandlers(JSON.parse(message.data)); } this.ws.onclose = function() { _this.ws = new WebSocket(this.url) @@ -39,7 +38,7 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } } - updateStuff(message: any) { + updateHandlers(message: any): void { for (let i = 0; i < this.handlers.length; i++) { this.handlers[i].handleMessageAdded(message, this.notificationCache.length -1); } @@ -49,30 +48,10 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag return this.url; } - ngOnInit() { - - this.ws.onmessage = function () { - // Do something? - } - - - this.ws.onerror = function () { - this.close(); - } - } - push(notification: ZoweNotification): void { this.ws.send(JSON.stringify(notification)) } - // pop(): ZoweNotification | void { - // let n = this.notificationCache.pop(); - // for (let i = 0; i < this.handlers.length; i++) { - // // this.handlers[i].handleMessageAdded(); - // } - // return n; - // } - removeFromCache(index: number): void{ this.notificationCache.splice(index, 1) } diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index 523cfc3..c623b82 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -93,7 +93,8 @@ declare namespace MVDHosting { _setURL(url: string): void; getURL(): string; push(notification: ZoweNotification): void; - // pop(): ZoweNotification | void; + updateHandlers(message: any): void; + removeFromCache(index: number): void; getAll(): ZoweNotification[] | void; getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; From 2bacb67f87ec6bfb19d578210a2775a8404a4139 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Fri, 6 Sep 2019 16:25:58 -0400 Subject: [PATCH 22/27] Fixed Seans Requests Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 36 ++++++++++--------- interface/src/mvd-hosting.d.ts | 2 -- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index 490b697..d96fec4 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -11,11 +11,12 @@ import { ZoweNotification } from './notification'; +let urlSet: boolean = false; + export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManagerInterface { private notificationCache: any[]; private handlers: MVDHosting.ZoweNotificationWatcher[]; private ws: WebSocket; - private url: string; constructor() { this.notificationCache = new Array(); @@ -23,19 +24,22 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } _setURL(url: string): void { - this.url = url; - this.ws = new WebSocket(url); - var _this = this; - this.ws.onmessage = function(message) { - _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) - _this.updateHandlers(JSON.parse(message.data)); - } - this.ws.onclose = function() { - _this.ws = new WebSocket(this.url) - } - this.ws.onerror = function() { - _this.ws = new WebSocket(this.url) + if (!urlSet) { + this.ws = new WebSocket(url); + var _this = this; + this.ws.onmessage = function(message) { + _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) + _this.updateHandlers(JSON.parse(message.data)); + } + this.ws.onclose = () => { + _this.ws = new WebSocket(url) + } + this.ws.onerror = () => { + _this.ws = new WebSocket(url) + } + urlSet = true; } + } updateHandlers(message: any): void { @@ -44,9 +48,9 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } } - getURL() { - return this.url; - } + // getURL() { + // return this.url; + // } push(notification: ZoweNotification): void { this.ws.send(JSON.stringify(notification)) diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index c623b82..acbbb12 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -90,8 +90,6 @@ declare namespace MVDHosting { } export interface ZoweNotificationManagerInterface { - _setURL(url: string): void; - getURL(): string; push(notification: ZoweNotification): void; updateHandlers(message: any): void; removeFromCache(index: number): void; From 62e552cb0ed357371c539837a5dcfbccbcc07795 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Thu, 12 Sep 2019 17:16:17 -0400 Subject: [PATCH 23/27] Restructured the storage of the notifications Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 58 +++++++++++++------ base/src/notification-manager/notification.ts | 10 +++- interface/src/mvd-hosting.d.ts | 9 ++- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index d96fec4..4decf0f 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -14,32 +14,40 @@ import { ZoweNotification } from './notification'; let urlSet: boolean = false; export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManagerInterface { - private notificationCache: any[]; + public notificationCache: any[]; private handlers: MVDHosting.ZoweNotificationWatcher[]; - private ws: WebSocket; + private restUrl: string; + public idCount: number; constructor() { this.notificationCache = new Array(); this.handlers = new Array(); + this.idCount = 0; } - _setURL(url: string): void { + _setURL(wsUrl: string, restUrl: string): void { if (!urlSet) { - this.ws = new WebSocket(url); + this.restUrl = restUrl; + let ws = new WebSocket(wsUrl); var _this = this; - this.ws.onmessage = function(message) { + ws.onmessage = function(message) { _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) - _this.updateHandlers(JSON.parse(message.data)); + _this.updateHandlers(JSON.parse(message.data)['notification']); } - this.ws.onclose = () => { - _this.ws = new WebSocket(url) + ws.onclose = () => { + ws = new WebSocket(wsUrl) } - this.ws.onerror = () => { - _this.ws = new WebSocket(url) + ws.onerror = () => { + ws = new WebSocket(wsUrl) } urlSet = true; } + } + createNotification(title: string, message: string, type: number, plugin: string, config?: any): ZoweNotification { + let notification = new ZoweNotification(this.idCount, title, message, type, plugin, config) + this.idCount = this.idCount + 1; + return notification; } updateHandlers(message: any): void { @@ -48,16 +56,28 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } } - // getURL() { - // return this.url; - // } + notify(notification: ZoweNotification): number { + this.notificationCache.push(notification); + this.updateHandlers(notification) + return this.notificationCache.length; + } - push(notification: ZoweNotification): void { - this.ws.send(JSON.stringify(notification)) + serverNotify(message: any): any { + return fetch(this.restUrl, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(message) + }) } - removeFromCache(index: number): void{ - this.notificationCache.splice(index, 1) + dismissNotification(id: number) { + this.notificationCache.splice(this.notificationCache.findIndex(x => x.id === id), 1) + for (let i = 0; i < this.handlers.length; i++) { + this.handlers[i].handleMessageRemoved(id); + } } getAll(): ZoweNotification[] { @@ -100,6 +120,10 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag addMessageHandler(object: MVDHosting.ZoweNotificationWatcher) { this.handlers.push(object); } + + removeMessageHandler(object: MVDHosting.ZoweNotificationWatcher) { + this.handlers.splice(this.handlers.findIndex(x => x === object), 1) + } } diff --git a/base/src/notification-manager/notification.ts b/base/src/notification-manager/notification.ts index a0abd4e..c80c06b 100644 --- a/base/src/notification-manager/notification.ts +++ b/base/src/notification-manager/notification.ts @@ -17,8 +17,10 @@ export class ZoweNotification { private plugin: string; private config: any; private title: string; + private id: number; - constructor(title: string, message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { + constructor(id: number, title: string, message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { + this.id = id; this.title = title; this.message = message; this.type = type; @@ -50,7 +52,11 @@ export class ZoweNotification { } getConfig(): any { - return this.config + return this.config; + } + + getId(): any { + return this.id; } } diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index acbbb12..28df3f2 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -90,17 +90,22 @@ declare namespace MVDHosting { } export interface ZoweNotificationManagerInterface { - push(notification: ZoweNotification): void; + createNotification(title: string, message: string, type: number, plugin: string, config?: any): ZoweNotification; + notify(notification: ZoweNotification): number; + serverNotify(message: any): void; updateHandlers(message: any): void; - removeFromCache(index: number): void; + dismissNotification(index: number): void; getAll(): ZoweNotification[] | void; getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; + removeAll(): void; addMessageHandler(object: ZoweNotificationWatcher): void; + removeMessageHandler(object: ZoweNotificationWatcher): void; } export interface ZoweNotificationWatcher { handleMessageAdded(data: any, index: number): void; + handleMessageRemoved(id: number): void; } } From 099a09c31d076db0440e34d4e38784b574e4b84d Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Fri, 13 Sep 2019 16:21:48 -0400 Subject: [PATCH 24/27] Fix some things Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 17 ++++++++--------- base/src/notification-manager/notification.ts | 7 +------ interface/src/mvd-hosting.d.ts | 5 ++--- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index 4decf0f..d24dd70 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -15,14 +15,16 @@ let urlSet: boolean = false; export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManagerInterface { public notificationCache: any[]; + public notificationCache2: any[]; private handlers: MVDHosting.ZoweNotificationWatcher[]; private restUrl: string; - public idCount: number; + public idCount2: number; constructor() { this.notificationCache = new Array(); + this.notificationCache2 = new Array(); this.handlers = new Array(); - this.idCount = 0; + this.idCount2 = 0; } _setURL(wsUrl: string, restUrl: string): void { @@ -44,15 +46,12 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } } - createNotification(title: string, message: string, type: number, plugin: string, config?: any): ZoweNotification { - let notification = new ZoweNotification(this.idCount, title, message, type, plugin, config) - this.idCount = this.idCount + 1; - return notification; - } - updateHandlers(message: any): void { + let notif = {'id': this.idCount2, 'notification': message} + this.notificationCache2.push(notif); + this.idCount2 = this.idCount2 + 1; for (let i = 0; i < this.handlers.length; i++) { - this.handlers[i].handleMessageAdded(message, this.notificationCache.length -1); + this.handlers[i].handleMessageAdded(notif); } } diff --git a/base/src/notification-manager/notification.ts b/base/src/notification-manager/notification.ts index c80c06b..fce76f5 100644 --- a/base/src/notification-manager/notification.ts +++ b/base/src/notification-manager/notification.ts @@ -17,10 +17,8 @@ export class ZoweNotification { private plugin: string; private config: any; private title: string; - private id: number; - constructor(id: number, title: string, message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { - this.id = id; + constructor(title: string, message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { this.title = title; this.message = message; this.type = type; @@ -55,9 +53,6 @@ export class ZoweNotification { return this.config; } - getId(): any { - return this.id; - } } diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index 28df3f2..3f17164 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -90,11 +90,10 @@ declare namespace MVDHosting { } export interface ZoweNotificationManagerInterface { - createNotification(title: string, message: string, type: number, plugin: string, config?: any): ZoweNotification; notify(notification: ZoweNotification): number; serverNotify(message: any): void; updateHandlers(message: any): void; - dismissNotification(index: number): void; + dismissNotification(id: number): void; getAll(): ZoweNotification[] | void; getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; @@ -104,7 +103,7 @@ declare namespace MVDHosting { } export interface ZoweNotificationWatcher { - handleMessageAdded(data: any, index: number): void; + handleMessageAdded(test: any): void; handleMessageRemoved(id: number): void; } } From 58df09270a9c0c8d3ea440347fd0351c43995dda Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Fri, 13 Sep 2019 16:46:13 -0400 Subject: [PATCH 25/27] Removed things Signed-off-by: Suneeth Keerthy --- .../notification-manager/notification-manager.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index d24dd70..620307f 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -15,16 +15,14 @@ let urlSet: boolean = false; export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManagerInterface { public notificationCache: any[]; - public notificationCache2: any[]; private handlers: MVDHosting.ZoweNotificationWatcher[]; private restUrl: string; - public idCount2: number; + public idCount: number; constructor() { this.notificationCache = new Array(); - this.notificationCache2 = new Array(); this.handlers = new Array(); - this.idCount2 = 0; + this.idCount = 0; } _setURL(wsUrl: string, restUrl: string): void { @@ -33,7 +31,6 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag let ws = new WebSocket(wsUrl); var _this = this; ws.onmessage = function(message) { - _this.notificationCache.push((JSON.parse(message.data)['notification']) as ZoweNotification) _this.updateHandlers(JSON.parse(message.data)['notification']); } ws.onclose = () => { @@ -47,9 +44,9 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } updateHandlers(message: any): void { - let notif = {'id': this.idCount2, 'notification': message} - this.notificationCache2.push(notif); - this.idCount2 = this.idCount2 + 1; + let notif = {'id': this.idCount, 'notification': message} + this.notificationCache.push(notif); + this.idCount = this.idCount + 1; for (let i = 0; i < this.handlers.length; i++) { this.handlers[i].handleMessageAdded(notif); } From 2bddfe6238c830843a09aafde2fc020bbe32d9b6 Mon Sep 17 00:00:00 2001 From: Suneeth Keerthy Date: Fri, 13 Sep 2019 16:51:57 -0400 Subject: [PATCH 26/27] Removed unneeded things Signed-off-by: Suneeth Keerthy --- .../notification-manager.ts | 29 ------------------- base/src/notification-manager/notification.ts | 10 +------ interface/src/mvd-hosting.d.ts | 2 -- 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/base/src/notification-manager/notification-manager.ts b/base/src/notification-manager/notification-manager.ts index 620307f..65c19d6 100644 --- a/base/src/notification-manager/notification-manager.ts +++ b/base/src/notification-manager/notification-manager.ts @@ -76,35 +76,6 @@ export class ZoweNotificationManager implements MVDHosting.ZoweNotificationManag } } - getAll(): ZoweNotification[] { - let copy: ZoweNotification[] = this.notificationCache.slice(0); - - /* NgFor is going from first element. We need to start from the end to show the most recent notifications first. - It would make more sense to just pop all elements from notification cache, but if we closed the app, they'd all be gone. - */ - copy.reverse(); - - return copy; - } - - getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] { - var filtered: ZoweNotification[] = []; - var i: number; - - for (i = 0; i < this.notificationCache.length; i++) { - if (this.notificationCache[i].getType() === type) { - filtered.push(this.notificationCache[i]); - } - } - - /* NgFor is going from first element. We need to start from the end to show the most recent notifications first. - It would make more sense to just pop all elements from notification cache, but if we closed the app, they'd all be gone. - */ - filtered.reverse(); - - return filtered; - } - removeAll(): void { this.notificationCache.length = 0; } diff --git a/base/src/notification-manager/notification.ts b/base/src/notification-manager/notification.ts index fce76f5..11d841d 100644 --- a/base/src/notification-manager/notification.ts +++ b/base/src/notification-manager/notification.ts @@ -15,18 +15,14 @@ export class ZoweNotification { private date: Date; private type: MVDHosting.ZoweNotificationType; private plugin: string; - private config: any; private title: string; - constructor(title: string, message: string, type: MVDHosting.ZoweNotificationType, plugin: string, config?: any) { + constructor(title: string, message: string, type: MVDHosting.ZoweNotificationType, plugin: string) { this.title = title; this.message = message; this.type = type; this.date = new Date(); this.plugin = plugin; - if (config) { - this.config = config - } } getTitle(): string { @@ -49,10 +45,6 @@ export class ZoweNotification { return this.plugin; } - getConfig(): any { - return this.config; - } - } diff --git a/interface/src/mvd-hosting.d.ts b/interface/src/mvd-hosting.d.ts index 3f17164..b5e056b 100644 --- a/interface/src/mvd-hosting.d.ts +++ b/interface/src/mvd-hosting.d.ts @@ -94,8 +94,6 @@ declare namespace MVDHosting { serverNotify(message: any): void; updateHandlers(message: any): void; dismissNotification(id: number): void; - getAll(): ZoweNotification[] | void; - getAllByCategory(type: MVDHosting.ZoweNotificationType): ZoweNotification[] | void; getCount(): number; removeAll(): void; addMessageHandler(object: ZoweNotificationWatcher): void; From 8bfc6eb9846cd6b38b32684b6441305d9adaf7e8 Mon Sep 17 00:00:00 2001 From: 1000TurquoisePogs <30730276+1000TurquoisePogs@users.noreply.github.com> Date: Sun, 15 Sep 2019 23:26:04 -0400 Subject: [PATCH 27/27] Create README.md Signed-off-by: 1000TurquoisePogs --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..b58555a --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +This program and the accompanying materials are +made available under the terms of the Eclipse Public License v2.0 which accompanies +this distribution, and is available at https://www.eclipse.org/legal/epl-v20.html + +SPDX-License-Identifier: EPL-2.0 + +Copyright Contributors to the Zowe Project. +# zlux-platform +This repository contains typescript interface definitions and some UI and web-library independent essential framework objects. +The code within here is needed and used by the Zowe's App Framework and specifically the web Desktop. +This repo does not get built directly, but its objects are build within [zlux-app-manager](https://github.com/zowe/zlux-app-manager) within the bootstrap directory. + +**To request features or report bugs, please use the issues page at the [zlux repo](https://github.com/zowe/zlux/issues) with the client infrastructure tag**