From d685695fdff4b53451ad1906b06b7f5092c67072 Mon Sep 17 00:00:00 2001 From: Sergei Kurnevich Date: Thu, 5 Sep 2024 15:48:33 +0200 Subject: [PATCH 1/6] Updates for networking tab Signed-off-by: Sergei Kurnevich --- src/renderer/components/stages/Networking.tsx | 28 +++++++++---------- src/renderer/components/stages/Planning.tsx | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/renderer/components/stages/Networking.tsx b/src/renderer/components/stages/Networking.tsx index 8de699c0..22ea998d 100644 --- a/src/renderer/components/stages/Networking.tsx +++ b/src/renderer/components/stages/Networking.tsx @@ -545,7 +545,7 @@ const Networking = () => { const SUB_STAGE_ID = SUB_STAGES ? getSubStageDetails(STAGE_ID, subStageLabel).id : 0; const dispatch = useAppDispatch(); - const [yaml, setLocalYaml] = useState(useAppSelector(selectYaml)); + const yaml = useAppSelector(selectYaml); const [editorVisible, setEditorVisible] = useState(false); const [isFormValid, setIsFormValid] = useState(false); const [formError, setFormError] = useState(''); @@ -566,9 +566,11 @@ const Networking = () => { }, [stageStatus]); useEffect(() => { - const nextPosition = document.getElementById('container-box-id'); - if(nextPosition) nextPosition.scrollIntoView({behavior: 'smooth'}); - + // const nextPosition = document.getElementById('container-box-id'); + // if(nextPosition) nextPosition.scrollIntoView({behavior: 'smooth'}); + if (yaml.zowe.externalDomains?.length === 1 && yaml.zowe.externalDomains[0] === 'sample-domain.com') { + dispatch(setYaml({...yaml, zowe: {...yaml.zowe, externalDomains: [connectionArgs.host]}})); + } dispatch(setNextStepEnabled(getProgress('networkingStatus'))); dispatch(setInitializationStatus(isInitializationStageComplete())); @@ -620,7 +622,7 @@ const Networking = () => { const setStageConfig = (isValid: boolean, errorMsg: string, data: any) => { setIsFormValid(isValid); setFormError(errorMsg); - setLocalYaml(data); + dispatch(setYaml(data)); } const onSaveYaml = (e: any) => { @@ -664,15 +666,16 @@ const Networking = () => { } setStageConfig(true, '', newYaml); }}/>} - dispatch(setYaml((await window.electron.ipcRenderer.getConfig()).details ?? yaml))}> + dispatch(setYaml((await window.electron.ipcRenderer.getConfig()).details ?? yaml))} // REVIEW: Why? + > {!isFormValid &&
{formError}
}

External Domains { let domains = [...yaml.zowe?.externalDomains || [], ""]; const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)) + dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); - setLocalYaml(newYaml); }}>

