diff options
Diffstat (limited to 'app/assets/javascripts/clusters')
8 files changed, 353 insertions, 267 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index d8bfbdb458c..f15efb2fdeb 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -468,6 +468,11 @@ export default class Clusters { return; } + if (appId === KNATIVE && !params.hostname && !params.pages_domain_id) { + reject(s__('ClusterIntegration|You must specify a domain before you can install Knative.')); + return; + } + resolve(); }); } @@ -520,6 +525,7 @@ export default class Clusters { this.store.updateAppProperty(appId, 'isEditingDomain', true); this.store.updateAppProperty(appId, 'hostname', domain); this.store.updateAppProperty(appId, 'pagesDomain', domainId ? { id: domainId, domain } : null); + this.store.updateAppProperty(appId, 'validationError', null); } setCrossplaneProviderStack(data) { diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue index 53bc079a4e1..ba6de41e025 100644 --- a/app/assets/javascripts/clusters/components/application_row.vue +++ b/app/assets/javascripts/clusters/components/application_row.vue @@ -1,23 +1,24 @@ <script> -/* eslint-disable vue/require-default-prop */ -/* eslint-disable @gitlab/vue-require-i18n-strings */ -import { GlLink, GlModalDirective } from '@gitlab/ui'; +import { GlLink, GlModalDirective, GlSprintf } from '@gitlab/ui'; import { s__, __, sprintf } from '~/locale'; import eventHub from '../event_hub'; import identicon from '../../vue_shared/components/identicon.vue'; import loadingButton from '../../vue_shared/components/loading_button.vue'; import UninstallApplicationButton from './uninstall_application_button.vue'; import UninstallApplicationConfirmationModal from './uninstall_application_confirmation_modal.vue'; +import UpdateApplicationConfirmationModal from './update_application_confirmation_modal.vue'; -import { APPLICATION_STATUS } from '../constants'; +import { APPLICATION_STATUS, ELASTIC_STACK } from '../constants'; export default { components: { loadingButton, identicon, GlLink, + GlSprintf, UninstallApplicationButton, UninstallApplicationConfirmationModal, + UpdateApplicationConfirmationModal, }, directives: { GlModalDirective, @@ -34,15 +35,17 @@ export default { titleLink: { type: String, required: false, + default: '', }, manageLink: { type: String, required: false, + default: '', }, logoUrl: { type: String, required: false, - default: null, + default: '', }, disabled: { type: Boolean, @@ -57,14 +60,17 @@ export default { status: { type: String, required: false, + default: '', }, statusReason: { type: String, required: false, + default: '', }, requestReason: { type: String, required: false, + default: '', }, installed: { type: Boolean, @@ -76,17 +82,15 @@ export default { required: false, default: false, }, - installedVia: { - type: String, - required: false, - }, version: { type: String, required: false, + default: '', }, chartRepo: { type: String, required: false, + default: '', }, updateAvailable: { type: Boolean, @@ -204,15 +208,6 @@ export default { return sprintf(errorDescription, { title: this.title }); }, - versionLabel() { - if (this.updateFailed) { - return __('Update failed'); - } else if (this.isUpdating) { - return __('Updating'); - } - - return this.updateSuccessful ? __('Updated to') : __('Updated'); - }, updateFailureDescription() { return s__('ClusterIntegration|Update failed. Please check the logs and try again.'); }, @@ -233,6 +228,17 @@ export default { return label; }, + updatingNeedsConfirmation() { + if (this.version) { + const majorVersion = parseInt(this.version.split('.')[0], 10); + + if (!Number.isNaN(majorVersion)) { + return this.id === ELASTIC_STACK && majorVersion < 3; + } + } + + return false; + }, isUpdating() { // Since upgrading is handled asynchronously on the backend we need this check to prevent any delay on the frontend return this.status === APPLICATION_STATUS.UPDATING; @@ -248,6 +254,12 @@ export default { title: this.title, }); }, + updateModalId() { + return `update-${this.id}`; + }, + uninstallModalId() { + return `uninstall-${this.id}`; + }, }, watch: { updateSuccessful(updateSuccessful) { @@ -263,12 +275,16 @@ export default { }, methods: { installClicked() { + if (this.disabled || this.installButtonDisabled) return; + eventHub.$emit('installApplication', { id: this.id, params: this.installApplicationRequestParams, }); }, - updateClicked() { + updateConfirmed() { + if (this.isUpdating) return; + eventHub.$emit('updateApplication', { id: this.id, params: this.installApplicationRequestParams, @@ -294,7 +310,7 @@ export default { :data-qa-selector="id" > <div class="gl-responsive-table-row-layout" role="row"> - <div class="table-section append-right-8 section-align-top" role="gridcell"> + <div class="table-section gl-mr-3 section-align-top" role="gridcell"> <img v-if="hasLogo" :src="logoUrl" @@ -315,14 +331,12 @@ export default { > <span v-else class="js-cluster-application-title">{{ title }}</span> </strong> - <span - v-if="installedVia" - class="js-cluster-application-installed-via" - v-html="installedVia" - ></span> - <slot name="description"></slot> + <slot name="installedVia"></slot> + <div> + <slot name="description"></slot> + </div> <div v-if="hasError" class="cluster-application-error text-danger prepend-top-10"> - <p class="js-cluster-application-general-error-message append-bottom-0"> + <p class="js-cluster-application-general-error-message gl-mb-0"> {{ generalErrorDescription }} </p> <ul v-if="statusReason || requestReason"> @@ -340,14 +354,20 @@ export default { v-if="shouldShowUpdateDetails" class="form-text text-muted label p-0 js-cluster-application-update-details" > - {{ versionLabel }} - <gl-link - v-if="updateSuccessful" - :href="chartRepo" - target="_blank" - class="js-cluster-application-update-version" - >chart v{{ version }}</gl-link - > + <template v-if="updateFailed">{{ __('Update failed') }}</template> + <template v-else-if="isUpdating">{{ __('Updating') }}</template> + <template v-else> + <gl-sprintf :message="__('Updated to %{linkStart}chart v%{linkEnd}')"> + <template #link="{ content }"> + <gl-link + :href="chartRepo" + target="_blank" + class="js-cluster-application-update-version" + >{{ content }}{{ version }}</gl-link + > + </template> + </gl-sprintf> + </template> </div> <div @@ -356,14 +376,36 @@ export default { > {{ updateFailureDescription }} </div> - <loading-button - v-if="updateAvailable || updateFailed || isUpdating" - class="btn btn-primary js-cluster-application-update-button mt-2" - :loading="isUpdating" - :disabled="isUpdating" - :label="updateButtonLabel" - @click="updateClicked" - /> + <template v-if="updateAvailable || updateFailed || isUpdating"> + <template v-if="updatingNeedsConfirmation"> + <loading-button + v-gl-modal-directive="updateModalId" + class="btn btn-primary js-cluster-application-update-button mt-2" + :loading="isUpdating" + :disabled="isUpdating" + :label="updateButtonLabel" + data-qa-selector="update_button_with_confirmation" + :data-qa-application="id" + /> + + <update-application-confirmation-modal + :application="id" + :application-title="title" + @confirm="updateConfirmed()" + /> + </template> + + <loading-button + v-else + class="btn btn-primary js-cluster-application-update-button mt-2" + :loading="isUpdating" + :disabled="isUpdating" + :label="updateButtonLabel" + data-qa-selector="update_button" + :data-qa-application="id" + @click="updateConfirmed" + /> + </template> </div> </div> <div @@ -389,7 +431,7 @@ export default { /> <uninstall-application-button v-if="displayUninstallButton" - v-gl-modal-directive="'uninstall-' + id" + v-gl-modal-directive="uninstallModalId" :status="status" data-qa-selector="uninstall_button" :data-qa-application="id" diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index f11502a7dde..214906021ad 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -1,21 +1,16 @@ <script> -import { escape } from 'lodash'; import helmInstallIllustration from '@gitlab/svgs/dist/illustrations/kubernetes-installation.svg'; -import { GlLoadingIcon } from '@gitlab/ui'; -import elasticsearchLogo from 'images/cluster_app_logos/elasticsearch.png'; +import { GlLoadingIcon, GlSprintf, GlLink } from '@gitlab/ui'; import gitlabLogo from 'images/cluster_app_logos/gitlab.png'; import helmLogo from 'images/cluster_app_logos/helm.png'; -import jeagerLogo from 'images/cluster_app_logos/jeager.png'; import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png'; import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png'; import certManagerLogo from 'images/cluster_app_logos/cert_manager.png'; import crossplaneLogo from 'images/cluster_app_logos/crossplane.png'; import knativeLogo from 'images/cluster_app_logos/knative.png'; -import meltanoLogo from 'images/cluster_app_logos/meltano.png'; import prometheusLogo from 'images/cluster_app_logos/prometheus.png'; import elasticStackLogo from 'images/cluster_app_logos/elastic_stack.png'; import fluentdLogo from 'images/cluster_app_logos/fluentd.png'; -import { s__, sprintf } from '../../locale'; import applicationRow from './application_row.vue'; import clipboardButton from '../../vue_shared/components/clipboard_button.vue'; import KnativeDomainEditor from './knative_domain_editor.vue'; @@ -30,6 +25,8 @@ export default { applicationRow, clipboardButton, GlLoadingIcon, + GlSprintf, + GlLink, KnativeDomainEditor, CrossplaneProviderStack, IngressModsecuritySettings, @@ -92,25 +89,7 @@ export default { default: false, }, }, - data: () => ({ - elasticsearchLogo, - gitlabLogo, - helmLogo, - jeagerLogo, - jupyterhubLogo, - kubernetesLogo, - certManagerLogo, - crossplaneLogo, - knativeLogo, - meltanoLogo, - prometheusLogo, - elasticStackLogo, - fluentdLogo, - }), computed: { - isProjectCluster() { - return this.type === CLUSTER_TYPE.PROJECT; - }, managedAppsLocalTillerEnabled() { return Boolean(gon.features?.managedAppsLocalTiller); }, @@ -133,84 +112,12 @@ export default { certManagerInstalled() { return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED; }, - crossplaneInstalled() { - return this.applications.crossplane.status === APPLICATION_STATUS.INSTALLED; - }, - ingressDescription() { - return sprintf( - escape( - s__( - `ClusterIntegration|Installing Ingress may incur additional costs. Learn more about %{pricingLink}.`, - ), - ), - { - pricingLink: `<a href="https://cloud.google.com/compute/pricing#lb" - target="_blank" rel="noopener noreferrer"> - ${escape(s__('ClusterIntegration|pricing'))}</a>`, - }, - false, - ); - }, - certManagerDescription() { - return sprintf( - escape( - s__( - `ClusterIntegration|Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. - Installing Cert-Manager on your cluster will issue a certificate by %{letsEncrypt} and ensure that certificates - are valid and up-to-date.`, - ), - ), - { - letsEncrypt: `<a href="https://letsencrypt.org/" - target="_blank" rel="noopener noreferrer"> - ${escape(s__("ClusterIntegration|Let's Encrypt"))}</a>`, - }, - false, - ); - }, - crossplaneDescription() { - return sprintf( - escape( - s__( - `ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{kubectl} or %{gitlabIntegrationLink}. -Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on.`, - ), - ), - { - gitlabIntegrationLink: `<a href="https://docs.gitlab.com/ee/user/clusters/applications.html#crossplane" - target="_blank" rel="noopener noreferrer"> - ${escape(s__('ClusterIntegration|Gitlab Integration'))}</a>`, - kubectl: `<code>kubectl</code>`, - }, - false, - ); - }, - - prometheusDescription() { - return sprintf( - escape( - s__( - `ClusterIntegration|Prometheus is an open-source monitoring system - with %{gitlabIntegrationLink} to monitor deployed applications.`, - ), - ), - { - gitlabIntegrationLink: `<a href="https://docs.gitlab.com/ce/user/project/integrations/prometheus.html" - target="_blank" rel="noopener noreferrer"> - ${escape(s__('ClusterIntegration|GitLab Integration'))}</a>`, - }, - false, - ); - }, jupyterInstalled() { return this.applications.jupyter.status === APPLICATION_STATUS.INSTALLED; }, jupyterHostname() { return this.applications.jupyter.hostname; }, - elasticStackInstalled() { - return this.applications.elastic_stack.status === APPLICATION_STATUS.INSTALLED; - }, knative() { return this.applications.knative; }, @@ -220,29 +127,10 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity cloudRun() { return this.providerType === PROVIDER_TYPE.GCP && this.preInstalledKnative; }, - installedVia() { - if (this.cloudRun) { - return sprintf( - escape(s__(`ClusterIntegration|installed via %{installed_via}`)), - { - installed_via: `<a href="${ - this.cloudRunHelpPath - }" target="_blank" rel="noopener noreferrer">${escape( - s__('ClusterIntegration|Cloud Run'), - )}</a>`, - }, - false, - ); - } - return null; - }, ingress() { return this.applications.ingress; }, }, - created() { - this.helmInstallIllustration = helmInstallIllustration; - }, methods: { saveKnativeDomain() { eventHub.$emit('saveKnativeDomain', { @@ -267,24 +155,37 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity }); }, }, + logos: { + gitlabLogo, + helmLogo, + jupyterhubLogo, + kubernetesLogo, + certManagerLogo, + crossplaneLogo, + knativeLogo, + prometheusLogo, + elasticStackLogo, + fluentdLogo, + }, + helmInstallIllustration, }; </script> <template> <section id="cluster-applications"> - <p class="append-bottom-0"> + <p class="gl-mb-0"> {{ s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster. Helm Tiller is required to install any of the following applications.`) }} - <a :href="helpPath">{{ __('More information') }}</a> + <gl-link :href="helpPath">{{ __('More information') }}</gl-link> </p> <div class="cluster-application-list prepend-top-10"> <application-row v-if="!managedAppsLocalTillerEnabled" id="helm" - :logo-url="helmLogo" + :logo-url="$options.logos.helmLogo" :title="applications.helm.title" :status="applications.helm.status" :status-reason="applications.helm.statusReason" @@ -298,17 +199,17 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity class="rounded-top" title-link="https://docs.helm.sh/" > - <div slot="description"> + <template #description> {{ s__(`ClusterIntegration|Helm streamlines installing and managing Kubernetes applications. Tiller runs inside of your Kubernetes Cluster, and manages releases of your charts.`) }} - </div> + </template> </application-row> <div v-show="!helmInstalled" class="cluster-application-warning"> - <div class="svg-container" v-html="helmInstallIllustration"></div> + <div class="svg-container" v-html="$options.helmInstallIllustration"></div> {{ s__(`ClusterIntegration|You must first install Helm Tiller before installing the applications below`) @@ -316,7 +217,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity </div> <application-row :id="ingressId" - :logo-url="kubernetesLogo" + :logo-url="$options.logos.kubernetesLogo" :title="applications.ingress.title" :status="applications.ingress.status" :status-reason="applications.ingress.statusReason" @@ -335,7 +236,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :updateable="false" title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/" > - <div slot="description"> + <template #description> <p> {{ s__(`ClusterIntegration|Ingress gives you a way to route @@ -352,27 +253,29 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity <template v-if="ingressInstalled"> <div class="form-group"> <label for="ingress-endpoint">{{ s__('ClusterIntegration|Ingress Endpoint') }}</label> - <div v-if="ingressExternalEndpoint" class="input-group"> - <input - id="ingress-endpoint" - :value="ingressExternalEndpoint" - type="text" - class="form-control js-endpoint" - readonly - /> - <span class="input-group-append"> - <clipboard-button - :text="ingressExternalEndpoint" - :title="s__('ClusterIntegration|Copy Ingress Endpoint')" - class="input-group-text js-clipboard-btn" + <div class="input-group"> + <template v-if="ingressExternalEndpoint"> + <input + id="ingress-endpoint" + :value="ingressExternalEndpoint" + type="text" + class="form-control js-endpoint" + readonly /> - </span> - </div> - <div v-else class="input-group"> - <input type="text" class="form-control js-endpoint" readonly /> - <gl-loading-icon - class="position-absolute align-self-center ml-2 js-ingress-ip-loading-icon" - /> + <span class="input-group-append"> + <clipboard-button + :text="ingressExternalEndpoint" + :title="s__('ClusterIntegration|Copy Ingress Endpoint')" + class="input-group-text js-clipboard-btn" + /> + </span> + </template> + <template v-else> + <input type="text" class="form-control js-endpoint" readonly /> + <gl-loading-icon + class="position-absolute align-self-center ml-2 js-ingress-ip-loading-icon" + /> + </template> </div> <p class="form-text text-muted"> {{ @@ -380,9 +283,9 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity generated endpoint in order to access your application after it has been deployed.`) }} - <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> + <gl-link :href="ingressDnsHelpPath" target="_blank"> {{ __('More information') }} - </a> + </gl-link> </p> </div> @@ -392,21 +295,35 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity the process of being assigned. Please check your Kubernetes cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }} - <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> + <gl-link :href="ingressDnsHelpPath" target="_blank"> {{ __('More information') }} - </a> + </gl-link> </p> </template> - <template v-if="!ingressInstalled"> + <template v-else> <div class="bs-callout bs-callout-info"> - <strong v-html="ingressDescription"></strong> + <strong data-testid="ingressCostWarning"> + <gl-sprintf + :message=" + s__( + 'ClusterIntegration|Installing Ingress may incur additional costs. Learn more about %{linkStart}pricing%{linkEnd}.', + ) + " + > + <template #link="{ content }"> + <gl-link href="https://cloud.google.com/compute/pricing#lb" target="_blank">{{ + content + }}</gl-link> + </template> + </gl-sprintf> + </strong> </div> </template> - </div> + </template> </application-row> <application-row id="cert_manager" - :logo-url="certManagerLogo" + :logo-url="$options.logos.certManagerLogo" :title="applications.cert_manager.title" :status="applications.cert_manager.status" :status-reason="applications.cert_manager.statusReason" @@ -421,40 +338,50 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :disabled="!helmInstalled" title-link="https://cert-manager.readthedocs.io/en/latest/#" > - <template> - <div slot="description"> - <p v-html="certManagerDescription"></p> - <div class="form-group"> - <label for="cert-manager-issuer-email"> - {{ s__('ClusterIntegration|Issuer Email') }} - </label> - <div class="input-group"> - <input - v-model="applications.cert_manager.email" - :readonly="certManagerInstalled" - type="text" - class="form-control js-email" - /> - </div> - <p class="form-text text-muted"> - {{ - s__(`ClusterIntegration|Issuers represent a certificate authority. - You must provide an email address for your Issuer. `) - }} - <a - href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email" - target="_blank" - rel="noopener noreferrer" - >{{ __('More information') }}</a - > - </p> + <template #description> + <p data-testid="certManagerDescription"> + <gl-sprintf + :message=" + s__(`ClusterIntegration|Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. + Installing Cert-Manager on your cluster will issue a certificate by %{linkStart}Let's Encrypt%{linkEnd} and ensure that certificates + are valid and up-to-date.`) + " + > + <template #link="{ content }"> + <gl-link href="https://letsencrypt.org/" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </p> + <div class="form-group"> + <label for="cert-manager-issuer-email"> + {{ s__('ClusterIntegration|Issuer Email') }} + </label> + <div class="input-group"> + <input + id="cert-manager-issuer-email" + v-model="applications.cert_manager.email" + :readonly="certManagerInstalled" + type="text" + class="form-control js-email" + /> </div> + <p class="form-text text-muted"> + {{ + s__(`ClusterIntegration|Issuers represent a certificate authority. + You must provide an email address for your Issuer.`) + }} + <gl-link + href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email" + target="_blank" + >{{ __('More information') }}</gl-link + > + </p> </div> </template> </application-row> <application-row id="prometheus" - :logo-url="prometheusLogo" + :logo-url="$options.logos.prometheusLogo" :title="applications.prometheus.title" :manage-link="managePrometheusPath" :status="applications.prometheus.status" @@ -469,11 +396,28 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :disabled="!helmInstalled" title-link="https://prometheus.io/docs/introduction/overview/" > - <div slot="description" v-html="prometheusDescription"></div> + <template #description> + <span data-testid="prometheusDescription"> + <gl-sprintf + :message=" + s__(`ClusterIntegration|Prometheus is an open-source monitoring system + with %{linkStart}GitLab Integration%{linkEnd} to monitor deployed applications.`) + " + > + <template #link="{ content }"> + <gl-link + href="https://docs.gitlab.com/ce/user/project/integrations/prometheus.html" + target="_blank" + >{{ content }}</gl-link + > + </template> + </gl-sprintf> + </span> + </template> </application-row> <application-row id="runner" - :logo-url="gitlabLogo" + :logo-url="$options.logos.gitlabLogo" :title="applications.runner.title" :status="applications.runner.status" :status-reason="applications.runner.statusReason" @@ -492,18 +436,18 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :disabled="!helmInstalled" title-link="https://docs.gitlab.com/runner/" > - <div slot="description"> + <template #description> {{ s__(`ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production.`) }} - </div> + </template> </application-row> <application-row id="crossplane" - :logo-url="crossplaneLogo" + :logo-url="$options.logos.crossplaneLogo" :title="applications.crossplane.title" :status="applications.crossplane.status" :status-reason="applications.crossplane.statusReason" @@ -518,19 +462,37 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :disabled="!helmInstalled" title-link="https://crossplane.io" > - <template> - <div slot="description"> - <p v-html="crossplaneDescription"></p> - <div class="form-group"> - <CrossplaneProviderStack :crossplane="crossplane" @set="setCrossplaneProviderStack" /> - </div> + <template #description> + <p data-testid="crossplaneDescription"> + <gl-sprintf + :message=" + s__( + `ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{codeStart}kubectl%{codeEnd} or %{linkStart}GitLab Integration%{linkEnd}. + Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on.`, + ) + " + > + <template #code="{content}"> + <code>{{ content }}</code> + </template> + <template #link="{ content }"> + <gl-link + href="https://docs.gitlab.com/ee/user/clusters/applications.html#crossplane" + target="_blank" + >{{ content }}</gl-link + > + </template> + </gl-sprintf> + </p> + <div class="form-group"> + <CrossplaneProviderStack :crossplane="crossplane" @set="setCrossplaneProviderStack" /> </div> </template> </application-row> <application-row id="jupyter" - :logo-url="jupyterhubLogo" + :logo-url="$options.logos.jupyterhubLogo" :title="applications.jupyter.title" :status="applications.jupyter.status" :status-reason="applications.jupyter.statusReason" @@ -545,7 +507,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :disabled="!helmInstalled" title-link="https://jupyterhub.readthedocs.io/en/stable/" > - <div slot="description"> + <template #description> <p> {{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns, @@ -562,6 +524,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity <div class="input-group"> <input + id="jupyter-hostname" v-model="applications.jupyter.hostname" :readonly="jupyterInstalled" type="text" @@ -581,17 +544,17 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity s__(`ClusterIntegration|Replace this with your own hostname if you want. If you do so, point hostname to Ingress IP Address from above.`) }} - <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer"> + <gl-link :href="ingressDnsHelpPath" target="_blank"> {{ __('More information') }} - </a> + </gl-link> </p> </div> </template> - </div> + </template> </application-row> <application-row id="knative" - :logo-url="knativeLogo" + :logo-url="$options.logos.knativeLogo" :title="applications.knative.title" :status="applications.knative.status" :status-reason="applications.knative.statusReason" @@ -603,7 +566,6 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity hostname: applications.knative.hostname, pages_domain_id: applications.knative.pagesDomain && applications.knative.pagesDomain.id, }" - :installed-via="installedVia" :uninstallable="applications.knative.uninstallable" :uninstall-successful="applications.knative.uninstallSuccessful" :uninstall-failed="applications.knative.uninstallFailed" @@ -612,19 +574,14 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity v-bind="applications.knative" title-link="https://github.com/knative/docs" > - <div slot="description"> - <span v-if="!rbac"> - <p v-if="!rbac" class="rbac-notice bs-callout bs-callout-info append-bottom-0"> - {{ - s__(`ClusterIntegration|You must have an RBAC-enabled cluster - to install Knative.`) - }} - <a :href="helpPath" target="_blank" rel="noopener noreferrer"> - {{ __('More information') }} - </a> - </p> - <br /> - </span> + <template #description> + <p v-if="!rbac" class="rbac-notice bs-callout bs-callout-info"> + {{ + s__(`ClusterIntegration|You must have an RBAC-enabled cluster + to install Knative.`) + }} + <gl-link :href="helpPath" target="_blank">{{ __('More information') }}</gl-link> + </p> <p> {{ s__(`ClusterIntegration|Knative extends Kubernetes to provide @@ -641,11 +598,22 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity @save="saveKnativeDomain" @set="setKnativeDomain" /> - </div> + </template> + <template v-if="cloudRun" #installedVia> + <span data-testid="installedVia"> + <gl-sprintf + :message="s__('ClusterIntegration|installed via %{linkStart}Cloud Run%{linkEnd}')" + > + <template #link="{ content }"> + <gl-link :href="cloudRunHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </span> + </template> </application-row> <application-row id="elastic_stack" - :logo-url="elasticStackLogo" + :logo-url="$options.logos.elasticStackLogo" :title="applications.elastic_stack.title" :status="applications.elastic_stack.status" :status-reason="applications.elastic_stack.statusReason" @@ -664,7 +632,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :disabled="!helmInstalled" title-link="https://gitlab.com/gitlab-org/charts/elastic-stack" > - <div slot="description"> + <template #description> <p> {{ s__( @@ -672,12 +640,12 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity ) }} </p> - </div> + </template> </application-row> <application-row id="fluentd" - :logo-url="fluentdLogo" + :logo-url="$options.logos.fluentdLogo" :title="applications.fluentd.title" :status="applications.fluentd.status" :status-reason="applications.fluentd.statusReason" @@ -699,7 +667,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :updateable="false" title-link="https://github.com/helm/charts/tree/master/stable/fluentd" > - <div slot="description"> + <template #description> <p> {{ s__( @@ -717,7 +685,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity :status="applications.fluentd.status" :update-failed="applications.fluentd.updateFailed" /> - </div> + </template> </application-row> </div> </section> diff --git a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue index 1884b501a20..20f6210aba8 100644 --- a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue +++ b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue @@ -215,10 +215,10 @@ export default { </div> <div class="form-group flex flex-wrap"> <gl-form-checkbox :checked="wafLogEnabled" @input="wafLogChanged"> - <strong>{{ s__('ClusterIntegration|Send ModSecurity Logs') }}</strong> + <strong>{{ s__('ClusterIntegration|Send Web Application Firewall Logs') }}</strong> </gl-form-checkbox> <gl-form-checkbox :checked="ciliumLogEnabled" @input="ciliumLogChanged"> - <strong>{{ s__('ClusterIntegration|Send Cilium Logs') }}</strong> + <strong>{{ s__('ClusterIntegration|Send Container Network Policies Logs') }}</strong> </gl-form-checkbox> </div> <div v-if="showButtons" class="mt-3"> diff --git a/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue index c2f963f0b34..54f5468bdd0 100644 --- a/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue +++ b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue @@ -13,12 +13,12 @@ import { GlIcon, } from '@gitlab/ui'; import eventHub from '~/clusters/event_hub'; -import modSecurityLogo from 'images/cluster_app_logos/modsecurity.png'; +import modSecurityLogo from 'images/cluster_app_logos/gitlab.png'; const { UPDATING, UNINSTALLING, INSTALLING, INSTALLED, UPDATED } = APPLICATION_STATUS; export default { - title: 'ModSecurity Web Application Firewall', + title: __('Web Application Firewall'), modsecurityUrl: 'https://modsecurity.org/about.html', components: { GlAlert, @@ -168,7 +168,7 @@ export default { }} </gl-alert> <div class="gl-responsive-table-row-layout" role="row"> - <div class="table-section append-right-8 section-align-top" role="gridcell"> + <div class="table-section gl-mr-3 section-align-top" role="gridcell"> <img :src="modSecurityLogo" :alt="`${$options.title} logo`" diff --git a/app/assets/javascripts/clusters/components/knative_domain_editor.vue b/app/assets/javascripts/clusters/components/knative_domain_editor.vue index 8136704d13b..ac61cd8e242 100644 --- a/app/assets/javascripts/clusters/components/knative_domain_editor.vue +++ b/app/assets/javascripts/clusters/components/knative_domain_editor.vue @@ -82,6 +82,9 @@ export default { showDomainsDropdown() { return this.availableDomains.length > 0; }, + validationError() { + return this.knative.validationError; + }, }, watch: { knativeUpdateSuccessful(updateSuccessful) { @@ -157,6 +160,8 @@ export default { type="text" class="form-control js-knative-domainname" /> + + <span v-if="validationError" class="gl-field-error">{{ validationError }}</span> </div> <template v-if="knativeInstalled"> diff --git a/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue b/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue index 271f9f74838..c5375cbfbdc 100644 --- a/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue +++ b/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue @@ -147,7 +147,7 @@ export default { ) }}</span> </template> - <template slot="modal-footer"> + <template #modal-footer> <gl-deprecated-button variant="secondary" @click="handleCancel">{{ s__('Cancel') }}</gl-deprecated-button> diff --git a/app/assets/javascripts/clusters/components/update_application_confirmation_modal.vue b/app/assets/javascripts/clusters/components/update_application_confirmation_modal.vue new file mode 100644 index 00000000000..04aa28e9b74 --- /dev/null +++ b/app/assets/javascripts/clusters/components/update_application_confirmation_modal.vue @@ -0,0 +1,65 @@ +<script> +import { GlModal } from '@gitlab/ui'; +import { sprintf, s__ } from '~/locale'; +import { ELASTIC_STACK } from '../constants'; + +const CUSTOM_APP_WARNING_TEXT = { + [ELASTIC_STACK]: s__( + 'ClusterIntegration|Your Elasticsearch cluster will be re-created during this upgrade. Your logs will be re-indexed, and you will lose historical logs from hosts terminated in the last 30 days.', + ), +}; + +export default { + components: { + GlModal, + }, + props: { + application: { + type: String, + required: true, + }, + applicationTitle: { + type: String, + required: true, + }, + }, + computed: { + title() { + return sprintf(s__('ClusterIntegration|Update %{appTitle}'), { + appTitle: this.applicationTitle, + }); + }, + warningText() { + return sprintf( + s__('ClusterIntegration|You are about to update %{appTitle} on your cluster.'), + { + appTitle: this.applicationTitle, + }, + ); + }, + customAppWarningText() { + return CUSTOM_APP_WARNING_TEXT[this.application]; + }, + modalId() { + return `update-${this.application}`; + }, + }, + methods: { + confirmUpdate() { + this.$emit('confirm'); + }, + }, +}; +</script> +<template> + <gl-modal + ok-variant="danger" + cancel-variant="light" + :ok-title="title" + :modal-id="modalId" + :title="title" + @ok="confirmUpdate()" + > + {{ warningText }} <span v-html="customAppWarningText"></span> + </gl-modal> +</template> |