Prettifies pipeline's javascript code
This commit is contained in:
parent
07de43a7e0
commit
eb2de72c69
|
@ -1,18 +1,18 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'PipelinesSvgState',
|
||||
props: {
|
||||
svgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
message: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
name: 'PipelinesSvgState',
|
||||
props: {
|
||||
svgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
|
||||
message: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'PipelinesEmptyState',
|
||||
props: {
|
||||
helpPagePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
emptyStateSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
canSetCi: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
export default {
|
||||
name: 'PipelinesEmptyState',
|
||||
props: {
|
||||
helpPagePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
emptyStateSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
canSetCi: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="row empty-state js-empty-state">
|
||||
|
|
|
@ -41,7 +41,6 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -67,7 +66,8 @@ export default {
|
|||
|
||||
this.isDisabled = true;
|
||||
|
||||
axios.post(`${this.link}.json`)
|
||||
axios
|
||||
.post(`${this.link}.json`)
|
||||
.then(() => {
|
||||
this.isDisabled = false;
|
||||
this.$emit('pipelineActionRequestComplete');
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
<script>
|
||||
import ciIcon from '../../../vue_shared/components/ci_icon.vue';
|
||||
import ciIcon from '../../../vue_shared/components/ci_icon.vue';
|
||||
|
||||
/**
|
||||
* Component that renders both the CI icon status and the job name.
|
||||
* Used in
|
||||
* - Badge component
|
||||
* - Dropdown badge components
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
ciIcon,
|
||||
/**
|
||||
* Component that renders both the CI icon status and the job name.
|
||||
* Used in
|
||||
* - Badge component
|
||||
* - Dropdown badge components
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
ciIcon,
|
||||
},
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
status: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
status: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<span class="ci-job-name-component">
|
||||
|
|
|
@ -1,81 +1,81 @@
|
|||
<script>
|
||||
import ciHeader from '../../vue_shared/components/header_ci_component.vue';
|
||||
import eventHub from '../event_hub';
|
||||
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
|
||||
import ciHeader from '../../vue_shared/components/header_ci_component.vue';
|
||||
import eventHub from '../event_hub';
|
||||
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
|
||||
|
||||
export default {
|
||||
name: 'PipelineHeaderSection',
|
||||
components: {
|
||||
ciHeader,
|
||||
loadingIcon,
|
||||
export default {
|
||||
name: 'PipelineHeaderSection',
|
||||
components: {
|
||||
ciHeader,
|
||||
loadingIcon,
|
||||
},
|
||||
props: {
|
||||
pipeline: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
pipeline: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actions: this.getActions(),
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actions: this.getActions(),
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
status() {
|
||||
return this.pipeline.details && this.pipeline.details.status;
|
||||
},
|
||||
shouldRenderContent() {
|
||||
return !this.isLoading && Object.keys(this.pipeline).length;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
pipeline() {
|
||||
this.actions = this.getActions();
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
postAction(action) {
|
||||
const index = this.actions.indexOf(action);
|
||||
|
||||
this.$set(this.actions[index], 'isLoading', true);
|
||||
|
||||
eventHub.$emit('headerPostAction', action);
|
||||
},
|
||||
|
||||
computed: {
|
||||
status() {
|
||||
return this.pipeline.details && this.pipeline.details.status;
|
||||
},
|
||||
shouldRenderContent() {
|
||||
return !this.isLoading && Object.keys(this.pipeline).length;
|
||||
},
|
||||
getActions() {
|
||||
const actions = [];
|
||||
|
||||
if (this.pipeline.retry_path) {
|
||||
actions.push({
|
||||
label: 'Retry',
|
||||
path: this.pipeline.retry_path,
|
||||
cssClass: 'js-retry-button btn btn-inverted-secondary',
|
||||
type: 'button',
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.pipeline.cancel_path) {
|
||||
actions.push({
|
||||
label: 'Cancel running',
|
||||
path: this.pipeline.cancel_path,
|
||||
cssClass: 'js-btn-cancel-pipeline btn btn-danger',
|
||||
type: 'button',
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
|
||||
watch: {
|
||||
pipeline() {
|
||||
this.actions = this.getActions();
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
postAction(action) {
|
||||
const index = this.actions.indexOf(action);
|
||||
|
||||
this.$set(this.actions[index], 'isLoading', true);
|
||||
|
||||
eventHub.$emit('headerPostAction', action);
|
||||
},
|
||||
|
||||
getActions() {
|
||||
const actions = [];
|
||||
|
||||
if (this.pipeline.retry_path) {
|
||||
actions.push({
|
||||
label: 'Retry',
|
||||
path: this.pipeline.retry_path,
|
||||
cssClass: 'js-retry-button btn btn-inverted-secondary',
|
||||
type: 'button',
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.pipeline.cancel_path) {
|
||||
actions.push({
|
||||
label: 'Cancel running',
|
||||
path: this.pipeline.cancel_path,
|
||||
cssClass: 'js-btn-cancel-pipeline btn btn-danger',
|
||||
type: 'button',
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="pipeline-header-container">
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
<script>
|
||||
import LoadingButton from '../../vue_shared/components/loading_button.vue';
|
||||
import LoadingButton from '../../vue_shared/components/loading_button.vue';
|
||||
|
||||
export default {
|
||||
name: 'PipelineNavControls',
|
||||
components: {
|
||||
LoadingButton,
|
||||
export default {
|
||||
name: 'PipelineNavControls',
|
||||
components: {
|
||||
LoadingButton,
|
||||
},
|
||||
props: {
|
||||
newPipelinePath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
props: {
|
||||
newPipelinePath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
|
||||
resetCachePath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
|
||||
ciLintPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
|
||||
isResetCacheButtonLoading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
resetCachePath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
methods: {
|
||||
onClickResetCache() {
|
||||
this.$emit('resetRunnersCache', this.resetCachePath);
|
||||
},
|
||||
|
||||
ciLintPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
|
||||
isResetCacheButtonLoading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClickResetCache() {
|
||||
this.$emit('resetRunnersCache', this.resetCachePath);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="nav-controls">
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
<script>
|
||||
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import popover from '../../vue_shared/directives/popover';
|
||||
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import popover from '../../vue_shared/directives/popover';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
userAvatarLink,
|
||||
export default {
|
||||
components: {
|
||||
userAvatarLink,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
popover,
|
||||
},
|
||||
props: {
|
||||
pipeline: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
popover,
|
||||
autoDevopsHelpPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
pipeline: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
autoDevopsHelpPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.pipeline.user;
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.pipeline.user;
|
||||
},
|
||||
popoverOptions() {
|
||||
return {
|
||||
html: true,
|
||||
trigger: 'focus',
|
||||
placement: 'top',
|
||||
title: `<div class="autodevops-title">
|
||||
popoverOptions() {
|
||||
return {
|
||||
html: true,
|
||||
trigger: 'focus',
|
||||
placement: 'top',
|
||||
title: `<div class="autodevops-title">
|
||||
This pipeline makes use of a predefined CI/CD configuration enabled by <b>Auto DevOps.</b>
|
||||
</div>`,
|
||||
content: `<a
|
||||
content: `<a
|
||||
class="autodevops-link"
|
||||
href="${this.autoDevopsHelpPath}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer nofollow">
|
||||
Learn more about Auto DevOps
|
||||
</a>`,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="table-section section-15 d-none d-sm-none d-md-block pipeline-tags">
|
||||
|
|
|
@ -1,283 +1,283 @@
|
|||
<script>
|
||||
import _ from 'underscore';
|
||||
import { __, sprintf, s__ } from '../../locale';
|
||||
import createFlash from '../../flash';
|
||||
import PipelinesService from '../services/pipelines_service';
|
||||
import pipelinesMixin from '../mixins/pipelines';
|
||||
import TablePagination from '../../vue_shared/components/table_pagination.vue';
|
||||
import NavigationTabs from '../../vue_shared/components/navigation_tabs.vue';
|
||||
import NavigationControls from './nav_controls.vue';
|
||||
import { getParameterByName } from '../../lib/utils/common_utils';
|
||||
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
|
||||
import _ from 'underscore';
|
||||
import { __, sprintf, s__ } from '../../locale';
|
||||
import createFlash from '../../flash';
|
||||
import PipelinesService from '../services/pipelines_service';
|
||||
import pipelinesMixin from '../mixins/pipelines';
|
||||
import TablePagination from '../../vue_shared/components/table_pagination.vue';
|
||||
import NavigationTabs from '../../vue_shared/components/navigation_tabs.vue';
|
||||
import NavigationControls from './nav_controls.vue';
|
||||
import { getParameterByName } from '../../lib/utils/common_utils';
|
||||
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TablePagination,
|
||||
NavigationTabs,
|
||||
NavigationControls,
|
||||
export default {
|
||||
components: {
|
||||
TablePagination,
|
||||
NavigationTabs,
|
||||
NavigationControls,
|
||||
},
|
||||
mixins: [pipelinesMixin, CIPaginationMixin],
|
||||
props: {
|
||||
store: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
mixins: [pipelinesMixin, CIPaginationMixin],
|
||||
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',
|
||||
},
|
||||
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,
|
||||
},
|
||||
// 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',
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// Start with loading state to avoid a glitch when the empty state will be rendered
|
||||
isLoading: true,
|
||||
state: this.store.state,
|
||||
scope: getParameterByName('scope') || 'all',
|
||||
page: getParameterByName('page') || '1',
|
||||
requestData: {},
|
||||
isResetCacheButtonLoading: false,
|
||||
};
|
||||
endpoint: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
stateMap: {
|
||||
// with tabs
|
||||
loading: 'loading',
|
||||
tableList: 'tableList',
|
||||
error: 'error',
|
||||
emptyTab: 'emptyTab',
|
||||
|
||||
// without tabs
|
||||
emptyState: 'emptyState',
|
||||
helpPagePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
scopes: {
|
||||
all: 'all',
|
||||
pending: 'pending',
|
||||
running: 'running',
|
||||
finished: 'finished',
|
||||
branches: 'branches',
|
||||
tags: 'tags',
|
||||
emptyStateSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* `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;
|
||||
},
|
||||
/**
|
||||
* Tabs are rendered in all states except empty state.
|
||||
* They are not rendered before the first request to avoid a flicker on first load.
|
||||
*/
|
||||
shouldRenderTabs() {
|
||||
const { stateMap } = this.$options;
|
||||
return (
|
||||
this.hasMadeRequest &&
|
||||
[stateMap.loading, stateMap.tableList, stateMap.error, stateMap.emptyTab].includes(
|
||||
this.stateToRender,
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
shouldRenderButtons() {
|
||||
return (
|
||||
(this.newPipelinePath || this.resetCachePath || this.ciLintPath) && this.shouldRenderTabs
|
||||
);
|
||||
},
|
||||
|
||||
shouldRenderPagination() {
|
||||
return (
|
||||
!this.isLoading &&
|
||||
this.state.pipelines.length &&
|
||||
this.state.pageInfo.total > this.state.pageInfo.perPage
|
||||
);
|
||||
},
|
||||
|
||||
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.');
|
||||
},
|
||||
|
||||
tabs() {
|
||||
const { count } = this.state;
|
||||
const { scopes } = this.$options;
|
||||
|
||||
return [
|
||||
{
|
||||
name: __('All'),
|
||||
scope: scopes.all,
|
||||
count: count.all,
|
||||
isActive: this.scope === 'all',
|
||||
},
|
||||
{
|
||||
name: __('Pending'),
|
||||
scope: scopes.pending,
|
||||
count: count.pending,
|
||||
isActive: this.scope === 'pending',
|
||||
},
|
||||
{
|
||||
name: __('Running'),
|
||||
scope: scopes.running,
|
||||
count: count.running,
|
||||
isActive: this.scope === 'running',
|
||||
},
|
||||
{
|
||||
name: __('Finished'),
|
||||
scope: scopes.finished,
|
||||
count: count.finished,
|
||||
isActive: this.scope === 'finished',
|
||||
},
|
||||
{
|
||||
name: __('Branches'),
|
||||
scope: scopes.branches,
|
||||
isActive: this.scope === 'branches',
|
||||
},
|
||||
{
|
||||
name: __('Tags'),
|
||||
scope: scopes.tags,
|
||||
isActive: this.scope === 'tags',
|
||||
},
|
||||
];
|
||||
},
|
||||
errorStateSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
created() {
|
||||
this.service = new PipelinesService(this.endpoint);
|
||||
this.requestData = { page: this.page, scope: this.scope };
|
||||
noPipelinesSvgPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
methods: {
|
||||
successCallback(resp) {
|
||||
// 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);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
updateContent(parameters) {
|
||||
this.updateInternalState(parameters);
|
||||
|
||||
// fetch new data
|
||||
return this.service
|
||||
.getPipelines(this.requestData)
|
||||
.then(response => {
|
||||
this.isLoading = false;
|
||||
this.successCallback(response);
|
||||
|
||||
// restart polling
|
||||
this.poll.restart({ data: this.requestData });
|
||||
})
|
||||
.catch(() => {
|
||||
this.isLoading = false;
|
||||
this.errorCallback();
|
||||
|
||||
// restart polling
|
||||
this.poll.restart({ data: this.requestData });
|
||||
});
|
||||
},
|
||||
|
||||
handleResetRunnersCache(endpoint) {
|
||||
this.isResetCacheButtonLoading = true;
|
||||
|
||||
this.service
|
||||
.postAction(endpoint)
|
||||
.then(() => {
|
||||
this.isResetCacheButtonLoading = false;
|
||||
createFlash(s__('Pipelines|Project cache successfully reset.'), 'notice');
|
||||
})
|
||||
.catch(() => {
|
||||
this.isResetCacheButtonLoading = false;
|
||||
createFlash(s__('Pipelines|Something went wrong while cleaning runners cache.'));
|
||||
});
|
||||
},
|
||||
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,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// Start with loading state to avoid a glitch when the empty state will be rendered
|
||||
isLoading: true,
|
||||
state: this.store.state,
|
||||
scope: getParameterByName('scope') || 'all',
|
||||
page: getParameterByName('page') || '1',
|
||||
requestData: {},
|
||||
isResetCacheButtonLoading: false,
|
||||
};
|
||||
},
|
||||
stateMap: {
|
||||
// with tabs
|
||||
loading: 'loading',
|
||||
tableList: 'tableList',
|
||||
error: 'error',
|
||||
emptyTab: 'emptyTab',
|
||||
|
||||
// without tabs
|
||||
emptyState: 'emptyState',
|
||||
},
|
||||
scopes: {
|
||||
all: 'all',
|
||||
pending: 'pending',
|
||||
running: 'running',
|
||||
finished: 'finished',
|
||||
branches: 'branches',
|
||||
tags: 'tags',
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* `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;
|
||||
},
|
||||
/**
|
||||
* Tabs are rendered in all states except empty state.
|
||||
* They are not rendered before the first request to avoid a flicker on first load.
|
||||
*/
|
||||
shouldRenderTabs() {
|
||||
const { stateMap } = this.$options;
|
||||
return (
|
||||
this.hasMadeRequest &&
|
||||
[stateMap.loading, stateMap.tableList, stateMap.error, stateMap.emptyTab].includes(
|
||||
this.stateToRender,
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
shouldRenderButtons() {
|
||||
return (
|
||||
(this.newPipelinePath || this.resetCachePath || this.ciLintPath) && this.shouldRenderTabs
|
||||
);
|
||||
},
|
||||
|
||||
shouldRenderPagination() {
|
||||
return (
|
||||
!this.isLoading &&
|
||||
this.state.pipelines.length &&
|
||||
this.state.pageInfo.total > this.state.pageInfo.perPage
|
||||
);
|
||||
},
|
||||
|
||||
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.');
|
||||
},
|
||||
|
||||
tabs() {
|
||||
const { count } = this.state;
|
||||
const { scopes } = this.$options;
|
||||
|
||||
return [
|
||||
{
|
||||
name: __('All'),
|
||||
scope: scopes.all,
|
||||
count: count.all,
|
||||
isActive: this.scope === 'all',
|
||||
},
|
||||
{
|
||||
name: __('Pending'),
|
||||
scope: scopes.pending,
|
||||
count: count.pending,
|
||||
isActive: this.scope === 'pending',
|
||||
},
|
||||
{
|
||||
name: __('Running'),
|
||||
scope: scopes.running,
|
||||
count: count.running,
|
||||
isActive: this.scope === 'running',
|
||||
},
|
||||
{
|
||||
name: __('Finished'),
|
||||
scope: scopes.finished,
|
||||
count: count.finished,
|
||||
isActive: this.scope === 'finished',
|
||||
},
|
||||
{
|
||||
name: __('Branches'),
|
||||
scope: scopes.branches,
|
||||
isActive: this.scope === 'branches',
|
||||
},
|
||||
{
|
||||
name: __('Tags'),
|
||||
scope: scopes.tags,
|
||||
isActive: this.scope === 'tags',
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.service = new PipelinesService(this.endpoint);
|
||||
this.requestData = { page: this.page, scope: this.scope };
|
||||
},
|
||||
methods: {
|
||||
successCallback(resp) {
|
||||
// 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);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
updateContent(parameters) {
|
||||
this.updateInternalState(parameters);
|
||||
|
||||
// fetch new data
|
||||
return this.service
|
||||
.getPipelines(this.requestData)
|
||||
.then(response => {
|
||||
this.isLoading = false;
|
||||
this.successCallback(response);
|
||||
|
||||
// restart polling
|
||||
this.poll.restart({ data: this.requestData });
|
||||
})
|
||||
.catch(() => {
|
||||
this.isLoading = false;
|
||||
this.errorCallback();
|
||||
|
||||
// restart polling
|
||||
this.poll.restart({ data: this.requestData });
|
||||
});
|
||||
},
|
||||
|
||||
handleResetRunnersCache(endpoint) {
|
||||
this.isResetCacheButtonLoading = true;
|
||||
|
||||
this.service
|
||||
.postAction(endpoint)
|
||||
.then(() => {
|
||||
this.isResetCacheButtonLoading = false;
|
||||
createFlash(s__('Pipelines|Project cache successfully reset.'), 'notice');
|
||||
})
|
||||
.catch(() => {
|
||||
this.isResetCacheButtonLoading = false;
|
||||
createFlash(s__('Pipelines|Something went wrong while cleaning runners cache.'));
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="pipelines-container">
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
<script>
|
||||
import eventHub from '../event_hub';
|
||||
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
|
||||
import icon from '../../vue_shared/components/icon.vue';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import eventHub from '../event_hub';
|
||||
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
|
||||
import icon from '../../vue_shared/components/icon.vue';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
tooltip,
|
||||
export default {
|
||||
directives: {
|
||||
tooltip,
|
||||
},
|
||||
components: {
|
||||
loadingIcon,
|
||||
icon,
|
||||
},
|
||||
props: {
|
||||
actions: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
components: {
|
||||
loadingIcon,
|
||||
icon,
|
||||
},
|
||||
props: {
|
||||
actions: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClickAction(endpoint) {
|
||||
this.isLoading = true;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClickAction(endpoint) {
|
||||
this.isLoading = true;
|
||||
|
||||
eventHub.$emit('postAction', endpoint);
|
||||
},
|
||||
|
||||
isActionDisabled(action) {
|
||||
if (action.playable === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !action.playable;
|
||||
},
|
||||
eventHub.$emit('postAction', endpoint);
|
||||
},
|
||||
};
|
||||
|
||||
isActionDisabled(action) {
|
||||
if (action.playable === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !action.playable;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="btn-group">
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
<script>
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import icon from '../../vue_shared/components/icon.vue';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import icon from '../../vue_shared/components/icon.vue';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
tooltip,
|
||||
export default {
|
||||
directives: {
|
||||
tooltip,
|
||||
},
|
||||
components: {
|
||||
icon,
|
||||
},
|
||||
props: {
|
||||
artifacts: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
components: {
|
||||
icon,
|
||||
},
|
||||
props: {
|
||||
artifacts: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
|
|
|
@ -1,74 +1,82 @@
|
|||
<script>
|
||||
import Modal from '~/vue_shared/components/gl_modal.vue';
|
||||
import { s__, sprintf } from '~/locale';
|
||||
import PipelinesTableRowComponent from './pipelines_table_row.vue';
|
||||
import eventHub from '../event_hub';
|
||||
import Modal from '~/vue_shared/components/gl_modal.vue';
|
||||
import { s__, sprintf } from '~/locale';
|
||||
import PipelinesTableRowComponent from './pipelines_table_row.vue';
|
||||
import eventHub from '../event_hub';
|
||||
|
||||
/**
|
||||
* Pipelines Table Component.
|
||||
*
|
||||
* Given an array of objects, renders a table.
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
PipelinesTableRowComponent,
|
||||
Modal,
|
||||
/**
|
||||
* Pipelines Table Component.
|
||||
*
|
||||
* Given an array of objects, renders a table.
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
PipelinesTableRowComponent,
|
||||
Modal,
|
||||
},
|
||||
props: {
|
||||
pipelines: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
pipelines: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
updateGraphDropdown: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
autoDevopsHelpPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
viewType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
updateGraphDropdown: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pipelineId: '',
|
||||
endpoint: '',
|
||||
cancelingPipeline: null,
|
||||
};
|
||||
autoDevopsHelpPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
modalTitle() {
|
||||
return sprintf(s__('Pipeline|Stop pipeline #%{pipelineId}?'), {
|
||||
viewType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pipelineId: '',
|
||||
endpoint: '',
|
||||
cancelingPipeline: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
modalTitle() {
|
||||
return sprintf(
|
||||
s__('Pipeline|Stop pipeline #%{pipelineId}?'),
|
||||
{
|
||||
pipelineId: `${this.pipelineId}`,
|
||||
}, false);
|
||||
},
|
||||
modalText() {
|
||||
return sprintf(s__('Pipeline|You’re about to stop pipeline %{pipelineId}.'), {
|
||||
},
|
||||
false,
|
||||
);
|
||||
},
|
||||
modalText() {
|
||||
return sprintf(
|
||||
s__('Pipeline|You’re about to stop pipeline %{pipelineId}.'),
|
||||
{
|
||||
pipelineId: `<strong>#${this.pipelineId}</strong>`,
|
||||
}, false);
|
||||
},
|
||||
},
|
||||
false,
|
||||
);
|
||||
},
|
||||
created() {
|
||||
eventHub.$on('openConfirmationModal', this.setModalData);
|
||||
},
|
||||
created() {
|
||||
eventHub.$on('openConfirmationModal', this.setModalData);
|
||||
},
|
||||
beforeDestroy() {
|
||||
eventHub.$off('openConfirmationModal', this.setModalData);
|
||||
},
|
||||
methods: {
|
||||
setModalData(data) {
|
||||
this.pipelineId = data.pipelineId;
|
||||
this.endpoint = data.endpoint;
|
||||
},
|
||||
beforeDestroy() {
|
||||
eventHub.$off('openConfirmationModal', this.setModalData);
|
||||
onSubmit() {
|
||||
eventHub.$emit('postAction', this.endpoint);
|
||||
this.cancelingPipeline = this.pipelineId;
|
||||
},
|
||||
methods: {
|
||||
setModalData(data) {
|
||||
this.pipelineId = data.pipelineId;
|
||||
this.endpoint = data.endpoint;
|
||||
},
|
||||
onSubmit() {
|
||||
eventHub.$emit('postAction', this.endpoint);
|
||||
this.cancelingPipeline = this.pipelineId;
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="ci-table">
|
||||
|
|
|
@ -1,255 +1,253 @@
|
|||
<script>
|
||||
import eventHub from '../event_hub';
|
||||
import PipelinesActionsComponent from './pipelines_actions.vue';
|
||||
import PipelinesArtifactsComponent from './pipelines_artifacts.vue';
|
||||
import CiBadge from '../../vue_shared/components/ci_badge_link.vue';
|
||||
import PipelineStage from './stage.vue';
|
||||
import PipelineUrl from './pipeline_url.vue';
|
||||
import PipelinesTimeago from './time_ago.vue';
|
||||
import CommitComponent from '../../vue_shared/components/commit.vue';
|
||||
import LoadingButton from '../../vue_shared/components/loading_button.vue';
|
||||
import Icon from '../../vue_shared/components/icon.vue';
|
||||
import { PIPELINES_TABLE } from '../constants';
|
||||
import eventHub from '../event_hub';
|
||||
import PipelinesActionsComponent from './pipelines_actions.vue';
|
||||
import PipelinesArtifactsComponent from './pipelines_artifacts.vue';
|
||||
import CiBadge from '../../vue_shared/components/ci_badge_link.vue';
|
||||
import PipelineStage from './stage.vue';
|
||||
import PipelineUrl from './pipeline_url.vue';
|
||||
import PipelinesTimeago from './time_ago.vue';
|
||||
import CommitComponent from '../../vue_shared/components/commit.vue';
|
||||
import LoadingButton from '../../vue_shared/components/loading_button.vue';
|
||||
import Icon from '../../vue_shared/components/icon.vue';
|
||||
import { PIPELINES_TABLE } from '../constants';
|
||||
|
||||
/**
|
||||
* Pipeline table row.
|
||||
*
|
||||
* Given the received object renders a table row in the pipelines' table.
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
PipelinesActionsComponent,
|
||||
PipelinesArtifactsComponent,
|
||||
CommitComponent,
|
||||
PipelineStage,
|
||||
PipelineUrl,
|
||||
CiBadge,
|
||||
PipelinesTimeago,
|
||||
LoadingButton,
|
||||
Icon,
|
||||
/**
|
||||
* Pipeline table row.
|
||||
*
|
||||
* Given the received object renders a table row in the pipelines' table.
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
PipelinesActionsComponent,
|
||||
PipelinesArtifactsComponent,
|
||||
CommitComponent,
|
||||
PipelineStage,
|
||||
PipelineUrl,
|
||||
CiBadge,
|
||||
PipelinesTimeago,
|
||||
LoadingButton,
|
||||
Icon,
|
||||
},
|
||||
props: {
|
||||
pipeline: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
props: {
|
||||
pipeline: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
updateGraphDropdown: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
autoDevopsHelpPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
viewType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
cancelingPipeline: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
updateGraphDropdown: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
pipelinesTable: PIPELINES_TABLE,
|
||||
data() {
|
||||
return {
|
||||
isRetrying: false,
|
||||
};
|
||||
autoDevopsHelpPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* If provided, returns the commit tag.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* This field needs a lot of verification, because of different possible cases:
|
||||
*
|
||||
* 1. person who is an author of a commit might be a GitLab user
|
||||
* 2. if person who is an author of a commit is a GitLab user he/she can have a GitLab avatar
|
||||
* 3. If GitLab user does not have avatar he/she might have a Gravatar
|
||||
* 4. If committer is not a GitLab User he/she can have a Gravatar
|
||||
* 5. We do not have consistent API object in this case
|
||||
* 6. We should improve API and the code
|
||||
*
|
||||
* @returns {Object|Undefined}
|
||||
*/
|
||||
commitAuthor() {
|
||||
let commitAuthorInformation;
|
||||
viewType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
cancelingPipeline: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
pipelinesTable: PIPELINES_TABLE,
|
||||
data() {
|
||||
return {
|
||||
isRetrying: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* If provided, returns the commit tag.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* This field needs a lot of verification, because of different possible cases:
|
||||
*
|
||||
* 1. person who is an author of a commit might be a GitLab user
|
||||
* 2. if person who is an author of a commit is a GitLab user he/she can have a GitLab avatar
|
||||
* 3. If GitLab user does not have avatar he/she might have a Gravatar
|
||||
* 4. If committer is not a GitLab User he/she can have a Gravatar
|
||||
* 5. We do not have consistent API object in this case
|
||||
* 6. We should improve API and the code
|
||||
*
|
||||
* @returns {Object|Undefined}
|
||||
*/
|
||||
commitAuthor() {
|
||||
let commitAuthorInformation;
|
||||
|
||||
if (!this.pipeline || !this.pipeline.commit) {
|
||||
return null;
|
||||
}
|
||||
if (!this.pipeline || !this.pipeline.commit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. person who is an author of a commit might be a GitLab user
|
||||
if (this.pipeline.commit.author) {
|
||||
// 2. if person who is an author of a commit is a GitLab user
|
||||
// he/she can have a GitLab avatar
|
||||
if (this.pipeline.commit.author.avatar_url) {
|
||||
commitAuthorInformation = this.pipeline.commit.author;
|
||||
// 1. person who is an author of a commit might be a GitLab user
|
||||
if (this.pipeline.commit.author) {
|
||||
// 2. if person who is an author of a commit is a GitLab user
|
||||
// he/she can have a GitLab avatar
|
||||
if (this.pipeline.commit.author.avatar_url) {
|
||||
commitAuthorInformation = this.pipeline.commit.author;
|
||||
|
||||
// 3. If GitLab user does not have avatar he/she might have a Gravatar
|
||||
} else if (this.pipeline.commit.author_gravatar_url) {
|
||||
commitAuthorInformation = Object.assign({}, this.pipeline.commit.author, {
|
||||
avatar_url: this.pipeline.commit.author_gravatar_url,
|
||||
});
|
||||
}
|
||||
// 4. If committer is not a GitLab User he/she can have a Gravatar
|
||||
} else {
|
||||
commitAuthorInformation = {
|
||||
// 3. If GitLab user does not have avatar he/she might have a Gravatar
|
||||
} else if (this.pipeline.commit.author_gravatar_url) {
|
||||
commitAuthorInformation = Object.assign({}, this.pipeline.commit.author, {
|
||||
avatar_url: this.pipeline.commit.author_gravatar_url,
|
||||
path: `mailto:${this.pipeline.commit.author_email}`,
|
||||
username: this.pipeline.commit.author_name,
|
||||
};
|
||||
});
|
||||
}
|
||||
// 4. If committer is not a GitLab User he/she can have a Gravatar
|
||||
} else {
|
||||
commitAuthorInformation = {
|
||||
avatar_url: this.pipeline.commit.author_gravatar_url,
|
||||
path: `mailto:${this.pipeline.commit.author_email}`,
|
||||
username: this.pipeline.commit.author_name,
|
||||
};
|
||||
}
|
||||
|
||||
return commitAuthorInformation;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit tag.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitTag() {
|
||||
if (this.pipeline.ref &&
|
||||
this.pipeline.ref.tag) {
|
||||
return this.pipeline.ref.tag;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit ref.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* Matches `path` prop sent in the API to `ref_url` prop needed
|
||||
* in the commit component.
|
||||
*
|
||||
* @returns {Object|Undefined}
|
||||
*/
|
||||
commitRef() {
|
||||
if (this.pipeline.ref) {
|
||||
return Object.keys(this.pipeline.ref).reduce((accumulator, prop) => {
|
||||
if (prop === 'path') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
accumulator.ref_url = this.pipeline.ref[prop];
|
||||
} else {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
accumulator[prop] = this.pipeline.ref[prop];
|
||||
}
|
||||
return accumulator;
|
||||
}, {});
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit url.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitUrl() {
|
||||
if (this.pipeline.commit &&
|
||||
this.pipeline.commit.commit_path) {
|
||||
return this.pipeline.commit.commit_path;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit short sha.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitShortSha() {
|
||||
if (this.pipeline.commit &&
|
||||
this.pipeline.commit.short_id) {
|
||||
return this.pipeline.commit.short_id;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit title.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitTitle() {
|
||||
if (this.pipeline.commit &&
|
||||
this.pipeline.commit.title) {
|
||||
return this.pipeline.commit.title;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Timeago components expects a number
|
||||
*
|
||||
* @return {type} description
|
||||
*/
|
||||
pipelineDuration() {
|
||||
if (this.pipeline.details && this.pipeline.details.duration) {
|
||||
return this.pipeline.details.duration;
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Timeago component expects a String.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
pipelineFinishedAt() {
|
||||
if (this.pipeline.details && this.pipeline.details.finished_at) {
|
||||
return this.pipeline.details.finished_at;
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
pipelineStatus() {
|
||||
if (this.pipeline.details && this.pipeline.details.status) {
|
||||
return this.pipeline.details.status;
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
displayPipelineActions() {
|
||||
return this.pipeline.flags.retryable ||
|
||||
this.pipeline.flags.cancelable ||
|
||||
this.pipeline.details.manual_actions.length ||
|
||||
this.pipeline.details.artifacts.length;
|
||||
},
|
||||
|
||||
isChildView() {
|
||||
return this.viewType === 'child';
|
||||
},
|
||||
|
||||
isCancelling() {
|
||||
return this.cancelingPipeline === this.pipeline.id;
|
||||
},
|
||||
return commitAuthorInformation;
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleCancelClick() {
|
||||
eventHub.$emit('openConfirmationModal', {
|
||||
pipelineId: this.pipeline.id,
|
||||
endpoint: this.pipeline.cancel_path,
|
||||
});
|
||||
},
|
||||
handleRetryClick() {
|
||||
this.isRetrying = true;
|
||||
eventHub.$emit('retryPipeline', this.pipeline.retry_path);
|
||||
},
|
||||
/**
|
||||
* If provided, returns the commit tag.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitTag() {
|
||||
if (this.pipeline.ref && this.pipeline.ref.tag) {
|
||||
return this.pipeline.ref.tag;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* If provided, returns the commit ref.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* Matches `path` prop sent in the API to `ref_url` prop needed
|
||||
* in the commit component.
|
||||
*
|
||||
* @returns {Object|Undefined}
|
||||
*/
|
||||
commitRef() {
|
||||
if (this.pipeline.ref) {
|
||||
return Object.keys(this.pipeline.ref).reduce((accumulator, prop) => {
|
||||
if (prop === 'path') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
accumulator.ref_url = this.pipeline.ref[prop];
|
||||
} else {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
accumulator[prop] = this.pipeline.ref[prop];
|
||||
}
|
||||
return accumulator;
|
||||
}, {});
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit url.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitUrl() {
|
||||
if (this.pipeline.commit && this.pipeline.commit.commit_path) {
|
||||
return this.pipeline.commit.commit_path;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit short sha.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitShortSha() {
|
||||
if (this.pipeline.commit && this.pipeline.commit.short_id) {
|
||||
return this.pipeline.commit.short_id;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* If provided, returns the commit title.
|
||||
* Needed to render the commit component column.
|
||||
*
|
||||
* @returns {String|Undefined}
|
||||
*/
|
||||
commitTitle() {
|
||||
if (this.pipeline.commit && this.pipeline.commit.title) {
|
||||
return this.pipeline.commit.title;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Timeago components expects a number
|
||||
*
|
||||
* @return {type} description
|
||||
*/
|
||||
pipelineDuration() {
|
||||
if (this.pipeline.details && this.pipeline.details.duration) {
|
||||
return this.pipeline.details.duration;
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Timeago component expects a String.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
pipelineFinishedAt() {
|
||||
if (this.pipeline.details && this.pipeline.details.finished_at) {
|
||||
return this.pipeline.details.finished_at;
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
pipelineStatus() {
|
||||
if (this.pipeline.details && this.pipeline.details.status) {
|
||||
return this.pipeline.details.status;
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
displayPipelineActions() {
|
||||
return (
|
||||
this.pipeline.flags.retryable ||
|
||||
this.pipeline.flags.cancelable ||
|
||||
this.pipeline.details.manual_actions.length ||
|
||||
this.pipeline.details.artifacts.length
|
||||
);
|
||||
},
|
||||
|
||||
isChildView() {
|
||||
return this.viewType === 'child';
|
||||
},
|
||||
|
||||
isCancelling() {
|
||||
return this.cancelingPipeline === this.pipeline.id;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleCancelClick() {
|
||||
eventHub.$emit('openConfirmationModal', {
|
||||
pipelineId: this.pipeline.id,
|
||||
endpoint: this.pipeline.cancel_path,
|
||||
});
|
||||
},
|
||||
handleRetryClick() {
|
||||
this.isRetrying = true;
|
||||
eventHub.$emit('retryPipeline', this.pipeline.retry_path);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="commit gl-responsive-table-row">
|
||||
|
|
|
@ -1,60 +1,58 @@
|
|||
<script>
|
||||
import iconTimerSvg from 'icons/_icon_timer.svg';
|
||||
import '../../lib/utils/datetime_utility';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import timeagoMixin from '../../vue_shared/mixins/timeago';
|
||||
import iconTimerSvg from 'icons/_icon_timer.svg';
|
||||
import '../../lib/utils/datetime_utility';
|
||||
import tooltip from '../../vue_shared/directives/tooltip';
|
||||
import timeagoMixin from '../../vue_shared/mixins/timeago';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
tooltip,
|
||||
export default {
|
||||
directives: {
|
||||
tooltip,
|
||||
},
|
||||
mixins: [timeagoMixin],
|
||||
props: {
|
||||
finishedTime: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
mixins: [
|
||||
timeagoMixin,
|
||||
],
|
||||
props: {
|
||||
finishedTime: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
iconTimerSvg,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
iconTimerSvg,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
hasDuration() {
|
||||
return this.duration > 0;
|
||||
},
|
||||
computed: {
|
||||
hasDuration() {
|
||||
return this.duration > 0;
|
||||
},
|
||||
hasFinishedTime() {
|
||||
return this.finishedTime !== '';
|
||||
},
|
||||
durationFormated() {
|
||||
const date = new Date(this.duration * 1000);
|
||||
hasFinishedTime() {
|
||||
return this.finishedTime !== '';
|
||||
},
|
||||
durationFormated() {
|
||||
const date = new Date(this.duration * 1000);
|
||||
|
||||
let hh = date.getUTCHours();
|
||||
let mm = date.getUTCMinutes();
|
||||
let ss = date.getSeconds();
|
||||
let hh = date.getUTCHours();
|
||||
let mm = date.getUTCMinutes();
|
||||
let ss = date.getSeconds();
|
||||
|
||||
// left pad
|
||||
if (hh < 10) {
|
||||
hh = `0${hh}`;
|
||||
}
|
||||
if (mm < 10) {
|
||||
mm = `0${mm}`;
|
||||
}
|
||||
if (ss < 10) {
|
||||
ss = `0${ss}`;
|
||||
}
|
||||
// left pad
|
||||
if (hh < 10) {
|
||||
hh = `0${hh}`;
|
||||
}
|
||||
if (mm < 10) {
|
||||
mm = `0${mm}`;
|
||||
}
|
||||
if (ss < 10) {
|
||||
ss = `0${ss}`;
|
||||
}
|
||||
|
||||
return `${hh}:${mm}:${ss}`;
|
||||
},
|
||||
return `${hh}:${mm}:${ss}`;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="table-section section-15 pipelines-time-ago">
|
||||
|
|
|
@ -75,8 +75,7 @@ export default {
|
|||
// Stop polling
|
||||
this.poll.stop();
|
||||
// Update the table
|
||||
return this.getPipelines()
|
||||
.then(() => this.poll.restart());
|
||||
return this.getPipelines().then(() => this.poll.restart());
|
||||
},
|
||||
fetchPipelines() {
|
||||
if (!this.isMakingRequest) {
|
||||
|
@ -86,9 +85,10 @@ export default {
|
|||
}
|
||||
},
|
||||
getPipelines() {
|
||||
return this.service.getPipelines(this.requestData)
|
||||
return this.service
|
||||
.getPipelines(this.requestData)
|
||||
.then(response => this.successCallback(response))
|
||||
.catch((error) => this.errorCallback(error));
|
||||
.catch(error => this.errorCallback(error));
|
||||
},
|
||||
setCommonData(pipelines) {
|
||||
this.store.storePipelines(pipelines);
|
||||
|
@ -118,7 +118,8 @@ export default {
|
|||
}
|
||||
},
|
||||
postAction(endpoint) {
|
||||
this.service.postAction(endpoint)
|
||||
this.service
|
||||
.postAction(endpoint)
|
||||
.then(() => this.fetchPipelines())
|
||||
.catch(() => Flash(__('An error occurred while making the request.')));
|
||||
},
|
||||
|
|
|
@ -31,7 +31,8 @@ export default () => {
|
|||
requestRefreshPipelineGraph() {
|
||||
// When an action is clicked
|
||||
// (wether in the dropdown or in the main nodes, we refresh the big graph)
|
||||
this.mediator.refreshPipeline()
|
||||
this.mediator
|
||||
.refreshPipeline()
|
||||
.catch(() => Flash(__('An error occurred while making the request.')));
|
||||
},
|
||||
},
|
||||
|
|
|
@ -52,7 +52,8 @@ export default class pipelinesMediator {
|
|||
refreshPipeline() {
|
||||
this.poll.stop();
|
||||
|
||||
return this.service.getPipeline()
|
||||
return this.service
|
||||
.getPipeline()
|
||||
.then(response => this.successCallback(response))
|
||||
.catch(() => this.errorCallback())
|
||||
.finally(() => this.poll.restart());
|
||||
|
|
Loading…
Reference in New Issue