diff options
author | Kushal Pandya <kushalspandya@gmail.com> | 2017-04-06 10:40:39 +0000 |
---|---|---|
committer | Jacob Schatz <jschatz@gitlab.com> | 2017-04-06 10:40:39 +0000 |
commit | 28a4e9d8d01e86d09c7dedcd85e63df792dbf8e3 (patch) | |
tree | 5df6e3239aca443e4af12e7933d0091c63302706 | |
parent | 32db15b24b8c69e39451f4afb951c993f9fbf31e (diff) | |
download | gitlab-ce-28a4e9d8d01e86d09c7dedcd85e63df792dbf8e3.tar.gz |
Show CI status as Favicon on Pipelines, Job and MR pages
21 files changed, 109 insertions, 3 deletions
diff --git a/app/assets/images/ci_favicons/icon_status_canceled.ico b/app/assets/images/ci_favicons/icon_status_canceled.ico Binary files differnew file mode 100755 index 00000000000..5a19458f2a2 --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_canceled.ico diff --git a/app/assets/images/ci_favicons/icon_status_created.ico b/app/assets/images/ci_favicons/icon_status_created.ico Binary files differnew file mode 100755 index 00000000000..4dca9640cb3 --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_created.ico diff --git a/app/assets/images/ci_favicons/icon_status_failed.ico b/app/assets/images/ci_favicons/icon_status_failed.ico Binary files differnew file mode 100755 index 00000000000..c961ff9a69b --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_failed.ico diff --git a/app/assets/images/ci_favicons/icon_status_manual.ico b/app/assets/images/ci_favicons/icon_status_manual.ico Binary files differnew file mode 100755 index 00000000000..5fbbc99ea7c --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_manual.ico diff --git a/app/assets/images/ci_favicons/icon_status_not_found.ico b/app/assets/images/ci_favicons/icon_status_not_found.ico Binary files differnew file mode 100755 index 00000000000..21afa9c72e6 --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_not_found.ico diff --git a/app/assets/images/ci_favicons/icon_status_pending.ico b/app/assets/images/ci_favicons/icon_status_pending.ico Binary files differnew file mode 100755 index 00000000000..8be32dab85a --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_pending.ico diff --git a/app/assets/images/ci_favicons/icon_status_running.ico b/app/assets/images/ci_favicons/icon_status_running.ico Binary files differnew file mode 100755 index 00000000000..f328ff1a5ed --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_running.ico diff --git a/app/assets/images/ci_favicons/icon_status_skipped.ico b/app/assets/images/ci_favicons/icon_status_skipped.ico Binary files differnew file mode 100755 index 00000000000..b4394e1b4af --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_skipped.ico diff --git a/app/assets/images/ci_favicons/icon_status_success.ico b/app/assets/images/ci_favicons/icon_status_success.ico Binary files differnew file mode 100755 index 00000000000..4f436c95242 --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_success.ico diff --git a/app/assets/images/ci_favicons/icon_status_warning.ico b/app/assets/images/ci_favicons/icon_status_warning.ico Binary files differnew file mode 100755 index 00000000000..805cc20cdec --- /dev/null +++ b/app/assets/images/ci_favicons/icon_status_warning.ico diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js index 6efd26ccc37..fe54ecffdfe 100644 --- a/app/assets/javascripts/build.js +++ b/app/assets/javascripts/build.js @@ -88,6 +88,7 @@ window.Build = (function() { dataType: 'json', success: function(buildData) { $('.js-build-output').html(buildData.trace_html); + gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`); if (window.location.hash === DOWN_BUILD_TRACE) { $("html,body").scrollTop(this.$buildTrace.height()); } diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 80490052389..9c7acc903d1 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -226,9 +226,11 @@ const ShortcutsBlob = require('./shortcuts_blob'); case 'projects:pipelines:builds': case 'projects:pipelines:show': const { controllerAction } = document.querySelector('.js-pipeline-container').dataset; + const pipelineStatusUrl = `${document.querySelector('.js-pipeline-tab-link a').getAttribute('href')}/status.json`; new gl.Pipelines({ initTabs: true, + pipelineStatusUrl, tabsOptions: { action: controllerAction, defaultAction: 'pipelines', diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 46b80c04e20..e1e6ca25446 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -2,6 +2,8 @@ (function() { (function(w) { var base; + const faviconEl = document.getElementById('favicon'); + const originalFavicon = faviconEl ? faviconEl.getAttribute('href') : null; w.gl || (w.gl = {}); (base = w.gl).utils || (base.utils = {}); w.gl.utils.isInGroupsPage = function() { @@ -361,5 +363,34 @@ fn(next, stop); }); }; + + w.gl.utils.setFavicon = (iconName) => { + if (faviconEl && iconName) { + faviconEl.setAttribute('href', `/assets/${iconName}.ico`); + } + }; + + w.gl.utils.resetFavicon = () => { + if (faviconEl) { + faviconEl.setAttribute('href', originalFavicon); + } + }; + + w.gl.utils.setCiStatusFavicon = (pageUrl) => { + $.ajax({ + url: pageUrl, + dataType: 'json', + success: function(data) { + if (data && data.icon) { + gl.utils.setFavicon(`ci_favicons/${data.icon}`); + } else { + gl.utils.resetFavicon(); + } + }, + error: function() { + gl.utils.resetFavicon(); + } + }); + }; })(window); }).call(window); diff --git a/app/assets/javascripts/merge_request_widget.js b/app/assets/javascripts/merge_request_widget.js index 0e2af3df071..b0254b17dd2 100644 --- a/app/assets/javascripts/merge_request_widget.js +++ b/app/assets/javascripts/merge_request_widget.js @@ -38,11 +38,13 @@ import MiniPipelineGraph from './mini_pipeline_graph_dropdown'; function MergeRequestWidget(opts) { // Initialize MergeRequestWidget behavior // - // check_enable - Boolean, whether to check automerge status - // merge_check_url - String, URL to use to check automerge status + // check_enable - Boolean, whether to check automerge status + // merge_check_url - String, URL to use to check automerge status // ci_status_url - String, URL to use to check CI status + // pipeline_status_url - String, URL to use to get CI status for Favicon // this.opts = opts; + this.opts.pipeline_status_url = `${this.opts.pipeline_status_url}.json`; this.$widgetBody = $('.mr-widget-body'); $('#modal_merge_info').modal({ show: false @@ -159,6 +161,7 @@ import MiniPipelineGraph from './mini_pipeline_graph_dropdown'; _this.status = data.status; _this.hasCi = data.has_ci; _this.updateMergeButton(_this.status, _this.hasCi); + gl.utils.setCiStatusFavicon(_this.opts.pipeline_status_url); if (data.environments && data.environments.length) _this.renderEnvironments(data.environments); if (data.status !== _this.opts.ci_status || data.sha !== _this.opts.ci_sha || diff --git a/app/assets/javascripts/pipelines.js b/app/assets/javascripts/pipelines.js index 9203abefbbc..4252b615887 100644 --- a/app/assets/javascripts/pipelines.js +++ b/app/assets/javascripts/pipelines.js @@ -9,6 +9,10 @@ require('./lib/utils/bootstrap_linked_tabs'); new global.LinkedTabs(options.tabsOptions); } + if (options.pipelineStatusUrl) { + gl.utils.setCiStatusFavicon(options.pipelineStatusUrl); + } + this.addMarginToBuildColumns(); } diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index f6d8bb08a64..a611481a0a4 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -23,7 +23,7 @@ %title= page_title(site_name) %meta{ name: "description", content: page_description } - = favicon_link_tag favicon + = favicon_link_tag favicon, id: 'favicon' = stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "print", media: "print" diff --git a/app/views/projects/merge_requests/widget/_show.html.haml b/app/views/projects/merge_requests/widget/_show.html.haml index 0b0fb7854c2..c716b69b35b 100644 --- a/app/views/projects/merge_requests/widget/_show.html.haml +++ b/app/views/projects/merge_requests/widget/_show.html.haml @@ -12,6 +12,7 @@ merge_check_url: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", check_enable: #{@merge_request.unchecked? ? "true" : "false"}, ci_status_url: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", + pipeline_status_url: "#{pipeline_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", ci_environments_status_url: "#{ci_environments_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", gitlab_icon: "#{asset_path 'gitlab_logo.png'}", ci_status: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.status : ''}", diff --git a/changelogs/unreleased/12818-ci-status-as-favicon.yml b/changelogs/unreleased/12818-ci-status-as-favicon.yml new file mode 100644 index 00000000000..70194178d90 --- /dev/null +++ b/changelogs/unreleased/12818-ci-status-as-favicon.yml @@ -0,0 +1,4 @@ +--- +title: Show CI status as Favicon on Pipelines, Job and MR pages +merge_request: 10144 +author: diff --git a/spec/javascripts/build_spec.js b/spec/javascripts/build_spec.js index 549c7af8ea8..beee6cb2969 100644 --- a/spec/javascripts/build_spec.js +++ b/spec/javascripts/build_spec.js @@ -75,6 +75,7 @@ describe('Build', () => { expect(url).toBe(`${BUILD_URL}.json`); expect(dataType).toBe('json'); expect(success).toEqual(jasmine.any(Function)); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); success.call(context, { trace_html: '<span>Example</span>', status: 'running' }); @@ -83,6 +84,7 @@ describe('Build', () => { it('removes the spinner', () => { const [{ success, context }] = $.ajax.calls.argsFor(0); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); success.call(context, { trace_html: '<span>Example</span>', status: 'success' }); expect($('.js-build-refresh').length).toBe(0); diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 5a93d479c1f..03f3c206f44 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -310,5 +310,56 @@ require('~/lib/utils/common_utils'); }); }, 10000); }); + + describe('gl.utils.setFavicon', () => { + it('should set page favicon to provided favicon', () => { + const faviconName = 'custom_favicon'; + const fakeLink = { + setAttribute() {}, + }; + + spyOn(window.document, 'getElementById').and.callFake(() => fakeLink); + spyOn(fakeLink, 'setAttribute').and.callFake((attr, val) => { + expect(attr).toEqual('href'); + expect(val.indexOf('/assets/custom_favicon.ico') > -1).toBe(true); + }); + gl.utils.setFavicon(faviconName); + }); + }); + + describe('gl.utils.resetFavicon', () => { + it('should reset page favicon to tanuki', () => { + const fakeLink = { + setAttribute() {}, + }; + + spyOn(window.document, 'getElementById').and.callFake(() => fakeLink); + spyOn(fakeLink, 'setAttribute').and.callFake((attr, val) => { + expect(attr).toEqual('href'); + expect(val).toMatch(/favicon/); + }); + gl.utils.resetFavicon(); + }); + }); + + describe('gl.utils.setCiStatusFavicon', () => { + it('should set page favicon to CI status favicon based on provided status', () => { + const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1/status.json`; + const FAVICON_PATH = 'ci_favicons/'; + const FAVICON = 'icon_status_success'; + const spySetFavicon = spyOn(gl.utils, 'setFavicon').and.stub(); + const spyResetFavicon = spyOn(gl.utils, 'resetFavicon').and.stub(); + spyOn($, 'ajax').and.callFake(function (options) { + options.success({ icon: FAVICON }); + expect(spySetFavicon).toHaveBeenCalledWith(FAVICON_PATH + FAVICON); + options.success(); + expect(spyResetFavicon).toHaveBeenCalled(); + options.error(); + expect(spyResetFavicon).toHaveBeenCalled(); + }); + + gl.utils.setCiStatusFavicon(BUILD_URL); + }); + }); }); })(); diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js index d5193b41c33..88dae8c3e06 100644 --- a/spec/javascripts/merge_request_widget_spec.js +++ b/spec/javascripts/merge_request_widget_spec.js @@ -142,18 +142,21 @@ require('~/lib/utils/datetime_utility'); it('should call showCIStatus even if a notification should not be displayed', function() { var spy; spy = spyOn(this["class"], 'showCIStatus').and.stub(); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); this["class"].getCIStatus(false); return expect(spy).toHaveBeenCalledWith(this.ciStatusData.status); }); it('should call showCIStatus when a notification should be displayed', function() { var spy; spy = spyOn(this["class"], 'showCIStatus').and.stub(); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); this["class"].getCIStatus(true); return expect(spy).toHaveBeenCalledWith(this.ciStatusData.status); }); it('should call showCICoverage when the coverage rate is set', function() { var spy; spy = spyOn(this["class"], 'showCICoverage').and.stub(); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); this["class"].getCIStatus(false); return expect(spy).toHaveBeenCalledWith(this.ciStatusData.coverage); }); @@ -161,12 +164,14 @@ require('~/lib/utils/datetime_utility'); var spy; this.ciStatusData.coverage = null; spy = spyOn(this["class"], 'showCICoverage').and.stub(); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); this["class"].getCIStatus(false); return expect(spy).not.toHaveBeenCalled(); }); it('should not display a notification on the first check after the widget has been created', function() { var spy; spy = spyOn(window, 'notify'); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); this["class"] = new window.gl.MergeRequestWidget(this.opts); this["class"].getCIStatus(true); return expect(spy).not.toHaveBeenCalled(); @@ -174,6 +179,7 @@ require('~/lib/utils/datetime_utility'); it('should update the pipeline URL when the pipeline changes', function() { var spy; spy = spyOn(this["class"], 'updatePipelineUrls').and.stub(); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); this["class"].getCIStatus(false); this.ciStatusData.pipeline += 1; this["class"].getCIStatus(false); @@ -182,6 +188,7 @@ require('~/lib/utils/datetime_utility'); it('should update the commit URL when the sha changes', function() { var spy; spy = spyOn(this["class"], 'updateCommitUrls').and.stub(); + spyOn(gl.utils, 'setCiStatusFavicon').and.callFake(() => {}); this["class"].getCIStatus(false); this.ciStatusData.sha = "9b50b99a"; this["class"].getCIStatus(false); |