Improve cluster apps installation flow
BIN
app/assets/images/cluster_app_logos/elasticsearch.png
Normal file
After Width: | Height: | Size: 796 B |
BIN
app/assets/images/cluster_app_logos/gitlab.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/assets/images/cluster_app_logos/helm.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/assets/images/cluster_app_logos/jeager.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
app/assets/images/cluster_app_logos/jupyterhub.png
Normal file
After Width: | Height: | Size: 895 B |
BIN
app/assets/images/cluster_app_logos/kubernetes.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/assets/images/cluster_app_logos/meltano.png
Normal file
After Width: | Height: | Size: 580 B |
BIN
app/assets/images/cluster_app_logos/prometheus.png
Normal file
After Width: | Height: | Size: 923 B |
|
@ -2,6 +2,7 @@
|
|||
/* eslint-disable vue/require-default-prop */
|
||||
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 {
|
||||
APPLICATION_STATUS,
|
||||
|
@ -13,6 +14,7 @@
|
|||
export default {
|
||||
components: {
|
||||
loadingButton,
|
||||
identicon,
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
|
@ -31,6 +33,16 @@
|
|||
type: String,
|
||||
required: false,
|
||||
},
|
||||
logoUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -60,6 +72,18 @@
|
|||
isKnownStatus() {
|
||||
return Object.values(APPLICATION_STATUS).includes(this.status);
|
||||
},
|
||||
isInstalled() {
|
||||
return (
|
||||
this.status === APPLICATION_STATUS.INSTALLED || this.status === APPLICATION_STATUS.UPDATED
|
||||
);
|
||||
},
|
||||
hasLogo() {
|
||||
return !!this.logoUrl;
|
||||
},
|
||||
identiconId() {
|
||||
// generate a deterministic integer id for the identicon background
|
||||
return this.id.charCodeAt(0);
|
||||
},
|
||||
rowJsClass() {
|
||||
return `js-cluster-application-row-${this.id}`;
|
||||
},
|
||||
|
@ -128,73 +152,61 @@
|
|||
|
||||
<template>
|
||||
<div
|
||||
:class="rowJsClass"
|
||||
class="gl-responsive-table-row gl-responsive-table-row-col-span"
|
||||
:class="[
|
||||
rowJsClass,
|
||||
isInstalled && 'cluster-application-installed',
|
||||
disabled && 'cluster-application-disabled'
|
||||
]"
|
||||
class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span"
|
||||
>
|
||||
<div
|
||||
class="gl-responsive-table-row-layout"
|
||||
role="row"
|
||||
>
|
||||
<a
|
||||
v-if="titleLink"
|
||||
:href="titleLink"
|
||||
target="blank"
|
||||
rel="noopener noreferrer"
|
||||
role="gridcell"
|
||||
class="table-section section-15 section-align-top js-cluster-application-title"
|
||||
>
|
||||
{{ title }}
|
||||
</a>
|
||||
<span
|
||||
v-else
|
||||
class="table-section section-15 section-align-top js-cluster-application-title"
|
||||
>
|
||||
{{ title }}
|
||||
</span>
|
||||
<div
|
||||
class="table-section section-wrap"
|
||||
class="table-section append-right-8 section-align-top"
|
||||
role="gridcell"
|
||||
>
|
||||
<slot name="description"></slot>
|
||||
<img
|
||||
v-if="hasLogo"
|
||||
:src="logoUrl"
|
||||
:alt="`${title} logo`"
|
||||
class="cluster-application-logo avatar s40"
|
||||
/>
|
||||
<identicon
|
||||
v-else
|
||||
:entity-id="identiconId"
|
||||
:entity-name="title"
|
||||
size-class="s40"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
:class="{ 'section-20': showManageButton, 'section-15': !showManageButton }"
|
||||
class="table-section table-button-footer section-align-top"
|
||||
class="table-section cluster-application-description section-wrap"
|
||||
role="gridcell"
|
||||
>
|
||||
<div
|
||||
v-if="showManageButton"
|
||||
class="btn-group table-action-buttons"
|
||||
>
|
||||
<strong>
|
||||
<a
|
||||
:href="manageLink"
|
||||
class="btn"
|
||||
v-if="titleLink"
|
||||
:href="titleLink"
|
||||
target="blank"
|
||||
rel="noopener noreferrer"
|
||||
class="js-cluster-application-title"
|
||||
>
|
||||
{{ manageButtonLabel }}
|
||||
{{ title }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="btn-group table-action-buttons">
|
||||
<loading-button
|
||||
:loading="installButtonLoading"
|
||||
:disabled="installButtonDisabled"
|
||||
:label="installButtonLabel"
|
||||
class="js-cluster-application-install-button"
|
||||
@click="installClicked"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasError || isUnknownStatus"
|
||||
class="gl-responsive-table-row-layout"
|
||||
role="row"
|
||||
>
|
||||
<div
|
||||
class="alert alert-danger alert-block append-bottom-0 clusters-error-alert"
|
||||
role="gridcell"
|
||||
>
|
||||
<div>
|
||||
<p class="js-cluster-application-general-error-message">
|
||||
<span
|
||||
v-else
|
||||
class="js-cluster-application-title"
|
||||
>
|
||||
{{ title }}
|
||||
</span>
|
||||
</strong>
|
||||
<slot name="description"></slot>
|
||||
<div
|
||||
v-if="hasError || isUnknownStatus"
|
||||
class="cluster-application-error text-danger prepend-top-10"
|
||||
>
|
||||
<p class="js-cluster-application-general-error-message append-bottom-0">
|
||||
{{ generalErrorDescription }}
|
||||
</p>
|
||||
<ul v-if="statusReason || requestReason">
|
||||
|
@ -213,6 +225,33 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:class="{ 'section-25': showManageButton, 'section-15': !showManageButton }"
|
||||
class="table-section table-button-footer section-align-top"
|
||||
role="gridcell"
|
||||
>
|
||||
<div
|
||||
v-if="showManageButton"
|
||||
class="btn-group table-action-buttons"
|
||||
>
|
||||
<a
|
||||
:href="manageLink"
|
||||
:class="{ disabled: disabled }"
|
||||
class="btn"
|
||||
>
|
||||
{{ manageButtonLabel }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="btn-group table-action-buttons">
|
||||
<loading-button
|
||||
:loading="installButtonLoading"
|
||||
:disabled="disabled || installButtonDisabled"
|
||||
:label="installButtonLabel"
|
||||
class="js-cluster-application-install-button"
|
||||
@click="installClicked"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
<script>
|
||||
import _ from 'underscore';
|
||||
import helmInstallIllustration from '@gitlab-org/gitlab-svgs/illustrations/kubernetes-installation.svg';
|
||||
import elasticsearchLogo from 'images/cluster_app_logos/elasticsearch.png';
|
||||
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 meltanoLogo from 'images/cluster_app_logos/meltano.png';
|
||||
import prometheusLogo from 'images/cluster_app_logos/prometheus.png';
|
||||
import { s__, sprintf } from '../../locale';
|
||||
import applicationRow from './application_row.vue';
|
||||
import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
|
||||
|
@ -37,21 +46,21 @@ export default {
|
|||
default: '',
|
||||
},
|
||||
},
|
||||
data: () => ({
|
||||
elasticsearchLogo,
|
||||
gitlabLogo,
|
||||
helmLogo,
|
||||
jeagerLogo,
|
||||
jupyterhubLogo,
|
||||
kubernetesLogo,
|
||||
meltanoLogo,
|
||||
prometheusLogo,
|
||||
}),
|
||||
computed: {
|
||||
generalApplicationDescription() {
|
||||
return sprintf(
|
||||
_.escape(
|
||||
s__(
|
||||
`ClusterIntegration|Install applications on your Kubernetes cluster.
|
||||
Read more about %{helpLink}`,
|
||||
),
|
||||
),
|
||||
{
|
||||
helpLink: `<a href="${this.helpPath}">
|
||||
${_.escape(s__('ClusterIntegration|installing applications'))}
|
||||
</a>`,
|
||||
},
|
||||
false,
|
||||
helmInstalled() {
|
||||
return (
|
||||
this.applications.helm.status === APPLICATION_STATUS.INSTALLED ||
|
||||
this.applications.helm.status === APPLICATION_STATUS.UPDATED
|
||||
);
|
||||
},
|
||||
ingressId() {
|
||||
|
@ -128,224 +137,240 @@ export default {
|
|||
return this.applications.jupyter.hostname;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.helmInstallIllustration = helmInstallIllustration;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
id="cluster-applications"
|
||||
class="settings no-animate expanded"
|
||||
>
|
||||
<div class="settings-header">
|
||||
<h4>
|
||||
{{ s__('ClusterIntegration|Applications') }}
|
||||
</h4>
|
||||
<p
|
||||
class="append-bottom-0"
|
||||
v-html="generalApplicationDescription"
|
||||
<section id="cluster-applications">
|
||||
<h4>
|
||||
{{ s__('ClusterIntegration|Applications') }}
|
||||
</h4>
|
||||
<p class="append-bottom-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>
|
||||
</p>
|
||||
|
||||
<div class="cluster-application-list prepend-top-10">
|
||||
<application-row
|
||||
id="helm"
|
||||
:logo-url="helmLogo"
|
||||
:title="applications.helm.title"
|
||||
:status="applications.helm.status"
|
||||
:status-reason="applications.helm.statusReason"
|
||||
:request-status="applications.helm.requestStatus"
|
||||
:request-reason="applications.helm.requestReason"
|
||||
class="rounded-top"
|
||||
title-link="https://docs.helm.sh/"
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="settings-content">
|
||||
<div class="append-bottom-20">
|
||||
<application-row
|
||||
id="helm"
|
||||
:title="applications.helm.title"
|
||||
:status="applications.helm.status"
|
||||
:status-reason="applications.helm.statusReason"
|
||||
:request-status="applications.helm.requestStatus"
|
||||
:request-reason="applications.helm.requestReason"
|
||||
title-link="https://docs.helm.sh/"
|
||||
<div slot="description">
|
||||
{{ s__(`ClusterIntegration|Helm streamlines installing
|
||||
and managing Kubernetes applications.
|
||||
Tiller runs inside of your Kubernetes Cluster,
|
||||
and manages releases of your charts.`) }}
|
||||
</div>
|
||||
</application-row>
|
||||
<div
|
||||
v-show="!helmInstalled"
|
||||
class="cluster-application-warning"
|
||||
>
|
||||
<div
|
||||
class="svg-container"
|
||||
v-html="helmInstallIllustration"
|
||||
>
|
||||
<div slot="description">
|
||||
{{ s__(`ClusterIntegration|Helm streamlines installing
|
||||
and managing Kubernetes applications.
|
||||
Tiller runs inside of your Kubernetes Cluster,
|
||||
and manages releases of your charts.`) }}
|
||||
</div>
|
||||
</application-row>
|
||||
<application-row
|
||||
:id="ingressId"
|
||||
:title="applications.ingress.title"
|
||||
:status="applications.ingress.status"
|
||||
:status-reason="applications.ingress.statusReason"
|
||||
:request-status="applications.ingress.requestStatus"
|
||||
:request-reason="applications.ingress.requestReason"
|
||||
title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/"
|
||||
>
|
||||
<div slot="description">
|
||||
<p>
|
||||
{{ s__(`ClusterIntegration|Ingress gives you a way to route
|
||||
requests to services based on the request host or path,
|
||||
centralizing a number of services into a single entrypoint.`) }}
|
||||
</p>
|
||||
</div>
|
||||
{{ s__(`ClusterIntegration|You must first install Helm Tiller before
|
||||
installing the applications below`) }}
|
||||
</div>
|
||||
<application-row
|
||||
:id="ingressId"
|
||||
:logo-url="kubernetesLogo"
|
||||
:title="applications.ingress.title"
|
||||
:status="applications.ingress.status"
|
||||
:status-reason="applications.ingress.statusReason"
|
||||
:request-status="applications.ingress.requestStatus"
|
||||
:request-reason="applications.ingress.requestReason"
|
||||
:disabled="!helmInstalled"
|
||||
title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/"
|
||||
>
|
||||
<div slot="description">
|
||||
<p>
|
||||
{{ s__(`ClusterIntegration|Ingress gives you a way to route
|
||||
requests to services based on the request host or path,
|
||||
centralizing a number of services into a single entrypoint.`) }}
|
||||
</p>
|
||||
|
||||
<template v-if="ingressInstalled">
|
||||
<div class="form-group">
|
||||
<label for="ingress-ip-address">
|
||||
{{ s__('ClusterIntegration|Ingress IP Address') }}
|
||||
</label>
|
||||
<div
|
||||
v-if="ingressExternalIp"
|
||||
class="input-group"
|
||||
>
|
||||
<input
|
||||
id="ingress-ip-address"
|
||||
:value="ingressExternalIp"
|
||||
type="text"
|
||||
class="form-control js-ip-address"
|
||||
readonly
|
||||
/>
|
||||
<span class="input-group-append">
|
||||
<clipboard-button
|
||||
:text="ingressExternalIp"
|
||||
:title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')"
|
||||
class="input-group-text js-clipboard-btn"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<template v-if="ingressInstalled">
|
||||
<div class="form-group">
|
||||
<label for="ingress-ip-address">
|
||||
{{ s__('ClusterIntegration|Ingress IP Address') }}
|
||||
</label>
|
||||
<div
|
||||
v-if="ingressExternalIp"
|
||||
class="input-group"
|
||||
>
|
||||
<input
|
||||
v-else
|
||||
id="ingress-ip-address"
|
||||
:value="ingressExternalIp"
|
||||
type="text"
|
||||
class="form-control js-ip-address"
|
||||
readonly
|
||||
value="?"
|
||||
/>
|
||||
<span class="input-group-append">
|
||||
<clipboard-button
|
||||
:text="ingressExternalIp"
|
||||
:title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')"
|
||||
class="input-group-text js-clipboard-btn"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p
|
||||
v-if="!ingressExternalIp"
|
||||
class="settings-message js-no-ip-message"
|
||||
>
|
||||
{{ s__(`ClusterIntegration|The IP address is in
|
||||
the process of being assigned. Please check your Kubernetes
|
||||
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }}
|
||||
|
||||
<a
|
||||
:href="ingressHelpPath"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ __('More information') }}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{ s__(`ClusterIntegration|Point a wildcard DNS to this
|
||||
generated IP address in order to access
|
||||
your application after it has been deployed.`) }}
|
||||
<a
|
||||
:href="ingressDnsHelpPath"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ __('More information') }}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
</template>
|
||||
<div
|
||||
v-else
|
||||
v-html="ingressDescription"
|
||||
>
|
||||
<input
|
||||
v-else
|
||||
type="text"
|
||||
class="form-control js-ip-address"
|
||||
readonly
|
||||
value="?"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</application-row>
|
||||
<application-row
|
||||
id="prometheus"
|
||||
:title="applications.prometheus.title"
|
||||
:manage-link="managePrometheusPath"
|
||||
:status="applications.prometheus.status"
|
||||
:status-reason="applications.prometheus.statusReason"
|
||||
:request-status="applications.prometheus.requestStatus"
|
||||
:request-reason="applications.prometheus.requestReason"
|
||||
title-link="https://prometheus.io/docs/introduction/overview/"
|
||||
>
|
||||
<div
|
||||
slot="description"
|
||||
v-html="prometheusDescription"
|
||||
>
|
||||
</div>
|
||||
</application-row>
|
||||
<application-row
|
||||
id="runner"
|
||||
:title="applications.runner.title"
|
||||
:status="applications.runner.status"
|
||||
:status-reason="applications.runner.statusReason"
|
||||
:request-status="applications.runner.requestStatus"
|
||||
:request-reason="applications.runner.requestReason"
|
||||
title-link="https://docs.gitlab.com/runner/"
|
||||
>
|
||||
<div slot="description">
|
||||
{{ s__(`ClusterIntegration|GitLab Runner connects to this
|
||||
project's repository and executes CI/CD jobs,
|
||||
pushing results back and deploying,
|
||||
applications to production.`) }}
|
||||
</div>
|
||||
</application-row>
|
||||
<application-row
|
||||
id="jupyter"
|
||||
:title="applications.jupyter.title"
|
||||
:status="applications.jupyter.status"
|
||||
:status-reason="applications.jupyter.statusReason"
|
||||
:request-status="applications.jupyter.requestStatus"
|
||||
:request-reason="applications.jupyter.requestReason"
|
||||
:install-application-request-params="{ hostname: applications.jupyter.hostname }"
|
||||
title-link="https://jupyterhub.readthedocs.io/en/stable/"
|
||||
>
|
||||
<div slot="description">
|
||||
<p>
|
||||
{{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
|
||||
manages, and proxies multiple instances of the single-user
|
||||
Jupyter notebook server. JupyterHub can be used to serve
|
||||
notebooks to a class of students, a corporate data science group,
|
||||
or a scientific research group.`) }}
|
||||
|
||||
<p
|
||||
v-if="!ingressExternalIp"
|
||||
class="settings-message js-no-ip-message"
|
||||
>
|
||||
{{ s__(`ClusterIntegration|The IP address is in
|
||||
the process of being assigned. Please check your Kubernetes
|
||||
cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }}
|
||||
|
||||
<a
|
||||
:href="ingressHelpPath"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ __('More information') }}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<template v-if="ingressExternalIp">
|
||||
<div class="form-group">
|
||||
<label for="jupyter-hostname">
|
||||
{{ s__('ClusterIntegration|Jupyter Hostname') }}
|
||||
</label>
|
||||
<p>
|
||||
{{ s__(`ClusterIntegration|Point a wildcard DNS to this
|
||||
generated IP address in order to access
|
||||
your application after it has been deployed.`) }}
|
||||
<a
|
||||
:href="ingressDnsHelpPath"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ __('More information') }}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
v-model="applications.jupyter.hostname"
|
||||
:readonly="jupyterInstalled"
|
||||
type="text"
|
||||
class="form-control js-hostname"
|
||||
/>
|
||||
<span
|
||||
class="input-group-btn"
|
||||
>
|
||||
<clipboard-button
|
||||
:text="jupyterHostname"
|
||||
:title="s__('ClusterIntegration|Copy Jupyter Hostname to clipboard')"
|
||||
class="js-clipboard-btn"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="ingressInstalled">
|
||||
{{ 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"
|
||||
>
|
||||
{{ __('More information') }}
|
||||
</a>
|
||||
</p>
|
||||
</template>
|
||||
</template>
|
||||
<div
|
||||
v-html="ingressDescription"
|
||||
>
|
||||
</div>
|
||||
</application-row>
|
||||
<!--
|
||||
NOTE: Don't forget to update `clusters.scss`
|
||||
min-height for this block and uncomment `application_spec` tests
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</application-row>
|
||||
<application-row
|
||||
id="prometheus"
|
||||
:logo-url="prometheusLogo"
|
||||
:title="applications.prometheus.title"
|
||||
:manage-link="managePrometheusPath"
|
||||
:status="applications.prometheus.status"
|
||||
:status-reason="applications.prometheus.statusReason"
|
||||
:request-status="applications.prometheus.requestStatus"
|
||||
:request-reason="applications.prometheus.requestReason"
|
||||
:disabled="!helmInstalled"
|
||||
title-link="https://prometheus.io/docs/introduction/overview/"
|
||||
>
|
||||
<div
|
||||
slot="description"
|
||||
v-html="prometheusDescription"
|
||||
>
|
||||
</div>
|
||||
</application-row>
|
||||
<application-row
|
||||
id="runner"
|
||||
:logo-url="gitlabLogo"
|
||||
:title="applications.runner.title"
|
||||
:status="applications.runner.status"
|
||||
:status-reason="applications.runner.statusReason"
|
||||
:request-status="applications.runner.requestStatus"
|
||||
:request-reason="applications.runner.requestReason"
|
||||
:disabled="!helmInstalled"
|
||||
title-link="https://docs.gitlab.com/runner/"
|
||||
>
|
||||
<div slot="description">
|
||||
{{ s__(`ClusterIntegration|GitLab Runner connects to this
|
||||
project's repository and executes CI/CD jobs,
|
||||
pushing results back and deploying,
|
||||
applications to production.`) }}
|
||||
</div>
|
||||
</application-row>
|
||||
<application-row
|
||||
id="jupyter"
|
||||
:logo-url="jupyterhubLogo"
|
||||
:title="applications.jupyter.title"
|
||||
:status="applications.jupyter.status"
|
||||
:status-reason="applications.jupyter.statusReason"
|
||||
:request-status="applications.jupyter.requestStatus"
|
||||
:request-reason="applications.jupyter.requestReason"
|
||||
:install-application-request-params="{ hostname: applications.jupyter.hostname }"
|
||||
:disabled="!helmInstalled"
|
||||
class="hide-bottom-border rounded-bottom"
|
||||
title-link="https://jupyterhub.readthedocs.io/en/stable/"
|
||||
>
|
||||
<div slot="description">
|
||||
<p>
|
||||
{{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
|
||||
manages, and proxies multiple instances of the single-user
|
||||
Jupyter notebook server. JupyterHub can be used to serve
|
||||
notebooks to a class of students, a corporate data science group,
|
||||
or a scientific research group.`) }}
|
||||
</p>
|
||||
|
||||
<template v-if="ingressExternalIp">
|
||||
<div class="form-group">
|
||||
<label for="jupyter-hostname">
|
||||
{{ s__('ClusterIntegration|Jupyter Hostname') }}
|
||||
</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input
|
||||
v-model="applications.jupyter.hostname"
|
||||
:readonly="jupyterInstalled"
|
||||
type="text"
|
||||
class="form-control js-hostname"
|
||||
/>
|
||||
<span
|
||||
class="input-group-btn"
|
||||
>
|
||||
<clipboard-button
|
||||
:text="jupyterHostname"
|
||||
:title="s__('ClusterIntegration|Copy Jupyter Hostname to clipboard')"
|
||||
class="js-clipboard-btn"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="ingressInstalled">
|
||||
{{ 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"
|
||||
>
|
||||
{{ __('More information') }}
|
||||
</a>
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</application-row>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
@ -4,9 +4,60 @@
|
|||
}
|
||||
}
|
||||
|
||||
.cluster-applications-table {
|
||||
// Wait for the Vue to kick-in and render the applications block
|
||||
min-height: 628px;
|
||||
.cluster-application-row {
|
||||
background: $gray-lighter;
|
||||
|
||||
&.cluster-application-installed {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.settings-message {
|
||||
padding: $gl-vert-padding $gl-padding-8;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: map-get($grid-breakpoints, md)) {
|
||||
.cluster-application-list {
|
||||
border: 1px solid $border-color;
|
||||
border-radius: $border-radius-default;
|
||||
}
|
||||
|
||||
.cluster-application-row {
|
||||
border-bottom: 1px solid $border-color;
|
||||
padding: $gl-padding;
|
||||
}
|
||||
}
|
||||
|
||||
.cluster-application-logo {
|
||||
border: 3px solid $white-light;
|
||||
box-shadow: 0 0 0 1px $gray-normal;
|
||||
|
||||
&.avatar:hover {
|
||||
border-color: $white-light;
|
||||
}
|
||||
}
|
||||
|
||||
.cluster-application-warning {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
padding: $gl-padding;
|
||||
border-bottom: 1px solid $white-normal;
|
||||
|
||||
.svg-container {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: $gl-padding-8;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.cluster-application-description {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.cluster-application-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.clusters-dropdown-menu {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Improve install flow of Kubernetes cluster apps
|
||||
merge_request: 21567
|
||||
author:
|
||||
type: changed
|
|
@ -1353,6 +1353,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster. Helm Tiller is required to install any of the following applications."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Choose which of your environments will use this cluster."
|
||||
msgstr ""
|
||||
|
||||
|
@ -1443,9 +1446,6 @@ msgstr ""
|
|||
msgid "ClusterIntegration|Install"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Install applications on your Kubernetes cluster. Read more about %{helpLink}"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Installed"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1653,6 +1653,9 @@ msgstr ""
|
|||
msgid "ClusterIntegration|With a Kubernetes cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|You must first install Helm Tiller before installing the applications below"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1671,9 +1674,6 @@ msgstr ""
|
|||
msgid "ClusterIntegration|help page"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|installing applications"
|
||||
msgstr ""
|
||||
|
||||
msgid "ClusterIntegration|meets the requirements"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ describe 'User Cluster', :js do
|
|||
context 'when user disables the cluster' do
|
||||
before do
|
||||
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
|
||||
fill_in 'cluster_name', with: 'dev-cluster'
|
||||
page.within('#cluster-integration') { click_button 'Save changes' }
|
||||
end
|
||||
|
||||
|
|