From a2616afa4a27509f681f772f31341edd0f183c7a Mon Sep 17 00:00:00 2001 From: Robert Patrick Date: Mon, 7 Feb 2022 17:56:47 -0600 Subject: [PATCH 01/99] moving version to 1.2.0 --- electron/package-lock.json | 4 ++-- electron/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/electron/package-lock.json b/electron/package-lock.json index e027d40fa..cbd5c4287 100644 --- a/electron/package-lock.json +++ b/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "wktui", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wktui", - "version": "1.1.1", + "version": "1.2.0", "license": "UPL-1.0", "dependencies": { "electron-updater": "^4.6.5", diff --git a/electron/package.json b/electron/package.json index decf2e8d6..062d5a402 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,7 +1,7 @@ { "name": "wktui", "productName": "WebLogic Kubernetes Toolkit UI", - "version": "1.1.1", + "version": "1.2.0", "description": "WebLogic Kubernetes Toolkit UI", "copyright": "Copyright (c) 2021, 2022, Oracle and/or its affiliates.", "homepage": "https://github.com/oracle/weblogic-toolkit-ui", From edb5a6bab3c8d40e021eee760a2c39fbeb7e679b Mon Sep 17 00:00:00 2001 From: Robert Patrick <31662131+robertpatrick@users.noreply.github.com> Date: Thu, 10 Feb 2022 18:36:41 -0600 Subject: [PATCH 02/99] initial commit for RC integration scaffolding (#93) * initial commit for RC integration scaffolding * adding version checking code * rearranging version checking * removing extra spaces * fixing typo --- electron/app/js/childProcessExecutor.js | 24 +- electron/app/js/ipcRendererPreload.js | 7 +- electron/app/js/userSettings.js | 20 +- electron/app/js/wlRemoteConsoleUtils.js | 488 ++++++++++++++++++ electron/app/locales/en/electron.json | 25 +- electron/app/locales/en/webui.json | 15 + electron/app/main.js | 40 ++ url-catalog.json | 3 + webui/src/js/models/wdt-model-definition.js | 2 + webui/src/js/viewModels/model-design-view.js | 91 +++- .../src/js/viewModels/user-settings-dialog.js | 37 +- webui/src/js/views/model-design-view.html | 44 +- webui/src/js/views/user-settings-dialog.html | 19 + webui/src/js/windowStateUtils.js | 6 +- 14 files changed, 791 insertions(+), 30 deletions(-) create mode 100644 electron/app/js/wlRemoteConsoleUtils.js diff --git a/electron/app/js/childProcessExecutor.js b/electron/app/js/childProcessExecutor.js index c0c44296d..209af5d80 100644 --- a/electron/app/js/childProcessExecutor.js +++ b/electron/app/js/childProcessExecutor.js @@ -1,6 +1,6 @@ /** * @license - * Copyright (c) 2021, Oracle and/or its affiliates. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. */ const { exec, execFile, spawn } = require('child_process'); @@ -45,7 +45,20 @@ async function executeChildProcess(currentWindow, executable, argList, env, stdo return child.exitCode; } -function getSpawnOptions(env, shell, detached, windowsHide) { +function spawnDaemonChildProcess(executable, argList, env, extraOptions = {}, { + shell = false, + detached = false, + windowHide = true, +} = {}) { + const command = workaroundNodeJsIssue38490(shell, executable, argList); + const options = getSpawnOptions(env, shell, detached, windowHide, extraOptions); + + getLogger().debug('Spawning daemon process %s with arguments %s and options %s', + command.executable, command.argList, JSON.stringify(options)); + return spawn(command.executable, command.argList, options); +} + +function getSpawnOptions(env, shell, detached, windowsHide, extraOptions = {}) { const options = { stdio: [ 'pipe', 'pipe', 'pipe' ], shell: shell, @@ -56,6 +69,10 @@ function getSpawnOptions(env, shell, detached, windowsHide) { if (envIsNotEmpty(env)) { options['env'] = env; } + + for (const [key, value] of Object.entries(extraOptions)) { + options[key] = value; + } return options; } @@ -199,5 +216,6 @@ module.exports = { executeChildProcess, executeChildShellScript, executeFileCommand, - executeScriptCommand + executeScriptCommand, + spawnDaemonChildProcess }; diff --git a/electron/app/js/ipcRendererPreload.js b/electron/app/js/ipcRendererPreload.js index be76317f6..051f186a2 100644 --- a/electron/app/js/ipcRendererPreload.js +++ b/electron/app/js/ipcRendererPreload.js @@ -50,6 +50,7 @@ contextBridge.exposeInMainWorld( 'project-created', 'project-opened', 'project-saved', + 'set-wrc-backend-port', 'start-add-model-file', 'start-add-variable-file', 'start-add-archive-file', @@ -198,7 +199,11 @@ contextBridge.exposeInMainWorld( 'k8s-delete-object', 'openssl-generate-certs', 'validate-k8s-namespaces-exist', - 'validate-wko-domain-exist' + 'validate-wko-domain-exist', + 'get-wrc-home-directory', + 'get-wrc-app-image', + 'wrc-get-home-default-value', + 'wrc-set-home-and-start' ]; return new Promise((resolve, reject) => { if (validChannels.includes(channel)) { diff --git a/electron/app/js/userSettings.js b/electron/app/js/userSettings.js index b3e293e3f..ca302ddc3 100644 --- a/electron/app/js/userSettings.js +++ b/electron/app/js/userSettings.js @@ -11,6 +11,7 @@ const { getErrorMessage } = require('./errorUtils'); // eslint-disable-next-line no-unused-vars const userSettableFieldNames = [ + 'webLogicRemoteConsoleHome', 'proxy', 'logging', 'skipQuickstartAtStartup', @@ -31,6 +32,7 @@ let _userSettingsFileName; // Here is an example with every possible field specified: // // { +// "webLogicRemoteConsoleHome": "The path to the WebLogic Remote Console installation", // "proxy": { // "httpsProxyUrl": "The proxy to use for the application's all https outbound communication", // "bypassProxyHosts: "The value to use to set the NO_PROXY environment variable for child processes" @@ -89,6 +91,20 @@ function applyUserSettingsFromRemote(remoteUserSettingsJson) { logger.debug('user settings saved...restart the application to pick up logger settings changes'); } +function getWebLogicRemoteConsoleHome() { + let wlRemoteConsoleHome; + const userSettingsObj = _getUserSettings(); + if ('webLogicRemoteConsoleHome' in userSettingsObj) { + wlRemoteConsoleHome = userSettingsObj['webLogicRemoteConsoleHome']; + } + return wlRemoteConsoleHome; +} + +function setWebLogicRemoteConsoleHome(wlRemoteConsoleHome) { + const settings = _getUserSettings(); + settings['webLogicRemoteConsoleHome'] = wlRemoteConsoleHome; +} + function getHttpsProxyUrl() { let httpsProxyUrl; const userSettingsObj = _getUserSettings(); @@ -413,5 +429,7 @@ module.exports = { setWindowSize, getLoggingConfiguration, getUserSettingsForRemote, - saveUserSettings + saveUserSettings, + getWebLogicRemoteConsoleHome, + setWebLogicRemoteConsoleHome }; diff --git a/electron/app/js/wlRemoteConsoleUtils.js b/electron/app/js/wlRemoteConsoleUtils.js new file mode 100644 index 000000000..c7021da6a --- /dev/null +++ b/electron/app/js/wlRemoteConsoleUtils.js @@ -0,0 +1,488 @@ +/** + * @license + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + */ +'use strict'; + +const path = require('path'); +const readline = require('readline'); +const { app, dialog } = require('electron'); +const fsPromises = require('fs/promises'); + +const userSettings = require('./userSettings'); +const fsUtils = require('./fsUtils'); +const i18n = require('./i18next.config'); +const { getErrorMessage } = require('./errorUtils'); +const { getLogger } = require('./wktLogging'); +const osUtils = require('./osUtils'); +const { sendToWindow } = require('./windowUtils'); +const { spawnDaemonChildProcess } = require('./childProcessExecutor'); + +// TODO - Change this to the correct version once the RC version changes to 2.3.0... +const MIN_VERSION = '2.2.0'; +const MIN_VERSION_COMPONENTS = MIN_VERSION.split('.').map((item) => { return Number(item); }); +let _wlRemoteConsoleChildProcess; + + +async function startWebLogicRemoteConsoleBackend(currentWindow, skipVersionCheck = false) { + if (_wlRemoteConsoleChildProcess) { + return Promise.resolve(); + } + + return new Promise((resolve) => { + _getWebLogicRemoteConsoleHome(skipVersionCheck).then(rcHome => { + if (!rcHome) { + return resolve(); + } + _getWebLogicRemoteConsoleExecutableData(rcHome).then(result => { + const executable = result['executable']; + const argList = result['arguments']; + const options = result['options']; + + _wlRemoteConsoleChildProcess = spawnDaemonChildProcess(executable, argList, null, options); + _wlRemoteConsoleChildProcess.on('error', (err) => { + const title = i18n.t('wrc-spawn-error-title'); + dialog.showErrorBox(title, getErrorMessage(err)); + }); + _wlRemoteConsoleChildProcess.on('exit', (code) => { + getLogger().info('WebLogic Remote Console backend process exited with code %s', code); + }); + + const stdoutLines = readline.createInterface({ input: _wlRemoteConsoleChildProcess.stdout }); + const stderrLines = readline.createInterface({ input: _wlRemoteConsoleChildProcess.stderr }); + + let foundPort = false; + const portRegex = /^Port=(\d+)\s?$/; + stdoutLines.on('line', (line) => { + getLogger().debug('WebLogic Remote Console stdout: %s', line.trim()); + if (!foundPort) { + const matcher = line.match(portRegex); + if (matcher) { + foundPort = true; + sendToWindow(currentWindow, 'set-wrc-backend-port', matcher[1]); + } + } + }); + stderrLines.on('line', (line) => { + getLogger().debug('WebLogic Remote Console stderr: %s', line.trim()); + }); + resolve(); + }).catch(err => { + const title = i18n.t('wrc-init-error-title'); + dialog.showErrorBox(title, getErrorMessage(err)); + resolve(); + }); + }).catch(err => { + const title = i18n.t('wrc-home-error-title'); + dialog.showErrorBox(title, getErrorMessage(err)); + resolve(); + }); + }); +} + +async function setWebLogicRemoteConsoleHomeAndStart(currentWindow, rcHome) { + const title = i18n.t('wrc-set-and-start-error-title'); + return new Promise(resolve => { + fsUtils.exists(rcHome).then(doesExist => { + if (!doesExist) { + const message = i18n.t('wrc-set-home-not-exists', { rcHome: rcHome }); + dialog.showErrorBox(title, message); + return resolve(); + } + + _isCompatibleVersion(rcHome).then(isCompatibleResult => { + getLogger().debug('_isCompatibleVersion() returned %s', JSON.stringify(isCompatibleResult)); + if (isCompatibleResult.isCompatible) { + userSettings.setWebLogicRemoteConsoleHome(rcHome); + startWebLogicRemoteConsoleBackend(currentWindow, true).then(() => resolve() ); + } else { + const message = i18n.t('wrc-version-incompatible-message', + { rcVersion: isCompatibleResult['version'], minVersion: MIN_VERSION }); + dialog.showErrorBox(title, message); + return resolve(); + } + }).catch(err => { + dialog.showErrorBox(title, getErrorMessage(err)); + return resolve(); + }); + }).catch(err => { + const message = i18n.t('wrc-set-home-existence-check-failed', { rcHome: rcHome, error: getErrorMessage(err) }); + dialog.showErrorBox(title, message); + resolve(); + }); + }); +} + +async function getDefaultWebLogicRemoteConsoleHome() { + let rcHome = userSettings.getWebLogicRemoteConsoleHome(); + if (rcHome) { + return Promise.resolve(rcHome); + } + + // This only works if the WebLogic Remote Console is installed and has been run at least once. + // + rcHome = await _getLocationFromPreferencesFile(); + if (rcHome) { + return Promise.resolve(rcHome); + } + + // Just in case the WebLogic Remote Console is installed but has never been run... + // + if (osUtils.isMac()) { + return _getDefaultLocationForMacOS(); + } else if (osUtils.isWindows()) { + return _getDefaultLocationForWindows(); + } else { + return _getDefaultLocationForLinux(); + } +} + +function getDefaultDirectoryForOpenDialog(isAppImage = false) { + let result; + if (osUtils.isMac()) { + result = '/Applications'; + } else if (osUtils.isWindows()) { + result = path.normalize(path.join(path.dirname(app.getPath('exe')), '..')); + } else if (isAppImage) { + result = app.getPath('home'); + } else { + result = '/opt'; + } + return result; +} + +async function _getWebLogicRemoteConsoleHome(skipVersionCheck = false) { + const rcHome = userSettings.getWebLogicRemoteConsoleHome(); + if (!rcHome) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + fsUtils.exists(rcHome).then(doesExist => { + if (doesExist) { + if (!skipVersionCheck) { + _isCompatibleVersion(rcHome).then(isCompatibleResult => { + if (isCompatibleResult['isCompatible']) { + resolve(rcHome); + } else { + const message = i18n.t('wrc-version-incompatible-message', + { rcVersion: isCompatibleResult['version'], minVersion: MIN_VERSION }); + reject(new Error(message)); + } + }).catch(err => reject(err)); + } else { + resolve(rcHome); + } + } else { + const message = i18n.t('wrc-home-not-exist', { rcHome: rcHome }); + reject(new Error(message)); + } + }).catch(err => { + const message = i18n.t('wrc-location-existence-check-failed', { location: rcHome, error: getErrorMessage(err) }); + reject(new Error(message)); + }); + }); +} + +async function _isCompatibleVersion(rcHome) { + let packageJsonFile; + if (osUtils.isMac()) { + packageJsonFile = path.join(rcHome, 'Contents', 'MacOS', 'package.json'); + } else if (osUtils.isWindows()) { + packageJsonFile = path.join(rcHome, 'package.json'); + } else { + // For Linux, the rcHome is either a directory or a path to an AppImage file. + // + let isDirectory; + try { + isDirectory = await fsUtils.isDirectory(rcHome); + } catch (err) { + const message = i18n.t('wrc-linux-executable-directory-check-failed', + { rcHome: rcHome, error: getErrorMessage(err) }); + return Promise.reject(new Error(message)); + } + + if (isDirectory) { + packageJsonFile = path.join(rcHome, 'package.json'); + } + } + + return new Promise((resolve, reject) => { + _verifyVersionCompatibility(packageJsonFile, rcHome).then(versionResult => { + resolve(versionResult); + }).catch(err => { + const message = i18n.t('wrc-version-verification-failed', { error: getErrorMessage(err) }); + reject(new Error(message)); + }); + }); +} + +async function _getWebLogicRemoteConsoleExecutableData(rcHome) { + // The first thing we need to do is to determine if the Remote Console "home" + // is a dev install or not. + // + // In a dev install, the assumption is that the home is set to /electron. + // + const results = { }; + if (rcHome.endsWith('electron')) { + const pathToDirectoryWithExecutable = path.join(rcHome, 'node_modules', 'electron', 'dist'); + return new Promise((resolve, reject) => { + fsUtils.isDirectory(pathToDirectoryWithExecutable).then(doesExist => { + if (!doesExist) { + const message = i18n.t('wrc-dev-executable-directory-not-exists', + { rcHome: rcHome, location: pathToDirectoryWithExecutable }); + return reject(new Error(message)); + } + + _getDevExecutablePath(rcHome, pathToDirectoryWithExecutable).then(exeResult => { + if (exeResult.exists) { + results['executable'] = exeResult.executable; + results['arguments'] = ['.', 'dev', '--showPort', '--stdin', '--quiet', '--headless']; + results['options'] = { cwd: rcHome }; + } else { + const message = i18n.t('wrc-dev-executable-existence-check-failed', + { rcHome: rcHome, executable: exeResult['executable'] }); + reject(new Error(message)); + } + }).catch(err => reject(err)); + }).catch(err => reject(err)); + }); + } + + // If we get here, this is an (installed) executable environment. + // + return new Promise((resolve, reject) => { + _getInstalledExecutablePath(rcHome).then(exeResult => { + if (exeResult['exists']) { + results['executable'] = exeResult['executable']; + results['arguments'] = ['--showPort', '--stdin', '--quiet', '--headless']; + resolve(results); + } else { + const message = i18n.t('wrc-executable-not-exists', { rcHome: rcHome, executable: results['executable'] }); + reject(new Error(message)); + } + }).catch(err => reject(err)); + }); +} + +async function _getDevExecutablePath(rcHome, pathToDirectoryWithExecutable) { + const result = { + exists: true + }; + + if (osUtils.isMac()) { + result['executable'] = path.join(pathToDirectoryWithExecutable, 'Electron.app', 'Contents', 'MacOS', 'Electron'); + } else { + result['executable'] = path.join(pathToDirectoryWithExecutable, `electron${osUtils.isWindows() ? '.exe' : ''}`); + } + + return new Promise((resolve, reject) => { + fsUtils.exists(result['executable']).then(doesExist => { + if (!doesExist) { + result['exists'] = false; + } + resolve(result); + }).catch(err => { + const message = i18n.t('wrc-dev-executable-existence-check-failed', + { rcHome: rcHome, executable: result['executable'], error: getErrorMessage(err) }); + reject(new Error(message)); + }); + }); +} + +async function _getInstalledExecutablePath(rcHome) { + const result = { + exists: true + }; + + if (osUtils.isMac()) { + result['executable'] = path.join(rcHome, 'Contents', 'MacOS', 'WebLogic Remote Console'); + } else if (osUtils.isWindows()) { + result['executable'] = path.join(rcHome, 'WebLogic Remote Console.exe'); + } else { + // For Linux, the rcHome is either a directory or a path to an AppImage file. + // + let isDirectory; + try { + isDirectory = await fsUtils.isDirectory(rcHome); + } catch (err) { + const message = i18n.t('wrc-linux-executable-directory-check-failed', + { rcHome: rcHome, error: getErrorMessage(err) }); + return Promise.reject(new Error(message)); + } + + if (isDirectory) { + result['executable'] = path.join(rcHome, 'weblogic-remote-console'); + } else { + result['executable'] = rcHome; + } + } + + return new Promise((resolve, reject) => { + fsUtils.exists(result['executable']).then(doesExist => { + result['exists'] = doesExist; + resolve(result); + }).catch(err => { + const message = i18n.t('wrc-executable-existence-check-failed', + {rcHome: rcHome, executable: result['executable'], error: getErrorMessage(err) }); + reject(new Error(message)); + }); + }); +} + +async function _verifyVersionCompatibility(packageJsonFile, executablePath) { + const result = { + isCompatible: false + }; + + if (packageJsonFile) { + return new Promise((resolve, reject) => { + fsUtils.exists(packageJsonFile).then(doesExist => { + if (doesExist) { + const packageJson = require(packageJsonFile); + if (packageJson.version) { + result['version'] = packageJson.version; + result['isCompatible'] = _verifyVersionNumberCompatibility(packageJson.version); + resolve(result); + } else { + const message = i18n.t('wrc-package-json-missing-version', { packageJsonFile: packageJsonFile }); + reject(new Error(message)); + } + } else { + const message = i18n.t('wrc-package-json-file-missing', { packageJsonFile: packageJsonFile }); + reject(new Error(message)); + } + }).catch(err => { + const message = i18n.t('wrc-package-json-existence-check-failed', + {packageJsonFile: packageJsonFile, error: getErrorMessage(err)}); + reject(new Error(message)); + }); + }); + } + + // If we get here, that means the user is using the AppImage file. + // All we can really do is try to look at the file name for the + // version number and hope that they didn't change the file name... + // + const appImageRegex = /^WebLogic.Remote.Console-(\d+\.\d+\.\d+)\.AppImage$/; + const executableFileName = path.basename(executablePath); + const matcher = executableFileName.match(appImageRegex); + if (matcher) { + result['version'] = matcher[1]; + result['isCompatible'] = _verifyVersionNumberCompatibility(matcher[1]); + return Promise.resolve(result); + } else { + const message = i18n.t('wrc-app-image-file-version-no-match', + { rcHone: executablePath, filename: executableFileName }); + return Promise.reject(new Error(message)); + } +} + +function _verifyVersionNumberCompatibility(actualVersion) { + const versionComponents = actualVersion.split('.').map((item) => { return Number(item); }); + + let versionIsCompatible = true; + for (let i = 0; i < 3; i++) { + if (versionComponents[i] < MIN_VERSION_COMPONENTS[i]) { + versionIsCompatible = false; + break; + } + } + return versionIsCompatible; +} + +async function _getLocationFromPreferencesFile() { + const autoPrefsLocation = path.join(app.getPath('appData'), 'weblogic-remote-console', 'auto-prefs.json'); + + return new Promise(resolve => { + fsUtils.exists(autoPrefsLocation).then(doesExist => { + if (!doesExist) { + return resolve(); + } + + fsPromises.readFile(autoPrefsLocation, { encoding: 'utf8' }).then(contents => { + try { + const props = JSON.parse(contents); + resolve(props.location); + } catch (err) { + getLogger().debug('Failed to parse file %s: %s', autoPrefsLocation, getErrorMessage(err)); + resolve(); + } + }).catch(err => { + getLogger().debug('Failed to read file %s: %s', autoPrefsLocation, getErrorMessage(err)); + resolve(); + }); + }).catch(err => { + getLogger().debug('Failed to determine whether the file %s exists: %s', autoPrefsLocation, getErrorMessage(err)); + resolve(); + }); + }); +} + +async function _getDefaultLocationForMacOS() { + const defaultLocation = '/Applications/WebLogic Remote Console.app'; + return new Promise(resolve => { + fsUtils.exists(defaultLocation).then(doesExist => { + if (doesExist) { + resolve(defaultLocation); + } else { + resolve(); + } + }).catch(err => { + getLogger().debug('Existence check for default WebLogic Remote Console Home location %s failed: %s', + defaultLocation, getErrorMessage(err)); + resolve(); + }); + }); +} + +async function _getDefaultLocationForWindows() { + const defaultAllUsersLocation = 'c:\\Program Files\\WebLogic Remote Console'; + fsUtils.exists(defaultAllUsersLocation).then(doesExist => { + if (doesExist) { + return Promise.resolve(defaultAllUsersLocation); + } + // fall through to check the alternate location... + }).catch(err => { + getLogger().debug('Existence check for default WebLogic Remote Console Home location %s failed: %s', + defaultAllUsersLocation, getErrorMessage(err)); + return Promise.resolve(); + }); + + const defaultLocation = path.join(app.getPath('appData'), 'Local', 'Programs', 'WebLogic Remote Console'); + fsUtils.exists(defaultLocation).then(doesExist => { + if (doesExist) { + return Promise.resolve(defaultLocation); + } + return Promise.resolve(); + }).catch(err => { + getLogger().debug('Existence check for default WebLogic Remote Console Home location %s failed: %s', + defaultAllUsersLocation, getErrorMessage(err)); + return Promise.resolve(); + }); +} + +async function _getDefaultLocationForLinux() { + const defaultLocation = '/opt/WebLogic Remote Console'; + return new Promise(resolve => { + fsUtils.exists(defaultLocation).then(doesExist => { + if (doesExist) { + resolve(defaultLocation); + } else { + resolve(); + } + }).catch(err => { + getLogger().debug('Existence check for default WebLogic Remote Console Home location %s failed: %s', + defaultLocation, getErrorMessage(err)); + resolve(); + }); + }); +} + +module.exports = { + getDefaultDirectoryForOpenDialog, + getDefaultWebLogicRemoteConsoleHome, + setWebLogicRemoteConsoleHomeAndStart, + startWebLogicRemoteConsoleBackend +}; diff --git a/electron/app/locales/en/electron.json b/electron/app/locales/en/electron.json index 51b23c4fd..4d068d3db 100644 --- a/electron/app/locales/en/electron.json +++ b/electron/app/locales/en/electron.json @@ -180,6 +180,8 @@ "dialog-chooseArchiveEntry": "Choose {{entryType}} for Archive", "dialog-archiveEntryFilter": "{{entryType}}", + "dialog-getWebLogicRemoteConsoleHome": "Select the WebLogic Remote Console Installation", + "dialog-getWebLogicRemoteConsoleAppImage": "Select the WebLogic Remote Console AppImage file", "title-edited": "edited", @@ -363,5 +365,26 @@ "wkt-tools-wdt-version-not-compatible-error": "The installed WebLogic Deploy Tooling version {{version}} does not meet the minimum compatible version {{minimumVersion}} required by WebLogic Kubernetes Toolkit UI version {{wktuiVersion}}", "project-save-file-already-open-title": "Project File Already Open", - "project-save-file-already-open-message": "The project file {{projectFile}} is already open in another window. Please either close the existing window or select a different project file and try again." + "project-save-file-already-open-message": "The project file {{projectFile}} is already open in another window. Please either close the existing window or select a different project file and try again.", + + "wrc-home-error-title": "Invalid WebLogic Remote Console Location", + "wrc-init-error-title": "Initializing WebLogic Remote Console Backend Failed", + "wrc-location-existence-check-failed": "Unable to start the WebLogic Remote Console backend at {{location}} due to an error while trying to determine its existence: {{error}}.", + "wrc-dev-executable-directory-not-exists": "Unable to start the WebLogic Remote Console backend in development mode at {{rcHome}} because the expected directory {{location}} does not exist.", + "wrc-dev-executable-not-exists": "Unable to start the WebLogic Remote Console backend in development mode at {{rcHome}} because the executable file {{executable}} does not exist.", + "wrc-dev-executable-existence-check-failed": "Unable to start the WebLogic Remote Console backend in development mode at {{rcHome}} because the existence check for the executable file {{executable}} failed: {{error}}.", + "wrc-linux-executable-directory-check-failed": "Unable to start the WebLogic Remote Console backend at {{rcHome}} because the check to determine if {{rcHome}} is a Linux directory or an AppImage file failed: {{error}}.", + "wrc-executable-existence-check-failed": "Unable to start the WebLogic Remote Console backend at {{rcHome}} because existence check for the executable file {{executable}} failed: {{error}}.", + "wrc-executable-not-exists": "Unable to start the WebLogic Remote Console backend at {{rcHome}} because the executable file {{executable}} does not exist.", + "wrc-spawn-error-title": "Starting WebLogic Remote Console Backend Failed", + "wrc-set-home-not-exists": "Unable to set the WebLogic Remote Console Home because {{rcHome}} does not exist.", + "wrc-set-home-existence-check-failed": "Unable to set the WebLogic Remote Console Home because the existence check for {{rcHome}} failed: {{error}}.", + "wrc-set-and-start-error-title": "Starting WebLogic Remote Console Backend Failed", + "wrc-package-json-file-missing": "Unable to determine the WebLogic Remote Console version because the {{packageJsonFile}} file was missing.", + "wrc-package-json-missing-version": "Unable to determine the WebLogic Remote Console version because the {{packageJsonFile}} file was missing the version element.", + "wrc-package-json-existence-check-failed": "Unable to determine the WebLogic Remote Console version because the existence check for {{packageJsonFile}} failed: {{error}}.", + "wrc-app-image-file-version-no-match": "Unable to determine the WebLogic Remote Console version because the location {{rcHome}} AppImage file name {{filename}} does not match the expected filename pattern needed to extract the version number.", + "wrc-version-incompatible-message": "The WebLogic Remote Console version {{rcVersion}} does not meet the minimum version requirement of {{minVersion}}.", + "wrc-version-verification-failed": "Unable to start the WebLogic Remote Console backend because an error occurred while trying to determine the version compatibility: {{error}}", + "wrc-home-not-exist": "Unable to start the WebLogic Remote Console backend because the configured location {{rcHome}} does not exist." } diff --git a/electron/app/locales/en/webui.json b/electron/app/locales/en/webui.json index 30de76d27..95126758a 100644 --- a/electron/app/locales/en/webui.json +++ b/electron/app/locales/en/webui.json @@ -160,6 +160,12 @@ "user-settings-dialog-https-proxy-url-help": "The proxy server URL to use for all outbound HTTPS requests (e.g., http://myproxy:80)", "user-settings-dialog-bypass-proxy-hosts-label": "Bypass Proxy Hosts", "user-settings-dialog-bypass-proxy-hosts-help": "The list of hostnames or patterns to use to set the NO_PROXY environment variable. Please see NO_PROXY documentation for legal values.", + "user-settings-dialog-wrc-section-title": "WebLogic Remote Console Configuration", + "user-settings-dialog-wrc-home-label": "WebLogic Remote Console Install Location", + "user-settings-dialog-wrc-home-macos-help": "The location of the WebLogic Remote Console.app, typically /Applications/WebLogic Remote Console.app.", + "user-settings-dialog-wrc-home-windows-help": "The location of the WebLogic Remote Console installation directory.", + "user-settings-dialog-wrc-home-linux-help": "The location of the WebLogic Remote Console installation. For RPM or DEB installers, this will typically be /opt/WebLogic Remote Console. If using the AppImage, simply point to the AppImage file directly.", + "user-settings-dialog-logging-section-title": "Logging Configuration", "user-settings-dialog-console-level-label": "Console Transport Log Level", "user-settings-dialog-console-level-help": "The log level to use to filter output to the console.", @@ -181,6 +187,15 @@ "model-design-form-name": "Model", "model-design-coming-soon": "Coming Soon...", + "model-design-wrc-form-title": "WebLogic Remote Console Integration", + "model-design-wrc-home-label": "WebLogic Remote Console Install Location", + "model-design-wrc-install-description": "The Model Design View is provided through integration with the WebLogic Remote Console. Install the WebLogic Remote Console on the local machine and use the form below to provide its location and start the daemon process with which the UI will communicate. Note that this integration required WebLogic Remote Console version 2.3.0 or newer.", + "model-design-wrc-install-location-prefix": "Download and run the appropriate installer for your machine from the GitHub", + "model-design-wrc-link-text": "WebLogic Remote Console Releases", + "model-design-wrc-install-location-postfix": "page.", + "model-design-wrc-start-description": "Once the WebLogic Remote Console is installed, set the WebLogic Remote Console Install Location field below accordingly and press the Start WebLogic Remote Console button.", + "model-design-button-startWebLogicRemoteConsole": "Start WebLogic Remote Console", + "model-design-hints-startWebLogicRemoteConsole": "Start the WebLogic Remote Console backend process", "image-page-hints-createImage": "Create Primary Image", "image-page-button-createImage": "Create Primary Image", diff --git a/electron/app/main.js b/electron/app/main.js index c706330d7..cdeab6917 100644 --- a/electron/app/main.js +++ b/electron/app/main.js @@ -34,6 +34,8 @@ const helmUtils = require('./js/helmUtils'); 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'); const { getHttpsProxyUrl, getBypassProxyHosts } = require('./js/userSettings'); const { sendToWindow } = require('./js/windowUtils'); @@ -153,6 +155,8 @@ class Main { } createWindow(this._isJetDevMode, this._wktApp).then(win => { + startWebLogicRemoteConsoleBackend(win).then(); + if (filePath) { win.once('ready-to-show', () => { this.openProjectFileInWindow(win, filePath); @@ -206,6 +210,7 @@ class Main { this._logger.debug('Received window-is-ready for window %d', event.sender.getOwnerBrowserWindow().id); const currentWindow = event.sender.getOwnerBrowserWindow(); currentWindow.isReady = true; + project.sendProjectOpened(currentWindow).then(async () => { if (!this._startupDialogsShownAlready) { const startupInformation = { @@ -891,6 +896,41 @@ class Main { // called before any projects opened, no need for extra checks app.quit(); }); + + ipcMain.handle('get-wrc-home-directory', async (event) => { + const title = i18n.t('dialog-getWebLogicRemoteConsoleHome'); + const properties = osUtils.isMac() ? [ 'openFile', 'dontAddToRecent' ] : [ 'openDirectory', 'dontAddToRecent' ]; + return chooseFromFileSystem(event.sender.getOwnerBrowserWindow(), { + title: title, + defaultPath: getDefaultDirectoryForOpenDialog(), + message: title, + buttonLabel: i18n.t('button-select'), + properties: properties + }); + }); + + ipcMain.handle('get-wrc-app-image', async (event) => { + const title = i18n.t('dialog-getWebLogicRemoteConsoleAppImage'); + return chooseFromFileSystem(event.sender.getOwnerBrowserWindow(), { + title: title, + defaultPath: getDefaultDirectoryForOpenDialog(true), + message: title, + buttonLabel: i18n.t('button-select'), + properties: [ 'openFile', 'dontAddToRecent' ], + filters: [ + { name: 'AppImage Files', extensions: ['AppImage'] } + ] + }); + }); + + ipcMain.handle('wrc-set-home-and-start', async (event, wlRemoteConsoleHome) => { + return setWebLogicRemoteConsoleHomeAndStart(event.sender.getOwnerBrowserWindow(), wlRemoteConsoleHome); + }); + + // eslint-disable-next-line no-unused-vars + ipcMain.handle('wrc-get-home-default-value', async (event) => { + return getDefaultWebLogicRemoteConsoleHome(); + }); } async getLatestWdtInstaller(targetWindow) { diff --git a/url-catalog.json b/url-catalog.json index d29596c32..7441ebb53 100644 --- a/url-catalog.json +++ b/url-catalog.json @@ -1,4 +1,7 @@ { + "model": { + "weblogicRemoteConsoleLatestRelease": "https://github.com/oracle/weblogic-remote-console/releases/latest" + }, "image": { "imageTagFormat": "https://docs.docker.com/engine/reference/commandline/tag/#extended-description" }, diff --git a/webui/src/js/models/wdt-model-definition.js b/webui/src/js/models/wdt-model-definition.js index e6c566cf8..c0650163d 100644 --- a/webui/src/js/models/wdt-model-definition.js +++ b/webui/src/js/models/wdt-model-definition.js @@ -40,6 +40,8 @@ define(['knockout', 'utils/observable-properties', 'js-yaml', 'utils/validation- // internal values that are implemented as properties, but are excluded from default serialization this.internal = { + wlRemoteConsolePort: ko.observable(), + wlRemoteConsoleHome: props.createProperty(window.api.ipc.invoke('wrc-get-home-default-value')), propertiesContent: createPropertiesObject({}) }; diff --git a/webui/src/js/viewModels/model-design-view.js b/webui/src/js/viewModels/model-design-view.js index 43c07f0df..5cac655ba 100644 --- a/webui/src/js/viewModels/model-design-view.js +++ b/webui/src/js/viewModels/model-design-view.js @@ -1,26 +1,83 @@ /** * @license - * Copyright (c) 2021, Oracle and/or its affiliates. + * 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'], - function(accUtils, i18n) { - function ModelDesignViewModel() { +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.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.labelMapper = (labelId, payload) => { + return i18n.t(`model-design-${labelId}`, payload); + }; - } + this.isLinux = () => { + return window.api.process.isLinux(); + }; - /* - * Returns a constructor for the ViewModel. - */ - return ModelDesignViewModel; + 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. + */ + return ModelDesignViewModel; +}); diff --git a/webui/src/js/viewModels/user-settings-dialog.js b/webui/src/js/viewModels/user-settings-dialog.js index 50ed22c37..734b34ea6 100644 --- a/webui/src/js/viewModels/user-settings-dialog.js +++ b/webui/src/js/viewModels/user-settings-dialog.js @@ -22,6 +22,10 @@ function(accUtils, ko, utils, i18n, ArrayDataProvider, project, wktLogger) { return i18n.t(`user-settings-dialog-${labelId}`); }; + this.isLinux = () => { + return window.api.process.isLinux(); + }; + this.userSettings = {}; try { this.userSettings = JSON.parse(payload['userSettingsJson']); @@ -49,6 +53,7 @@ function(accUtils, ko, utils, i18n, ArrayDataProvider, project, wktLogger) { this.connectivityTestTimeoutSeconds = ko.observable(payload.defaults.connectivityTestTimeoutMilliseconds / 1000); this.internalConnectivityTestTimeoutMilliseconds = ko.observable(payload.defaults.connectivityTestTimeoutMilliseconds); this.skipQuickstart = ko.observable(false); + this.wlRemoteConsoleHome = ko.observable(); this.loadUserSettings = () => { if ('proxy' in this.userSettings) { @@ -87,12 +92,42 @@ function(accUtils, ko, utils, i18n, ArrayDataProvider, project, wktLogger) { if ('skipQuickstartAtStartup' in this.userSettings) { this.skipQuickstart(this.userSettings.skipQuickstartAtStartup); } + + if ('webLogicRemoteConsoleHome' in this.userSettings) { + this.wlRemoteConsoleHome(this.userSettings.webLogicRemoteConsoleHome); + } }; this.chooseLogFileDir = async () => { this.fileLogDir(await window.api.ipc.invoke('get-log-file-directory-location')); }; + this.chooseWebLogicRemoteConsoleHomeDirectory = async () => { + const rcHome = await window.api.ipc.invoke('get-wrc-home-directory'); + if (rcHome) { + this.wlRemoteConsoleHome(rcHome); + } + }; + + this.chooseWebLogicRemoteConsoleAppImage = async () => { + const rcHome = await window.api.ipc.invoke('get-wrc-app-image'); + if (rcHome) { + this.wlRemoteConsoleHome(rcHome); + } + }; + + this.getWebLogicRemoteConsoleHomeHelp = () => { + let helpKey; + if (window.api.process.isMac()) { + helpKey = 'wrc-home-macos-help'; + } else if (window.api.process.isWindows()) { + helpKey = 'wrc-home-windows-help'; + } else { + helpKey = 'wrc-home-linux-help'; + } + return this.labelMapper(helpKey); + }; + this.storeUserSettings = () => { project.setHttpsProxyUrl(this.proxyUrl()); project.setBypassProxyHosts(this.bypassProxyHosts()); @@ -107,12 +142,12 @@ function(accUtils, ko, utils, i18n, ArrayDataProvider, project, wktLogger) { this.internalConnectivityTestTimeoutMilliseconds, payload.defaults.connectivityTestTimeoutMilliseconds); } this._storeSetting('skipQuickstartAtStartup', this.skipQuickstart, false); + this._storeSetting('webLogicRemoteConsoleHome', this.wlRemoteConsoleHome); }; this._storeSetting = (key, observable, defaultValue) => { const keyPath = key.split('.'); if (defaultValue === undefined || defaultValue !== observable()) { - let currentObj = this.userSettings; for (let i = 0; i < keyPath.length - 1; i++) { if (!(keyPath[i] in currentObj)) { diff --git a/webui/src/js/views/model-design-view.html b/webui/src/js/views/model-design-view.html index c6495f68e..bcac442b9 100644 --- a/webui/src/js/views/model-design-view.html +++ b/webui/src/js/views/model-design-view.html @@ -1,9 +1,43 @@

