Commit a0d0ffe5 authored by Luke "Jared" Bennett's avatar Luke "Jared" Bennett

added inline pipeline graph

Added tests

review changes
parent 1bbc99f1
...@@ -159,6 +159,11 @@ ...@@ -159,6 +159,11 @@
new ZenMode(); new ZenMode();
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
break; break;
case 'projects:commit:pipelines':
new gl.MiniPipelineGraph({
container: '.js-pipeline-table',
}).bindEvents();
break;
case 'projects:commits:show': case 'projects:commits:show':
case 'projects:activity': case 'projects:activity':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
......
...@@ -51,6 +51,8 @@ require('./smart_interval'); ...@@ -51,6 +51,8 @@ require('./smart_interval');
this.getCIStatus(false); this.getCIStatus(false);
this.retrieveSuccessIcon(); this.retrieveSuccessIcon();
this.initMiniPipelineGraph();
this.ciStatusInterval = new global.SmartInterval({ this.ciStatusInterval = new global.SmartInterval({
callback: this.getCIStatus.bind(this, true), callback: this.getCIStatus.bind(this, true),
startingInterval: 10000, startingInterval: 10000,
...@@ -66,6 +68,7 @@ require('./smart_interval'); ...@@ -66,6 +68,7 @@ require('./smart_interval');
incrementByFactorOf: 15000, incrementByFactorOf: 15000,
immediateExecution: true, immediateExecution: true,
}); });
notifyPermissions(); notifyPermissions();
} }
...@@ -236,17 +239,20 @@ require('./smart_interval'); ...@@ -236,17 +239,20 @@ require('./smart_interval');
case "failed": case "failed":
case "canceled": case "canceled":
case "not_found": case "not_found":
return this.setMergeButtonClass('btn-danger'); this.setMergeButtonClass('btn-danger');
break;
case "running": case "running":
return this.setMergeButtonClass('btn-info'); this.setMergeButtonClass('btn-info');
break;
case "success": case "success":
case "success_with_warnings": case "success_with_warnings":
return this.setMergeButtonClass('btn-create'); this.setMergeButtonClass('btn-create');
} }
} else { } else {
$('.ci_widget.ci-error').show(); $('.ci_widget.ci-error').show();
return this.setMergeButtonClass('btn-danger'); this.setMergeButtonClass('btn-danger');
} }
this.initMiniPipelineGraph();
}; };
MergeRequestWidget.prototype.showCICoverage = function(coverage) { MergeRequestWidget.prototype.showCICoverage = function(coverage) {
...@@ -269,6 +275,12 @@ require('./smart_interval'); ...@@ -269,6 +275,12 @@ require('./smart_interval');
$('.js-commit-link').text(`#${id}`).attr('href', [commitsUrl, id].join('/')); $('.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; return MergeRequestWidget;
})(); })();
})(window.gl || (window.gl = {})); })(window.gl || (window.gl = {}));
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
this.container = opts.container || ''; this.container = opts.container || '';
this.dropdownListSelector = '.js-builds-dropdown-container'; this.dropdownListSelector = '.js-builds-dropdown-container';
this.getBuildsList = this.getBuildsList.bind(this); this.getBuildsList = this.getBuildsList.bind(this);
this.bindEvents();
} }
/** /**
......
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
.ci_widget { .ci_widget {
border-bottom: 1px solid $well-inner-border; border-bottom: 1px solid $well-inner-border;
color: $gl-text-color; color: $gl-text-color;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
svg { svg {
margin-right: 4px; margin-right: 4px;
...@@ -88,12 +92,20 @@ ...@@ -88,12 +92,20 @@
overflow: visible; overflow: visible;
} }
&> span {
padding-right: 4px;
}
&.ci-success_with_warnings { &.ci-success_with_warnings {
i { i {
color: $gl-warning; color: $gl-warning;
} }
} }
@media (max-width: $screen-xs-max) {
flex-wrap: wrap;
}
} }
.mr-widget-body, .mr-widget-body,
...@@ -102,6 +114,37 @@ ...@@ -102,6 +114,37 @@
padding: $gl-padding; 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 { .normal {
color: $gl-text-color; color: $gl-text-color;
} }
......
...@@ -183,48 +183,6 @@ ...@@ -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, .duration,
.finished-at { .finished-at {
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
...@@ -311,6 +269,48 @@ ...@@ -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 { .admin-builds-table {
.ci-table td:last-child { .ci-table td:last-child {
min-width: 120px; min-width: 120px;
......
...@@ -40,25 +40,8 @@ ...@@ -40,25 +40,8 @@
- else - else
Cant find HEAD commit for this branch Cant find HEAD commit for this branch
%td.stage-cell %td
- pipeline.stages.each do |stage| = render 'shared/mini_pipeline_graph', pipeline: pipeline, klass: 'js-mini-pipeline-graph'
- 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 %td
- if pipeline.duration - if pipeline.duration
......
- if @pipeline - if @pipeline
.mr-widget-heading .mr-widget-heading
- %w[success success_with_warnings skipped canceled failed running pending].each do |status| - %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) } .ci_widget{ class: "ci-#{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 %div{ class: "ci-status-icon-#{status}" }
= ci_icon_for_status(status) = link_to namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'icon-link' do
= ci_icon_for_status(status)
%span %span
Pipeline Pipeline
= link_to "##{@pipeline.id}", namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'pipeline' = link_to "##{@pipeline.id}", namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'pipeline'
= ci_label_for_status(status) = ci_label_for_status(status)
for .mr-widget-pipeline-graph
= succeed "." do = render 'shared/mini_pipeline_graph', pipeline: @pipeline, klass: 'js-pipeline-inline-mr-widget-graph'
= 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
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 %span.ci-coverage
- elsif @merge_request.has_ci? - elsif @merge_request.has_ci?
......
.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
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'); ...@@ -31,7 +31,7 @@ require('~/mini_pipeline_graph_dropdown');
it('should call getBuildsList', () => { it('should call getBuildsList', () => {
const getBuildsListSpy = spyOn(gl.MiniPipelineGraph.prototype, 'getBuildsList').and.callFake(function () {}); 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(); document.querySelector('.js-builds-dropdown-button').click();
...@@ -41,7 +41,7 @@ require('~/mini_pipeline_graph_dropdown'); ...@@ -41,7 +41,7 @@ require('~/mini_pipeline_graph_dropdown');
it('should make a request to the endpoint provided in the html', () => { it('should make a request to the endpoint provided in the html', () => {
const ajaxSpy = spyOn($, 'ajax').and.callFake(function () {}); 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(); document.querySelector('.js-builds-dropdown-button').click();
expect(ajaxSpy.calls.allArgs()[0][0].url).toEqual('foobar'); expect(ajaxSpy.calls.allArgs()[0][0].url).toEqual('foobar');
......
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