Commit 5295f23b authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'add-shared-vue-loading-button' into 'master'

Add loading button

See merge request gitlab-org/gitlab-ce!14883
parents 02e283ff 69be3ce8
<script>
/* This is a re-usable vue component for rendering a button
that will probably be sending off ajax requests and need
to show the loading status by setting the `loading` option.
This can also be used for initial page load when you don't
know the action of the button yet by setting
`loading: true, label: undefined`.
Sample configuration:
<loading-button
:loading="true"
:label="Hello"
@click="..."
/>
*/
import loadingIcon from './loading_icon.vue';
export default {
props: {
loading: {
type: Boolean,
required: false,
default: false,
},
label: {
type: String,
required: false,
},
},
components: {
loadingIcon,
},
methods: {
onClick(e) {
this.$emit('click', e);
},
},
};
</script>
<template>
<button
class="btn btn-align-content"
@click="onClick"
type="button"
:disabled="loading"
>
<transition name="fade">
<loading-icon
v-if="loading"
:inline="true"
class="js-loading-button-icon"
:class="{
'append-right-5': label
}"
/>
</transition>
<transition name="fade">
<span
v-if="label"
class="js-loading-button-label"
>
{{ label }}
</span>
</transition>
</button>
</template>
......@@ -5,6 +5,7 @@
@import "framework/layout";
@import "framework/animations";
@import "framework/vue_transitions";
@import "framework/avatar";
@import "framework/asciidoctor";
@import "framework/banner";
......
......@@ -292,6 +292,11 @@
}
}
.btn-align-content {
display: flex;
align-items: center;
}
.btn-group {
&.btn-grouped {
@include btn-with-margin;
......
.fade-enter-active,
.fade-leave-active {
transition: opacity $sidebar-transition-duration $general-hover-transition-curve;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity $sidebar-transition-duration;
}
.monaco-loader {
position: absolute;
top: 0;
......
---
title: Add loading button for new UX paradigm
merge_request: 14883
author:
type: added
import Vue from 'vue';
import loadingButton from '~/vue_shared/components/loading_button.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
const LABEL = 'Hello';
describe('LoadingButton', function () {
let vm;
let LoadingButton;
beforeEach(() => {
LoadingButton = Vue.extend(loadingButton);
});
afterEach(() => {
vm.$destroy();
});
describe('loading spinner', () => {
it('shown when loading', () => {
vm = mountComponent(LoadingButton, {
loading: true,
});
expect(vm.$el.querySelector('.js-loading-button-icon')).toBeDefined();
});
});
describe('disabled state', () => {
it('disabled when loading', () => {
vm = mountComponent(LoadingButton, {
loading: true,
});
expect(vm.$el.disabled).toEqual(true);
});
it('not disabled when normal', () => {
vm = mountComponent(LoadingButton, {
loading: false,
});
expect(vm.$el.disabled).toEqual(false);
});
});
describe('label', () => {
it('shown when normal', () => {
vm = mountComponent(LoadingButton, {
loading: false,
label: LABEL,
});
const label = vm.$el.querySelector('.js-loading-button-label');
expect(label.textContent.trim()).toEqual(LABEL);
});
it('shown when loading', () => {
vm = mountComponent(LoadingButton, {
loading: true,
label: LABEL,
});
const label = vm.$el.querySelector('.js-loading-button-label');
expect(label.textContent.trim()).toEqual(LABEL);
});
});
describe('click callback prop', () => {
it('calls given callback when normal', () => {
vm = mountComponent(LoadingButton, {
loading: false,
});
spyOn(vm, '$emit');
vm.$el.click();
expect(vm.$emit).toHaveBeenCalledWith('click', jasmine.any(Object));
});
it('does not call given callback when disabled because of loading', () => {
vm = mountComponent(LoadingButton, {
loading: true,
indeterminate: true,
});
spyOn(vm, '$emit');
vm.$el.click();
expect(vm.$emit).not.toHaveBeenCalled();
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment