From a7b37de15d9edef66635fa09dfc68b87651f81ad Mon Sep 17 00:00:00 2001 From: Robert Patrick Date: Wed, 2 Nov 2022 10:06:04 -0500 Subject: [PATCH 1/2] fixing app/component deployment issues --- electron/app/js/ipcRendererPreload.js | 1 + electron/app/js/kubectlUtils.js | 40 ++++++++++- electron/app/locales/en/electron.json | 1 + electron/app/locales/en/webui.json | 7 ++ electron/app/main.js | 5 ++ webui/src/js/models/k8s-domain-definition.js | 11 --- .../src/js/models/vz-component-definition.js | 4 -- .../utils/k8s-domain-configmap-generator.js | 2 +- webui/src/js/utils/k8s-domain-deployer.js | 27 ++++---- webui/src/js/utils/observable-properties.js | 4 ++ webui/src/js/utils/vz-application-deployer.js | 32 ++++++++- .../utils/vz-component-configmap-generator.js | 4 ++ webui/src/js/utils/vz-component-deployer.js | 5 +- webui/src/js/utils/vz-component-undeployer.js | 3 +- webui/src/js/utils/vz-helper.js | 67 +++---------------- webui/src/js/viewModels/domain-code-view.js | 5 +- .../viewModels/vz-application-design-view.js | 9 +++ .../js/viewModels/vz-component-code-view.js | 5 +- .../js/views/vz-application-design-view.html | 8 +++ .../vz-ingress-trait-rule-edit-dialog.html | 8 ++- 20 files changed, 146 insertions(+), 102 deletions(-) diff --git a/electron/app/js/ipcRendererPreload.js b/electron/app/js/ipcRendererPreload.js index 5ecddae6f..e409dc783 100644 --- a/electron/app/js/ipcRendererPreload.js +++ b/electron/app/js/ipcRendererPreload.js @@ -232,6 +232,7 @@ contextBridge.exposeInMainWorld( 'get-verrazzano-secret-names', 'get-verrazzano-cluster-names', 'get-verrazzano-deployment-names-all-namespaces', + 'verify-verrazzano-components-exist', 'deploy-verrazzano-project', 'deploy-verrazzano-application', 'undeploy-verrazzano-application', diff --git a/electron/app/js/kubectlUtils.js b/electron/app/js/kubectlUtils.js index d7bb01160..5346514d5 100644 --- a/electron/app/js/kubectlUtils.js +++ b/electron/app/js/kubectlUtils.js @@ -688,7 +688,7 @@ async function apply(kubectlExe, fileData, options) { fsUtils.writeTempFile(fileData, { baseName: 'k8sApplyData', extension: '.yaml' }).then(fileName => { const args = [ 'apply', '-f', fileName ]; executeFileCommand(kubectlExe, args, env).then(stdout => { - console.log('kubectl apply returned: %s', stdout); + getLogger().debug('kubectl apply returned: %s', stdout); fsUtils.recursivelyRemoveTemporaryFileDirectory(fileName).then(() => resolve(result)).catch(err => { getLogger().warn('kubectlUtils.apply() failed to remove temporary file %s: %s', fileName, err); resolve(result); @@ -860,7 +860,12 @@ async function isVerrazzanoInstalled(kubectlExe, options) { const vzObject = vzObjectList[0]; result.isInstalled = true; result.name = vzObject.metadata?.name; - result.version = vzObject.status?.version; + + let statusVersion = vzObject.status?.version; + if (statusVersion && statusVersion.startsWith('v')) { + statusVersion = statusVersion.slice(1); + } + result.version = statusVersion; } resolve(result); }).catch(err => { @@ -972,6 +977,36 @@ async function getKubernetesObjectsFromAllNamespaces(kubectlExe, kubectlOptions, }); } +async function verifyVerrazzanoComponentsDeployed(kubectlExe, componentNames, namespace, kubectlOptions) { + const httpsProxyUrl = getHttpsProxyUrl(); + const bypassProxyHosts = getBypassProxyHosts(); + + const env = getKubectlEnvironment(kubectlOptions, httpsProxyUrl, bypassProxyHosts); + + const result = { + isSuccess: true + }; + + const missingComponentNames = []; + for (const componentName of componentNames) { + const args = [ 'get', 'Component', componentName, '-n', namespace ]; + try { + const stdout = await executeFileCommand(kubectlExe, args, env); + getLogger().debug('Found component %s in namespace %s: %s', componentName, namespace, stdout); + } catch (err) { + getLogger().warn('Error getting component %s in namespace %s: %s', componentName, namespace, getErrorMessage(err)); + missingComponentNames.push(componentName); + } + } + + if (missingComponentNames.length > 0) { + result.isSuccess = false; + result.reason = i18n.t('kubectl-verify-vz-components-deployed-error-message', + { namespace: namespace, missingComponents: missingComponentNames.join(', ')}); + } + return Promise.resolve(result); +} + async function doCreateSecret(kubectlExe, createArgs, env, namespace, secret, resolve, results, key) { executeFileCommand(kubectlExe, createArgs, env, true).then(() => { resolve(results); @@ -1063,5 +1098,6 @@ module.exports = { validateDomainExist, validateApplicationExist, verifyClusterConnectivity, + verifyVerrazzanoComponentsDeployed, verifyVerrazzanoPlatformOperatorRollout, }; diff --git a/electron/app/locales/en/electron.json b/electron/app/locales/en/electron.json index 5efd35774..ebcaf617c 100644 --- a/electron/app/locales/en/electron.json +++ b/electron/app/locales/en/electron.json @@ -318,6 +318,7 @@ "kubectl-get-named-vz-install-error-message": "Unable to get Verrazzano installation with name {{name}}: {{error}}", "kubectl-get-vz-application-status-error-message": "Unable to get Verrazzano application status: {{error}}", "kubectl-get-operator-version-not-found-error-message": "Failed to find the operator version from its log entries", + "kubectl-verify-vz-components-deployed-error-message": "Unable to find one or more components in namespace {{namespace}}: {{missingComponents}}", "helm-not-specified-error-message": "Helm executable path was not provided", "helm-not-exists-error-message": "Helm executable {{filePath}} does not exist", diff --git a/electron/app/locales/en/webui.json b/electron/app/locales/en/webui.json index ac3405bb1..a2fbfa88f 100644 --- a/electron/app/locales/en/webui.json +++ b/electron/app/locales/en/webui.json @@ -1324,6 +1324,7 @@ "flow-getting-vz-application-status-in-progress": "Getting Application Status", "flow-checking-operator-version-in-progress": "Checking operator version", "flow-checking-vz-already-installed-in-progress": "Checking if Verrazzano is already installed.", + "flow-checking-vz-app-components-deployed-in-progress": "Checking if Verrazzano application's components are deployed.", "flow-install-verrazzano-name": "Install Verrazzano", "flow-verrazzano-install-status-check-name": "Check Verrazzano Install Status", "flow-verrazzano-get-install-version-name": "Get Verrazzano Installed Version", @@ -1564,8 +1565,11 @@ "vz-application-design-project-name-label": "Verrazzano Project Name", "vz-application-design-project-name-help": "The name to use when creating the new Verrazzano project for this multicluster application.", "vz-application-design-components-title": "Components", + "vz-application-design-components-label": "Components", "vz-application-design-component-name-label": "Component Name", "vz-application-design-component-name-help": "The name of the Verrazzano component used by this application.", + "vz-application-design-delete-component-button-label": "Delete Component", + "vz-application-design-delete-component-button-help": "Delete the component reference from the application.", "vz-application-design-add-component-button-label": "Add Component", "vz-application.design-add-component-flow-nane": "Add Component", "vz-application-design-add-component-validation-error-title": "Add Component to Application Aborted", @@ -1662,11 +1666,13 @@ "vz-application-design-ingress-trait-rule-edit-paths-table-aria-label": "Paths table", "vz-application-design-ingress-trait-rule-edit-path-label": "Path", "vz-application-design-ingress-trait-rule-edit-path-help": "The path value to match using the specified Path Type value.", + "vz-application-design-ingress-trait-rule-edit-path-placeholder": "Enter Path Value", "vz-application-design-ingress-trait-rule-edit-path-type-label": "Path Type", "vz-application-design-ingress-trait-rule-edit-path-type-prefix-label": "Prefix", "vz-application-design-ingress-trait-rule-edit-path-type-exact-label": "Exact", "vz-application-design-ingress-trait-rule-edit-path-type-regex-label": "Regular Expression", "vz-application-design-ingress-trait-rule-edit-path-type-help": "The expression type to use to process the Path value.", + "vz-application-design-ingress-trait-rule-edit-path-type-placeholder": "Select Path Type", "vz-application-design-ingress-trait-rule-edit-path-add-row-tooltip": "Add Path", "vz-application-design-ingress-trait-rule-edit-path-delete-row-tooltip": "Delete Path", "vz-application-design-ingress-trait-rule-editASdd-destination-title": "Destination", @@ -1691,6 +1697,7 @@ "vz-application-deployer-set-context-error-message": "Unable to deploy Verrazzano application because setting the Kubernetes client cluster context failed: {{error}}.", "vz-application-deployer-install-check-failed-error-message": "Unable to deploy Verrazzano application because checking to see if Verrazzano is installed failed: {{error}}.", "vz-application-deployer-not-installed-error-message": "Unable to deploy Verrazzano application because Verrazzano is not installed.", + "vz-application-deployer-verify-components-error-message": "Unable to deploy Verrazzano application because one or more referenced components are not deployed in the Kubernetes namespace {{namespace}}: {{error}}.", "vz-application-deployer-deploy-project-in-progress": "Deploying Verrazzano Project", "vz-application-deployer-deploy-project-error-message": "Unable to deploy Verrazzano application because an error occurred while deploying the Verrazzano project {{projectName}}: {{error}}.", "vz-application-deployer-deploy-application-in-progress": "Deploying Application", diff --git a/electron/app/main.js b/electron/app/main.js index 4ec007e62..a73904837 100644 --- a/electron/app/main.js +++ b/electron/app/main.js @@ -1059,6 +1059,11 @@ class Main { ipcMain.handle('deploy-verrazzano-project', async (event, kubectlExe, project, kubectlOptions) => { return deployProject(kubectlExe, project, kubectlOptions); }); + + // eslint-disable-next-line no-unused-vars + ipcMain.handle('verify-verrazzano-components-exist',async (event, kubectlExe, componentNames, namespace, kubectlOptions) => { + return kubectlUtils.verifyVerrazzanoComponentsDeployed(kubectlExe, componentNames, namespace, kubectlOptions); + }); } async getLatestWdtInstaller(targetWindow) { diff --git a/webui/src/js/models/k8s-domain-definition.js b/webui/src/js/models/k8s-domain-definition.js index ae44051ae..6c3780f5a 100644 --- a/webui/src/js/models/k8s-domain-definition.js +++ b/webui/src/js/models/k8s-domain-definition.js @@ -113,17 +113,6 @@ define(['knockout', 'utils/observable-properties', 'utils/common-utilities', 'ut this.updateSecrets(); }); - this.configMapIsEmpty = () => { - let result = true; - for (const entry of wdtModel.getMergedPropertiesContent().observable()) { - if (entry.Override) { - result = false; - break; - } - } - return result; - }; - this.readFrom = (json) => { props.createGroup(name, this).readFrom(json); }; diff --git a/webui/src/js/models/vz-component-definition.js b/webui/src/js/models/vz-component-definition.js index 975cc2721..268b89958 100644 --- a/webui/src/js/models/vz-component-definition.js +++ b/webui/src/js/models/vz-component-definition.js @@ -17,10 +17,6 @@ define(['utils/observable-properties', 'utils/validation-helper'], this.componentName = props.createProperty('${1}', k8sDomain.uid.observable); this.componentName.addValidator(...validationHelper.getK8sNameValidators()); - this.configMapIsEmpty = () => { - return k8sDomain.configMapIsEmpty(); - }; - this.readFrom = (json) => { props.createGroup(name, this).readFrom(json); }; diff --git a/webui/src/js/utils/k8s-domain-configmap-generator.js b/webui/src/js/utils/k8s-domain-configmap-generator.js index 3e7d3fda8..cd3f3a864 100644 --- a/webui/src/js/utils/k8s-domain-configmap-generator.js +++ b/webui/src/js/utils/k8s-domain-configmap-generator.js @@ -13,7 +13,7 @@ define(['models/wkt-project', 'js-yaml'], } shouldCreateConfigMap() { - return this.project.settings.targetDomainLocation.value === 'mii' && !this.project.k8sDomain.configMapIsEmpty(); + return this.project.settings.targetDomainLocation.value === 'mii'; } generate(generateYaml = true) { diff --git a/webui/src/js/utils/k8s-domain-deployer.js b/webui/src/js/utils/k8s-domain-deployer.js index 57c2e0547..3b76665e6 100644 --- a/webui/src/js/utils/k8s-domain-deployer.js +++ b/webui/src/js/utils/k8s-domain-deployer.js @@ -247,18 +247,16 @@ function (K8sDomainActionsBase, project, wktConsole, i18n, projectIo, dialogHelp {domainName: domainUid, domainNamespace: domainNamespace}); dialogHelper.updateBusyDialog(busyDialogMessage, 12 / totalSteps); if (this.project.settings.targetDomainLocation.value === 'mii') { - if (!this.project.k8sDomain.configMapIsEmpty()) { - const configMapData = this.k8sDomainConfigMapGenerator.generate().join('\n'); - wktLogger.debug(configMapData); - const mapResults = await (window.api.ipc.invoke('k8s-apply', kubectlExe, configMapData, kubectlOptions)); - if (!mapResults.isSuccess) { - const configMapName = this.project.k8sDomain.modelConfigMapName.value; - const errMessage = i18n.t('k8s-domain-deployer-create-config-map-failed-error-message', - {configMapName: configMapName, domainNamespace: domainNamespace, error: mapResults.reason}); - dialogHelper.closeBusyDialog(); - await window.api.ipc.invoke('show-error-message', errTitle, errMessage); - return Promise.resolve(false); - } + const configMapData = this.k8sDomainConfigMapGenerator.generate().join('\n'); + wktLogger.debug(configMapData); + const mapResults = await (window.api.ipc.invoke('k8s-apply', kubectlExe, configMapData, kubectlOptions)); + if (!mapResults.isSuccess) { + const configMapName = this.project.k8sDomain.modelConfigMapName.value; + const errMessage = i18n.t('k8s-domain-deployer-create-config-map-failed-error-message', + {configMapName: configMapName, domainNamespace: domainNamespace, error: mapResults.reason}); + dialogHelper.closeBusyDialog(); + await window.api.ipc.invoke('show-error-message', errTitle, errMessage); + return Promise.resolve(false); } } @@ -266,7 +264,7 @@ function (K8sDomainActionsBase, project, wktConsole, i18n, projectIo, dialogHelp busyDialogMessage = i18n.t('k8s-domain-deployer-deploy-in-progress', {domainName: domainUid, domainNamespace: domainNamespace}); dialogHelper.updateBusyDialog(busyDialogMessage, 13 / totalSteps); - const domainSpecData = this.k8sDomainResourceGenerator.generate().join('\n'); + const domainSpecData = new K8sDomainResourceGenerator(this.project.wko.installedVersion.value).generate().join('\n'); const domainResult = await (window.api.ipc.invoke('k8s-apply', kubectlExe, domainSpecData, kubectlOptions)); dialogHelper.closeBusyDialog(); if (domainResult.isSuccess) { @@ -415,10 +413,9 @@ function (K8sDomainActionsBase, project, wktConsole, i18n, projectIo, dialogHelp } } - if (!this.project.k8sDomain.configMapIsEmpty()) { + if (this.project.settings.targetDomainLocation.value === 'mii') { validationObject.addField('domain-design-configmap-label', this.project.k8sDomain.modelConfigMapName.validate(true), domainFormConfig); - // The fields in the table should not require validation since no empty override values should be in this computed table. } return validationObject; diff --git a/webui/src/js/utils/observable-properties.js b/webui/src/js/utils/observable-properties.js index 1c80b994d..bb28f28f9 100644 --- a/webui/src/js/utils/observable-properties.js +++ b/webui/src/js/utils/observable-properties.js @@ -442,6 +442,10 @@ define(['knockout', 'utils/common-utilities', 'utils/validation-helper', 'utils/ this.observable.push(this.createArrayItem(this, !!item ? item : {})); } + removeItemByIndex(index) { + this.observable.splice(index, 1); + } + get observable() { if (this._observable == null) { this._observable = ko.observableArray(this.createList(this._defaultValue)); diff --git a/webui/src/js/utils/vz-application-deployer.js b/webui/src/js/utils/vz-application-deployer.js index 1cc84d69f..a10f52092 100644 --- a/webui/src/js/utils/vz-application-deployer.js +++ b/webui/src/js/utils/vz-application-deployer.js @@ -9,7 +9,7 @@ define(['utils/vz-actions-base', 'models/wkt-project', 'models/wkt-console', 'ut 'utils/dialog-helper', 'utils/validation-helper', 'utils/vz-application-resource-generator', 'utils/vz-application-project-generator', 'utils/wkt-logger'], function(VzActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, validationHelper, - VerrazzanoApplicationResourceGenerator, VerrazzanoProjectResourceGenerator) { + VerrazzanoApplicationResourceGenerator, VerrazzanoProjectResourceGenerator, wktLogger) { class VzApplicationDeployer extends VzActionsBase { constructor() { super(); @@ -35,7 +35,7 @@ function(VzActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, vali const createProject = this.project.vzApplication.useMultiClusterApplication.value && this.project.vzApplication.createProject.value; - const totalSteps = createProject ? 6.0 : 5.0; + const totalSteps = createProject ? 7.0 : 6.0; const kubectlExe = this.getKubectlExe(); try { let busyDialogMessage = i18n.t('flow-validate-kubectl-exe-in-progress'); @@ -86,7 +86,25 @@ function(VzActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, vali } } - let step = 4; + // Verify that all referenced components are already deployed in the namespace. + const namespace = this.project.k8sDomain.kubernetesNamespace.value; + busyDialogMessage = i18n.t('flow-checking-vz-app-components-deployed-in-progress'); + dialogHelper.updateBusyDialog(busyDialogMessage, 4/totalSteps); + if (!options.skipVzComponentsDeployedCheck) { + const appComponentNames = this.getApplicationComponentNames(); + wktLogger.debug('appComponentNames = %s', appComponentNames); + const result = await window.api.ipc.invoke('verify-verrazzano-components-exist', + kubectlExe, appComponentNames, namespace, kubectlOptions); + if (!result.isSuccess) { + dialogHelper.closeBusyDialog(); + const errMessage = i18n.t('vz-application-deployer-verify-components-error-message', + { namespace: namespace, error: result.reason }); + await window.api.ipc.invoke('show-error-message', errTitle, errMessage); + return Promise.resolve(false); + } + } + + let step = 5; if (createProject) { const vzProjectGenerator = new VerrazzanoProjectResourceGenerator(); const projectSpec = vzProjectGenerator.generate().join('\n'); @@ -153,8 +171,16 @@ function(VzActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, vali this.project.vzApplication.projectName.validate(true), vzApplicationFormConfig); } + // Don't allow an application with zero components... + validationObject.addField('vz-application-design-components-label', + validationHelper.validateRequiredField(this.project.vzApplication.components.value), vzApplicationFormConfig); + return validationObject; } + + getApplicationComponentNames() { + return this.project.vzApplication.components.value.map(component => component.name); + } } return new VzApplicationDeployer(); }); diff --git a/webui/src/js/utils/vz-component-configmap-generator.js b/webui/src/js/utils/vz-component-configmap-generator.js index 0ef148c58..cafead6e8 100644 --- a/webui/src/js/utils/vz-component-configmap-generator.js +++ b/webui/src/js/utils/vz-component-configmap-generator.js @@ -15,6 +15,10 @@ define(['models/wkt-project', 'utils/k8s-domain-configmap-generator', 'utils/vz- this.configMapComponentNamespace = ''; } + shouldCreateConfigMap() { + return this.k8sDomainConfigMapGenerator.shouldCreateConfigMap(); + } + generate() { const k8sDomainConfigMap = this.k8sDomainConfigMapGenerator.generate(false); diff --git a/webui/src/js/utils/vz-component-deployer.js b/webui/src/js/utils/vz-component-deployer.js index 7fc0909f5..b4eb30649 100644 --- a/webui/src/js/utils/vz-component-deployer.js +++ b/webui/src/js/utils/vz-component-deployer.js @@ -205,7 +205,7 @@ function(VzActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, vali const vzResourceGenerator = new VerrazzanoComponentResourceGenerator(); const vzConfigMapGenerator = new VerrazzanoComponentConfigMapGenerator(); const components = [ vzResourceGenerator.generate().join('\n') ]; - if (!this.project.vzComponent.configMapIsEmpty()) { + if (vzConfigMapGenerator.shouldCreateConfigMap()) { wktLogger.debug('Adding ConfigMap for component deployment'); components.push(vzConfigMapGenerator.generate().join('\n')); } @@ -326,10 +326,9 @@ function(VzActionsBase, project, wktConsole, i18n, projectIo, dialogHelper, vali } } - if (!this.project.vzComponent.configMapIsEmpty()) { + if (this.project.settings.targetDomainLocation.value === 'mii') { validationObject.addField('domain-design-configmap-label', this.project.k8sDomain.modelConfigMapName.validate(true), vzComponentFormConfig); - // The fields in the table should not require validation since no empty override values should be in this computed table. } return validationObject; diff --git a/webui/src/js/utils/vz-component-undeployer.js b/webui/src/js/utils/vz-component-undeployer.js index 3cdcd0da7..d385e6a0e 100644 --- a/webui/src/js/utils/vz-component-undeployer.js +++ b/webui/src/js/utils/vz-component-undeployer.js @@ -34,7 +34,8 @@ function(VzActionsBase, project, wktConsole, i18n, projectIo, dialogHelper) { // Prompt user to remove just the domain or the entire domain namespace. const componentName = this.project.vzComponent.componentName.value; const componentNamespace = this.project.k8sDomain.kubernetesNamespace.value; - const configMapName = this.project.vzComponent.configMapIsEmpty() ? undefined : this.project.k8sDomain.modelConfigMapName.value; + const configMapName = this.project.settings.targetDomainLocation.value === 'mii' ? + this.project.k8sDomain.modelConfigMapName.value : undefined; const promptTitle = i18n.t('vz-component-undeployer-remove-namespace-prompt-title'); const promptQuestion = this._getPromptQuestion(componentName, componentNamespace, configMapName); diff --git a/webui/src/js/utils/vz-helper.js b/webui/src/js/utils/vz-helper.js index da351bd45..f15376421 100644 --- a/webui/src/js/utils/vz-helper.js +++ b/webui/src/js/utils/vz-helper.js @@ -16,18 +16,9 @@ const VZ_ALPHA1_MANUAL_SCALER_TRAIT_API_VERSION = 'core.oam.dev/v1alpha2'; const VZ_ALPHA1_METRICS_TRAIT_API_VERSION = 'oam.verrazzano.io/v1alpha1'; const VZ_ALPHA1_PROJECT_API_VERSION = 'clusters.verrazzano.io/v1alpha1'; -const VZ_BETA1_SWITCH_VERSION = '1.4.0'; +const VZ_CR_BETA1_SWITCH_VERSION = '1.4.0'; const VZ_BETA1_INSTALL_API_VERSION = 'install.verrazzano.io/v1beta1'; -const VZ_BETA1_COMPONENT_API_VERSION = 'core.oam.dev/v1alpha2'; -const VZ_BETA1_WORKLOAD_API_VERSION = 'oam.verrazzano.io/v1beta1'; -const VZ_BETA1_APPLICATION_API_VERSION = 'core.oam.dev/v1alpha2'; -const VZ_BETA1_MULTI_CLUSTER_APPLICATION_API_VERSION = 'clusters.verrazzano.io/v1beta1'; -const VZ_BETA1_INGRESS_TRAIT_API_VERSION = 'oam.verrazzano.io/v1beta1'; -const VZ_BETA1_LOGGING_TRAIT_API_VERSION = 'oam.verrazzano.io/v1beta1'; -const VZ_BETA1_MANUAL_SCALER_TRAIT_API_VERSION = 'core.oam.dev/v1alpha2'; -const VZ_BETA1_METRICS_TRAIT_API_VERSION = 'oam.verrazzano.io/v1beta1'; -const VZ_BETA1_PROJECT_API_VERSION = 'clusters.verrazzano.io/v1beta1'; define([], function() { @@ -45,7 +36,7 @@ define([], } getInstallApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { + if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_CR_BETA1_SWITCH_VERSION) < 0) { return VZ_ALPHA1_INSTALL_API_VERSION; } else { return VZ_BETA1_INSTALL_API_VERSION; @@ -53,75 +44,39 @@ define([], } getComponentApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_COMPONENT_API_VERSION; - } else { - return VZ_BETA1_COMPONENT_API_VERSION; - } + return VZ_ALPHA1_COMPONENT_API_VERSION; } getWorkloadApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_WORKLOAD_API_VERSION; - } else { - return VZ_BETA1_WORKLOAD_API_VERSION; - } + return VZ_ALPHA1_WORKLOAD_API_VERSION; } getApplicationApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_APPLICATION_API_VERSION; - } else { - return VZ_BETA1_APPLICATION_API_VERSION; - } + return VZ_ALPHA1_APPLICATION_API_VERSION; } getMultiClusterApplicationApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_MULTI_CLUSTER_APPLICATION_API_VERSION; - } else { - return VZ_BETA1_MULTI_CLUSTER_APPLICATION_API_VERSION; - } + return VZ_ALPHA1_MULTI_CLUSTER_APPLICATION_API_VERSION; } getProjectApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_PROJECT_API_VERSION; - } else { - return VZ_BETA1_PROJECT_API_VERSION; - } + return VZ_ALPHA1_PROJECT_API_VERSION; } getIngressTraitApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_INGRESS_TRAIT_API_VERSION; - } else { - return VZ_BETA1_INGRESS_TRAIT_API_VERSION; - } + return VZ_ALPHA1_INGRESS_TRAIT_API_VERSION; } getLoggingTraitApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_LOGGING_TRAIT_API_VERSION; - } else { - return VZ_BETA1_LOGGING_TRAIT_API_VERSION; - } + return VZ_ALPHA1_LOGGING_TRAIT_API_VERSION; } getManualScalerTraitApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_MANUAL_SCALER_TRAIT_API_VERSION; - } else { - return VZ_BETA1_MANUAL_SCALER_TRAIT_API_VERSION; - } + return VZ_ALPHA1_MANUAL_SCALER_TRAIT_API_VERSION; } getMetricsTraitApiVersion() { - if (window.api.utils.compareVersions(this.verrazzanoVersion, VZ_BETA1_SWITCH_VERSION) < 0) { - return VZ_ALPHA1_METRICS_TRAIT_API_VERSION; - } else { - return VZ_BETA1_METRICS_TRAIT_API_VERSION; - } + return VZ_ALPHA1_METRICS_TRAIT_API_VERSION; } } diff --git a/webui/src/js/viewModels/domain-code-view.js b/webui/src/js/viewModels/domain-code-view.js index 6db7701a6..28a0e104c 100644 --- a/webui/src/js/viewModels/domain-code-view.js +++ b/webui/src/js/viewModels/domain-code-view.js @@ -55,13 +55,14 @@ function (accUtils, ko, project, K8sDomainScriptGenerator, K8sDomainConfigMapGen this.isConfigMapDisabled = () => { - return this.project.k8sDomain.configMapIsEmpty(); + return this.project.settings.targetDomainLocation.value !== 'mii'; }; this.subviews = [ {id: 'script', name: this.labelMapper('script-title')}, {id: 'domain', name: this.labelMapper('domain-resource-title')}, - {id: 'configMap', name: this.labelMapper('configmap-resource-title'), disabled: this.project.k8sDomain.configMapIsEmpty()} + {id: 'configMap', name: this.labelMapper('configmap-resource-title'), + disabled: this.isConfigMapDisabled()} ]; this.subviewsDP = new ArrayDataProvider(this.subviews, {keyAttributes: 'id'}); diff --git a/webui/src/js/viewModels/vz-application-design-view.js b/webui/src/js/viewModels/vz-application-design-view.js index b5e3fd20b..7a003634a 100644 --- a/webui/src/js/viewModels/vz-application-design-view.js +++ b/webui/src/js/viewModels/vz-application-design-view.js @@ -38,6 +38,15 @@ function (project, accUtils, utils, ko, i18n, BufferingDataProvider, ArrayDataPr this.componentsDataProvider = new ArrayDataProvider(this.components.observable, { keyAttributes: 'name' }); this.hasComponents = ko.computed(() => this.components.observable().length > 0); + // eslint-disable-next-line no-unused-vars + this.disableComponentDeleteButton = (index) => { + return false; + }; + + this.deleteApplicationComponent = (index) => { + this.project.vzApplication.components.removeItemByIndex(index); + }; + this.integerConverter = new ojConverterNumber.IntlNumberConverter({ style: 'decimal', roundingMode: 'HALF_DOWN', diff --git a/webui/src/js/viewModels/vz-component-code-view.js b/webui/src/js/viewModels/vz-component-code-view.js index 951459be0..f5953fd98 100644 --- a/webui/src/js/viewModels/vz-component-code-view.js +++ b/webui/src/js/viewModels/vz-component-code-view.js @@ -55,13 +55,14 @@ function (accUtils, ko, project, VerrazzanoComponentScriptGenerator, VerrazzanoC this.isConfigMapDisabled = () => { - return this.project.vzComponent.configMapIsEmpty(); + return this.project.settings.targetDomainLocation.value !== 'mii'; }; this.subviews = [ {id: 'script', name: this.labelMapper('script-title')}, {id: 'component', name: this.labelMapper('component-resource-title')}, - {id: 'configMap', name: this.labelMapper('configmap-resource-title'), disabled: this.project.vzComponent.configMapIsEmpty()} + {id: 'configMap', name: this.labelMapper('configmap-resource-title'), + disabled: this.isConfigMapDisabled()} ]; this.subviewsDP = new ArrayDataProvider(this.subviews, {keyAttributes: 'id'}); diff --git a/webui/src/js/views/vz-application-design-view.html b/webui/src/js/views/vz-application-design-view.html index 878ed83a9..224b37780 100644 --- a/webui/src/js/views/vz-application-design-view.html +++ b/webui/src/js/views/vz-application-design-view.html @@ -101,6 +101,14 @@
readonly="true" help.instruction="[[labelMapper('component-name-help')]]"> + + + + +
diff --git a/webui/src/js/views/vz-ingress-trait-rule-edit-dialog.html b/webui/src/js/views/vz-ingress-trait-rule-edit-dialog.html index 5933173a2..73a45d7be 100644 --- a/webui/src/js/views/vz-ingress-trait-rule-edit-dialog.html +++ b/webui/src/js/views/vz-ingress-trait-rule-edit-dialog.html @@ -26,23 +26,27 @@