{yaml.zowe.externalDomains != undefined && yaml.zowe.externalDomains.map((domain: string, index: number) => { const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; // console.log(domains); window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)) + dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); - setLocalYaml(newYaml); }} /> { let domains = [...yaml.zowe?.externalDomains]; @@ -694,7 +696,6 @@ const Networking = () => { window.electron.ipcRenderer.setConfig(newYaml ) dispatch(setYaml(newYaml)) dispatch(setNetworkingStatus(false)); - setLocalYaml(newYaml); }}>)}
{ onChange={async (e) => { const newYaml = {...yaml, zowe: {...yaml.zowe, externalPort: Number(e.target.value)}}; window.electron.ipcRenderer.setConfig(newYaml) - dispatch(setYaml(newYaml)) - setLocalYaml(newYaml); + dispatch(setYaml(newYaml)); // // props.setYaml(newYaml); // await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${keys[i]}.${toMatch[k]}.${matchedProps[l]}`, Number(e.target.value)) // // dispatch(setYaml(newYaml)); @@ -742,7 +742,6 @@ const Networking = () => { control={ { // console.log('new yaml:', JSON.stringify({...yaml, [keys[i]]: {...yaml[keys[i]], [toMatch[k]]: {...yaml[keys[i]][toMatch[k]], [matchedProps[l]]: !yaml[keys[i]][toMatch[k]][matchedProps[l]]}}})); const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], [schemaProperty]: !yaml[schemaKey][matchedPattern][schemaProperty]}}}; - setLocalYaml(newYaml); await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.${schemaProperty}`, !yaml[schemaKey][matchedPattern][schemaProperty]) dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); @@ -757,7 +756,6 @@ const Networking = () => { onChange={async (e) => { if(!Number.isNaN(Number(e.target.value))){ const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], [schemaProperty]: Number(e.target.value)}}}; - setLocalYaml(newYaml); await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.${schemaProperty}`, Number(e.target.value)) dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); diff --git a/src/renderer/components/stages/Planning.tsx b/src/renderer/components/stages/Planning.tsx index 3c519e35..f41035e6 100644 --- a/src/renderer/components/stages/Planning.tsx +++ b/src/renderer/components/stages/Planning.tsx @@ -248,7 +248,7 @@ const Planning = () => { if (localYaml?.zowe?.logDirectory.startsWith(localYaml?.zowe?.runtimeDirectory) || localYaml?.zowe?.workspaceDirectory.startsWith(localYaml?.zowe?.runtimeDirectory) || localYaml?.zowe?.extensionDirectory.startsWith(localYaml?.zowe?.runtimeDirectory)) { - alertEmitter.emit('showAlert', `Some instance locations (workspace, logs or extensions) are defined inside the runtime directory ${localYaml?.zowe?.runtimeDirectory}. It is not recommended as the runtime directory ment to be read-only.`, 'warning', 20000); + alertEmitter.emit('showAlert', `Some instance locations (workspace, logs or extensions) are defined inside the runtime directory ${localYaml?.zowe?.runtimeDirectory}. It is not recommended as the runtime directory is meant to be read-only.`, 'warning', 20000); } }) } From d51f03ccbdad38a27a8e6131f1c780157d6cfbcf Mon Sep 17 00:00:00 2001 From: Sergei Kurnevich Date: Thu, 12 Sep 2024 20:42:38 +0200 Subject: [PATCH 2/6] replacing components port selection UI Signed-off-by: Sergei Kurnevich --- src/renderer/components/stages/Networking.tsx | 1170 +++++++++-------- 1 file changed, 609 insertions(+), 561 deletions(-) diff --git a/src/renderer/components/stages/Networking.tsx b/src/renderer/components/stages/Networking.tsx index 22ea998d..63b5c5e4 100644 --- a/src/renderer/components/stages/Networking.tsx +++ b/src/renderer/components/stages/Networking.tsx @@ -9,9 +9,10 @@ */ import { useState, useEffect, useRef } from "react"; -import { Box, Button, Checkbox, FormControlLabel, IconButton, SvgIcon, SvgIconProps, TextField } from '@mui/material'; +import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Checkbox, FormControlLabel, IconButton, SvgIcon, SvgIconProps, TextField } from '@mui/material'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { useAppSelector, useAppDispatch } from '../../hooks'; -import { selectYaml, setNextStepEnabled, setYaml } from '../configuration-wizard/wizardSlice'; +import { selectYaml, setNextStepEnabled, setYaml, selectSchema } from '../configuration-wizard/wizardSlice'; import ContainerCard from '../common/ContainerCard'; import EditorDialog from "../common/EditorDialog"; import { createTheme } from '@mui/material/styles'; @@ -25,497 +26,503 @@ import { selectConnectionArgs } from "./connection/connectionSlice"; import { getInstallationArguments, getProgress, isInitializationStageComplete, updateSubStepSkipStatus } from "./progress/StageProgressStatus"; import { alertEmitter } from "../Header"; -// const schema = useAppSelector(selectSchema); -const schema: any = { - "$id": "https://zowe.org/schemas/v2/server-base", - "title": "Zowe configuration file", - "description": "Configuration file for Zowe (zowe.org) version 2.", - "type": "object", - "additionalProperties": true, - "properties": { - "zowe": { - "type": "object", - "additionalProperties": true, - "properties": { - "externalDomains": { - "type": "array", - "description": "List of domain names of how you access Zowe from your local computer.", - "minItems": 1, - "uniqueItems": true, - "items": { - "type": ["string"] - } - }, - "externalPort": { - "type": "integer", - "minimum": 0, - "maximum": 65535, - "description": "Port number of how you access Zowe APIML Gateway from your local computer." - } - } - }, - "components": { - "type": "object", - "patternProperties": { - "^.*$": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether to enable or disable this component", - "default": false - }, - "port": { - "type": "integer", - "description": "Optional, port number for component if applicable.", - }, - "debug": { - "type": "boolean", - "description": "Whether to enable or disable debug tracing for this component", - "default": false - }, - "certificate": { - "$ref": "#/$defs/certificate", - "description": "Certificate for current component." - }, - "launcher": { - "type": "object", - "description": "Set behavior of how the Zowe launcher will handle this particular component", - "additionalProperties": true, - "properties": { - "restartIntervals": { - "type": "array", - "description": "Intervals of seconds to wait before restarting a component if it fails before the minUptime value.", - "items": { - "type": "integer" - } - }, - "minUptime": { - "type": "integer", - "default": 90, - "description": "The minimum amount of seconds before a component is considered running and the restart counter is reset." - }, - "shareAs": { - "type": "string", - "description": "Determines which SHAREAS mode should be used when starting a component", - "enum": ["no", "yes", "must", ""], - "default": "yes" - } - } - }, - "zowe": { - "type": "object", - "description": "Component level overrides for top level Zowe network configuration.", - "additionalProperties": false, - "properties": { - "network": { - "$ref": "#/$defs/networkSettings" - }, - "job": { - "$ref": "#/$defs/componentJobSettings" - } - } - } - } - } - } - }, - "haInstances": { - "type": "object", - "patternProperties": { - "^.*$": { - "type": "object", - "description": "Configuration of Zowe high availability instance.", - "required": ["hostname", "sysname"], - "properties": { - "hostname": { - "type": "string", - "description": "Host name of the Zowe high availability instance. This is hostname for internal communications." - }, - "sysname": { - "type": "string", - "description": "z/OS system name of the Zowe high availability instance. Some JES command will be routed to this system name." - }, - "components": { - "type": "object", - "patternProperties": { - "^.*$": { - "$ref": "#/$defs/component" - } - } - } - } - } - } - } - }, - "$defs": { - "port": { - "type": "integer", - "minimum": 0, - "maximum": 65535 - }, - "scheme": { - "type": "string", - "enum": [ - "http", - "https" - ], - "default": "https" - }, - "certificate": { - "oneOf": [ - { "$ref": "#/$defs/pkcs12-certificate" }, - { "$ref": "#/$defs/keyring-certificate" } - ] - }, - "pkcs12-certificate": { - "type": "object", - "additionalProperties": false, - "required": ["keystore", "truststore", "pem"], - "properties": { - "keystore": { - "type": "object", - "additionalProperties": false, - "description": "Certificate keystore.", - "required": ["type", "file", "alias"], - "properties": { - "type": { - "type": "string", - "description": "Keystore type.", - "const": "PKCS12" - }, - "file": { - "type": "string", - "pattern": "^([^\\0]){1,1024}$", - "minLength": 1, - "maxLength": 1024, - "description": "Path to your PKCS#12 keystore." - }, - "password": { - "type": "string", - "description": "Password of your PKCS#12 keystore." - }, - "alias": { - "type": "string", - "description": "Certificate alias name of defined in your PKCS#12 keystore" - } - } - }, - "truststore": { - "type": "object", - "additionalProperties": false, - "description": "Certificate truststore.", - "required": ["type", "file"], - "properties": { - "type": { - "type": "string", - "description": "Truststore type.", - "const": "PKCS12" - }, - "file": { - "type": "string", - "pattern": "^([^\\0]){1,1024}$", - "minLength": 1, - "maxLength": 1024, - "description": "Path to your PKCS#12 keystore." - }, - "password": { - "type": "string", - "description": "Password of your PKCS#12 keystore." - } - } - }, - "pem": { - "type": "object", - "additionalProperties": false, - "description": "Certificate in PEM format.", - "required": ["key", "certificate"], - "properties": { - "key": { - "type": "string", - "pattern": "^([^\\0]){1,1024}$", - "minLength": 1, - "maxLength": 1024, - "description": "Path to the certificate private key stored in PEM format." - }, - "certificate": { - "type": "string", - "pattern": "^([^\\0]){1,1024}$", - "minLength": 1, - "maxLength": 1024, - "description": "Path to the certificate stored in PEM format." - }, - "certificateAuthorities": { - "description": "List of paths to the certificate authorities stored in PEM format.", - "oneOf": [{ - "type": "string", - "pattern": "^([^\\0]){1,1024}$", - "minLength": 1, - "maxLength": 1024, - "description": "Paths to the certificate authorities stored in PEM format. You can separate multiple certificate authorities by comma." - }, - { - "type": "array", - "description": "Path to the certificate authority stored in PEM format.", - "items": { - "type": "string", - "pattern": "^([^\\0]){1,1024}$", - "minLength": 1, - "maxLength": 1024, - } - } - ] - } - } - } - } - }, - "keyring-certificate": { - "type": "object", - "additionalProperties": false, - "required": ["keystore", "truststore"], - "properties": { - "keystore": { - "type": "object", - "additionalProperties": false, - "description": "Certificate keystore.", - "required": ["type", "file", "alias"], - "properties": { - "type": { - "type": "string", - "description": "Keystore type.", - "enum": ["JCEKS", "JCECCAKS", "JCERACFKS", "JCECCARACFKS", "JCEHYBRIDRACFKS"] - }, - "file": { - "type": "string", - "description": "Path of your z/OS keyring, including ring owner and ring name. Case sensitivity and spaces matter.", - "pattern": "^safkeyring:\/\/.*" - }, - "password": { - "type": "string", - "description": "Literally 'password' may be needed when using keyrings for compatibility with java servers.", - "enum": ["", "password"] - }, - "alias": { - "type": "string", - "description": "Certificate label of z/OS keyring. Case sensitivity and spaces matter." - } - } - }, - "truststore": { - "type": "object", - "additionalProperties": false, - "description": "Certificate truststore.", - "required": ["type", "file"], - "properties": { - "type": { - "type": "string", - "description": "Truststore type.", - "enum": ["JCEKS", "JCECCAKS", "JCERACFKS", "JCECCARACFKS", "JCEHYBRIDRACFKS"] - }, - "file": { - "type": "string", - "description": "Path of your z/OS keyring, including ring owner and ring name. Case sensitivity and spaces matter.", - "pattern": "^safkeyring:\/\/.*" - }, - "password": { - "type": "string", - "description": "Literally 'password' may be needed when using keyrings for compatibility with java servers.", - "enum": ["", "password"] - } - } - }, - "pem": { - "type": "object", - "additionalProperties": false, - "description": "Certificate in PEM format.", - "properties": { - "key": { - "type": "string", - "description": "Path to the certificate private key stored in PEM format." - }, - "certificate": { - "type": "string", - "description": "Path to the certificate stored in PEM format." - }, - "certificateAuthorities": { - "description": "List of paths to the certificate authorities stored in PEM format.", - "oneOf": [{ - "type": "string", - "description": "Paths to the certificate authorities stored in PEM format. You can separate multiple certificate authorities by comma." - }, - { - "type": "array", - "description": "Path to the certificate authority stored in PEM format.", - "items": { - "type": "string" - } - } - ] - } - } - } - } - }, - "component": { - "$anchor": "zoweComponent", - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether to enable or disable this component", - "default": false - }, - "certificate": { - "$ref": "#/$defs/certificate", - "description": "Certificate for current component." - }, - "launcher": { - "type": "object", - "description": "Set behavior of how the Zowe launcher will handle this particular component", - "additionalProperties": true, - "properties": { - "restartIntervals": { - "type": "array", - "description": "Intervals of seconds to wait before restarting a component if it fails before the minUptime value.", - "items": { - "type": "integer" - } - }, - "minUptime": { - "type": "integer", - "default": 90, - "description": "The minimum amount of seconds before a component is considered running and the restart counter is reset." - }, - "shareAs": { - "type": "string", - "description": "Determines which SHAREAS mode should be used when starting a component", - "enum": ["no", "yes", "must", ""], - "default": "yes" - } - } - }, - "zowe": { - "type": "object", - "description": "Component level overrides for top level Zowe network configuration.", - "additionalProperties": false, - "properties": { - "network": { - "$ref": "#/$defs/networkSettings" - }, - "job": { - "$ref": "#/$defs/componentJobSettings" - } - } - } - } - }, - "componentJobSettings": { - "$anchor": "componentJobSettings", - "type": "object", - "description": "Component level overrides for job execution behavior", - "properties": { - "suffix": { - "type": "string", - "description": "Can be used by components to declare a jobname suffix to append to their job. This is not currently used by Zowe itself, it is up to components to use this value if desired. Zowe may use this value in the future." - } - } - }, - "tlsSettings": { - "$anchor": "tlsSettings", - "type": "object", - "properties": { - "ciphers": { - "type": "array", - "description": "Acceptable TLS cipher suites for network connections, in IANA format.", - "items": { - "type": "string" - } - }, - "curves": { - "type": "array", - "description": "Acceptable key exchange elliptic curves for network connections.", - "items": { - "type": "string" - } - }, - "maxTls": { - "type": "string", - "enum": ["TLSv1.2", "TLSv1.3"], - "default": "TLSv1.3", - "description": "Maximum TLS version allowed for network connections." - }, - "minTls": { - "type": "string", - "enum": ["TLSv1.2", "TLSv1.3"], - "default": "TLSv1.2", - "description": "Minimum TLS version allowed for network connections, and less than or equal to network.maxTls." - } - } - }, - "networkSettings": { - "type": "object", - "$anchor": "networkSettings", - "additionalProperties": false, - "description": "Optional, advanced network configuration parameters", - "properties": { - "server": { - "type": "object", - "additionalProperties": false, - "description": "Optional, advanced network configuration parameters for Zowe servers", - "properties": { - "tls": { - "$ref": "#/$defs/tlsSettings" - }, - "listenAddresses": { - "type": "array", - "description": "The IP addresses which all of the Zowe servers will be binding on and listening to. Some servers may only support listening on the first element.", - "items": { - "type": "string", - "pattern": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" - } - }, - "vipaIp": { - "type": "string", - "description": "The IP address which all of the Zowe servers will be binding to. If you are using multiple DIPVA addresses, do not use this option." - }, - "validatePortFree": { - "type": "boolean", - "default": true, - "description": "Whether or not to ensure that the port a server is about to use is available. Usually, servers will know this when they attempt to bind to a port, so this option allows you to disable the additional verification step." - } - } - }, - "client": { - "type": "object", - "additionalProperties": false, - "description": "Optional, advanced network configuration parameters for Zowe servers when sending requests as clients.", - "properties": { - "tls": { - "$ref": "#/$defs/tlsSettings" - } - } - } - } - }, - "registryHandler": { - "$anchor": "registryHandler", - "type": "object", - "required": ["registry", "path"], - "properties": { - "registry": { - "type": "string", - "description": "The location of the default registry for this handler. It could be a URL, path, dataset, whatever this handler supports" - }, - "path": { - "$ref": "/schemas/v2/server-common#zowePath", - "description": "Unix file path to the configmgr-compatible JS file which implements the handler API" - } - } - } - } -} +// TODO: Fix the schema usage +// Add helper text describing ports usage, and important details +// Hide components under collapsible customize panel +// Validate that ports are unique between components + + +// const customSchema = useAppSelector(selectSchema); +// const customSchema: any = { +// "$id": "https://zowe.org/schemas/v2/server-base", +// "title": "Zowe configuration file", +// "description": "Configuration file for Zowe (zowe.org) version 2.", +// "type": "object", +// "additionalProperties": true, +// "properties": { +// "zowe": { +// "type": "object", +// "additionalProperties": true, +// "properties": { +// "externalDomains": { +// "type": "array", +// "description": "List of domain names of how you access Zowe from your local computer.", +// "minItems": 1, +// "uniqueItems": true, +// "items": { +// "type": ["string"] +// } +// }, +// "externalPort": { +// "type": "integer", +// "minimum": 0, +// "maximum": 65535, +// "description": "Port number of how you access Zowe APIML Gateway from your local computer." +// } +// } +// }, +// "components": { +// "type": "object", +// "patternProperties": { +// "^.*$": { +// "type": "object", +// "properties": { +// "enabled": { +// "type": "boolean", +// "description": "Whether to enable or disable this component", +// "default": false +// }, +// "port": { +// "type": "integer", +// "description": "Optional, port number for component if applicable.", +// }, +// "debug": { +// "type": "boolean", +// "description": "Whether to enable or disable debug tracing for this component", +// "default": false +// }, +// "certificate": { +// "$ref": "#/$defs/certificate", +// "description": "Certificate for current component." +// }, +// "launcher": { +// "type": "object", +// "description": "Set behavior of how the Zowe launcher will handle this particular component", +// "additionalProperties": true, +// "properties": { +// "restartIntervals": { +// "type": "array", +// "description": "Intervals of seconds to wait before restarting a component if it fails before the minUptime value.", +// "items": { +// "type": "integer" +// } +// }, +// "minUptime": { +// "type": "integer", +// "default": 90, +// "description": "The minimum amount of seconds before a component is considered running and the restart counter is reset." +// }, +// "shareAs": { +// "type": "string", +// "description": "Determines which SHAREAS mode should be used when starting a component", +// "enum": ["no", "yes", "must", ""], +// "default": "yes" +// } +// } +// }, +// "zowe": { +// "type": "object", +// "description": "Component level overrides for top level Zowe network configuration.", +// "additionalProperties": false, +// "properties": { +// "network": { +// "$ref": "#/$defs/networkSettings" +// }, +// "job": { +// "$ref": "#/$defs/componentJobSettings" +// } +// } +// } +// } +// } +// } +// }, +// "haInstances": { +// "type": "object", +// "patternProperties": { +// "^.*$": { +// "type": "object", +// "description": "Configuration of Zowe high availability instance.", +// "required": ["hostname", "sysname"], +// "properties": { +// "hostname": { +// "type": "string", +// "description": "Host name of the Zowe high availability instance. This is hostname for internal communications." +// }, +// "sysname": { +// "type": "string", +// "description": "z/OS system name of the Zowe high availability instance. Some JES command will be routed to this system name." +// }, +// "components": { +// "type": "object", +// "patternProperties": { +// "^.*$": { +// "$ref": "#/$defs/component" +// } +// } +// } +// } +// } +// } +// } +// }, +// "$defs": { +// "port": { +// "type": "integer", +// "minimum": 0, +// "maximum": 65535 +// }, +// "scheme": { +// "type": "string", +// "enum": [ +// "http", +// "https" +// ], +// "default": "https" +// }, +// "certificate": { +// "oneOf": [ +// { "$ref": "#/$defs/pkcs12-certificate" }, +// { "$ref": "#/$defs/keyring-certificate" } +// ] +// }, +// "pkcs12-certificate": { +// "type": "object", +// "additionalProperties": false, +// "required": ["keystore", "truststore", "pem"], +// "properties": { +// "keystore": { +// "type": "object", +// "additionalProperties": false, +// "description": "Certificate keystore.", +// "required": ["type", "file", "alias"], +// "properties": { +// "type": { +// "type": "string", +// "description": "Keystore type.", +// "const": "PKCS12" +// }, +// "file": { +// "type": "string", +// "pattern": "^([^\\0]){1,1024}$", +// "minLength": 1, +// "maxLength": 1024, +// "description": "Path to your PKCS#12 keystore." +// }, +// "password": { +// "type": "string", +// "description": "Password of your PKCS#12 keystore." +// }, +// "alias": { +// "type": "string", +// "description": "Certificate alias name of defined in your PKCS#12 keystore" +// } +// } +// }, +// "truststore": { +// "type": "object", +// "additionalProperties": false, +// "description": "Certificate truststore.", +// "required": ["type", "file"], +// "properties": { +// "type": { +// "type": "string", +// "description": "Truststore type.", +// "const": "PKCS12" +// }, +// "file": { +// "type": "string", +// "pattern": "^([^\\0]){1,1024}$", +// "minLength": 1, +// "maxLength": 1024, +// "description": "Path to your PKCS#12 keystore." +// }, +// "password": { +// "type": "string", +// "description": "Password of your PKCS#12 keystore." +// } +// } +// }, +// "pem": { +// "type": "object", +// "additionalProperties": false, +// "description": "Certificate in PEM format.", +// "required": ["key", "certificate"], +// "properties": { +// "key": { +// "type": "string", +// "pattern": "^([^\\0]){1,1024}$", +// "minLength": 1, +// "maxLength": 1024, +// "description": "Path to the certificate private key stored in PEM format." +// }, +// "certificate": { +// "type": "string", +// "pattern": "^([^\\0]){1,1024}$", +// "minLength": 1, +// "maxLength": 1024, +// "description": "Path to the certificate stored in PEM format." +// }, +// "certificateAuthorities": { +// "description": "List of paths to the certificate authorities stored in PEM format.", +// "oneOf": [{ +// "type": "string", +// "pattern": "^([^\\0]){1,1024}$", +// "minLength": 1, +// "maxLength": 1024, +// "description": "Paths to the certificate authorities stored in PEM format. You can separate multiple certificate authorities by comma." +// }, +// { +// "type": "array", +// "description": "Path to the certificate authority stored in PEM format.", +// "items": { +// "type": "string", +// "pattern": "^([^\\0]){1,1024}$", +// "minLength": 1, +// "maxLength": 1024, +// } +// } +// ] +// } +// } +// } +// } +// }, +// "keyring-certificate": { +// "type": "object", +// "additionalProperties": false, +// "required": ["keystore", "truststore"], +// "properties": { +// "keystore": { +// "type": "object", +// "additionalProperties": false, +// "description": "Certificate keystore.", +// "required": ["type", "file", "alias"], +// "properties": { +// "type": { +// "type": "string", +// "description": "Keystore type.", +// "enum": ["JCEKS", "JCECCAKS", "JCERACFKS", "JCECCARACFKS", "JCEHYBRIDRACFKS"] +// }, +// "file": { +// "type": "string", +// "description": "Path of your z/OS keyring, including ring owner and ring name. Case sensitivity and spaces matter.", +// "pattern": "^safkeyring:\/\/.*" +// }, +// "password": { +// "type": "string", +// "description": "Literally 'password' may be needed when using keyrings for compatibility with java servers.", +// "enum": ["", "password"] +// }, +// "alias": { +// "type": "string", +// "description": "Certificate label of z/OS keyring. Case sensitivity and spaces matter." +// } +// } +// }, +// "truststore": { +// "type": "object", +// "additionalProperties": false, +// "description": "Certificate truststore.", +// "required": ["type", "file"], +// "properties": { +// "type": { +// "type": "string", +// "description": "Truststore type.", +// "enum": ["JCEKS", "JCECCAKS", "JCERACFKS", "JCECCARACFKS", "JCEHYBRIDRACFKS"] +// }, +// "file": { +// "type": "string", +// "description": "Path of your z/OS keyring, including ring owner and ring name. Case sensitivity and spaces matter.", +// "pattern": "^safkeyring:\/\/.*" +// }, +// "password": { +// "type": "string", +// "description": "Literally 'password' may be needed when using keyrings for compatibility with java servers.", +// "enum": ["", "password"] +// } +// } +// }, +// "pem": { +// "type": "object", +// "additionalProperties": false, +// "description": "Certificate in PEM format.", +// "properties": { +// "key": { +// "type": "string", +// "description": "Path to the certificate private key stored in PEM format." +// }, +// "certificate": { +// "type": "string", +// "description": "Path to the certificate stored in PEM format." +// }, +// "certificateAuthorities": { +// "description": "List of paths to the certificate authorities stored in PEM format.", +// "oneOf": [{ +// "type": "string", +// "description": "Paths to the certificate authorities stored in PEM format. You can separate multiple certificate authorities by comma." +// }, +// { +// "type": "array", +// "description": "Path to the certificate authority stored in PEM format.", +// "items": { +// "type": "string" +// } +// } +// ] +// } +// } +// } +// } +// }, +// "component": { +// "$anchor": "zoweComponent", +// "type": "object", +// "properties": { +// "enabled": { +// "type": "boolean", +// "description": "Whether to enable or disable this component", +// "default": false +// }, +// "certificate": { +// "$ref": "#/$defs/certificate", +// "description": "Certificate for current component." +// }, +// "launcher": { +// "type": "object", +// "description": "Set behavior of how the Zowe launcher will handle this particular component", +// "additionalProperties": true, +// "properties": { +// "restartIntervals": { +// "type": "array", +// "description": "Intervals of seconds to wait before restarting a component if it fails before the minUptime value.", +// "items": { +// "type": "integer" +// } +// }, +// "minUptime": { +// "type": "integer", +// "default": 90, +// "description": "The minimum amount of seconds before a component is considered running and the restart counter is reset." +// }, +// "shareAs": { +// "type": "string", +// "description": "Determines which SHAREAS mode should be used when starting a component", +// "enum": ["no", "yes", "must", ""], +// "default": "yes" +// } +// } +// }, +// "zowe": { +// "type": "object", +// "description": "Component level overrides for top level Zowe network configuration.", +// "additionalProperties": false, +// "properties": { +// "network": { +// "$ref": "#/$defs/networkSettings" +// }, +// "job": { +// "$ref": "#/$defs/componentJobSettings" +// } +// } +// } +// } +// }, +// "componentJobSettings": { +// "$anchor": "componentJobSettings", +// "type": "object", +// "description": "Component level overrides for job execution behavior", +// "properties": { +// "suffix": { +// "type": "string", +// "description": "Can be used by components to declare a jobname suffix to append to their job. This is not currently used by Zowe itself, it is up to components to use this value if desired. Zowe may use this value in the future." +// } +// } +// }, +// "tlsSettings": { +// "$anchor": "tlsSettings", +// "type": "object", +// "properties": { +// "ciphers": { +// "type": "array", +// "description": "Acceptable TLS cipher suites for network connections, in IANA format.", +// "items": { +// "type": "string" +// } +// }, +// "curves": { +// "type": "array", +// "description": "Acceptable key exchange elliptic curves for network connections.", +// "items": { +// "type": "string" +// } +// }, +// "maxTls": { +// "type": "string", +// "enum": ["TLSv1.2", "TLSv1.3"], +// "default": "TLSv1.3", +// "description": "Maximum TLS version allowed for network connections." +// }, +// "minTls": { +// "type": "string", +// "enum": ["TLSv1.2", "TLSv1.3"], +// "default": "TLSv1.2", +// "description": "Minimum TLS version allowed for network connections, and less than or equal to network.maxTls." +// } +// } +// }, +// "networkSettings": { +// "type": "object", +// "$anchor": "networkSettings", +// "additionalProperties": false, +// "description": "Optional, advanced network configuration parameters", +// "properties": { +// "server": { +// "type": "object", +// "additionalProperties": false, +// "description": "Optional, advanced network configuration parameters for Zowe servers", +// "properties": { +// "tls": { +// "$ref": "#/$defs/tlsSettings" +// }, +// "listenAddresses": { +// "type": "array", +// "description": "The IP addresses which all of the Zowe servers will be binding on and listening to. Some servers may only support listening on the first element.", +// "items": { +// "type": "string", +// "pattern": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" +// } +// }, +// "vipaIp": { +// "type": "string", +// "description": "The IP address which all of the Zowe servers will be binding to. If you are using multiple DIPVA addresses, do not use this option." +// }, +// "validatePortFree": { +// "type": "boolean", +// "default": true, +// "description": "Whether or not to ensure that the port a server is about to use is available. Usually, servers will know this when they attempt to bind to a port, so this option allows you to disable the additional verification step." +// } +// } +// }, +// "client": { +// "type": "object", +// "additionalProperties": false, +// "description": "Optional, advanced network configuration parameters for Zowe servers when sending requests as clients.", +// "properties": { +// "tls": { +// "$ref": "#/$defs/tlsSettings" +// } +// } +// } +// } +// }, +// "registryHandler": { +// "$anchor": "registryHandler", +// "type": "object", +// "required": ["registry", "path"], +// "properties": { +// "registry": { +// "type": "string", +// "description": "The location of the default registry for this handler. It could be a URL, path, dataset, whatever this handler supports" +// }, +// "path": { +// "$ref": "/schemas/v2/server-common#zowePath", +// "description": "Unix file path to the configmgr-compatible JS file which implements the handler API" +// } +// } +// } +// } +// } function AddIcon(props: SvgIconProps) { return ( @@ -546,23 +553,25 @@ const Networking = () => { const dispatch = useAppDispatch(); const yaml = useAppSelector(selectYaml); + const schema = useAppSelector(selectSchema); const [editorVisible, setEditorVisible] = useState(false); const [isFormValid, setIsFormValid] = useState(false); const [formError, setFormError] = useState(''); const [contentType, setContentType] = useState(''); - const [installationArgs, setInstArgs] = useState(getInstallationArguments()); + + const installationArgs = getInstallationArguments(); const connectionArgs = useAppSelector(selectConnectionArgs); - const [validate] = useState(() => ajv.getSchema("https://zowe.org/schemas/v2/server-base") || ajv.compile(schema)); - const [LOOP_LIMIT] = useState(1024); + // const validate = ajv.getSchema("https://zowe.org/schemas/v2/server-base") || ajv.compile(customSchema); // REVIEW: What is returned by getSchema, do we need ajv? maybe only once on customSchema retrieving. + const LOOP_LIMIT = 1024; - const [stateUpdated, setStateUpdated] = useState(false); + // const [stateUpdated, setStateUpdated] = useState(false); const [stageStatus, setStageStatus] = useState(stages[STAGE_ID].subStages[SUB_STAGE_ID].isSkipped); const stageStatusRef = useRef(stageStatus); - const isInitializationSkipped = !useAppSelector(selectInitializationStatus); + // const isInitializationSkipped = !useAppSelector(selectInitializationStatus); useEffect(() => { - stageStatusRef.current = stageStatus; + stageStatusRef.current = stageStatus; // REVIEW: What it does? }, [stageStatus]); useEffect(() => { @@ -587,7 +596,7 @@ const Networking = () => { } const updateProgress = (status: boolean) => { - setStateUpdated(!setStateUpdated); + // setStateUpdated(!setStateUpdated); dispatch(setNetworkingStatus(status)); dispatch(setNextStepEnabled(status)); setStageSkipStatus(!status); @@ -597,33 +606,33 @@ const Networking = () => { setContentType(type); setEditorVisible(!editorVisible); }; - - const handleFormChange = async (data: any, isYamlUpdated?: boolean) => { - if(validate) { - validate(data); - if(validate.errors) { - const errPath = validate.errors[0].schemaPath; - const errMsg = validate.errors[0].message; - setStageConfig(false, errPath+' '+errMsg, data.zowe); - - } - } - let newYaml; - if (data.zowe && data.zowe.externalDomains && data.zowe.externalPort) { - newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: data.zowe.externalDomains, externalPort: data.zowe.externalPort}}; - } - if(data.components){ - newYaml = {...newYaml, components: data.components}; - } - window.electron.ipcRenderer.setConfig(newYaml) - setStageConfig(true, '', newYaml); - }; const setStageConfig = (isValid: boolean, errorMsg: string, data: any) => { setIsFormValid(isValid); setFormError(errorMsg); dispatch(setYaml(data)); } + + // const handleFormChange = async (data: any, isYamlUpdated?: boolean) => { + // if(validate) { + // validate(data); + // if(validate.errors) { + // const errPath = validate.errors[0].schemaPath; + // const errMsg = validate.errors[0].message; + // setStageConfig(false, errPath+' '+errMsg, data.zowe); + + // } + // } + // let newYaml; + // if (data.zowe && data.zowe.externalDomains && data.zowe.externalPort) { + // newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: data.zowe.externalDomains, externalPort: data.zowe.externalPort}}; + // } + // if(data.components){ + // newYaml = {...newYaml, components: data.components}; + // } + // window.electron.ipcRenderer.setConfig(newYaml) + // setStageConfig(true, '', newYaml); + // }; const onSaveYaml = (e: any) => { e.preventDefault(); @@ -689,14 +698,19 @@ const Networking = () => { dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); }} - /> { - let domains = [...yaml.zowe?.externalDomains]; - domains.splice(index, 1); - const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; - window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)) - dispatch(setNetworkingStatus(false)); - }}>
)} + /> + {yaml.zowe?.externalDomains.length > 1 && { + let domains = [...yaml.zowe?.externalDomains]; + domains.splice(index, 1); + const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; + window.electron.ipcRenderer.setConfig(newYaml ) + dispatch(setYaml(newYaml)) + dispatch(setNetworkingStatus(false)); + }}> + + } +
)}
{ // // dispatch(setYaml(newYaml)); }} /> -
- {Object.keys(schema.properties).map((schemaKey, index) => { + + } + aria-controls="components-content" + id="components-header" + > + Components + + + {Object.keys(yaml.components).filter(component => yaml.components[component].hasOwnProperty('port')).map(component => { // yaml.components[component].hasOwnProperty('enabled') && + console.log(component, yaml.components[component].enabled, yaml.components[component].port); + return
+ { + const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], enabled: !yaml.components[component].enabled}}}; + console.log(JSON.stringify(newYaml)) + await window.electron.ipcRenderer.setConfigByKeyAndValidate(`components.${component}.enabled`, !yaml.components[component].enabled); + dispatch(setYaml(newYaml)); + dispatch(setNetworkingStatus(false)); + }}/>} + /> + { + if (!Number.isNaN(Number(e.target.value))) { // REVIEW: Use schema for validation + const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], port: Number(e.target.value)}}}; + await window.electron.ipcRenderer.setConfigByKeyAndValidate(`components.${component}.port`, Number(e.target.value)) + dispatch(setYaml(newYaml)); + dispatch(setNetworkingStatus(false)); + } + }} + /> +
+ })} +
+
+ {/*
+ {Object.keys(customSchema.properties).map((schemaKey, index) => { if(index < LOOP_LIMIT){ - if (schema.properties[schemaKey].patternProperties != undefined) { //only for rendering patternProperties + if (customSchema.properties[schemaKey].patternProperties != undefined) { //only for rendering patternProperties if(typeof yaml[schemaKey] === "object" && Object.keys(yaml[schemaKey]).length > 0) { return

{schemaKey}

- {Object.keys(schema.properties[schemaKey].patternProperties).map((regexPattern, rIndex) => { + {Object.keys(customSchema.properties[schemaKey].patternProperties).map((regexPattern, rIndex) => { const pattern = new RegExp(regexPattern); if(rIndex < LOOP_LIMIT && yaml[schemaKey]) { return Object.keys(yaml[schemaKey]).map((matchedPattern, mIndex) => { if(mIndex < LOOP_LIMIT && pattern.test(matchedPattern)){ - return
-
- - {matchedPattern} -
-
- {Object.keys(yaml[schemaKey][matchedPattern]).map((schemaProperty, sIndex) => { - - if(sIndex < LOOP_LIMIT && schemaProperty.length > 0){ - return
- - {typeof yaml[schemaKey][matchedPattern][schemaProperty] === "boolean" && { + return
+ {yaml[schemaKey][matchedPattern].hasOwnProperty('enabled') && { // console.log('new yaml:', JSON.stringify({...yaml, [keys[i]]: {...yaml[keys[i]], [toMatch[k]]: {...yaml[keys[i]][toMatch[k]], [matchedProps[l]]: !yaml[keys[i]][toMatch[k]][matchedProps[l]]}}})); - const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], [schemaProperty]: !yaml[schemaKey][matchedPattern][schemaProperty]}}}; - await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.${schemaProperty}`, !yaml[schemaKey][matchedPattern][schemaProperty]) + const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], enabled: !yaml[schemaKey][matchedPattern].enabled}}}; + await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.enabled`, !yaml[schemaKey][matchedPattern].enabled); dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); }}/>} - />} - {typeof yaml[schemaKey][matchedPattern][schemaProperty] === "number" &&} + + {matchedPattern} +
+
+ {yaml[schemaKey][matchedPattern].port && { if(!Number.isNaN(Number(e.target.value))){ - const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], [schemaProperty]: Number(e.target.value)}}}; - await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.${schemaProperty}`, Number(e.target.value)) + const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], port: Number(e.target.value)}}}; + await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.port`, Number(e.target.value)) dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); } }} />} -
- } - return null; - })}
+
} return null; }) @@ -779,7 +827,7 @@ const Networking = () => { } return null; })} -
+
*/} From ab45c53153f55766bc36759c6c2535df93507af5 Mon Sep 17 00:00:00 2001 From: Sergei Kurnevich Date: Fri, 18 Oct 2024 14:41:52 +0200 Subject: [PATCH 3/6] latest Signed-off-by: Sergei Kurnevich --- src/renderer/components/stages/Networking.tsx | 601 +----------------- 1 file changed, 34 insertions(+), 567 deletions(-) diff --git a/src/renderer/components/stages/Networking.tsx b/src/renderer/components/stages/Networking.tsx index 63b5c5e4..21ba845e 100644 --- a/src/renderer/components/stages/Networking.tsx +++ b/src/renderer/components/stages/Networking.tsx @@ -9,7 +9,7 @@ */ import { useState, useEffect, useRef } from "react"; -import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Checkbox, FormControlLabel, IconButton, SvgIcon, SvgIconProps, TextField } from '@mui/material'; +import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Checkbox, FormControlLabel, IconButton, SvgIcon, SvgIconProps, TextField, Typography } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { useAppSelector, useAppDispatch } from '../../hooks'; import { selectYaml, setNextStepEnabled, setYaml, selectSchema } from '../configuration-wizard/wizardSlice'; @@ -25,505 +25,13 @@ import { IResponse } from "../../../types/interfaces"; import { selectConnectionArgs } from "./connection/connectionSlice"; import { getInstallationArguments, getProgress, isInitializationStageComplete, updateSubStepSkipStatus } from "./progress/StageProgressStatus"; import { alertEmitter } from "../Header"; +import JsonForm from '../common/JsonForms'; -// TODO: Fix the schema usage +// TODO: Fix the schema usage, remove schema validation as useless // Add helper text describing ports usage, and important details // Hide components under collapsible customize panel // Validate that ports are unique between components - -// const customSchema = useAppSelector(selectSchema); -// const customSchema: any = { -// "$id": "https://zowe.org/schemas/v2/server-base", -// "title": "Zowe configuration file", -// "description": "Configuration file for Zowe (zowe.org) version 2.", -// "type": "object", -// "additionalProperties": true, -// "properties": { -// "zowe": { -// "type": "object", -// "additionalProperties": true, -// "properties": { -// "externalDomains": { -// "type": "array", -// "description": "List of domain names of how you access Zowe from your local computer.", -// "minItems": 1, -// "uniqueItems": true, -// "items": { -// "type": ["string"] -// } -// }, -// "externalPort": { -// "type": "integer", -// "minimum": 0, -// "maximum": 65535, -// "description": "Port number of how you access Zowe APIML Gateway from your local computer." -// } -// } -// }, -// "components": { -// "type": "object", -// "patternProperties": { -// "^.*$": { -// "type": "object", -// "properties": { -// "enabled": { -// "type": "boolean", -// "description": "Whether to enable or disable this component", -// "default": false -// }, -// "port": { -// "type": "integer", -// "description": "Optional, port number for component if applicable.", -// }, -// "debug": { -// "type": "boolean", -// "description": "Whether to enable or disable debug tracing for this component", -// "default": false -// }, -// "certificate": { -// "$ref": "#/$defs/certificate", -// "description": "Certificate for current component." -// }, -// "launcher": { -// "type": "object", -// "description": "Set behavior of how the Zowe launcher will handle this particular component", -// "additionalProperties": true, -// "properties": { -// "restartIntervals": { -// "type": "array", -// "description": "Intervals of seconds to wait before restarting a component if it fails before the minUptime value.", -// "items": { -// "type": "integer" -// } -// }, -// "minUptime": { -// "type": "integer", -// "default": 90, -// "description": "The minimum amount of seconds before a component is considered running and the restart counter is reset." -// }, -// "shareAs": { -// "type": "string", -// "description": "Determines which SHAREAS mode should be used when starting a component", -// "enum": ["no", "yes", "must", ""], -// "default": "yes" -// } -// } -// }, -// "zowe": { -// "type": "object", -// "description": "Component level overrides for top level Zowe network configuration.", -// "additionalProperties": false, -// "properties": { -// "network": { -// "$ref": "#/$defs/networkSettings" -// }, -// "job": { -// "$ref": "#/$defs/componentJobSettings" -// } -// } -// } -// } -// } -// } -// }, -// "haInstances": { -// "type": "object", -// "patternProperties": { -// "^.*$": { -// "type": "object", -// "description": "Configuration of Zowe high availability instance.", -// "required": ["hostname", "sysname"], -// "properties": { -// "hostname": { -// "type": "string", -// "description": "Host name of the Zowe high availability instance. This is hostname for internal communications." -// }, -// "sysname": { -// "type": "string", -// "description": "z/OS system name of the Zowe high availability instance. Some JES command will be routed to this system name." -// }, -// "components": { -// "type": "object", -// "patternProperties": { -// "^.*$": { -// "$ref": "#/$defs/component" -// } -// } -// } -// } -// } -// } -// } -// }, -// "$defs": { -// "port": { -// "type": "integer", -// "minimum": 0, -// "maximum": 65535 -// }, -// "scheme": { -// "type": "string", -// "enum": [ -// "http", -// "https" -// ], -// "default": "https" -// }, -// "certificate": { -// "oneOf": [ -// { "$ref": "#/$defs/pkcs12-certificate" }, -// { "$ref": "#/$defs/keyring-certificate" } -// ] -// }, -// "pkcs12-certificate": { -// "type": "object", -// "additionalProperties": false, -// "required": ["keystore", "truststore", "pem"], -// "properties": { -// "keystore": { -// "type": "object", -// "additionalProperties": false, -// "description": "Certificate keystore.", -// "required": ["type", "file", "alias"], -// "properties": { -// "type": { -// "type": "string", -// "description": "Keystore type.", -// "const": "PKCS12" -// }, -// "file": { -// "type": "string", -// "pattern": "^([^\\0]){1,1024}$", -// "minLength": 1, -// "maxLength": 1024, -// "description": "Path to your PKCS#12 keystore." -// }, -// "password": { -// "type": "string", -// "description": "Password of your PKCS#12 keystore." -// }, -// "alias": { -// "type": "string", -// "description": "Certificate alias name of defined in your PKCS#12 keystore" -// } -// } -// }, -// "truststore": { -// "type": "object", -// "additionalProperties": false, -// "description": "Certificate truststore.", -// "required": ["type", "file"], -// "properties": { -// "type": { -// "type": "string", -// "description": "Truststore type.", -// "const": "PKCS12" -// }, -// "file": { -// "type": "string", -// "pattern": "^([^\\0]){1,1024}$", -// "minLength": 1, -// "maxLength": 1024, -// "description": "Path to your PKCS#12 keystore." -// }, -// "password": { -// "type": "string", -// "description": "Password of your PKCS#12 keystore." -// } -// } -// }, -// "pem": { -// "type": "object", -// "additionalProperties": false, -// "description": "Certificate in PEM format.", -// "required": ["key", "certificate"], -// "properties": { -// "key": { -// "type": "string", -// "pattern": "^([^\\0]){1,1024}$", -// "minLength": 1, -// "maxLength": 1024, -// "description": "Path to the certificate private key stored in PEM format." -// }, -// "certificate": { -// "type": "string", -// "pattern": "^([^\\0]){1,1024}$", -// "minLength": 1, -// "maxLength": 1024, -// "description": "Path to the certificate stored in PEM format." -// }, -// "certificateAuthorities": { -// "description": "List of paths to the certificate authorities stored in PEM format.", -// "oneOf": [{ -// "type": "string", -// "pattern": "^([^\\0]){1,1024}$", -// "minLength": 1, -// "maxLength": 1024, -// "description": "Paths to the certificate authorities stored in PEM format. You can separate multiple certificate authorities by comma." -// }, -// { -// "type": "array", -// "description": "Path to the certificate authority stored in PEM format.", -// "items": { -// "type": "string", -// "pattern": "^([^\\0]){1,1024}$", -// "minLength": 1, -// "maxLength": 1024, -// } -// } -// ] -// } -// } -// } -// } -// }, -// "keyring-certificate": { -// "type": "object", -// "additionalProperties": false, -// "required": ["keystore", "truststore"], -// "properties": { -// "keystore": { -// "type": "object", -// "additionalProperties": false, -// "description": "Certificate keystore.", -// "required": ["type", "file", "alias"], -// "properties": { -// "type": { -// "type": "string", -// "description": "Keystore type.", -// "enum": ["JCEKS", "JCECCAKS", "JCERACFKS", "JCECCARACFKS", "JCEHYBRIDRACFKS"] -// }, -// "file": { -// "type": "string", -// "description": "Path of your z/OS keyring, including ring owner and ring name. Case sensitivity and spaces matter.", -// "pattern": "^safkeyring:\/\/.*" -// }, -// "password": { -// "type": "string", -// "description": "Literally 'password' may be needed when using keyrings for compatibility with java servers.", -// "enum": ["", "password"] -// }, -// "alias": { -// "type": "string", -// "description": "Certificate label of z/OS keyring. Case sensitivity and spaces matter." -// } -// } -// }, -// "truststore": { -// "type": "object", -// "additionalProperties": false, -// "description": "Certificate truststore.", -// "required": ["type", "file"], -// "properties": { -// "type": { -// "type": "string", -// "description": "Truststore type.", -// "enum": ["JCEKS", "JCECCAKS", "JCERACFKS", "JCECCARACFKS", "JCEHYBRIDRACFKS"] -// }, -// "file": { -// "type": "string", -// "description": "Path of your z/OS keyring, including ring owner and ring name. Case sensitivity and spaces matter.", -// "pattern": "^safkeyring:\/\/.*" -// }, -// "password": { -// "type": "string", -// "description": "Literally 'password' may be needed when using keyrings for compatibility with java servers.", -// "enum": ["", "password"] -// } -// } -// }, -// "pem": { -// "type": "object", -// "additionalProperties": false, -// "description": "Certificate in PEM format.", -// "properties": { -// "key": { -// "type": "string", -// "description": "Path to the certificate private key stored in PEM format." -// }, -// "certificate": { -// "type": "string", -// "description": "Path to the certificate stored in PEM format." -// }, -// "certificateAuthorities": { -// "description": "List of paths to the certificate authorities stored in PEM format.", -// "oneOf": [{ -// "type": "string", -// "description": "Paths to the certificate authorities stored in PEM format. You can separate multiple certificate authorities by comma." -// }, -// { -// "type": "array", -// "description": "Path to the certificate authority stored in PEM format.", -// "items": { -// "type": "string" -// } -// } -// ] -// } -// } -// } -// } -// }, -// "component": { -// "$anchor": "zoweComponent", -// "type": "object", -// "properties": { -// "enabled": { -// "type": "boolean", -// "description": "Whether to enable or disable this component", -// "default": false -// }, -// "certificate": { -// "$ref": "#/$defs/certificate", -// "description": "Certificate for current component." -// }, -// "launcher": { -// "type": "object", -// "description": "Set behavior of how the Zowe launcher will handle this particular component", -// "additionalProperties": true, -// "properties": { -// "restartIntervals": { -// "type": "array", -// "description": "Intervals of seconds to wait before restarting a component if it fails before the minUptime value.", -// "items": { -// "type": "integer" -// } -// }, -// "minUptime": { -// "type": "integer", -// "default": 90, -// "description": "The minimum amount of seconds before a component is considered running and the restart counter is reset." -// }, -// "shareAs": { -// "type": "string", -// "description": "Determines which SHAREAS mode should be used when starting a component", -// "enum": ["no", "yes", "must", ""], -// "default": "yes" -// } -// } -// }, -// "zowe": { -// "type": "object", -// "description": "Component level overrides for top level Zowe network configuration.", -// "additionalProperties": false, -// "properties": { -// "network": { -// "$ref": "#/$defs/networkSettings" -// }, -// "job": { -// "$ref": "#/$defs/componentJobSettings" -// } -// } -// } -// } -// }, -// "componentJobSettings": { -// "$anchor": "componentJobSettings", -// "type": "object", -// "description": "Component level overrides for job execution behavior", -// "properties": { -// "suffix": { -// "type": "string", -// "description": "Can be used by components to declare a jobname suffix to append to their job. This is not currently used by Zowe itself, it is up to components to use this value if desired. Zowe may use this value in the future." -// } -// } -// }, -// "tlsSettings": { -// "$anchor": "tlsSettings", -// "type": "object", -// "properties": { -// "ciphers": { -// "type": "array", -// "description": "Acceptable TLS cipher suites for network connections, in IANA format.", -// "items": { -// "type": "string" -// } -// }, -// "curves": { -// "type": "array", -// "description": "Acceptable key exchange elliptic curves for network connections.", -// "items": { -// "type": "string" -// } -// }, -// "maxTls": { -// "type": "string", -// "enum": ["TLSv1.2", "TLSv1.3"], -// "default": "TLSv1.3", -// "description": "Maximum TLS version allowed for network connections." -// }, -// "minTls": { -// "type": "string", -// "enum": ["TLSv1.2", "TLSv1.3"], -// "default": "TLSv1.2", -// "description": "Minimum TLS version allowed for network connections, and less than or equal to network.maxTls." -// } -// } -// }, -// "networkSettings": { -// "type": "object", -// "$anchor": "networkSettings", -// "additionalProperties": false, -// "description": "Optional, advanced network configuration parameters", -// "properties": { -// "server": { -// "type": "object", -// "additionalProperties": false, -// "description": "Optional, advanced network configuration parameters for Zowe servers", -// "properties": { -// "tls": { -// "$ref": "#/$defs/tlsSettings" -// }, -// "listenAddresses": { -// "type": "array", -// "description": "The IP addresses which all of the Zowe servers will be binding on and listening to. Some servers may only support listening on the first element.", -// "items": { -// "type": "string", -// "pattern": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" -// } -// }, -// "vipaIp": { -// "type": "string", -// "description": "The IP address which all of the Zowe servers will be binding to. If you are using multiple DIPVA addresses, do not use this option." -// }, -// "validatePortFree": { -// "type": "boolean", -// "default": true, -// "description": "Whether or not to ensure that the port a server is about to use is available. Usually, servers will know this when they attempt to bind to a port, so this option allows you to disable the additional verification step." -// } -// } -// }, -// "client": { -// "type": "object", -// "additionalProperties": false, -// "description": "Optional, advanced network configuration parameters for Zowe servers when sending requests as clients.", -// "properties": { -// "tls": { -// "$ref": "#/$defs/tlsSettings" -// } -// } -// } -// } -// }, -// "registryHandler": { -// "$anchor": "registryHandler", -// "type": "object", -// "required": ["registry", "path"], -// "properties": { -// "registry": { -// "type": "string", -// "description": "The location of the default registry for this handler. It could be a URL, path, dataset, whatever this handler supports" -// }, -// "path": { -// "$ref": "/schemas/v2/server-common#zowePath", -// "description": "Unix file path to the configmgr-compatible JS file which implements the handler API" -// } -// } -// } -// } -// } - function AddIcon(props: SvgIconProps) { return ( @@ -656,7 +164,7 @@ const Networking = () => { dispatch(setInitializationStatus(isInitializationStageComplete())); } } - + // console.log(JSON.stringify(schema)); return ( yaml && schema &&
@@ -679,13 +187,22 @@ const Networking = () => { // onBlur={async () => dispatch(setYaml((await window.electron.ipcRenderer.getConfig()).details ?? yaml))} // REVIEW: Why? > {!isFormValid &&
{formError}
} -

