diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-12-03 22:00:25 +0100 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-12-03 22:00:25 +0100 |
commit | f1cce0cba88089442194b53833b6b5a0ca96e8e4 (patch) | |
tree | a62185a58ff201741dbfee7f7914f1ffe038b60c /app/assets | |
parent | 5ea53d2e8179e3a1e3d4b991a91d506ce13c3fca (diff) | |
parent | 363c57468dc6f656c6c345f0b9eda32029571201 (diff) | |
download | gitlab-ce-f1cce0cba88089442194b53833b6b5a0ca96e8e4.tar.gz |
Merge remote-tracking branch 'origin/list-multiple-clusters' into cluster-page-with-list-clusters
Diffstat (limited to 'app/assets')
12 files changed, 300 insertions, 143 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index cdb5c430aa9..2cfd6179a25 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -150,8 +150,8 @@ export default class Clusters { } toggle() { - this.toggleButton.classList.toggle('checked'); - this.toggleInput.setAttribute('value', this.toggleButton.classList.contains('checked').toString()); + this.toggleButton.classList.toggle('is-checked'); + this.toggleInput.setAttribute('value', this.toggleButton.classList.contains('is-checked').toString()); } showToken() { diff --git a/app/assets/javascripts/clusters/clusters_index.js b/app/assets/javascripts/clusters/clusters_index.js new file mode 100644 index 00000000000..3fd188a8770 --- /dev/null +++ b/app/assets/javascripts/clusters/clusters_index.js @@ -0,0 +1,57 @@ +import Flash from '../flash'; +import { s__ } from '../locale'; +import ClustersService from './services/clusters_service'; +/** + * Toggles loading and disabled classes. + * @param {HTMLElement} button + */ +const toggleLoadingButton = (button) => { + if (button.getAttribute('disabled')) { + button.removeAttribute('disabled'); + } else { + button.setAttribute('disabled', true); + } + + button.classList.toggle('is-loading'); +}; + +/** + * Toggles checked class for the given button + * @param {HTMLElement} button + */ +const toggleValue = (button) => { + button.classList.toggle('is-checked'); +}; + +/** + * Handles toggle buttons in the cluster's table. + * + * When the user clicks the toggle button for each cluster, it: + * - toggles the button + * - shows a loding and disabled state + * - Makes a put request to the given endpoint + * Once we receive the response, either: + * 1) Show updated status in case of successfull response + * 2) Show initial status in case of failed response + */ +export default function setClusterTableToggles() { + document.querySelectorAll('.js-toggle-cluster-list') + .forEach(button => button.addEventListener('click', (e) => { + const toggleButton = e.currentTarget; + const value = toggleButton.classList.contains('checked').toString(); + const endpoint = toggleButton.getAttribute('data-endpoint'); + + toggleValue(toggleButton); + toggleLoadingButton(toggleButton); + + ClustersService.updateCluster(endpoint, { cluster: { enabled: value } }) + .then(() => { + toggleLoadingButton(toggleButton); + }) + .catch(() => { + toggleLoadingButton(toggleButton); + toggleValue(toggleButton); + Flash(s__('ClusterIntegration|Something went wrong on our end.')); + }); + })); +} diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js index ce14c9a9945..755c2981c2e 100644 --- a/app/assets/javascripts/clusters/services/clusters_service.js +++ b/app/assets/javascripts/clusters/services/clusters_service.js @@ -17,4 +17,8 @@ export default class ClusterService { installApplication(appId) { return axios.post(this.appInstallEndpointMap[appId]); } + + static updateCluster(endpoint, data) { + return axios.put(endpoint, data); + } } diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index a21c92f24d6..7793140e608 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -558,7 +558,15 @@ import ProjectVariables from './project_variables'; import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle') .then(cluster => new cluster.default()) // eslint-disable-line new-cap .catch((err) => { - Flash(s__('ClusterIntegration|Problem setting up the cluster JavaScript')); + Flash(s__('ClusterIntegration|Problem setting up the cluster')); + throw err; + }); + break; + case 'projects:clusters:index': + import(/* webpackChunkName: "clusters_index" */ './clusters/clusters_index') + .then(clusterIndex => clusterIndex.default()) + .catch((err) => { + Flash(s__('ClusterIntegration|Problem setting up the clusters list')); throw err; }); break; diff --git a/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue b/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue index 80c5d39f736..8fce4c63872 100644 --- a/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue +++ b/app/assets/javascripts/projects/permissions/components/project_feature_setting.vue @@ -1,5 +1,5 @@ <script> -import projectFeatureToggle from './project_feature_toggle.vue'; +import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue'; export default { props: { diff --git a/app/assets/javascripts/projects/permissions/components/project_feature_toggle.vue b/app/assets/javascripts/projects/permissions/components/project_feature_toggle.vue deleted file mode 100644 index 2403c60186a..00000000000 --- a/app/assets/javascripts/projects/permissions/components/project_feature_toggle.vue +++ /dev/null @@ -1,51 +0,0 @@ -<script> -export default { - props: { - name: { - type: String, - required: false, - default: '', - }, - value: { - type: Boolean, - required: true, - }, - disabledInput: { - type: Boolean, - required: false, - default: false, - }, - }, - - model: { - prop: 'value', - event: 'change', - }, - - methods: { - toggleFeature() { - if (!this.disabledInput) this.$emit('change', !this.value); - }, - }, -}; -</script> - -<template> - <label class="toggle-wrapper"> - <input - v-if="name" - type="hidden" - :name="name" - :value="value" - /> - <button - type="button" - aria-label="Toggle" - class="project-feature-toggle" - data-enabled-text="Enabled" - data-disabled-text="Disabled" - :class="{ checked: value, disabled: disabledInput }" - @click="toggleFeature" - /> - </label> -</template> diff --git a/app/assets/javascripts/projects/permissions/components/settings_panel.vue b/app/assets/javascripts/projects/permissions/components/settings_panel.vue index 326d9105666..639429baf26 100644 --- a/app/assets/javascripts/projects/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/projects/permissions/components/settings_panel.vue @@ -1,6 +1,6 @@ <script> import projectFeatureSetting from './project_feature_setting.vue'; -import projectFeatureToggle from './project_feature_toggle.vue'; +import projectFeatureToggle from '../../../vue_shared/components/toggle_button.vue'; import projectSettingRow from './project_setting_row.vue'; import { visibilityOptions, visibilityLevelDescriptions } from '../constants'; import { toggleHiddenClassBySelector } from '../external'; diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue new file mode 100644 index 00000000000..ddc9ddbc3a3 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue @@ -0,0 +1,77 @@ +<script> + import loadingIcon from './loading_icon.vue'; + + export default { + props: { + name: { + type: String, + required: false, + default: '', + }, + value: { + type: Boolean, + required: true, + }, + disabledInput: { + type: Boolean, + required: false, + default: false, + }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, + enabledText: { + type: String, + required: false, + default: 'Enabled', + }, + disabledText: { + type: String, + required: false, + default: 'Disabled', + }, + }, + + components: { + loadingIcon, + }, + + model: { + prop: 'value', + event: 'change', + }, + + methods: { + toggleFeature() { + if (!this.disabledInput) this.$emit('change', !this.value); + }, + }, + }; +</script> + +<template> + <label class="toggle-wrapper"> + <input + type="hidden" + :name="name" + :value="value" + /> + <button + type="button" + aria-label="Toggle" + class="project-feature-toggle" + :data-enabled-text="enabledText" + :data-disabled-text="disabledText" + :class="{ + 'is-checked': value, + 'is-disabled': disabledInput, + 'is-loading': isLoading + }" + @click="toggleFeature" + > + <loadingIcon class="loading-icon" /> + </button> + </label> +</template> diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index 66212be1b8f..43b16d3cf7d 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -44,6 +44,7 @@ @import "framework/tabs"; @import "framework/timeline"; @import "framework/tooltips"; +@import "framework/toggle"; @import "framework/typography"; @import "framework/zen"; @import "framework/blank"; diff --git a/app/assets/stylesheets/framework/toggle.scss b/app/assets/stylesheets/framework/toggle.scss new file mode 100644 index 00000000000..71765da3908 --- /dev/null +++ b/app/assets/stylesheets/framework/toggle.scss @@ -0,0 +1,138 @@ +/** +* Toggle button +* +* @usage +* ### Active and Inactive text should be provided as data attributes: +* <button type="button" class="project-feature-toggle" data-enabled-text="Enabled" data-disabled-text="Disabled"> +* <i class="fa fa-spinner fa-spin loading-icon hidden"></i> +* </button> + +* ### Checked should have `is-checked` class +* <button type="button" class="project-feature-toggle is-checked" data-enabled-text="Enabled" data-disabled-text="Disabled"> +* <i class="fa fa-spinner fa-spin loading-icon hidden"></i> +* </button> + +* ### Disabled should have `is-disabled` class +* <button type="button" class="project-feature-toggle is-disabled" data-enabled-text="Enabled" data-disabled-text="Disabled" disabled="true"> +* <i class="fa fa-spinner fa-spin loading-icon hidden"></i> +* </button> + +* ### Loading should have `is-loading` and an icon with `loading-icon` class +* <button type="button" class="project-feature-toggle is-loading" data-enabled-text="Enabled" data-disabled-text="Disabled"> +* <i class="fa fa-spinner fa-spin loading-icon"></i> +* </button> +*/ +.project-feature-toggle { + position: relative; + border: 0; + outline: 0; + display: block; + width: 100px; + height: 24px; + cursor: pointer; + user-select: none; + background: $feature-toggle-color-disabled; + border-radius: 12px; + padding: 3px; + transition: all .4s ease; + + &::selection, + &::before::selection, + &::after::selection { + background: none; + } + + &::before { + color: $feature-toggle-text-color; + font-size: 12px; + line-height: 24px; + position: absolute; + top: 0; + left: 25px; + right: 5px; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + animation: animate-disabled .2s ease-in; + content: attr(data-disabled-text); + } + + &::after { + position: relative; + display: block; + content: ""; + width: 22px; + height: 18px; + left: 0; + border-radius: 9px; + background: $feature-toggle-color; + transition: all .2s ease; + } + + .loading-icon { + display: none; + font-size: 12px; + color: $white-light; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + } + + &.is-loading { + &::before { + display: none; + } + + .loading-icon { + display: block; + + &::before { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } + } + + &.is-checked { + background: $feature-toggle-color-enabled; + + &::before { + left: 5px; + right: 25px; + animation: animate-enabled .2s ease-in; + content: attr(data-enabled-text); + } + + &::after { + left: calc(100% - 22px); + } + } + + &.is-disabled { + opacity: 0.4; + cursor: not-allowed; + } + + @media (max-width: $screen-xs-min) { + width: 50px; + + &::before, + &.is-checked::before { + display: none; + } + } + + @keyframes animate-enabled { + 0%, 35% { opacity: 0; } + 100% { opacity: 1; } + } + + @keyframes animate-disabled { + 0%, 35% { opacity: 0; } + 100% { opacity: 1; } + } +} diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss index 83e211d6086..b5ac6db04ad 100644 --- a/app/assets/stylesheets/pages/clusters.scss +++ b/app/assets/stylesheets/pages/clusters.scss @@ -14,3 +14,13 @@ } @include new-style-dropdown('.clusters-dropdown '); + +.clusters-container { + .nav-bar-right { + padding: $gl-padding-top $gl-padding; + } + + .empty-state .svg-content img { + width: 145px; + } +} diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 2dc0c288a6d..2856af37f8d 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -126,93 +126,6 @@ } } -.project-feature-toggle { - position: relative; - border: 0; - outline: 0; - display: block; - width: 100px; - height: 24px; - cursor: pointer; - user-select: none; - background: $feature-toggle-color-disabled; - border-radius: 12px; - padding: 3px; - transition: all .4s ease; - - &::selection, - &::before::selection, - &::after::selection { - background: none; - } - - &::before { - color: $feature-toggle-text-color; - font-size: 12px; - line-height: 24px; - position: absolute; - top: 0; - left: 25px; - right: 5px; - text-align: center; - overflow: hidden; - text-overflow: ellipsis; - animation: animate-disabled .2s ease-in; - content: attr(data-disabled-text); - } - - &::after { - position: relative; - display: block; - content: ""; - width: 22px; - height: 18px; - left: 0; - border-radius: 9px; - background: $feature-toggle-color; - transition: all .2s ease; - } - - &.checked { - background: $feature-toggle-color-enabled; - - &::before { - left: 5px; - right: 25px; - animation: animate-enabled .2s ease-in; - content: attr(data-enabled-text); - } - - &::after { - left: calc(100% - 22px); - } - } - - &.disabled { - opacity: 0.4; - cursor: not-allowed; - } - - @media (max-width: $screen-xs-min) { - width: 50px; - - &::before, - &.checked::before { - display: none; - } - } - - @keyframes animate-enabled { - 0%, 35% { opacity: 0; } - 100% { opacity: 1; } - } - - @keyframes animate-disabled { - 0%, 35% { opacity: 0; } - 100% { opacity: 1; } - } -} - .project-home-panel, .group-home-panel { padding-top: 24px; |