diff --git a/electron/app/js/wlRemoteConsoleUtils.js b/electron/app/js/wlRemoteConsoleUtils.js index fd1363ca9..9cbbd195f 100644 --- a/electron/app/js/wlRemoteConsoleUtils.js +++ b/electron/app/js/wlRemoteConsoleUtils.js @@ -22,7 +22,7 @@ const { wlRemoteConsoleFrontendVersion } = require('../webui.json'); let _wlRemoteConsoleChildProcess; - +/* global process */ async function startWebLogicRemoteConsoleBackend(currentWindow, skipVersionCheck = false) { if (_wlRemoteConsoleChildProcess) { return Promise.resolve(); @@ -236,7 +236,8 @@ 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', @@ -254,7 +255,8 @@ async function _getWebLogicRemoteConsoleExecutableData(rcHome) { _getInstalledExecutablePath(rcHome).then(exeResult => { if (exeResult['exists']) { results['executable'] = exeResult['executable']; - results['arguments'] = ['--showPort', '--stdin', '--quiet', '--headless']; + results['arguments'] = + ['--showPort', `--check-pid=${process.pid}`, '--quiet', '--headless', '--useTokenNotCookie']; resolve(results); } else { const message = i18n.t('wrc-executable-not-exists', { rcHome: rcHome, executable: results['executable'] }); @@ -415,7 +417,16 @@ async function _getLocationFromPreferencesFile() { fsPromises.readFile(autoPrefsLocation, { encoding: 'utf8' }).then(contents => { try { const props = JSON.parse(contents); - resolve(props.location); + + let location; + if (props.location) { + if (osUtils.isMac()) { + location = path.normalize(path.join(path.dirname(props.location), '..', '..')); + } else { + location = path.dirname(props.location); + } + } + resolve(location); } catch (err) { getLogger().debug('Failed to parse file %s: %s', autoPrefsLocation, getErrorMessage(err)); resolve(); diff --git a/webui/package-lock.json b/webui/package-lock.json index 5c84344a9..4333e3953 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -6,6 +6,7 @@ "": { "dependencies": { "@oracle/oraclejet": "^11.1.5", + "@oracle/wrc-jet-pack": "~2.3.0-develop", "i18next": "^21.6.3", "jquery": "^3.6.0", "js-yaml": "^4.1.0" @@ -272,6 +273,14 @@ "node": ">=12.21.0" } }, + "node_modules/@oracle/wrc-jet-pack": { + "version": "2.3.0-develop.202203061303", + "resolved": "https://registry.npmjs.org/@oracle/wrc-jet-pack/-/wrc-jet-pack-2.3.0-develop.202203061303.tgz", + "integrity": "sha512-pZ6y7qYdptov50QNulJaRQx59ogo5erYmnZuXun4WNugEM1rG449EsQ/q/vwvk+4r1vQmA+7L7v3RMj572UYpQ==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -6293,6 +6302,11 @@ "underscore": "^1.10.2" } }, + "@oracle/wrc-jet-pack": { + "version": "2.3.0-develop.202203061303", + "resolved": "https://registry.npmjs.org/@oracle/wrc-jet-pack/-/wrc-jet-pack-2.3.0-develop.202203061303.tgz", + "integrity": "sha512-pZ6y7qYdptov50QNulJaRQx59ogo5erYmnZuXun4WNugEM1rG449EsQ/q/vwvk+4r1vQmA+7L7v3RMj572UYpQ==" + }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", diff --git a/webui/package.json b/webui/package.json index 4163075f9..362a660db 100644 --- a/webui/package.json +++ b/webui/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@oracle/oraclejet": "^11.1.5", + "@oracle/wrc-jet-pack": "~2.3.0-develop", "i18next": "^21.6.3", "jquery": "^3.6.0", "js-yaml": "^4.1.0" diff --git a/webui/src/css/app.css b/webui/src/css/app.css index 0877bc67a..71107d8ac 100644 --- a/webui/src/css/app.css +++ b/webui/src/css/app.css @@ -193,18 +193,20 @@ /*padding-top: 10px;*/ } -/* container for model design view, currently text */ -.wkt-model-edit-design { - margin: 10px; -} - -/* container for model design view, currently text */ +/* container for model design view */ +.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; +} + /* the ace editor pane */ #model-editor { width: 100%; diff --git a/webui/src/js/main.js b/webui/src/js/main.js index 1bdcc5a4f..549ad9386 100644 --- a/webui/src/js/main.js +++ b/webui/src/js/main.js @@ -40,9 +40,23 @@ '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-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' } // 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..f61d5f883 100644 --- a/webui/src/js/path_mapping.json +++ b/webui/src/js/path_mapping.json @@ -332,6 +332,96 @@ "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-designer": { + "cdn": "3rdparty", + "cwd": "node_modules/@oracle/wrc-jet-pack/dist/jet-composites/wdt-model-designer", + "debug": { + "src": ["**"], + "path": "jet-composites/wdt-model-designer/1.0.0", + "cdnPath": "" + }, + "release": { + "src": ["**"], + "path": "jet-composites/wdt-model-designer/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..e4d47b3bf 100644 --- a/webui/src/js/viewModels/model-design-view.js +++ b/webui/src/js/viewModels/model-design-view.js @@ -4,13 +4,59 @@ * 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) { + '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() { + let subscriptions = []; + this.project = project; + this.i18n = i18n; + this.designer = undefined; + this.dataProvider = {}; + this.disableStartButton = ko.observable(false); + this.connected = () => { accUtils.announce('Model design view loaded.', 'assertive'); - // Implement further logic if needed + subscriptions.push(this.project.wdtModel.internal.wlRemoteConsolePort.subscribe((newValue) => { + wktLogger.debug('Model Design View got event for Remote Console backend port change to %s', newValue); + this.showWdtModelDesigner(newValue, this); + }, this)); + + // eslint-disable-next-line no-unused-vars + subscriptions.push(this.project.wdtModel.modelContent.subscribe((newValue) => { + wktLogger.debug('Model Design View got event for Model contents changed'); + + if (this.designer) { + // FIXME - There doesn't seem to be a way to update the data of the data provider. + // Please fix this accordingly and delete this comment... + // + } + }, this)); + + // The subscription won't trigger if the backend port has already been set so handle it here. + // + const port = this.project.wdtModel.internal.wlRemoteConsolePort(); + if (typeof port !== 'undefined') { + wktLogger.debug('direct connected: port=%s', port); + + // FIXME - There seems to be a race condition where the JET component does not seem to + // be fully loaded by the time we get to this point. Working around it for now... + // + setTimeout( () => { + this.showWdtModelDesigner(port); + }, 1000); + } + }; + + this.disconnected = function() { + subscriptions.forEach((subscription) => { + subscription.dispose(); + }); + + if (this.designer) { + this.designer.deactivateProvider(self.dataProvider); + } }; this.labelMapper = (labelId, payload) => { @@ -21,10 +67,99 @@ function(accUtils, i18n, ko, project, urlCatalog) { return window.api.process.isLinux(); }; - this.project = project; - this.i18n = i18n; + this.showWdtModelDesigner = (backendPort) => { + wktLogger.info('showWdtModelDesigner using backendPort %s', backendPort); + if (!backendPort) { + return; + } - this.disableStartButton = ko.observable(false); + 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 its visibility. The default value for that + // property is false. + // + self.designer.visible = this.showRemoteConsoleComponent(); + 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); + + // TODO - Do we need to use the Remote Console parser or can we just use js-yaml? + // + const providerOptions = this.getRemoteConsoleProviderOptions(); + YamlParser.parse(providerOptions.fileContents).then(data => { + self.designer.createProvider(providerOptions.name, data); + }).catch(err => { + ViewModelUtils.failureResponseDefaultHandling(err); + }); + }; + + // 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 model editor is empty. + // UC-3: User clicks "Design View" tab with a WKT project loaded, and the model editor 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. + // + this.getRemoteConsoleProviderOptions = () => { + const providerOptions = { + fileContents: this.project.wdtModel.modelContent() + }; + + if (!providerOptions.fileContents) { + const modelTemplates = self.designer.getProperty('modelTemplate'); + providerOptions.fileContents = modelTemplates.sparse; + } + + // A name is needed to create a WDT Model File provider. + // + providerOptions['name'] = this.project.wdtModel.getDefaultModelFile(); + return providerOptions; + }; + + // Triggered when WDT Model File provider has been activated with the WRC backend. + // + this.providerActivated = (event) => { + self.dataProvider = event.detail.value; + self.designer.selectLastVisitedSlice(); + }; + + // Triggered when changes have been downloaded from the WRC backend, for the active WDT Model File provider. + // + this.changesAutoDownloaded = (event) => { + self.project.wdtModel.modelContent(event.detail.value); + }; + + // 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'}; + }; + + // Triggered when WDT Model Designer has lost its connection to the WRC backend. + // + this.connectionLostRefused = (event) => { + wktLogger.debug('connectionLostRefused: backendUrl=%s', event.detail.value); + if (self.designer) { + self.designer.visible = false; + } + self.project.wdtModel.internal.wlRemoteConsolePort(undefined); + }; const wrcInitialText = this.labelMapper('wrc-install-description'); const wrcInstallLocation = ' { const rcHome = this.project.wdtModel.internal.wlRemoteConsoleHome.observable(); - // TODO - do we need a busy dialog? + // Set cursor to BUSY and let the 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); }; } diff --git a/webui/src/js/views/model-design-view.html b/webui/src/js/views/model-design-view.html index bcac442b9..768775380 100644 --- a/webui/src/js/views/model-design-view.html +++ b/webui/src/js/views/model-design-view.html @@ -2,12 +2,13 @@ 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/ --> -
- -
-

-
-
+
+ +