summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2017-01-27 22:24:08 +0000
committerFilipa Lacerda <filipa@gitlab.com>2017-02-03 09:43:53 +0000
commit037b4fe939696eebe6295a858470f2661d1e3878 (patch)
tree63370a1cf7a938abc3068dfbc66b984c6ae45dda /app
parentfd46fb1cd9cc1fdf826d31261aa594baa38d4898 (diff)
downloadgitlab-ce-037b4fe939696eebe6295a858470f2661d1e3878.tar.gz
First iteration
Create shared folder for vue common files Update paths Second iteration - refactor main component to be 100% reusable between the 3 tables
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/commit/pipelines_bundle.js.es661
-rw-r--r--app/assets/javascripts/commit/pipelines_service.js.es677
-rw-r--r--app/assets/javascripts/commit/pipelines_store.js.es630
-rw-r--r--app/assets/javascripts/environments/components/environment_item.js.es62
-rw-r--r--app/assets/javascripts/vue_pipelines_index/index.js.es62
-rw-r--r--app/assets/javascripts/vue_shared/components/commit.js.es6 (renamed from app/assets/javascripts/vue_common_component/commit.js.es6)0
-rw-r--r--app/assets/javascripts/vue_shared/components/pipelines_table.js.es6270
-rw-r--r--app/assets/javascripts/vue_shared/vue_resource_interceptor.js.es610
-rw-r--r--app/views/projects/commit/_pipelines_list.haml15
-rw-r--r--app/views/projects/commit/pipelines.html.haml27
10 files changed, 476 insertions, 18 deletions
diff --git a/app/assets/javascripts/commit/pipelines_bundle.js.es6 b/app/assets/javascripts/commit/pipelines_bundle.js.es6
new file mode 100644
index 00000000000..d2547f0b4a8
--- /dev/null
+++ b/app/assets/javascripts/commit/pipelines_bundle.js.es6
@@ -0,0 +1,61 @@
+/* eslint-disable no-new */
+/* global Vue, VueResource */
+
+//= 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
+
+/**
+ * Commits View > Pipelines Tab > Pipelines Table.
+ *
+ * Renders Pipelines table in pipelines tab in the commits show view.
+ *
+ * Uses `pipelines-table-component` to render Pipelines table with an API call.
+ * Endpoint is provided in HTML and passed as scope.
+ * We need a store to make the request and store the received environemnts.
+ *
+ * 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 || {};
+
+ if (gl.Commits.PipelinesTableView) {
+ gl.Commits.PipelinesTableView.$destroy(true);
+ }
+
+ gl.Commits.PipelinesTableView = new Vue({
+
+ el: document.querySelector('#commit-pipeline-table-view'),
+
+ /**
+ * Accesses the DOM to provide the needed data.
+ * Returns the necessary props to render `pipelines-table-component` component.
+ *
+ * @return {Object} Props for `pipelines-table-component`
+ */
+ data() {
+ const pipelinesTableData = document.querySelector('#commit-pipeline-table-view').dataset;
+
+ return {
+ scope: pipelinesTableData.pipelinesData,
+ store: new CommitsPipelineStore(),
+ service: new PipelinesService(),
+ svgs: pipelinesTableData,
+ };
+ },
+
+ components: {
+ 'pipelines-table-component': gl.pipelines.PipelinesTableComponent,
+ },
+
+ template: `
+ <pipelines-table-component :scope='scope' :store='store' :svgs='svgs'></pipelines-table-component>
+ `,
+ });
+});
diff --git a/app/assets/javascripts/commit/pipelines_service.js.es6 b/app/assets/javascripts/commit/pipelines_service.js.es6
new file mode 100644
index 00000000000..7d773e0d361
--- /dev/null
+++ b/app/assets/javascripts/commit/pipelines_service.js.es6
@@ -0,0 +1,77 @@
+/* globals Vue */
+/* eslint-disable no-unused-vars, no-param-reassign */
+
+/**
+ * Pipelines service.
+ *
+ * Used to fetch the data used to render the pipelines table.
+ * Used Vue.Resource
+ */
+
+window.gl = window.gl || {};
+gl.pipelines = gl.pipelines || {};
+
+class PipelinesService {
+ constructor(root) {
+ Vue.http.options.root = root;
+
+ this.pipelines = Vue.resource(root);
+
+ Vue.http.interceptors.push((request, next) => {
+ // needed in order to not break the tests.
+ if ($.rails) {
+ request.headers['X-CSRF-Token'] = $.rails.csrfToken();
+ }
+ next();
+ });
+ }
+
+ /**
+ * Given the root param provided when the class is initialized, will
+ * make a GET request.
+ *
+ * @return {Promise}
+ */
+ all() {
+ 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();
+// }
+// };
diff --git a/app/assets/javascripts/commit/pipelines_store.js.es6 b/app/assets/javascripts/commit/pipelines_store.js.es6
new file mode 100644
index 00000000000..bc748bece5d
--- /dev/null
+++ b/app/assets/javascripts/commit/pipelines_store.js.es6
@@ -0,0 +1,30 @@
+/* global gl, Flash */
+/* eslint-disable no-param-reassign, no-underscore-dangle */
+/*= require vue_realtime_listener/index.js */
+
+/**
+ * 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 = {
+ state: {},
+
+ create() {
+ this.state.pipelines = [];
+
+ return this;
+ },
+
+ storePipelines(pipelines = []) {
+ this.state.pipelines = pipelines;
+ return pipelines;
+ },
+ };
+
+ return CommitPipelineStore;
+})();
diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6
index 0e6bc3fdb2c..c7cb0913213 100644
--- a/app/assets/javascripts/environments/components/environment_item.js.es6
+++ b/app/assets/javascripts/environments/components/environment_item.js.es6
@@ -3,7 +3,7 @@
/*= require timeago */
/*= require lib/utils/text_utility */
-/*= require vue_common_component/commit */
+/*= require vue_shared/components/commit */
/*= require ./environment_actions */
/*= require ./environment_external_url */
/*= require ./environment_stop */
diff --git a/app/assets/javascripts/vue_pipelines_index/index.js.es6 b/app/assets/javascripts/vue_pipelines_index/index.js.es6
index edd01f17a97..36f861a7d02 100644
--- a/app/assets/javascripts/vue_pipelines_index/index.js.es6
+++ b/app/assets/javascripts/vue_pipelines_index/index.js.es6
@@ -1,5 +1,5 @@
/* global Vue, VueResource, gl */
-/*= require vue_common_component/commit */
+/*= require vue_shared/components/commit */
/*= require vue_pagination/index */
/*= require vue-resource
/*= require boards/vue_resource_interceptor */
diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_shared/components/commit.js.es6
index 62a22e39a3b..62a22e39a3b 100644
--- a/app/assets/javascripts/vue_common_component/commit.js.es6
+++ b/app/assets/javascripts/vue_shared/components/commit.js.es6
diff --git a/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6 b/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6
new file mode 100644
index 00000000000..0b20bf66a69
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/pipelines_table.js.es6
@@ -0,0 +1,270 @@
+/* eslint-disable no-param-reassign, no-new */
+/* 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
+
+(() => {
+ window.gl = window.gl || {};
+ gl.pipelines = gl.pipelines || {};
+
+ gl.pipelines.PipelinesTableComponent = Vue.component('pipelines-table-component', {
+
+ props: {
+
+ /**
+ * Stores 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.
+ */
+ 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,
+ required: true,
+ },
+
+ /**
+ * 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,
+ },
+
+ 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>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/vue_shared/vue_resource_interceptor.js.es6 b/app/assets/javascripts/vue_shared/vue_resource_interceptor.js.es6
new file mode 100644
index 00000000000..54c2b4ad369
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/vue_resource_interceptor.js.es6
@@ -0,0 +1,10 @@
+/* eslint-disable func-names, prefer-arrow-callback, no-unused-vars */
+/* global Vue */
+
+Vue.http.interceptors.push((request, next) => {
+ Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1;
+
+ next(function (response) {
+ Vue.activeResources -= 1;
+ });
+});
diff --git a/app/views/projects/commit/_pipelines_list.haml b/app/views/projects/commit/_pipelines_list.haml
index 1164627fa11..e69de29bb2d 100644
--- a/app/views/projects/commit/_pipelines_list.haml
+++ b/app/views/projects/commit/_pipelines_list.haml
@@ -1,15 +0,0 @@
-%div
- - if pipelines.blank?
- %div
- .nothing-here-block No pipelines to show
- - else
- .table-holder.pipelines
- %table.table.ci-table.js-pipeline-table
- %thead
- %th.pipeline-status Status
- %th.pipeline-info Pipeline
- %th.pipeline-commit Commit
- %th.pipeline-stages Stages
- %th.pipeline-date
- %th.pipeline-actions
- = render pipelines, commit_sha: true, stage: true, allow_retry: true, show_commit: false
diff --git a/app/views/projects/commit/pipelines.html.haml b/app/views/projects/commit/pipelines.html.haml
index 89968cf4e0d..f4937a03f03 100644
--- a/app/views/projects/commit/pipelines.html.haml
+++ b/app/views/projects/commit/pipelines.html.haml
@@ -2,4 +2,29 @@
= render 'commit_box'
= render 'ci_menu'
-= render 'pipelines_list', pipelines: @pipelines
+
+- content_for :page_specific_javascripts do
+ = page_specific_javascript_tag("commit/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"),
+ "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"),
+} }