Commit 2c2da2c0 authored by Filipa Lacerda's avatar Filipa Lacerda

Use new vue js pipelines table to render in merge request view

Remove duplicate data-toggle attributes.

Reuse the same pipeline table

Remove unneeded required resources

Remove unused file; Fix mr pipelines loading

Updates documentation
parent 7ef21460
/* eslint-disable no-new */ /* eslint-disable no-new, no-param-reassign */
/* global Vue, CommitsPipelineStore, PipelinesService, Flash */ /* global Vue, CommitsPipelineStore, PipelinesService, Flash */
//= require vue //= require vue
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
/** /**
* Commits View > Pipelines Tab > Pipelines Table. * 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 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. * Uses `pipelines-table-component` to render Pipelines table with an API call.
* Endpoint is provided in HTML and passed as scope. * Endpoint is provided in HTML and passed as scope.
...@@ -20,6 +22,7 @@ ...@@ -20,6 +22,7 @@
* Necessary SVG in the table are provided as props. This should be refactored * 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. * as soon as we have Webpack and can load them directly into JS files.
*/ */
$(() => { $(() => {
window.gl = window.gl || {}; window.gl = window.gl || {};
gl.commits = gl.commits || {}; gl.commits = gl.commits || {};
...@@ -55,11 +58,12 @@ $(() => { ...@@ -55,11 +58,12 @@ $(() => {
}, {}); }, {});
return { return {
endpoint: pipelinesTableData.pipelinesData, endpoint: pipelinesTableData.endpoint,
svgs: svgsObject, svgs: svgsObject,
store, store,
state: store.state, state: store.state,
isLoading: false, isLoading: false,
error: false,
}; };
}, },
...@@ -82,7 +86,9 @@ $(() => { ...@@ -82,7 +86,9 @@ $(() => {
.then((json) => { .then((json) => {
this.store.store(json); this.store.store(json);
this.isLoading = false; this.isLoading = false;
this.error = false;
}).catch(() => { }).catch(() => {
this.error = true;
this.isLoading = false; this.isLoading = false;
new Flash('An error occurred while fetching the pipelines.', 'alert'); new Flash('An error occurred while fetching the pipelines.', 'alert');
}); });
...@@ -95,14 +101,15 @@ $(() => { ...@@ -95,14 +101,15 @@ $(() => {
</div> </div>
<div class="blank-state blank-state-no-icon" <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"> <h2 class="blank-state-title js-blank-state-title">
You don't have any pipelines. You don't have any pipelines.
</h2> </h2>
Put get started with pipelines button here!!!
</div> </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-table-component
:pipelines='state.pipelines' :pipelines='state.pipelines'
:svgs='svgs'> :svgs='svgs'>
......
/* global gl, Flash */
/* eslint-disable no-param-reassign, no-underscore-dangle */
/*= require vue_realtime_listener/index.js */
/** /**
* Pipelines' Store for commits view. * Pipelines' Store for commits view.
* *
......
...@@ -159,11 +159,6 @@ ...@@ -159,11 +159,6 @@
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',
});
break;
case 'projects:commits:show': case 'projects:commits:show':
case 'projects:activity': case 'projects:activity':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
......
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
constructor({ action, setUrl, stubLocation } = {}) { constructor({ action, setUrl, stubLocation } = {}) {
this.diffsLoaded = false; this.diffsLoaded = false;
this.pipelinesLoaded = false;
this.commitsLoaded = false; this.commitsLoaded = false;
this.fixedLayoutPref = null; this.fixedLayoutPref = null;
...@@ -116,10 +115,6 @@ ...@@ -116,10 +115,6 @@
$.scrollTo('.merge-request-details .merge-request-tabs', { $.scrollTo('.merge-request-details .merge-request-tabs', {
offset: -navBarHeight, offset: -navBarHeight,
}); });
} else if (action === 'pipelines') {
this.loadPipelines($target.attr('href'));
this.expandView();
this.resetViewContainer();
} else { } else {
this.expandView(); this.expandView();
this.resetViewContainer(); this.resetViewContainer();
...@@ -243,25 +238,6 @@ ...@@ -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 // Show or hide the loading spinner
// //
// status - Boolean, true to show, false to hide // status - Boolean, true to show, false to hide
......
/* eslint-disable no-param-reassign */
/* global Vue, VueResource, gl */ /* global Vue, VueResource, gl */
/*= require vue_shared/components/commit */
/*= require vue_pagination/index */ //= require vue
/*= require vue-resource /*= require vue-resource
/*= require vue_shared/vue_resource_interceptor */ /*= 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 */ /*= 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); Vue.use(VueResource);
if (!entry) return null;
return new Vue({ return new Vue({
el: entry, el: document.querySelector('.vue-pipelines-index'),
data: {
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, scope: project.dataset.url,
store: new gl.PipelineStore(), store: new gl.PipelineStore(),
svgs: svgs.dataset, svgs: svgsObject,
};
}, },
components: { components: {
'vue-pipelines': gl.VuePipelines, 'vue-pipelines': gl.VuePipelines,
...@@ -39,4 +40,4 @@ ...@@ -39,4 +40,4 @@
</vue-pipelines> </vue-pipelines>
`, `,
}); });
})(); });
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
<button <button
v-if='actions' v-if='actions'
class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions" class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
data-toggle="dropdown"
title="Manual build" title="Manual build"
data-placement="top" data-placement="top"
aria-label="Manual build" aria-label="Manual build"
...@@ -50,7 +49,6 @@ ...@@ -50,7 +49,6 @@
<button <button
v-if='artifacts' v-if='artifacts'
class="dropdown-toggle btn btn-default build-artifacts has-tooltip js-pipeline-dropdown-download" class="dropdown-toggle btn btn-default build-artifacts has-tooltip js-pipeline-dropdown-download"
data-toggle="dropdown"
title="Artifacts" title="Artifacts"
data-placement="top" data-placement="top"
aria-label="Artifacts" aria-label="Artifacts"
...@@ -72,7 +70,7 @@ ...@@ -72,7 +70,7 @@
</div> </div>
</div> </div>
<div class="cancel-retry-btns inline"> <div class="cancel-retry-btns inline">
<a <button
v-if='pipeline.flags.retryable' v-if='pipeline.flags.retryable'
class="btn has-tooltip" class="btn has-tooltip"
title="Retry" title="Retry"
...@@ -81,11 +79,10 @@ ...@@ -81,11 +79,10 @@
data-placement="top" data-placement="top"
data-toggle="dropdown" data-toggle="dropdown"
:href='pipeline.retry_path' :href='pipeline.retry_path'
aria-label="Retry" aria-label="Retry">
>
<i class="fa fa-repeat" aria-hidden="true"></i> <i class="fa fa-repeat" aria-hidden="true"></i>
</a> </a>
<a <button
v-if='pipeline.flags.cancelable' v-if='pipeline.flags.cancelable'
class="btn btn-remove has-tooltip" class="btn btn-remove has-tooltip"
title="Cancel" title="Cancel"
...@@ -94,8 +91,7 @@ ...@@ -94,8 +91,7 @@
data-placement="top" data-placement="top"
data-toggle="dropdown" data-toggle="dropdown"
:href='pipeline.cancel_path' :href='pipeline.cancel_path'
aria-label="Cancel" aria-label="Cancel">
>
<i class="fa fa-remove" aria-hidden="true"></i> <i class="fa fa-remove" aria-hidden="true"></i>
</a> </a>
</div> </div>
......
/* global Vue, Turbolinks, gl */ /* global Vue, Turbolinks, gl */
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
//= require vue_pagination/index
//= require ./store.js.es6
//= require vue_shared/components/pipelines_table
((gl) => { ((gl) => {
gl.VuePipelines = Vue.extend({ gl.VuePipelines = Vue.extend({
components: { components: {
runningPipeline: gl.VueRunningPipeline,
pipelineActions: gl.VuePipelineActions,
stages: gl.VueStages,
commit: gl.CommitComponent,
pipelineUrl: gl.VuePipelineUrl,
pipelineHead: gl.VuePipelineHead,
glPagination: gl.VueGlPagination, glPagination: gl.VueGlPagination,
statusScope: gl.VueStatusScope, 'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
timeAgo: gl.VueTimeAgo,
}, },
data() { data() {
return { return {
pipelines: [], pipelines: [],
...@@ -38,31 +37,6 @@ ...@@ -38,31 +37,6 @@
change(pagenum, apiScope) { change(pagenum, apiScope) {
Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`); 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: ` template: `
<div> <div>
...@@ -70,49 +44,10 @@ ...@@ -70,49 +44,10 @@
<i class="fa fa-spinner fa-spin"></i> <i class="fa fa-spinner fa-spin"></i>
</div> </div>
<div class="table-holder" v-if='pipelines.length'> <div class="table-holder" v-if='pipelines.length'>
<table class="table ci-table"> <pipelines-table-component
<thead> :pipelines='pipelines'
<tr> :svgs='svgs'>
<th class="pipeline-status">Status</th> </pipelines-table-component>
<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>
</div> </div>
<div class="pipelines realtime-loading" v-if='pageRequest'> <div class="pipelines realtime-loading" v-if='pageRequest'>
<i class="fa fa-spinner fa-spin"></i> <i class="fa fa-spinner fa-spin"></i>
......
...@@ -14,9 +14,8 @@ ...@@ -14,9 +14,8 @@
type: Object, type: Object,
required: true, required: true,
}, },
//FIXME: DOMStringMap is non standard, let's use a plain object.
svgs: { svgs: {
type: DOMStringMap, type: Object,
required: true, required: true,
}, },
match: { match: {
......
/* 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 = {}));
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
/* global Vue */ /* global Vue */
//=require ./pipelines_table_row //= require ./pipelines_table_row
/** /**
* Pipelines Table Component * Pipelines Table Component
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
pipelineUrl: gl.VuePipelineUrl, pipelineUrl: gl.VuePipelineUrl,
pipelineHead: gl.VuePipelineHead, pipelineHead: gl.VuePipelineHead,
statusScope: gl.VueStatusScope, statusScope: gl.VueStatusScope,
'time-ago': gl.VueTimeAgo,
}, },
computed: { computed: {
...@@ -45,18 +46,50 @@ ...@@ -45,18 +46,50 @@
* If provided, returns the commit tag. * If provided, returns the commit tag.
* Needed to render the commit component column. * Needed to render the commit component column.
* *
* TODO: Document this logic, need to ask @grzesiek and @selfup
*
* @returns {Object|Undefined} * @returns {Object|Undefined}
*/ */
commitAuthor() { commitAuthor() {
if (!this.pipeline.commit) {
return { avatar_url: '', web_url: '', username: '' };
}
if (this.pipeline && if (this.pipeline &&
this.pipeline.commit && this.pipeline.commit &&
this.pipeline.commit.author) { this.pipeline.commit.author) {
return 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; 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. * If provided, returns the commit tag.
* Needed to render the commit component column. * Needed to render the commit component column.
...@@ -64,10 +97,10 @@ ...@@ -64,10 +97,10 @@
* @returns {String|Undefined} * @returns {String|Undefined}
*/ */
commitTag() { commitTag() {
// if (this.model.last_deployment && if (this.pipeline.ref &&
// this.model.last_deployment.tag) { this.pipeline.ref.tag) {
// return this.model.last_deployment.tag; return this.pipeline.ref.tag;
// } }
return undefined; return undefined;
}, },
...@@ -133,20 +166,6 @@ ...@@ -133,20 +166,6 @@
} }
return undefined; 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: { methods: {
......
...@@ -216,13 +216,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -216,13 +216,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
format.json do format.json do
render json: { render json: PipelineSerializer
html: view_to_html_string('projects/merge_requests/show/_pipelines'),
pipelines: PipelineSerializer
.new(project: @project, user: @current_user) .new(project: @project, user: @current_user)
.with_pagination(request, response) .with_pagination(request, response)
.represent(@pipelines) .represent(@pipelines)
}
end end
end end
end end
......
#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')
...@@ -2,29 +2,4 @@ ...@@ -2,29 +2,4 @@
= render 'commit_box' = render 'commit_box'
= render 'ci_menu' = render 'ci_menu'
= render 'projects/commit/pipelines_list', endpoint: pipelines_namespace_project_commit_path(@project.namespace, @project, @commit.id)
#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')
...@@ -44,9 +44,9 @@ ...@@ -44,9 +44,9 @@
= render "projects/merge_requests/show/commits" = render "projects/merge_requests/show/commits"
#diffs.diffs.tab-pane #diffs.diffs.tab-pane
-# This tab is always loaded via AJAX -# This tab is always loaded via AJAX
- if @pipelines.any?
#pipelines.pipelines.tab-pane #pipelines.pipelines.tab-pane
= render "projects/merge_requests/show/pipelines" //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 .mr-loading-status
= spinner = spinner
......
...@@ -94,7 +94,8 @@ ...@@ -94,7 +94,8 @@
#commits.commits.tab-pane #commits.commits.tab-pane
-# This tab is always loaded via AJAX -# This tab is always loaded via AJAX
#pipelines.pipelines.tab-pane #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 #diffs.diffs.tab-pane
-# This tab is always loaded via AJAX -# This tab is always loaded via AJAX
......
= 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)
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