Tech debt: Creates vue component for loading icon

This commit is contained in:
Filipa Lacerda 2017-05-10 15:52:09 +00:00 committed by Phil Hughes
parent a8fb310cec
commit d1da5624d7
20 changed files with 187 additions and 105 deletions

View File

@ -2,6 +2,7 @@
import boardNewIssue from './board_new_issue'; import boardNewIssue from './board_new_issue';
import boardCard from './board_card'; import boardCard from './board_card';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
const Store = gl.issueBoards.BoardsStore; const Store = gl.issueBoards.BoardsStore;
@ -44,6 +45,7 @@ export default {
components: { components: {
boardCard, boardCard,
boardNewIssue, boardNewIssue,
loadingIcon,
}, },
methods: { methods: {
listHeight() { listHeight() {
@ -156,10 +158,7 @@ export default {
class="board-list-loading text-center" class="board-list-loading text-center"
aria-label="Loading issues" aria-label="Loading issues"
v-if="loading"> v-if="loading">
<i <loading-icon />
class="fa fa-spinner fa-spin"
aria-hidden="true">
</i>
</div> </div>
<board-new-issue <board-new-issue
:list="list" :list="list"
@ -184,12 +183,12 @@ export default {
class="board-list-count text-center" class="board-list-count text-center"
v-if="showCount" v-if="showCount"
data-id="-1"> data-id="-1">
<i
class="fa fa-spinner fa-spin" <loading-icon
aria-label="Loading more issues" v-show="list.loadingMore"
aria-hidden="true" label="Loading more issues"
v-show="list.loadingMore"> />
</i>
<span v-if="list.issues.length === list.issuesSize"> <span v-if="list.issues.length === list.issuesSize">
Showing all issues Showing all issues
</span> </span>

View File

@ -2,6 +2,7 @@
import Vue from 'vue'; import Vue from 'vue';
import queryData from '../../utils/query_data'; import queryData from '../../utils/query_data';
import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
require('./header'); require('./header');
require('./list'); require('./list');
@ -137,6 +138,7 @@ gl.issueBoards.IssuesModal = Vue.extend({
'modal-list': gl.issueBoards.ModalList, 'modal-list': gl.issueBoards.ModalList,
'modal-footer': gl.issueBoards.ModalFooter, 'modal-footer': gl.issueBoards.ModalFooter,
'empty-state': gl.issueBoards.ModalEmptyState, 'empty-state': gl.issueBoards.ModalEmptyState,
loadingIcon,
}, },
template: ` template: `
<div <div
@ -161,7 +163,7 @@ gl.issueBoards.IssuesModal = Vue.extend({
class="add-issues-list text-center" class="add-issues-list text-center"
v-if="loading || filterLoading"> v-if="loading || filterLoading">
<div class="add-issues-list-loading"> <div class="add-issues-list-loading">
<i class="fa fa-spinner fa-spin"></i> <loading-icon />
</div> </div>
</section> </section>
<modal-footer></modal-footer> <modal-footer></modal-footer>

View File

@ -6,6 +6,7 @@ import PipelineStore from '../../pipelines/stores/pipelines_store';
import eventHub from '../../pipelines/event_hub'; import eventHub from '../../pipelines/event_hub';
import EmptyState from '../../pipelines/components/empty_state.vue'; import EmptyState from '../../pipelines/components/empty_state.vue';
import ErrorState from '../../pipelines/components/error_state.vue'; import ErrorState from '../../pipelines/components/error_state.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import '../../lib/utils/common_utils'; import '../../lib/utils/common_utils';
import '../../vue_shared/vue_resource_interceptor'; import '../../vue_shared/vue_resource_interceptor';
import Poll from '../../lib/utils/poll'; import Poll from '../../lib/utils/poll';
@ -17,8 +18,6 @@ import Poll from '../../lib/utils/poll';
* We need a store to store the received environemnts. * We need a store to store the received environemnts.
* We need a service to communicate with the server. * We need a service to communicate with the server.
* *
* Necessary SVG in the table are provided as props. This should be refactored
* as soon as we have Webpack and can load them directly into JS files.
*/ */
export default Vue.component('pipelines-table', { export default Vue.component('pipelines-table', {
@ -27,6 +26,7 @@ export default Vue.component('pipelines-table', {
'pipelines-table-component': PipelinesTableComponent, 'pipelines-table-component': PipelinesTableComponent,
'error-state': ErrorState, 'error-state': ErrorState,
'empty-state': EmptyState, 'empty-state': EmptyState,
loadingIcon,
}, },
/** /**
@ -151,13 +151,12 @@ export default Vue.component('pipelines-table', {
template: ` template: `
<div class="content-list pipelines"> <div class="content-list pipelines">
<div
class="realtime-loading" <loading-icon
v-if="isLoading"> label="Loading pipelines"
<i size="3"
class="fa fa-spinner fa-spin" v-if="isLoading"
aria-hidden="true" /> />
</div>
<empty-state <empty-state
v-if="shouldRenderEmptyState" v-if="shouldRenderEmptyState"

View File

@ -1,5 +1,6 @@
<script> <script>
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
data() { data() {
@ -22,6 +23,11 @@
default: 'btn-default', default: 'btn-default',
}, },
}, },
components: {
loadingIcon,
},
methods: { methods: {
doAction() { doAction() {
this.isLoading = true; this.isLoading = true;
@ -44,11 +50,6 @@
:disabled="isLoading" :disabled="isLoading"
@click="doAction"> @click="doAction">
{{ text }} {{ text }}
<i <loading-icon v-if="isLoading" />
v-if="isLoading"
class="fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="Loading">
</i>
</button> </button>
</template> </template>

View File

@ -4,6 +4,7 @@
import DeployKeysService from '../service'; import DeployKeysService from '../service';
import DeployKeysStore from '../store'; import DeployKeysStore from '../store';
import keysPanel from './keys_panel.vue'; import keysPanel from './keys_panel.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
data() { data() {
@ -28,6 +29,7 @@
}, },
components: { components: {
keysPanel, keysPanel,
loadingIcon,
}, },
methods: { methods: {
fetchKeys() { fetchKeys() {
@ -74,15 +76,11 @@
<template> <template>
<div class="col-lg-9 col-lg-offset-3 append-bottom-default deploy-keys"> <div class="col-lg-9 col-lg-offset-3 append-bottom-default deploy-keys">
<div <loading-icon
class="text-center" v-if="isLoading && !hasKeys"
v-if="isLoading && !hasKeys"> size="2"
<i label="Loading deploy keys"
class="fa fa-spinner fa-spin fa-2x" />
aria-hidden="true"
aria-label="Loading deploy keys">
</i>
</div>
<div v-else-if="hasKeys"> <div v-else-if="hasKeys">
<keys-panel <keys-panel
title="Enabled deploy keys for this project" title="Enabled deploy keys for this project"

View File

@ -3,6 +3,7 @@
import EnvironmentsService from '../services/environments_service'; import EnvironmentsService from '../services/environments_service';
import environmentTable from './environments_table.vue'; import environmentTable from './environments_table.vue';
import EnvironmentsStore from '../stores/environments_store'; import EnvironmentsStore from '../stores/environments_store';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue'; import tablePagination from '../../vue_shared/components/table_pagination.vue';
import '../../lib/utils/common_utils'; import '../../lib/utils/common_utils';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
@ -12,6 +13,7 @@ export default {
components: { components: {
environmentTable, environmentTable,
tablePagination, tablePagination,
loadingIcon,
}, },
data() { data() {
@ -186,14 +188,11 @@ export default {
</div> </div>
<div class="content-list environments-container"> <div class="content-list environments-container">
<div <loading-icon
class="environments-list-loading text-center" label="Loading environments"
v-if="isLoading"> size="3"
v-if="isLoading"
<i />
class="fa fa-spinner fa-spin"
aria-hidden="true" />
</div>
<div <div
class="blank-state blank-state-no-icon" class="blank-state blank-state-no-icon"

View File

@ -1,6 +1,7 @@
<script> <script>
import playIconSvg from 'icons/_icon_play.svg'; import playIconSvg from 'icons/_icon_play.svg';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
props: { props: {
@ -11,6 +12,10 @@ export default {
}, },
}, },
components: {
loadingIcon,
},
data() { data() {
return { return {
playIconSvg, playIconSvg,
@ -61,10 +66,7 @@ export default {
<i <i
class="fa fa-caret-down" class="fa fa-caret-down"
aria-hidden="true"/> aria-hidden="true"/>
<i <loading-icon v-if="isLoading" />
v-if="isLoading"
class="fa fa-spinner fa-spin"
aria-hidden="true"/>
</span> </span>
</button> </button>

View File

@ -6,6 +6,7 @@
* Makes a post request when the button is clicked. * Makes a post request when the button is clicked.
*/ */
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
props: { props: {
@ -20,6 +21,10 @@ export default {
}, },
}, },
components: {
loadingIcon,
},
data() { data() {
return { return {
isLoading: false, isLoading: false,
@ -49,9 +54,6 @@ export default {
Rollback Rollback
</span> </span>
<i <loading-icon v-if="isLoading" />
v-if="isLoading"
class="fa fa-spinner fa-spin"
aria-hidden="true" />
</button> </button>
</template> </template>

View File

@ -4,6 +4,7 @@
* Used in environments table. * Used in environments table.
*/ */
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
props: { props: {
@ -19,6 +20,10 @@ export default {
}; };
}, },
components: {
loadingIcon,
},
computed: { computed: {
title() { title() {
return 'Stop'; return 'Stop';
@ -51,9 +56,6 @@ export default {
<i <i
class="fa fa-stop stop-env-icon" class="fa fa-stop stop-env-icon"
aria-hidden="true" /> aria-hidden="true" />
<i <loading-icon v-if="isLoading" />
v-if="isLoading"
class="fa fa-spinner fa-spin"
aria-hidden="true" />
</button> </button>
</template> </template>

View File

@ -3,10 +3,12 @@
* Render environments table. * Render environments table.
*/ */
import EnvironmentTableRowComponent from './environment_item.vue'; import EnvironmentTableRowComponent from './environment_item.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
components: { components: {
'environment-item': EnvironmentTableRowComponent, 'environment-item': EnvironmentTableRowComponent,
loadingIcon,
}, },
props: { props: {
@ -77,10 +79,8 @@ export default {
<template v-if="model.isFolder && model.isOpen && model.children && model.children.length > 0"> <template v-if="model.isFolder && model.isOpen && model.children && model.children.length > 0">
<tr v-if="isLoadingFolderContent"> <tr v-if="isLoadingFolderContent">
<td colspan="6" class="text-center"> <td colspan="6">
<i <loading-icon size="2" />
class="fa fa-spin fa-spinner fa-2x"
aria-hidden="true" />
</td> </td>
</tr> </tr>

View File

@ -3,6 +3,7 @@
import EnvironmentsService from '../services/environments_service'; import EnvironmentsService from '../services/environments_service';
import environmentTable from '../components/environments_table.vue'; import environmentTable from '../components/environments_table.vue';
import EnvironmentsStore from '../stores/environments_store'; import EnvironmentsStore from '../stores/environments_store';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue'; import tablePagination from '../../vue_shared/components/table_pagination.vue';
import '../../lib/utils/common_utils'; import '../../lib/utils/common_utils';
import '../../vue_shared/vue_resource_interceptor'; import '../../vue_shared/vue_resource_interceptor';
@ -11,6 +12,7 @@ export default {
components: { components: {
environmentTable, environmentTable,
tablePagination, tablePagination,
loadingIcon,
}, },
data() { data() {
@ -153,13 +155,12 @@ export default {
</div> </div>
<div class="environments-container"> <div class="environments-container">
<div
class="environments-list-loading text-center" <loading-icon
v-if="isLoading"> label="Loading environments"
<i v-if="isLoading"
class="fa fa-spinner fa-spin" size="3"
aria-hidden="true"/> />
</div>
<div <div
class="table-holder" class="table-holder"

View File

@ -3,6 +3,7 @@
/* global Flash */ /* global Flash */
import '~/flash'; import '~/flash';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
props: { props: {
@ -37,6 +38,10 @@ export default {
}, },
}, },
components: {
loadingIcon,
},
data() { data() {
return { return {
isLoading: false, isLoading: false,
@ -94,9 +99,6 @@ export default {
<i <i
:class="iconClass" :class="iconClass"
aria-hidden="true" /> aria-hidden="true" />
<i <loading-icon v-if="isLoading" />
class="fa fa-spinner fa-spin"
aria-hidden="true"
v-if="isLoading" />
</button> </button>
</template> </template>

View File

@ -5,11 +5,13 @@
import PipelineService from '../../services/pipeline_service'; import PipelineService from '../../services/pipeline_service';
import PipelineStore from '../../stores/pipeline_store'; import PipelineStore from '../../stores/pipeline_store';
import stageColumnComponent from './stage_column_component.vue'; import stageColumnComponent from './stage_column_component.vue';
import loadingIcon from '../../../vue_shared/components/loading_icon.vue';
import '../../../flash'; import '../../../flash';
export default { export default {
components: { components: {
stageColumnComponent, stageColumnComponent,
loadingIcon,
}, },
data() { data() {
@ -89,11 +91,10 @@
<div class="build-content middle-block js-pipeline-graph"> <div class="build-content middle-block js-pipeline-graph">
<div class="pipeline-visualization pipeline-graph"> <div class="pipeline-visualization pipeline-graph">
<div class="text-center"> <div class="text-center">
<i <loading-icon
v-if="isLoading" v-if="isLoading"
class="loading-icon fa fa-spin fa-spinner fa-3x" size="3"
aria-label="Loading" />
aria-hidden="true" />
</div> </div>
<ul <ul

View File

@ -3,6 +3,7 @@
import '~/flash'; import '~/flash';
import playIconSvg from 'icons/_icon_play.svg'; import playIconSvg from 'icons/_icon_play.svg';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import loadingIconComponent from '../../vue_shared/components/loading_icon.vue';
export default { export default {
props: { props: {
@ -17,6 +18,10 @@ export default {
}, },
}, },
components: {
loadingIconComponent,
},
data() { data() {
return { return {
playIconSvg, playIconSvg,
@ -65,10 +70,7 @@ export default {
<i <i
class="fa fa-caret-down" class="fa fa-caret-down"
aria-hidden="true" /> aria-hidden="true" />
<i <loading-icon v-if="isLoading" />
v-if="isLoading"
class="fa fa-spinner fa-spin"
aria-hidden="true" />
</button> </button>
<ul class="dropdown-menu dropdown-menu-align-right"> <ul class="dropdown-menu dropdown-menu-align-right">

View File

@ -15,6 +15,7 @@
/* global Flash */ /* global Flash */
import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons'; import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
props: { props: {
@ -38,6 +39,10 @@ export default {
}; };
}, },
components: {
loadingIcon,
},
updated() { updated() {
if (this.dropdownContent.length > 0) { if (this.dropdownContent.length > 0) {
this.stopDropdownClickPropagation(); this.stopDropdownClickPropagation();
@ -153,15 +158,7 @@ export default {
:class="dropdownClass" :class="dropdownClass"
class="js-builds-dropdown-list scrollable-menu"> class="js-builds-dropdown-list scrollable-menu">
<div <loading-icon v-if="isLoading"/>
class="text-center"
v-if="isLoading">
<i
class="fa fa-spin fa-spinner"
aria-hidden="true"
aria-label="Loading">
</i>
</div>
<ul <ul
v-else v-else

View File

@ -7,6 +7,7 @@ import EmptyState from './components/empty_state.vue';
import ErrorState from './components/error_state.vue'; import ErrorState from './components/error_state.vue';
import NavigationTabs from './components/navigation_tabs'; import NavigationTabs from './components/navigation_tabs';
import NavigationControls from './components/nav_controls'; import NavigationControls from './components/nav_controls';
import loadingIcon from '../vue_shared/components/loading_icon.vue';
import Poll from '../lib/utils/poll'; import Poll from '../lib/utils/poll';
export default { export default {
@ -24,6 +25,7 @@ export default {
'error-state': ErrorState, 'error-state': ErrorState,
'navigation-tabs': NavigationTabs, 'navigation-tabs': NavigationTabs,
'navigation-controls': NavigationControls, 'navigation-controls': NavigationControls,
loadingIcon,
}, },
data() { data() {
@ -244,13 +246,11 @@ export default {
<div class="content-list pipelines"> <div class="content-list pipelines">
<div <loading-icon
class="realtime-loading" label="Loading Pipelines"
v-if="isLoading"> size="3"
<i v-if="isLoading"
class="fa fa-spinner fa-spin" />
aria-hidden="true" />
</div>
<empty-state <empty-state
v-if="shouldRenderEmptyState" v-if="shouldRenderEmptyState"

View File

@ -0,0 +1,33 @@
<script>
export default {
props: {
label: {
type: String,
required: false,
default: 'Loading',
},
size: {
type: String,
required: false,
default: '1',
},
},
computed: {
cssClass() {
return `fa-${this.size}x`;
},
},
};
</script>
<template>
<div class="text-center">
<i
class="fa fa-spin fa-spinner"
:class="cssClass"
aria-hidden="true"
:aria-label="label">
</i>
</div>
</template>

View File

@ -5,11 +5,6 @@
} }
} }
.environments-list-loading {
width: 100%;
font-size: 34px;
}
.environments-folder-name { .environments-folder-name {
font-weight: normal; font-weight: normal;
padding-top: 20px; padding-top: 20px;

View File

@ -1,10 +1,4 @@
.pipelines { .pipelines {
.realtime-loading {
font-size: 40px;
text-align: center;
margin: 0 auto;
}
.stage { .stage {
max-width: 90px; max-width: 90px;
width: 90px; width: 90px;

View File

@ -0,0 +1,53 @@
import Vue from 'vue';
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
describe('Loading Icon Component', () => {
let LoadingIconComponent;
beforeEach(() => {
LoadingIconComponent = Vue.extend(loadingIcon);
});
it('should render a spinner font awesome icon', () => {
const component = new LoadingIconComponent().$mount();
expect(
component.$el.querySelector('i').getAttribute('class'),
).toEqual('fa fa-spin fa-spinner fa-1x');
expect(component.$el.tagName).toEqual('DIV');
expect(component.$el.classList.contains('text-center')).toEqual(true);
});
it('should render accessibility attributes', () => {
const component = new LoadingIconComponent().$mount();
const icon = component.$el.querySelector('i');
expect(icon.getAttribute('aria-hidden')).toEqual('true');
expect(icon.getAttribute('aria-label')).toEqual('Loading');
});
it('should render the provided label', () => {
const component = new LoadingIconComponent({
propsData: {
label: 'This is a loading icon',
},
}).$mount();
expect(
component.$el.querySelector('i').getAttribute('aria-label'),
).toEqual('This is a loading icon');
});
it('should render the provided size', () => {
const component = new LoadingIconComponent({
propsData: {
size: '2',
},
}).$mount();
expect(
component.$el.querySelector('i').classList.contains('fa-2x'),
).toEqual(true);
});
});