diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 6595010d221..3e52c482ece 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -525,3 +525,4 @@ Pipeline Graph */ $stage-hover-bg: #eaf3fc; $stage-hover-border: #d1e7fc; +$action-icon-color: #d6d6d6; diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 1e4f242d40d..6061e53f386 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -177,12 +177,13 @@ .stage-cell { font-size: 0; - svg { - height: 18px; - width: 18px; - position: relative; + > .stage-container > button > svg { + height: 22px; + width: 22px; + position: absolute; + top: -1px; + left: -1px; z-index: 2; - vertical-align: middle; overflow: visible; } @@ -200,7 +201,7 @@ content: ''; width: 8px; position: absolute; - right: -7px; + right: -8px; top: 10px; border-bottom: 2px solid $border-color; } @@ -470,6 +471,47 @@ white-space: normal; color: $gl-text-color-secondary; + // Action Icons in big pipeline-graph nodes + > .ci-action-icon-container .ci-action-icon-wrapper { + i { + color: $border-color; + border-radius: 100%; + border: 1px solid $border-color; + padding: 5px 6px; + font-size: 13px; + background: $white-light; + height: 30px; + width: 30px; + + &::before { + position: relative; + top: 3px; + left: 3px; + } + + &:hover { + color: $gl-text-color; + background-color: $stage-hover-bg; + border: 1px solid $stage-hover-bg; + } + } + + .ci-play-icon { + padding: 5px 5px 5px 7px; + } + } + + > .ci-action-icon-container { + position: absolute; + right: 5px; + top: 5px; + } + + .ci-status-icon svg { + height: 20px; + width: 20px; + } + .dropdown-menu-toggle { background-color: transparent; border: none; @@ -504,16 +546,6 @@ } } - > .ci-action-icon-container { - position: absolute; - right: 5px; - top: 5px; - } - - .ci-status-icon svg { - height: 20px; - width: 20px; - } .arrow { &::before, @@ -596,29 +628,9 @@ } } } - - .grouped-pipeline-dropdown { - .dropdown-build { - .build-content { - width: 100%; - - &:hover { - background-color: $stage-hover-bg; - color: $gl-text-color; - } - } - - .ci-action-icon-container { - padding: 0; - font-size: 11px; - position: absolute; - top: 1px; - right: 8px; - } - } - } } +// Triggers the dropdown in the big pipeline graph .dropdown-counter-badge { color: $border-color; font-weight: 100; @@ -628,7 +640,8 @@ top: 8px; } -.grouped-pipeline-dropdown { +// Dropdown in the big pipeline graph +.big-pipeline-graph-dropdown-menu { padding: 0; width: 195px; min-width: 195px; @@ -636,56 +649,6 @@ right: -195px; top: -4px; box-shadow: 0 1px 5px $black-transparent; - - a { - display: inline-block; - } - - .dropdown-build { - .build-content { - width: 100%; - - &:hover { - background-color: $stage-hover-bg; - color: $gl-text-color; - } - } - - .ci-action-icon-container { - padding: 0; - font-size: 11px; - position: absolute; - margin-top: 3px; - right: 7px; - } - } - - ul { - max-height: 245px; - overflow: auto; - margin: 3px 0; - - li { - margin: 4px 8px 4px 9px; - padding: 0; - line-height: 1.1; - position: relative; - - .ci-action-icon-container:hover { - background-color: transparent; - } - - .ci-status-icon { - position: relative; - top: 2px; - } - } - } -} - -.pipeline-graph .dropdown-build .ci-status-icon svg { - width: 18px; - height: 18px; } .ci-status-text { @@ -699,177 +662,217 @@ font-weight: 200; } -// Action Icons -.ci-action-icon-container .ci-action-icon-wrapper { - i { - color: $border-color; - border-radius: 100%; - border: 1px solid $border-color; - padding: 5px 6px; - font-size: 13px; - background: $white-light; - height: 30px; - width: 30px; +// Dropdown button in mini pipeline graph +.mini-pipeline-graph-dropdown-toggle { + border-radius: 100px; + background-color: $white-light; + border-width: 1px; + border-style: solid; + width: 22px; + height: 22px; + margin: 0; + padding: 0; + transition: all 0.2s linear; + position: relative; - &::before { - position: relative; - top: 3px; - left: 3px; - } + > .fa.fa-caret-down { + position: absolute; + left: 20px; + top: 5px; + display: inline-block; + visibility: hidden; + opacity: 0; + color: inherit; + font-size: 12px; + transition: visibility 0.1s, opacity 0.1s linear; + } - &:hover { - color: $gl-text-color; - background-color: $stage-hover-bg; - border: 1px solid $stage-hover-bg; + &:active, + &:focus, + &:hover { + outline: none; + width: 35px; + + .fa.fa-caret-down { + visibility: visible; + opacity: 1; } } - .ci-play-icon { - padding: 5px 5px 5px 7px; + // Dropdown button animation in mini pipeline graph + &.ci-status-icon-success { + border-color: $gl-success; + color: $gl-success; + + &:hover, + &:focus, + &:active { + background-color: rgba($gl-success, 0.1); + border-color: $gl-success; + } + } + + &.ci-status-icon-failed { + border-color: $gl-danger; + color: $gl-danger; + + &:hover, + &:focus, + &:active { + background-color: rgba($gl-danger, 0.1); + border-color: $gl-danger; + } + } + + &.ci-status-icon-pending, + &.ci-status-icon-success_with_warnings { + border-color: $gl-warning; + color: $gl-warning; + + &:hover, + &:focus, + &:active { + background-color: rgba($gl-warning, 0.1); + border-color: $gl-warning; + } + } + + &.ci-status-icon-running { + border-color: $blue-normal; + color: $blue-normal; + + &:hover, + &:focus, + &:active { + background-color: rgba($blue-normal, 0.1); + border-color: $blue-normal; + } + } + + &.ci-status-icon-canceled, + &.ci-status-icon-disabled, + &.ci-status-icon-not-found, + &.ci-status-icon-manual { + border-color: $gl-text-color; + color: $gl-text-color; + + &:hover, + &:focus, + &:active { + background-color: rgba($gl-text-color, 0.1); + border-color: $gl-text-color; + } + } + + &.ci-status-icon-created, + &.ci-status-icon-skipped { + border-color: $gray-darkest; + color: $gray-darkest; + + &:hover, + &:focus, + &:active { + background-color: rgba($gray-darkest, 0.1); + border-color: $gray-darkest; + } } } -.dropdown-build { - color: $gl-text-color-secondary; +// dropdown content for big and mini pipeline +.big-pipeline-graph-dropdown-menu, +.mini-pipeline-graph-dropdown-menu { + width: 195px; + max-width: 195px; - .build-content { - padding: 4px 7px 8px; + li { + padding: 2px 3px; } - .ci-action-icon-container { - padding: 0; - font-size: 11px; - float: right; - margin-top: 3px; - display: inline-block; - position: relative; + .scrollable-menu { + max-height: 245px; + overflow: auto; + } - i { - font-size: 11px; - margin-top: 0; + // Loading icon + .builds-dropdown-loading { + margin: 0 auto; + width: 20px; + } + + // Action icon on the right + a.ci-action-icon-wrapper { + color: $action-icon-color; + border: 1px solid $action-icon-color; + border-radius: 20px; + width: 22px; + height: 22px; + padding: 2px 0 0 5px; + cursor: pointer; + float: right; + margin: -26px 9px 0 0; + font-size: 12px; + background-color: $white-light; + + &:hover, + &:focus { + text-decoration: none; + color: $gl-text-color; + background-color: $stage-hover-bg; + border: 1px solid transparent; } } - .ci-action-icon-container { - i { - width: 24px; - height: 24px; + // link to the build + .mini-pipeline-graph-dropdown-item { + padding: 3px 7px 4px; + clear: both; + font-weight: normal; + line-height: 1.428571429; + white-space: nowrap; + margin: 0 5px; + border-radius: 3px; - &::before { - top: 1px; - left: 1px; + // build name + .ci-build-text { + font-weight: 200; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + width: 90px; + color: $gl-text-color-secondary; + margin-left: 2px; + display: inline-block; + top: 1px; + vertical-align: text-bottom; + position: relative; + } + + // status icon on the left + .ci-status-icon { + top: 3px; + position: relative; + + > svg { + overflow: visible; + width: 18px; + height: 18px; } } - } - .stage { - max-width: 100px; - width: 100px; - } - - .ci-status-icon svg { - height: 18px; - width: 18px; - } - - .ci-status-text { - max-width: 95px; + &:hover, + &:focus { + outline: none; + text-decoration: none; + color: $gl-text-color; + background-color: $stage-hover-bg; + } } } /** - * Builds dropdown in mini pipeline + * Top arrow in the dropdown in the mini pipeline graph */ -.mini-pipeline-graph { - .builds-dropdown { - background-color: transparent; - padding: 0; - color: $gl-text-color-secondary; - border: none; - margin: 0; - - &:focus, - &:hover { - outline: none; - margin-right: -8px; - - .ci-status-icon { - width: 32px; - padding: 0 8px 0 0; - transition: width 0.1s cubic-bezier(0.25, 0, 1, 1); - - + .dropdown-caret { - visibility: visible; - opacity: 1; - } - } - } - - &:focus, - &:active { - .ci-status-icon-success { - background-color: rgba($gl-success, .1); - } - - .ci-status-icon-failed { - background-color: rgba($gl-danger, .1); - } - - .ci-status-icon-pending, - .ci-status-icon-success_with_warnings { - background-color: rgba($gl-warning, .1); - } - - .ci-status-icon-running { - background-color: rgba($blue-normal, .1); - } - - .ci-status-icon-canceled, - .ci-status-icon-disabled, - .ci-status-icon-not-found { - background-color: rgba($gl-text-color, .1); - } - - .ci-status-icon-created, - .ci-status-icon-skipped { - background-color: rgba($gray-darkest, .1); - } - } - - .mini-pipeline-graph-icon-container { - .dropdown-caret { - font-size: 11px; - position: absolute; - top: 6px; - left: 20px; - margin-right: -6px; - z-index: 2; - visibility: hidden; - opacity: 0; - transition: visibility 0.1s, opacity 0.1s linear; - } - } - } - - .dropdown-build .build-content { - padding: 3px 7px 7px; - } - - .builds-dropdown-loading { - margin: 10px auto; - width: 18px; - } - - .grouped-pipeline-dropdown { - right: -172px; - top: 23px; - min-height: 50px; - - a { - color: $gl-text-color-secondary; - } - } - +.mini-pipeline-graph-dropdown-menu { .arrow-up { &::before, &::after { @@ -898,31 +901,8 @@ } /** - * Icons in mini pipeline graph + * Terminal */ -.mini-pipeline-graph-icon-container .ci-status-icon { - display: inline-block; - border: 1px solid; - border-radius: 22px; - margin-right: 1px; - width: 22px; - height: 22px; - position: relative; - z-index: 2; - transition: all 0.1s cubic-bezier(0.25, 0, 1, 1); - - svg { - top: -1px; - left: -1px; - } -} - -.stage-cell .mini-pipeline-graph-icon-container .ci-status-icon svg { - width: 22px; - height: 22px; -} - - .terminal-icon { margin-left: 3px; } diff --git a/app/views/ci/status/_dropdown_graph_badge.html.haml b/app/views/ci/status/_dropdown_graph_badge.html.haml new file mode 100644 index 00000000000..8dea3479f82 --- /dev/null +++ b/app/views/ci/status/_dropdown_graph_badge.html.haml @@ -0,0 +1,19 @@ +-# Renders the content of each li in the dropdown + +- subject = local_assigns.fetch(:subject) +- status = subject.detailed_status(current_user) +- klass = "ci-status-icon ci-status-icon-#{status.group}" +- tooltip = "#{subject.name} - #{status.label}" + +- if status.has_details? + = link_to status.details_path, class: 'mini-pipeline-graph-dropdown-item', data: { toggle: 'tooltip', title: tooltip } do + %span{ class: klass }= custom_icon(status.icon) + %span.ci-build-text= subject.name +- else + .mini-pipeline-graph-dropdown-item{ data: { toggle: 'tooltip', title: tooltip } } + %span{ class: klass }= custom_icon(status.icon) + %span.ci-build-text= subject.name + +- 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 } do + = icon(status.action_icon, class: status.action_class) diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index e67492a36d1..aaf1b428178 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -47,21 +47,18 @@ - icon_status = "#{detailed_status.icon}_borderless" - status_klass = "ci-status-icon ci-status-icon-#{detailed_status.group}" - .stage-container.mini-pipeline-graph - .dropdown.inline.build-content - %button.has-tooltip.builds-dropdown.js-builds-dropdown-button{ 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) } } - %span.has-tooltip{ class: status_klass } - %span.mini-pipeline-graph-icon-container - %span{ class: status_klass }= custom_icon(icon_status) - = icon('caret-down', class: 'dropdown-caret') + .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') - .js-builds-dropdown-container - .dropdown-menu.grouped-pipeline-dropdown - .arrow-up - .js-builds-dropdown-list + %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 - .js-builds-dropdown-loading.builds-dropdown-loading.hidden - %span.fa.fa-spinner.fa-spin %td - if pipeline.duration diff --git a/app/views/projects/pipelines/_stage.html.haml b/app/views/projects/pipelines/_stage.html.haml index cf1b366bf2c..a0b14a7274a 100644 --- a/app/views/projects/pipelines/_stage.html.haml +++ b/app/views/projects/pipelines/_stage.html.haml @@ -1,4 +1,3 @@ -%ul - - @stage.statuses.latest.each do |status| - %li.dropdown-build - = render 'ci/status/graph_badge', subject: status +- @stage.statuses.latest.each do |status| + %li + = render 'ci/status/dropdown_graph_badge', subject: status diff --git a/app/views/projects/stage/_in_stage_group.html.haml b/app/views/projects/stage/_in_stage_group.html.haml index c4cb9ab50d0..9c5eb501174 100644 --- a/app/views/projects/stage/_in_stage_group.html.haml +++ b/app/views/projects/stage/_in_stage_group.html.haml @@ -5,9 +5,10 @@ %span.ci-status-text = name %span.dropdown-counter-badge= subject.size -.dropdown-menu.grouped-pipeline-dropdown + +%ul.dropdown-menu.big-pipeline-graph-dropdown-menu.js-grouped-pipeline-dropdown .arrow - %ul + .scrollable-menu - subject.each do |status| - %li.dropdown-build - = render 'ci/status/graph_badge', subject: status + %li + = render 'ci/status/dropdown_graph_badge', subject: status diff --git a/changelogs/unreleased/pipelines-graph-html-css.yml b/changelogs/unreleased/pipelines-graph-html-css.yml new file mode 100644 index 00000000000..ff0c3122fdb --- /dev/null +++ b/changelogs/unreleased/pipelines-graph-html-css.yml @@ -0,0 +1,4 @@ +--- +title: Fixes and Improves CSS and HTML problems in mini pipeline graph and builds dropdown +merge_request: 8443 +author: diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 1ff57f92c4c..cef50f6f237 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -183,7 +183,7 @@ describe 'Pipelines', :feature, :js do it 'should render a mini pipeline graph' do endpoint = stage_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline, stage: build.name) - expect(page).to have_selector('.mini-pipeline-graph') + expect(page).to have_selector('.js-mini-pipeline-graph') expect(page).to have_selector(".js-builds-dropdown-button[data-stage-endpoint='#{endpoint}']") end @@ -201,7 +201,7 @@ describe 'Pipelines', :feature, :js do wait_for_ajax - find('a.ci-action-icon-container').trigger('click') + find('a.js-ci-action-icon').trigger('click') expect(page).not_to have_content('Cancel running') end end diff --git a/spec/views/projects/pipelines/show.html.haml_spec.rb b/spec/views/projects/pipelines/show.html.haml_spec.rb index a066ea078e6..c101f6f164d 100644 --- a/spec/views/projects/pipelines/show.html.haml_spec.rb +++ b/spec/views/projects/pipelines/show.html.haml_spec.rb @@ -29,7 +29,7 @@ describe 'projects/pipelines/show' do render expect(rendered).to have_css('.js-pipeline-graph') - expect(rendered).to have_css('.grouped-pipeline-dropdown') + expect(rendered).to have_css('.js-grouped-pipeline-dropdown') # stages expect(rendered).to have_text('Build')