Commit d01d509b authored by Tim Zallmann's avatar Tim Zallmann

Fixing Icons

parent e3c7d264
<script>
import getActionIcon from '../../../vue_shared/ci_action_icons';
import tooltip from '../../../vue_shared/directives/tooltip';
import icon from '../../../vue_shared/components/icon.vue';
/**
* Renders either a cancel, retry or play icon pointing to the given path.
......@@ -29,6 +30,10 @@
},
},
components: {
icon,
},
directives: {
tooltip,
},
......@@ -50,14 +55,11 @@
:data-method="actionMethod"
:title="tooltipText"
:href="link"
class="ci-action-icon-container"
class="ci-action-icon-container ci-action-icon-wrapper"
:class="cssClass"
data-container="body">
<i
class="ci-action-icon-wrapper"
:class="cssClass"
v-html="actionIconSvg"
aria-hidden="true"
/>
<icon
name="stop"
size="16"/>
</a>
</template>
<script>
import getActionIcon from '../../../vue_shared/ci_action_icons';
import icon from '../../../vue_shared/components/icon.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
/**
......@@ -29,12 +30,17 @@
},
},
components: {
icon,
},
directives: {
tooltip,
},
computed: {
actionIconSvg() {
alert('LA');
return getActionIcon(this.actionIcon);
},
},
......@@ -49,7 +55,9 @@
rel="nofollow"
class="ci-action-icon-wrapper js-ci-status-icon"
data-container="body"
v-html="actionIconSvg"
aria-label="Job's action">
{{actionIcon}}
<icon
name="retry"/>
</a>
</template>
......@@ -18,7 +18,7 @@
* "group": "success",
* "details_path": "/root/ci-mock/builds/4256",
* "action": {
* "icon": "icon_action_retry",
* "icon": "retry",
* "title": "Retry",
* "path": "/root/ci-mock/builds/4256/retry",
* "method": "post"
......
......@@ -19,7 +19,7 @@
* "group": "success",
* "details_path": "/root/ci-mock/builds/4256",
* "action": {
* "icon": "icon_action_retry",
* "icon": "retry",
* "title": "Retry",
* "path": "/root/ci-mock/builds/4256/retry",
* "method": "post"
......
......@@ -14,7 +14,7 @@
*/
import Flash from '../../flash';
import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons';
import icon from '../../vue_shared/components/icon.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip';
......@@ -45,6 +45,7 @@ export default {
components: {
loadingIcon,
icon,
},
updated() {
......@@ -121,10 +122,6 @@ export default {
triggerButtonClass() {
return `ci-status-icon-${this.stage.status.group}`;
},
svgIcon() {
return borderlessStatusIconEntityMap[this.stage.status.icon];
},
},
};
</script>
......@@ -145,9 +142,10 @@ export default {
aria-expanded="false">
<span
v-html="svgIcon"
aria-hidden="true"
:aria-label="stage.title">
<icon
:name="stage.status.icon"/>
</span>
<i
......
import PipelineStage from '../../pipelines/components/stage.vue';
import ciIcon from '../../vue_shared/components/ci_icon.vue';
import { statusIconEntityMap } from '../../vue_shared/ci_status_icons';
import icon from '../../vue_shared/components/icon.vue';
export default {
name: 'MRWidgetPipeline',
......@@ -10,6 +10,7 @@ export default {
components: {
'pipeline-stage': PipelineStage,
ciIcon,
icon,
},
computed: {
hasPipeline() {
......@@ -20,9 +21,6 @@ export default {
return hasCI && !ciStatus;
},
svg() {
return statusIconEntityMap.icon_status_failed;
},
stageText() {
return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage';
},
......@@ -38,8 +36,10 @@ export default {
<template v-if="hasCIError">
<div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-10">
<span
v-html="svg"
aria-hidden="true"></span>
aria-hidden="true">
<icon
name="status_failed"/>
</span>
</div>
<div class="media-body">
Could not connect to the CI server. Please check your settings and try again
......
import BORDERLESS_CANCELED_SVG from 'icons/_icon_status_canceled_borderless.svg';
import BORDERLESS_CREATED_SVG from 'icons/_icon_status_created_borderless.svg';
import BORDERLESS_FAILED_SVG from 'icons/_icon_status_failed_borderless.svg';
import BORDERLESS_MANUAL_SVG from 'icons/_icon_status_manual_borderless.svg';
import BORDERLESS_PENDING_SVG from 'icons/_icon_status_pending_borderless.svg';
import BORDERLESS_RUNNING_SVG from 'icons/_icon_status_running_borderless.svg';
import BORDERLESS_SKIPPED_SVG from 'icons/_icon_status_skipped_borderless.svg';
import BORDERLESS_SUCCESS_SVG from 'icons/_icon_status_success_borderless.svg';
import BORDERLESS_WARNING_SVG from 'icons/_icon_status_warning_borderless.svg';
import CANCELED_SVG from 'icons/_icon_status_canceled.svg';
import CREATED_SVG from 'icons/_icon_status_created.svg';
import FAILED_SVG from 'icons/_icon_status_failed.svg';
import MANUAL_SVG from 'icons/_icon_status_manual.svg';
import PENDING_SVG from 'icons/_icon_status_pending.svg';
import RUNNING_SVG from 'icons/_icon_status_running.svg';
import SKIPPED_SVG from 'icons/_icon_status_skipped.svg';
import SUCCESS_SVG from 'icons/_icon_status_success.svg';
import WARNING_SVG from 'icons/_icon_status_warning.svg';
export const borderlessStatusIconEntityMap = {
icon_status_canceled: BORDERLESS_CANCELED_SVG,
icon_status_created: BORDERLESS_CREATED_SVG,
icon_status_failed: BORDERLESS_FAILED_SVG,
icon_status_manual: BORDERLESS_MANUAL_SVG,
icon_status_pending: BORDERLESS_PENDING_SVG,
icon_status_running: BORDERLESS_RUNNING_SVG,
icon_status_skipped: BORDERLESS_SKIPPED_SVG,
icon_status_success: BORDERLESS_SUCCESS_SVG,
icon_status_warning: BORDERLESS_WARNING_SVG,
};
export const statusIconEntityMap = {
icon_status_canceled: CANCELED_SVG,
icon_status_created: CREATED_SVG,
icon_status_failed: FAILED_SVG,
icon_status_manual: MANUAL_SVG,
icon_status_pending: PENDING_SVG,
icon_status_running: RUNNING_SVG,
icon_status_skipped: SKIPPED_SVG,
icon_status_success: SUCCESS_SVG,
icon_status_warning: WARNING_SVG,
};
<script>
import { statusIconEntityMap } from '../ci_status_icons';
import icon from '../../vue_shared/components/icon.vue';
/**
* Renders CI icon based on API response shared between all places where it is used.
......@@ -30,11 +30,11 @@
},
},
computed: {
statusIconSvg() {
return statusIconEntityMap[this.status.icon];
},
components: {
icon,
},
computed: {
cssClass() {
const status = this.status.group;
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`;
......@@ -44,7 +44,8 @@
</script>
<template>
<span
:class="cssClass"
v-html="statusIconSvg">
:class="cssClass">
<icon
:name="status.icon"/>
</span>
</template>
<script>
/* This is a re-usable vue component for rendering a svg sprite
icon
Sample configuration:
<icon
:img-src="userAvatarSrc"
:img-alt="tooltipText"
:tooltip-text="tooltipText"
tooltip-placement="top"
/>
*/
export default {
props: {
name: {
type: String,
required: true,
},
size: {
type: Number,
required: false,
default: 0,
},
cssClass: {
type: String,
required: false,
default: '',
},
},
computed: {
spriteHref() {
return `${gon.sprite_icons}#${this.name}`
},
fullCssClass() {
let classString = '' || this.cssClass;
// if (this.size) classString += `s${this.size}`
return classString;
},
},
};
</script>
<template>
<svg
:class="fullCssClass">
<use v-bind="{'xlink:href':spriteHref}"/>
</svg>
</template>
......@@ -165,8 +165,9 @@
z-index: 300;
}
.ci-action-icon-wrapper {
line-height: 16px;
.ci-action-icon-wrapper svg {
width: 16px;
height: 16px;
}
}
......
......@@ -452,7 +452,7 @@
}
// Action Icons in big pipeline-graph nodes
.ci-action-icon-container .ci-action-icon-wrapper {
.ci-action-icon-container.ci-action-icon-wrapper {
height: 30px;
width: 30px;
background: $white-light;
......@@ -468,8 +468,10 @@
svg {
fill: $gl-text-color-secondary;
position: relative;
left: -1px;
top: -1px;
left: 5px;
top: 2px;
width: 18px;
height: 18px;
}
&:hover svg {
......
......@@ -22,7 +22,7 @@ export default {
details_path: '/root/ci-mock/-/jobs/4757',
favicon: '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico',
action: {
icon: 'icon_action_retry',
icon: 'retry',
title: 'Retry',
path: '/root/ci-mock/-/jobs/4757/retry',
method: 'post',
......
......@@ -11,7 +11,7 @@ describe('pipeline graph action component', () => {
tooltipText: 'bar',
link: 'foo',
actionMethod: 'post',
actionIcon: 'icon_action_cancel',
actionIcon: 'cancel',
},
}).$mount();
......
......@@ -14,7 +14,7 @@ describe('pipeline graph job component', () => {
group: 'success',
details_path: '/root/ci-mock/builds/4256',
action: {
icon: 'icon_action_retry',
icon: 'retry',
title: 'Retry',
path: '/root/ci-mock/builds/4256/retry',
method: 'post',
......
......@@ -39,7 +39,7 @@ export default {
"details_path": "/root/ci-mock/builds/4153",
"favicon": "/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico",
"action": {
"icon": "icon_action_retry",
"icon": "retry",
"title": "Retry",
"path": "/root/ci-mock/builds/4153/retry",
"method": "post"
......@@ -62,7 +62,7 @@ export default {
"details_path": "/root/ci-mock/builds/4153",
"favicon": "/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico",
"action": {
"icon": "icon_action_retry",
"icon": "retry",
"title": "Retry",
"path": "/root/ci-mock/builds/4153/retry",
"method": "post"
......@@ -96,7 +96,7 @@ export default {
"details_path": "/root/ci-mock/builds/4166",
"favicon": "/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico",
"action": {
"icon": "icon_action_retry",
"icon": "retry",
"title": "Retry",
"path": "/root/ci-mock/builds/4166/retry",
"method": "post"
......@@ -119,7 +119,7 @@ export default {
"details_path": "/root/ci-mock/builds/4166",
"favicon": "/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico",
"action": {
"icon": "icon_action_retry",
"icon": "retry",
"title": "Retry",
"path": "/root/ci-mock/builds/4166/retry",
"method": "post"
......@@ -138,7 +138,7 @@ export default {
"details_path": "/root/ci-mock/builds/4159",
"favicon": "/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico",
"action": {
"icon": "icon_action_retry",
"icon": "retry",
"title": "Retry",
"path": "/root/ci-mock/builds/4159/retry",
"method": "post"
......@@ -161,7 +161,7 @@ export default {
"details_path": "/root/ci-mock/builds/4159",
"favicon": "/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico",
"action": {
"icon": "icon_action_retry",
"icon": "retry",
"title": "Retry",
"path": "/root/ci-mock/builds/4159/retry",
"method": "post"
......
......@@ -13,7 +13,7 @@ describe('stage column component', () => {
group: 'success',
details_path: '/root/ci-mock/builds/4256',
action: {
icon: 'icon_action_retry',
icon: 'retry',
title: 'Retry',
path: '/root/ci-mock/builds/4256/retry',
method: 'post',
......
import Vue from 'vue';
import { statusIconEntityMap } from '~/vue_shared/ci_status_icons';
import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline';
import mockData from '../mock_data';
......@@ -29,14 +28,6 @@ describe('MRWidgetPipeline', () => {
});
describe('computed', () => {
describe('svg', () => {
it('should have the proper SVG icon', () => {
const vm = createComponent({ pipeline: mockData.pipeline });
expect(vm.svg).toEqual(statusIconEntityMap.icon_status_failed);
});
});
describe('hasPipeline', () => {
it('should return true when there is a pipeline', () => {
expect(Object.keys(mockData.pipeline).length).toBeGreaterThan(0);
......@@ -142,6 +133,7 @@ describe('MRWidgetPipeline', () => {
Vue.nextTick(() => {
expect(el.querySelectorAll('.js-ci-error').length).toEqual(1);
expect(el.innerText).toContain('Could not connect to the CI server');
expect(el.querySelector('.ci-status-icon svg use').getAttribute('xlink:href')).toContain('status_failed');
done();
});
});
......
import getActionIcon from '~/vue_shared/ci_action_icons';
import cancelSVG from 'icons/_icon_action_cancel.svg';
import retrySVG from 'icons/_icon_action_retry.svg';
import playSVG from 'icons/_icon_action_play.svg';
import stopSVG from 'icons/_icon_action_stop.svg';
describe('getActionIcon', () => {
it('should return an empty string', () => {
expect(getActionIcon()).toEqual('');
});
it('should return cancel svg', () => {
expect(getActionIcon('icon_action_cancel')).toEqual(cancelSVG);
});
it('should return retry svg', () => {
expect(getActionIcon('icon_action_retry')).toEqual(retrySVG);
});
it('should return play svg', () => {
expect(getActionIcon('icon_action_play')).toEqual(playSVG);
});
it('should render stop svg', () => {
expect(getActionIcon('icon_action_stop')).toEqual(stopSVG);
});
});
import { borderlessStatusIconEntityMap, statusIconEntityMap } from '~/vue_shared/ci_status_icons';
describe('CI status icons', () => {
const statuses = [
'icon_status_canceled',
'icon_status_created',
'icon_status_failed',
'icon_status_manual',
'icon_status_pending',
'icon_status_running',
'icon_status_skipped',
'icon_status_success',
'icon_status_warning',
];
it('should have a dictionary for borderless icons', () => {
statuses.forEach((status) => {
expect(borderlessStatusIconEntityMap[status]).toBeDefined();
});
});
it('should have a dictionary for icons', () => {
statuses.forEach((status) => {
expect(statusIconEntityMap[status]).toBeDefined();
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment