From cec32c6be43e41c2c2ffdad5e8fdf77d425c3f54 Mon Sep 17 00:00:00 2001 From: mwooten Date: Wed, 16 Feb 2022 13:14:09 -0500 Subject: [PATCH 1/2] Updates to webui files for wrc integ --- webui/src/css/app.css | 18 +- webui/src/js/main.js | 15 +- webui/src/js/path_mapping.json | 91 +++++++ webui/src/js/viewModels/model-design-view.js | 270 +++++++++++++------ webui/src/js/views/model-design-view.html | 12 +- 5 files changed, 324 insertions(+), 82 deletions(-) diff --git a/webui/src/css/app.css b/webui/src/css/app.css index 0877bc67a..bbea5f2aa 100644 --- a/webui/src/css/app.css +++ b/webui/src/css/app.css @@ -194,16 +194,32 @@ } /* container for model design view, currently text */ +.wkt-model-edit-design, +.wkt-model-code-view +{ + display: flex; + height: 100%; + width: 100%; +} + +.wkt-model-edit-design > a > img { + margin: 0 3px 0 0; + height: 24px; + width: 18px; +} + +/* +///MLW .wkt-model-edit-design { margin: 10px; } -/* container for model design view, currently text */ .wkt-model-code-view { display: flex; height: 100%; width: 100%; } +*/ /* the ace editor pane */ #model-editor { diff --git a/webui/src/js/main.js b/webui/src/js/main.js index 1bdcc5a4f..02e66d53e 100644 --- a/webui/src/js/main.js +++ b/webui/src/js/main.js @@ -40,9 +40,22 @@ 'corejs' : 'libs/corejs/shim', 'chai': 'libs/chai/chai-4.2.0', 'regenerator-runtime' : 'libs/regenerator-runtime/runtime', - 'ace': 'libs/ace/ace' + 'ace': 'libs/ace/ace', + 'wrc-translations': 'resources', + 'wrc-frontend': 'jet-composites/wrc-frontend/1.0.0', + 'wdt-model-builder': 'jet-composites/wrc-frontend/1.0.0', + 'cfe-navtree': 'jet-composites/cfe-navtree/1.0.0', + 'cfe-multi-select': 'jet-composites/cfe-multi-select/1.0.0', + 'cfe-property-list-editor': 'jet-composites/cfe-property-list-editor/1.0.0' } // endinjector + , config: { + ojL10n: { + merge: { + 'ojtranslations/nls/ojtranslations': 'resources/nls/frontend' + } + } + } } ); }()); diff --git a/webui/src/js/path_mapping.json b/webui/src/js/path_mapping.json index fc550ee03..fead04c1c 100644 --- a/webui/src/js/path_mapping.json +++ b/webui/src/js/path_mapping.json @@ -332,6 +332,97 @@ "path": "libs/ace/ace.js", "cdnPath": "" } + }, + + "wrc-translations": { + "cdn": "3rdparty", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/resources", + "debug": { + "src": ["**"], + "path": "resources", + "cdnPath": "" + }, + "release": { + "src": ["**"], + "path": "resources", + "cdnPath": "" + } + }, + + "wrc-frontend": { + "cdn": "3rdparty", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/wrc-frontend", + "debug": { + "src": ["**"], + "path": "jet-composites/wrc-frontend/1.0.0", + "cdnPath": "" + }, + "release": { + "src": ["**"], + "path": "jet-composites/wrc-frontend/1.0.0", + "cdnPath": "" + } + }, + + "wdt-model-builder": { + "cdn": "3rdparty", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/wdt-model-builder", + "debug": { + "src": ["**"], + "path": "jet-composites/wdt-model-builder/1.0.0", + "cdnPath": "" + }, + "release": { + "src": ["**"], + "path": "jet-composites/wdt-model-builder/1.0.0", + "cdnPath": "" + } + }, + + "cfe-navtree": { + "cdn": "3rdparty", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/cfe-navtree", + "debug": { + "src": ["**"], + "path": "jet-composites/cfe-navtree/1.0.0", + "cdnPath": "" + }, + "release": { + "src": ["**"], + "path": "jet-composites/cfe-navtree/1.0.0", + "cdnPath": "" + } + }, + + "cfe-multi-select": { + "cdn": "3rdparty", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/cfe-multi-select", + "debug": { + "src": ["**"], + "path": "jet-composites/cfe-multi-select/1.0.0", + "cdnPath": "" + }, + "release": { + "src": ["**"], + "path": "jet-composites/cfe-multi-select/1.0.0", + "cdnPath": "" + } + }, + + "cfe-property-list-editor": { + "cdn": "3rdparty", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/cfe-property-list-editor", + "debug": { + "src": ["**"], + "path": "jet-composites/cfe-property-list-editor/1.0.0", + "cdnPath": "" + }, + "release": { + "src": ["**"], + "path": "jet-composites/cfe-property-list-editor/1.0.0", + "cdnPath": "" + } } + } } diff --git a/webui/src/js/viewModels/model-design-view.js b/webui/src/js/viewModels/model-design-view.js index 5cac655ba..6dc413ac3 100644 --- a/webui/src/js/viewModels/model-design-view.js +++ b/webui/src/js/viewModels/model-design-view.js @@ -3,81 +3,199 @@ * Copyright (c) 2021, 2022, Oracle and/or its affiliates. * Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ */ -define(['accUtils', 'utils/i18n', 'knockout', 'models/wkt-project', 'utils/url-catalog', 'utils/wkt-logger', - 'ojs/ojinputtext', 'ojs/ojlabel', 'ojs/ojbutton', 'ojs/ojformlayout' ], -function(accUtils, i18n, ko, project, urlCatalog) { - function ModelDesignViewModel() { - - this.connected = () => { - accUtils.announce('Model design view loaded.', 'assertive'); - // Implement further logic if needed - }; - - this.labelMapper = (labelId, payload) => { - return i18n.t(`model-design-${labelId}`, payload); - }; - - this.isLinux = () => { - return window.api.process.isLinux(); - }; - - this.project = project; - this.i18n = i18n; - - this.disableStartButton = ko.observable(false); - - const wrcInitialText = this.labelMapper('wrc-install-description'); - const wrcInstallLocation = '' + - this.labelMapper('wrc-link-text') + ''; - const wrcInstallParagraph = this.labelMapper('wrc-install-location-prefix') + ' ' + wrcInstallLocation + - ' ' + this.labelMapper('wrc-install-location-postfix'); - const wrcStartParagraph = this.labelMapper('wrc-start-description'); - this.wrcInstallInstructions = wrcInitialText + '

