diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 21:42:06 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 21:42:06 +0300 |
commit | 6e4e1050d9dba2b7b2523fdd1768823ab85feef4 (patch) | |
tree | 78be5963ec075d80116a932011d695dd33910b4e /app/assets/javascripts/clusters | |
parent | 1ce776de4ae122aba3f349c02c17cebeaa8ecf07 (diff) |
Add latest changes from gitlab-org/gitlab@13-3-stable-ee
Diffstat (limited to 'app/assets/javascripts/clusters')
15 files changed, 397 insertions, 156 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index 83bdea15e62..92517203972 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -4,23 +4,15 @@ import { GlToast } from '@gitlab/ui'; import AccessorUtilities from '~/lib/utils/accessor'; import PersistentUserCallout from '../persistent_user_callout'; import { s__, sprintf } from '../locale'; -import Flash from '../flash'; +import { deprecatedCreateFlash as Flash } from '../flash'; import Poll from '../lib/utils/poll'; import initSettingsPanels from '../settings_panels'; import eventHub from './event_hub'; -import { - APPLICATION_STATUS, - INGRESS, - INGRESS_DOMAIN_SUFFIX, - CROSSPLANE, - KNATIVE, - FLUENTD, -} from './constants'; +import { APPLICATION_STATUS, CROSSPLANE, KNATIVE, FLUENTD } from './constants'; import ClustersService from './services/clusters_service'; import ClustersStore from './stores/clusters_store'; import Applications from './components/applications.vue'; import RemoveClusterConfirmation from './components/remove_cluster_confirmation.vue'; -import setupToggleButtons from '../toggle_buttons'; import initProjectSelectDropdown from '~/project_select'; import initServerlessSurveyBanner from '~/serverless/survey_banner'; @@ -68,6 +60,7 @@ export default class Clusters { deployBoardsHelpPath, cloudRunHelpPath, clusterId, + ciliumHelpPath, } = document.querySelector('.js-edit-cluster-form').dataset; this.clusterId = clusterId; @@ -84,6 +77,7 @@ export default class Clusters { clustersHelpPath, deployBoardsHelpPath, cloudRunHelpPath, + ciliumHelpPath, ); this.store.setManagePrometheusPath(managePrometheusPath); this.store.updateStatus(clusterStatus); @@ -119,19 +113,11 @@ export default class Clusters { this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason'); this.successApplicationContainer = document.querySelector('.js-cluster-application-notice'); this.tokenField = document.querySelector('.js-cluster-token'); - this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text'); - this.ingressDomainSnippet = - this.ingressDomainHelpText && - this.ingressDomainHelpText.querySelector('.js-ingress-domain-snippet'); initProjectSelectDropdown(); Clusters.initDismissableCallout(); initSettingsPanels(); - const toggleButtonsContainer = document.querySelector('.js-cluster-enable-toggle-area'); - if (toggleButtonsContainer) { - setupToggleButtons(toggleButtonsContainer); - } this.initApplications(clusterType); this.initEnvironments(); @@ -184,6 +170,7 @@ export default class Clusters { providerType: this.state.providerType, preInstalledKnative: this.state.preInstalledKnative, rbac: this.state.rbac, + ciliumHelpPath: this.state.ciliumHelpPath, }, }); }, @@ -329,13 +316,6 @@ export default class Clusters { this.checkForNewInstalls(prevApplicationMap, this.store.state.applications); this.updateContainer(prevStatus, this.store.state.status, this.store.state.statusReason); - if (this.ingressDomainHelpText) { - this.toggleIngressDomainHelpText( - prevApplicationMap[INGRESS], - this.store.state.applications[INGRESS], - ); - } - if (this.store.state.applications[KNATIVE]?.status === APPLICATION_STATUS.INSTALLED) { initServerlessSurveyBanner(); } @@ -507,13 +487,6 @@ export default class Clusters { }); } - toggleIngressDomainHelpText({ externalIp }, { externalIp: newExternalIp }) { - if (externalIp !== newExternalIp) { - this.ingressDomainHelpText.classList.toggle('hide', !newExternalIp); - this.ingressDomainSnippet.textContent = `${newExternalIp}${INGRESS_DOMAIN_SUFFIX}`; - } - } - saveKnativeDomain(data) { const appId = data.id; this.store.updateApplication(appId); diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue index ba6de41e025..c86db28515f 100644 --- a/app/assets/javascripts/clusters/components/application_row.vue +++ b/app/assets/javascripts/clusters/components/application_row.vue @@ -52,6 +52,11 @@ export default { required: false, default: false, }, + installable: { + type: Boolean, + required: false, + default: true, + }, uninstallable: { type: Boolean, required: false, @@ -141,6 +146,7 @@ export default { return ( this.status === APPLICATION_STATUS.NOT_INSTALLABLE || this.status === APPLICATION_STATUS.INSTALLABLE || + this.status === APPLICATION_STATUS.UNINSTALLED || this.isUnknownStatus ); }, @@ -164,14 +170,20 @@ export default { return !this.status || this.isInstalling; }, installButtonDisabled() { + // Applications installed through the management project can + // only be installed through the CI pipeline. Installation should + // be disable in all states. + if (!this.installable) return true; + // Avoid the potential for the real-time data to say APPLICATION_STATUS.INSTALLABLE but // we already made a request to install and are just waiting for the real-time // to sync up. + if (this.isInstalling) return true; + + if (!this.isKnownStatus) return false; + return ( - ((this.status !== APPLICATION_STATUS.INSTALLABLE && - this.status !== APPLICATION_STATUS.ERROR) || - this.isInstalling) && - this.isKnownStatus + this.status !== APPLICATION_STATUS.INSTALLABLE && this.status !== APPLICATION_STATUS.ERROR ); }, installButtonLabel() { @@ -335,7 +347,7 @@ export default { <div> <slot name="description"></slot> </div> - <div v-if="hasError" class="cluster-application-error text-danger prepend-top-10"> + <div v-if="hasError" class="cluster-application-error text-danger gl-mt-3"> <p class="js-cluster-application-general-error-message gl-mb-0"> {{ generalErrorDescription }} </p> diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 214906021ad..039237042ea 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -1,8 +1,6 @@ <script> -import helmInstallIllustration from '@gitlab/svgs/dist/illustrations/kubernetes-installation.svg'; 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 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'; @@ -88,18 +86,13 @@ export default { required: false, default: false, }, + ciliumHelpPath: { + type: String, + required: false, + default: '', + }, }, computed: { - managedAppsLocalTillerEnabled() { - return Boolean(gon.features?.managedAppsLocalTiller); - }, - helmInstalled() { - return ( - this.managedAppsLocalTillerEnabled || - this.applications.helm.status === APPLICATION_STATUS.INSTALLED || - this.applications.helm.status === APPLICATION_STATUS.UPDATED - ); - }, ingressId() { return INGRESS; }, @@ -157,7 +150,6 @@ export default { }, logos: { gitlabLogo, - helmLogo, jupyterhubLogo, kubernetesLogo, certManagerLogo, @@ -167,7 +159,6 @@ export default { elasticStackLogo, fluentdLogo, }, - helmInstallIllustration, }; </script> @@ -175,46 +166,12 @@ export default { <section id="cluster-applications"> <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.`) + s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster.`) }} <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="$options.logos.helmLogo" - :title="applications.helm.title" - :status="applications.helm.status" - :status-reason="applications.helm.statusReason" - :request-status="applications.helm.requestStatus" - :request-reason="applications.helm.requestReason" - :installed="applications.helm.installed" - :install-failed="applications.helm.installFailed" - :uninstallable="applications.helm.uninstallable" - :uninstall-successful="applications.helm.uninstallSuccessful" - :uninstall-failed="applications.helm.uninstallFailed" - class="rounded-top" - title-link="https://docs.helm.sh/" - > - <template #description> - {{ - s__(`ClusterIntegration|Helm streamlines installing - and managing Kubernetes applications. - Tiller runs inside of your Kubernetes Cluster, - and manages releases of your charts.`) - }} - </template> - </application-row> - <div v-show="!helmInstalled" class="cluster-application-warning"> - <div class="svg-container" v-html="$options.helmInstallIllustration"></div> - {{ - s__(`ClusterIntegration|You must first install Helm Tiller before - installing the applications below`) - }} - </div> + <div class="cluster-application-list gl-mt-3"> <application-row :id="ingressId" :logo-url="$options.logos.kubernetesLogo" @@ -232,7 +189,6 @@ export default { :uninstallable="applications.ingress.uninstallable" :uninstall-successful="applications.ingress.uninstallSuccessful" :uninstall-failed="applications.ingress.uninstallFailed" - :disabled="!helmInstalled" :updateable="false" title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/" > @@ -335,7 +291,6 @@ export default { :uninstallable="applications.cert_manager.uninstallable" :uninstall-successful="applications.cert_manager.uninstallSuccessful" :uninstall-failed="applications.cert_manager.uninstallFailed" - :disabled="!helmInstalled" title-link="https://cert-manager.readthedocs.io/en/latest/#" > <template #description> @@ -393,7 +348,6 @@ export default { :uninstallable="applications.prometheus.uninstallable" :uninstall-successful="applications.prometheus.uninstallSuccessful" :uninstall-failed="applications.prometheus.uninstallFailed" - :disabled="!helmInstalled" title-link="https://prometheus.io/docs/introduction/overview/" > <template #description> @@ -433,7 +387,6 @@ export default { :uninstallable="applications.runner.uninstallable" :uninstall-successful="applications.runner.uninstallSuccessful" :uninstall-failed="applications.runner.uninstallFailed" - :disabled="!helmInstalled" title-link="https://docs.gitlab.com/runner/" > <template #description> @@ -459,7 +412,6 @@ export default { :uninstall-successful="applications.crossplane.uninstallSuccessful" :uninstall-failed="applications.crossplane.uninstallFailed" :install-application-request-params="{ stack: applications.crossplane.stack }" - :disabled="!helmInstalled" title-link="https://crossplane.io" > <template #description> @@ -504,7 +456,6 @@ export default { :uninstall-successful="applications.jupyter.uninstallSuccessful" :uninstall-failed="applications.jupyter.uninstallFailed" :install-application-request-params="{ hostname: applications.jupyter.hostname }" - :disabled="!helmInstalled" title-link="https://jupyterhub.readthedocs.io/en/stable/" > <template #description> @@ -570,7 +521,6 @@ export default { :uninstall-successful="applications.knative.uninstallSuccessful" :uninstall-failed="applications.knative.uninstallFailed" :updateable="false" - :disabled="!helmInstalled" v-bind="applications.knative" title-link="https://github.com/knative/docs" > @@ -592,7 +542,7 @@ export default { </p> <knative-domain-editor - v-if="(knative.installed || (helmInstalled && rbac)) && !preInstalledKnative" + v-if="(knative.installed || rbac) && !preInstalledKnative" :knative="knative" :ingress-dns-help-path="ingressDnsHelpPath" @save="saveKnativeDomain" @@ -629,7 +579,6 @@ export default { :uninstallable="applications.elastic_stack.uninstallable" :uninstall-successful="applications.elastic_stack.uninstallSuccessful" :uninstall-failed="applications.elastic_stack.uninstallFailed" - :disabled="!helmInstalled" title-link="https://gitlab.com/gitlab-org/charts/elastic-stack" > <template #description> @@ -663,7 +612,6 @@ export default { :uninstallable="applications.fluentd.uninstallable" :uninstall-successful="applications.fluentd.uninstallSuccessful" :uninstall-failed="applications.fluentd.uninstallFailed" - :disabled="!helmInstalled" :updateable="false" title-link="https://github.com/helm/charts/tree/master/stable/fluentd" > @@ -687,6 +635,39 @@ export default { /> </template> </application-row> + + <div class="gl-mt-7 gl-border-1 gl-border-t-solid gl-border-gray-100"> + <!-- This empty div serves as a separator. The applications below can be externally installed using a cluster-management project. --> + </div> + + <application-row + id="cilium" + :title="applications.cilium.title" + :logo-url="$options.logos.gitlabLogo" + :status="applications.cilium.status" + :status-reason="applications.cilium.statusReason" + :installable="applications.cilium.installable" + :uninstallable="applications.cilium.uninstallable" + :installed="applications.cilium.installed" + :install-failed="applications.cilium.installFailed" + :title-link="ciliumHelpPath" + > + <template #description> + <p data-testid="ciliumDescription"> + <gl-sprintf + :message=" + s__( + 'ClusterIntegration|Protect your clusters with GitLab Container Network Policies by enforcing how pods communicate with each other and other network endpoints. %{linkStart}Learn more about configuring Network Policies here.%{linkEnd}', + ) + " + > + <template #link="{ content }"> + <gl-link :href="ciliumHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </p> + </template> + </application-row> </div> </section> </template> diff --git a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue index 6b99bb09504..c816fc56d7a 100644 --- a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue +++ b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue @@ -1,12 +1,12 @@ <script> -import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui'; +import { GlDeprecatedDropdown, GlDeprecatedDropdownItem, GlIcon } from '@gitlab/ui'; import { s__ } from '../../locale'; export default { name: 'CrossplaneProviderStack', components: { - GlDropdown, - GlDropdownItem, + GlDeprecatedDropdown, + GlDeprecatedDropdownItem, GlIcon, }, props: { @@ -67,17 +67,21 @@ export default { <label> {{ s__('ClusterIntegration|Enabled stack') }} </label> - <gl-dropdown + <gl-deprecated-dropdown :disabled="crossplane.installed" :text="dropdownText" toggle-class="dropdown-menu-toggle gl-field-error-outline" class="w-100" :class="{ 'gl-show-field-errors': validationError }" > - <gl-dropdown-item v-for="stack in stacks" :key="stack.code" @click="selectStack(stack)"> + <gl-deprecated-dropdown-item + v-for="stack in stacks" + :key="stack.code" + @click="selectStack(stack)" + > <span class="ml-1">{{ stack.name }}</span> - </gl-dropdown-item> - </gl-dropdown> + </gl-deprecated-dropdown-item> + </gl-deprecated-dropdown> <span v-if="validationError" class="gl-field-error">{{ validationError }}</span> <p class="form-text text-muted"> {{ s__(`You must select a stack for configuring your cloud provider. Learn more about`) }} diff --git a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue index 20f6210aba8..e6001b11296 100644 --- a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue +++ b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue @@ -1,15 +1,15 @@ <script> -import { __ } from '~/locale'; -import { APPLICATION_STATUS, FLUENTD } from '~/clusters/constants'; import { GlAlert, GlDeprecatedButton, - GlDropdown, - GlDropdownItem, + GlDeprecatedDropdown, + GlDeprecatedDropdownItem, GlFormCheckbox, } from '@gitlab/ui'; -import eventHub from '~/clusters/event_hub'; import { mapValues } from 'lodash'; +import { __ } from '~/locale'; +import { APPLICATION_STATUS, FLUENTD } from '~/clusters/constants'; +import eventHub from '~/clusters/event_hub'; const { UPDATING, UNINSTALLING, INSTALLING, INSTALLED, UPDATED } = APPLICATION_STATUS; @@ -17,8 +17,8 @@ export default { components: { GlAlert, GlDeprecatedButton, - GlDropdown, - GlDropdownItem, + GlDeprecatedDropdown, + GlDeprecatedDropdownItem, GlFormCheckbox, }, props: { @@ -203,15 +203,15 @@ export default { <label for="fluentd-protocol"> <strong>{{ s__('ClusterIntegration|SIEM Protocol') }}</strong> </label> - <gl-dropdown :text="protocolName" class="w-100"> - <gl-dropdown-item + <gl-deprecated-dropdown :text="protocolName" class="w-100"> + <gl-deprecated-dropdown-item v-for="(value, index) in protocols" :key="index" @click="selectProtocol(value.toLowerCase())" > {{ value }} - </gl-dropdown-item> - </gl-dropdown> + </gl-deprecated-dropdown-item> + </gl-deprecated-dropdown> </div> <div class="form-group flex flex-wrap"> <gl-form-checkbox :checked="wafLogEnabled" @input="wafLogChanged"> diff --git a/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue index 87c3225085f..5e8e1a76182 100644 --- a/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue +++ b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue @@ -1,19 +1,19 @@ <script> import { escape } from 'lodash'; -import { s__, __ } from '../../locale'; -import { APPLICATION_STATUS, INGRESS, LOGGING_MODE, BLOCKING_MODE } from '~/clusters/constants'; import { GlAlert, GlSprintf, GlLink, GlToggle, GlDeprecatedButton, - GlDropdown, - GlDropdownItem, + GlDeprecatedDropdown, + GlDeprecatedDropdownItem, GlIcon, } from '@gitlab/ui'; -import eventHub from '~/clusters/event_hub'; import modSecurityLogo from 'images/cluster_app_logos/gitlab.png'; +import { s__, __ } from '../../locale'; +import { APPLICATION_STATUS, INGRESS, LOGGING_MODE, BLOCKING_MODE } from '~/clusters/constants'; +import eventHub from '~/clusters/event_hub'; const { UPDATING, UNINSTALLING, INSTALLING, INSTALLED, UPDATED } = APPLICATION_STATUS; @@ -26,8 +26,8 @@ export default { GlLink, GlToggle, GlDeprecatedButton, - GlDropdown, - GlDropdownItem, + GlDeprecatedDropdown, + GlDeprecatedDropdownItem, GlIcon, }, props: { @@ -221,11 +221,15 @@ export default { </strong> </p> </div> - <gl-dropdown :text="modSecurityModeName" :disabled="saveButtonDisabled"> - <gl-dropdown-item v-for="(mode, key) in modes" :key="key" @click="selectMode(key)"> + <gl-deprecated-dropdown :text="modSecurityModeName" :disabled="saveButtonDisabled"> + <gl-deprecated-dropdown-item + v-for="(mode, key) in modes" + :key="key" + @click="selectMode(key)" + > {{ mode.name }} - </gl-dropdown-item> - </gl-dropdown> + </gl-deprecated-dropdown-item> + </gl-deprecated-dropdown> </div> </div> <div v-if="showButtons" class="mt-3"> diff --git a/app/assets/javascripts/clusters/components/knative_domain_editor.vue b/app/assets/javascripts/clusters/components/knative_domain_editor.vue index ac61cd8e242..1236d2a46c9 100644 --- a/app/assets/javascripts/clusters/components/knative_domain_editor.vue +++ b/app/assets/javascripts/clusters/components/knative_domain_editor.vue @@ -1,8 +1,8 @@ <script> import { - GlDropdown, - GlDropdownDivider, - GlDropdownItem, + GlDeprecatedDropdown, + GlDeprecatedDropdownDivider, + GlDeprecatedDropdownItem, GlLoadingIcon, GlSearchBoxByType, GlSprintf, @@ -20,9 +20,9 @@ export default { LoadingButton, ClipboardButton, GlLoadingIcon, - GlDropdown, - GlDropdownDivider, - GlDropdownItem, + GlDeprecatedDropdown, + GlDeprecatedDropdownDivider, + GlDeprecatedDropdownItem, GlSearchBoxByType, GlSprintf, }, @@ -121,7 +121,7 @@ export default { <strong>{{ s__('ClusterIntegration|Knative Domain Name:') }}</strong> </label> - <gl-dropdown + <gl-deprecated-dropdown v-if="showDomainsDropdown" :text="domainDropdownText" toggle-class="dropdown-menu-toggle" @@ -132,16 +132,16 @@ export default { :placeholder="s__('ClusterIntegration|Search domains')" class="m-2" /> - <gl-dropdown-item + <gl-deprecated-dropdown-item v-for="domain in filteredDomains" :key="domain.id" @click="selectDomain(domain)" > <span class="ml-1">{{ domain.domain }}</span> - </gl-dropdown-item> + </gl-deprecated-dropdown-item> <template v-if="searchQuery"> - <gl-dropdown-divider /> - <gl-dropdown-item key="custom-domain" @click="selectCustomDomain(searchQuery)"> + <gl-deprecated-dropdown-divider /> + <gl-deprecated-dropdown-item key="custom-domain" @click="selectCustomDomain(searchQuery)"> <span class="ml-1"> <gl-sprintf :message="s__('ClusterIntegration|Use %{query}')"> <template #query> @@ -149,9 +149,9 @@ export default { </template> </gl-sprintf> </span> - </gl-dropdown-item> + </gl-deprecated-dropdown-item> </template> - </gl-dropdown> + </gl-deprecated-dropdown> <input v-else diff --git a/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue b/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue index 45f2dd48961..3e3b102f0aa 100644 --- a/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue +++ b/app/assets/javascripts/clusters/components/remove_cluster_confirmation.vue @@ -1,7 +1,7 @@ <script> import { escape } from 'lodash'; +import { GlModal, GlButton, GlDeprecatedButton, GlFormInput, GlSprintf } from '@gitlab/ui'; import SplitButton from '~/vue_shared/components/split_button.vue'; -import { GlModal, GlButton, GlDeprecatedButton, GlFormInput } from '@gitlab/ui'; import { s__, sprintf } from '~/locale'; import csrf from '~/lib/utils/csrf'; @@ -30,6 +30,7 @@ export default { GlButton, GlDeprecatedButton, GlFormInput, + GlSprintf, }, props: { clusterPath: { @@ -67,18 +68,6 @@ export default { ) : s__('ClusterIntegration|You are about to remove your cluster integration.'); }, - warningToBeRemoved() { - return s__(`ClusterIntegration| - This will permanently delete the following resources: - <ul> - <li>All installed applications and related resources</li> - <li>The <code>gitlab-managed-apps</code> namespace</li> - <li>Any project namespaces</li> - <li><code>clusterroles</code></li> - <li><code>clusterrolebindings</code></li> - </ul> - `); - }, confirmationTextLabel() { return sprintf( this.confirmCleanup @@ -118,7 +107,7 @@ export default { </script> <template> - <div> + <div class="gl-display-flex gl-justify-content-end"> <split-button v-if="canCleanupResources" :action-items="$options.splitButtonActionItems" @@ -144,9 +133,29 @@ export default { > <template> <p>{{ warningMessage }}</p> - <div v-if="confirmCleanup" v-html="warningToBeRemoved"></div> + <div v-if="confirmCleanup"> + {{ s__('ClusterIntegration|This will permanently delete the following resources:') }} + <ul> + <li> + {{ s__('ClusterIntegration|All installed applications and related resources') }} + </li> + <li> + <gl-sprintf :message="s__('ClusterIntegration|The %{gitlabNamespace} namespace')"> + <template #gitlabNamespace> + <!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings --> + <code>{{ 'gitlab-managed-apps' }}</code> + </template> + </gl-sprintf> + </li> + <li>{{ s__('ClusterIntegration|Any project namespaces') }}</li> + <!-- eslint-disable @gitlab/vue-require-i18n-strings --> + <li><code>clusterroles</code></li> + <li><code>clusterrolebindings</code></li> + <!-- eslint-enable @gitlab/vue-require-i18n-strings --> + </ul> + </div> <strong v-html="confirmationTextLabel"></strong> - <form ref="form" :action="clusterPath" method="post" class="append-bottom-20"> + <form ref="form" :action="clusterPath" method="post" class="gl-mb-5"> <input ref="method" type="hidden" name="_method" value="delete" /> <input :value="csrfToken" type="hidden" name="authenticity_token" /> <input ref="cleanup" type="hidden" name="cleanup" value="true" /> diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js index 60e179c54eb..e2227c61cee 100644 --- a/app/assets/javascripts/clusters/constants.js +++ b/app/assets/javascripts/clusters/constants.js @@ -25,6 +25,7 @@ export const APPLICATION_STATUS = { UNINSTALL_ERRORED: 'uninstall_errored', ERROR: 'errored', PRE_INSTALLED: 'pre_installed', + UNINSTALLED: 'uninstalled', }; /* diff --git a/app/assets/javascripts/clusters/forms/components/integration_form.vue b/app/assets/javascripts/clusters/forms/components/integration_form.vue new file mode 100644 index 00000000000..53e004b4fc0 --- /dev/null +++ b/app/assets/javascripts/clusters/forms/components/integration_form.vue @@ -0,0 +1,163 @@ +<script> +import { + GlFormGroup, + GlFormInput, + GlToggle, + GlTooltipDirective, + GlSprintf, + GlLink, + GlButton, +} from '@gitlab/ui'; +import { mapState } from 'vuex'; + +export default { + components: { + GlFormGroup, + GlToggle, + GlFormInput, + GlSprintf, + GlLink, + GlButton, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + inject: { + autoDevopsHelpPath: { + type: String, + }, + externalEndpointHelpPath: { + type: String, + }, + }, + data() { + return { + toggleEnabled: true, + envScope: '*', + baseDomainField: '', + externalIp: '', + }; + }, + computed: { + ...mapState([ + 'enabled', + 'editable', + 'environmentScope', + 'baseDomain', + 'applicationIngressExternalIp', + ]), + canSubmit() { + return ( + this.enabled !== this.toggleEnabled || + this.environmentScope !== this.envScope || + this.baseDomain !== this.baseDomainField + ); + }, + }, + mounted() { + this.toggleEnabled = this.enabled; + this.envScope = this.environmentScope; + this.baseDomainField = this.baseDomain; + this.externalIp = this.applicationIngressExternalIp; + }, +}; +</script> + +<template> + <div class="d-flex gl-flex-direction-column"> + <gl-form-group> + <div class="gl-display-flex gl-align-items-center"> + <h4 class="gl-pr-3 gl-m-0">{{ s__('ClusterIntegration|GitLab Integration') }}</h4> + + <div class="js-cluster-enable-toggle-area"> + <gl-toggle + id="toggleCluster" + v-model="toggleEnabled" + v-gl-tooltip:tooltipcontainer + name="cluster[enabled]" + class="gl-mb-0 js-project-feature-toggle" + data-qa-selector="integration_status_toggle" + aria-describedby="toggleCluster" + :disabled="!editable" + :title=" + s__( + 'ClusterIntegration|Enable or disable GitLab\'s connection to your Kubernetes cluster.', + ) + " + /> + </div> + </div> + </gl-form-group> + + <gl-form-group + :label="s__('ClusterIntegration|Environment scope')" + label-size="sm" + label-for="cluster_environment_scope" + :description=" + s__('ClusterIntegration|Choose which of your environments will use this cluster.') + " + > + <gl-form-input + id="cluster_environment_scope" + v-model="envScope" + name="cluster[environment_scope]" + class="col-md-6" + type="text" + /> + </gl-form-group> + + <gl-form-group + :label="s__('ClusterIntegration|Base domain')" + label-size="sm" + label-for="cluster_base_domain" + > + <gl-form-input + id="cluster_base_domain" + v-model="baseDomainField" + name="cluster[base_domain]" + data-qa-selector="base_domain_field" + class="col-md-6" + type="text" + /> + <div class="form-text text-muted inline"> + <gl-sprintf + :message=" + s__( + 'ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. ', + ) + " + > + <template #link="{ content }"> + <gl-link :href="autoDevopsHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + <div v-if="applicationIngressExternalIp" class="js-ingress-domain-help-text inline"> + {{ s__('ClusterIntegration|Alternatively, ') }} + <gl-sprintf :message="s__('ClusterIntegration|%{externalIp}.nip.io')"> + <template #externalIp>{{ externalIp }}</template> + </gl-sprintf> + {{ s__('ClusterIntegration|can be used instead of a custom domain. ') }} + </div> + <gl-sprintf + class="inline" + :message="s__('ClusterIntegration|%{linkStart}More information%{linkEnd}')" + > + <template #link="{ content }"> + <gl-link :href="externalEndpointHelpPath" target="_blank">{{ content }}</gl-link> + </template> + </gl-sprintf> + </div> + </gl-form-group> + <div v-if="editable" class="form group gl-display-flex gl-justify-content-end"> + <gl-button + category="primary" + variant="success" + type="submit" + :disabled="!canSubmit" + :aria-disabled="!canSubmit" + data-qa-selector="save_changes_button" + >{{ s__('ClusterIntegration|Save changes') }}</gl-button + > + </div> + </div> +</template> diff --git a/app/assets/javascripts/clusters/forms/show/index.js b/app/assets/javascripts/clusters/forms/show/index.js new file mode 100644 index 00000000000..47a3016c777 --- /dev/null +++ b/app/assets/javascripts/clusters/forms/show/index.js @@ -0,0 +1,27 @@ +import Vue from 'vue'; +import IntegrationForm from '../components/integration_form.vue'; +import { createStore } from '../stores'; + +export default () => { + const entryPoint = document.querySelector('#js-cluster-integration-form'); + + if (!entryPoint) { + return; + } + + const { autoDevopsHelpPath, externalEndpointHelpPath } = entryPoint.dataset; + + // eslint-disable-next-line no-new + new Vue({ + el: entryPoint, + store: createStore(entryPoint.dataset), + provide: { + autoDevopsHelpPath, + externalEndpointHelpPath, + }, + + render(createElement) { + return createElement(IntegrationForm, {}); + }, + }); +}; diff --git a/app/assets/javascripts/clusters/forms/stores/index.js b/app/assets/javascripts/clusters/forms/stores/index.js new file mode 100644 index 00000000000..ae082c07f26 --- /dev/null +++ b/app/assets/javascripts/clusters/forms/stores/index.js @@ -0,0 +1,12 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import state from './state'; + +Vue.use(Vuex); + +export const createStore = initialState => + new Vuex.Store({ + state: state(initialState), + }); + +export default createStore; diff --git a/app/assets/javascripts/clusters/forms/stores/state.js b/app/assets/javascripts/clusters/forms/stores/state.js new file mode 100644 index 00000000000..2a96590b5e7 --- /dev/null +++ b/app/assets/javascripts/clusters/forms/stores/state.js @@ -0,0 +1,13 @@ +import { parseBoolean } from '../../../lib/utils/common_utils'; + +export default (initialState = {}) => { + return { + enabled: parseBoolean(initialState.enabled), + editable: parseBoolean(initialState.editable), + environmentScope: initialState.environmentScope, + baseDomain: initialState.baseDomain, + applicationIngressExternalIp: initialState.applicationIngressExternalIp, + autoDevopsHelpPath: initialState.autoDevopsHelpPath, + externalEndpointHelpPath: initialState.externalEndpointHelpPath, + }; +}; diff --git a/app/assets/javascripts/clusters/services/application_state_machine.js b/app/assets/javascripts/clusters/services/application_state_machine.js index 6af9b10f12f..683b0e18534 100644 --- a/app/assets/javascripts/clusters/services/application_state_machine.js +++ b/app/assets/javascripts/clusters/services/application_state_machine.js @@ -14,6 +14,7 @@ const { UNINSTALLING, UNINSTALL_ERRORED, PRE_INSTALLED, + UNINSTALLED, } = APPLICATION_STATUS; const applicationStateMachine = { @@ -67,6 +68,9 @@ const applicationStateMachine = { [PRE_INSTALLED]: { target: PRE_INSTALLED, }, + [UNINSTALLED]: { + target: UNINSTALLED, + }, }, }, [NOT_INSTALLABLE]: { @@ -87,9 +91,17 @@ const applicationStateMachine = { [NOT_INSTALLABLE]: { target: NOT_INSTALLABLE, }, - // This is possible in artificial environments for E2E testing [INSTALLED]: { target: INSTALLED, + effects: { + installFailed: false, + }, + }, + [UNINSTALLED]: { + target: UNINSTALLED, + effects: { + installFailed: false, + }, }, }, }, @@ -125,6 +137,15 @@ const applicationStateMachine = { uninstallSuccessful: false, }, }, + [UNINSTALLED]: { + target: UNINSTALLED, + }, + [ERROR]: { + target: INSTALLABLE, + effects: { + installFailed: true, + }, + }, }, }, [PRE_INSTALLED]: { @@ -180,6 +201,19 @@ const applicationStateMachine = { }, }, }, + [UNINSTALLED]: { + on: { + [INSTALLED]: { + target: INSTALLED, + }, + [ERROR]: { + target: INSTALLABLE, + effects: { + installFailed: true, + }, + }, + }, + }, }; /** diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index 9d354e66661..53868b7c02d 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -23,6 +23,7 @@ const applicationInitialState = { status: null, statusReason: null, requestReason: null, + installable: true, installed: false, installFailed: false, uninstallable: false, @@ -114,6 +115,11 @@ export default class ClusterStore { ciliumLogEnabled: null, isEditingSettings: false, }, + cilium: { + ...applicationInitialState, + title: s__('ClusterIntegration|GitLab Container Network Policies'), + installable: false, + }, }, environments: [], fetchingEnvironments: false, @@ -129,6 +135,7 @@ export default class ClusterStore { clustersHelpPath, deployBoardsHelpPath, cloudRunHelpPath, + ciliumHelpPath, ) { this.state.helpPath = helpPath; this.state.ingressHelpPath = ingressHelpPath; @@ -138,6 +145,7 @@ export default class ClusterStore { this.state.clustersHelpPath = clustersHelpPath; this.state.deployBoardsHelpPath = deployBoardsHelpPath; this.state.cloudRunHelpPath = cloudRunHelpPath; + this.state.ciliumHelpPath = ciliumHelpPath; } setManagePrometheusPath(managePrometheusPath) { |