-
-

-
-
\ No newline at end of file + +
+

+
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+
+ diff --git a/webui/src/js/views/user-settings-dialog.html b/webui/src/js/views/user-settings-dialog.html index 2cec6588f..43a501b16 100644 --- a/webui/src/js/views/user-settings-dialog.html +++ b/webui/src/js/views/user-settings-dialog.html @@ -21,6 +21,25 @@
+
+ + + + + + + + + + + +
+
+ +
diff --git a/webui/src/js/windowStateUtils.js b/webui/src/js/windowStateUtils.js index 0ffe338ac..9cafe0300 100644 --- a/webui/src/js/windowStateUtils.js +++ b/webui/src/js/windowStateUtils.js @@ -247,7 +247,7 @@ function(wktProject, wktConsole, wdtDiscoverer, dialogHelper, projectIO, return doDirtyCheck('window-app-quit'); }); - window.api.ipc.receive('show-quickstart', async() => { + window.api.ipc.receive('show-quickstart', async () => { dialogHelper.openDialog('quickstart-dialog'); }); @@ -255,6 +255,10 @@ function(wktProject, wktConsole, wdtDiscoverer, dialogHelper, projectIO, return appUpdater.showStartupDialogs(startupInformation); }); + window.api.ipc.receive('set-wrc-backend-port', (port) => { + wktProject.wdtModel.internal.wlRemoteConsolePort(port); + }); + async function doDirtyCheck(responseChannel) { return new Promise(resolve => { if (wktProject.isDirty()) { From 6081eda2d083880c69d1ec97e737e06593473d05 Mon Sep 17 00:00:00 2001 From: Robert Patrick <31662131+robertpatrick@users.noreply.github.com> Date: Fri, 11 Feb 2022 18:49:11 -0600 Subject: [PATCH 03/99] converting all aria-label attributes to use i18n resource bundle (#94) --- electron/app/locales/en/webui.json | 14 ++++++++++++++ webui/src/js/views/app-main.html | 2 +- webui/src/js/views/domain-design-view.html | 4 ++-- webui/src/js/views/ingress-design-view.html | 2 +- .../views/macos-environment-variables-dialog.html | 2 +- .../js/views/macos-path-directories-dialog.html | 2 +- webui/src/js/views/model-archive-view.html | 4 ++-- webui/src/js/views/model-properties-view.html | 2 +- webui/src/js/views/project-settings-page.html | 4 ++-- webui/src/js/views/quickstart-dialog.html | 2 +- webui/src/js/views/route-edit-dialog.html | 2 +- 11 files changed, 27 insertions(+), 13 deletions(-) diff --git a/electron/app/locales/en/webui.json b/electron/app/locales/en/webui.json index 95126758a..0fde7d43a 100644 --- a/electron/app/locales/en/webui.json +++ b/electron/app/locales/en/webui.json @@ -1,6 +1,7 @@ { "copyright-footer-text": "Copyright (c) 2021, {{currentYear}}, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0, as shown at", + "nav-aria-label": "Choose a navigation item", "nav-model": "Model", "nav-project-settings": "Project Settings", "nav-image": "Image", @@ -81,12 +82,14 @@ "project-settings-form-name": "Project Settings", "project-settings-title": "Project Settings", "project-settings-mac-environment-question": "For macOS, do you need to add directories to the PATH or define other environment variables for Docker/Podman or Kubernetes?", + "project-settings-mac-path-table-aria-label": "macOS Extra Path Directories Table", "project-settings-add-path-row-icon-text": "Add Extra Path Directory", "project-settings-choose-path-icon-text": "Choose Extra Path Directory", "project-settings-delete-path-row-icon-text": "Remove Extra Path Directory", "project-settings-extra-path-directory-header": "Extra Path Directory", "project-settings-hints-macos-path-directories": "Show System Path Directories", "project-settings-button-macos-path-directories": "Show System Path", + "project-settings-mac-env-var-table-aria-label": "macOS Extra Environment Variables Table", "project-settings-add-env-var-row-icon-text": "Add Extra Environment Variable", "project-settings-delete-env-var-row-icon-text": "Remove Extra Environment Variable", "project-settings-extra-environment-variable-name-header": "Extra Environment Variable Name", @@ -144,9 +147,11 @@ "project-settings-credential-store-policy-answer-message": "The Credential Store Policy controls how credentials are handled when the project is saved and loaded. The options are to store them in the machine's native credential store, store them in the project file encrypted with a passphrase, or not store them at all.", "macos-path-directories-dialog-title": "System Path", + "macos-path-directories-dialog-table-aria-label": "System Path Environment Variable Directories", "macos-path-directories-dialog-name-header": "Path Directory", "macos-environment-variables-dialog-title": "System Environment Variables", + "macos-environment-variables-dialog-table-aria-label": "System Environment Variables Table", "macos-environment-variables-dialog-name-header": "Environment Variable Name", "macos-environment-variables-dialog-value-header": "Environment Variable Value", @@ -578,6 +583,7 @@ "domain-design-cluster-additional-java-options-label": "Additional Java Options", "domain-design-cluster-additional-java-options-help": "A list of additional Java runtime options, separated by spaces, tabs, or commas.", + "domain-design-configmap-table-aria-label": "ConfigMap Properties Table", "domain-design-configmap-title": "Model Variables Overrides", "domain-design-configmap-label": "Kubernetes ConfigMap Name", "domain-design-configmap-help": "The name of the Kubernetes ConfigMap that holds the model variable overrides.", @@ -614,6 +620,7 @@ "domain-design-propname-header": "Model Variable Name", "domain-design-propvalue-header": "Model Variable File Value", "domain-design-propoverride-header": "Model Variable Override Value", + "domain-design-secrets-table-aria-label": "Secrets Table", "domain-design-secretname-header": "Secret Name", "domain-design-username-header": "Username", "domain-design-password-header": "Password", @@ -678,6 +685,7 @@ "ingress-design-ingress-route-is-console-svc-help": "For SSL terminating at ingress and accessing WebLogic Console Service, turn on this option. Your domain must have 'WeblogicPluginEnabled: true' in the 'resources->WebAppContainer' section", "ingress-design-ingress-route-name-label": "Name", "ingress-design-ingress-route-dialog-title": "Edit Ingress Route", + "ingress-design-ingress-route-annotations-table-aria-label": "Ingress Route Annotations Table", "ingress-design-ingress-route-annotation-label": "Annotation", "ingress-design-ingress-route-annotationValue-label": "Value", "ingress-design-ingress-annotations": "Optional Annotations", @@ -720,6 +728,7 @@ "ingress-design-generate-tls-subject-label": "Subject to Use for the Generated TLS Certificate", "ingress-design-generate-tls-subject-help": "The Subject (e.g., /CN=www.mydomain.org) to use when generating TLS certificate. The format must be /type0=value0/type1=value1/type2=...", + "ingress-design-routes-table-aria-label": "Ingress Routes Table", "ingress-design-add-route-label": "Add Route", "ingress-design-edit-route-label": "Edit Route", "ingress-design-delete-route-label": "Delete Route", @@ -1004,10 +1013,14 @@ "model-page-hints-prepareModel": "Prepare Model for Kubernetes", "model-page-model-editor-contents": "Model Editor Contents", + "model-properties-table-aria-label": "Model Variables Editable Table", "model-properties-name-header": "Variable Name", "model-properties-value-header": "Variable Value", "model-properties-add-label": "Add Variable", "model-properties-delete-label": "Delete", + + "model-archive-toolbar-aria-label": "Archive Editing Toolbar", + "model-archive-tree-view-aria-label": "Archive Editor Tree View", "model-archive-add-label": "Add", "model-archive-delete-label": "Delete", "model-archive-no-archive-label": "(no archive)", @@ -1299,6 +1312,7 @@ "quickstart-dialog-title": "WebLogic Kubernetes Toolkit (WKT) UI Introduction", "quickstart-dialog-stop-showing-quickstart-message": "Stop showing this introduction at startup.", + "quickstart-dialog-filmstrip-aria-label": "WebLogic Kubernetes Toolkit UI Tutorial", "quickstart-page1-title": "Introduction", "quickstart-page1-paragraph-1": "Ready to get your WebLogic Server domain running in Kubernetes?", "quickstart-page1-paragraph-2": "This application will guide you through the process of creating a WebLogic Server domain in Kubernetes.", diff --git a/webui/src/js/views/app-main.html b/webui/src/js/views/app-main.html index a8a01308d..684da44ba 100644 --- a/webui/src/js/views/app-main.html +++ b/webui/src/js/views/app-main.html @@ -16,7 +16,7 @@
-
@@ -27,7 +27,7 @@ data="[[archiveDataProvider]]" selection-mode="single" on-selected-changed="[[selectionChanged]]" - aria-label="Tree View with JSON Data"> + :aria-label="[[labelMapper('tree-view-aria-label')]]">