' + wrcInstallParagraph + '

' + wrcStartParagraph; - - this.showRemoteConsoleConfigForm = () => { - return !project.wdtModel.internal.wlRemoteConsolePort(); - }; - - this.showRemoteConsoleComponent = () => { - return !!project.wdtModel.internal.wlRemoteConsolePort(); - }; - - this.getWebLogicRemoteConsoleHomeHelpText = () => { - let helpKey; - if (window.api.process.isMac()) { - helpKey = 'user-settings-dialog-wrc-home-macos-help'; - } else if (window.api.process.isWindows()) { - helpKey = 'user-settings-dialog-wrc-home-windows-help'; - } else { - helpKey = 'user-settings-dialog-wrc-home-linux-help'; - } - return i18n.t(helpKey); - }; - - this.chooseWebLogicRemoteConsoleHomeDirectory = async () => { - const rcHome = await window.api.ipc.invoke('get-wrc-home-directory'); - if (rcHome) { - this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); - } - }; - - this.chooseWebLogicRemoteConsoleAppImage = async () => { - const rcHome = await window.api.ipc.invoke('get-wrc-app-image'); - if (rcHome) { - this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); - } - }; - - this.startWebLogicRemoteConsole = async () => { - const rcHome = this.project.wdtModel.internal.wlRemoteConsoleHome.observable(); - // TODO - do we need a busy dialog? - return window.api.ipc.invoke('wrc-set-home-and-start', rcHome); - }; - } - - /* - * Returns a constructor for the ViewModel. + define(['accUtils', 'utils/i18n', 'knockout', 'models/wkt-project', 'utils/url-catalog', + 'ojs/ojcontext', 'wrc-frontend/core/parsers/yaml', + 'wdt-model-builder/loader', 'utils/wkt-logger', 'ojs/ojinputtext', 'ojs/ojlabel', 'ojs/ojbutton', 'ojs/ojformlayout'], +function(accUtils, i18n, ko, project, urlCatalog, Context, YamlParser) { + function ModelDesignViewModel() { + const self = this; + + this.project = project; + this.builder = undefined; + this.dataProvider = {}; + + this.connected = function() { + accUtils.announce('Model design view loaded.', 'assertive'); + // Implement further logic if needed + const ele = document.querySelector('.wkt-model-edit-design'); + Context.getContext(ele).getBusyContext().whenReady() + .then(() => { + const urlPort = this.project.wdtModel.internal.wlRemoteConsolePort(); + if (typeof urlPort === 'undefined') { + return; + } + // Wait until we're first inserted into the DOM, + // to create our module-scoped instance of the + // builder. We'll be using that to interact with + // the builder, programmatically. + this.builder = document.getElementById('WdtModelBuilder'); + // The first priority is to set the port the + // cbe-data-manager uses when making REST calls to + // the backend. + this.builder.setBackendUrlPort(urlPort); + // ResizeIbservar needs to be set on the parent + // element of the tag. + const parentElement = this.builder.parentElement; + new ResizeObserver(() => { + this.builder.resize(); + }).observe(parentElement); + + // We need to support several use cases: + // + // UC-1: User clicks "Design View" tab, but no WKT project + // has been loaded. + // UC-2: User clicks "Design View" tab with a WKT project + // loaded, but the editor (on the "Code View" tab) + // is empty. + // UC-3: User clicks "Design View" tab with a WKT project + // loaded, and the editor (on the "Code View" tab) + // is not empty. + // + // The project.wdtModel.modelContent knockout observable is + // used to determine the use case. The latest value of that + // observable is used to create (and activate) WDT Model File + // provider session, in the WRC-CBE. + const providerOptions = { + fileContents: project.wdtModel.modelContent() + }; + + // A string representation of the model contents is required, + // in order to create a WDT Model File provider. + + if (!providerOptions.fileContents || providerOptions.fileContents === '') { + // There is nothing assigned to the modelContext observable, + // so we need to use the builder's modelTemplate property + // to populate the fileContents variable. + const modelTemplates = self.builder.getProperty('modelTemplate'); + // The demo just uses the "sparse" model template. + providerOptions.fileContents = modelTemplates.sparse; + } + + // A unique name for the string representation of the model + // contents is required, in order to create a WDT Model File + // provider. It looks like project.wdtModel.getDefaultModelFile() + // returns 'models/model.yaml', for UC-1 and US-2. Otherwise, it + // looks like it returns the following concatenated string: + // + // -models/model.yaml + // + // Both are non-empty strings, which is really the only requirement. + // The WRC-CBE doesn't care if the name is unique or not, because + // the name is not the key. The WRC-CFE enforces name uniqueness so + // prevent the end-user from thinking that the Kiosk has duplicates. + // Net, net we get the name by making on a WKT-UI module, so the name + // being used is completely up to the WKT-UI. + providerOptions['name'] = project.wdtModel.getDefaultModelFile(); + + // The WRC Frontend JET Pack includes a YamlParser and + // JsonParser module. For the demo, fileContents is YAML, + // so the YamlParser module is used. + YamlParser.parse(providerOptions.fileContents) + .then(data => { + // Use promise fulfillment value for second argument + // of the builder's createProvider() method. The newly + // created (and activated) provider, needs to be captured + // in your event listener for the "providerActivated" + // custom event. + self.builder.createProvider(providerOptions.name, data); + }); + }); + }.bind(this); + + this.disconnected = function() { + if (typeof self.builder !== 'undefined') { + self.builder.deactivateProvider(self.dataProvider); + } + }.bind(this); + + /** + * @param {CustomEvent} event - Triggered when WDT Model File provider has been activated with the WRC-CBE. + */ + this.providerActivated = (event) => { + self.dataProvider = event.detail.value; + self.builder.selectLastVisitedSlice(); + }; + + /** + * @param {CustomEvent} event - Triggered when changes have been downloaded from the WRC-CBE, for the active WDT Model File provider. + */ + this.changesAutoDownloaded = (event) => { + project.wdtModel.modelContent(event.detail.value); + }; + + /** + * @param {CustomEvent} event - Triggered when WDT Model File provider has been deactivated with the WRC-CBE. */ - return ModelDesignViewModel; + this.providerDeactivated = (event) => { + const result = event.detail.value; + delete result.data; + self.dataProvider = {state: 'disconnected'}; + }; + + this.labelMapper = (labelId, payload) => { + return i18n.t(`model-design-${labelId}`, payload); + }; + + this.isLinux = () => { + return window.api.process.isLinux(); + }; + + this.i18n = i18n; + + this.disableStartButton = ko.observable(false); + + const wrcInitialText = this.labelMapper('wrc-install-description'); + const wrcInstallLocation = '' + + this.labelMapper('wrc-link-text') + ''; + const wrcInstallParagraph = this.labelMapper('wrc-install-location-prefix') + ' ' + wrcInstallLocation + + ' ' + this.labelMapper('wrc-install-location-postfix'); + const wrcStartParagraph = this.labelMapper('wrc-start-description'); + this.wrcInstallInstructions = wrcInitialText + '

