Uniform CI status components in vue
This commit is contained in:
parent
aa6f44328e
commit
a1348a5d29
16 changed files with 213 additions and 266 deletions
|
@ -1,104 +0,0 @@
|
||||||
/* global Flash */
|
|
||||||
import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
builds: '',
|
|
||||||
spinner: '<span class="fa fa-spinner fa-spin"></span>',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
stage: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
updated() {
|
|
||||||
if (this.builds) {
|
|
||||||
this.stopDropdownClickPropagation();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
fetchBuilds(e) {
|
|
||||||
const ariaExpanded = e.currentTarget.attributes['aria-expanded'];
|
|
||||||
|
|
||||||
if (ariaExpanded && (ariaExpanded.textContent === 'true')) return null;
|
|
||||||
|
|
||||||
return this.$http.get(this.stage.dropdown_path)
|
|
||||||
.then((response) => {
|
|
||||||
this.builds = JSON.parse(response.body).html;
|
|
||||||
}, () => {
|
|
||||||
const flash = new Flash('Something went wrong on our end.');
|
|
||||||
return flash;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the user right clicks or cmd/ctrl + click in the job name
|
|
||||||
* the dropdown should not be closed and the link should open in another tab,
|
|
||||||
* so we stop propagation of the click event inside the dropdown.
|
|
||||||
*
|
|
||||||
* Since this component is rendered multiple times per page we need to guarantee we only
|
|
||||||
* target the click event of this component.
|
|
||||||
*/
|
|
||||||
stopDropdownClickPropagation() {
|
|
||||||
$(this.$el.querySelectorAll('.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item')).on('click', (e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
buildsOrSpinner() {
|
|
||||||
return this.builds ? this.builds : this.spinner;
|
|
||||||
},
|
|
||||||
dropdownClass() {
|
|
||||||
if (this.builds) return 'js-builds-dropdown-container';
|
|
||||||
return 'js-builds-dropdown-loading builds-dropdown-loading';
|
|
||||||
},
|
|
||||||
buildStatus() {
|
|
||||||
return `Build: ${this.stage.status.label}`;
|
|
||||||
},
|
|
||||||
tooltip() {
|
|
||||||
return `has-tooltip ci-status-icon ci-status-icon-${this.stage.status.group}`;
|
|
||||||
},
|
|
||||||
triggerButtonClass() {
|
|
||||||
return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`;
|
|
||||||
},
|
|
||||||
svgHTML() {
|
|
||||||
return borderlessStatusIconEntityMap[this.stage.status.icon];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'stage.title': function stageTitle() {
|
|
||||||
$(this.$refs.button).tooltip('destroy').tooltip();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
template: `
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
@click="fetchBuilds($event)"
|
|
||||||
:class="triggerButtonClass"
|
|
||||||
:title="stage.title"
|
|
||||||
data-placement="top"
|
|
||||||
data-toggle="dropdown"
|
|
||||||
type="button"
|
|
||||||
ref="button"
|
|
||||||
:aria-label="stage.title">
|
|
||||||
<span v-html="svgHTML" aria-hidden="true"></span>
|
|
||||||
<i class="fa fa-caret-down" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
|
|
||||||
<div class="arrow-up" aria-hidden="true"></div>
|
|
||||||
<div
|
|
||||||
:class="dropdownClass"
|
|
||||||
class="js-builds-dropdown-list scrollable-menu"
|
|
||||||
v-html="buildsOrSpinner">
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
};
|
|
|
@ -1,60 +0,0 @@
|
||||||
import canceledSvg from 'icons/_icon_status_canceled.svg';
|
|
||||||
import createdSvg from 'icons/_icon_status_created.svg';
|
|
||||||
import failedSvg from 'icons/_icon_status_failed.svg';
|
|
||||||
import manualSvg from 'icons/_icon_status_manual.svg';
|
|
||||||
import pendingSvg from 'icons/_icon_status_pending.svg';
|
|
||||||
import runningSvg from 'icons/_icon_status_running.svg';
|
|
||||||
import skippedSvg from 'icons/_icon_status_skipped.svg';
|
|
||||||
import successSvg from 'icons/_icon_status_success.svg';
|
|
||||||
import warningSvg from 'icons/_icon_status_warning.svg';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
pipeline: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
const svgsDictionary = {
|
|
||||||
icon_status_canceled: canceledSvg,
|
|
||||||
icon_status_created: createdSvg,
|
|
||||||
icon_status_failed: failedSvg,
|
|
||||||
icon_status_manual: manualSvg,
|
|
||||||
icon_status_pending: pendingSvg,
|
|
||||||
icon_status_running: runningSvg,
|
|
||||||
icon_status_skipped: skippedSvg,
|
|
||||||
icon_status_success: successSvg,
|
|
||||||
icon_status_warning: warningSvg,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
svg: svgsDictionary[this.pipeline.details.status.icon],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
cssClasses() {
|
|
||||||
return `ci-status ci-${this.pipeline.details.status.group}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
detailsPath() {
|
|
||||||
const { status } = this.pipeline.details;
|
|
||||||
return status.has_details ? status.details_path : false;
|
|
||||||
},
|
|
||||||
|
|
||||||
content() {
|
|
||||||
return `${this.svg} ${this.pipeline.details.status.text}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
template: `
|
|
||||||
<td class="commit-link">
|
|
||||||
<a
|
|
||||||
:class="cssClasses"
|
|
||||||
:href="detailsPath"
|
|
||||||
v-html="content">
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
`,
|
|
||||||
};
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* global Flash */
|
/* global Flash */
|
||||||
|
|
||||||
import '~/lib/utils/datetime_utility';
|
import '~/lib/utils/datetime_utility';
|
||||||
import { statusClassToSvgMap } from '../../vue_shared/pipeline_svg_icons';
|
import { statusIconEntityMap } from '../../vue_shared/ci_status_icons';
|
||||||
import MemoryUsage from './mr_widget_memory_usage';
|
import MemoryUsage from './mr_widget_memory_usage';
|
||||||
import MRWidgetService from '../services/mr_widget_service';
|
import MRWidgetService from '../services/mr_widget_service';
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
svg() {
|
svg() {
|
||||||
return statusClassToSvgMap.icon_status_success;
|
return statusIconEntityMap.icon_status_success;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import PipelineStage from '../../pipelines/components/stage';
|
import PipelineStage from '../../pipelines/components/stage.vue';
|
||||||
import pipelineStatusIcon from '../../vue_shared/components/pipeline_status_icon';
|
import ciIcon from '../../vue_shared/components/ci_icon.vue';
|
||||||
import { statusClassToSvgMap } from '../../vue_shared/pipeline_svg_icons';
|
import { statusIconEntityMap } from '../../vue_shared/ci_status_icons';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MRWidgetPipeline',
|
name: 'MRWidgetPipeline',
|
||||||
|
@ -9,7 +9,7 @@ export default {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'pipeline-stage': PipelineStage,
|
'pipeline-stage': PipelineStage,
|
||||||
'pipeline-status-icon': pipelineStatusIcon,
|
ciIcon,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
hasCIError() {
|
hasCIError() {
|
||||||
|
@ -18,11 +18,14 @@ export default {
|
||||||
return hasCI && !ciStatus;
|
return hasCI && !ciStatus;
|
||||||
},
|
},
|
||||||
svg() {
|
svg() {
|
||||||
return statusClassToSvgMap.icon_status_failed;
|
return statusIconEntityMap.icon_status_failed;
|
||||||
},
|
},
|
||||||
stageText() {
|
stageText() {
|
||||||
return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage';
|
return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage';
|
||||||
},
|
},
|
||||||
|
status() {
|
||||||
|
return this.mr.pipeline.details.status || {};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div class="mr-widget-heading">
|
<div class="mr-widget-heading">
|
||||||
|
@ -38,7 +41,13 @@ export default {
|
||||||
<span>Could not connect to the CI server. Please check your settings and try again.</span>
|
<span>Could not connect to the CI server. Please check your settings and try again.</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<pipeline-status-icon :pipelineStatus="mr.pipelineDetailedStatus" />
|
<div>
|
||||||
|
<a
|
||||||
|
class="icon-link"
|
||||||
|
:href="this.status.details_path">
|
||||||
|
<ci-icon :status="status" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
<span>
|
<span>
|
||||||
Pipeline
|
Pipeline
|
||||||
<a
|
<a
|
||||||
|
|
|
@ -41,15 +41,3 @@ export const statusIconEntityMap = {
|
||||||
icon_status_success: SUCCESS_SVG,
|
icon_status_success: SUCCESS_SVG,
|
||||||
icon_status_warning: WARNING_SVG,
|
icon_status_warning: WARNING_SVG,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const statusCssClasses = {
|
|
||||||
icon_status_canceled: 'canceled',
|
|
||||||
icon_status_created: 'created',
|
|
||||||
icon_status_failed: 'failed',
|
|
||||||
icon_status_manual: 'manual',
|
|
||||||
icon_status_pending: 'pending',
|
|
||||||
icon_status_running: 'running',
|
|
||||||
icon_status_skipped: 'skipped',
|
|
||||||
icon_status_success: 'success',
|
|
||||||
icon_status_warning: 'warning',
|
|
||||||
};
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<script>
|
||||||
|
import ciIcon from './ci_icon.vue';
|
||||||
|
/**
|
||||||
|
* Renders CI Badge link with CI icon and status text based on
|
||||||
|
* API response shared between all places where it is used.
|
||||||
|
*
|
||||||
|
* Receives status object containing:
|
||||||
|
* status: {
|
||||||
|
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
|
||||||
|
* group:"running" // used for CSS class
|
||||||
|
* icon: "icon_status_running" // used to render the icon
|
||||||
|
* label:"running" // used for potential tooltip
|
||||||
|
* text:"running" // text rendered
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Used in:
|
||||||
|
* - Pipelines table - first column
|
||||||
|
* - Jobs table - first column
|
||||||
|
* - Pipeline show view - header
|
||||||
|
* - Job show view - header
|
||||||
|
* - MR widget
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
status: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
ciIcon,
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
cssClass() {
|
||||||
|
const className = this.status.group;
|
||||||
|
|
||||||
|
return className ? `ci-status ci-${this.status.group}` : 'ci-status';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
:href="status.details_path"
|
||||||
|
:class="cssClass">
|
||||||
|
<ci-icon :status="status" />
|
||||||
|
{{status.text}}
|
||||||
|
</a>
|
||||||
|
</template>
|
|
@ -1,6 +1,27 @@
|
||||||
<script>
|
<script>
|
||||||
import { statusIconEntityMap, statusCssClasses } from '../../vue_shared/ci_status_icons';
|
import { statusIconEntityMap } from '../ci_status_icons';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders CI icon based on API response shared between all places where it is used.
|
||||||
|
*
|
||||||
|
* Receives status object containing:
|
||||||
|
* status: {
|
||||||
|
* details_path: "/gitlab-org/gitlab-ce/pipelines/8150156" // url
|
||||||
|
* group:"running" // used for CSS class
|
||||||
|
* icon: "icon_status_running" // used to render the icon
|
||||||
|
* label:"running" // used for potential tooltip
|
||||||
|
* text:"running" // text rendered
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Used in:
|
||||||
|
* - Pipelines table Badge
|
||||||
|
* - Pipelines table mini graph
|
||||||
|
* - Pipeline graph
|
||||||
|
* - Pipeline show view badge
|
||||||
|
* - Jobs table
|
||||||
|
* - Jobs show view header
|
||||||
|
* - Jobs show view sidebar
|
||||||
|
*/
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
status: {
|
status: {
|
||||||
|
@ -15,7 +36,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
cssClass() {
|
cssClass() {
|
||||||
const status = statusCssClasses[this.status.icon];
|
const status = this.status.group;
|
||||||
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`;
|
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { statusClassToSvgMap } from '../pipeline_svg_icons';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'PipelineStatusIcon',
|
|
||||||
props: {
|
|
||||||
pipelineStatus: { type: Object, required: true, default: () => ({}) },
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
svg() {
|
|
||||||
return statusClassToSvgMap[this.pipelineStatus.icon];
|
|
||||||
},
|
|
||||||
statusClass() {
|
|
||||||
return `ci-status-icon ci-status-icon-${this.pipelineStatus.group}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
template: `
|
|
||||||
<div :class="statusClass">
|
|
||||||
<a class="icon-link" :href="pipelineStatus.details_path">
|
|
||||||
<span v-html="svg" aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
};
|
|
|
@ -2,7 +2,7 @@
|
||||||
import AsyncButtonComponent from '../../pipelines/components/async_button.vue';
|
import AsyncButtonComponent from '../../pipelines/components/async_button.vue';
|
||||||
import PipelinesActionsComponent from '../../pipelines/components/pipelines_actions';
|
import PipelinesActionsComponent from '../../pipelines/components/pipelines_actions';
|
||||||
import PipelinesArtifactsComponent from '../../pipelines/components/pipelines_artifacts';
|
import PipelinesArtifactsComponent from '../../pipelines/components/pipelines_artifacts';
|
||||||
import PipelinesStatusComponent from '../../pipelines/components/status';
|
import ciBadge from './ci_badge_link.vue';
|
||||||
import PipelinesStageComponent from '../../pipelines/components/stage.vue';
|
import PipelinesStageComponent from '../../pipelines/components/stage.vue';
|
||||||
import PipelinesUrlComponent from '../../pipelines/components/pipeline_url';
|
import PipelinesUrlComponent from '../../pipelines/components/pipeline_url';
|
||||||
import PipelinesTimeagoComponent from '../../pipelines/components/time_ago';
|
import PipelinesTimeagoComponent from '../../pipelines/components/time_ago';
|
||||||
|
@ -39,7 +39,7 @@ export default {
|
||||||
'commit-component': CommitComponent,
|
'commit-component': CommitComponent,
|
||||||
'dropdown-stage': PipelinesStageComponent,
|
'dropdown-stage': PipelinesStageComponent,
|
||||||
'pipeline-url': PipelinesUrlComponent,
|
'pipeline-url': PipelinesUrlComponent,
|
||||||
'status-scope': PipelinesStatusComponent,
|
ciBadge,
|
||||||
'time-ago': PipelinesTimeagoComponent,
|
'time-ago': PipelinesTimeagoComponent,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -196,11 +196,20 @@ export default {
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pipelineStatus() {
|
||||||
|
if (this.pipeline.details && this.pipeline.details.status) {
|
||||||
|
return this.pipeline.details.status;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
template: `
|
template: `
|
||||||
<tr class="commit">
|
<tr class="commit">
|
||||||
<status-scope :pipeline="pipeline"/>
|
<td class="commit-link">
|
||||||
|
<ci-badge :status="pipelineStatus"/>
|
||||||
|
</td>
|
||||||
|
|
||||||
<pipeline-url :pipeline="pipeline"></pipeline-url>
|
<pipeline-url :pipeline="pipeline"></pipeline-url>
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
import canceledSvg from 'icons/_icon_status_canceled.svg';
|
|
||||||
import createdSvg from 'icons/_icon_status_created.svg';
|
|
||||||
import failedSvg from 'icons/_icon_status_failed.svg';
|
|
||||||
import manualSvg from 'icons/_icon_status_manual.svg';
|
|
||||||
import pendingSvg from 'icons/_icon_status_pending.svg';
|
|
||||||
import runningSvg from 'icons/_icon_status_running.svg';
|
|
||||||
import skippedSvg from 'icons/_icon_status_skipped.svg';
|
|
||||||
import successSvg from 'icons/_icon_status_success.svg';
|
|
||||||
import warningSvg from 'icons/_icon_status_warning.svg';
|
|
||||||
|
|
||||||
import canceledBorderlessSvg from 'icons/_icon_status_canceled_borderless.svg';
|
|
||||||
import createdBorderlessSvg from 'icons/_icon_status_created_borderless.svg';
|
|
||||||
import failedBorderlessSvg from 'icons/_icon_status_failed_borderless.svg';
|
|
||||||
import manualBorderlessSvg from 'icons/_icon_status_manual_borderless.svg';
|
|
||||||
import pendingBorderlessSvg from 'icons/_icon_status_pending_borderless.svg';
|
|
||||||
import runningBorderlessSvg from 'icons/_icon_status_running_borderless.svg';
|
|
||||||
import skippedBorderlessSvg from 'icons/_icon_status_skipped_borderless.svg';
|
|
||||||
import successBorderlessSvg from 'icons/_icon_status_success_borderless.svg';
|
|
||||||
import warningBorderlessSvg from 'icons/_icon_status_warning_borderless.svg';
|
|
||||||
|
|
||||||
export const statusClassToSvgMap = {
|
|
||||||
icon_status_canceled: canceledSvg,
|
|
||||||
icon_status_created: createdSvg,
|
|
||||||
icon_status_failed: failedSvg,
|
|
||||||
icon_status_manual: manualSvg,
|
|
||||||
icon_status_pending: pendingSvg,
|
|
||||||
icon_status_running: runningSvg,
|
|
||||||
icon_status_skipped: skippedSvg,
|
|
||||||
icon_status_success: successSvg,
|
|
||||||
icon_status_warning: warningSvg,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const statusClassToBorderlessSvgMap = {
|
|
||||||
icon_status_canceled: canceledBorderlessSvg,
|
|
||||||
icon_status_created: createdBorderlessSvg,
|
|
||||||
icon_status_failed: failedBorderlessSvg,
|
|
||||||
icon_status_manual: manualBorderlessSvg,
|
|
||||||
icon_status_pending: pendingBorderlessSvg,
|
|
||||||
icon_status_running: runningBorderlessSvg,
|
|
||||||
icon_status_skipped: skippedBorderlessSvg,
|
|
||||||
icon_status_success: successBorderlessSvg,
|
|
||||||
icon_status_warning: warningBorderlessSvg,
|
|
||||||
};
|
|
|
@ -90,11 +90,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: $gl-padding-top $gl-padding 0;
|
padding: $gl-padding-top $gl-padding 0;
|
||||||
|
|
||||||
i,
|
|
||||||
svg {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 1px;
|
top: 1px;
|
||||||
|
@ -109,9 +104,10 @@
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ci-status-icon > .icon-link svg {
|
.icon-link > .ci-status-icon > svg {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
changelogs/unreleased/30286-ci-badge-component.yml
Normal file
4
changelogs/unreleased/30286-ci-badge-component.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Refactor all CI vue badges to use the same vue component
|
||||||
|
merge_request:
|
||||||
|
author:
|
|
@ -1,7 +1,7 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import deploymentComponent from '~/vue_merge_request_widget/components/mr_widget_deployment';
|
import deploymentComponent from '~/vue_merge_request_widget/components/mr_widget_deployment';
|
||||||
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
|
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
|
||||||
import { statusClassToSvgMap } from '~/vue_shared/pipeline_svg_icons';
|
import { statusIconEntityMap } from '~/vue_shared/ci_status_icons';
|
||||||
|
|
||||||
const deploymentMockData = [
|
const deploymentMockData = [
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,7 @@ describe('MRWidgetDeployment', () => {
|
||||||
describe('svg', () => {
|
describe('svg', () => {
|
||||||
it('should have the proper SVG icon', () => {
|
it('should have the proper SVG icon', () => {
|
||||||
const vm = createComponent(deploymentMockData);
|
const vm = createComponent(deploymentMockData);
|
||||||
expect(vm.svg).toEqual(statusClassToSvgMap.icon_status_success);
|
expect(vm.svg).toEqual(statusIconEntityMap.icon_status_success);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { statusClassToSvgMap } from '~/vue_shared/pipeline_svg_icons';
|
import { statusIconEntityMap } from '~/vue_shared/ci_status_icons';
|
||||||
import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline';
|
import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline';
|
||||||
import mockData from '../mock_data';
|
import mockData from '../mock_data';
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ describe('MRWidgetPipeline', () => {
|
||||||
describe('components', () => {
|
describe('components', () => {
|
||||||
it('should have components added', () => {
|
it('should have components added', () => {
|
||||||
expect(pipelineComponent.components['pipeline-stage']).toBeDefined();
|
expect(pipelineComponent.components['pipeline-stage']).toBeDefined();
|
||||||
expect(pipelineComponent.components['pipeline-status-icon']).toBeDefined();
|
expect(pipelineComponent.components.ciIcon).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ describe('MRWidgetPipeline', () => {
|
||||||
it('should have the proper SVG icon', () => {
|
it('should have the proper SVG icon', () => {
|
||||||
const vm = createComponent({ pipeline: mockData.pipeline });
|
const vm = createComponent({ pipeline: mockData.pipeline });
|
||||||
|
|
||||||
expect(vm.svg).toEqual(statusClassToSvgMap.icon_status_failed);
|
expect(vm.svg).toEqual(statusIconEntityMap.icon_status_failed);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
89
spec/javascripts/vue_shared/components/ci_badge_link_spec.js
Normal file
89
spec/javascripts/vue_shared/components/ci_badge_link_spec.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import ciBadge from '~/vue_shared/components/ci_badge_link.vue';
|
||||||
|
|
||||||
|
describe('CI Badge Link Component', () => {
|
||||||
|
let CIBadge;
|
||||||
|
|
||||||
|
const statuses = {
|
||||||
|
canceled: {
|
||||||
|
text: 'canceled',
|
||||||
|
label: 'canceled',
|
||||||
|
group: 'canceled',
|
||||||
|
icon: 'icon_status_canceled',
|
||||||
|
details_path: 'status/canceled',
|
||||||
|
},
|
||||||
|
created: {
|
||||||
|
text: 'created',
|
||||||
|
label: 'created',
|
||||||
|
group: 'created',
|
||||||
|
icon: 'icon_status_created',
|
||||||
|
details_path: 'status/created',
|
||||||
|
},
|
||||||
|
failed: {
|
||||||
|
text: 'failed',
|
||||||
|
label: 'failed',
|
||||||
|
group: 'failed',
|
||||||
|
icon: 'icon_status_failed',
|
||||||
|
details_path: 'status/failed',
|
||||||
|
},
|
||||||
|
manual: {
|
||||||
|
text: 'manual',
|
||||||
|
label: 'manual action',
|
||||||
|
group: 'manual',
|
||||||
|
icon: 'icon_status_manual',
|
||||||
|
details_path: 'status/manual',
|
||||||
|
},
|
||||||
|
pending: {
|
||||||
|
text: 'pending',
|
||||||
|
label: 'pending',
|
||||||
|
group: 'pending',
|
||||||
|
icon: 'icon_status_pending',
|
||||||
|
details_path: 'status/pending',
|
||||||
|
},
|
||||||
|
running: {
|
||||||
|
text: 'running',
|
||||||
|
label: 'running',
|
||||||
|
group: 'running',
|
||||||
|
icon: 'icon_status_running',
|
||||||
|
details_path: 'status/running',
|
||||||
|
},
|
||||||
|
skipped: {
|
||||||
|
text: 'skipped',
|
||||||
|
label: 'skipped',
|
||||||
|
group: 'skipped',
|
||||||
|
icon: 'icon_status_skipped',
|
||||||
|
details_path: 'status/skipped',
|
||||||
|
},
|
||||||
|
success_warining: {
|
||||||
|
text: 'passed',
|
||||||
|
label: 'passed',
|
||||||
|
group: 'success_with_warnings',
|
||||||
|
icon: 'icon_status_warning',
|
||||||
|
details_path: 'status/warning',
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
text: 'passed',
|
||||||
|
label: 'passed',
|
||||||
|
group: 'passed',
|
||||||
|
icon: 'icon_status_success',
|
||||||
|
details_path: 'status/passed',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should render each status badge', () => {
|
||||||
|
CIBadge = Vue.extend(ciBadge);
|
||||||
|
Object.keys(statuses).map((status) => {
|
||||||
|
const vm = new CIBadge({
|
||||||
|
propsData: {
|
||||||
|
status: statuses[status],
|
||||||
|
},
|
||||||
|
}).$mount();
|
||||||
|
|
||||||
|
expect(vm.$el.getAttribute('href')).toEqual(statuses[status].details_path);
|
||||||
|
expect(vm.$el.textContent.trim()).toEqual(statuses[status].text);
|
||||||
|
expect(vm.$el.getAttribute('class')).toEqual(`ci-status ci-${statuses[status].group}`);
|
||||||
|
expect(vm.$el.querySelector('svg')).toBeDefined();
|
||||||
|
return vm;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -25,6 +25,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_success',
|
icon: 'icon_status_success',
|
||||||
|
group: 'success',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -37,6 +38,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_failed',
|
icon: 'icon_status_failed',
|
||||||
|
group: 'failed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -49,6 +51,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_warning',
|
icon: 'icon_status_warning',
|
||||||
|
group: 'warning',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -61,6 +64,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_pending',
|
icon: 'icon_status_pending',
|
||||||
|
group: 'pending',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -73,6 +77,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_running',
|
icon: 'icon_status_running',
|
||||||
|
group: 'running',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -85,6 +90,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_created',
|
icon: 'icon_status_created',
|
||||||
|
group: 'created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -97,6 +103,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_skipped',
|
icon: 'icon_status_skipped',
|
||||||
|
group: 'skipped',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -109,6 +116,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_canceled',
|
icon: 'icon_status_canceled',
|
||||||
|
group: 'canceled',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
@ -121,6 +129,7 @@ describe('CI Icon component', () => {
|
||||||
propsData: {
|
propsData: {
|
||||||
status: {
|
status: {
|
||||||
icon: 'icon_status_manual',
|
icon: 'icon_status_manual',
|
||||||
|
group: 'manual',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
|
Loading…
Reference in a new issue