External Domains { - let domains = [...yaml.zowe?.externalDomains || [], ""]; - const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; - window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); - }}>

+ {/* REVIEW: button as child of

*/} +

+ External Domains + { + let domains = [...yaml.zowe?.externalDomains || [], ""]; + const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; + window.electron.ipcRenderer.setConfig(newYaml ) + dispatch(setYaml(newYaml)); + dispatch(setNetworkingStatus(false)); + }}> + + +

{yaml.zowe.externalDomains != undefined && yaml.zowe.externalDomains.map((domain: string, index: number) => { }} /> {yaml.zowe?.externalDomains.length > 1 && { let domains = [...yaml.zowe?.externalDomains]; domains.splice(index, 1); @@ -727,19 +246,19 @@ const Networking = () => { // // dispatch(setYaml(newYaml)); }} /> - + } aria-controls="components-content" id="components-header" > - Components + Components {Object.keys(yaml.components).filter(component => yaml.components[component].hasOwnProperty('port')).map(component => { // yaml.components[component].hasOwnProperty('enabled') && - console.log(component, yaml.components[component].enabled, yaml.components[component].port); - return
+ return
{ @@ -751,12 +270,17 @@ const Networking = () => { }}/>} /> 65535} variant="standard" + size="small" required={yaml.components[component].enabled} type="number" key={`port-input-${component}`} value={yaml.components[component].port} + InputProps={{ + style: {minWidth: '100px', width: '100px'} + }} onChange={async (e) => { if (!Number.isNaN(Number(e.target.value))) { // REVIEW: Use schema for validation const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], port: Number(e.target.value)}}}; @@ -770,65 +294,8 @@ const Networking = () => { })} - {/*
- {Object.keys(customSchema.properties).map((schemaKey, index) => { - if(index < LOOP_LIMIT){ - if (customSchema.properties[schemaKey].patternProperties != undefined) { //only for rendering patternProperties - if(typeof yaml[schemaKey] === "object" && Object.keys(yaml[schemaKey]).length > 0) { - return
-

{schemaKey}

- {Object.keys(customSchema.properties[schemaKey].patternProperties).map((regexPattern, rIndex) => { - const pattern = new RegExp(regexPattern); - if(rIndex < LOOP_LIMIT && yaml[schemaKey]) { - return Object.keys(yaml[schemaKey]).map((matchedPattern, mIndex) => { - if(mIndex < LOOP_LIMIT && pattern.test(matchedPattern)){ - return
- {yaml[schemaKey][matchedPattern].hasOwnProperty('enabled') && { - // console.log('new yaml:', JSON.stringify({...yaml, [keys[i]]: {...yaml[keys[i]], [toMatch[k]]: {...yaml[keys[i]][toMatch[k]], [matchedProps[l]]: !yaml[keys[i]][toMatch[k]][matchedProps[l]]}}})); - const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], enabled: !yaml[schemaKey][matchedPattern].enabled}}}; - await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.enabled`, !yaml[schemaKey][matchedPattern].enabled); - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); - }}/>} - />} - - {matchedPattern} -
-
- {yaml[schemaKey][matchedPattern].port && { - if(!Number.isNaN(Number(e.target.value))){ - const newYaml = {...yaml, [schemaKey]: {...yaml[schemaKey], [matchedPattern]: {...yaml[schemaKey][matchedPattern], port: Number(e.target.value)}}}; - await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${schemaKey}.${matchedPattern}.port`, Number(e.target.value)) - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); - } - }} - />} -
- } - return null; - }) - } - return null; - }) - } -
- } - } - } - return null; - })} -
*/} - + {console.log(wut)}} formData={yaml.zowe.network}/> +
From e501e5f714c71d13e8f79d8e047be1e7db6a29f1 Mon Sep 17 00:00:00 2001 From: Sergei Kurnevich Date: Fri, 1 Nov 2024 11:08:10 +0100 Subject: [PATCH 4/6] Add zowe.network support Signed-off-by: Sergei Kurnevich --- src/renderer/components/stages/Networking.tsx | 200 ++++++++++++------ 1 file changed, 137 insertions(+), 63 deletions(-) diff --git a/src/renderer/components/stages/Networking.tsx b/src/renderer/components/stages/Networking.tsx index 21ba845e..caf7cf58 100644 --- a/src/renderer/components/stages/Networking.tsx +++ b/src/renderer/components/stages/Networking.tsx @@ -8,9 +8,9 @@ * Copyright Contributors to the Zowe Project. */ -import { useState, useEffect, useRef } from "react"; +import { useState, useEffect, useRef, Fragment } from "react"; import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Checkbox, FormControlLabel, IconButton, SvgIcon, SvgIconProps, TextField, Typography } from '@mui/material'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import { ExpandMore, Add, DeleteForever} from '@mui/icons-material'; import { useAppSelector, useAppDispatch } from '../../hooks'; import { selectYaml, setNextStepEnabled, setYaml, selectSchema } from '../configuration-wizard/wizardSlice'; import ContainerCard from '../common/ContainerCard'; @@ -28,24 +28,68 @@ import { alertEmitter } from "../Header"; import JsonForm from '../common/JsonForms'; // TODO: Fix the schema usage, remove schema validation as useless -// Add helper text describing ports usage, and important details -// Hide components under collapsible customize panel -// Validate that ports are unique between components -function AddIcon(props: SvgIconProps) { - return ( - - - - ); -} - -function DeleteIcon(props: SvgIconProps) { - return ( - - - - ); +// FIXME: Hardcoded altered network schema as JsonForms can't work with complete schema syntax ("attls": {"const": true, ...}) +const networkSchema = { + "type": "object", + "additionalProperties": false, + "description": "Optional, advanced network configuration parameters", + "properties": { + "server": { + "type": "object", + "description": "Optional, advanced network configuration parameters for Zowe servers", + "properties": { + "tls": { + "type": "object", + "additionalProperties": false, + "required": ["maxTls", "minTls"], + "properties": { + "attls": { + "description": "Enables AT-TLS for server operations. AT-TLS should only be enabled in a z/OS host environment. Servers will be switched into HTTP mode to accomodate z/OS the specific AT-TLS feature which wraps network calls in TLS.", + "type": "boolean", + "default": false + }, + "maxTls": { + "type": "string", + "enum": [ + "TLSv1.2", + "TLSv1.3" + ], + "default": "TLSv1.3", + "description": "Maximum TLS version allowed for network connections if AT-TLS is not used" + }, + "minTls": { + "type": "string", + "enum": [ + "TLSv1.2", + "TLSv1.3" + ], + "default": "TLSv1.2", + "description": "Minimum TLS version allowed for network connections if AT-TLS is not used, and less than or equal to network.maxTls." + } + } + } + } + }, + "client": { + "type": "object", + "additionalProperties": false, + "description": "Optional, advanced network configuration parameters for Zowe servers when sending requests as clients.", + "properties": { + "tls": { + "type": "object", + "additionalProperties": false, + "properties": { + "attls": { + "description": "Enables AT-TLS for client operations. AT-TLS should only be enabled in a z/OS host environment. Servers will be switched into HTTP mode to accomodate z/OS the specific AT-TLS feature which wraps network calls in TLS.", + "type": "boolean", + "default": false + } + } + } + } + } + } } const Networking = () => { @@ -72,20 +116,19 @@ const Networking = () => { // const validate = ajv.getSchema("https://zowe.org/schemas/v2/server-base") || ajv.compile(customSchema); // REVIEW: What is returned by getSchema, do we need ajv? maybe only once on customSchema retrieving. const LOOP_LIMIT = 1024; - // const [stateUpdated, setStateUpdated] = useState(false); const [stageStatus, setStageStatus] = useState(stages[STAGE_ID].subStages[SUB_STAGE_ID].isSkipped); const stageStatusRef = useRef(stageStatus); // const isInitializationSkipped = !useAppSelector(selectInitializationStatus); useEffect(() => { - stageStatusRef.current = stageStatus; // REVIEW: What it does? + stageStatusRef.current = stageStatus; }, [stageStatus]); useEffect(() => { // const nextPosition = document.getElementById('container-box-id'); // if(nextPosition) nextPosition.scrollIntoView({behavior: 'smooth'}); - if (yaml.zowe.externalDomains?.length === 1 && yaml.zowe.externalDomains[0] === 'sample-domain.com') { + if (yaml.zowe?.externalDomains?.length === 1 && yaml.zowe.externalDomains[0] === 'sample-domain.com') { dispatch(setYaml({...yaml, zowe: {...yaml.zowe, externalDomains: [connectionArgs.host]}})); } dispatch(setNextStepEnabled(getProgress('networkingStatus'))); @@ -142,9 +185,27 @@ const Networking = () => { // setStageConfig(true, '', newYaml); // }; + const handleNetworkTLSChange = async (data: any, section: string) => { + const newYaml = {...yaml, zowe: {...yaml.zowe, network: {...yaml.zowe.network, [section]: {...yaml.zowe.network[section], tls: data}}}}; + await window.electron.ipcRenderer.setConfigByKeyAndValidate(`zowe.network.${section}.tls`, data); + dispatch(setYaml(newYaml)); + dispatch(setNetworkingStatus(false)); + } + const onSaveYaml = (e: any) => { e.preventDefault(); updateProgress(false); + + // Check for duplicated ports in components + const ports = Object.keys(yaml.components) + .filter((c: any) => yaml.components[c].enabled && yaml.components[c].port) + .map(c => Number(yaml.components[c].port)); + const duplicatedPorts = ports.filter((p, ind) => ports.indexOf(p) !== ind); + if (duplicatedPorts.length) { + alertEmitter.emit('showAlert', `Port ${duplicatedPorts[0]} is assigned to a multiple enabled components`, 'error'); + return; + } + alertEmitter.emit('showAlert', 'Uploading yaml...', 'info'); if(!installationArgs.dryRunMode){ window.electron.ipcRenderer.uploadLatestYaml(connectionArgs, installationArgs).then((res: IResponse) => { @@ -164,7 +225,7 @@ const Networking = () => { dispatch(setInitializationStatus(isInitializationStageComplete())); } } - // console.log(JSON.stringify(schema)); + return ( yaml && schema &&
@@ -181,15 +242,31 @@ const Networking = () => { if(data.components){ newYaml = {...newYaml, components: data.components}; } + if(data.zowe && data.zowe.network){ + newYaml = {...yaml, zowe: {...yaml.zowe, network: data.zowe.network}}; + } setStageConfig(true, '', newYaml); }}/>} dispatch(setYaml((await window.electron.ipcRenderer.getConfig()).details ?? yaml))} // REVIEW: Why? > {!isFormValid &&
{formError}
} - {/* REVIEW: button as child of

*/} -

- External Domains + External Domains + You can list your external domains on how you want to access Zowe.

+ This should be the domain list you would like to put into your web browser's address bar.
+ {yaml.zowe?.externalDomains != undefined && yaml.zowe.externalDomains.map((domain: string, index: number) => + { + let domains = [...yaml.zowe?.externalDomains]; + domains[index] = e.target.value; + const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; + window.electron.ipcRenderer.setConfig(newYaml) + dispatch(setYaml(newYaml)); + dispatch(setNetworkingStatus(false)); + }} + /> { dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); }}> - + -

- {yaml.zowe.externalDomains != undefined && yaml.zowe.externalDomains.map((domain: string, index: number) => { - let domains = [...yaml.zowe?.externalDomains]; - domains[index] = e.target.value; - const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; - // console.log(domains); - window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); - }} - /> - {yaml.zowe?.externalDomains.length > 1 && { - let domains = [...yaml.zowe?.externalDomains]; - domains.splice(index, 1); - const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; - window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)) - dispatch(setNetworkingStatus(false)); - }}> - - } + {yaml.zowe?.externalDomains.length > 1 && { + let domains = [...yaml.zowe?.externalDomains]; + domains.splice(index, 1); + const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; + window.electron.ipcRenderer.setConfig(newYaml ) + dispatch(setYaml(newYaml)) + dispatch(setNetworkingStatus(false)); + }}> + + } )}
{ @@ -246,16 +310,21 @@ const Networking = () => { // // dispatch(setYaml(newYaml)); }} /> - + You can configure which port will be used by every component.

+ Note that the gateway port should match the External Port in most cases. + In some use cases, like containerization, this port could be different.
+

+ } + sx={{mt: '12px'}} + expandIcon={} aria-controls="components-content" id="components-header" > - Components + Component ports configuration - {Object.keys(yaml.components).filter(component => yaml.components[component].hasOwnProperty('port')).map(component => { // yaml.components[component].hasOwnProperty('enabled') && + {Object.keys(yaml.components).filter(component => yaml.components[component].hasOwnProperty('port')).map(component => { return
{ key={`toggle-${component}`} control={ { const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], enabled: !yaml.components[component].enabled}}}; - console.log(JSON.stringify(newYaml)) await window.electron.ipcRenderer.setConfigByKeyAndValidate(`components.${component}.enabled`, !yaml.components[component].enabled); dispatch(setYaml(newYaml)); dispatch(setNetworkingStatus(false)); @@ -271,18 +339,17 @@ const Networking = () => { /> 65535} + error={!yaml.components[component].port || yaml.components[component].port > 65535} variant="standard" size="small" required={yaml.components[component].enabled} - type="number" key={`port-input-${component}`} value={yaml.components[component].port} InputProps={{ style: {minWidth: '100px', width: '100px'} }} onChange={async (e) => { - if (!Number.isNaN(Number(e.target.value))) { // REVIEW: Use schema for validation + if (!Number.isNaN(Number(e.target.value))) { const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], port: Number(e.target.value)}}}; await window.electron.ipcRenderer.setConfigByKeyAndValidate(`components.${component}.port`, Number(e.target.value)) dispatch(setYaml(newYaml)); @@ -294,7 +361,14 @@ const Networking = () => { })} - {console.log(wut)}} formData={yaml.zowe.network}/> + {(networkSchema && yaml.zowe?.network) ? + + Server TLS configuration + handleNetworkTLSChange(data, 'server')} formData={yaml.zowe?.network.server.tls}/> + Client TLS configuration + handleNetworkTLSChange(data, 'client')} formData={yaml.zowe?.network.client.tls}/> + : null + } From 79e968123b96ae37369a036afce4c5f8b7d1dc23 Mon Sep 17 00:00:00 2001 From: Sergei Kurnevich Date: Mon, 4 Nov 2024 17:12:57 +0100 Subject: [PATCH 5/6] Minor code clean up Signed-off-by: Sergei Kurnevich --- src/renderer/components/stages/Networking.tsx | 76 +++++-------------- 1 file changed, 20 insertions(+), 56 deletions(-) diff --git a/src/renderer/components/stages/Networking.tsx b/src/renderer/components/stages/Networking.tsx index caf7cf58..a82fd783 100644 --- a/src/renderer/components/stages/Networking.tsx +++ b/src/renderer/components/stages/Networking.tsx @@ -9,7 +9,7 @@ */ import { useState, useEffect, useRef, Fragment } from "react"; -import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Checkbox, FormControlLabel, IconButton, SvgIcon, SvgIconProps, TextField, Typography } from '@mui/material'; +import { Accordion, AccordionDetails, AccordionSummary, Box, Button, Checkbox, FormControlLabel, IconButton, TextField, Typography } from '@mui/material'; import { ExpandMore, Add, DeleteForever} from '@mui/icons-material'; import { useAppSelector, useAppDispatch } from '../../hooks'; import { selectYaml, setNextStepEnabled, setYaml, selectSchema } from '../configuration-wizard/wizardSlice'; @@ -18,18 +18,16 @@ import EditorDialog from "../common/EditorDialog"; import { createTheme } from '@mui/material/styles'; import { getStageDetails, getSubStageDetails } from "../../../services/StageDetails"; import { stages } from "../configuration-wizard/Wizard"; -import { selectInitializationStatus, setInitializationStatus, setNetworkingStatus } from "./progress/progressSlice"; +import { setInitializationStatus, setNetworkingStatus } from "./progress/progressSlice"; import { setActiveStep } from "./progress/activeStepSlice"; -import { TYPE_YAML, TYPE_JCL, TYPE_OUTPUT, ajv } from "../common/Utils"; +import { TYPE_YAML, TYPE_OUTPUT } from "../common/Utils"; import { IResponse } from "../../../types/interfaces"; import { selectConnectionArgs } from "./connection/connectionSlice"; import { getInstallationArguments, getProgress, isInitializationStageComplete, updateSubStepSkipStatus } from "./progress/StageProgressStatus"; import { alertEmitter } from "../Header"; import JsonForm from '../common/JsonForms'; -// TODO: Fix the schema usage, remove schema validation as useless - -// FIXME: Hardcoded altered network schema as JsonForms can't work with complete schema syntax ("attls": {"const": true, ...}) +// FIXME: Hardcoded altered network schema for render purpose as JsonForms can't work with complete schema syntax like ("attls": {"const": true, ...}) const networkSchema = { "type": "object", "additionalProperties": false, @@ -113,21 +111,20 @@ const Networking = () => { const installationArgs = getInstallationArguments(); const connectionArgs = useAppSelector(selectConnectionArgs); - // const validate = ajv.getSchema("https://zowe.org/schemas/v2/server-base") || ajv.compile(customSchema); // REVIEW: What is returned by getSchema, do we need ajv? maybe only once on customSchema retrieving. - const LOOP_LIMIT = 1024; + // const validate = ajv.compile(schema); // REVIEW: Does not work with current schema. "reference "https://zowe.org/schemas/v2/server-base#zowePath" resolves to more than one schema" const [stageStatus, setStageStatus] = useState(stages[STAGE_ID].subStages[SUB_STAGE_ID].isSkipped); const stageStatusRef = useRef(stageStatus); - // const isInitializationSkipped = !useAppSelector(selectInitializationStatus); + // const isInitializationSkipped = !useAppSelector(selectInitializationStatus); // Not used useEffect(() => { stageStatusRef.current = stageStatus; }, [stageStatus]); useEffect(() => { - // const nextPosition = document.getElementById('container-box-id'); - // if(nextPosition) nextPosition.scrollIntoView({behavior: 'smooth'}); + const nextPosition = document.getElementById('container-box-id'); + if(nextPosition) nextPosition.scrollIntoView({behavior: 'smooth'}); if (yaml.zowe?.externalDomains?.length === 1 && yaml.zowe.externalDomains[0] === 'sample-domain.com') { dispatch(setYaml({...yaml, zowe: {...yaml.zowe, externalDomains: [connectionArgs.host]}})); } @@ -147,7 +144,6 @@ const Networking = () => { } const updateProgress = (status: boolean) => { - // setStateUpdated(!setStateUpdated); dispatch(setNetworkingStatus(status)); dispatch(setNextStepEnabled(status)); setStageSkipStatus(!status); @@ -163,33 +159,16 @@ const Networking = () => { setFormError(errorMsg); dispatch(setYaml(data)); } - - // const handleFormChange = async (data: any, isYamlUpdated?: boolean) => { - // if(validate) { - // validate(data); - // if(validate.errors) { - // const errPath = validate.errors[0].schemaPath; - // const errMsg = validate.errors[0].message; - // setStageConfig(false, errPath+' '+errMsg, data.zowe); - // } - // } - // let newYaml; - // if (data.zowe && data.zowe.externalDomains && data.zowe.externalPort) { - // newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: data.zowe.externalDomains, externalPort: data.zowe.externalPort}}; - // } - // if(data.components){ - // newYaml = {...newYaml, components: data.components}; - // } - // window.electron.ipcRenderer.setConfig(newYaml) - // setStageConfig(true, '', newYaml); - // }; + const handleFormChange = async (data: any) => { + window.electron.ipcRenderer.setConfig(data) + dispatch(setYaml(data)); + dispatch(setNetworkingStatus(false)); + }; const handleNetworkTLSChange = async (data: any, section: string) => { const newYaml = {...yaml, zowe: {...yaml.zowe, network: {...yaml.zowe.network, [section]: {...yaml.zowe.network[section], tls: data}}}}; - await window.electron.ipcRenderer.setConfigByKeyAndValidate(`zowe.network.${section}.tls`, data); - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); + handleFormChange(newYaml); } const onSaveYaml = (e: any) => { @@ -262,9 +241,7 @@ const Networking = () => { let domains = [...yaml.zowe?.externalDomains]; domains[index] = e.target.value; const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; - window.electron.ipcRenderer.setConfig(newYaml) - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); + handleFormChange(newYaml); }} /> { onClick={(e) => { let domains = [...yaml.zowe?.externalDomains || [], ""]; const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; - window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); + handleFormChange(newYaml); }}> @@ -286,9 +261,7 @@ const Networking = () => { let domains = [...yaml.zowe?.externalDomains]; domains.splice(index, 1); const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; - window.electron.ipcRenderer.setConfig(newYaml ) - dispatch(setYaml(newYaml)) - dispatch(setNetworkingStatus(false)); + handleFormChange(newYaml); }}> } @@ -303,11 +276,7 @@ const Networking = () => { value={yaml.zowe.externalPort} onChange={async (e) => { const newYaml = {...yaml, zowe: {...yaml.zowe, externalPort: Number(e.target.value)}}; - window.electron.ipcRenderer.setConfig(newYaml) - dispatch(setYaml(newYaml)); - // // props.setYaml(newYaml); - // await window.electron.ipcRenderer.setConfigByKeyAndValidate(`${keys[i]}.${toMatch[k]}.${matchedProps[l]}`, Number(e.target.value)) - // // dispatch(setYaml(newYaml)); + handleFormChange(newYaml); }} /> You can configure which port will be used by every component.

@@ -332,13 +301,10 @@ const Networking = () => { key={`toggle-${component}`} control={ { const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], enabled: !yaml.components[component].enabled}}}; - await window.electron.ipcRenderer.setConfigByKeyAndValidate(`components.${component}.enabled`, !yaml.components[component].enabled); - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); + handleFormChange(newYaml); }}/>} /> 65535} variant="standard" size="small" @@ -351,9 +317,7 @@ const Networking = () => { onChange={async (e) => { if (!Number.isNaN(Number(e.target.value))) { const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], port: Number(e.target.value)}}}; - await window.electron.ipcRenderer.setConfigByKeyAndValidate(`components.${component}.port`, Number(e.target.value)) - dispatch(setYaml(newYaml)); - dispatch(setNetworkingStatus(false)); + handleFormChange(newYaml); } }} /> From 8d542c0957fbcfbd3819d9645435cf7411ead604 Mon Sep 17 00:00:00 2001 From: Sergei Kurnevich Date: Mon, 4 Nov 2024 19:38:35 +0100 Subject: [PATCH 6/6] Fix linter errors Signed-off-by: Sergei Kurnevich --- src/renderer/components/stages/Networking.tsx | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/renderer/components/stages/Networking.tsx b/src/renderer/components/stages/Networking.tsx index a82fd783..07f3003c 100644 --- a/src/renderer/components/stages/Networking.tsx +++ b/src/renderer/components/stages/Networking.tsx @@ -233,23 +233,20 @@ const Networking = () => { External Domains You can list your external domains on how you want to access Zowe.

This should be the domain list you would like to put into your web browser's address bar.
- {yaml.zowe?.externalDomains != undefined && yaml.zowe.externalDomains.map((domain: string, index: number) => + {Array.isArray(yaml.zowe?.externalDomains) && yaml.zowe.externalDomains.map((domain: string, index: number) => { - let domains = [...yaml.zowe?.externalDomains]; - domains[index] = e.target.value; - const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; + const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: yaml.zowe.externalDomains.with(index, e.target.value)}}; handleFormChange(newYaml); }} /> { - let domains = [...yaml.zowe?.externalDomains || [], ""]; - const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; + onClick={() => { + const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: [...yaml.zowe.externalDomains, ""]}}; handleFormChange(newYaml); }}> @@ -257,9 +254,8 @@ const Networking = () => { {yaml.zowe?.externalDomains.length > 1 && { - let domains = [...yaml.zowe?.externalDomains]; - domains.splice(index, 1); + onClick={() => { + const domains = [...yaml.zowe.externalDomains.slice(0, index), ...yaml.zowe.externalDomains.slice(index + 1)]; const newYaml = {...yaml, zowe: {...yaml.zowe, externalDomains: domains}}; handleFormChange(newYaml); }}> @@ -293,13 +289,13 @@ const Networking = () => { Component ports configuration - {Object.keys(yaml.components).filter(component => yaml.components[component].hasOwnProperty('port')).map(component => { + {Object.keys(yaml.components).filter(component => Object.prototype.hasOwnProperty.call(yaml.components[component], "port")).map(component => { return
{ + control={ { const newYaml = {...yaml, components: {...yaml.components, [component]: {...yaml.components[component], enabled: !yaml.components[component].enabled}}}; handleFormChange(newYaml); }}/>}