application_row.vue 7.1 KB
Newer Older
1
<script>
Filipa Lacerda's avatar
Filipa Lacerda committed
2
  /* eslint-disable vue/require-default-prop */
3 4
  import { s__, sprintf } from '../../locale';
  import eventHub from '../event_hub';
5
  import identicon from '../../vue_shared/components/identicon.vue';
6 7
  import loadingButton from '../../vue_shared/components/loading_button.vue';
  import {
8
    APPLICATION_STATUS,
9 10 11 12
    REQUEST_LOADING,
    REQUEST_SUCCESS,
    REQUEST_FAILURE,
  } from '../constants';
13

14 15 16
  export default {
    components: {
      loadingButton,
17
      identicon,
18
    },
19 20 21 22 23 24 25 26 27 28 29 30 31
    props: {
      id: {
        type: String,
        required: true,
      },
      title: {
        type: String,
        required: true,
      },
      titleLink: {
        type: String,
        required: false,
      },
32 33 34 35
      manageLink: {
        type: String,
        required: false,
      },
36 37 38 39 40 41 42 43 44 45
      logoUrl: {
        type: String,
        required: false,
        default: null,
      },
      disabled: {
        type: Boolean,
        required: false,
        default: false,
      },
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
      status: {
        type: String,
        required: false,
      },
      statusReason: {
        type: String,
        required: false,
      },
      requestStatus: {
        type: String,
        required: false,
      },
      requestReason: {
        type: String,
        required: false,
      },
62 63 64 65 66
      installApplicationRequestParams: {
        type: Object,
        required: false,
        default: () => ({}),
      },
67
    },
68
    computed: {
69 70 71 72 73 74
      isUnknownStatus() {
        return !this.isKnownStatus && this.status !== null;
      },
      isKnownStatus() {
        return Object.values(APPLICATION_STATUS).includes(this.status);
      },
75 76 77 78 79 80 81 82 83 84 85 86
      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);
      },
87 88 89 90
      rowJsClass() {
        return `js-cluster-application-row-${this.id}`;
      },
      installButtonLoading() {
Filipa Lacerda's avatar
Filipa Lacerda committed
91
        return !this.status ||
92 93
          this.status === APPLICATION_STATUS.SCHEDULED ||
          this.status === APPLICATION_STATUS.INSTALLING ||
94 95 96
          this.requestStatus === REQUEST_LOADING;
      },
      installButtonDisabled() {
97
        // Avoid the potential for the real-time data to say APPLICATION_STATUS.INSTALLABLE but
98 99
        // we already made a request to install and are just waiting for the real-time
        // to sync up.
100 101
        return ((this.status !== APPLICATION_STATUS.INSTALLABLE
          && this.status !== APPLICATION_STATUS.ERROR) ||
102
          this.requestStatus === REQUEST_LOADING ||
103
          this.requestStatus === REQUEST_SUCCESS) && this.isKnownStatus;
104 105 106 107
      },
      installButtonLabel() {
        let label;
        if (
108 109 110 111
          this.status === APPLICATION_STATUS.NOT_INSTALLABLE ||
          this.status === APPLICATION_STATUS.INSTALLABLE ||
          this.status === APPLICATION_STATUS.ERROR ||
          this.isUnknownStatus
112 113
        ) {
          label = s__('ClusterIntegration|Install');
114 115
        } else if (this.status === APPLICATION_STATUS.SCHEDULED ||
          this.status === APPLICATION_STATUS.INSTALLING) {
116
          label = s__('ClusterIntegration|Installing');
117 118
        } else if (this.status === APPLICATION_STATUS.INSTALLED ||
          this.status === APPLICATION_STATUS.UPDATED) {
119 120
          label = s__('ClusterIntegration|Installed');
        }
121

122 123
        return label;
      },
124
      showManageButton() {
125
        return this.manageLink && this.status === APPLICATION_STATUS.INSTALLED;
126
      },
127 128 129
      manageButtonLabel() {
        return s__('ClusterIntegration|Manage');
      },
130
      hasError() {
131
        return this.status === APPLICATION_STATUS.ERROR ||
Filipa Lacerda's avatar
Filipa Lacerda committed
132
        this.requestStatus === REQUEST_FAILURE;
133 134 135 136 137 138 139 140
      },
      generalErrorDescription() {
        return sprintf(
          s__('ClusterIntegration|Something went wrong while installing %{title}'), {
            title: this.title,
          },
        );
      },
141
    },
142 143
    methods: {
      installClicked() {
144 145 146 147
        eventHub.$emit('installApplication', {
          id: this.id,
          params: this.installApplicationRequestParams,
        });
148
      },
149
    },
150
  };
151 152 153 154
</script>

<template>
  <div
155 156 157 158 159 160
    :class="[
      rowJsClass,
      isInstalled && 'cluster-application-installed',
      disabled && 'cluster-application-disabled'
    ]"
    class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span"
161 162 163 164 165
  >
    <div
      class="gl-responsive-table-row-layout"
      role="row"
    >
166 167
      <div
        class="table-section append-right-8 section-align-top"
168 169
        role="gridcell"
      >
170 171 172 173 174 175 176 177 178 179 180 181 182
        <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>
183
      <div
184
        class="table-section cluster-application-description section-wrap"
185 186
        role="gridcell"
      >
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
        <strong>
          <a
            v-if="titleLink"
            :href="titleLink"
            target="blank"
            rel="noopener noreferrer"
            class="js-cluster-application-title"
          >
            {{ title }}
          </a>
          <span
            v-else
            class="js-cluster-application-title"
          >
            {{ title }}
          </span>
        </strong>
204
        <slot name="description"></slot>
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
        <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">
            <li
              v-if="statusReason"
              class="js-cluster-application-status-error-message"
            >
              {{ statusReason }}
            </li>
            <li
              v-if="requestReason"
              class="js-cluster-application-request-error-message"
            >
              {{ requestReason }}
            </li>
          </ul>
        </div>
227 228
      </div>
      <div
229
        :class="{ 'section-25': showManageButton, 'section-15': !showManageButton }"
230
        class="table-section table-button-footer section-align-top"
231 232
        role="gridcell"
      >
233
        <div
234
          v-if="showManageButton"
235 236 237 238
          class="btn-group table-action-buttons"
        >
          <a
            :href="manageLink"
239
            :class="{ disabled: disabled }"
240
            class="btn"
241
          >
242
            {{ manageButtonLabel }}
243 244
          </a>
        </div>
245 246 247
        <div class="btn-group table-action-buttons">
          <loading-button
            :loading="installButtonLoading"
248
            :disabled="disabled || installButtonDisabled"
249
            :label="installButtonLabel"
250
            class="js-cluster-application-install-button"
251 252 253 254 255 256 257
            @click="installClicked"
          />
        </div>
      </div>
    </div>
  </div>
</template>