debian-mirror-gitlab/app/assets/javascripts/clusters/components/application_row.vue

479 lines
14 KiB
Vue
Raw Normal View History

2018-03-17 18:26:18 +05:30
<script>
2020-11-24 15:15:51 +05:30
import { GlLink, GlModalDirective, GlSprintf, GlButton, GlAlert } from '@gitlab/ui';
2019-09-04 21:01:54 +05:30
import { s__, __, sprintf } from '~/locale';
2018-12-13 13:39:08 +05:30
import identicon from '../../vue_shared/components/identicon.vue';
2021-03-11 19:13:27 +05:30
import { APPLICATION_STATUS, ELASTIC_STACK } from '../constants';
import eventHub from '../event_hub';
2019-07-31 22:56:46 +05:30
import UninstallApplicationButton from './uninstall_application_button.vue';
import UninstallApplicationConfirmationModal from './uninstall_application_confirmation_modal.vue';
2020-06-23 00:09:42 +05:30
import UpdateApplicationConfirmationModal from './update_application_confirmation_modal.vue';
2019-07-31 22:56:46 +05:30
2018-12-13 13:39:08 +05:30
export default {
components: {
2020-11-24 15:15:51 +05:30
GlButton,
2018-12-13 13:39:08 +05:30
identicon,
2019-03-02 22:35:43 +05:30
GlLink,
2020-11-24 15:15:51 +05:30
GlAlert,
2020-06-23 00:09:42 +05:30
GlSprintf,
2019-07-31 22:56:46 +05:30
UninstallApplicationButton,
UninstallApplicationConfirmationModal,
2020-06-23 00:09:42 +05:30
UpdateApplicationConfirmationModal,
2019-07-31 22:56:46 +05:30
},
directives: {
GlModalDirective,
2018-12-13 13:39:08 +05:30
},
props: {
id: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
titleLink: {
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2018-12-13 13:39:08 +05:30
},
manageLink: {
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2018-12-13 13:39:08 +05:30
},
logoUrl: {
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2018-12-13 13:39:08 +05:30
},
disabled: {
type: Boolean,
required: false,
default: false,
},
2020-10-24 23:57:45 +05:30
installable: {
type: Boolean,
required: false,
default: true,
},
2019-07-31 22:56:46 +05:30
uninstallable: {
type: Boolean,
required: false,
default: false,
},
2018-12-13 13:39:08 +05:30
status: {
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2018-12-13 13:39:08 +05:30
},
statusReason: {
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2018-12-13 13:39:08 +05:30
},
2019-07-31 22:56:46 +05:30
requestReason: {
2018-12-13 13:39:08 +05:30
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2018-12-13 13:39:08 +05:30
},
2019-07-31 22:56:46 +05:30
installed: {
type: Boolean,
2018-12-13 13:39:08 +05:30
required: false,
2019-07-31 22:56:46 +05:30
default: false,
},
installFailed: {
type: Boolean,
required: false,
default: false,
2018-12-13 13:39:08 +05:30
},
2019-03-02 22:35:43 +05:30
version: {
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2019-03-02 22:35:43 +05:30
},
chartRepo: {
type: String,
required: false,
2020-06-23 00:09:42 +05:30
default: '',
2019-03-02 22:35:43 +05:30
},
2019-09-04 21:01:54 +05:30
updateAvailable: {
2019-03-02 22:35:43 +05:30
type: Boolean,
required: false,
},
2019-09-04 21:01:54 +05:30
updateable: {
type: Boolean,
default: true,
2020-04-22 19:07:51 +05:30
required: false,
2019-09-04 21:01:54 +05:30
},
2019-07-31 22:56:46 +05:30
updateSuccessful: {
type: Boolean,
required: false,
default: false,
},
updateFailed: {
type: Boolean,
required: false,
default: false,
},
uninstallFailed: {
type: Boolean,
required: false,
default: false,
},
uninstallSuccessful: {
type: Boolean,
required: false,
default: false,
},
2018-12-13 13:39:08 +05:30
installApplicationRequestParams: {
type: Object,
required: false,
default: () => ({}),
},
},
computed: {
isUnknownStatus() {
return !this.isKnownStatus && this.status !== null;
},
isKnownStatus() {
return Object.values(APPLICATION_STATUS).includes(this.status);
},
2019-03-02 22:35:43 +05:30
isInstalling() {
2019-07-31 22:56:46 +05:30
return this.status === APPLICATION_STATUS.INSTALLING;
2019-03-02 22:35:43 +05:30
},
2021-04-29 21:17:54 +05:30
isExternallyInstalled() {
return this.status === APPLICATION_STATUS.EXTERNALLY_INSTALLED;
},
2019-03-02 22:35:43 +05:30
canInstall() {
return (
this.status === APPLICATION_STATUS.NOT_INSTALLABLE ||
this.status === APPLICATION_STATUS.INSTALLABLE ||
2020-10-24 23:57:45 +05:30
this.status === APPLICATION_STATUS.UNINSTALLED ||
2019-03-02 22:35:43 +05:30
this.isUnknownStatus
2018-12-13 13:39:08 +05:30
);
},
hasLogo() {
2019-09-04 21:01:54 +05:30
return Boolean(this.logoUrl);
2018-12-13 13:39:08 +05:30
},
identiconId() {
// generate a deterministic integer id for the identicon background
return this.id.charCodeAt(0);
},
rowJsClass() {
return `js-cluster-application-row-${this.id}`;
},
2019-07-31 22:56:46 +05:30
displayUninstallButton() {
return this.installed && this.uninstallable;
},
displayInstallButton() {
return !this.installed || !this.uninstallable;
},
2018-12-13 13:39:08 +05:30
installButtonLoading() {
2019-07-31 22:56:46 +05:30
return !this.status || this.isInstalling;
2018-12-13 13:39:08 +05:30
},
installButtonDisabled() {
2020-10-24 23:57:45 +05:30
// 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;
2018-12-13 13:39:08 +05:30
// 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.
2020-10-24 23:57:45 +05:30
if (this.isInstalling) return true;
if (!this.isKnownStatus) return false;
2018-12-13 13:39:08 +05:30
return (
2020-10-24 23:57:45 +05:30
this.status !== APPLICATION_STATUS.INSTALLABLE && this.status !== APPLICATION_STATUS.ERROR
2018-12-13 13:39:08 +05:30
);
},
installButtonLabel() {
let label;
2019-03-02 22:35:43 +05:30
if (this.canInstall) {
2019-09-04 21:01:54 +05:30
label = __('Install');
2019-03-02 22:35:43 +05:30
} else if (this.isInstalling) {
2019-09-04 21:01:54 +05:30
label = __('Installing');
2019-07-31 22:56:46 +05:30
} else if (this.installed) {
2019-09-04 21:01:54 +05:30
label = __('Installed');
2021-04-29 21:17:54 +05:30
} else if (this.isExternallyInstalled) {
label = __('Externally installed');
2018-12-13 13:39:08 +05:30
}
2018-03-17 18:26:18 +05:30
2018-12-13 13:39:08 +05:30
return label;
},
2021-04-29 21:17:54 +05:30
buttonGridCellClass() {
return this.showManageButton || this.status === APPLICATION_STATUS.EXTERNALLY_INSTALLED
? 'section-25'
: 'section-15';
},
2018-12-13 13:39:08 +05:30
showManageButton() {
return this.manageLink && this.status === APPLICATION_STATUS.INSTALLED;
},
manageButtonLabel() {
2019-09-04 21:01:54 +05:30
return __('Manage');
2018-12-13 13:39:08 +05:30
},
hasError() {
2019-07-31 22:56:46 +05:30
return this.installFailed || this.uninstallFailed;
2018-12-13 13:39:08 +05:30
},
generalErrorDescription() {
2019-07-31 22:56:46 +05:30
let errorDescription;
if (this.installFailed) {
errorDescription = s__('ClusterIntegration|Something went wrong while installing %{title}');
} else if (this.uninstallFailed) {
errorDescription = s__(
'ClusterIntegration|Something went wrong while uninstalling %{title}',
);
}
return sprintf(errorDescription, { title: this.title });
2018-12-13 13:39:08 +05:30
},
2019-09-04 21:01:54 +05:30
updateFailureDescription() {
2019-07-07 11:18:12 +05:30
return s__('ClusterIntegration|Update failed. Please check the logs and try again.');
2019-03-02 22:35:43 +05:30
},
2019-09-04 21:01:54 +05:30
updateSuccessDescription() {
return sprintf(s__('ClusterIntegration|%{title} updated successfully.'), {
2019-03-02 22:35:43 +05:30
title: this.title,
});
},
2019-09-04 21:01:54 +05:30
updateButtonLabel() {
2019-03-02 22:35:43 +05:30
let label;
2019-09-04 21:01:54 +05:30
if (this.updateAvailable && !this.updateFailed && !this.isUpdating) {
label = __('Update');
} else if (this.isUpdating) {
label = __('Updating');
2019-07-31 22:56:46 +05:30
} else if (this.updateFailed) {
2019-09-04 21:01:54 +05:30
label = __('Retry update');
2019-03-02 22:35:43 +05:30
}
return label;
},
2020-06-23 00:09:42 +05:30
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;
},
2019-09-04 21:01:54 +05:30
isUpdating() {
2019-03-02 22:35:43 +05:30
// Since upgrading is handled asynchronously on the backend we need this check to prevent any delay on the frontend
2019-07-31 22:56:46 +05:30
return this.status === APPLICATION_STATUS.UPDATING;
2019-03-02 22:35:43 +05:30
},
2019-09-04 21:01:54 +05:30
shouldShowUpdateDetails() {
2019-07-07 11:18:12 +05:30
// This method only returns true when;
2019-09-04 21:01:54 +05:30
// Update was successful OR Update failed
// AND new update is unavailable AND version information is present.
return (this.updateSuccessful || this.updateFailed) && !this.updateAvailable && this.version;
2019-07-31 22:56:46 +05:30
},
uninstallSuccessDescription() {
return sprintf(s__('ClusterIntegration|%{title} uninstalled successfully.'), {
title: this.title,
});
2019-07-07 11:18:12 +05:30
},
2020-06-23 00:09:42 +05:30
updateModalId() {
return `update-${this.id}`;
},
uninstallModalId() {
return `uninstall-${this.id}`;
},
2019-03-02 22:35:43 +05:30
},
watch: {
2019-07-31 22:56:46 +05:30
updateSuccessful(updateSuccessful) {
if (updateSuccessful) {
2019-09-04 21:01:54 +05:30
this.$toast.show(this.updateSuccessDescription);
2019-07-31 22:56:46 +05:30
}
},
uninstallSuccessful(uninstallSuccessful) {
if (uninstallSuccessful) {
this.$toast.show(this.uninstallSuccessDescription);
2019-03-02 22:35:43 +05:30
}
},
2018-12-13 13:39:08 +05:30
},
methods: {
installClicked() {
2020-06-23 00:09:42 +05:30
if (this.disabled || this.installButtonDisabled) return;
2018-12-13 13:39:08 +05:30
eventHub.$emit('installApplication', {
id: this.id,
params: this.installApplicationRequestParams,
});
},
2020-06-23 00:09:42 +05:30
updateConfirmed() {
if (this.isUpdating) return;
2019-09-04 21:01:54 +05:30
eventHub.$emit('updateApplication', {
2019-03-02 22:35:43 +05:30
id: this.id,
params: this.installApplicationRequestParams,
});
},
2019-07-31 22:56:46 +05:30
uninstallConfirmed() {
eventHub.$emit('uninstallApplication', {
id: this.id,
});
2019-03-02 22:35:43 +05:30
},
2018-12-13 13:39:08 +05:30
},
};
2018-03-17 18:26:18 +05:30
</script>
<template>
<div
2018-12-05 23:21:45 +05:30
:class="[
rowJsClass,
2019-07-31 22:56:46 +05:30
installed && 'cluster-application-installed',
2019-02-15 15:39:39 +05:30
disabled && 'cluster-application-disabled',
2018-12-05 23:21:45 +05:30
]"
class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span"
2020-03-13 15:44:24 +05:30
:data-qa-selector="id"
2018-03-17 18:26:18 +05:30
>
2019-02-15 15:39:39 +05:30
<div class="gl-responsive-table-row-layout" role="row">
2020-06-23 00:09:42 +05:30
<div class="table-section gl-mr-3 section-align-top" role="gridcell">
2018-12-05 23:21:45 +05:30
<img
v-if="hasLogo"
:src="logoUrl"
:alt="`${title} logo`"
class="cluster-application-logo avatar s40"
/>
2019-02-15 15:39:39 +05:30
<identicon v-else :entity-id="identiconId" :entity-name="title" size-class="s40" />
2018-12-05 23:21:45 +05:30
</div>
2019-02-15 15:39:39 +05:30
<div class="table-section cluster-application-description section-wrap" role="gridcell">
2018-12-05 23:21:45 +05:30
<strong>
<a
v-if="titleLink"
:href="titleLink"
2020-03-13 15:44:24 +05:30
target="_blank"
2018-12-05 23:21:45 +05:30
rel="noopener noreferrer"
class="js-cluster-application-title"
2019-07-31 22:56:46 +05:30
>{{ title }}</a
2018-12-05 23:21:45 +05:30
>
2019-07-31 22:56:46 +05:30
<span v-else class="js-cluster-application-title">{{ title }}</span>
2018-12-05 23:21:45 +05:30
</strong>
2021-01-29 00:20:46 +05:30
<slot name="installed-via"></slot>
2020-06-23 00:09:42 +05:30
<div>
<slot name="description"></slot>
</div>
2020-10-24 23:57:45 +05:30
<div v-if="hasError" class="cluster-application-error text-danger gl-mt-3">
2020-06-23 00:09:42 +05:30
<p class="js-cluster-application-general-error-message gl-mb-0">
2018-12-05 23:21:45 +05:30
{{ generalErrorDescription }}
</p>
<ul v-if="statusReason || requestReason">
2019-02-15 15:39:39 +05:30
<li v-if="statusReason" class="js-cluster-application-status-error-message">
2018-12-05 23:21:45 +05:30
{{ statusReason }}
</li>
2019-02-15 15:39:39 +05:30
<li v-if="requestReason" class="js-cluster-application-request-error-message">
2018-12-05 23:21:45 +05:30
{{ requestReason }}
</li>
</ul>
</div>
2019-03-02 22:35:43 +05:30
2019-09-04 21:01:54 +05:30
<div v-if="updateable">
<div
v-if="shouldShowUpdateDetails"
class="form-text text-muted label p-0 js-cluster-application-update-details"
2019-03-02 22:35:43 +05:30
>
2020-06-23 00:09:42 +05:30
<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>
2019-09-04 21:01:54 +05:30
</div>
2020-11-24 15:15:51 +05:30
<gl-alert
2019-09-04 21:01:54 +05:30
v-if="updateFailed && !isUpdating"
2020-11-24 15:15:51 +05:30
variant="danger"
:dismissible="false"
class="gl-mt-3 gl-mb-0 js-cluster-application-update-details"
2019-09-04 21:01:54 +05:30
>
{{ updateFailureDescription }}
2020-11-24 15:15:51 +05:30
</gl-alert>
2020-06-23 00:09:42 +05:30
<template v-if="updateAvailable || updateFailed || isUpdating">
<template v-if="updatingNeedsConfirmation">
2020-11-24 15:15:51 +05:30
<gl-button
2020-06-23 00:09:42 +05:30
v-gl-modal-directive="updateModalId"
2020-11-24 15:15:51 +05:30
class="js-cluster-application-update-button mt-2"
variant="info"
category="primary"
2020-06-23 00:09:42 +05:30
:loading="isUpdating"
:disabled="isUpdating"
data-qa-selector="update_button_with_confirmation"
:data-qa-application="id"
2020-11-24 15:15:51 +05:30
>
{{ updateButtonLabel }}
</gl-button>
2020-06-23 00:09:42 +05:30
<update-application-confirmation-modal
:application="id"
:application-title="title"
@confirm="updateConfirmed()"
/>
</template>
2020-11-24 15:15:51 +05:30
<gl-button
2020-06-23 00:09:42 +05:30
v-else
2020-11-24 15:15:51 +05:30
class="js-cluster-application-update-button mt-2"
variant="info"
category="primary"
2020-06-23 00:09:42 +05:30
:loading="isUpdating"
:disabled="isUpdating"
data-qa-selector="update_button"
:data-qa-application="id"
@click="updateConfirmed"
2020-11-24 15:15:51 +05:30
>
{{ updateButtonLabel }}
</gl-button>
2020-06-23 00:09:42 +05:30
</template>
2019-03-02 22:35:43 +05:30
</div>
2018-03-17 18:26:18 +05:30
</div>
<div
2021-04-29 21:17:54 +05:30
:class="[buttonGridCellClass, 'table-section', 'table-button-footer', 'section-align-top']"
2018-03-17 18:26:18 +05:30
role="gridcell"
>
2019-02-15 15:39:39 +05:30
<div v-if="showManageButton" class="btn-group table-action-buttons">
2019-07-31 22:56:46 +05:30
<a :href="manageLink" :class="{ disabled: disabled }" class="btn">{{
manageButtonLabel
}}</a>
2018-03-17 18:26:18 +05:30
</div>
<div class="btn-group table-action-buttons">
2020-11-24 15:15:51 +05:30
<gl-button
2019-07-31 22:56:46 +05:30
v-if="displayInstallButton"
2018-03-17 18:26:18 +05:30
:loading="installButtonLoading"
2018-12-05 23:21:45 +05:30
:disabled="disabled || installButtonDisabled"
2018-11-08 19:23:39 +05:30
class="js-cluster-application-install-button"
2020-11-24 15:15:51 +05:30
variant="default"
2020-03-13 15:44:24 +05:30
data-qa-selector="install_button"
:data-qa-application="id"
2018-03-17 18:26:18 +05:30
@click="installClicked"
2020-11-24 15:15:51 +05:30
>
{{ installButtonLabel }}
</gl-button>
2019-07-31 22:56:46 +05:30
<uninstall-application-button
v-if="displayUninstallButton"
2020-06-23 00:09:42 +05:30
v-gl-modal-directive="uninstallModalId"
2019-07-31 22:56:46 +05:30
:status="status"
2020-03-13 15:44:24 +05:30
data-qa-selector="uninstall_button"
:data-qa-application="id"
2019-07-31 22:56:46 +05:30
class="js-cluster-application-uninstall-button"
/>
<uninstall-application-confirmation-modal
:application="id"
:application-title="title"
@confirm="uninstallConfirmed()"
/>
2018-03-17 18:26:18 +05:30
</div>
</div>
</div>
</div>
</template>