Cleans up CSS - All pipeline dropdowns use the same CSS to render the action icons
This commit is contained in:
parent
9ff5041090
commit
e0b7541b9a
3 changed files with 131 additions and 317 deletions
|
@ -1,261 +1,139 @@
|
||||||
<script>
|
<script>
|
||||||
/**
|
/**
|
||||||
* Renders each stage of the pipeline mini graph.
|
* Renders each stage of the pipeline mini graph.
|
||||||
*
|
*
|
||||||
* Given the provided endpoint will make a request to
|
* Given the provided endpoint will make a request to
|
||||||
* fetch the dropdown data when the stage is clicked.
|
* fetch the dropdown data when the stage is clicked.
|
||||||
*
|
*
|
||||||
* Request is made inside this component to make it reusable between:
|
* Request is made inside this component to make it reusable between:
|
||||||
* 1. Pipelines main table
|
* 1. Pipelines main table
|
||||||
* 2. Pipelines table in commit and Merge request views
|
* 2. Pipelines table in commit and Merge request views
|
||||||
* 3. Merge request widget
|
* 3. Merge request widget
|
||||||
* 4. Commit widget
|
* 4. Commit widget
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import Flash from '../../flash';
|
import { _ } from '~/locale';
|
||||||
import axios from '../../lib/utils/axios_utils';
|
import Flash from '../../flash';
|
||||||
import eventHub from '../event_hub';
|
import axios from '../../lib/utils/axios_utils';
|
||||||
import Icon from '../../vue_shared/components/icon.vue';
|
import eventHub from '../event_hub';
|
||||||
import LoadingIcon from '../../vue_shared/components/loading_icon.vue';
|
import Icon from '../../vue_shared/components/icon.vue';
|
||||||
import JobComponent from './graph/job_component.vue';
|
import LoadingIcon from '../../vue_shared/components/loading_icon.vue';
|
||||||
import tooltip from '../../vue_shared/directives/tooltip';
|
import JobComponent from './graph/job_component.vue';
|
||||||
|
import tooltip from '../../vue_shared/directives/tooltip';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
LoadingIcon,
|
LoadingIcon,
|
||||||
Icon,
|
Icon,
|
||||||
JobComponent,
|
JobComponent,
|
||||||
|
},
|
||||||
|
|
||||||
|
directives: {
|
||||||
|
tooltip,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
stage: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
directives: {
|
updateDropdown: {
|
||||||
tooltip,
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isLoading: false,
|
||||||
|
dropdownContent: '',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
dropdownClass() {
|
||||||
|
return this.dropdownContent.length > 0
|
||||||
|
? 'js-builds-dropdown-container'
|
||||||
|
: 'js-builds-dropdown-loading';
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
triggerButtonClass() {
|
||||||
stage: {
|
return `ci-status-icon-${this.stage.status.group}`;
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
updateDropdown: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
borderlessIcon() {
|
||||||
return {
|
return `${this.stage.status.icon}_borderless`;
|
||||||
isLoading: false,
|
|
||||||
dropdownContent: '',
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
computed: {
|
watch: {
|
||||||
dropdownClass() {
|
updateDropdown() {
|
||||||
// return this.dropdownContent.length > 0
|
if (this.updateDropdown && this.isDropdownOpen() && !this.isLoading) {
|
||||||
// ? 'js-builds-dropdown-container'
|
this.fetchJobs();
|
||||||
// : 'js-builds-dropdown-loading';
|
}
|
||||||
},
|
|
||||||
|
|
||||||
triggerButtonClass() {
|
|
||||||
return `ci-status-icon-${this.stage.status.group}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
borderlessIcon() {
|
|
||||||
return `${this.stage.status.icon}_borderless`;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
watch: {
|
updated() {
|
||||||
updateDropdown() {
|
if (this.dropdownContent.length > 0) {
|
||||||
if (this.updateDropdown && this.isDropdownOpen() && !this.isLoading) {
|
this.stopDropdownClickPropagation();
|
||||||
this.fetchJobs();
|
}
|
||||||
}
|
},
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
updated() {
|
methods: {
|
||||||
if (this.dropdownContent.length > 0) {
|
onClickStage() {
|
||||||
this.stopDropdownClickPropagation();
|
if (!this.isDropdownOpen()) {
|
||||||
|
eventHub.$emit('clickedDropdown');
|
||||||
|
this.isLoading = true;
|
||||||
|
this.fetchJobs();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
fetchJobs() {
|
||||||
onClickStage() {
|
axios
|
||||||
if (!this.isDropdownOpen()) {
|
.get(this.stage.dropdown_path)
|
||||||
eventHub.$emit('clickedDropdown');
|
.then(({ data }) => {
|
||||||
this.isLoading = true;
|
this.dropdownContent = data;
|
||||||
this.fetchJobs();
|
this.isLoading = false;
|
||||||
}
|
})
|
||||||
},
|
.catch(() => {
|
||||||
|
this.closeDropdown();
|
||||||
|
this.isLoading = false;
|
||||||
|
|
||||||
fetchJobs() {
|
Flash(_('Something went wrong on our end.'));
|
||||||
axios
|
|
||||||
.get(this.stage.dropdown_path)
|
|
||||||
.then(({ data }) => {
|
|
||||||
// TODO: REMOVE THIS ONCE WE HAVE BACKEND
|
|
||||||
this.dropdownContent = [
|
|
||||||
{
|
|
||||||
id: 966,
|
|
||||||
name: 'rspec:linux 0 3',
|
|
||||||
started: false,
|
|
||||||
build_path: '/twitter/flight/-/jobs/966',
|
|
||||||
cancel_path: '/twitter/flight/-/jobs/966/cancel',
|
|
||||||
playable: false,
|
|
||||||
created_at: '2018-04-18T12:10:14.315Z',
|
|
||||||
updated_at: '2018-04-18T12:10:14.500Z',
|
|
||||||
status: {
|
|
||||||
icon: 'status_pending',
|
|
||||||
text: 'pending',
|
|
||||||
label: 'pending',
|
|
||||||
group: 'pending',
|
|
||||||
tooltip: 'pending',
|
|
||||||
has_details: true,
|
|
||||||
details_path: '/twitter/flight/-/jobs/966',
|
|
||||||
favicon:
|
|
||||||
'/assets/ci_favicons/dev/favicon_status_pending-db32e1faf94b9f89530ac519790920d1f18ea8f6af6cd2e0a26cd6840cacf101.ico',
|
|
||||||
action: {
|
|
||||||
icon: 'cancel',
|
|
||||||
title: 'Cancel',
|
|
||||||
path: '/twitter/flight/-/jobs/966/cancel',
|
|
||||||
method: 'post',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 208,
|
|
||||||
name: 'rspec:linux 1 3',
|
|
||||||
started: '2018-03-07T06:41:46.233Z',
|
|
||||||
build_path: '/twitter/flight/-/jobs/208',
|
|
||||||
retry_path: '/twitter/flight/-/jobs/208/retry',
|
|
||||||
playable: false,
|
|
||||||
created_at: '2018-03-07T14:41:57.559Z',
|
|
||||||
updated_at: '2018-03-07T14:41:57.559Z',
|
|
||||||
status: {
|
|
||||||
icon: 'status_success',
|
|
||||||
text: 'passed',
|
|
||||||
label: 'passed',
|
|
||||||
group: 'success',
|
|
||||||
tooltip: 'passed',
|
|
||||||
has_details: true,
|
|
||||||
details_path: '/twitter/flight/-/jobs/208',
|
|
||||||
favicon:
|
|
||||||
'/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico',
|
|
||||||
action: {
|
|
||||||
icon: 'retry',
|
|
||||||
title: 'Retry',
|
|
||||||
path: '/twitter/flight/-/jobs/208/retry',
|
|
||||||
method: 'post',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 209,
|
|
||||||
name: 'rspec:linux 2 3',
|
|
||||||
started: '2018-03-07T06:41:46.233Z',
|
|
||||||
build_path: '/twitter/flight/-/jobs/209',
|
|
||||||
retry_path: '/twitter/flight/-/jobs/209/retry',
|
|
||||||
playable: false,
|
|
||||||
created_at: '2018-03-07T14:41:57.605Z',
|
|
||||||
updated_at: '2018-03-07T14:41:57.605Z',
|
|
||||||
status: {
|
|
||||||
icon: 'status_success',
|
|
||||||
text: 'passed',
|
|
||||||
label: 'passed',
|
|
||||||
group: 'success',
|
|
||||||
tooltip: 'passed',
|
|
||||||
has_details: true,
|
|
||||||
details_path: '/twitter/flight/-/jobs/209',
|
|
||||||
favicon:
|
|
||||||
'/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico',
|
|
||||||
action: {
|
|
||||||
icon: 'retry',
|
|
||||||
title: 'Retry',
|
|
||||||
path: '/twitter/flight/-/jobs/209/retry',
|
|
||||||
method: 'post',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 63701097,
|
|
||||||
name: 'spinach-mysql 0 2',
|
|
||||||
started: false,
|
|
||||||
build_path: '/gitlab-org/gitlab-ce/-/jobs/63701097',
|
|
||||||
playable: false,
|
|
||||||
created_at: '2018-04-18T15:16:52.707Z',
|
|
||||||
updated_at: '2018-04-18T15:16:52.707Z',
|
|
||||||
status: {
|
|
||||||
icon: 'status_created',
|
|
||||||
text: 'created',
|
|
||||||
label: 'created',
|
|
||||||
group: 'created',
|
|
||||||
tooltip: 'created',
|
|
||||||
has_details: true,
|
|
||||||
details_path: '/gitlab-org/gitlab-ce/-/jobs/63701097',
|
|
||||||
favicon:
|
|
||||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 63701098,
|
|
||||||
name: 'spinach-mysql 1 2',
|
|
||||||
started: false,
|
|
||||||
build_path: '/gitlab-org/gitlab-ce/-/jobs/63701098',
|
|
||||||
playable: false,
|
|
||||||
created_at: '2018-04-18T15:16:52.808Z',
|
|
||||||
updated_at: '2018-04-18T15:16:52.808Z',
|
|
||||||
status: {
|
|
||||||
icon: 'status_created',
|
|
||||||
text: 'created',
|
|
||||||
label: 'created',
|
|
||||||
group: 'created',
|
|
||||||
tooltip: 'created',
|
|
||||||
has_details: true,
|
|
||||||
details_path: '/gitlab-org/gitlab-ce/-/jobs/63701098',
|
|
||||||
favicon:
|
|
||||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
this.isLoading = false;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.closeDropdown();
|
|
||||||
this.isLoading = false;
|
|
||||||
|
|
||||||
Flash('Something went wrong on our end.');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
closeDropdown() {
|
|
||||||
if (this.isDropdownOpen()) {
|
|
||||||
$(this.$refs.dropdown).dropdown('toggle');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isDropdownOpen() {
|
|
||||||
return this.$el.classList.contains('open');
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
closeDropdown() {
|
||||||
|
if (this.isDropdownOpen()) {
|
||||||
|
$(this.$refs.dropdown).dropdown('toggle');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isDropdownOpen() {
|
||||||
|
return this.$el.classList.contains('open');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.ci-table {
|
.ci-table {
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
|
@ -123,7 +122,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.branch-commit {
|
.branch-commit {
|
||||||
|
|
||||||
.ref-name {
|
.ref-name {
|
||||||
font-weight: $gl-font-weight-bold;
|
font-weight: $gl-font-weight-bold;
|
||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
|
@ -505,7 +503,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.build {
|
.build {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -548,7 +546,6 @@
|
||||||
border: 1px solid $dropdown-toggle-active-border-color;
|
border: 1px solid $dropdown-toggle-active-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Connect first build in each stage with right horizontal line
|
// Connect first build in each stage with right horizontal line
|
||||||
&:first-child {
|
&:first-child {
|
||||||
&::after {
|
&::after {
|
||||||
|
@ -604,15 +601,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Icons inside dropdown
|
Action icons inside dropdowns:
|
||||||
|
- mini graph in pipelines table
|
||||||
|
- dropdown in big graph
|
||||||
|
- mini graph in MR widget pipeline
|
||||||
|
- mini graph in Commit widget pipeline
|
||||||
*/
|
*/
|
||||||
.big-pipeline-graph-dropdown-menu,
|
.big-pipeline-graph-dropdown-menu,
|
||||||
.mini-pipeline-graph-dropdown-menu {
|
.mini-pipeline-graph-dropdown-menu {
|
||||||
|
|
||||||
// override dropdown.scss
|
// override dropdown.scss
|
||||||
&.dropdown-menu li button {
|
&.dropdown-menu li button,
|
||||||
|
&.dropdown-menu li a.ci-action-icon-container {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -622,7 +622,6 @@
|
||||||
right: 5px;
|
right: 5px;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
|
|
||||||
// Action Icons in big pipeline-graph nodes
|
|
||||||
&.ci-action-icon-wrapper {
|
&.ci-action-icon-wrapper {
|
||||||
height: $ci-action-dropdown-button-size;
|
height: $ci-action-dropdown-button-size;
|
||||||
width: $ci-action-dropdown-button-size;
|
width: $ci-action-dropdown-button-size;
|
||||||
|
@ -651,6 +650,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SVGs in the commit widget and mr widget
|
||||||
|
a.ci-action-icon-container.ci-action-icon-wrapper svg {
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Triggers the dropdown in the big pipeline graph
|
// Triggers the dropdown in the big pipeline graph
|
||||||
|
@ -780,74 +784,6 @@ button.mini-pipeline-graph-dropdown-toggle {
|
||||||
@extend .mini-pipeline-graph-dropdown-item:hover;
|
@extend .mini-pipeline-graph-dropdown-item:hover;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action icon on the right
|
|
||||||
a.ci-action-icon-wrapper {
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid $border-color;
|
|
||||||
width: $ci-action-icon-size;
|
|
||||||
height: $ci-action-icon-size;
|
|
||||||
padding: 2px 0 0 5px;
|
|
||||||
font-size: 12px;
|
|
||||||
background-color: $white-light;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: $gl-padding;
|
|
||||||
margin-top: -#{$ci-action-icon-size / 2};
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
background-color: $stage-hover-bg;
|
|
||||||
border: 1px solid $dropdown-toggle-active-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
fill: $gl-text-color-secondary;
|
|
||||||
width: #{$ci-action-icon-size - 6};
|
|
||||||
height: #{$ci-action-icon-size - 6};
|
|
||||||
left: -3px;
|
|
||||||
position: relative;
|
|
||||||
top: -1px;
|
|
||||||
|
|
||||||
&.icon-action-stop,
|
|
||||||
&.icon-action-cancel {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
top: 1px;
|
|
||||||
left: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icon-action-play {
|
|
||||||
width: 11px;
|
|
||||||
height: 11px;
|
|
||||||
top: 1px;
|
|
||||||
left: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icon-action-retry {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
top: 0;
|
|
||||||
left: -3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover svg,
|
|
||||||
&:focus svg {
|
|
||||||
fill: $gl-text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icon-action-retry,
|
|
||||||
&.icon-action-play {
|
|
||||||
svg {
|
|
||||||
width: #{$ci-action-icon-size - 6};
|
|
||||||
height: #{$ci-action-icon-size - 6};
|
|
||||||
left: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// link to the build
|
// link to the build
|
||||||
.mini-pipeline-graph-dropdown-item {
|
.mini-pipeline-graph-dropdown-item {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -988,7 +924,7 @@ button.mini-pipeline-graph-dropdown-toggle {
|
||||||
&.dropdown-menu {
|
&.dropdown-menu {
|
||||||
transform: translate(-80%, 0);
|
transform: translate(-80%, 0);
|
||||||
|
|
||||||
@media(min-width: $screen-md-min) {
|
@media (min-width: $screen-md-min) {
|
||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
right: auto;
|
right: auto;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|
|
@ -16,5 +16,5 @@
|
||||||
%span.ci-build-text= subject.name
|
%span.ci-build-text= subject.name
|
||||||
|
|
||||||
- if status.has_action?
|
- if status.has_action?
|
||||||
= link_to status.action_path, class: "ci-action-icon-wrapper js-ci-action-icon", method: status.action_method, data: { toggle: 'tooltip', title: status.action_title, container: 'body' } do
|
= link_to status.action_path, class: "ci-action-icon-container ci-action-icon-wrapper js-ci-action-icon", method: status.action_method, data: { toggle: 'tooltip', title: status.action_title, container: 'body' } do
|
||||||
= sprite_icon(status.action_icon, css_class: "icon-action-#{status.action_icon}")
|
= sprite_icon(status.action_icon, css_class: "icon-action-#{status.action_icon}")
|
||||||
|
|
Loading…
Reference in a new issue