diff options
17 files changed, 124 insertions, 223 deletions
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 index d42f2d15f19..a06aad17824 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js.es6 @@ -1,4 +1,4 @@ -/* eslint-disable no-new */ +/* eslint-disable no-new, no-param-reassign */ /* global Vue, CommitsPipelineStore, PipelinesService, Flash */ //= require vue @@ -10,8 +10,10 @@ /** * Commits View > Pipelines Tab > Pipelines Table. + * Merge Request View > Pipelines Tab > Pipelines Table. * * Renders Pipelines table in pipelines tab in the commits show view. + * Renders Pipelines table in pipelines tab in the merge request show view. * * Uses `pipelines-table-component` to render Pipelines table with an API call. * Endpoint is provided in HTML and passed as scope. @@ -20,6 +22,7 @@ * Necessary SVG in the table are provided as props. This should be refactored * as soon as we have Webpack and can load them directly into JS files. */ + $(() => { window.gl = window.gl || {}; gl.commits = gl.commits || {}; @@ -55,11 +58,12 @@ $(() => { }, {}); return { - endpoint: pipelinesTableData.pipelinesData, + endpoint: pipelinesTableData.endpoint, svgs: svgsObject, store, state: store.state, isLoading: false, + error: false, }; }, @@ -82,7 +86,9 @@ $(() => { .then((json) => { this.store.store(json); this.isLoading = false; + this.error = false; }).catch(() => { + this.error = true; this.isLoading = false; new Flash('An error occurred while fetching the pipelines.', 'alert'); }); @@ -95,14 +101,15 @@ $(() => { </div> <div class="blank-state blank-state-no-icon" - v-if="!isLoading && state.pipelines.length === 0"> + v-if="!isLoading && !error && state.pipelines.length === 0"> <h2 class="blank-state-title js-blank-state-title"> You don't have any pipelines. </h2> - Put get started with pipelines button here!!! </div> - <div class="table-holder" v-if='!isLoading && state.pipelines.length > 0'> + <div + class="table-holder pipelines" + v-if='!isLoading && state.pipelines.length > 0'> <pipelines-table-component :pipelines='state.pipelines' :svgs='svgs'> diff --git a/app/assets/javascripts/commit/pipelines/pipelines_store.js.es6 b/app/assets/javascripts/commit/pipelines/pipelines_store.js.es6 index 5c2e1b33cd1..b7d8e97fed3 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_store.js.es6 +++ b/app/assets/javascripts/commit/pipelines/pipelines_store.js.es6 @@ -1,7 +1,3 @@ -/* global gl, Flash */ -/* eslint-disable no-param-reassign, no-underscore-dangle */ -/*= require vue_realtime_listener/index.js */ - /** * Pipelines' Store for commits view. * diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js.es6 index edec21e3b63..70f467d608f 100644 --- a/app/assets/javascripts/dispatcher.js.es6 +++ b/app/assets/javascripts/dispatcher.js.es6 @@ -159,11 +159,6 @@ new ZenMode(); shortcut_handler = new ShortcutsNavigation(); break; - case 'projects:commit:pipelines': - new gl.MiniPipelineGraph({ - container: '.js-pipeline-table', - }); - break; case 'projects:commits:show': case 'projects:activity': shortcut_handler = new ShortcutsNavigation(); diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6 index 4c8c28af755..dabba9e1fa9 100644 --- a/app/assets/javascripts/merge_request_tabs.js.es6 +++ b/app/assets/javascripts/merge_request_tabs.js.es6 @@ -61,7 +61,6 @@ constructor({ action, setUrl, stubLocation } = {}) { this.diffsLoaded = false; - this.pipelinesLoaded = false; this.commitsLoaded = false; this.fixedLayoutPref = null; @@ -116,10 +115,6 @@ $.scrollTo('.merge-request-details .merge-request-tabs', { offset: -navBarHeight, }); - } else if (action === 'pipelines') { - this.loadPipelines($target.attr('href')); - this.expandView(); - this.resetViewContainer(); } else { this.expandView(); this.resetViewContainer(); @@ -243,25 +238,6 @@ }); } - loadPipelines(source) { - if (this.pipelinesLoaded) { - return; - } - this.ajaxGet({ - url: `${source}.json`, - success: (data) => { - $('#pipelines').html(data.html); - gl.utils.localTimeAgo($('.js-timeago', '#pipelines')); - this.pipelinesLoaded = true; - this.scrollToElement('#pipelines'); - - new gl.MiniPipelineGraph({ - container: '.js-pipeline-table', - }); - }, - }); - } - // Show or hide the loading spinner // // status - Boolean, true to show, false to hide diff --git a/app/assets/javascripts/vue_pipelines_index/index.js.es6 b/app/assets/javascripts/vue_pipelines_index/index.js.es6 index 9ca7b1a746c..e5359ba5398 100644 --- a/app/assets/javascripts/vue_pipelines_index/index.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/index.js.es6 @@ -1,31 +1,32 @@ +/* eslint-disable no-param-reassign */ /* global Vue, VueResource, gl */ -/*= require vue_shared/components/commit */ -/*= require vue_pagination/index */ + +//= require vue /*= require vue-resource /*= require vue_shared/vue_resource_interceptor */ -/*= require ./status.js.es6 */ -/*= require ./store.js.es6 */ -/*= require ./pipeline_url.js.es6 */ -/*= require ./stage.js.es6 */ -/*= require ./stages.js.es6 */ -/*= require ./pipeline_actions.js.es6 */ -/*= require ./time_ago.js.es6 */ /*= require ./pipelines.js.es6 */ -(() => { - const project = document.querySelector('.pipelines'); - const entry = document.querySelector('.vue-pipelines-index'); - const svgs = document.querySelector('.pipeline-svgs'); - +$(() => { Vue.use(VueResource); - if (!entry) return null; return new Vue({ - el: entry, - data: { - scope: project.dataset.url, - store: new gl.PipelineStore(), - svgs: svgs.dataset, + el: document.querySelector('.vue-pipelines-index'), + + data() { + const project = document.querySelector('.pipelines'); + const svgs = document.querySelector('.pipeline-svgs').dataset; + + // Transform svgs DOMStringMap to a plain Object. + const svgsObject = Object.keys(svgs).reduce((acc, element) => { + acc[element] = svgs[element]; + return acc; + }, {}); + + return { + scope: project.dataset.url, + store: new gl.PipelineStore(), + svgs: svgsObject, + }; }, components: { 'vue-pipelines': gl.VuePipelines, @@ -39,4 +40,4 @@ </vue-pipelines> `, }); -})(); +}); diff --git a/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 index a7176e27ea1..9b4897b1a9e 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 @@ -25,7 +25,6 @@ <button v-if='actions' class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions" - data-toggle="dropdown" title="Manual build" data-placement="top" aria-label="Manual build" @@ -50,7 +49,6 @@ <button v-if='artifacts' class="dropdown-toggle btn btn-default build-artifacts has-tooltip js-pipeline-dropdown-download" - data-toggle="dropdown" title="Artifacts" data-placement="top" aria-label="Artifacts" @@ -72,7 +70,7 @@ </div> </div> <div class="cancel-retry-btns inline"> - <a + <button v-if='pipeline.flags.retryable' class="btn has-tooltip" title="Retry" @@ -81,11 +79,10 @@ data-placement="top" data-toggle="dropdown" :href='pipeline.retry_path' - aria-label="Retry" - > + aria-label="Retry"> <i class="fa fa-repeat" aria-hidden="true"></i> </a> - <a + <button v-if='pipeline.flags.cancelable' class="btn btn-remove has-tooltip" title="Cancel" @@ -94,8 +91,7 @@ data-placement="top" data-toggle="dropdown" :href='pipeline.cancel_path' - aria-label="Cancel" - > + aria-label="Cancel"> <i class="fa fa-remove" aria-hidden="true"></i> </a> </div> diff --git a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 index b2ed05503c9..34d93ce1b7f 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 @@ -1,19 +1,18 @@ /* global Vue, Turbolinks, gl */ /* eslint-disable no-param-reassign */ +//= require vue_pagination/index +//= require ./store.js.es6 +//= require vue_shared/components/pipelines_table + ((gl) => { gl.VuePipelines = Vue.extend({ + components: { - runningPipeline: gl.VueRunningPipeline, - pipelineActions: gl.VuePipelineActions, - stages: gl.VueStages, - commit: gl.CommitComponent, - pipelineUrl: gl.VuePipelineUrl, - pipelineHead: gl.VuePipelineHead, glPagination: gl.VueGlPagination, - statusScope: gl.VueStatusScope, - timeAgo: gl.VueTimeAgo, + 'pipelines-table-component': gl.pipelines.PipelinesTableComponent, }, + data() { return { pipelines: [], @@ -38,31 +37,6 @@ change(pagenum, apiScope) { Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`); }, - author(pipeline) { - if (!pipeline.commit) return { avatar_url: '', web_url: '', username: '' }; - if (pipeline.commit.author) return pipeline.commit.author; - return { - avatar_url: pipeline.commit.author_gravatar_url, - web_url: `mailto:${pipeline.commit.author_email}`, - username: pipeline.commit.author_name, - }; - }, - ref(pipeline) { - const { ref } = pipeline; - return { name: ref.name, tag: ref.tag, ref_url: ref.path }; - }, - commitTitle(pipeline) { - return pipeline.commit ? pipeline.commit.title : ''; - }, - commitSha(pipeline) { - return pipeline.commit ? pipeline.commit.short_id : ''; - }, - commitUrl(pipeline) { - return pipeline.commit ? pipeline.commit.commit_path : ''; - }, - match(string) { - return string.replace(/_([a-z])/g, (m, w) => w.toUpperCase()); - }, }, template: ` <div> @@ -70,49 +44,10 @@ <i class="fa fa-spinner fa-spin"></i> </div> <div class="table-holder" v-if='pipelines.length'> - <table class="table ci-table"> - <thead> - <tr> - <th class="pipeline-status">Status</th> - <th class="pipeline-info">Pipeline</th> - <th class="pipeline-commit">Commit</th> - <th class="pipeline-stages">Stages</th> - <th class="pipeline-date"></th> - <th class="pipeline-actions hidden-xs"></th> - </tr> - </thead> - <tbody> - <tr class="commit" v-for='pipeline in pipelines'> - <status-scope - :pipeline='pipeline' - :match='match' - :svgs='svgs' - > - </status-scope> - <pipeline-url :pipeline='pipeline'></pipeline-url> - <td> - <commit - :commit-icon-svg='svgs.commitIconSvg' - :author='author(pipeline)' - :tag="pipeline.ref.tag" - :title='commitTitle(pipeline)' - :commit-ref='ref(pipeline)' - :short-sha='commitSha(pipeline)' - :commit-url='commitUrl(pipeline)' - > - </commit> - </td> - <stages - :pipeline='pipeline' - :svgs='svgs' - :match='match' - > - </stages> - <time-ago :pipeline='pipeline' :svgs='svgs'></time-ago> - <pipeline-actions :pipeline='pipeline' :svgs='svgs'></pipeline-actions> - </tr> - </tbody> - </table> + <pipelines-table-component + :pipelines='pipelines' + :svgs='svgs'> + </pipelines-table-component> </div> <div class="pipelines realtime-loading" v-if='pageRequest'> <i class="fa fa-spinner fa-spin"></i> diff --git a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 b/app/assets/javascripts/vue_pipelines_index/stage.js.es6 index 572644c8e6e..8cc417a9966 100644 --- a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/stage.js.es6 @@ -14,9 +14,8 @@ type: Object, required: true, }, - //FIXME: DOMStringMap is non standard, let's use a plain object. svgs: { - type: DOMStringMap, + type: Object, required: true, }, match: { diff --git a/app/assets/javascripts/vue_pipelines_index/stages.js.es6 b/app/assets/javascripts/vue_pipelines_index/stages.js.es6 deleted file mode 100644 index cb176b3f0c6..00000000000 --- a/app/assets/javascripts/vue_pipelines_index/stages.js.es6 +++ /dev/null @@ -1,21 +0,0 @@ -/* global Vue, gl */ -/* eslint-disable no-param-reassign */ - -((gl) => { - gl.VueStages = Vue.extend({ - components: { - 'vue-stage': gl.VueStage, - }, - props: ['pipeline', 'svgs', 'match'], - template: ` - <td class="stage-cell"> - <div - class="stage-container dropdown js-mini-pipeline-graph" - v-for='stage in pipeline.details.stages' - > - <vue-stage :stage='stage' :svgs='svgs' :match='match'></vue-stage> - </div> - </td> - `, - }); -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6 b/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6 index e606632306f..4b6bba461d7 100644 --- a/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6 +++ b/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable no-param-reassign */ /* global Vue */ -//=require ./pipelines_table_row +//= require ./pipelines_table_row /** * Pipelines Table Component diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table_row.js.es6 b/app/assets/javascripts/vue_shared/components/pipelines_table_row.js.es6 index 1e55cce1c41..c0ff0c90e4e 100644 --- a/app/assets/javascripts/vue_shared/components/pipelines_table_row.js.es6 +++ b/app/assets/javascripts/vue_shared/components/pipelines_table_row.js.es6 @@ -38,6 +38,7 @@ pipelineUrl: gl.VuePipelineUrl, pipelineHead: gl.VuePipelineHead, statusScope: gl.VueStatusScope, + 'time-ago': gl.VueTimeAgo, }, computed: { @@ -45,29 +46,61 @@ * If provided, returns the commit tag. * Needed to render the commit component column. * + * TODO: Document this logic, need to ask @grzesiek and @selfup + * * @returns {Object|Undefined} */ commitAuthor() { + if (!this.pipeline.commit) { + return { avatar_url: '', web_url: '', username: '' }; + } + if (this.pipeline && this.pipeline.commit && this.pipeline.commit.author) { return this.pipeline.commit.author; } + if (this.pipeline && + this.pipeline.commit && + this.pipeline.commit.author_gravatar_url && + this.pipeline.commit.author_name && + this.pipeline.commit.author_email) { + return { + avatar_url: this.pipeline.commit.author_gravatar_url, + web_url: `mailto:${this.pipeline.commit.author_email}`, + username: this.pipeline.commit.author_name, + }; + } + return undefined; }, /** + * Figure this out! + * Needed to render the commit component column. + */ + author(pipeline) { + if (!pipeline.commit) return { avatar_url: '', web_url: '', username: '' }; + if (pipeline.commit.author) return pipeline.commit.author; + return { + avatar_url: pipeline.commit.author_gravatar_url, + web_url: `mailto:${pipeline.commit.author_email}`, + username: pipeline.commit.author_name, + }; + }, + + /** * If provided, returns the commit tag. * Needed to render the commit component column. * * @returns {String|Undefined} */ commitTag() { - // if (this.model.last_deployment && - // this.model.last_deployment.tag) { - // return this.model.last_deployment.tag; - // } + if (this.pipeline.ref && + this.pipeline.ref.tag) { + return this.pipeline.ref.tag; + } return undefined; }, @@ -133,20 +166,6 @@ } return undefined; }, - - /** - * Figure this out! - * Needed to render the commit component column. - */ - author(pipeline) { - if (!pipeline.commit) return { avatar_url: '', web_url: '', username: '' }; - if (pipeline.commit.author) return pipeline.commit.author; - return { - avatar_url: pipeline.commit.author_gravatar_url, - web_url: `mailto:${pipeline.commit.author_email}`, - username: pipeline.commit.author_name, - }; - }, }, methods: { diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 6eb542e4bd8..deb084c2e91 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -216,13 +216,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController end format.json do - render json: { - html: view_to_html_string('projects/merge_requests/show/_pipelines'), - pipelines: PipelineSerializer - .new(project: @project, user: @current_user) - .with_pagination(request, response) - .represent(@pipelines) - } + render json: PipelineSerializer + .new(project: @project, user: @current_user) + .with_pagination(request, response) + .represent(@pipelines) end end end diff --git a/app/views/projects/commit/_pipelines_list.haml b/app/views/projects/commit/_pipelines_list.haml index e69de29bb2d..bfe5eb18ad1 100644 --- a/app/views/projects/commit/_pipelines_list.haml +++ b/app/views/projects/commit/_pipelines_list.haml @@ -0,0 +1,25 @@ +#commit-pipeline-table-view{ data: { endpoint: endpoint } } +.pipeline-svgs{ data: { "commit_icon_svg" => custom_icon("icon_commit"), + "icon_status_canceled" => custom_icon("icon_status_canceled"), + "icon_status_running" => custom_icon("icon_status_running"), + "icon_status_skipped" => custom_icon("icon_status_skipped"), + "icon_status_created" => custom_icon("icon_status_created"), + "icon_status_pending" => custom_icon("icon_status_pending"), + "icon_status_success" => custom_icon("icon_status_success"), + "icon_status_failed" => custom_icon("icon_status_failed"), + "icon_status_warning" => custom_icon("icon_status_warning"), + "stage_icon_status_canceled" => custom_icon("icon_status_canceled_borderless"), + "stage_icon_status_running" => custom_icon("icon_status_running_borderless"), + "stage_icon_status_skipped" => custom_icon("icon_status_skipped_borderless"), + "stage_icon_status_created" => custom_icon("icon_status_created_borderless"), + "stage_icon_status_pending" => custom_icon("icon_status_pending_borderless"), + "stage_icon_status_success" => custom_icon("icon_status_success_borderless"), + "stage_icon_status_failed" => custom_icon("icon_status_failed_borderless"), + "stage_icon_status_warning" => custom_icon("icon_status_warning_borderless"), + "icon_play" => custom_icon("icon_play"), + "icon_timer" => custom_icon("icon_timer"), + "icon_status_manual" => custom_icon("icon_status_manual"), +} } + +- content_for :page_specific_javascripts do + = page_specific_javascript_tag('commit/pipelines/pipelines_bundle.js') diff --git a/app/views/projects/commit/pipelines.html.haml b/app/views/projects/commit/pipelines.html.haml index f62fbe4d9cd..ac93eac41ac 100644 --- a/app/views/projects/commit/pipelines.html.haml +++ b/app/views/projects/commit/pipelines.html.haml @@ -2,29 +2,4 @@ = render 'commit_box' = render 'ci_menu' - -#commit-pipeline-table-view{ data: { pipelines_data: pipelines_namespace_project_commit_path(@project.namespace, @project, @commit.id)}} -.pipeline-svgs{ data: { "commit_icon_svg" => custom_icon("icon_commit"), - "icon_status_canceled" => custom_icon("icon_status_canceled"), - "icon_status_running" => custom_icon("icon_status_running"), - "icon_status_skipped" => custom_icon("icon_status_skipped"), - "icon_status_created" => custom_icon("icon_status_created"), - "icon_status_pending" => custom_icon("icon_status_pending"), - "icon_status_success" => custom_icon("icon_status_success"), - "icon_status_failed" => custom_icon("icon_status_failed"), - "icon_status_warning" => custom_icon("icon_status_warning"), - "stage_icon_status_canceled" => custom_icon("icon_status_canceled_borderless"), - "stage_icon_status_running" => custom_icon("icon_status_running_borderless"), - "stage_icon_status_skipped" => custom_icon("icon_status_skipped_borderless"), - "stage_icon_status_created" => custom_icon("icon_status_created_borderless"), - "stage_icon_status_pending" => custom_icon("icon_status_pending_borderless"), - "stage_icon_status_success" => custom_icon("icon_status_success_borderless"), - "stage_icon_status_failed" => custom_icon("icon_status_failed_borderless"), - "stage_icon_status_warning" => custom_icon("icon_status_warning_borderless"), - "icon_play" => custom_icon("icon_play"), - "icon_timer" => custom_icon("icon_timer"), - "icon_status_manual" => custom_icon("icon_status_manual"), -} } - -- content_for :page_specific_javascripts do - = page_specific_javascript_tag('commit/pipelines/pipelines_bundle.js') += render 'projects/commit/pipelines_list', endpoint: pipelines_namespace_project_commit_path(@project.namespace, @project, @commit.id) diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index d3c013b3f21..c1f48837e0e 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -44,9 +44,9 @@ = render "projects/merge_requests/show/commits" #diffs.diffs.tab-pane -# This tab is always loaded via AJAX - - if @pipelines.any? - #pipelines.pipelines.tab-pane - = render "projects/merge_requests/show/pipelines" + #pipelines.pipelines.tab-pane + //TODO: This needs to make a new request every time is opened! + = render "projects/merge_requests/show/pipelines", endpoint: link_to url_for(params) .mr-loading-status = spinner diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 9585a9a3ad4..8dfe967a937 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -94,7 +94,8 @@ #commits.commits.tab-pane -# This tab is always loaded via AJAX #pipelines.pipelines.tab-pane - -# This tab is always loaded via AJAX + //TODO: This needs to make a new request every time is opened! + = render 'projects/commit/pipelines_list', endpoint: pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) #diffs.diffs.tab-pane -# This tab is always loaded via AJAX diff --git a/app/views/projects/merge_requests/show/_pipelines.html.haml b/app/views/projects/merge_requests/show/_pipelines.html.haml index afe3f3430c6..cbe534abedb 100644 --- a/app/views/projects/merge_requests/show/_pipelines.html.haml +++ b/app/views/projects/merge_requests/show/_pipelines.html.haml @@ -1 +1 @@ -= render "projects/commit/pipelines_list", pipelines: @pipelines, link_to_commit: true += render 'projects/commit/pipelines_list', endpoint: pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) |