added inline pipeline graph
Added tests review changes
This commit is contained in:
parent
1bbc99f1c8
commit
a0d0ffe53b
10 changed files with 238 additions and 75 deletions
|
@ -159,6 +159,11 @@
|
|||
new ZenMode();
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
break;
|
||||
case 'projects:commit:pipelines':
|
||||
new gl.MiniPipelineGraph({
|
||||
container: '.js-pipeline-table',
|
||||
}).bindEvents();
|
||||
break;
|
||||
case 'projects:commits:show':
|
||||
case 'projects:activity':
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
|
|
|
@ -51,6 +51,8 @@ require('./smart_interval');
|
|||
this.getCIStatus(false);
|
||||
this.retrieveSuccessIcon();
|
||||
|
||||
this.initMiniPipelineGraph();
|
||||
|
||||
this.ciStatusInterval = new global.SmartInterval({
|
||||
callback: this.getCIStatus.bind(this, true),
|
||||
startingInterval: 10000,
|
||||
|
@ -66,6 +68,7 @@ require('./smart_interval');
|
|||
incrementByFactorOf: 15000,
|
||||
immediateExecution: true,
|
||||
});
|
||||
|
||||
notifyPermissions();
|
||||
}
|
||||
|
||||
|
@ -236,17 +239,20 @@ require('./smart_interval');
|
|||
case "failed":
|
||||
case "canceled":
|
||||
case "not_found":
|
||||
return this.setMergeButtonClass('btn-danger');
|
||||
this.setMergeButtonClass('btn-danger');
|
||||
break;
|
||||
case "running":
|
||||
return this.setMergeButtonClass('btn-info');
|
||||
this.setMergeButtonClass('btn-info');
|
||||
break;
|
||||
case "success":
|
||||
case "success_with_warnings":
|
||||
return this.setMergeButtonClass('btn-create');
|
||||
this.setMergeButtonClass('btn-create');
|
||||
}
|
||||
} else {
|
||||
$('.ci_widget.ci-error').show();
|
||||
return this.setMergeButtonClass('btn-danger');
|
||||
this.setMergeButtonClass('btn-danger');
|
||||
}
|
||||
this.initMiniPipelineGraph();
|
||||
};
|
||||
|
||||
MergeRequestWidget.prototype.showCICoverage = function(coverage) {
|
||||
|
@ -269,6 +275,12 @@ require('./smart_interval');
|
|||
$('.js-commit-link').text(`#${id}`).attr('href', [commitsUrl, id].join('/'));
|
||||
};
|
||||
|
||||
MergeRequestWidget.prototype.initMiniPipelineGraph = function() {
|
||||
new gl.MiniPipelineGraph({
|
||||
container: '.js-pipeline-inline-mr-widget-graph:visible',
|
||||
}).bindEvents();
|
||||
};
|
||||
|
||||
return MergeRequestWidget;
|
||||
})();
|
||||
})(window.gl || (window.gl = {}));
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
this.container = opts.container || '';
|
||||
this.dropdownListSelector = '.js-builds-dropdown-container';
|
||||
this.getBuildsList = this.getBuildsList.bind(this);
|
||||
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -80,6 +80,10 @@
|
|||
.ci_widget {
|
||||
border-bottom: 1px solid $well-inner-border;
|
||||
color: $gl-text-color;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
margin-right: 4px;
|
||||
|
@ -88,12 +92,20 @@
|
|||
overflow: visible;
|
||||
}
|
||||
|
||||
&> span {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
&.ci-success_with_warnings {
|
||||
|
||||
i {
|
||||
color: $gl-warning;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.mr-widget-body,
|
||||
|
@ -102,6 +114,37 @@
|
|||
padding: $gl-padding;
|
||||
}
|
||||
|
||||
.mr-widget-pipeline-graph {
|
||||
flex-shrink: 0;
|
||||
|
||||
.dropdown-menu {
|
||||
margin-top: 11px;
|
||||
}
|
||||
|
||||
.ci-action-icon-wrapper {
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: $screen-xs-max) {
|
||||
order: 1;
|
||||
margin-top: $gl-padding-top;
|
||||
border-radius: 3px;
|
||||
background-color: $white-light;
|
||||
border: 1px solid $gray-darker;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
.dropdown-menu {
|
||||
margin-left: -97.5px;
|
||||
}
|
||||
|
||||
.arrow-up::before,
|
||||
.arrow-up::after, {
|
||||
margin-left: 97.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.normal {
|
||||
color: $gl-text-color;
|
||||
}
|
||||
|
|
|
@ -183,48 +183,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.stage-cell {
|
||||
font-size: 0;
|
||||
padding: 10px 4px;
|
||||
|
||||
> .stage-container > div > button > span > svg,
|
||||
> .stage-container > button > svg {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
z-index: 2;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.stage-container {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
height: 22px;
|
||||
margin: 3px 6px 3px 0;
|
||||
|
||||
.tooltip {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
padding: 3px 4px;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
&::after {
|
||||
content: '';
|
||||
width: 7px;
|
||||
position: absolute;
|
||||
right: -7px;
|
||||
top: 10px;
|
||||
border-bottom: 2px solid $border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.duration,
|
||||
.finished-at {
|
||||
color: $gl-text-color-secondary;
|
||||
|
@ -311,6 +269,48 @@
|
|||
}
|
||||
}
|
||||
|
||||
.stage-cell {
|
||||
font-size: 0;
|
||||
padding: 10px 4px;
|
||||
|
||||
> .stage-container > div > button > span > svg,
|
||||
> .stage-container > button > svg {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
z-index: 2;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.stage-container {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
height: 22px;
|
||||
margin: 3px 6px 3px 0;
|
||||
|
||||
.tooltip {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
padding: 3px 4px;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
&::after {
|
||||
content: '';
|
||||
width: 7px;
|
||||
position: absolute;
|
||||
right: -7px;
|
||||
top: 10px;
|
||||
border-bottom: 2px solid $border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.admin-builds-table {
|
||||
.ci-table td:last-child {
|
||||
min-width: 120px;
|
||||
|
|
|
@ -40,25 +40,8 @@
|
|||
- else
|
||||
Cant find HEAD commit for this branch
|
||||
|
||||
%td.stage-cell
|
||||
- pipeline.stages.each do |stage|
|
||||
- if stage.status
|
||||
- detailed_status = stage.detailed_status(current_user)
|
||||
- icon_status = "#{detailed_status.icon}_borderless"
|
||||
- status_klass = "ci-status-icon ci-status-icon-#{detailed_status.group}"
|
||||
|
||||
.stage-container.dropdown.js-mini-pipeline-graph
|
||||
%button.mini-pipeline-graph-dropdown-toggle.has-tooltip.js-builds-dropdown-button{ class: "ci-status-icon-#{detailed_status.group}", type: 'button', data: { toggle: 'dropdown', title: "#{stage.name}: #{detailed_status.label}", placement: 'top', "stage-endpoint" => stage_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline, stage: stage.name) } }
|
||||
= custom_icon(icon_status)
|
||||
= icon('caret-down')
|
||||
|
||||
%ul.dropdown-menu.mini-pipeline-graph-dropdown-menu.js-builds-dropdown-container
|
||||
.arrow-up
|
||||
.js-builds-dropdown-list.scrollable-menu
|
||||
|
||||
.js-builds-dropdown-loading.builds-dropdown-loading.hidden
|
||||
%span.fa.fa-spinner.fa-spin
|
||||
|
||||
%td
|
||||
= render 'shared/mini_pipeline_graph', pipeline: pipeline, klass: 'js-mini-pipeline-graph'
|
||||
|
||||
%td
|
||||
- if pipeline.duration
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
- if @pipeline
|
||||
.mr-widget-heading
|
||||
- %w[success success_with_warnings skipped canceled failed running pending].each do |status|
|
||||
.ci_widget{ class: "ci-#{status} ci-status-icon-#{status}", style: ("display:none" unless @pipeline.status == status) }
|
||||
= link_to namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'icon-link' do
|
||||
= ci_icon_for_status(status)
|
||||
.ci_widget{ class: "ci-#{status}", style: ("display:none" unless @pipeline.status == status) }
|
||||
%div{ class: "ci-status-icon-#{status}" }
|
||||
= link_to namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'icon-link' do
|
||||
= ci_icon_for_status(status)
|
||||
%span
|
||||
Pipeline
|
||||
= link_to "##{@pipeline.id}", namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'pipeline'
|
||||
= ci_label_for_status(status)
|
||||
for
|
||||
= succeed "." do
|
||||
= link_to @pipeline.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @pipeline.sha), class: "monospace js-commit-link"
|
||||
.mr-widget-pipeline-graph
|
||||
= render 'shared/mini_pipeline_graph', pipeline: @pipeline, klass: 'js-pipeline-inline-mr-widget-graph'
|
||||
%span
|
||||
for
|
||||
= succeed "." do
|
||||
= link_to @pipeline.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @pipeline.sha), class: "monospace js-commit-link"
|
||||
%span.ci-coverage
|
||||
|
||||
- elsif @merge_request.has_ci?
|
||||
|
|
18
app/views/shared/_mini_pipeline_graph.html.haml
Normal file
18
app/views/shared/_mini_pipeline_graph.html.haml
Normal file
|
@ -0,0 +1,18 @@
|
|||
.stage-cell
|
||||
- pipeline.stages.each do |stage|
|
||||
- if stage.status
|
||||
- detailed_status = stage.detailed_status(current_user)
|
||||
- icon_status = "#{detailed_status.icon}_borderless"
|
||||
- status_klass = "ci-status-icon ci-status-icon-#{detailed_status.group}"
|
||||
|
||||
.stage-container.dropdown{ class: klass }
|
||||
%button.mini-pipeline-graph-dropdown-toggle.has-tooltip.js-builds-dropdown-button{ class: "ci-status-icon-#{detailed_status.group}", type: 'button', data: { toggle: 'dropdown', title: "#{stage.name}: #{detailed_status.label}", placement: 'top', "stage-endpoint" => stage_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline, stage: stage.name) } }
|
||||
= custom_icon(icon_status)
|
||||
= icon('caret-down')
|
||||
|
||||
%ul.dropdown-menu.mini-pipeline-graph-dropdown-menu.js-builds-dropdown-container
|
||||
.arrow-up
|
||||
.js-builds-dropdown-list.scrollable-menu
|
||||
|
||||
.js-builds-dropdown-loading.builds-dropdown-loading.hidden
|
||||
%span.fa.fa-spinner.fa-spin
|
100
spec/features/merge_requests/mini_pipeline_graph_spec.rb
Normal file
100
spec/features/merge_requests/mini_pipeline_graph_spec.rb
Normal file
|
@ -0,0 +1,100 @@
|
|||
require 'rails_helper'
|
||||
|
||||
feature 'Mini Pipeline Graph', :js, :feature do
|
||||
include WaitForAjax
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public) }
|
||||
let(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
||||
let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running', sha: project.commit.id) }
|
||||
let(:build) { create(:ci_build, pipeline: pipeline, stage: 'test', commands: 'test') }
|
||||
|
||||
before do
|
||||
build.run
|
||||
|
||||
login_as(user)
|
||||
visit namespace_project_merge_request_path(project.namespace, project, merge_request)
|
||||
end
|
||||
|
||||
it 'should display a mini pipeline graph' do
|
||||
expect(page).to have_selector('.mr-widget-pipeline-graph')
|
||||
end
|
||||
|
||||
describe 'build list toggle' do
|
||||
let(:toggle) do
|
||||
find('.mini-pipeline-graph-dropdown-toggle')
|
||||
first('.mini-pipeline-graph-dropdown-toggle')
|
||||
end
|
||||
|
||||
it 'should expand when hovered' do
|
||||
before_width = evaluate_script("$('.mini-pipeline-graph-dropdown-toggle:visible').outerWidth();")
|
||||
|
||||
toggle.hover
|
||||
|
||||
after_width = evaluate_script("$('.mini-pipeline-graph-dropdown-toggle:visible').outerWidth();")
|
||||
|
||||
expect(before_width).to be < after_width
|
||||
end
|
||||
|
||||
it 'should show dropdown caret when hovered' do
|
||||
toggle.hover
|
||||
|
||||
expect(toggle).to have_selector('.fa-caret-down')
|
||||
end
|
||||
|
||||
it 'should show tooltip when hovered' do
|
||||
toggle.hover
|
||||
|
||||
expect(toggle.find(:xpath, '..')).to have_selector('.tooltip')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'builds list menu' do
|
||||
let(:toggle) do
|
||||
find('.mini-pipeline-graph-dropdown-toggle')
|
||||
first('.mini-pipeline-graph-dropdown-toggle')
|
||||
end
|
||||
|
||||
before do
|
||||
toggle.click
|
||||
wait_for_ajax
|
||||
end
|
||||
|
||||
it 'should open when toggle is clicked' do
|
||||
expect(toggle.find(:xpath, '..')).to have_selector('.mini-pipeline-graph-dropdown-menu')
|
||||
end
|
||||
|
||||
it 'should close when toggle is clicked again' do
|
||||
toggle.click
|
||||
|
||||
expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
|
||||
end
|
||||
|
||||
it 'should close when clicking somewhere else' do
|
||||
find('body').click
|
||||
|
||||
expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
|
||||
end
|
||||
|
||||
describe 'build list build item' do
|
||||
let(:build_item) do
|
||||
find('.mini-pipeline-graph-dropdown-item')
|
||||
first('.mini-pipeline-graph-dropdown-item')
|
||||
end
|
||||
|
||||
it 'should visit the build page when clicked' do
|
||||
build_item.click
|
||||
find('.build-page')
|
||||
|
||||
expect(current_path).to eql(namespace_project_build_path(project.namespace, project, build))
|
||||
end
|
||||
|
||||
it 'should show tooltip when hovered' do
|
||||
build_item.hover
|
||||
|
||||
expect(build_item.find(:xpath, '..')).to have_selector('.tooltip')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -31,7 +31,7 @@ require('~/mini_pipeline_graph_dropdown');
|
|||
it('should call getBuildsList', () => {
|
||||
const getBuildsListSpy = spyOn(gl.MiniPipelineGraph.prototype, 'getBuildsList').and.callFake(function () {});
|
||||
|
||||
new gl.MiniPipelineGraph({ container: '.js-builds-dropdown-tests' });
|
||||
new gl.MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
|
||||
|
||||
document.querySelector('.js-builds-dropdown-button').click();
|
||||
|
||||
|
@ -41,7 +41,7 @@ require('~/mini_pipeline_graph_dropdown');
|
|||
it('should make a request to the endpoint provided in the html', () => {
|
||||
const ajaxSpy = spyOn($, 'ajax').and.callFake(function () {});
|
||||
|
||||
new gl.MiniPipelineGraph({ container: '.js-builds-dropdown-tests' });
|
||||
new gl.MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
|
||||
|
||||
document.querySelector('.js-builds-dropdown-button').click();
|
||||
expect(ajaxSpy.calls.allArgs()[0][0].url).toEqual('foobar');
|
||||
|
|
Loading…
Reference in a new issue