debian-mirror-gitlab/app/assets/javascripts/pipelines/components/pipelines.vue

370 lines
10 KiB
Vue
Raw Normal View History

2017-09-10 17:25:29 +05:30
<script>
2018-03-17 18:26:18 +05:30
import _ from 'underscore';
2018-03-27 19:54:05 +05:30
import { __, sprintf, s__ } from '../../locale';
2018-05-09 12:01:36 +05:30
import createFlash from '../../flash';
2017-09-10 17:25:29 +05:30
import PipelinesService from '../services/pipelines_service';
import pipelinesMixin from '../mixins/pipelines';
2018-03-27 19:54:05 +05:30
import TablePagination from '../../vue_shared/components/table_pagination.vue';
import NavigationTabs from '../../vue_shared/components/navigation_tabs.vue';
import NavigationControls from './nav_controls.vue';
2018-10-15 14:42:47 +05:30
import { getParameterByName } from '../../lib/utils/common_utils';
2018-03-17 18:26:18 +05:30
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
2017-09-10 17:25:29 +05:30
export default {
components: {
2018-03-27 19:54:05 +05:30
TablePagination,
NavigationTabs,
NavigationControls,
2017-09-10 17:25:29 +05:30
},
2018-10-15 14:42:47 +05:30
mixins: [pipelinesMixin, CIPaginationMixin],
2018-03-17 18:26:18 +05:30
props: {
store: {
type: Object,
required: true,
},
// Can be rendered in 3 different places, with some visual differences
// Accepts root | child
// `root` -> main view
// `child` -> rendered inside MR or Commit View
viewType: {
type: String,
required: false,
default: 'root',
},
2018-03-27 19:54:05 +05:30
endpoint: {
type: String,
required: true,
},
helpPagePath: {
type: String,
required: true,
},
emptyStateSvgPath: {
type: String,
required: true,
},
errorStateSvgPath: {
type: String,
required: true,
},
noPipelinesSvgPath: {
type: String,
required: true,
},
autoDevopsPath: {
type: String,
required: true,
},
hasGitlabCi: {
type: Boolean,
required: true,
},
canCreatePipeline: {
type: Boolean,
required: true,
},
ciLintPath: {
type: String,
required: false,
default: null,
},
resetCachePath: {
type: String,
required: false,
default: null,
},
newPipelinePath: {
type: String,
required: false,
default: null,
},
2018-03-17 18:26:18 +05:30
},
2017-09-10 17:25:29 +05:30
data() {
return {
2018-03-27 19:54:05 +05:30
// Start with loading state to avoid a glitch when the empty state will be rendered
isLoading: true,
2017-09-10 17:25:29 +05:30
state: this.store.state,
2018-03-17 18:26:18 +05:30
scope: getParameterByName('scope') || 'all',
page: getParameterByName('page') || '1',
requestData: {},
2018-05-09 12:01:36 +05:30
isResetCacheButtonLoading: false,
2017-09-10 17:25:29 +05:30
};
},
2018-03-27 19:54:05 +05:30
stateMap: {
// with tabs
loading: 'loading',
tableList: 'tableList',
error: 'error',
emptyTab: 'emptyTab',
2017-09-10 17:25:29 +05:30
2018-03-27 19:54:05 +05:30
// without tabs
emptyState: 'emptyState',
},
scopes: {
all: 'all',
pending: 'pending',
running: 'running',
finished: 'finished',
branches: 'branches',
tags: 'tags',
},
computed: {
2017-09-10 17:25:29 +05:30
/**
2018-03-27 19:54:05 +05:30
* `hasGitlabCi` handles both internal and external CI.
* The order on which the checks are made in this method is
* important to guarantee we handle all the corner cases.
*/
stateToRender() {
const { stateMap } = this.$options;
if (this.isLoading) {
return stateMap.loading;
}
if (this.hasError) {
return stateMap.error;
}
if (this.state.pipelines.length) {
return stateMap.tableList;
}
if ((this.scope !== 'all' && this.scope !== null) || this.hasGitlabCi) {
return stateMap.emptyTab;
}
return stateMap.emptyState;
2017-09-10 17:25:29 +05:30
},
/**
2018-03-27 19:54:05 +05:30
* Tabs are rendered in all states except empty state.
* They are not rendered before the first request to avoid a flicker on first load.
2017-09-10 17:25:29 +05:30
*/
2018-03-27 19:54:05 +05:30
shouldRenderTabs() {
const { stateMap } = this.$options;
2018-10-15 14:42:47 +05:30
return (
this.hasMadeRequest &&
[stateMap.loading, stateMap.tableList, stateMap.error, stateMap.emptyTab].includes(
this.stateToRender,
)
);
2017-09-10 17:25:29 +05:30
},
2018-03-27 19:54:05 +05:30
shouldRenderButtons() {
2018-10-15 14:42:47 +05:30
return (
(this.newPipelinePath || this.resetCachePath || this.ciLintPath) && this.shouldRenderTabs
);
2017-09-10 17:25:29 +05:30
},
2018-03-27 19:54:05 +05:30
2017-09-10 17:25:29 +05:30
shouldRenderPagination() {
2018-10-15 14:42:47 +05:30
return (
!this.isLoading &&
2017-09-10 17:25:29 +05:30
this.state.pipelines.length &&
2018-10-15 14:42:47 +05:30
this.state.pageInfo.total > this.state.pageInfo.perPage
);
2017-09-10 17:25:29 +05:30
},
2018-03-27 19:54:05 +05:30
emptyTabMessage() {
const { scopes } = this.$options;
const possibleScopes = [scopes.pending, scopes.running, scopes.finished];
if (possibleScopes.includes(this.scope)) {
return sprintf(s__('Pipelines|There are currently no %{scope} pipelines.'), {
scope: this.scope,
});
}
return s__('Pipelines|There are currently no pipelines.');
2017-09-10 17:25:29 +05:30
},
2018-03-17 18:26:18 +05:30
tabs() {
const { count } = this.state;
2018-03-27 19:54:05 +05:30
const { scopes } = this.$options;
2018-03-17 18:26:18 +05:30
return [
{
2018-03-27 19:54:05 +05:30
name: __('All'),
scope: scopes.all,
2018-03-17 18:26:18 +05:30
count: count.all,
isActive: this.scope === 'all',
},
{
2018-03-27 19:54:05 +05:30
name: __('Pending'),
scope: scopes.pending,
2018-03-17 18:26:18 +05:30
count: count.pending,
isActive: this.scope === 'pending',
},
{
2018-03-27 19:54:05 +05:30
name: __('Running'),
scope: scopes.running,
2018-03-17 18:26:18 +05:30
count: count.running,
isActive: this.scope === 'running',
},
{
2018-03-27 19:54:05 +05:30
name: __('Finished'),
scope: scopes.finished,
2018-03-17 18:26:18 +05:30
count: count.finished,
isActive: this.scope === 'finished',
},
{
2018-03-27 19:54:05 +05:30
name: __('Branches'),
scope: scopes.branches,
2018-03-17 18:26:18 +05:30
isActive: this.scope === 'branches',
},
{
2018-03-27 19:54:05 +05:30
name: __('Tags'),
scope: scopes.tags,
2018-03-17 18:26:18 +05:30
isActive: this.scope === 'tags',
},
];
2017-09-10 17:25:29 +05:30
},
},
created() {
this.service = new PipelinesService(this.endpoint);
2018-03-17 18:26:18 +05:30
this.requestData = { page: this.page, scope: this.scope };
2017-09-10 17:25:29 +05:30
},
methods: {
2018-03-17 18:26:18 +05:30
successCallback(resp) {
2018-10-15 14:42:47 +05:30
// Because we are polling & the user is interacting verify if the response received
// matches the last request made
if (_.isEqual(resp.config.params, this.requestData)) {
this.store.storeCount(resp.data.count);
this.store.storePagination(resp.headers);
this.setCommonData(resp.data.pipelines);
}
2018-03-17 18:26:18 +05:30
},
2017-09-10 17:25:29 +05:30
/**
2018-03-17 18:26:18 +05:30
* Handles URL and query parameter changes.
* When the user uses the pagination or the tabs,
* - update URL
* - Make API request to the server with new parameters
* - Update the polling function
* - Update the internal state
2017-09-10 17:25:29 +05:30
*/
2018-03-17 18:26:18 +05:30
updateContent(parameters) {
this.updateInternalState(parameters);
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
// fetch new data
2018-10-15 14:42:47 +05:30
return this.service
.getPipelines(this.requestData)
.then(response => {
2018-03-17 18:26:18 +05:30
this.isLoading = false;
this.successCallback(response);
2017-09-10 17:25:29 +05:30
2018-03-17 18:26:18 +05:30
// restart polling
this.poll.restart({ data: this.requestData });
})
.catch(() => {
this.isLoading = false;
this.errorCallback();
// restart polling
2018-03-27 19:54:05 +05:30
this.poll.restart({ data: this.requestData });
2018-03-17 18:26:18 +05:30
});
2017-09-10 17:25:29 +05:30
},
2018-05-09 12:01:36 +05:30
handleResetRunnersCache(endpoint) {
this.isResetCacheButtonLoading = true;
2018-10-15 14:42:47 +05:30
this.service
.postAction(endpoint)
2018-05-09 12:01:36 +05:30
.then(() => {
this.isResetCacheButtonLoading = false;
2018-10-15 14:42:47 +05:30
createFlash(s__('Pipelines|Project cache successfully reset.'), 'notice');
2018-05-09 12:01:36 +05:30
})
.catch(() => {
this.isResetCacheButtonLoading = false;
createFlash(s__('Pipelines|Something went wrong while cleaning runners cache.'));
});
},
2017-09-10 17:25:29 +05:30
},
};
</script>
<template>
2018-03-17 18:26:18 +05:30
<div class="pipelines-container">
2017-09-10 17:25:29 +05:30
<div
class="top-area scrolling-tabs-container inner-page-scroll-tabs"
2018-03-27 19:54:05 +05:30
v-if="shouldRenderTabs || shouldRenderButtons"
2018-03-17 18:26:18 +05:30
>
2017-09-10 17:25:29 +05:30
<div class="fade-left">
<i
class="fa fa-angle-left"
2018-03-27 19:54:05 +05:30
aria-hidden="true"
>
2017-09-10 17:25:29 +05:30
</i>
</div>
<div class="fade-right">
<i
class="fa fa-angle-right"
2018-03-27 19:54:05 +05:30
aria-hidden="true"
>
2017-09-10 17:25:29 +05:30
</i>
</div>
2018-03-17 18:26:18 +05:30
2017-09-10 17:25:29 +05:30
<navigation-tabs
2018-03-27 19:54:05 +05:30
v-if="shouldRenderTabs"
2018-03-17 18:26:18 +05:30
:tabs="tabs"
@onChangeTab="onChangeTab"
scope="pipelines"
/>
2017-09-10 17:25:29 +05:30
<navigation-controls
2018-03-27 19:54:05 +05:30
v-if="shouldRenderButtons"
2017-09-10 17:25:29 +05:30
:new-pipeline-path="newPipelinePath"
2018-03-17 18:26:18 +05:30
:reset-cache-path="resetCachePath"
:ci-lint-path="ciLintPath"
2018-05-09 12:01:36 +05:30
@resetRunnersCache="handleResetRunnersCache"
:is-reset-cache-button-loading="isResetCacheButtonLoading"
2018-03-17 18:26:18 +05:30
/>
2017-09-10 17:25:29 +05:30
</div>
<div class="content-list pipelines">
<loading-icon
2018-03-27 19:54:05 +05:30
v-if="stateToRender === $options.stateMap.loading"
:label="s__('Pipelines|Loading Pipelines')"
2017-09-10 17:25:29 +05:30
size="3"
2018-03-17 18:26:18 +05:30
class="prepend-top-20"
/>
2017-09-10 17:25:29 +05:30
<empty-state
2018-03-27 19:54:05 +05:30
v-else-if="stateToRender === $options.stateMap.emptyState"
2017-09-10 17:25:29 +05:30
:help-page-path="helpPagePath"
2018-03-17 18:26:18 +05:30
:empty-state-svg-path="emptyStateSvgPath"
2018-03-27 19:54:05 +05:30
:can-set-ci="canCreatePipeline"
2018-03-17 18:26:18 +05:30
/>
2017-09-10 17:25:29 +05:30
2018-03-27 19:54:05 +05:30
<svg-blank-state
v-else-if="stateToRender === $options.stateMap.error"
:svg-path="errorStateSvgPath"
:message="s__(`Pipelines|There was an error fetching the pipelines.
Try again in a few moments or contact your support team.`)"
2018-03-17 18:26:18 +05:30
/>
2017-09-10 17:25:29 +05:30
2018-03-27 19:54:05 +05:30
<svg-blank-state
v-else-if="stateToRender === $options.stateMap.emptyTab"
:svg-path="noPipelinesSvgPath"
:message="emptyTabMessage"
/>
2017-09-10 17:25:29 +05:30
<div
class="table-holder"
2018-03-27 19:54:05 +05:30
v-else-if="stateToRender === $options.stateMap.tableList"
2018-03-17 18:26:18 +05:30
>
2017-09-10 17:25:29 +05:30
<pipelines-table-component
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
2018-03-17 18:26:18 +05:30
:auto-devops-help-path="autoDevopsPath"
:view-type="viewType"
/>
2017-09-10 17:25:29 +05:30
</div>
<table-pagination
v-if="shouldRenderPagination"
2018-03-17 18:26:18 +05:30
:change="onChangePage"
:page-info="state.pageInfo"
/>
2017-09-10 17:25:29 +05:30
</div>
</div>
</template>