Makes title section collapsible
In the job log, if the user clicks the section title the job log section will be collapsed
This commit is contained in:
parent
4aa824e705
commit
85e0eb472d
6 changed files with 75 additions and 19 deletions
|
@ -48,9 +48,14 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeEventListener() {
|
removeEventListener() {
|
||||||
this.$el
|
this.$el.querySelectorAll('.js-section-start').forEach(el => {
|
||||||
.querySelectorAll('.js-section-start')
|
const titleSection = el.nextSibling;
|
||||||
.forEach(el => el.removeEventListener('click', this.handleSectionClick));
|
titleSection.removeEventListener(
|
||||||
|
'click',
|
||||||
|
this.handleHeaderClick.bind(this, el, el.dataset.section),
|
||||||
|
);
|
||||||
|
el.removeEventListener('click', this.handleSectionClick);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* The collapsible rows are sent in HTML from the backend
|
* The collapsible rows are sent in HTML from the backend
|
||||||
|
@ -58,9 +63,28 @@ export default {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
handleCollapsibleRows() {
|
handleCollapsibleRows() {
|
||||||
this.$el
|
this.$el.querySelectorAll('.js-section-start').forEach(el => {
|
||||||
.querySelectorAll('.js-section-start')
|
const titleSection = el.nextSibling;
|
||||||
.forEach(el => el.addEventListener('click', this.handleSectionClick));
|
titleSection.addEventListener(
|
||||||
|
'click',
|
||||||
|
this.handleHeaderClick.bind(this, el, el.dataset.section),
|
||||||
|
);
|
||||||
|
el.addEventListener('click', this.handleSectionClick);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
handleHeaderClick(arrowElement, section) {
|
||||||
|
this.updateToggleSection(arrowElement, section);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateToggleSection(arrow, section) {
|
||||||
|
// toggle the arrow class
|
||||||
|
arrow.classList.toggle('fa-caret-right');
|
||||||
|
arrow.classList.toggle('fa-caret-down');
|
||||||
|
|
||||||
|
// hide the sections
|
||||||
|
const sibilings = this.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`);
|
||||||
|
sibilings.forEach(row => row.classList.toggle('hidden'));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* On click, we toggle the hidden class of
|
* On click, we toggle the hidden class of
|
||||||
|
@ -68,14 +92,7 @@ export default {
|
||||||
*/
|
*/
|
||||||
handleSectionClick(evt) {
|
handleSectionClick(evt) {
|
||||||
const clickedArrow = evt.currentTarget;
|
const clickedArrow = evt.currentTarget;
|
||||||
// toggle the arrow class
|
this.updateToggleSection(clickedArrow, clickedArrow.dataset.section);
|
||||||
clickedArrow.classList.toggle('fa-caret-right');
|
|
||||||
clickedArrow.classList.toggle('fa-caret-down');
|
|
||||||
|
|
||||||
const { section } = clickedArrow.dataset;
|
|
||||||
const sibilings = this.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`);
|
|
||||||
|
|
||||||
sibilings.forEach(row => row.classList.toggle('hidden'));
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
5
changelogs/unreleased/63181-collapsible-line.yml
Normal file
5
changelogs/unreleased/63181-collapsible-line.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Makes collapsible title clickable in job log
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -218,7 +218,7 @@ module Gitlab
|
||||||
return if @sections.include?(section)
|
return if @sections.include?(section)
|
||||||
|
|
||||||
@sections << section
|
@sections << section
|
||||||
write_raw %{<div class="js-section-start fa fa-caret-down append-right-8 cursor-pointer" data-timestamp="#{timestamp}" data-section="#{data_section_names}" role="button"></div>}
|
write_raw %{<div class="js-section-start fa fa-caret-down pr-2 cursor-pointer" data-timestamp="#{timestamp}" data-section="#{data_section_names}" role="button"></div>}
|
||||||
@lineno_in_section = 0
|
@lineno_in_section = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ module Gitlab
|
||||||
css_classes << "section"
|
css_classes << "section"
|
||||||
|
|
||||||
css_classes << if @lineno_in_section == 0
|
css_classes << if @lineno_in_section == 0
|
||||||
"js-section-header section-header"
|
"js-section-header section-header cursor-pointer"
|
||||||
else
|
else
|
||||||
"line"
|
"line"
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,6 +50,20 @@ describe 'User browses a job', :js do
|
||||||
expect(page).not_to have_content(text_to_hide)
|
expect(page).not_to have_content(text_to_hide)
|
||||||
expect(page).to have_content(text_to_show)
|
expect(page).to have_content(text_to_show)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'collapses the section header clicked' do
|
||||||
|
wait_for_requests
|
||||||
|
text_to_hide = "Cloning into '/nolith/ci-tests'"
|
||||||
|
text_to_show = 'Waiting for pod'
|
||||||
|
|
||||||
|
expect(page).to have_content(text_to_hide)
|
||||||
|
expect(page).to have_content(text_to_show)
|
||||||
|
|
||||||
|
first('.js-section-header.js-s-get-sources').click
|
||||||
|
|
||||||
|
expect(page).not_to have_content(text_to_hide)
|
||||||
|
expect(page).to have_content(text_to_show)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when job trace contains sections' do
|
context 'when job trace contains sections' do
|
||||||
|
|
|
@ -98,5 +98,25 @@ describe('Job Log', () => {
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('toggles hidden class to the sibilings rows when header section is clicked', done => {
|
||||||
|
vm.$nextTick()
|
||||||
|
.then(() => {
|
||||||
|
const { section } = vm.$el.querySelector('.js-section-header').dataset;
|
||||||
|
vm.$el.querySelector('.js-section-header').click();
|
||||||
|
|
||||||
|
vm.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`).forEach(el => {
|
||||||
|
expect(el.classList.contains('hidden')).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.$el.querySelector('.js-section-header').click();
|
||||||
|
|
||||||
|
vm.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`).forEach(el => {
|
||||||
|
expect(el.classList.contains('hidden')).toEqual(false);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(done)
|
||||||
|
.catch(done.fail);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -209,7 +209,7 @@ describe Gitlab::Ci::Ansi2html do
|
||||||
let(:section_start) { "section_start:#{section_start_time.to_i}:#{section_name}\r\033[0K"}
|
let(:section_start) { "section_start:#{section_start_time.to_i}:#{section_name}\r\033[0K"}
|
||||||
let(:section_end) { "section_end:#{section_end_time.to_i}:#{section_name}\r\033[0K"}
|
let(:section_end) { "section_end:#{section_end_time.to_i}:#{section_name}\r\033[0K"}
|
||||||
let(:section_start_html) do
|
let(:section_start_html) do
|
||||||
'<div class="js-section-start fa fa-caret-down append-right-8 cursor-pointer"' \
|
'<div class="js-section-start fa fa-caret-down pr-2 cursor-pointer"' \
|
||||||
" data-timestamp=\"#{section_start_time.to_i}\" data-section=\"#{class_name(section_name)}\"" \
|
" data-timestamp=\"#{section_start_time.to_i}\" data-section=\"#{class_name(section_name)}\"" \
|
||||||
' role="button"></div>'
|
' role="button"></div>'
|
||||||
end
|
end
|
||||||
|
@ -233,8 +233,8 @@ describe Gitlab::Ci::Ansi2html do
|
||||||
|
|
||||||
it 'prints light red' do
|
it 'prints light red' do
|
||||||
text = "#{section_start}\e[91mHello\e[0m\nLine 1\nLine 2\nLine 3\n#{section_end}"
|
text = "#{section_start}\e[91mHello\e[0m\nLine 1\nLine 2\nLine 3\n#{section_end}"
|
||||||
header = %{<span class="term-fg-l-red section js-section-header section-header js-s-#{class_name(section_name)}">Hello</span>}
|
header = %{<span class="term-fg-l-red section js-section-header section-header cursor-pointer js-s-#{class_name(section_name)}">Hello</span>}
|
||||||
line_break = %{<span class="section js-section-header section-header js-s-#{class_name(section_name)}"><br/></span>}
|
line_break = %{<span class="section js-section-header section-header cursor-pointer js-s-#{class_name(section_name)}"><br/></span>}
|
||||||
output_line = %{<span class="section line js-s-#{class_name(section_name)}">Line 1<br/>Line 2<br/>Line 3<br/></span>}
|
output_line = %{<span class="section line js-s-#{class_name(section_name)}">Line 1<br/>Line 2<br/>Line 3<br/></span>}
|
||||||
html = "#{section_start_html}#{header}#{line_break}#{output_line}#{section_end_html}"
|
html = "#{section_start_html}#{header}#{line_break}#{output_line}#{section_end_html}"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue