Commit 7ef21460 authored by Filipa Lacerda's avatar Filipa Lacerda

Transform vue_pipelines index into a non-dependent table component.

parent 7ad626e3
/* eslint-disable no-new */
/* global Vue, VueResource */
/* global Vue, CommitsPipelineStore, PipelinesService, Flash */
//= require vue
//= require_tree .
//= require vue
//= require vue-resource
//= require ./pipelines_store
//= require ./pipelines_service
//= require vue_shared/components/commit
//= require vue_shared/vue_resource_interceptor
//= require vue_shared/components/pipelines_table
......@@ -21,18 +20,23 @@
* 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 || {};
gl.commits = gl.commits || {};
gl.commits.pipelines = gl.commits.pipelines || {};
if (gl.Commits.PipelinesTableView) {
gl.Commits.PipelinesTableView.$destroy(true);
if (gl.commits.PipelinesTableView) {
gl.commits.PipelinesTableView.$destroy(true);
}
gl.Commits.PipelinesTableView = new Vue({
gl.commits.pipelines.PipelinesTableView = new Vue({
el: document.querySelector('#commit-pipeline-table-view'),
components: {
'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
},
/**
* Accesses the DOM to provide the needed data.
* Returns the necessary props to render `pipelines-table-component` component.
......@@ -41,21 +45,70 @@
*/
data() {
const pipelinesTableData = document.querySelector('#commit-pipeline-table-view').dataset;
const svgsData = document.querySelector('.pipeline-svgs').dataset;
const store = gl.commits.pipelines.PipelinesStore.create();
// Transform svgs DOMStringMap to a plain Object.
const svgsObject = Object.keys(svgsData).reduce((acc, element) => {
acc[element] = svgsData[element];
return acc;
}, {});
return {
scope: pipelinesTableData.pipelinesData,
store: new CommitsPipelineStore(),
service: new PipelinesService(),
svgs: pipelinesTableData,
endpoint: pipelinesTableData.pipelinesData,
svgs: svgsObject,
store,
state: store.state,
isLoading: false,
};
},
components: {
'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
/**
* When the component is created the service to fetch the data will be
* initialized with the correct endpoint.
*
* A request to fetch the pipelines will be made.
* In case of a successfull response we will store the data in the provided
* store, in case of a failed response we need to warn the user.
*
*/
created() {
gl.pipelines.pipelinesService = new PipelinesService(this.endpoint);
this.isLoading = true;
return gl.pipelines.pipelinesService.all()
.then(response => response.json())
.then((json) => {
this.store.store(json);
this.isLoading = false;
}).catch(() => {
this.isLoading = false;
new Flash('An error occurred while fetching the pipelines.', 'alert');
});
},
template: `
<pipelines-table-component :scope='scope' :store='store' :svgs='svgs'></pipelines-table-component>
<div>
<div class="pipelines realtime-loading" v-if='isLoading'>
<i class="fa fa-spinner fa-spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && 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'>
<pipelines-table-component
:pipelines='state.pipelines'
:svgs='svgs'>
</pipelines-table-component>
</div>
</div>
`,
});
});
......@@ -5,12 +5,8 @@
* Pipelines service.
*
* Used to fetch the data used to render the pipelines table.
* Used Vue.Resource
* Uses Vue.Resource
*/
window.gl = window.gl || {};
gl.pipelines = gl.pipelines || {};
class PipelinesService {
constructor(root) {
Vue.http.options.root = root;
......@@ -36,42 +32,3 @@ class PipelinesService {
return this.pipelines.get();
}
}
gl.pipelines.PipelinesService = PipelinesService;
// const pageValues = (headers) => {
// const normalized = gl.utils.normalizeHeaders(headers);
//
// const paginationInfo = {
// perPage: +normalized['X-PER-PAGE'],
// page: +normalized['X-PAGE'],
// total: +normalized['X-TOTAL'],
// totalPages: +normalized['X-TOTAL-PAGES'],
// nextPage: +normalized['X-NEXT-PAGE'],
// previousPage: +normalized['X-PREV-PAGE'],
// };
//
// return paginationInfo;
// };
// gl.PipelineStore = class {
// fetchDataLoop(Vue, pageNum, url, apiScope) {
// const goFetch = () =>
// this.$http.get(`${url}?scope=${apiScope}&page=${pageNum}`)
// .then((response) => {
// const pageInfo = pageValues(response.headers);
// this.pageInfo = Object.assign({}, this.pageInfo, pageInfo);
//
// const res = JSON.parse(response.body);
// this.count = Object.assign({}, this.count, res.count);
// this.pipelines = Object.assign([], this.pipelines, res);
//
// this.pageRequest = false;
// }, () => {
// this.pageRequest = false;
// return new Flash('Something went wrong on our end.');
// });
//
// goFetch();
// }
// };
......@@ -6,12 +6,14 @@
* Pipelines' Store for commits view.
*
* Used to store the Pipelines rendered in the commit view in the pipelines table.
*
* TODO: take care of timeago instances in here
*/
(() => {
const CommitPipelineStore = {
window.gl = window.gl || {};
gl.commits = gl.commits || {};
gl.commits.pipelines = gl.commits.pipelines || {};
gl.commits.pipelines.PipelinesStore = {
state: {},
create() {
......@@ -20,11 +22,9 @@
return this;
},
storePipelines(pipelines = []) {
store(pipelines = []) {
this.state.pipelines = pipelines;
return pipelines;
},
};
return CommitPipelineStore;
})();
......@@ -14,6 +14,7 @@
type: Object,
required: true,
},
//FIXME: DOMStringMap is non standard, let's use a plain object.
svgs: {
type: DOMStringMap,
required: true,
......
/* eslint-disable no-param-reassign, no-new */
/* eslint-disable no-param-reassign */
/* global Vue */
/* global PipelinesService */
/* global Flash */
//= require vue_pipelines_index/status.js.es6
//= require vue_pipelines_index/pipeline_url.js.es6
//= require vue_pipelines_index/stage.js.es6
//= require vue_pipelines_index/pipeline_actions.js.es6
//= require vue_pipelines_index/time_ago.js.es6
//= require vue_pipelines_index/pipelines.js.es6
//=require ./pipelines_table_row
/**
* Pipelines Table Component
*
* Given an array of pipelines, renders a table.
*
*/
(() => {
window.gl = window.gl || {};
......@@ -17,31 +17,10 @@
gl.pipelines.PipelinesTableComponent = Vue.component('pipelines-table-component', {
props: {
/**
* Object used to store the Pipelines to render.
* It's passed as a prop to allow different stores to use this Component.
* Different API calls can result in different responses, using a custom
* store allows us to use the same pipeline component.
*
* Note: All provided stores need to have a `storePipelines` method.
* Find a better way to do this.
*/
store: {
type: Object,
required: true,
default: () => ({}),
},
/**
* Will be used to fetch the needed data.
* This component is used in different and therefore different API calls
* to different endpoints will be made. To guarantee this is a reusable
* component, the endpoint must be provided.
*/
endpoint: {
type: String,
pipelines: {
type: Array,
required: true,
default: [],
},
/**
......@@ -55,219 +34,31 @@
},
components: {
'commit-component': gl.CommitComponent,
runningPipeline: gl.VueRunningPipeline,
pipelineActions: gl.VuePipelineActions,
'vue-stage': gl.VueStage,
pipelineUrl: gl.VuePipelineUrl,
pipelineHead: gl.VuePipelineHead,
statusScope: gl.VueStatusScope,
'pipelines-table-row-component': gl.pipelines.PipelinesTableRowComponent,
},
data() {
return {
state: this.store.state,
isLoading: false,
};
},
computed: {
/**
* If provided, returns the commit tag.
*
* @returns {Object|Undefined}
*/
commitAuthor() {
if (this.pipeline &&
this.pipeline.commit &&
this.pipeline.commit.author) {
return this.pipeline.commit.author;
}
return undefined;
},
/**
* If provided, returns the commit tag.
*
* @returns {String|Undefined}
*/
commitTag() {
if (this.model.last_deployment &&
this.model.last_deployment.tag) {
return this.model.last_deployment.tag;
}
return undefined;
},
/**
* If provided, returns the commit ref.
*
* @returns {Object|Undefined}
*/
commitRef() {
if (this.pipeline.ref) {
return Object.keys(this.pipeline.ref).reduce((accumulator, prop) => {
if (prop === 'url') {
accumulator.path = this.pipeline.ref[prop];
} else {
accumulator[prop] = this.pipeline.ref[prop];
}
return accumulator;
}, {});
}
return undefined;
},
/**
* If provided, returns the commit url.
*
* @returns {String|Undefined}
*/
commitUrl() {
if (this.pipeline.commit &&
this.pipeline.commit.commit_path) {
return this.pipeline.commit.commit_path;
}
return undefined;
},
/**
* If provided, returns the commit short sha.
*
* @returns {String|Undefined}
*/
commitShortSha() {
if (this.pipeline.commit &&
this.pipeline.commit.short_id) {
return this.pipeline.commit.short_id;
}
return undefined;
},
/**
* If provided, returns the commit title.
*
* @returns {String|Undefined}
*/
commitTitle() {
if (this.pipeline.commit &&
this.pipeline.commit.title) {
return this.pipeline.commit.title;
}
return undefined;
},
/**
* Figure this out!
*/
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,
};
},
/**
* Figure this out
*/
match(string) {
return string.replace(/_([a-z])/g, (m, w) => w.toUpperCase());
},
},
/**
* When the component is created the service to fetch the data will be
* initialized with the correct endpoint.
*
* A request to fetch the pipelines will be made.
* In case of a successfull response we will store the data in the provided
* store, in case of a failed response we need to warn the user.
*
*/
created() {
gl.pipelines.pipelinesService = new PipelinesService(this.endpoint);
this.isLoading = true;
return gl.pipelines.pipelinesService.all()
.then(resp => resp.json())
.then((json) => {
this.store.storePipelines(json);
this.isLoading = false;
}).catch(() => {
this.isLoading = false;
new Flash('An error occurred while fetching the pipelines.', 'alert');
});
},
// this need to be reusable between the 3 tables :/
template: `
<div>
<div class="pipelines realtime-loading" v-if='isLoading'>
<i class="fa fa-spinner fa-spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && 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'>
<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 state.pipelines'>
<status-scope
:pipeline='pipeline'
:match='match'
:svgs='svgs'>
</status-scope>
<pipeline-url :pipeline='pipeline'></pipeline-url>
<td>
<commit-component
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:short-sha="commitShortSha"
:title="commitTitle"
:author="commitAuthor"
:commit-icon-svg="commitIconSvg">
</commit-component>
</td>
<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>
<time-ago :pipeline='pipeline' :svgs='svgs'></time-ago>
<pipeline-actions :pipeline='pipeline' :svgs='svgs'></pipeline-actions>
</tr>
</tbody>
</table>
</div>
</div>
<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>
<template v-for="model in pipelines"
v-bind:model="model">
<tr
is="pipelines-table-row-component"
:pipeline="model"
:svgs="svgs"></tr>
</template>
</tbody>
</table>
`,
});
})();
/* eslint-disable no-param-reassign */
/* global Vue */
//= require vue_pipelines_index/status
//= require vue_pipelines_index/pipeline_url
//= require vue_pipelines_index/stage
//= require vue_shared/components/commit
//= require vue_pipelines_index/pipeline_actions
//= require vue_pipelines_index/time_ago
(() => {
window.gl = window.gl || {};
gl.pipelines = gl.pipelines || {};
gl.pipelines.PipelinesTableRowComponent = Vue.component('pipelines-table-row-component', {
props: {
pipeline: {
type: Object,
required: true,
default: () => ({}),
},
/**
* Remove this. Find a better way to do this. don't want to provide this 3 times.
*/
svgs: {
type: Object,
required: true,
default: () => ({}),
},
},
components: {
'commit-component': gl.CommitComponent,
runningPipeline: gl.VueRunningPipeline,
pipelineActions: gl.VuePipelineActions,
'vue-stage': gl.VueStage,
pipelineUrl: gl.VuePipelineUrl,
pipelineHead: gl.VuePipelineHead,
statusScope: gl.VueStatusScope,
},
computed: {
/**
* If provided, returns the commit tag.
* Needed to render the commit component column.
*
* @returns {Object|Undefined}
*/
commitAuthor() {
if (this.pipeline &&
this.pipeline.commit &&
this.pipeline.commit.author) {
return this.pipeline.commit.author;
}
return undefined;
},
/**
* 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;
// }
return undefined;
},
/**
* If provided, returns the commit ref.
* Needed to render the commit component column.
*
* @returns {Object|Undefined}
*/
commitRef() {
if (this.pipeline.ref) {
return Object.keys(this.pipeline.ref).reduce((accumulator, prop) => {
if (prop === 'url') {
accumulator.path = this.pipeline.ref[prop];
} else {
accumulator[prop] = this.pipeline.ref[prop];
}
return accumulator;
}, {});
}
return undefined;
},
/**
* If provided, returns the commit url.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitUrl() {
if (this.pipeline.commit &&
this.pipeline.commit.commit_path) {
return this.pipeline.commit.commit_path;
}
return undefined;
},
/**
* If provided, returns the commit short sha.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitShortSha() {
if (this.pipeline.commit &&
this.pipeline.commit.short_id) {
return this.pipeline.commit.short_id;
}
return undefined;
},
/**
* If provided, returns the commit title.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitTitle() {
if (this.pipeline.commit &&
this.pipeline.commit.title) {
return this.pipeline.commit.title;
}
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: {
match(string) {
return string.replace(/_([a-z])/g, (m, w) => w.toUpperCase());
},
},
template: `
<tr class="commit">
<status-scope
:pipeline='pipeline'
:svgs='svgs'
:match="match">
</status-scope>
<pipeline-url :pipeline='pipeline'></pipeline-url>
<td>
<commit-component
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:short-sha="commitShortSha"
:title="commitTitle"
:author="commitAuthor"
:commit-icon-svg="svgs.commitIconSvg">
</commit-component>
</td>
<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>
<time-ago :pipeline='pipeline' :svgs='svgs'></time-ago>
<pipeline-actions :pipeline='pipeline' :svgs='svgs'></pipeline-actions>
</tr>
`,
});
})();
......@@ -3,9 +3,6 @@
= render 'commit_box'
= render 'ci_menu'
- content_for :page_specific_javascripts do
= page_specific_javascript_tag("commit/pipelines/pipelines_bundle.js")
#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"),
......@@ -28,3 +25,6 @@
"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')
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