' + wrcInstallParagraph + '

' + wrcStartParagraph; + + this.showRemoteConsoleConfigForm = () => { + return !project.wdtModel.internal.wlRemoteConsolePort(); + }; + + this.showRemoteConsoleComponent = () => { + return !!project.wdtModel.internal.wlRemoteConsolePort(); + }; + + this.getWebLogicRemoteConsoleHomeHelpText = () => { + let helpKey; + if (window.api.process.isMac()) { + helpKey = 'user-settings-dialog-wrc-home-macos-help'; + } else if (window.api.process.isWindows()) { + helpKey = 'user-settings-dialog-wrc-home-windows-help'; + } else { + helpKey = 'user-settings-dialog-wrc-home-linux-help'; + } + return i18n.t(helpKey); + }; + + this.chooseWebLogicRemoteConsoleHomeDirectory = async () => { + const rcHome = await window.api.ipc.invoke('get-wrc-home-directory'); + if (rcHome) { + this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); + } + }; + + this.chooseWebLogicRemoteConsoleAppImage = async () => { + const rcHome = await window.api.ipc.invoke('get-wrc-app-image'); + if (rcHome) { + this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); + } + }; + + this.startWebLogicRemoteConsole = async () => { + const rcHome = this.project.wdtModel.internal.wlRemoteConsoleHome.observable(); + // TODO - do we need a busy dialog? + return window.api.ipc.invoke('wrc-set-home-and-start', rcHome); + }; + } + + /* + * Returns a constructor for the ViewModel. + */ + return ModelDesignViewModel; }); diff --git a/webui/src/js/views/model-design-view.html b/webui/src/js/views/model-design-view.html index bcac442b9..c4284c413 100644 --- a/webui/src/js/views/model-design-view.html +++ b/webui/src/js/views/model-design-view.html @@ -2,11 +2,15 @@ Copyright (c) 2021, 2022, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ --> -

+
-
-

-
+ +
From 364e07043fb1f324ef7549a3e8f5fd884c06e2a5 Mon Sep 17 00:00:00 2001 From: mwooten Date: Thu, 3 Mar 2022 16:11:28 -0500 Subject: [PATCH 2/2] Pre-PR updates to webui files for wrc integ --- electron/app/js/ipcRendererPreload.js | 3 +- electron/app/js/wlRemoteConsoleUtils.js | 18 +- electron/app/main.js | 7 +- webui/src/js/main.js | 2 +- webui/src/js/path_mapping.json | 8 +- webui/src/js/viewModels/model-design-view.js | 434 ++++++++++--------- webui/src/js/views/model-design-view.html | 17 +- 7 files changed, 273 insertions(+), 216 deletions(-) diff --git a/electron/app/js/ipcRendererPreload.js b/electron/app/js/ipcRendererPreload.js index 051f186a2..dc1782036 100644 --- a/electron/app/js/ipcRendererPreload.js +++ b/electron/app/js/ipcRendererPreload.js @@ -203,7 +203,8 @@ contextBridge.exposeInMainWorld( 'get-wrc-home-directory', 'get-wrc-app-image', 'wrc-get-home-default-value', - 'wrc-set-home-and-start' + 'wrc-set-home-and-start', + 'get-wrc-port' ]; return new Promise((resolve, reject) => { if (validChannels.includes(channel)) { diff --git a/electron/app/js/wlRemoteConsoleUtils.js b/electron/app/js/wlRemoteConsoleUtils.js index c7021da6a..82afab9fa 100644 --- a/electron/app/js/wlRemoteConsoleUtils.js +++ b/electron/app/js/wlRemoteConsoleUtils.js @@ -23,7 +23,7 @@ const { spawnDaemonChildProcess } = require('./childProcessExecutor'); const MIN_VERSION = '2.2.0'; const MIN_VERSION_COMPONENTS = MIN_VERSION.split('.').map((item) => { return Number(item); }); let _wlRemoteConsoleChildProcess; - +let _wlRemoteConsolePort; async function startWebLogicRemoteConsoleBackend(currentWindow, skipVersionCheck = false) { if (_wlRemoteConsoleChildProcess) { @@ -47,6 +47,8 @@ async function startWebLogicRemoteConsoleBackend(currentWindow, skipVersionCheck }); _wlRemoteConsoleChildProcess.on('exit', (code) => { getLogger().info('WebLogic Remote Console backend process exited with code %s', code); + _wlRemoteConsoleChildProcess = undefined; + _wlRemoteConsolePort = undefined; }); const stdoutLines = readline.createInterface({ input: _wlRemoteConsoleChildProcess.stdout }); @@ -60,6 +62,9 @@ async function startWebLogicRemoteConsoleBackend(currentWindow, skipVersionCheck const matcher = line.match(portRegex); if (matcher) { foundPort = true; + // The exported getWebLogicRemoteConsolePort function returns + // the current port, so we need to save it. + _wlRemoteConsolePort = matcher[1]; sendToWindow(currentWindow, 'set-wrc-backend-port', matcher[1]); } } @@ -152,6 +157,10 @@ function getDefaultDirectoryForOpenDialog(isAppImage = false) { return result; } +function getWebLogicRemoteConsolePort() { + return _wlRemoteConsolePort; +} + async function _getWebLogicRemoteConsoleHome(skipVersionCheck = false) { const rcHome = userSettings.getWebLogicRemoteConsoleHome(); if (!rcHome) { @@ -238,7 +247,7 @@ async function _getWebLogicRemoteConsoleExecutableData(rcHome) { _getDevExecutablePath(rcHome, pathToDirectoryWithExecutable).then(exeResult => { if (exeResult.exists) { results['executable'] = exeResult.executable; - results['arguments'] = ['.', 'dev', '--showPort', '--stdin', '--quiet', '--headless']; + results['arguments'] = ['.', 'dev', '--showPort', `--check-pid=${process.pid}`, '--quiet', '--headless', '--useTokenNotCookie']; results['options'] = { cwd: rcHome }; } else { const message = i18n.t('wrc-dev-executable-existence-check-failed', @@ -256,7 +265,7 @@ async function _getWebLogicRemoteConsoleExecutableData(rcHome) { _getInstalledExecutablePath(rcHome).then(exeResult => { if (exeResult['exists']) { results['executable'] = exeResult['executable']; - results['arguments'] = ['--showPort', '--stdin', '--quiet', '--headless']; + results['arguments'] = ['--showPort', '--useTokenNotCookie', `--check-pid=${process.pid}`, '--quiet', '--headless']; resolve(results); } else { const message = i18n.t('wrc-executable-not-exists', { rcHome: rcHome, executable: results['executable'] }); @@ -484,5 +493,6 @@ module.exports = { getDefaultDirectoryForOpenDialog, getDefaultWebLogicRemoteConsoleHome, setWebLogicRemoteConsoleHomeAndStart, - startWebLogicRemoteConsoleBackend + startWebLogicRemoteConsoleBackend, + getWebLogicRemoteConsolePort }; diff --git a/electron/app/main.js b/electron/app/main.js index cdeab6917..25cb0b746 100644 --- a/electron/app/main.js +++ b/electron/app/main.js @@ -35,7 +35,7 @@ const openSSLUtils = require('./js/openSSLUtils'); const osUtils = require('./js/osUtils'); const { initializeAutoUpdater, registerAutoUpdateListeners, installUpdates, getUpdateInformation } = require('./js/appUpdater'); const { startWebLogicRemoteConsoleBackend, getDefaultDirectoryForOpenDialog, setWebLogicRemoteConsoleHomeAndStart, - getDefaultWebLogicRemoteConsoleHome } = require('./js/wlRemoteConsoleUtils'); + getDefaultWebLogicRemoteConsoleHome, getWebLogicRemoteConsolePort } = require('./js/wlRemoteConsoleUtils'); const { getHttpsProxyUrl, getBypassProxyHosts } = require('./js/userSettings'); const { sendToWindow } = require('./js/windowUtils'); @@ -931,6 +931,11 @@ class Main { ipcMain.handle('wrc-get-home-default-value', async (event) => { return getDefaultWebLogicRemoteConsoleHome(); }); + + // eslint-disable-next-line no-unused-vars + ipcMain.handle('get-wrc-port', async (event) => { + return getWebLogicRemoteConsolePort(); + }); } async getLatestWdtInstaller(targetWindow) { diff --git a/webui/src/js/main.js b/webui/src/js/main.js index 02e66d53e..73af8ffb4 100644 --- a/webui/src/js/main.js +++ b/webui/src/js/main.js @@ -43,7 +43,7 @@ 'ace': 'libs/ace/ace', 'wrc-translations': 'resources', 'wrc-frontend': 'jet-composites/wrc-frontend/1.0.0', - 'wdt-model-builder': 'jet-composites/wrc-frontend/1.0.0', + 'wdt-model-designer': 'jet-composites/wdt-model-designer/1.0.0', 'cfe-navtree': 'jet-composites/cfe-navtree/1.0.0', 'cfe-multi-select': 'jet-composites/cfe-multi-select/1.0.0', 'cfe-property-list-editor': 'jet-composites/cfe-property-list-editor/1.0.0' diff --git a/webui/src/js/path_mapping.json b/webui/src/js/path_mapping.json index fead04c1c..21bf65747 100644 --- a/webui/src/js/path_mapping.json +++ b/webui/src/js/path_mapping.json @@ -364,17 +364,17 @@ } }, - "wdt-model-builder": { + "wdt-model-designer": { "cdn": "3rdparty", - "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/wdt-model-builder", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/wdt-model-designer", "debug": { "src": ["**"], - "path": "jet-composites/wdt-model-builder/1.0.0", + "path": "jet-composites/wdt-model-designer/1.0.0", "cdnPath": "" }, "release": { "src": ["**"], - "path": "jet-composites/wdt-model-builder/1.0.0", + "path": "jet-composites/wdt-model-designer/1.0.0", "cdnPath": "" } }, diff --git a/webui/src/js/viewModels/model-design-view.js b/webui/src/js/viewModels/model-design-view.js index 6dc413ac3..c6bb21b5c 100644 --- a/webui/src/js/viewModels/model-design-view.js +++ b/webui/src/js/viewModels/model-design-view.js @@ -3,199 +3,241 @@ * Copyright (c) 2021, 2022, Oracle and/or its affiliates. * Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ */ - define(['accUtils', 'utils/i18n', 'knockout', 'models/wkt-project', 'utils/url-catalog', - 'ojs/ojcontext', 'wrc-frontend/core/parsers/yaml', - 'wdt-model-builder/loader', 'utils/wkt-logger', 'ojs/ojinputtext', 'ojs/ojlabel', 'ojs/ojbutton', 'ojs/ojformlayout'], -function(accUtils, i18n, ko, project, urlCatalog, Context, YamlParser) { - function ModelDesignViewModel() { - const self = this; - - this.project = project; - this.builder = undefined; - this.dataProvider = {}; - - this.connected = function() { - accUtils.announce('Model design view loaded.', 'assertive'); - // Implement further logic if needed - const ele = document.querySelector('.wkt-model-edit-design'); - Context.getContext(ele).getBusyContext().whenReady() - .then(() => { - const urlPort = this.project.wdtModel.internal.wlRemoteConsolePort(); - if (typeof urlPort === 'undefined') { - return; - } - // Wait until we're first inserted into the DOM, - // to create our module-scoped instance of the - // builder. We'll be using that to interact with - // the builder, programmatically. - this.builder = document.getElementById('WdtModelBuilder'); - // The first priority is to set the port the - // cbe-data-manager uses when making REST calls to - // the backend. - this.builder.setBackendUrlPort(urlPort); - // ResizeIbservar needs to be set on the parent - // element of the tag. - const parentElement = this.builder.parentElement; - new ResizeObserver(() => { - this.builder.resize(); - }).observe(parentElement); - - // We need to support several use cases: - // - // UC-1: User clicks "Design View" tab, but no WKT project - // has been loaded. - // UC-2: User clicks "Design View" tab with a WKT project - // loaded, but the editor (on the "Code View" tab) - // is empty. - // UC-3: User clicks "Design View" tab with a WKT project - // loaded, and the editor (on the "Code View" tab) - // is not empty. - // - // The project.wdtModel.modelContent knockout observable is - // used to determine the use case. The latest value of that - // observable is used to create (and activate) WDT Model File - // provider session, in the WRC-CBE. - const providerOptions = { - fileContents: project.wdtModel.modelContent() - }; - - // A string representation of the model contents is required, - // in order to create a WDT Model File provider. - - if (!providerOptions.fileContents || providerOptions.fileContents === '') { - // There is nothing assigned to the modelContext observable, - // so we need to use the builder's modelTemplate property - // to populate the fileContents variable. - const modelTemplates = self.builder.getProperty('modelTemplate'); - // The demo just uses the "sparse" model template. - providerOptions.fileContents = modelTemplates.sparse; - } - - // A unique name for the string representation of the model - // contents is required, in order to create a WDT Model File - // provider. It looks like project.wdtModel.getDefaultModelFile() - // returns 'models/model.yaml', for UC-1 and US-2. Otherwise, it - // looks like it returns the following concatenated string: - // - // -models/model.yaml - // - // Both are non-empty strings, which is really the only requirement. - // The WRC-CBE doesn't care if the name is unique or not, because - // the name is not the key. The WRC-CFE enforces name uniqueness so - // prevent the end-user from thinking that the Kiosk has duplicates. - // Net, net we get the name by making on a WKT-UI module, so the name - // being used is completely up to the WKT-UI. - providerOptions['name'] = project.wdtModel.getDefaultModelFile(); - - // The WRC Frontend JET Pack includes a YamlParser and - // JsonParser module. For the demo, fileContents is YAML, - // so the YamlParser module is used. - YamlParser.parse(providerOptions.fileContents) - .then(data => { - // Use promise fulfillment value for second argument - // of the builder's createProvider() method. The newly - // created (and activated) provider, needs to be captured - // in your event listener for the "providerActivated" - // custom event. - self.builder.createProvider(providerOptions.name, data); - }); - }); - }.bind(this); - - this.disconnected = function() { - if (typeof self.builder !== 'undefined') { - self.builder.deactivateProvider(self.dataProvider); - } - }.bind(this); - - /** - * @param {CustomEvent} event - Triggered when WDT Model File provider has been activated with the WRC-CBE. - */ - this.providerActivated = (event) => { - self.dataProvider = event.detail.value; - self.builder.selectLastVisitedSlice(); - }; - - /** - * @param {CustomEvent} event - Triggered when changes have been downloaded from the WRC-CBE, for the active WDT Model File provider. - */ - this.changesAutoDownloaded = (event) => { - project.wdtModel.modelContent(event.detail.value); - }; - - /** - * @param {CustomEvent} event - Triggered when WDT Model File provider has been deactivated with the WRC-CBE. - */ - this.providerDeactivated = (event) => { - const result = event.detail.value; - delete result.data; - self.dataProvider = {state: 'disconnected'}; - }; - - this.labelMapper = (labelId, payload) => { - return i18n.t(`model-design-${labelId}`, payload); - }; - - this.isLinux = () => { - return window.api.process.isLinux(); - }; - - this.i18n = i18n; - - this.disableStartButton = ko.observable(false); - - const wrcInitialText = this.labelMapper('wrc-install-description'); - const wrcInstallLocation = '' + - this.labelMapper('wrc-link-text') + ''; - const wrcInstallParagraph = this.labelMapper('wrc-install-location-prefix') + ' ' + wrcInstallLocation + - ' ' + this.labelMapper('wrc-install-location-postfix'); - const wrcStartParagraph = this.labelMapper('wrc-start-description'); - this.wrcInstallInstructions = wrcInitialText + '

' + wrcInstallParagraph + '

' + wrcStartParagraph; - - this.showRemoteConsoleConfigForm = () => { - return !project.wdtModel.internal.wlRemoteConsolePort(); - }; - - this.showRemoteConsoleComponent = () => { - return !!project.wdtModel.internal.wlRemoteConsolePort(); - }; - - this.getWebLogicRemoteConsoleHomeHelpText = () => { - let helpKey; - if (window.api.process.isMac()) { - helpKey = 'user-settings-dialog-wrc-home-macos-help'; - } else if (window.api.process.isWindows()) { - helpKey = 'user-settings-dialog-wrc-home-windows-help'; - } else { - helpKey = 'user-settings-dialog-wrc-home-linux-help'; - } - return i18n.t(helpKey); - }; - - this.chooseWebLogicRemoteConsoleHomeDirectory = async () => { - const rcHome = await window.api.ipc.invoke('get-wrc-home-directory'); - if (rcHome) { - this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); - } - }; - - this.chooseWebLogicRemoteConsoleAppImage = async () => { - const rcHome = await window.api.ipc.invoke('get-wrc-app-image'); - if (rcHome) { - this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); - } - }; - - this.startWebLogicRemoteConsole = async () => { - const rcHome = this.project.wdtModel.internal.wlRemoteConsoleHome.observable(); - // TODO - do we need a busy dialog? - return window.api.ipc.invoke('wrc-set-home-and-start', rcHome); - }; - } - - /* - * Returns a constructor for the ViewModel. - */ - return ModelDesignViewModel; -}); + +define(['accUtils', 'utils/i18n', 'knockout', 'models/wkt-project', 'utils/url-catalog', 'utils/wkt-logger', 'wrc-frontend/core/parsers/yaml', 'wrc-frontend/integration/viewModels/utils', + 'wdt-model-designer/loader', 'ojs/ojinputtext', 'ojs/ojlabel', 'ojs/ojbutton', 'ojs/ojformlayout'], + function(accUtils, i18n, ko, project, urlCatalog, wktLogger, YamlParser, ViewModelUtils) { + function ModelDesignViewModel() { + const self = this; + + this.project = project; + this.designer; + this.dataProvider = {}; + + this.connected = function () { + accUtils.announce('Model design view loaded.', 'assertive'); + // Set up a change subscription on wlRemoteConsolePort observable, + // which will primarily be used in the "WRC Not Installed Yet" and + // "WRC Process Was Killed or Died" use cases. + this.wlRemoteConsolePortSubscription = project.wdtModel.internal.wlRemoteConsolePort.subscribe((newValue) => { + wktLogger.debug('connected: newValue=%s', newValue); + showWdtModelDesigner(newValue); + }); + // Get WRC backend port, asynchronously + window.api.ipc.invoke('get-wrc-port') + .then(backendPort => { + if (backendPort !== project.wdtModel.internal.wlRemoteConsolePort()) { + // Trigger the change subscription + project.wdtModel.internal.wlRemoteConsolePort(backendPort); + } else { + // Call showWdtModelDesigner directly + showWdtModelDesigner(backendPort); + } + }) + .catch(err => { + ViewModelUtils.failureResponseDefaultHandling(err); + }); + }; + + this.disconnected = function() { + self.wlRemoteConsolePortSubscription.dispose(); + if (self.designer) { + self.designer.deactivateProvider(self.dataProvider); + } + }; + + function showWdtModelDesigner(backendPort) { + wktLogger.info('showWdtModelDesigner: backendPort=%s', backendPort); + if (!backendPort) { + return; + } + // Lookup designer in the DOM, because we mainly need to + // interact with it programmatically. + self.designer = document.getElementById('WdtModelDesigner'); + // We cannot use to control the visibility of + // the JET composite, because it prevents + // JET from fully baking a JET composite. Being "half-baked" + // means that the JET composite exists, but custom methods + // on it are not callable, because of the . So, + // the wdt-model-designer JET composite has a visible property + // that controls it's visibility. The default value for that + // property is false. + self.designer.visible = self.showRemoteConsoleComponent(); + // Tell designer the port, so it can construct the backend + // URL it's internal module(s) uses when making REST calls + // to the WRC backend. + self.designer.setBackendUrlPort(backendPort); + // ResizeObserver needs to be set on the parent element + // of the tag. + const parentElement = self.designer.parentElement; + new ResizeObserver(() => { + self.designer.resize(); + }).observe(parentElement); + + // We need to support several use cases: + // + // UC-1: User clicks "Design View" tab, but no WKT project + // has been loaded. + // UC-2: User clicks "Design View" tab with a WKT project + // loaded, but the editor (on the "Code View" tab) + // is empty. + // UC-3: User clicks "Design View" tab with a WKT project + // loaded, and the editor (on the "Code View" tab) + // is not empty. + // + // The project.wdtModel.modelContent knockout observable is + // used to determine the use case. The latest value of that + // observable is used to create (and activate) WDT Model File + // provider session, in the WRC backend. + const providerOptions = { + fileContents: project.wdtModel.modelContent() + }; + + // A string representation of the model contents is required, + // in order to create a WDT Model File provider. + + if (!providerOptions.fileContents || providerOptions.fileContents === '') { + // There is nothing assigned to the modelContext observable, + // so we need to use the designer's modelTemplate property + // to populate the fileContents variable. + const modelTemplates = self.designer.getProperty('modelTemplate'); + // The demo just uses the "sparse" model template. + providerOptions.fileContents = modelTemplates.sparse; + } + + // A name is needed to create a WDT Model File provider. It looks like + // project.wdtModel.getDefaultModelFile() returns 'models/model.yaml', + // for UC-1 and US-2. Otherwise, it looks like it returns the following + // concatenated string: + // + // -models/model.yaml + // + // We'll use that call to get the name, for now. + providerOptions['name'] = project.wdtModel.getDefaultModelFile(); + // The WRC JET Pack includes a YamlParser and JsonParser module. For the + // demo, fileContents is YAML, so the YamlParser module is used. + YamlParser.parse(providerOptions.fileContents) + .then(data => { + // Use promise fulfillment value for second argument of the + // designer's createProvider() method. The newly created + // (and activated) provider, needs to be captured in your + // event listener for the "providerActivated" custom event. + self.designer.createProvider(providerOptions.name, data); + }) + .catch(err => { + ViewModelUtils.failureResponseDefaultHandling(err); + }); + } + + /** + * @param {CustomEvent} event - Triggered when WDT Model File provider has been activated with the WRC backend. + */ + this.providerActivated = (event) => { + self.dataProvider = event.detail.value; + self.designer.selectLastVisitedSlice(); + }; + + /** + * @param {CustomEvent} event - Triggered when changes have been downloaded from the WRC backend, for the active WDT Model File provider. + */ + this.changesAutoDownloaded = (event) => { + project.wdtModel.modelContent(event.detail.value); + }; + + /** + * @param {CustomEvent} event - Triggered when WDT Model File provider has been deactivated with the WRC backend. + */ + this.providerDeactivated = (event) => { + const result = event.detail.value; + delete result.data; + self.dataProvider = {state: 'disconnected'}; + }; + + /** + * @param {CustomEvent} event - Triggered when WDT Model Designer has lost it's connection to the WRC backend. + */ + this.connectionLostRefused = (event) => { + wktLogger.debug('connectionLostRefused: backendUrl=%s', event.detail.value); + if (self.designer) self.designer.visible = false; + project.wdtModel.internal.wlRemoteConsolePort(undefined); + }; + + this.labelMapper = (labelId, payload) => { + return i18n.t(`model-design-${labelId}`, payload); + }; + + this.isLinux = () => { + return window.api.process.isLinux(); + }; + + this.i18n = i18n; + + this.disableStartButton = ko.observable(false); + + const wrcInitialText = this.labelMapper('wrc-install-description'); + const wrcInstallLocation = '' + + this.labelMapper('wrc-link-text') + ''; + const wrcInstallParagraph = this.labelMapper('wrc-install-location-prefix') + ' ' + wrcInstallLocation + + ' ' + this.labelMapper('wrc-install-location-postfix'); + const wrcStartParagraph = this.labelMapper('wrc-start-description'); + this.wrcInstallInstructions = wrcInitialText + '

' + wrcInstallParagraph + '

' + wrcStartParagraph; + + this.showRemoteConsoleConfigForm = () => { + return !project.wdtModel.internal.wlRemoteConsolePort(); + }; + + this.showRemoteConsoleComponent = () => { + return !!project.wdtModel.internal.wlRemoteConsolePort(); + }; + + this.getWebLogicRemoteConsoleHomeHelpText = () => { + let helpKey; + if (window.api.process.isMac()) { + helpKey = 'user-settings-dialog-wrc-home-macos-help'; + } else if (window.api.process.isWindows()) { + helpKey = 'user-settings-dialog-wrc-home-windows-help'; + } else { + helpKey = 'user-settings-dialog-wrc-home-linux-help'; + } + return i18n.t(helpKey); + }; + + this.chooseWebLogicRemoteConsoleHomeDirectory = async () => { + const rcHome = await window.api.ipc.invoke('get-wrc-home-directory'); + if (rcHome) { + this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); + } + }; + + this.chooseWebLogicRemoteConsoleAppImage = async () => { + const rcHome = await window.api.ipc.invoke('get-wrc-app-image'); + if (rcHome) { + this.project.wdtModel.internal.wlRemoteConsoleHome.observable(rcHome); + } + }; + + this.startWebLogicRemoteConsole = async () => { + const rcHome = this.project.wdtModel.internal.wlRemoteConsoleHome.observable(); + // TODO - do we need a busy dialog? + // Set cursor to BUSY and let self.designer + // set it back to default + document.querySelector('oj-button#start-wrc-button span').style.cursor = 'wait'; + return window.api.ipc.invoke('wrc-set-home-and-start', rcHome) + .then(() => { + return window.api.ipc.invoke('get-wrc-port'); + }) + .then(backendPort => { + if (self.designer) self.designer.setBackendUrlPort(backendPort); + // Trigger the change subscription + project.wdtModel.internal.wlRemoteConsolePort(backendPort); + }); + }; + } + + /* + * Returns a constructor for the ViewModel. + */ + return ModelDesignViewModel; + } +); diff --git a/webui/src/js/views/model-design-view.html b/webui/src/js/views/model-design-view.html index c4284c413..009a8d734 100644 --- a/webui/src/js/views/model-design-view.html +++ b/webui/src/js/views/model-design-view.html @@ -3,15 +3,14 @@ Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ -->

- - - - + +