From 4df7c9edef9c51d2ba45f09ad7a1d2d5e1686ba3 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 14 Oct 2016 13:14:18 +0100 Subject: Starts Vue view for environmnets List --- .../components/environments_tree_view.js.es6 | 0 .../environments/environments_bundle.js.es6 | 49 ++++++++++++++++++++++ .../services/environments_service.js.es6 | 19 +++++++++ .../environments/stores/environmnets_store.js.es6 | 21 ++++++++++ 4 files changed, 89 insertions(+) create mode 100644 app/assets/javascripts/environments/components/environments_tree_view.js.es6 create mode 100644 app/assets/javascripts/environments/environments_bundle.js.es6 create mode 100644 app/assets/javascripts/environments/services/environments_service.js.es6 create mode 100644 app/assets/javascripts/environments/stores/environmnets_store.js.es6 diff --git a/app/assets/javascripts/environments/components/environments_tree_view.js.es6 b/app/assets/javascripts/environments/components/environments_tree_view.js.es6 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 new file mode 100644 index 00000000000..1708fd43d27 --- /dev/null +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -0,0 +1,49 @@ +//= require vue +//= require vue-resource +//= require_tree ./stores +//= require_tree ./services + + +$(() => { + + const $environmentsListApp = document.getElementById('environments-list-view'); + const Store = gl.environmentsList.EnvironmentsStore; + + window.gl = window.gl || {}; + + if (gl.EnvironmentsListApp) { + gl.EnvironmentsListApp.$destroy(true); + } + + gl.EnvironmentsListApp = new Vue({ + + el: $environmentsListApp, + + components: { + 'tree-view': gl.environmentsList.TreeView + }, + + data: { + endpoint: $environmentsListApp.dataset.endpoint, + loading: true + }, + + init: Store.create.bind(Store), + + created() { + gl.environmentsService = new EnvironmentsService(this.endpoint); + }, + + /** + * Fetches all the environmnets and stores them. + * Toggles loading property. + */ + ready() { + gl.environmentsService.all().then((resp) => { + Store.addEnvironments(resp.json()); + + this.loading = false; + }); + } + }); +}); \ No newline at end of file diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 new file mode 100644 index 00000000000..179c0807cea --- /dev/null +++ b/app/assets/javascripts/environments/services/environments_service.js.es6 @@ -0,0 +1,19 @@ +class EnvironmentsService { + + constructor (root) { + Vue.http.options.root = root; + + debugger; + + this.environments = Vue.resource(root); + + Vue.http.interceptors.push((request, next) => { + request.headers['X-CSRF-Token'] = $.rails.csrfToken(); + next(); + }); + } + + all () { + return this.environments.get(); + } +}; \ No newline at end of file diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 new file mode 100644 index 00000000000..879719997e2 --- /dev/null +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -0,0 +1,21 @@ +(() => { + window.gl = window.gl || {}; + window.gl.environmentsList = window.gl.environmentsList || {}; + + gl.environmentsList.EnvironmentsStore = { + + create () { + + }, + + /** + * Stores the received environmnets. + * + * @param {Array} environments List of environments + * @return {type} + */ + addEnvironments(environments) { + console.log(environments); + } + } +})(); \ No newline at end of file -- cgit v1.2.1 From 235213dc68b7eeec8527347f7bc304d7765b4ff0 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 14 Oct 2016 13:14:41 +0100 Subject: Modifies controller to format data to json --- app/controllers/projects/environments_controller.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index ea22b2dcc15..9255388eb84 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -15,6 +15,13 @@ class Projects::EnvironmentsController < Projects::ApplicationController else @all_environments.available end + + respond_to do |format| + format.html + format.json do + render json: @environments + end + end end def show -- cgit v1.2.1 From 2c0f97cd1e99abdf7c80e2c79ed55b321bf5fb7b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 14 Oct 2016 13:15:29 +0100 Subject: Includes page specific JS --- app/helpers/environments_helper.rb | 7 +++++++ app/views/projects/environments/index.html.haml | 7 +++++-- config/application.rb | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 app/helpers/environments_helper.rb diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb new file mode 100644 index 00000000000..d9a3106f706 --- /dev/null +++ b/app/helpers/environments_helper.rb @@ -0,0 +1,7 @@ +module EnvironmentsHelper + def environments_list_data + { + endpoint: namespace_project_environments_path(@project.namespace, @project) + } + end +end \ No newline at end of file diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 8f555afcf11..a2526209df2 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -2,6 +2,9 @@ - page_title "Environments" = render "projects/pipelines/head" +- content_for :page_specific_javascripts do + = page_specific_javascript_tag('environments/environments_bundle.js') + %div{ class: container_class } .top-area %ul.nav-links @@ -22,7 +25,7 @@ = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - .environments-container + .environments-container#environments-list-view{ "v-cloak" => true, data: environments_list_data } - if @all_environments.blank? .blank-state.blank-state-no-icon %h2.blank-state-title @@ -45,4 +48,4 @@ %th Commit %th %th.hidden-xs - = render @environments + / = render @environments diff --git a/config/application.rb b/config/application.rb index 946b632b0e8..fb84870dfbd 100644 --- a/config/application.rb +++ b/config/application.rb @@ -94,6 +94,7 @@ module Gitlab config.assets.precompile << "cycle_analytics/cycle_analytics_bundle.js" config.assets.precompile << "merge_conflicts/merge_conflicts_bundle.js" config.assets.precompile << "boards/test_utils/simulate_drag.js" + config.assets.precompile << "environments/environments_bundle.js" config.assets.precompile << "blob_edit/blob_edit_bundle.js" config.assets.precompile << "snippet/snippet_bundle.js" config.assets.precompile << "lib/utils/*.js" -- cgit v1.2.1 From 52c4f8ef648db49b1b8260e9239844faf6198972 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 14 Oct 2016 16:45:57 +0100 Subject: Stores environmnets in tree --- .../environments/environments_bundle.js.es6 | 2 +- .../environments/stores/environmnets_store.js.es6 | 53 +++++++++++++++++++--- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 1708fd43d27..783940c8f63 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -40,7 +40,7 @@ $(() => { */ ready() { gl.environmentsService.all().then((resp) => { - Store.addEnvironments(resp.json()); + Store.storeEnvironments(resp.json()); this.loading = false; }); diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 879719997e2..911dd3e9352 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -3,19 +3,58 @@ window.gl.environmentsList = window.gl.environmentsList || {}; gl.environmentsList.EnvironmentsStore = { + state: {}, create () { - + this.state.environments = []; }, /** - * Stores the received environmnets. + * In order to display a tree view we need to modify the received + * data in to a tree structure based on `environment_type` + * sorted alphabetically. * + * @example + * it will transform this: + * [ + * { name: "environment", environment_type: "review" }, + * { name: "environment_1", environment_type: null } + * { name: "environment_2, environment_type: "review" } + * ] + * into this: + * [ + * { name: "review", children: + * [ + * { name: "environment", environment_type: "review"}, + * { name: "environment_2", environment_type: "review"} + * ] + * }, + * {name: "environment_1", environment_type: null} + * ] * @param {Array} environments List of environments - * @return {type} - */ - addEnvironments(environments) { - console.log(environments); - } + */ + storeEnvironments(environments) { + this.state.environments = environments.reduce((acc, environment) => { + if (environment.environment_type !== null) { + const occurs = acc.find((element, index, array) => { + return element.name === environment.environment_type; + }); + + if (occurs !== undefined) { + acc[acc.indexOf(occurs)].children.push(environment); + acc[acc.indexOf(occurs)].children.sort(); + } else { + acc.push({ + name: environment.environment_type, + children: [environment] + }); + } + } else { + acc.push(environment); + } + + return acc; + }, []).sort(); + } } })(); \ No newline at end of file -- cgit v1.2.1 From de990812d54e0d1915b16d6d74fd912c39c6c1da Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 14 Oct 2016 18:38:13 +0100 Subject: Creates component --- .../components/environment_item.js.es6 | 34 +++++++++++++++ .../components/environments_tree_view.js.es6 | 0 .../environments/environments_bundle.js.es6 | 5 ++- .../services/environments_service.js.es6 | 2 - .../environments/stores/environmnets_store.js.es6 | 11 ++++- .../environments/components/_environment.html.haml | 8 ++++ app/views/projects/environments/index.html.haml | 49 ++++++++++++---------- 7 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 app/assets/javascripts/environments/components/environment_item.js.es6 delete mode 100644 app/assets/javascripts/environments/components/environments_tree_view.js.es6 create mode 100644 app/views/projects/environments/components/_environment.html.haml diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 new file mode 100644 index 00000000000..b62d77140fa --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -0,0 +1,34 @@ +(() => { + const Store = gl.environmentsList.EnvironmentsStore; + + window.gl = window.gl || {}; + window.gl.environmentsList = window.gl.environmentsList || {}; + + gl.environmentsList.EnvironmentItem = Vue.extend({ + + props: { + model: Object + }, + + data: function () { + return { + open: false + }; + }, + + computed: { + isFolder: function() { + debugger; + return this.model.children && this.model.children.length + } + }, + + methods: { + toggle: function () { + if (this.isFolder) { + this.open = !this.open; + } + } + } + }) +})(); \ No newline at end of file diff --git a/app/assets/javascripts/environments/components/environments_tree_view.js.es6 b/app/assets/javascripts/environments/components/environments_tree_view.js.es6 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 783940c8f63..89d2fad1215 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -2,7 +2,7 @@ //= require vue-resource //= require_tree ./stores //= require_tree ./services - +//= require ./components/environment_item $(() => { @@ -20,10 +20,11 @@ $(() => { el: $environmentsListApp, components: { - 'tree-view': gl.environmentsList.TreeView + 'environment-item': gl.environmentsList.EnvironmentItem }, data: { + state: Store.state, endpoint: $environmentsListApp.dataset.endpoint, loading: true }, diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 index 179c0807cea..5c545fc4778 100644 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ b/app/assets/javascripts/environments/services/environments_service.js.es6 @@ -3,8 +3,6 @@ class EnvironmentsService { constructor (root) { Vue.http.options.root = root; - debugger; - this.environments = Vue.resource(root); Vue.http.interceptors.push((request, next) => { diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 911dd3e9352..6aa1b828bcb 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -31,10 +31,13 @@ * }, * {name: "environment_1", environment_type: null} * ] - * @param {Array} environments List of environments + * + * + * @param {Array} environments List of environments. + * @returns {Array} Tree structured array with the received environments. */ storeEnvironments(environments) { - this.state.environments = environments.reduce((acc, environment) => { + const environmentsTree = environments.reduce((acc, environment) => { if (environment.environment_type !== null) { const occurs = acc.find((element, index, array) => { return element.name === environment.environment_type; @@ -55,6 +58,10 @@ return acc; }, []).sort(); + + this.state.environments = environmentsTree; + + return environmentsTree; } } })(); \ No newline at end of file diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml new file mode 100644 index 00000000000..7cfe1029a41 --- /dev/null +++ b/app/views/projects/environments/components/_environment.html.haml @@ -0,0 +1,8 @@ +%environment-item{"inline-template" => true, + "v-for" => "environment in state.environments", + ":model" => "environment"} + %i{"v-if" => "isFolder"} + = icon("plus") + %i{"v-if" => ""} + = icon("less") + {{model.name}} diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index a2526209df2..e989ec60611 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -26,26 +26,29 @@ New environment .environments-container#environments-list-view{ "v-cloak" => true, data: environments_list_data } - - if @all_environments.blank? - .blank-state.blank-state-no-icon - %h2.blank-state-title - You don't have any environments right now. - %p.blank-state-text - Environments are places where code gets deployed, such as staging or production. - %br - = succeed "." do - = link_to "Read more about environments", help_page_path("ci/environments") - - if can?(current_user, :create_environment, @project) - = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do - New environment - - else - .table-holder - %table.table.ci-table.environments - %tbody - %th Environment - %th Last Deployment - %th Build - %th Commit - %th - %th.hidden-xs - / = render @environments + .environments-list-viewtext-center{ "v-if" => "loading" } + = icon("spinner spin") + + .blank-state.blank-state-no-icon{ "v-if" => "state.environments.length === 0" } + %h2.blank-state-title + You don't have any environments right now. + %p.blank-state-text + Environments are places where code gets deployed, such as staging or production. + %br + = succeed "." do + = link_to "Read more about environments", help_page_path("ci/environments") + - if can?(current_user, :create_environment, @project) + = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do + New environment + + .table-holder{ "v-if" => "state.environments.length" } + %table.table.ci-table.environments + %thead + %th Environment + %th Last Deployment + %th Build + %th Commit + %th + %th.hidden-xs + %tbody + =render "projects/environments/components/environment" -- cgit v1.2.1 From 109dc41fad156b1999023b5e1deb133ef08660ce Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 17 Oct 2016 10:41:45 +0100 Subject: Adds folder icons --- .../environments/components/environment_item.js.es6 | 7 +++++-- .../projects/environments/components/_environment.html.haml | 11 ++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index b62d77140fa..70fab9b07d4 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -17,9 +17,12 @@ }, computed: { - isFolder: function() { - debugger; + isFolder: function () { return this.model.children && this.model.children.length + }, + + isOpen: function () { + return this.open; } }, diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 7cfe1029a41..01e3cb3a290 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -1,8 +1,9 @@ %environment-item{"inline-template" => true, "v-for" => "environment in state.environments", ":model" => "environment"} - %i{"v-if" => "isFolder"} - = icon("plus") - %i{"v-if" => ""} - = icon("less") - {{model.name}} + .name{"click" => "toggle"} + %i{"v-if" => "isFolder && isOpen"} + = icon("caret-down") + %i{"v-if" => "isFolder && !isOpen"} + = icon("caret-right") + {{model.name}} -- cgit v1.2.1 From 58f95c2ccd482dddb3e94f21b65790ca00fcf7ff Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 17 Oct 2016 16:09:39 +0100 Subject: Adds loading while fetching data --- app/assets/stylesheets/pages/environments.scss | 5 +++++ app/views/projects/environments/index.html.haml | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index fc49ff780fc..495284fa2d7 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -73,3 +73,8 @@ } } } + +.environments-list-loading { + width: 100%; + font-size: 34px; +} diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index e989ec60611..3483683bc2f 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -26,10 +26,10 @@ New environment .environments-container#environments-list-view{ "v-cloak" => true, data: environments_list_data } - .environments-list-viewtext-center{ "v-if" => "loading" } + .environments-list-loading.text-center{ "v-if" => "loading" } = icon("spinner spin") - .blank-state.blank-state-no-icon{ "v-if" => "state.environments.length === 0" } + .blank-state.blank-state-no-icon{ "v-if" => "!loading && state.environments.length === 0" } %h2.blank-state-title You don't have any environments right now. %p.blank-state-text @@ -41,7 +41,7 @@ = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - .table-holder{ "v-if" => "state.environments.length" } + .table-holder{ "v-if" => "!loading && state.environments.length" } %table.table.ci-table.environments %thead %th Environment -- cgit v1.2.1 From f716da652d857b26dd5e424c77ac0898ae85bdb5 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 17 Oct 2016 18:03:19 +0100 Subject: Adds template for table row --- .../components/environment_item.js.es6 | 8 ++--- .../environments/environments_bundle.js.es6 | 6 ++-- app/assets/stylesheets/pages/environments.scss | 4 +++ .../environments/components/_environment.html.haml | 17 ++++++---- app/views/projects/environments/index.html.haml | 36 ++++++++++++++-------- 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 70fab9b07d4..fd825842747 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -4,7 +4,11 @@ window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; + debugger; + gl.environmentsList.EnvironmentItem = Vue.extend({ + + template: '#environment-item-template', props: { model: Object @@ -19,10 +23,6 @@ computed: { isFolder: function () { return this.model.children && this.model.children.length - }, - - isOpen: function () { - return this.open; } }, diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 89d2fad1215..2769f6899fe 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -6,7 +6,7 @@ $(() => { - const $environmentsListApp = document.getElementById('environments-list-view'); + const environmentsListApp = document.getElementById('environments-list-view'); const Store = gl.environmentsList.EnvironmentsStore; window.gl = window.gl || {}; @@ -17,7 +17,7 @@ $(() => { gl.EnvironmentsListApp = new Vue({ - el: $environmentsListApp, + el: '#environments-list-view', components: { 'environment-item': gl.environmentsList.EnvironmentItem @@ -25,7 +25,7 @@ $(() => { data: { state: Store.state, - endpoint: $environmentsListApp.dataset.endpoint, + endpoint: environmentsListApp.dataset.endpoint, loading: true }, diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 495284fa2d7..f0bc2f635aa 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -72,6 +72,10 @@ margin-right: 0; } } + + .environment-folder-name { + cursor: pointer; + } } .environments-list-loading { diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 01e3cb3a290..8a0e7fb4349 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -1,9 +1,14 @@ %environment-item{"inline-template" => true, "v-for" => "environment in state.environments", ":model" => "environment"} - .name{"click" => "toggle"} - %i{"v-if" => "isFolder && isOpen"} - = icon("caret-down") - %i{"v-if" => "isFolder && !isOpen"} - = icon("caret-right") - {{model.name}} + .environment-folder-name{"@click" => "toggle"} + %span.icon-container{"v-if" => "isFolder"} + %i{"v-show" => "open"} + = icon("caret-down") + + %i{"v-show" => "!open"} + = icon("caret-right") + %span.name-container + {{model.name}} + + // {"name":"review","children":[{"id":8,"project_id":10,"name":"review/app","created_at":"2016-10-13T14:15:33.550Z","updated_at":"2016-10-13T14:15:33.550Z","external_url":"http://gitlab.com","environment_type":"review","state":"opened"}]} \ No newline at end of file diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 3483683bc2f..ec83399f480 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -25,11 +25,11 @@ = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - .environments-container#environments-list-view{ "v-cloak" => true, data: environments_list_data } + #environments-list-view{ data: environments_list_data, class: "environments-container" } .environments-list-loading.text-center{ "v-if" => "loading" } = icon("spinner spin") - .blank-state.blank-state-no-icon{ "v-if" => "!loading && state.environments.length === 0" } + .blank-state.blank-state-no-icon{ "v-if" => "!loading && !state.environments.length" } %h2.blank-state-title You don't have any environments right now. %p.blank-state-text @@ -42,13 +42,25 @@ New environment .table-holder{ "v-if" => "!loading && state.environments.length" } - %table.table.ci-table.environments - %thead - %th Environment - %th Last Deployment - %th Build - %th Commit - %th - %th.hidden-xs - %tbody - =render "projects/environments/components/environment" + %table.table + %tr{"is"=>"environment-item", + "inline-template" => true, + "v-for" => "environment in state.environments", + ":model" => "environment"} + + +%script#environment-item-template{"type"=> "text/x-template"} + %tr + %td.environment-folder-name{"@click" => "toggle"} + %span.icon-container{"v-if" => "isFolder"} + %i{"v-show" => "open"} + = icon("caret-down") + + %i{"v-show" => "!open"} + = icon("caret-right") + %span.name-container + {{model.name}} + %tr{"v-show" => "open", "v-if"=>"isFolder"} + %td{"v-for" => "child in model.children", + ":model" => "child"} + {{child.name}} -- cgit v1.2.1 From 37a100c80f81c8948b1a6d36696ba0a588e070db Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 17 Oct 2016 23:18:49 +0100 Subject: Adds children rows --- app/assets/stylesheets/pages/environments.scss | 6 ++++- app/views/projects/environments/index.html.haml | 35 ++++++++++++++++++------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index f0bc2f635aa..c60455e148f 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -61,7 +61,11 @@ } .table.ci-table.environments { - + + .environment-children td:first-child { + padding-left: 40px; + } + .icon-container { width: 20px; text-align: center; diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index ec83399f480..f8e264ac6bf 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -42,15 +42,23 @@ New environment .table-holder{ "v-if" => "!loading && state.environments.length" } - %table.table - %tr{"is"=>"environment-item", - "inline-template" => true, - "v-for" => "environment in state.environments", - ":model" => "environment"} + %table.table.ci-table.environments + %thead + %th Environment + %th Last Deployment + %th Build + %th Commit + %th + %th.hidden-xs + %tbody + %tr{"is"=>"environment-item", + "inline-template" => true, + "v-for" => "environment in state.environments", + ":model" => "environment"} %script#environment-item-template{"type"=> "text/x-template"} - %tr + %tr.environment %td.environment-folder-name{"@click" => "toggle"} %span.icon-container{"v-if" => "isFolder"} %i{"v-show" => "open"} @@ -60,7 +68,16 @@ = icon("caret-right") %span.name-container {{model.name}} - %tr{"v-show" => "open", "v-if"=>"isFolder"} - %td{"v-for" => "child in model.children", - ":model" => "child"} + %td + %a{{"v-if" => "model.last_deployment"}} + {{model.last_deployment.id}} + %tr.environment-children{"v-show" => "open", + "v-if"=>"isFolder", + "v-for" => "child in model.children", + ":model" => "child"} + %td {{child.name}} + %td.deployment-column + %span{"v-if" => "child.last_deployment && child.last_deployment.iid"} + {{child.last_deployment.iid}} + \ No newline at end of file -- cgit v1.2.1 From 234c0415e4b1a7584d629d9cc9d8d8d884dc7b6a Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 19 Oct 2016 10:06:03 +0100 Subject: Updates Component with documentation and template with links for details --- .../components/environment_item.js.es6 | 27 ++++++- .../environments/components/_environment.html.haml | 82 ++++++++++++++++++---- app/views/projects/environments/index.html.haml | 34 ++------- 3 files changed, 98 insertions(+), 45 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index fd825842747..a8298150ff5 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,11 +1,22 @@ (() => { + + /** + * Envrionment Item Component + * + * Used in a hierarchical structure to show folders with children + * in a table. + * Based on [Tree View](https://vuejs.org/examples/tree-view.html) + * The template used in this Component is non recursive. + * + * See this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/22539) + * for more information. + */ + const Store = gl.environmentsList.EnvironmentsStore; window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; - debugger; - gl.environmentsList.EnvironmentItem = Vue.extend({ template: '#environment-item-template', @@ -21,12 +32,24 @@ }, computed: { + + /** + * If an item has a `children` entry it means it is a folder. + * Folder items have different behaviours - it is possible to toggle + * them and show their children. + * + * @returns {Number} The length of the children array + */ isFolder: function () { return this.model.children && this.model.children.length } }, methods: { + + /** + * Toggles the visibility of a folders' children. + */ toggle: function () { if (this.isFolder) { this.open = !this.open; diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 8a0e7fb4349..2943e5ca2c6 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -1,14 +1,68 @@ -%environment-item{"inline-template" => true, - "v-for" => "environment in state.environments", - ":model" => "environment"} - .environment-folder-name{"@click" => "toggle"} - %span.icon-container{"v-if" => "isFolder"} - %i{"v-show" => "open"} - = icon("caret-down") - - %i{"v-show" => "!open"} - = icon("caret-right") - %span.name-container - {{model.name}} - - // {"name":"review","children":[{"id":8,"project_id":10,"name":"review/app","created_at":"2016-10-13T14:15:33.550Z","updated_at":"2016-10-13T14:15:33.550Z","external_url":"http://gitlab.com","environment_type":"review","state":"opened"}]} \ No newline at end of file +%script#environment-item-template{ "type"=> "text/x-template" } + %tr.environment + %td.environment-folder-name{ "@click" => "toggle" } + %a{ "v-if" => "!isFolder", + ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id" } + {{model.name}} + + %span{ "v-if" => "isFolder" } + %i{ "v-show" => "open" } + = icon("caret-down") + + %i{ "v-show" => "!open" } + = icon("caret-right") + + {{model.name}} + + %td.deployment-column + %span{ "v-if" => "model.last_deployment && model.last_deployment.iid" } + {{model.last_deployment.iid}} + by + %span{ "v-if" => "model.last_deployment.user" } + {{model.last_deployment.user}} + + %td + column 3 + + %td + column 4 + + %td + column 5 + + %td.hidden-xs + .pull-right + actions + -# = render 'projects/environments/external_url', environment: "model" + -# = render 'projects/deployments/actions', deployment: "model.last_deployment" + -# = render 'projects/environments/stop', environment: "model" + -# = render 'projects/deployments/rollback', deployment: "model.last_deployment" + + %tr.environment-children{ "v-show" => "open", + "v-if"=>"isFolder", + "v-for" => "child in model.children", + ":model" => "child" } + + %td + %a{ ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + child.id" } + {{child.name}} + + %td.deployment-column + %span{ "v-if" => "child.last_deployment && child.last_deployment.iid" } + {{child.last_deployment.iid}} + %span{ "v-if" => "child.last_deployment && child.last_deployment.user" } + {{child.last_deployment.user}} + /= user_avatar(user: "child.last_deployment.user", size: 20) + + %td + column 3 + + %td + column 4 + + %td + column 5 + + %td.hidden-xs + .pull-right + actions \ No newline at end of file diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index f8e264ac6bf..4391271f5c7 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -3,7 +3,7 @@ = render "projects/pipelines/head" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('environments/environments_bundle.js') + = page_specific_javascript_tag("environments/environments_bundle.js") %div{ class: container_class } .top-area @@ -22,7 +22,7 @@ - if can?(current_user, :create_environment, @project) && !@all_environments.blank? .nav-controls - = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do + = link_to new_namespace_project_environment_path(@project.namespace, @project), class: "btn btn-create" do New environment #environments-list-view{ data: environments_list_data, class: "environments-container" } @@ -51,33 +51,9 @@ %th %th.hidden-xs %tbody - %tr{"is"=>"environment-item", + %tr{ "is"=>"environment-item", "inline-template" => true, "v-for" => "environment in state.environments", - ":model" => "environment"} - - -%script#environment-item-template{"type"=> "text/x-template"} - %tr.environment - %td.environment-folder-name{"@click" => "toggle"} - %span.icon-container{"v-if" => "isFolder"} - %i{"v-show" => "open"} - = icon("caret-down") + ":model" => "environment" } - %i{"v-show" => "!open"} - = icon("caret-right") - %span.name-container - {{model.name}} - %td - %a{{"v-if" => "model.last_deployment"}} - {{model.last_deployment.id}} - %tr.environment-children{"v-show" => "open", - "v-if"=>"isFolder", - "v-for" => "child in model.children", - ":model" => "child"} - %td - {{child.name}} - %td.deployment-column - %span{"v-if" => "child.last_deployment && child.last_deployment.iid"} - {{child.last_deployment.iid}} - \ No newline at end of file +=render "projects/environments/components/environment" \ No newline at end of file -- cgit v1.2.1 From 2a40dec16d4690d11417013cab82cd6e2cbdb235 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 19 Oct 2016 17:03:48 +0100 Subject: Serialize all needed data --- app/controllers/projects/environments_controller.rb | 12 +++++++++++- app/helpers/environments_helper.rb | 2 +- .../environments/components/_environment.html.haml | 20 +++++++++++++------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 9255388eb84..e937e6b950b 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -19,7 +19,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController respond_to do |format| format.html format.json do - render json: @environments + render json: serialize_as_json(@environments) end end end @@ -69,4 +69,14 @@ class Projects::EnvironmentsController < Projects::ApplicationController def environment @environment ||= project.environments.find(params[:id]) end + + def serialize_as_json(resource) + resource.as_json( + include: { + last_deployment: { + include: [:deployable, :user] + } + } + ) + end end diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index d9a3106f706..954ecb65985 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -1,5 +1,5 @@ module EnvironmentsHelper - def environments_list_data + def environments_list_data() { endpoint: namespace_project_environments_path(@project.namespace, @project) } diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 2943e5ca2c6..a64af5fef6f 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -12,23 +12,27 @@ %i{ "v-show" => "!open" } = icon("caret-right") - {{model.name}} + %td.deployment-column - %span{ "v-if" => "model.last_deployment && model.last_deployment.iid" } + %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid" } {{model.last_deployment.iid}} + by %span{ "v-if" => "model.last_deployment.user" } - {{model.last_deployment.user}} + {{model.last_deployment.user.name}} %td - column 3 + %a{ "v-if" => "!isFolder" } + column 3 %td - column 4 + %a{ "v-if" => "!isFolder" } + column 3 %td - column 5 + %span{ "v-if" => "!isFolder && model.last_deployment" } + {{last_deployment.created_at}} %td.hidden-xs .pull-right @@ -55,7 +59,9 @@ /= user_avatar(user: "child.last_deployment.user", size: 20) %td - column 3 + %a.build-link{ "v-if" => "child.last_deployment && child.last_deployment.deployable", + ":href" => "" } + {{child.last_deployment}} %td column 4 -- cgit v1.2.1 From c02a4f384ad0530e9d48b3ede4238ac4fe2d3e9c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 19 Oct 2016 17:12:21 +0100 Subject: Adds all first row columns --- .../environments/components/_environment.html.haml | 48 ++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index a64af5fef6f..48fb7d90ed1 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -11,8 +11,8 @@ %i{ "v-show" => "!open" } = icon("caret-right") - - + + {{model.name}} %td.deployment-column %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid" } @@ -23,25 +23,25 @@ {{model.last_deployment.user.name}} %td - %a{ "v-if" => "!isFolder" } - column 3 + %a{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", + ":class" => "build-link", + ":href" => "" } + {{model.last_deployment.deployable.name}} (## {{model.last_deployment.deployable.id}}) %td - %a{ "v-if" => "!isFolder" } - column 3 + %a{ "v-if" => "!isFolder && model.last_deployment" } + column 4 + %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment"} + No deployments yet %td %span{ "v-if" => "!isFolder && model.last_deployment" } - {{last_deployment.created_at}} + {{model.last_deployment.created_at}} %td.hidden-xs - .pull-right + .pull-right{ "v-if" => "!isFolder"} actions - -# = render 'projects/environments/external_url', environment: "model" - -# = render 'projects/deployments/actions', deployment: "model.last_deployment" - -# = render 'projects/environments/stop', environment: "model" - -# = render 'projects/deployments/rollback', deployment: "model.last_deployment" - + %tr.environment-children{ "v-show" => "open", "v-if"=>"isFolder", "v-for" => "child in model.children", @@ -54,21 +54,27 @@ %td.deployment-column %span{ "v-if" => "child.last_deployment && child.last_deployment.iid" } {{child.last_deployment.iid}} - %span{ "v-if" => "child.last_deployment && child.last_deployment.user" } - {{child.last_deployment.user}} - /= user_avatar(user: "child.last_deployment.user", size: 20) + + by + %span{ "v-if" => "model.last_deployment.user" } + {{child.last_deployment.user.name}} %td - %a.build-link{ "v-if" => "child.last_deployment && child.last_deployment.deployable", + %a{ "v-if" => " child.last_deployment && child.last_deployment.deployable", + ":class" => "build-link", ":href" => "" } - {{child.last_deployment}} + {{model.last_deployment.deployable.name}} (## {{model.last_deployment.deployable.id}}) %td - column 4 + %a{ "v-if" => "child.last_deployment" } + column 4 + %p.commit-title{ "v-if" => "!child.last_deployment"} + No deployments yet %td - column 5 + %span{ "v-if" => "child.last_deployment" } + {{child.last_deployment.created_at}} %td.hidden-xs - .pull-right + .pull-right{ "v-if" => "!isFolder"} actions \ No newline at end of file -- cgit v1.2.1 From 4508f85ab7aae29729b8dce10585586ab206ce60 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 10:06:03 +0100 Subject: Adds user column with avatar url --- .../projects/environments_controller.rb | 7 ++-- .../environments/components/_environment.html.haml | 40 ++++++++++++++++------ 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index e937e6b950b..d261bfa9b8d 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -73,8 +73,11 @@ class Projects::EnvironmentsController < Projects::ApplicationController def serialize_as_json(resource) resource.as_json( include: { - last_deployment: { - include: [:deployable, :user] + last_deployment: { + include: { + user: { only: [:id, :name, :username], methods: [:avatar_url] }, + deployable: { only: [:id, :name] } + } } } ) diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 48fb7d90ed1..8dd477d11ec 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -18,9 +18,15 @@ %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid" } {{model.last_deployment.iid}} - by %span{ "v-if" => "model.last_deployment.user" } - {{model.last_deployment.user.name}} + by + %a{":href" => "'/' + model.last_deployment.user.username"} + + %img.avatar.has-tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", + ":alt" => "model.last_deployment.user.username + ' avatar'", + ":title" => "model.last_deployment.user.username", + data: { container: 'body'}, + width: 20, height: 20 } %td %a{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", @@ -30,7 +36,7 @@ %td %a{ "v-if" => "!isFolder && model.last_deployment" } - column 4 + / = render "projects/deployments/commit", deployment: "{{model.last_deployment}}" %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment"} No deployments yet @@ -40,7 +46,10 @@ %td.hidden-xs .pull-right{ "v-if" => "!isFolder"} - actions + -# = render "projects/environments/external_url", environment: "{{model}}" + -# = render "projects/deployments/actions", deployment: "{{model.last_deployment}}" + -# = render "projects/environments/stop", environment: "{{model}}" + -# = render "projects/deployments/rollback", deployment: "{{model.last_deployment}}" %tr.environment-children{ "v-show" => "open", "v-if"=>"isFolder", @@ -55,19 +64,25 @@ %span{ "v-if" => "child.last_deployment && child.last_deployment.iid" } {{child.last_deployment.iid}} - by - %span{ "v-if" => "model.last_deployment.user" } - {{child.last_deployment.user.name}} + %span{ "v-if" => "child.last_deployment.user" } + by + %a{":href" => "'/' + child.last_deployment.user.username"} + + %img.avatar.has-tooltip.s20{ ":src" => "child.last_deployment.user.avatar_url", + ":alt" => "child.last_deployment.user.username + ' avatar'", + ":title" => "child.last_deployment.user.username", + data: { container: 'body'}, + width: 20, height: 20 } %td %a{ "v-if" => " child.last_deployment && child.last_deployment.deployable", ":class" => "build-link", ":href" => "" } - {{model.last_deployment.deployable.name}} (## {{model.last_deployment.deployable.id}}) + {{chil.last_deployment.deployable.name}} (## {{child.last_deployment.deployable.id}}) %td %a{ "v-if" => "child.last_deployment" } - column 4 + / = render "projects/deployments/commit", deployment: "{{child.last_deployment}}" %p.commit-title{ "v-if" => "!child.last_deployment"} No deployments yet @@ -76,5 +91,8 @@ {{child.last_deployment.created_at}} %td.hidden-xs - .pull-right{ "v-if" => "!isFolder"} - actions \ No newline at end of file + .pull-right + -# = render "projects/environments/external_url", environment: "{{child}}" + -# = render "projects/deployments/actions", deployment: "{{child.last_deployment}}" + -# = render "projects/environments/stop", environment: "{{child}}" + -# = render "projects/deployments/rollback", deployment: "{{child.last_deployment}}" \ No newline at end of file -- cgit v1.2.1 From c28df601dcbfa5b1d44d4f351c64e04a69d24d0e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 11:20:37 +0100 Subject: Adds build column --- .../projects/environments/components/_environment.html.haml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 8dd477d11ec..fe34730440f 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -29,9 +29,8 @@ width: 20, height: 20 } %td - %a{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", - ":class" => "build-link", - ":href" => "" } + %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", + ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id" } {{model.last_deployment.deployable.name}} (## {{model.last_deployment.deployable.id}}) %td @@ -75,10 +74,9 @@ width: 20, height: 20 } %td - %a{ "v-if" => " child.last_deployment && child.last_deployment.deployable", - ":class" => "build-link", - ":href" => "" } - {{chil.last_deployment.deployable.name}} (## {{child.last_deployment.deployable.id}}) + %a.build-link{ "v-if" => "child.last_deployment && child.last_deployment.deployable", + ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + child.last_deployment.deployable.id" } + {{child.last_deployment.deployable.name}} (## {{child.last_deployment.deployable.id}}) %td %a{ "v-if" => "child.last_deployment" } -- cgit v1.2.1 From b31c9f531853172f5704c81f2f5dee5d1ce37afd Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 11:43:22 +0100 Subject: Commit column --- app/controllers/projects/environments_controller.rb | 2 +- app/views/projects/environments/components/_environment.html.haml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index d261bfa9b8d..c760f885a4c 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -76,7 +76,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController last_deployment: { include: { user: { only: [:id, :name, :username], methods: [:avatar_url] }, - deployable: { only: [:id, :name] } + deployable: { only: [:id, :name, :ref, :tag, :short_sha] } } } } diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index fe34730440f..ef82a70031e 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -21,7 +21,7 @@ %span{ "v-if" => "model.last_deployment.user" } by %a{":href" => "'/' + model.last_deployment.user.username"} - + %img.avatar.has-tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", ":alt" => "model.last_deployment.user.username + ' avatar'", ":title" => "model.last_deployment.user.username", @@ -35,7 +35,7 @@ %td %a{ "v-if" => "!isFolder && model.last_deployment" } - / = render "projects/deployments/commit", deployment: "{{model.last_deployment}}" + -# = render "projects/deployments/commit", deployment: "{{model.last_deployment}}" %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment"} No deployments yet @@ -80,7 +80,7 @@ %td %a{ "v-if" => "child.last_deployment" } - / = render "projects/deployments/commit", deployment: "{{child.last_deployment}}" + -# = render "projects/deployments/commit", deployment: "{{child.last_deployment}}" %p.commit-title{ "v-if" => "!child.last_deployment"} No deployments yet -- cgit v1.2.1 From c497153ece65b6cdcb2404a2a928b36e1ef9c75a Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 12:09:35 +0100 Subject: Adds newline at end of file --- app/assets/javascripts/environments/components/environment_item.js.es6 | 2 +- app/assets/javascripts/environments/environments_bundle.js.es6 | 2 +- .../javascripts/environments/services/environments_service.js.es6 | 2 +- app/assets/javascripts/environments/stores/environmnets_store.js.es6 | 2 +- app/helpers/environments_helper.rb | 2 +- app/views/projects/environments/components/_environment.html.haml | 2 +- app/views/projects/environments/index.html.haml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index a8298150ff5..3e43c64139a 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -57,4 +57,4 @@ } } }) -})(); \ No newline at end of file +})(); diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 2769f6899fe..9d4affdb2b6 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -47,4 +47,4 @@ $(() => { }); } }); -}); \ No newline at end of file +}); diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 index 5c545fc4778..5cc194ac034 100644 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ b/app/assets/javascripts/environments/services/environments_service.js.es6 @@ -14,4 +14,4 @@ class EnvironmentsService { all () { return this.environments.get(); } -}; \ No newline at end of file +}; diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 6aa1b828bcb..564b33607d7 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -64,4 +64,4 @@ return environmentsTree; } } -})(); \ No newline at end of file +})(); diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 954ecb65985..7c09c20d118 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -4,4 +4,4 @@ module EnvironmentsHelper endpoint: namespace_project_environments_path(@project.namespace, @project) } end -end \ No newline at end of file +end diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index ef82a70031e..1c91b60b741 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -93,4 +93,4 @@ -# = render "projects/environments/external_url", environment: "{{child}}" -# = render "projects/deployments/actions", deployment: "{{child.last_deployment}}" -# = render "projects/environments/stop", environment: "{{child}}" - -# = render "projects/deployments/rollback", deployment: "{{child.last_deployment}}" \ No newline at end of file + -# = render "projects/deployments/rollback", deployment: "{{child.last_deployment}}" diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 4391271f5c7..34f38a2ee32 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -56,4 +56,4 @@ "v-for" => "environment in state.environments", ":model" => "environment" } -=render "projects/environments/components/environment" \ No newline at end of file +=render "projects/environments/components/environment" -- cgit v1.2.1 From 3265518b39622c9522f49c8cad58185421b2eda6 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 13:40:23 +0100 Subject: Fixes build column --- app/views/projects/environments/components/_environment.html.haml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 1c91b60b741..8db29444935 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -31,7 +31,9 @@ %td %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id" } - {{model.last_deployment.deployable.name}} (## {{model.last_deployment.deployable.id}}) + {{model.last_deployment.deployable.name}} + = precede '#' do + ({{model.last_deployment.deployable.id}}) %td %a{ "v-if" => "!isFolder && model.last_deployment" } @@ -76,7 +78,9 @@ %td %a.build-link{ "v-if" => "child.last_deployment && child.last_deployment.deployable", ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + child.last_deployment.deployable.id" } - {{child.last_deployment.deployable.name}} (## {{child.last_deployment.deployable.id}}) + {{child.last_deployment.deployable.name}} + = precede '#' do + ({{child.last_deployment.deployable.id}}) %td %a{ "v-if" => "child.last_deployment" } -- cgit v1.2.1 From 96152f17d115a08726bfd1322d0dba33fe5cd211 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 13:53:28 +0100 Subject: Adds # back to deployment id --- app/assets/stylesheets/pages/environments.scss | 31 +++++++++++++--------- .../environments/components/_environment.html.haml | 16 ++++++----- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index c60455e148f..cb9196dde92 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -4,6 +4,11 @@ overflow: auto; } +.environments-list-loading { + width: 100%; + font-size: 34px; +} + .environments { .deployment-column { .avatar { @@ -58,14 +63,23 @@ } } } + + .children-name{ + margin-left: 17px; + margin-right: -17px; + } + + .folder-icon { + padding: 0 5px 0 0; + } + + .folder-name { + cursor: pointer; + } } .table.ci-table.environments { - .environment-children td:first-child { - padding-left: 40px; - } - .icon-container { width: 20px; text-align: center; @@ -76,13 +90,4 @@ margin-right: 0; } } - - .environment-folder-name { - cursor: pointer; - } -} - -.environments-list-loading { - width: 100%; - font-size: 34px; } diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 8db29444935..ae080137361 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -1,22 +1,23 @@ %script#environment-item-template{ "type"=> "text/x-template" } %tr.environment - %td.environment-folder-name{ "@click" => "toggle" } + %td.folder-name{ "@click" => "toggle" } %a{ "v-if" => "!isFolder", ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id" } {{model.name}} %span{ "v-if" => "isFolder" } - %i{ "v-show" => "open" } + %i.folder-icon{ "v-show" => "open" } = icon("caret-down") - %i{ "v-show" => "!open" } + %i.folder-icon{ "v-show" => "!open" } = icon("caret-right") {{model.name}} %td.deployment-column %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid" } - {{model.last_deployment.iid}} + = precede '#' do + {{model.last_deployment.iid}} %span{ "v-if" => "model.last_deployment.user" } by @@ -52,18 +53,19 @@ -# = render "projects/environments/stop", environment: "{{model}}" -# = render "projects/deployments/rollback", deployment: "{{model.last_deployment}}" - %tr.environment-children{ "v-show" => "open", + %tr{ "v-show" => "open", "v-if"=>"isFolder", "v-for" => "child in model.children", ":model" => "child" } %td - %a{ ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + child.id" } + %a.children-name{ ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + child.id" } {{child.name}} %td.deployment-column %span{ "v-if" => "child.last_deployment && child.last_deployment.iid" } - {{child.last_deployment.iid}} + = precede '#' do + {{child.last_deployment.iid}} %span{ "v-if" => "child.last_deployment.user" } by -- cgit v1.2.1 From e4ff8dd2f100daaec614881c2b2733a92f4ec4d8 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 17:43:52 +0100 Subject: Recursive component --- .../components/environment_item.js.es6 | 11 +- .../environments/environments_bundle.js.es6 | 2 +- .../environments/components/_environment.html.haml | 116 ++++++--------------- app/views/projects/environments/index.html.haml | 7 +- 4 files changed, 41 insertions(+), 95 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 3e43c64139a..71463bd1748 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -5,8 +5,7 @@ * * Used in a hierarchical structure to show folders with children * in a table. - * Based on [Tree View](https://vuejs.org/examples/tree-view.html) - * The template used in this Component is non recursive. + * Recursive component based on [Tree View](https://vuejs.org/examples/tree-view.html) * * See this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/22539) * for more information. @@ -17,7 +16,7 @@ window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; - gl.environmentsList.EnvironmentItem = Vue.extend({ + gl.environmentsList.EnvironmentItem = Vue.component("environment-item", { template: '#environment-item-template', @@ -25,7 +24,7 @@ model: Object }, - data: function () { + data () { return { open: false }; @@ -40,7 +39,7 @@ * * @returns {Number} The length of the children array */ - isFolder: function () { + isFolder () { return this.model.children && this.model.children.length } }, @@ -50,7 +49,7 @@ /** * Toggles the visibility of a folders' children. */ - toggle: function () { + toggle () { if (this.isFolder) { this.open = !this.open; } diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 9d4affdb2b6..027dc7fb211 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -20,7 +20,7 @@ $(() => { el: '#environments-list-view', components: { - 'environment-item': gl.environmentsList.EnvironmentItem + 'item': gl.environmentsList.EnvironmentItem }, data: { diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index ae080137361..76d921e9fd3 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -1,102 +1,52 @@ %script#environment-item-template{ "type"=> "text/x-template" } - %tr.environment - %td.folder-name{ "@click" => "toggle" } - %a{ "v-if" => "!isFolder", + %tr + %td.folder-name + %a{ "v-if" => "!isFolder", ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id" } {{model.name}} + %span{ "v-if" => "isFolder", + "@click" => "toggle" } - %span{ "v-if" => "isFolder" } - %i.folder-icon{ "v-show" => "open" } - = icon("caret-down") - - %i.folder-icon{ "v-show" => "!open" } - = icon("caret-right") + %i.folder-icon{ "v-show" => "open"} + =icon ("caret-down") + %i.folder-icon{ "v-show" => "!open"} + =icon("caret-right") {{model.name}} - + %td.deployment-column - %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid" } - = precede '#' do + %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid"} + = precede "#" do {{model.last_deployment.iid}} - - %span{ "v-if" => "model.last_deployment.user" } + + %span{ "v-if" => "model.last_deployment.user"} by %a{":href" => "'/' + model.last_deployment.user.username"} - - %img.avatar.has-tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", - ":alt" => "model.last_deployment.user.username + ' avatar'", + %img.avatar.has_tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", + ":alt" => "model.last_deployment.user.username + 'avatar'", ":title" => "model.last_deployment.user.username", - data: { container: 'body'}, - width: 20, height: 20 } - + data: {container: "body"}, + width: 20, height: 20} + %td %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", - ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id" } - {{model.last_deployment.deployable.name}} - = precede '#' do - ({{model.last_deployment.deployable.id}}) - + ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id"} + {{model.last_deployment.deployble.name}} + = precede "#" do + {{model.last_deployment.deployable.id}} + %td - %a{ "v-if" => "!isFolder && model.last_deployment" } - -# = render "projects/deployments/commit", deployment: "{{model.last_deployment}}" + %a{ "v-if" => "!isFolder && model.last_deployment"} + commit message goes here %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment"} No deployments yet - - %td - %span{ "v-if" => "!isFolder && model.last_deployment" } + + %td + %span{ "v-if" => "!isFolder && model.last_deployment"} {{model.last_deployment.created_at}} - + %td.hidden-xs .pull-right{ "v-if" => "!isFolder"} - -# = render "projects/environments/external_url", environment: "{{model}}" - -# = render "projects/deployments/actions", deployment: "{{model.last_deployment}}" - -# = render "projects/environments/stop", environment: "{{model}}" - -# = render "projects/deployments/rollback", deployment: "{{model.last_deployment}}" - - %tr{ "v-show" => "open", - "v-if"=>"isFolder", - "v-for" => "child in model.children", - ":model" => "child" } - - %td - %a.children-name{ ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + child.id" } - {{child.name}} - - %td.deployment-column - %span{ "v-if" => "child.last_deployment && child.last_deployment.iid" } - = precede '#' do - {{child.last_deployment.iid}} - - %span{ "v-if" => "child.last_deployment.user" } - by - %a{":href" => "'/' + child.last_deployment.user.username"} - - %img.avatar.has-tooltip.s20{ ":src" => "child.last_deployment.user.avatar_url", - ":alt" => "child.last_deployment.user.username + ' avatar'", - ":title" => "child.last_deployment.user.username", - data: { container: 'body'}, - width: 20, height: 20 } - - %td - %a.build-link{ "v-if" => "child.last_deployment && child.last_deployment.deployable", - ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + child.last_deployment.deployable.id" } - {{child.last_deployment.deployable.name}} - = precede '#' do - ({{child.last_deployment.deployable.id}}) - - %td - %a{ "v-if" => "child.last_deployment" } - -# = render "projects/deployments/commit", deployment: "{{child.last_deployment}}" - %p.commit-title{ "v-if" => "!child.last_deployment"} - No deployments yet - - %td - %span{ "v-if" => "child.last_deployment" } - {{child.last_deployment.created_at}} - - %td.hidden-xs - .pull-right - -# = render "projects/environments/external_url", environment: "{{child}}" - -# = render "projects/deployments/actions", deployment: "{{child.last_deployment}}" - -# = render "projects/environments/stop", environment: "{{child}}" - -# = render "projects/deployments/rollback", deployment: "{{child.last_deployment}}" + actions will go here + + %tr{"v-if" => "open && isFolder", "is" => "environment-item", "v-for" => "model in model.children", ":model" => "model"} diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 34f38a2ee32..a8667d88e7b 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -41,7 +41,7 @@ = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - .table-holder{ "v-if" => "!loading && state.environments.length" } + .table-holder{ "v-if" => "!loading && state.environments" } %table.table.ci-table.environments %thead %th Environment @@ -51,9 +51,6 @@ %th %th.hidden-xs %tbody - %tr{ "is"=>"environment-item", - "inline-template" => true, - "v-for" => "environment in state.environments", - ":model" => "environment" } + %tr{"is" => "environment-item", "v-for" => "model in state.environments", ":model" => "model"} =render "projects/environments/components/environment" -- cgit v1.2.1 From d873a3bd552bf63d8037392bdf56b86b1c7996d9 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 20 Oct 2016 20:37:54 +0100 Subject: Adds commit partial for vue component --- app/controllers/projects/environments_controller.rb | 5 +++-- .../environments/components/_commit.html.haml | 20 ++++++++++++++++++++ .../environments/components/_environment.html.haml | 6 +++--- 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 app/views/projects/environments/components/_commit.html.haml diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index c760f885a4c..20b4ed46d0a 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -76,8 +76,9 @@ class Projects::EnvironmentsController < Projects::ApplicationController last_deployment: { include: { user: { only: [:id, :name, :username], methods: [:avatar_url] }, - deployable: { only: [:id, :name, :ref, :tag, :short_sha] } - } + deployable: { only: [:id, :name, :ref, :tag] } + }, + methods: [:short_sha, :commit_title, :commit] } } ) diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml new file mode 100644 index 00000000000..25bd6223841 --- /dev/null +++ b/app/views/projects/environments/components/_commit.html.haml @@ -0,0 +1,20 @@ +.branch-commit{"v-if" => "!isFolder && model.last_deployment"} + %div{ "v-if" => "model.last_deployment.ref" } + .icon-container{ "v-if" => "model.last_deployment.tag" } + =icon("tag") + .icon-container{ "v-if" => "!model.last_deployment.tag" } + =icon("code-fork") + %a.monospace.branch-name{} + {{model.last_deployment.ref}} + + .icon-container.commit-icon + = custom_icon("icon_commit") + %a.commit-id.monospace{":href" => ""} + {{model.last_deployment.short_sha}} + + %p.commit-title + %span{ "v-if" => "model.last_deployment.commit_title"} + %a.commit-row-message{":href" => ""} + {{model.last_deployment.commit_title}} + %span{ "v-if" => "!model.last_deployment.commit_title"} + Cant find HEAD commit for this branch diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 76d921e9fd3..3e11141d01a 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -31,13 +31,13 @@ %td %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id"} - {{model.last_deployment.deployble.name}} + {{model.last_deployment.deployable.name}} = precede "#" do {{model.last_deployment.deployable.id}} %td - %a{ "v-if" => "!isFolder && model.last_deployment"} - commit message goes here + =render "projects/environments/components/commit" + %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment"} No deployments yet -- cgit v1.2.1 From 9c1e5649a59ec21dbd5eb47e2bbc8c903bd8b18a Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 12:05:31 +0100 Subject: Adds CSS for children rows to be indented --- .../environments/components/environment_item.js.es6 | 12 +++++++++++- app/assets/stylesheets/pages/environments.scss | 2 +- .../projects/environments/components/_environment.html.haml | 12 ++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 71463bd1748..961396b46b7 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -16,7 +16,7 @@ window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; - gl.environmentsList.EnvironmentItem = Vue.component("environment-item", { + gl.environmentsList.EnvironmentItem = Vue.component('environment-item', { template: '#environment-item-template', @@ -41,6 +41,16 @@ */ isFolder () { return this.model.children && this.model.children.length + }, + + /** + * If an item is inside a folder structure will return true. + * Used for css purposes. + * + * @returns {Boolean|undefined} + */ + isChildren () { + return this.model['vue-isChildren']; } }, diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index cb9196dde92..973820e8740 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -64,7 +64,7 @@ } } - .children-name{ + .children-row .environment-name{ margin-left: 17px; margin-right: -17px; } diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 3e11141d01a..677ab9f60bd 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -1,10 +1,11 @@ %script#environment-item-template{ "type"=> "text/x-template" } %tr - %td.folder-name - %a{ "v-if" => "!isFolder", + %td{"v-bind:class" => "{ 'children-row': isChildren}"} + %a.environment-name{ "v-if" => "!isFolder", ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id" } {{model.name}} - %span{ "v-if" => "isFolder", + + %span.folder-name{ "v-if" => "isFolder", "@click" => "toggle" } %i.folder-icon{ "v-show" => "open"} @@ -49,4 +50,7 @@ .pull-right{ "v-if" => "!isFolder"} actions will go here - %tr{"v-if" => "open && isFolder", "is" => "environment-item", "v-for" => "model in model.children", ":model" => "model"} + %tr{"v-if" => "open && isFolder", + "is" => "environment-item", + "v-for" => "model in model.children", + ":model" => "model"} -- cgit v1.2.1 From ea91d9cc970883e0de5dfb35894d52a60f258d3b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 12:06:33 +0100 Subject: Adds attribute in store --- .../environments/stores/environmnets_store.js.es6 | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 564b33607d7..dbf1bee05bb 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -13,6 +13,11 @@ * In order to display a tree view we need to modify the received * data in to a tree structure based on `environment_type` * sorted alphabetically. + * In each children a `vue-` property will be added. This property will be + * used to know if an item is a children mostly for css purposes. This is + * needed because the children row is a fragment instance and therfore does + * not accept non-prop attributes. + * * * @example * it will transform this: @@ -25,8 +30,8 @@ * [ * { name: "review", children: * [ - * { name: "environment", environment_type: "review"}, - * { name: "environment_2", environment_type: "review"} + * { name: "environment", environment_type: "review", vue-isChildren: true}, + * { name: "environment_2", environment_type: "review", vue-isChildren: true} * ] * }, * {name: "environment_1", environment_type: null} @@ -44,12 +49,15 @@ }); if (occurs !== undefined) { - acc[acc.indexOf(occurs)].children.push(environment); + acc[acc.indexOf(occurs)].children.push( + Object.assign({}, environment, {"vue-isChildren": true})); acc[acc.indexOf(occurs)].children.sort(); } else { acc.push({ name: environment.environment_type, - children: [environment] + children: [ + Object.assign({}, environment, {"vue-isChildren": true}) + ] }); } } else { -- cgit v1.2.1 From a60e6f14a7c9bbb6cd3d2eeec0ca384d389d501a Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 12:06:57 +0100 Subject: Adds commit partial for vue component --- app/views/projects/environments/components/_commit.html.haml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index 25bd6223841..3395b2fa240 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -1,20 +1,28 @@ .branch-commit{"v-if" => "!isFolder && model.last_deployment"} + %div{ "v-if" => "model.last_deployment.ref" } + .icon-container{ "v-if" => "model.last_deployment.tag" } =icon("tag") + .icon-container{ "v-if" => "!model.last_deployment.tag" } =icon("code-fork") - %a.monospace.branch-name{} + + %a.monospace.branch-name{":href" => ""} {{model.last_deployment.ref}} .icon-container.commit-icon = custom_icon("icon_commit") + %a.commit-id.monospace{":href" => ""} {{model.last_deployment.short_sha}} + {{model.last_deployment.sha}} %p.commit-title + %span{ "v-if" => "model.last_deployment.commit_title"} %a.commit-row-message{":href" => ""} {{model.last_deployment.commit_title}} + %span{ "v-if" => "!model.last_deployment.commit_title"} Cant find HEAD commit for this branch -- cgit v1.2.1 From dc46dc1d5f873e1a0aeaacca2b02614c9c79f79b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 12:53:08 +0100 Subject: Adds commit back --- app/controllers/projects/environments_controller.rb | 5 ++--- app/views/projects/environments/components/_commit.html.haml | 7 ++++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 20b4ed46d0a..cb2420f9042 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -75,10 +75,9 @@ class Projects::EnvironmentsController < Projects::ApplicationController include: { last_deployment: { include: { - user: { only: [:id, :name, :username], methods: [:avatar_url] }, - deployable: { only: [:id, :name, :ref, :tag] } + user: { only: [:id, :name, :username], methods: [:avatar_url] } }, - methods: [:short_sha, :commit_title, :commit] + methods: [:short_sha, :commit_title, :deployable, :commit] } } ) diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index 3395b2fa240..b10a2e483ba 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -9,19 +9,24 @@ =icon("code-fork") %a.monospace.branch-name{":href" => ""} + -# need commits branch name url {{model.last_deployment.ref}} .icon-container.commit-icon = custom_icon("icon_commit") %a.commit-id.monospace{":href" => ""} + -# need commit url built with commit sha {{model.last_deployment.short_sha}} - {{model.last_deployment.sha}} %p.commit-title %span{ "v-if" => "model.last_deployment.commit_title"} + + -# need commit author username and avatar_url + commit author goes here %a.commit-row-message{":href" => ""} + -# need commit url built with commit sha {{model.last_deployment.commit_title}} %span{ "v-if" => "!model.last_deployment.commit_title"} -- cgit v1.2.1 From 843e5642369e20d138e2053e50de4481dcb3f9ef Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 15:40:16 +0100 Subject: Adds commit links --- app/controllers/projects/environments_controller.rb | 3 ++- app/views/projects/environments/components/_commit.html.haml | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index cb2420f9042..6858b6da3ea 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -78,7 +78,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController user: { only: [:id, :name, :username], methods: [:avatar_url] } }, methods: [:short_sha, :commit_title, :deployable, :commit] - } + }, + project: { methods: [:namespace]} } ) end diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index b10a2e483ba..cbf76960ac4 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -8,8 +8,7 @@ .icon-container{ "v-if" => "!model.last_deployment.tag" } =icon("code-fork") - %a.monospace.branch-name{":href" => ""} - -# need commits branch name url + %a.monospace.branch-name{":href" => "'/' + model.project.namespace.name + '/' + model.project.name + '/commits/' +model.last_deployment.ref"} {{model.last_deployment.ref}} .icon-container.commit-icon -- cgit v1.2.1 From b20fd5c74ae87bb4187603ef8f535c1c9004abbb Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 15:47:53 +0100 Subject: Adds commit sha link --- app/views/projects/environments/components/_commit.html.haml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index cbf76960ac4..1f923a2d0d6 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -14,8 +14,7 @@ .icon-container.commit-icon = custom_icon("icon_commit") - %a.commit-id.monospace{":href" => ""} - -# need commit url built with commit sha + %a.commit-id.monospace{":href" => "'/' + model.project.namespace.name + '/' + model.project.name + '/commit/' +model.last_deployment.sha"} {{model.last_deployment.short_sha}} %p.commit-title @@ -24,8 +23,7 @@ -# need commit author username and avatar_url commit author goes here - %a.commit-row-message{":href" => ""} - -# need commit url built with commit sha + %a.commit-row-message{":href" => "'/' + model.project.namespace.name + '/' + model.project.name + '/commit/' +model.last_deployment.sha"} {{model.last_deployment.commit_title}} %span{ "v-if" => "!model.last_deployment.commit_title"} -- cgit v1.2.1 From 40e25ea866b14c57fd858fe30d8ab8e86f8af04e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 18:24:48 +0100 Subject: Adds external url partial for vue component --- app/views/projects/environments/components/_environment.html.haml | 2 +- app/views/projects/environments/components/_external_url.html.haml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 app/views/projects/environments/components/_external_url.html.haml diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 677ab9f60bd..deef1e034ca 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -48,7 +48,7 @@ %td.hidden-xs .pull-right{ "v-if" => "!isFolder"} - actions will go here + =render "projects/environments/components/external_url" %tr{"v-if" => "open && isFolder", "is" => "environment-item", diff --git a/app/views/projects/environments/components/_external_url.html.haml b/app/views/projects/environments/components/_external_url.html.haml new file mode 100644 index 00000000000..6cd405660cf --- /dev/null +++ b/app/views/projects/environments/components/_external_url.html.haml @@ -0,0 +1,4 @@ +%a.btn.external-url{ "v-if" => "!isFolder && model.external_url", + ":target" => "_blank", + ":href" => "model.external_url"} + = icon("external-link") \ No newline at end of file -- cgit v1.2.1 From 6b71ca0c46aab8612308823a5dfa01b193bc5eaf Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 22:16:05 +0100 Subject: Adds permissions verification to external url button --- .../projects/environments/components/_external_url.html.haml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/projects/environments/components/_external_url.html.haml b/app/views/projects/environments/components/_external_url.html.haml index 6cd405660cf..dc224475b8b 100644 --- a/app/views/projects/environments/components/_external_url.html.haml +++ b/app/views/projects/environments/components/_external_url.html.haml @@ -1,4 +1,5 @@ -%a.btn.external-url{ "v-if" => "!isFolder && model.external_url", - ":target" => "_blank", - ":href" => "model.external_url"} - = icon("external-link") \ No newline at end of file +-if can?(current_user, :read_environment, @project) + %a.btn.external-url{ "v-if" => "!isFolder && model.external_url", + ":target" => "_blank", + ":href" => "model.external_url"} + = icon("external-link") \ No newline at end of file -- cgit v1.2.1 From 9d8de1c97f03b5fbeedcd0d867eecdd2eed4e1bc Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 23:33:18 +0100 Subject: Adds actions --- .../projects/environments/components/_actions.html.haml | 14 ++++++++++++++ .../environments/components/_external_url.html.haml | 2 +- .../projects/environments/components/_rollback.html.haml | 0 app/views/projects/environments/components/_stop.html.haml | 0 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 app/views/projects/environments/components/_actions.html.haml create mode 100644 app/views/projects/environments/components/_rollback.html.haml create mode 100644 app/views/projects/environments/components/_stop.html.haml diff --git a/app/views/projects/environments/components/_actions.html.haml b/app/views/projects/environments/components/_actions.html.haml new file mode 100644 index 00000000000..35a80c936db --- /dev/null +++ b/app/views/projects/environments/components/_actions.html.haml @@ -0,0 +1,14 @@ +- if can?(current_user, :create_deployment, @project) + .inline{ "v-if" => "model.last_deployment.manual_actions && model.last_deployment.manual_actions.present"} + .dropdown + %a.dropdown-new.btn.btn-default{type: "button", "data-toggle" => "dropdown"} + = custom_icon('icon_play') + = icon('caret-down') + + %ul.dropdown-menu.dropdown-menu-align-right + %li{ "v-for" => "action in model.last_deployment.manual_actions" } + -# transform this = link_to [:play, @project.namespace.becomes(Namespace), @project, action] into href + %a{data: {"method" => ":post", "rel" => "nofollow"}} + = custom_icon('icon_play') + %span + {{action.name}} \ No newline at end of file diff --git a/app/views/projects/environments/components/_external_url.html.haml b/app/views/projects/environments/components/_external_url.html.haml index dc224475b8b..9b789d0ed5f 100644 --- a/app/views/projects/environments/components/_external_url.html.haml +++ b/app/views/projects/environments/components/_external_url.html.haml @@ -2,4 +2,4 @@ %a.btn.external-url{ "v-if" => "!isFolder && model.external_url", ":target" => "_blank", ":href" => "model.external_url"} - = icon("external-link") \ No newline at end of file + = icon("external-link") diff --git a/app/views/projects/environments/components/_rollback.html.haml b/app/views/projects/environments/components/_rollback.html.haml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/views/projects/environments/components/_stop.html.haml b/app/views/projects/environments/components/_stop.html.haml new file mode 100644 index 00000000000..e69de29bb2d -- cgit v1.2.1 From d418d4990ee5ee0db3d73b8270e2466d1915ad4f Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 23:33:41 +0100 Subject: Adds humanize function equivalent to ruby --- app/assets/javascripts/lib/utils/text_utility.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index 98f9815ff05..efa25958b15 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -112,6 +112,9 @@ gl.text.removeListeners = function(form) { return $('.js-md', form).off(); }; + gl.text.humanize = function(string) { + return string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1); + } return gl.text.truncate = function(string, maxLength) { return string.substr(0, (maxLength - 3)) + '...'; }; -- cgit v1.2.1 From adb223442f7167cbb5049ce7088614694f902b15 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 23:34:03 +0100 Subject: Beautifies sent data into human readable formats --- .../environments/stores/environmnets_store.js.es6 | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index dbf1bee05bb..7f0065bca8e 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -43,25 +43,41 @@ */ storeEnvironments(environments) { const environmentsTree = environments.reduce((acc, environment) => { + const data = Object.assign({}, environment); + + if (data.last_deployment) { + + //humanizes actions names if there are any actions + if (data.last_deployment.manual_actions) { + data.last_deployment.manual_actions = data.last_deployment.manual_actions.map((action) => Object.assign({}, action, {name: gl.text.humanize(action.name)})); + } + + //transforms created date for deployment in a human readable format + if (data.last_deployment.created_at) { + // TODO - how to do this without jquery + } + } + if (environment.environment_type !== null) { const occurs = acc.find((element, index, array) => { return element.name === environment.environment_type; }); + + data["vue-isChildren"] = true; if (occurs !== undefined) { - acc[acc.indexOf(occurs)].children.push( - Object.assign({}, environment, {"vue-isChildren": true})); + acc[acc.indexOf(occurs)].children.push(data); acc[acc.indexOf(occurs)].children.sort(); } else { acc.push({ name: environment.environment_type, children: [ - Object.assign({}, environment, {"vue-isChildren": true}) + Object.assign(data) ] }); } } else { - acc.push(environment); + acc.push(data); } return acc; -- cgit v1.2.1 From 070165f09bcbe63d079f67d5d0ccdc0259fa790b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 21 Oct 2016 23:39:52 +0100 Subject: Adds stop template --- app/views/projects/environments/components/_stop.html.haml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/views/projects/environments/components/_stop.html.haml b/app/views/projects/environments/components/_stop.html.haml index e69de29bb2d..6e13a6a1ac4 100644 --- a/app/views/projects/environments/components/_stop.html.haml +++ b/app/views/projects/environments/components/_stop.html.haml @@ -0,0 +1,8 @@ +- if can?(current_user, :create_deployment, @project) + .inline{ "v-if" => "environment.stop_action"} + -# TODO: Fix this link + -# link_to stop_namespace_project_environment_path(@project.namespace, @project, environment) + %a{":href" => "", + "method" => ":post", + "rel" => "nofollow", "confirm" => "Are you sure you want to stop this environment?"} + = icon('stop', class: 'stop-env-icon') -- cgit v1.2.1 From 3ea611e73f76fca4e773deb4e953617d5588fab5 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 24 Oct 2016 11:03:08 +0100 Subject: Adds counter for number of children in each folder --- .../environments/components/environment_item.js.es6 | 15 +++++++++++++-- app/assets/stylesheets/pages/environments.scss | 9 ++++++++- .../environments/components/_environment.html.haml | 3 +++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 961396b46b7..5159d5c4dee 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -37,10 +37,10 @@ * Folder items have different behaviours - it is possible to toggle * them and show their children. * - * @returns {Number} The length of the children array + * @returns {Boolean} */ isFolder () { - return this.model.children && this.model.children.length + return this.model.children && this.model.children.length ? true : false; }, /** @@ -51,6 +51,17 @@ */ isChildren () { return this.model['vue-isChildren']; + }, + + + /** + * Counts the number of environments in each folder. + * Used to show a badge with the counter. + * + * @returns {Boolean} The number of environments for the current folder + */ + childrenCounter () { + return this.model.children && this.model.children.length; } }, diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 973820e8740..ed0151bb120 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -64,7 +64,7 @@ } } - .children-row .environment-name{ + .children-row .environment-name { margin-left: 17px; margin-right: -17px; } @@ -75,6 +75,13 @@ .folder-name { cursor: pointer; + + .badge { + font-weight: normal; + background-color: $gray-darker; + color: $gl-placeholder-color; + vertical-align: baseline; + } } } diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index deef1e034ca..7e8bcbaa67d 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -14,6 +14,9 @@ =icon("caret-right") {{model.name}} + + %span.badge + {{childrenCounter}} %td.deployment-column %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid"} -- cgit v1.2.1 From 79e9b89069cbde9c76b8876a2e5296cf4356830e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 24 Oct 2016 11:18:34 +0100 Subject: Sort environments by name --- .../environments/stores/environmnets_store.js.es6 | 21 ++++++++++++++++++--- .../environments/components/_environment.html.haml | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 7f0065bca8e..8b5cb67ed37 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -60,14 +60,14 @@ if (environment.environment_type !== null) { const occurs = acc.find((element, index, array) => { - return element.name === environment.environment_type; + return element.environment_type === environment.environment_type; }); data["vue-isChildren"] = true; if (occurs !== undefined) { acc[acc.indexOf(occurs)].children.push(data); - acc[acc.indexOf(occurs)].children.sort(); + acc[acc.indexOf(occurs)].children.push(data).sort(this.sortByName) } else { acc.push({ name: environment.environment_type, @@ -81,11 +81,26 @@ } return acc; - }, []).sort(); + }, []).sort(this.sortByName); this.state.environments = environmentsTree; return environmentsTree; + }, + + sortByName (a,b) { + const nameA = a.name.toUpperCase(); + const nameB = b.name.toUpperCase(); + + if (nameA < nameB) { + return -1; + } + + if (nameA > nameB) { + return 1; + } + + return 0; } } })(); diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 7e8bcbaa67d..6cf0c1f3999 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -52,6 +52,7 @@ %td.hidden-xs .pull-right{ "v-if" => "!isFolder"} =render "projects/environments/components/external_url" + =render "projects/environments/components/actions" %tr{"v-if" => "open && isFolder", "is" => "environment-item", -- cgit v1.2.1 From 667b71a40b158ff3b0db4f34efdd1efc59c729c0 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 24 Oct 2016 11:36:35 +0100 Subject: Close button --- app/views/projects/environments/components/_actions.html.haml | 2 +- app/views/projects/environments/components/_environment.html.haml | 2 ++ app/views/projects/environments/components/_stop.html.haml | 8 +++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/projects/environments/components/_actions.html.haml b/app/views/projects/environments/components/_actions.html.haml index 35a80c936db..50a731475ba 100644 --- a/app/views/projects/environments/components/_actions.html.haml +++ b/app/views/projects/environments/components/_actions.html.haml @@ -1,5 +1,5 @@ - if can?(current_user, :create_deployment, @project) - .inline{ "v-if" => "model.last_deployment.manual_actions && model.last_deployment.manual_actions.present"} + .inline{ "v-if" => "model.last_deployment && model.last_deployment.manual_actions && model.last_deployment.manual_actions.present"} .dropdown %a.dropdown-new.btn.btn-default{type: "button", "data-toggle" => "dropdown"} = custom_icon('icon_play') diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 6cf0c1f3999..e479d5ef85b 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -53,6 +53,8 @@ .pull-right{ "v-if" => "!isFolder"} =render "projects/environments/components/external_url" =render "projects/environments/components/actions" + =render "projects/environments/components/stop" + =render "projects/environments/components/rollback" %tr{"v-if" => "open && isFolder", "is" => "environment-item", diff --git a/app/views/projects/environments/components/_stop.html.haml b/app/views/projects/environments/components/_stop.html.haml index 6e13a6a1ac4..741a72704c5 100644 --- a/app/views/projects/environments/components/_stop.html.haml +++ b/app/views/projects/environments/components/_stop.html.haml @@ -1,8 +1,6 @@ - if can?(current_user, :create_deployment, @project) - .inline{ "v-if" => "environment.stop_action"} - -# TODO: Fix this link - -# link_to stop_namespace_project_environment_path(@project.namespace, @project, environment) - %a{":href" => "", + .inline{ "v-if" => "model.stop_action" } + %a.btn.stop-env-link{":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id", "method" => ":post", "rel" => "nofollow", "confirm" => "Are you sure you want to stop this environment?"} - = icon('stop', class: 'stop-env-icon') + = icon("stop", class: "stop-env-icon") -- cgit v1.2.1 From a265826e01dec5341521deb029d6d3aa93ffa6d4 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 24 Oct 2016 11:56:54 +0100 Subject: Adds rollback button --- app/views/projects/environments/components/_rollback.html.haml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/views/projects/environments/components/_rollback.html.haml b/app/views/projects/environments/components/_rollback.html.haml index e69de29bb2d..bcc54187b6d 100644 --- a/app/views/projects/environments/components/_rollback.html.haml +++ b/app/views/projects/environments/components/_rollback.html.haml @@ -0,0 +1,10 @@ +- if can?(current_user, :create_deployment, @project) + %a.btn.btn-build{ "v-if" => "model.last_deployment && model.last_deployment.deployable", + ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id + '/retry'", + "data-method" => "post", + "rel" => "nofollow" } + + %span{ "v-if" => "model.last_deployment.last"} + Re-deploy + %span{ "v-if" => "!model.last_deployment.last"} + Rollback -- cgit v1.2.1 From d697b9c86d76603a6eda906572e37ccb049e78cd Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 24 Oct 2016 12:42:01 +0100 Subject: Adds link to actions. Cleans spaces --- .../components/environment_item.js.es6 | 7 ++-- .../environments/stores/environmnets_store.js.es6 | 21 +++++++---- app/assets/stylesheets/pages/environments.scss | 1 - .../projects/environments_controller.rb | 7 ++-- .../environments/components/_actions.html.haml | 6 ++- .../environments/components/_environment.html.haml | 44 +++++++++++----------- .../environments/components/_rollback.html.haml | 4 +- .../environments/components/_stop.html.haml | 3 +- 8 files changed, 51 insertions(+), 42 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 5159d5c4dee..df9f28b1c59 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -29,7 +29,7 @@ open: false }; }, - + computed: { /** @@ -42,7 +42,7 @@ isFolder () { return this.model.children && this.model.children.length ? true : false; }, - + /** * If an item is inside a folder structure will return true. * Used for css purposes. @@ -52,8 +52,7 @@ isChildren () { return this.model['vue-isChildren']; }, - - + /** * Counts the number of environments in each folder. * Used to show a badge with the counter. diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 8b5cb67ed37..35563b0d7fa 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -1,14 +1,14 @@ (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; - + gl.environmentsList.EnvironmentsStore = { state: {}, - + create () { this.state.environments = []; }, - + /** * In order to display a tree view we need to modify the received * data in to a tree structure based on `environment_type` @@ -87,15 +87,22 @@ return environmentsTree; }, - - sortByName (a,b) { + + /** + * Sorts the two objects provided by their name. + * + * @param {Object} a + * @param {Object} b + * @returns {Number} + */ + sortByName (a, b) { const nameA = a.name.toUpperCase(); const nameB = b.name.toUpperCase(); - + if (nameA < nameB) { return -1; } - + if (nameA > nameB) { return 1; } diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index ed0151bb120..2565036eae7 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -86,7 +86,6 @@ } .table.ci-table.environments { - .icon-container { width: 20px; text-align: center; diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 6858b6da3ea..b9e2187bc3b 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -75,11 +75,12 @@ class Projects::EnvironmentsController < Projects::ApplicationController include: { last_deployment: { include: { - user: { only: [:id, :name, :username], methods: [:avatar_url] } + user: { only: [:id, :name, :username], methods: [:avatar_url] }, + deployable: { only: [:id, :name, :ref, :tag] } }, - methods: [:short_sha, :commit_title, :deployable, :commit] + methods: [:short_sha, :commit_title, :commit] }, - project: { methods: [:namespace]} + project: { methods: [:namespace] } } ) end diff --git a/app/views/projects/environments/components/_actions.html.haml b/app/views/projects/environments/components/_actions.html.haml index 50a731475ba..82acda0de9c 100644 --- a/app/views/projects/environments/components/_actions.html.haml +++ b/app/views/projects/environments/components/_actions.html.haml @@ -7,8 +7,10 @@ %ul.dropdown-menu.dropdown-menu-align-right %li{ "v-for" => "action in model.last_deployment.manual_actions" } - -# transform this = link_to [:play, @project.namespace.becomes(Namespace), @project, action] into href - %a{data: {"method" => ":post", "rel" => "nofollow"}} + %a{ ":ref" => "'#{namespace_project_path(@project.namespace, @project)}/' + action.id + '/play'", + "data-method" => "post", + "rel" => "nofollow" } + = custom_icon('icon_play') %span {{action.name}} \ No newline at end of file diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index e479d5ef85b..1aa0d7ac5e2 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -1,62 +1,62 @@ %script#environment-item-template{ "type"=> "text/x-template" } %tr - %td{"v-bind:class" => "{ 'children-row': isChildren}"} + %td{"v-bind:class" => "{ 'children-row': isChildren}" } %a.environment-name{ "v-if" => "!isFolder", ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id" } {{model.name}} - + %span.folder-name{ "v-if" => "isFolder", "@click" => "toggle" } - - %i.folder-icon{ "v-show" => "open"} + + %i.folder-icon{ "v-show" => "open" } =icon ("caret-down") - %i.folder-icon{ "v-show" => "!open"} + %i.folder-icon{ "v-show" => "!open" } =icon("caret-right") - + {{model.name}} - + %span.badge {{childrenCounter}} - + %td.deployment-column - %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid"} + %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid" } = precede "#" do {{model.last_deployment.iid}} - %span{ "v-if" => "model.last_deployment.user"} + %span{ "v-if" => "model.last_deployment.user" } by - %a{":href" => "'/' + model.last_deployment.user.username"} + %a{":href" => "'/' + model.last_deployment.user.username" } %img.avatar.has_tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", ":alt" => "model.last_deployment.user.username + 'avatar'", ":title" => "model.last_deployment.user.username", - data: {container: "body"}, + data: {container: "body" }, width: 20, height: 20} - + %td %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", - ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id"} + ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id" } {{model.last_deployment.deployable.name}} = precede "#" do {{model.last_deployment.deployable.id}} - + %td =render "projects/environments/components/commit" - %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment"} + %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment" } No deployments yet - + %td - %span{ "v-if" => "!isFolder && model.last_deployment"} + %span{ "v-if" => "!isFolder && model.last_deployment" } {{model.last_deployment.created_at}} - + %td.hidden-xs - .pull-right{ "v-if" => "!isFolder"} + .pull-right{ "v-if" => "!isFolder" } =render "projects/environments/components/external_url" =render "projects/environments/components/actions" =render "projects/environments/components/stop" =render "projects/environments/components/rollback" - + %tr{"v-if" => "open && isFolder", "is" => "environment-item", "v-for" => "model in model.children", - ":model" => "model"} + ":model" => "model" } diff --git a/app/views/projects/environments/components/_rollback.html.haml b/app/views/projects/environments/components/_rollback.html.haml index bcc54187b6d..2258f6ec32d 100644 --- a/app/views/projects/environments/components/_rollback.html.haml +++ b/app/views/projects/environments/components/_rollback.html.haml @@ -4,7 +4,7 @@ "data-method" => "post", "rel" => "nofollow" } - %span{ "v-if" => "model.last_deployment.last"} + %span{ "v-if" => "model.last_deployment.last" } Re-deploy - %span{ "v-if" => "!model.last_deployment.last"} + %span{ "v-if" => "!model.last_deployment.last" } Rollback diff --git a/app/views/projects/environments/components/_stop.html.haml b/app/views/projects/environments/components/_stop.html.haml index 741a72704c5..55cccf9e72e 100644 --- a/app/views/projects/environments/components/_stop.html.haml +++ b/app/views/projects/environments/components/_stop.html.haml @@ -2,5 +2,6 @@ .inline{ "v-if" => "model.stop_action" } %a.btn.stop-env-link{":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id", "method" => ":post", - "rel" => "nofollow", "confirm" => "Are you sure you want to stop this environment?"} + "rel" => "nofollow", + "confirm" => "Are you sure you want to stop this environment?"} = icon("stop", class: "stop-env-icon") -- cgit v1.2.1 From 9c41191a002c088ecb269b1e69606000be9be005 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 24 Oct 2016 16:10:58 +0100 Subject: Adds tab behavior to vue component --- .../environments/environments_bundle.js.es6 | 46 +++++++++++++++++++++- .../environments/stores/environmnets_store.js.es6 | 2 +- .../projects/environments_controller.rb | 10 +---- app/views/projects/environments/index.html.haml | 14 +++---- 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 027dc7fb211..4dc4ac2c99b 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -15,6 +15,15 @@ $(() => { gl.EnvironmentsListApp.$destroy(true); } + const filters = { + stopped (environments) { + return environments.filter((env) => env.state === 'stopped') + }, + available (environments) { + return environments.filter((env) => env.state === 'available') + } + }; + gl.EnvironmentsListApp = new Vue({ el: '#environments-list-view', @@ -26,13 +35,33 @@ $(() => { data: { state: Store.state, endpoint: environmentsListApp.dataset.endpoint, - loading: true + loading: true, + visibility: 'available' + }, + + computed: { + filteredEnvironments () { + return filters[this.visibility](this.state.environments); + }, + + countStopped () { + return filters['stopped'](this.state.environments).length; + }, + + counAvailable () { + return filters['available'](this.state.environments).length; + } }, init: Store.create.bind(Store), created() { gl.environmentsService = new EnvironmentsService(this.endpoint); + + const scope = this.$options.getQueryParameter('scope'); + if (scope) { + this.visibility = scope; + } }, /** @@ -45,6 +74,21 @@ $(() => { this.loading = false; }); + }, + + /** + * Transforms the url parameter into an object and + * returns the one requested. + * + * @param {String} param + * @returns {String} The value of the requested parameter. + */ + getQueryParameter(param) { + return window.location.search.substring(1).split('&').reduce((acc, param) => { + acc[param.split('=')[0]] = param.split('=')[1]; + return acc; + }, {})[param]; } + }); }); diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 35563b0d7fa..f48e8d4c49a 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -82,7 +82,7 @@ return acc; }, []).sort(this.sortByName); - + this.state.environments = environmentsTree; return environmentsTree; diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index b9e2187bc3b..42f882b55ab 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -8,14 +8,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController def index @scope = params[:scope] - @all_environments = project.environments - @environments = - if @scope == 'stopped' - @all_environments.stopped - else - @all_environments.available - end - + @environments = project.environments + respond_to do |format| format.html format.json do diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index a8667d88e7b..7cec3fa281c 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -4,28 +4,28 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag("environments/environments_bundle.js") - -%div{ class: container_class } + +#environments-list-view{ data: environments_list_data, class: container_class } .top-area - %ul.nav-links + %ul.nav-links{ "v-if" => "!loading" } %li{class: ('active' if @scope.nil?)} = link_to project_environments_path(@project) do Available %span.badge.js-available-environments-count - = number_with_delimiter(@all_environments.available.count) + {{counAvailable}} %li{class: ('active' if @scope == 'stopped')} = link_to project_environments_path(@project, scope: :stopped) do Stopped %span.badge.js-stopped-environments-count - = number_with_delimiter(@all_environments.stopped.count) + {{countStopped}} - if can?(current_user, :create_environment, @project) && !@all_environments.blank? .nav-controls = link_to new_namespace_project_environment_path(@project.namespace, @project), class: "btn btn-create" do New environment - #environments-list-view{ data: environments_list_data, class: "environments-container" } + .environments-container .environments-list-loading.text-center{ "v-if" => "loading" } = icon("spinner spin") @@ -51,6 +51,6 @@ %th %th.hidden-xs %tbody - %tr{"is" => "environment-item", "v-for" => "model in state.environments", ":model" => "model"} + %tr{"is" => "environment-item", "v-for" => "model in filteredEnvironments", ":model" => "model"} =render "projects/environments/components/environment" -- cgit v1.2.1 From 98a0f72dd3717c0177271583a19973ce463b5191 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 24 Oct 2016 16:56:13 +0100 Subject: Properly filter all environments --- .../environments/environments_bundle.js.es6 | 27 +++++++++++----------- .../environments/stores/environmnets_store.js.es6 | 1 + 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 4dc4ac2c99b..f8cefabefa4 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -15,19 +15,20 @@ $(() => { gl.EnvironmentsListApp.$destroy(true); } - const filters = { - stopped (environments) { - return environments.filter((env) => env.state === 'stopped') - }, - available (environments) { - return environments.filter((env) => env.state === 'available') - } + const filterEnvironments = (environments = [], filter = "") => { + return environments.filter((env) => { + if (env.children) { + return env.children.filter((child) => child.state === filter).length; + } else { + return env.state === filter; + }; + }); }; gl.EnvironmentsListApp = new Vue({ el: '#environments-list-view', - + components: { 'item': gl.environmentsList.EnvironmentItem }, @@ -41,15 +42,15 @@ $(() => { computed: { filteredEnvironments () { - return filters[this.visibility](this.state.environments); + return filterEnvironments(this.state.environments, this.visibility); }, - + countStopped () { - return filters['stopped'](this.state.environments).length; + return filterEnvironments(this.state.environments, 'stopped').length; }, - + counAvailable () { - return filters['available'](this.state.environments).length; + return filterEnvironments(this.state.environments, 'available').length; } }, diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index f48e8d4c49a..72267b97255 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -63,6 +63,7 @@ return element.environment_type === environment.environment_type; }); + data["vue-isChildren"] = true; if (occurs !== undefined) { -- cgit v1.2.1 From 32c727cb9b8f0d8dc6de349482d49f81d8067656 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 25 Oct 2016 10:08:01 +0100 Subject: Fix typo --- app/assets/javascripts/environments/environments_bundle.js.es6 | 8 ++++---- .../javascripts/environments/stores/environmnets_store.js.es6 | 2 +- app/views/projects/environments/index.html.haml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index f8cefabefa4..4c1fea0d6c6 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -24,7 +24,7 @@ $(() => { }; }); }; - + gl.EnvironmentsListApp = new Vue({ el: '#environments-list-view', @@ -49,7 +49,7 @@ $(() => { return filterEnvironments(this.state.environments, 'stopped').length; }, - counAvailable () { + countAvailable () { return filterEnvironments(this.state.environments, 'available').length; } }, @@ -86,10 +86,10 @@ $(() => { */ getQueryParameter(param) { return window.location.search.substring(1).split('&').reduce((acc, param) => { - acc[param.split('=')[0]] = param.split('=')[1]; + const paramSplited = param.split('='); + acc[paramSplited[0]] = paramSplited[1]; return acc; }, {})[param]; } - }); }); diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 72267b97255..9442a1ee1de 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -41,7 +41,7 @@ * @param {Array} environments List of environments. * @returns {Array} Tree structured array with the received environments. */ - storeEnvironments(environments) { + storeEnvironments(environments = []) { const environmentsTree = environments.reduce((acc, environment) => { const data = Object.assign({}, environment); diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 7cec3fa281c..3538777d11c 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -12,7 +12,7 @@ = link_to project_environments_path(@project) do Available %span.badge.js-available-environments-count - {{counAvailable}} + {{countAvailable}} %li{class: ('active' if @scope == 'stopped')} = link_to project_environments_path(@project, scope: :stopped) do @@ -41,7 +41,7 @@ = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - .table-holder{ "v-if" => "!loading && state.environments" } + .table-holder{ "v-if" => "!loading && state.environments.length" } %table.table.ci-table.environments %thead %th Environment -- cgit v1.2.1 From cd476336d9c8f07c5a70fb05f646727965139706 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 25 Oct 2016 13:50:27 +0100 Subject: tests --- .../environments/environments_bundle.js.es6 | 3 + app/views/projects/environments/index.html.haml | 2 +- spec/features/environments_spec.rb | 484 +++++++++++---------- 3 files changed, 263 insertions(+), 226 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 4c1fea0d6c6..0ab3afb405c 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -3,6 +3,7 @@ //= require_tree ./stores //= require_tree ./services //= require ./components/environment_item +//= require ../boards/vue_resource_interceptor $(() => { @@ -72,6 +73,8 @@ $(() => { ready() { gl.environmentsService.all().then((resp) => { Store.storeEnvironments(resp.json()); + + console.log("HELLLLOOOOOOOOOOOOOO", resp.json()) this.loading = false; }); diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 3538777d11c..5b9fedb956f 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -41,7 +41,7 @@ = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - .table-holder{ "v-if" => "!loading && state.environments.length" } + .table-holder{ "v-if" => "!loading && state.environments" } %table.table.ci-table.environments %thead %th Environment diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index b565586ee14..c8ea4bb3945 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -1,7 +1,10 @@ require 'spec_helper' +require 'rails_helper' -feature 'Environments', feature: true do - given(:project) { create(:empty_project) } +feature 'Environments', feature: true, js:true do + include WaitForVueResource + + given(:project) { create(:project) } given(:user) { create(:user) } given(:role) { :developer } @@ -15,18 +18,17 @@ feature 'Environments', feature: true do given!(:deployment) { } given!(:manual) { } - before do - visit namespace_project_environments_path(project.namespace, project) - end - - context 'shows two tabs' do - scenario 'shows "Available" and "Stopped" tab with links' do + context 'without environments' do + before do + visit namespace_project_environments_path(project.namespace, project) + wait_for_vue_resource + end + + scenario 'does show "Available" and "Stopped" tab with links' do expect(page).to have_link('Available') expect(page).to have_link('Stopped') end - end - context 'without environments' do scenario 'does show no environments' do expect(page).to have_content('You don\'t have any environments right now.') end @@ -36,239 +38,271 @@ feature 'Environments', feature: true do expect(page.find('.js-stopped-environments-count').text).to eq('0') end end - - context 'with environments' do + + context 'loading environments' do given(:environment) { create(:environment, project: project) } + + before do + visit namespace_project_environments_path(project.namespace, project) + wait_for_vue_resource + end - scenario 'does show environment name' do - expect(page).to have_link(environment.name) + scenario 'does show loading spinner' do + expect(page).to have_selector('.environments-list-loading') end + end + context 'with environments' do + let(:environment1) { create(:environment, project: project) } + let(:environment2) { create(:environment, project: project) } + + before do + visit namespace_project_environments_path(project.namespace, project) + wait_for_vue_resource + expect(page).to have_selector('.table.ci-table.environments') + end + + scenario 'does show "Available" and "Stopped" tab with links' do + expect(page).to have_link('Stopped') + expect(page).to have_link('Available') + end + + scenario 'does show environment name' do + expect(page).to have_link(environment1.name) + end + scenario 'does show number of available and stopped environments' do expect(page.find('.js-available-environments-count').text).to eq('1') expect(page.find('.js-stopped-environments-count').text).to eq('0') end - + context 'without deployments' do scenario 'does show no deployments' do expect(page).to have_content('No deployments yet') end end - context 'with deployments' do - given(:deployment) { create(:deployment, environment: environment) } - - scenario 'does show deployment SHA' do - expect(page).to have_link(deployment.short_sha) - end - - scenario 'does show deployment internal id' do - expect(page).to have_content(deployment.iid) - end - - context 'with build and manual actions' do - given(:pipeline) { create(:ci_pipeline, project: project) } - given(:build) { create(:ci_build, pipeline: pipeline) } - given(:deployment) { create(:deployment, environment: environment, deployable: build) } - given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } - - scenario 'does show a play button' do - expect(page).to have_link(manual.name.humanize) - end - - scenario 'does allow to play manual action' do - expect(manual).to be_skipped - expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } - expect(page).to have_content(manual.name) - expect(manual.reload).to be_pending - end - - scenario 'does show build name and id' do - expect(page).to have_link("#{build.name} (##{build.id})") - end - - scenario 'does not show stop button' do - expect(page).not_to have_selector('.stop-env-link') - end - - scenario 'does not show external link button' do - expect(page).not_to have_css('external-url') - end - - context 'with external_url' do - given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } - given(:build) { create(:ci_build, pipeline: pipeline) } - given(:deployment) { create(:deployment, environment: environment, deployable: build) } - - scenario 'does show an external link button' do - expect(page).to have_link(nil, href: environment.external_url) - end - end - - context 'with stop action' do - given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } - given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - - scenario 'does show stop button' do - expect(page).to have_selector('.stop-env-link') - end - - scenario 'starts build when stop button clicked' do - first('.stop-env-link').click - - expect(page).to have_content('close_app') - end - - context 'for reporter' do - let(:role) { :reporter } - - scenario 'does not show stop button' do - expect(page).not_to have_selector('.stop-env-link') - end - end - end - end - end - end - - scenario 'does have a New environment button' do - expect(page).to have_link('New environment') + # context 'with deployments' do + # given(:deployment) { create(:deployment, environment: environment) } + # + # scenario 'does show deployment SHA' do + # expect(page).to have_link(deployment.short_sha) + # end + # + # scenario 'does show deployment internal id' do + # expect(page).to have_content(deployment.iid) + # end + # + # context 'with build and manual actions' do + # given(:pipeline) { create(:ci_pipeline, project: project) } + # given(:build) { create(:ci_build, pipeline: pipeline) } + # given(:deployment) { create(:deployment, environment: environment, deployable: build) } + # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } + # + # scenario 'does show a play button' do + # expect(page).to have_link(manual.name.humanize) + # end + # + # scenario 'does allow to play manual action' do + # expect(manual).to be_skipped + # expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } + # expect(page).to have_content(manual.name) + # expect(manual.reload).to be_pending + # end + # + # scenario 'does show build name and id' do + # expect(page).to have_link("#{build.name} (##{build.id})") + # end + # + # scenario 'does not show stop button' do + # expect(page).not_to have_selector('.stop-env-link') + # end + # + # scenario 'does not show external link button' do + # expect(page).not_to have_css('external-url') + # end + # + # # context 'with external_url' do + # given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } + # given(:build) { create(:ci_build, pipeline: pipeline) } + # given(:deployment) { create(:deployment, environment: environment, deployable: build) } + # + # scenario 'does show an external link button' do + # expect(page).to have_link(nil, href: environment.external_url) + # end + # end + # + # # context 'with stop action' do + # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } + # given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } + # + # scenario 'does show stop button' do + # expect(page).to have_selector('.stop-env-link') + # end + # + # scenario 'starts build when stop button clicked' do + # first('.stop-env-link').click + # + # expect(page).to have_content('close_app') + # end + # + # context 'for reporter' do + # let(:role) { :reporter } + # + # scenario 'does not show stop button' do + # expect(page).not_to have_selector('.stop-env-link') + # end + # end + # end + # end + # end end - end - - describe 'when showing the environment' do - given(:environment) { create(:environment, project: project) } - given!(:deployment) { } - given!(:manual) { } - - before do - visit namespace_project_environment_path(project.namespace, project, environment) - end - - context 'without deployments' do - scenario 'does show no deployments' do - expect(page).to have_content('You don\'t have any deployments right now.') - end - end - - context 'with deployments' do - given(:deployment) { create(:deployment, environment: environment) } - - scenario 'does show deployment SHA' do - expect(page).to have_link(deployment.short_sha) - end - - scenario 'does not show a re-deploy button for deployment without build' do - expect(page).not_to have_link('Re-deploy') - end - - context 'with build' do - given(:pipeline) { create(:ci_pipeline, project: project) } - given(:build) { create(:ci_build, pipeline: pipeline) } - given(:deployment) { create(:deployment, environment: environment, deployable: build) } - - scenario 'does show build name' do - expect(page).to have_link("#{build.name} (##{build.id})") - end - - scenario 'does show re-deploy button' do - expect(page).to have_link('Re-deploy') - end - - scenario 'does not show stop button' do - expect(page).not_to have_link('Stop') - end - - context 'with manual action' do - given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } - - scenario 'does show a play button' do - expect(page).to have_link(manual.name.humanize) - end - - scenario 'does allow to play manual action' do - expect(manual).to be_skipped - expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } - expect(page).to have_content(manual.name) - expect(manual.reload).to be_pending - end - - context 'with external_url' do - given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } - given(:build) { create(:ci_build, pipeline: pipeline) } - given(:deployment) { create(:deployment, environment: environment, deployable: build) } - - scenario 'does show an external link button' do - expect(page).to have_link(nil, href: environment.external_url) - end - end - - context 'with stop action' do - given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } - given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - - scenario 'does show stop button' do - expect(page).to have_link('Stop') - end - - scenario 'does allow to stop environment' do - click_link('Stop') - - expect(page).to have_content('close_app') - end - - context 'for reporter' do - let(:role) { :reporter } - - scenario 'does not show stop button' do - expect(page).not_to have_link('Stop') - end - end - end - end - end - end - end - - describe 'when creating a new environment' do - before do - visit namespace_project_environments_path(project.namespace, project) - end - - context 'when logged as developer' do + + context 'can create new environment' do before do - click_link 'New environment' - end - - context 'for valid name' do - before do - fill_in('Name', with: 'production') - click_on 'Save' - end - - scenario 'does create a new pipeline' do - expect(page).to have_content('Production') - end - end - - context 'for invalid name' do - before do - fill_in('Name', with: 'name,with,commas') - click_on 'Save' - end - - scenario 'does show errors' do - expect(page).to have_content('Name can contain only letters') - end + visit namespace_project_environments_path(project.namespace, project) + wait_for_vue_resource end - end - - context 'when logged as reporter' do - given(:role) { :reporter } - - scenario 'does not have a New environment link' do - expect(page).not_to have_link('New environment') + + scenario 'does have a New environment button' do + expect(page).to have_link('New environment') end end end + + # describe 'when showing the environment' do + # given(:environment) { create(:environment, project: project) } + # given!(:deployment) { } + # given!(:manual) { } + # + # before do + # visit namespace_project_environment_path(project.namespace, project, environment) + # end + # + # context 'without deployments' do + # scenario 'does show no deployments' do + # expect(page).to have_content('You don\'t have any deployments right now.') + # end + # end + # + # context 'with deployments' do + # given(:deployment) { create(:deployment, environment: environment) } + # + # scenario 'does show deployment SHA' do + # expect(page).to have_link(deployment.short_sha) + # end + # + # scenario 'does not show a re-deploy button for deployment without build' do + # expect(page).not_to have_link('Re-deploy') + # end + # + # context 'with build' do + # given(:pipeline) { create(:ci_pipeline, project: project) } + # given(:build) { create(:ci_build, pipeline: pipeline) } + # given(:deployment) { create(:deployment, environment: environment, deployable: build) } + # + # scenario 'does show build name' do + # expect(page).to have_link("#{build.name} (##{build.id})") + # end + # + # scenario 'does show re-deploy button' do + # expect(page).to have_link('Re-deploy') + # end + # + # scenario 'does not show stop button' do + # expect(page).not_to have_link('Stop') + # end + # + # context 'with manual action' do + # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } + # + # scenario 'does show a play button' do + # expect(page).to have_link(manual.name.humanize) + # end + # + # scenario 'does allow to play manual action' do + # expect(manual).to be_skipped + # expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } + # expect(page).to have_content(manual.name) + # expect(manual.reload).to be_pending + # end + # + # context 'with external_url' do + # given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } + # given(:build) { create(:ci_build, pipeline: pipeline) } + # given(:deployment) { create(:deployment, environment: environment, deployable: build) } + # + # scenario 'does show an external link button' do + # expect(page).to have_link(nil, href: environment.external_url) + # end + # end + # + # context 'with stop action' do + # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } + # given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } + # + # scenario 'does show stop button' do + # expect(page).to have_link('Stop') + # end + # + # scenario 'does allow to stop environment' do + # click_link('Stop') + # + # expect(page).to have_content('close_app') + # end + # + # context 'for reporter' do + # let(:role) { :reporter } + # + # scenario 'does not show stop button' do + # expect(page).not_to have_link('Stop') + # end + # end + # end + # end + # end + # end + # end + + # describe 'when creating a new environment' do + # before do + # visit namespace_project_environments_path(project.namespace, project) + # end + # + # context 'when logged as developer' do + # before do + # click_link 'New environment' + # end + # + # context 'for valid name' do + # before do + # fill_in('Name', with: 'production') + # click_on 'Save' + # end + # + # scenario 'does create a new pipeline' do + # expect(page).to have_content('Production') + # end + # end + # + # context 'for invalid name' do + # before do + # fill_in('Name', with: 'name,with,commas') + # click_on 'Save' + # end + # + # scenario 'does show errors' do + # expect(page).to have_content('Name can contain only letters') + # end + # end + # end + # + # context 'when logged as reporter' do + # given(:role) { :reporter } + # + # scenario 'does not have a New environment link' do + # expect(page).not_to have_link('New environment') + # end + # end + # end end -- cgit v1.2.1 From 1906a32bc03179aa15777073de0ff20547bc7f6a Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 25 Oct 2016 14:55:57 +0100 Subject: Fix SCSS lint errors Fixes some tests --- .../environments/environments_bundle.js.es6 | 3 - .../environments/stores/environmnets_store.js.es6 | 21 +- app/assets/stylesheets/pages/environments.scss | 8 +- app/views/projects/environments/index.html.haml | 2 +- spec/features/environments_spec.rb | 473 +++++++++++---------- 5 files changed, 252 insertions(+), 255 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 0ab3afb405c..3382e7a4b29 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -73,9 +73,6 @@ $(() => { ready() { gl.environmentsService.all().then((resp) => { Store.storeEnvironments(resp.json()); - - console.log("HELLLLOOOOOOOOOOOOOO", resp.json()) - this.loading = false; }); }, diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 9442a1ee1de..9416b944b4d 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -43,17 +43,16 @@ */ storeEnvironments(environments = []) { const environmentsTree = environments.reduce((acc, environment) => { - const data = Object.assign({}, environment); - - if (data.last_deployment) { + + if (environment.last_deployment) { //humanizes actions names if there are any actions - if (data.last_deployment.manual_actions) { - data.last_deployment.manual_actions = data.last_deployment.manual_actions.map((action) => Object.assign({}, action, {name: gl.text.humanize(action.name)})); + if (environment.last_deployment.manual_actions) { + environment.last_deployment.manual_actions = environment.last_deployment.manual_actions.map((action) => Object.assign({}, action, {name: gl.text.humanize(action.name)})); } //transforms created date for deployment in a human readable format - if (data.last_deployment.created_at) { + if (environment.last_deployment.created_at) { // TODO - how to do this without jquery } } @@ -64,21 +63,21 @@ }); - data["vue-isChildren"] = true; + environment["vue-isChildren"] = true; if (occurs !== undefined) { - acc[acc.indexOf(occurs)].children.push(data); - acc[acc.indexOf(occurs)].children.push(data).sort(this.sortByName) + acc[acc.indexOf(occurs)].children.push(environment); + acc[acc.indexOf(occurs)].children.push(environment).sort(this.sortByName) } else { acc.push({ name: environment.environment_type, children: [ - Object.assign(data) + Object.assign(environment) ] }); } } else { - acc.push(data); + acc.push(environment); } return acc; diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 2565036eae7..9d47e96bb69 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -63,19 +63,19 @@ } } } - + .children-row .environment-name { margin-left: 17px; margin-right: -17px; } - + .folder-icon { padding: 0 5px 0 0; } - + .folder-name { cursor: pointer; - + .badge { font-weight: normal; background-color: $gray-darker; diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 5b9fedb956f..3538777d11c 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -41,7 +41,7 @@ = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - .table-holder{ "v-if" => "!loading && state.environments" } + .table-holder{ "v-if" => "!loading && state.environments.length" } %table.table.ci-table.environments %thead %th Environment diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index c8ea4bb3945..62fc56f2f46 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -12,18 +12,32 @@ feature 'Environments', feature: true, js:true do login_as(user) project.team << [user, role] end - - describe 'when showing environments' do + + describe 'Loading environments' do given!(:environment) { } given!(:deployment) { } given!(:manual) { } - context 'without environments' do + context 'loading environments' do before do visit namespace_project_environments_path(project.namespace, project) - wait_for_vue_resource end - + + scenario 'does show loading spinner' do + expect(page).to have_selector('.environments-list-loading') + end + end + end + + describe 'when showing environments' do + + before do + visit namespace_project_environments_path(project.namespace, project) + wait_for_vue_resource + end + + context 'without environments' do + scenario 'does show "Available" and "Stopped" tab with links' do expect(page).to have_link('Available') expect(page).to have_link('Stopped') @@ -38,37 +52,17 @@ feature 'Environments', feature: true, js:true do expect(page.find('.js-stopped-environments-count').text).to eq('0') end end - - context 'loading environments' do - given(:environment) { create(:environment, project: project) } - - before do - visit namespace_project_environments_path(project.namespace, project) - wait_for_vue_resource - end - - scenario 'does show loading spinner' do - expect(page).to have_selector('.environments-list-loading') - end - end context 'with environments' do - let(:environment1) { create(:environment, project: project) } - let(:environment2) { create(:environment, project: project) } - - before do - visit namespace_project_environments_path(project.namespace, project) - wait_for_vue_resource - expect(page).to have_selector('.table.ci-table.environments') - end - + given!(:environment) { create(:environment, project: project) } + scenario 'does show "Available" and "Stopped" tab with links' do expect(page).to have_link('Stopped') expect(page).to have_link('Available') end scenario 'does show environment name' do - expect(page).to have_link(environment1.name) + expect(page).to have_link(environment.name) end scenario 'does show number of available and stopped environments' do @@ -77,85 +71,92 @@ feature 'Environments', feature: true, js:true do end context 'without deployments' do + + before do + visit namespace_project_environments_path(project.namespace, project) + wait_for_vue_resource + end + scenario 'does show no deployments' do expect(page).to have_content('No deployments yet') end end - # context 'with deployments' do - # given(:deployment) { create(:deployment, environment: environment) } - # - # scenario 'does show deployment SHA' do - # expect(page).to have_link(deployment.short_sha) - # end - # - # scenario 'does show deployment internal id' do - # expect(page).to have_content(deployment.iid) - # end - # - # context 'with build and manual actions' do - # given(:pipeline) { create(:ci_pipeline, project: project) } - # given(:build) { create(:ci_build, pipeline: pipeline) } - # given(:deployment) { create(:deployment, environment: environment, deployable: build) } - # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } - # - # scenario 'does show a play button' do - # expect(page).to have_link(manual.name.humanize) - # end - # - # scenario 'does allow to play manual action' do - # expect(manual).to be_skipped - # expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } - # expect(page).to have_content(manual.name) - # expect(manual.reload).to be_pending - # end - # - # scenario 'does show build name and id' do - # expect(page).to have_link("#{build.name} (##{build.id})") - # end - # - # scenario 'does not show stop button' do - # expect(page).not_to have_selector('.stop-env-link') - # end - # - # scenario 'does not show external link button' do - # expect(page).not_to have_css('external-url') - # end - # - # # context 'with external_url' do - # given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } - # given(:build) { create(:ci_build, pipeline: pipeline) } - # given(:deployment) { create(:deployment, environment: environment, deployable: build) } - # - # scenario 'does show an external link button' do - # expect(page).to have_link(nil, href: environment.external_url) - # end - # end - # - # # context 'with stop action' do - # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } - # given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - # - # scenario 'does show stop button' do - # expect(page).to have_selector('.stop-env-link') - # end - # - # scenario 'starts build when stop button clicked' do - # first('.stop-env-link').click - # - # expect(page).to have_content('close_app') - # end - # - # context 'for reporter' do - # let(:role) { :reporter } - # - # scenario 'does not show stop button' do - # expect(page).not_to have_selector('.stop-env-link') - # end - # end - # end - # end - # end + context 'with deployments' do + let!(:environment) { create(:environment, project: project) } + given(:deployment) { create(:deployment, environment: environment) } + + scenario 'does show deployment SHA' do + expect(page).to have_link(deployment.short_sha) + end + + scenario 'does show deployment internal id' do + expect(page).to have_content(deployment.iid) + end + + context 'with build and manual actions' do + given(:pipeline) { create(:ci_pipeline, project: project) } + given(:build) { create(:ci_build, pipeline: pipeline) } + given(:deployment) { create(:deployment, environment: environment, deployable: build) } + given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } + + scenario 'does show a play button' do + expect(page).to have_link(manual.name.humanize) + end + + scenario 'does allow to play manual action' do + expect(manual).to be_skipped + expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } + expect(page).to have_content(manual.name) + expect(manual.reload).to be_pending + end + + scenario 'does show build name and id' do + expect(page).to have_link("#{build.name} (##{build.id})") + end + + scenario 'does not show stop button' do + expect(page).not_to have_selector('.stop-env-link') + end + + scenario 'does not show external link button' do + expect(page).not_to have_css('external-url') + end + + context 'with external_url' do + given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } + given(:build) { create(:ci_build, pipeline: pipeline) } + given(:deployment) { create(:deployment, environment: environment, deployable: build) } + + scenario 'does show an external link button' do + expect(page).to have_link(nil, href: environment.external_url) + end + end + + context 'with stop action' do + given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } + given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } + + scenario 'does show stop button' do + expect(page).to have_selector('.stop-env-link') + end + + scenario 'starts build when stop button clicked' do + first('.stop-env-link').click + + expect(page).to have_content('close_app') + end + + context 'for reporter' do + let(:role) { :reporter } + + scenario 'does not show stop button' do + expect(page).not_to have_selector('.stop-env-link') + end + end + end + end + end end context 'can create new environment' do @@ -170,139 +171,139 @@ feature 'Environments', feature: true, js:true do end end - # describe 'when showing the environment' do - # given(:environment) { create(:environment, project: project) } - # given!(:deployment) { } - # given!(:manual) { } - # - # before do - # visit namespace_project_environment_path(project.namespace, project, environment) - # end - # - # context 'without deployments' do - # scenario 'does show no deployments' do - # expect(page).to have_content('You don\'t have any deployments right now.') - # end - # end - # - # context 'with deployments' do - # given(:deployment) { create(:deployment, environment: environment) } - # - # scenario 'does show deployment SHA' do - # expect(page).to have_link(deployment.short_sha) - # end - # - # scenario 'does not show a re-deploy button for deployment without build' do - # expect(page).not_to have_link('Re-deploy') - # end - # - # context 'with build' do - # given(:pipeline) { create(:ci_pipeline, project: project) } - # given(:build) { create(:ci_build, pipeline: pipeline) } - # given(:deployment) { create(:deployment, environment: environment, deployable: build) } - # - # scenario 'does show build name' do - # expect(page).to have_link("#{build.name} (##{build.id})") - # end - # - # scenario 'does show re-deploy button' do - # expect(page).to have_link('Re-deploy') - # end - # - # scenario 'does not show stop button' do - # expect(page).not_to have_link('Stop') - # end - # - # context 'with manual action' do - # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } - # - # scenario 'does show a play button' do - # expect(page).to have_link(manual.name.humanize) - # end - # - # scenario 'does allow to play manual action' do - # expect(manual).to be_skipped - # expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } - # expect(page).to have_content(manual.name) - # expect(manual.reload).to be_pending - # end - # - # context 'with external_url' do - # given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } - # given(:build) { create(:ci_build, pipeline: pipeline) } - # given(:deployment) { create(:deployment, environment: environment, deployable: build) } - # - # scenario 'does show an external link button' do - # expect(page).to have_link(nil, href: environment.external_url) - # end - # end - # - # context 'with stop action' do - # given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } - # given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - # - # scenario 'does show stop button' do - # expect(page).to have_link('Stop') - # end - # - # scenario 'does allow to stop environment' do - # click_link('Stop') - # - # expect(page).to have_content('close_app') - # end - # - # context 'for reporter' do - # let(:role) { :reporter } - # - # scenario 'does not show stop button' do - # expect(page).not_to have_link('Stop') - # end - # end - # end - # end - # end - # end - # end + describe 'when showing the environment' do + given(:environment) { create(:environment, project: project) } + given!(:deployment) { } + given!(:manual) { } + + before do + visit namespace_project_environment_path(project.namespace, project, environment) + end + + context 'without deployments' do + scenario 'does show no deployments' do + expect(page).to have_content('You don\'t have any deployments right now.') + end + end + + context 'with deployments' do + given(:deployment) { create(:deployment, environment: environment) } + + scenario 'does show deployment SHA' do + expect(page).to have_link(deployment.short_sha) + end + + scenario 'does not show a re-deploy button for deployment without build' do + expect(page).not_to have_link('Re-deploy') + end + + context 'with build' do + given(:pipeline) { create(:ci_pipeline, project: project) } + given(:build) { create(:ci_build, pipeline: pipeline) } + given(:deployment) { create(:deployment, environment: environment, deployable: build) } + + scenario 'does show build name' do + expect(page).to have_link("#{build.name} (##{build.id})") + end + + scenario 'does show re-deploy button' do + expect(page).to have_link('Re-deploy') + end + + scenario 'does not show stop button' do + expect(page).not_to have_link('Stop') + end + + context 'with manual action' do + given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } + + scenario 'does show a play button' do + expect(page).to have_link(manual.name.humanize) + end + + scenario 'does allow to play manual action' do + expect(manual).to be_skipped + expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } + expect(page).to have_content(manual.name) + expect(manual.reload).to be_pending + end + + context 'with external_url' do + given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } + given(:build) { create(:ci_build, pipeline: pipeline) } + given(:deployment) { create(:deployment, environment: environment, deployable: build) } + + scenario 'does show an external link button' do + expect(page).to have_link(nil, href: environment.external_url) + end + end + + context 'with stop action' do + given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } + given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } + + scenario 'does show stop button' do + expect(page).to have_link('Stop') + end + + scenario 'does allow to stop environment' do + click_link('Stop') + + expect(page).to have_content('close_app') + end + + context 'for reporter' do + let(:role) { :reporter } + + scenario 'does not show stop button' do + expect(page).not_to have_link('Stop') + end + end + end + end + end + end + end - # describe 'when creating a new environment' do - # before do - # visit namespace_project_environments_path(project.namespace, project) - # end - # - # context 'when logged as developer' do - # before do - # click_link 'New environment' - # end - # - # context 'for valid name' do - # before do - # fill_in('Name', with: 'production') - # click_on 'Save' - # end - # - # scenario 'does create a new pipeline' do - # expect(page).to have_content('Production') - # end - # end - # - # context 'for invalid name' do - # before do - # fill_in('Name', with: 'name,with,commas') - # click_on 'Save' - # end - # - # scenario 'does show errors' do - # expect(page).to have_content('Name can contain only letters') - # end - # end - # end - # - # context 'when logged as reporter' do - # given(:role) { :reporter } - # - # scenario 'does not have a New environment link' do - # expect(page).not_to have_link('New environment') - # end - # end - # end + describe 'when creating a new environment' do + before do + visit namespace_project_environments_path(project.namespace, project) + end + + context 'when logged as developer' do + before do + click_link 'New environment' + end + + context 'for valid name' do + before do + fill_in('Name', with: 'production') + click_on 'Save' + end + + scenario 'does create a new pipeline' do + expect(page).to have_content('Production') + end + end + + context 'for invalid name' do + before do + fill_in('Name', with: 'name,with,commas') + click_on 'Save' + end + + scenario 'does show errors' do + expect(page).to have_content('Name can contain only letters') + end + end + end + + context 'when logged as reporter' do + given(:role) { :reporter } + + scenario 'does not have a New environment link' do + expect(page).not_to have_link('New environment') + end + end + end end -- cgit v1.2.1 From 9a7fa3b6d38f6ac9dbdfef793d66cb6d21c6431e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 25 Oct 2016 15:14:08 +0100 Subject: Adds tests for environments store --- .../environments/environments_store_spec.js.es6 | 19 ++++++ spec/javascripts/environments/mock_data.js.es6 | 77 ++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 spec/javascripts/environments/environments_store_spec.js.es6 create mode 100644 spec/javascripts/environments/mock_data.js.es6 diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 new file mode 100644 index 00000000000..19c71305aa6 --- /dev/null +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -0,0 +1,19 @@ +//= require vue +//= require vue-resource +//= require lib/utils/url_utility +//= require ./mock_data +// + +(() => { + beforeEach(() => { + gl.environmentsService = new EnvironmentsService('test/environments'); + gl.environmentsList.EnvironmentsStore.create(); + }); + + describe('Store', () => { + it('starts with a blank state', () => { + expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(0); + }); + + }); +})(); diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 new file mode 100644 index 00000000000..8d12965332e --- /dev/null +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -0,0 +1,77 @@ +const environmentsList = [ + { + "id": 15, + "project_id": 11, + "name": "production", + "created_at": "2016-10-18T10:47:46.840Z", + "updated_at": "2016-10-19T15:49:24.378Z", + "external_url": "https://test.com", + "environment_type": null, + "state": "available", + "last_deployment": { + "id": 57, + "iid": 5, + "project_id": 11, + "environment_id": 15, + "ref": "master", + "tag": false, + "sha": "edf8704ba6cea79be4634b82927e9ff534068428", + "user_id": 1, + "deployable_id": 1170, + "deployable_type": "CommitStatus", + "on_stop": null, + "short_sha": "edf8704b", + "commit_title": "Update .gitlab-ci.yml", + "commit": { + "id": "edf8704ba6cea79be4634b82927e9ff534068428", + "message": "Update .gitlab-ci.yml", + "parent_ids": ["f215999006bd3d5c89b9b1e8c0873c9aca0f913a"], + "authored_date": "2016-10-19T16:49:09.000+01:00", + "author_name": "Administrator", + "author_email": "admin@example.com", + "committed_date": "2016-10-19T16:49:09.000+01:00", + "committer_name": "Administrator", + "committer_email": "admin@example.com" + }, + "user": { + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon" + }, + "deployable": { + "id": 1170, + "name": "deploy", + "tag": false, + "ref": "master" + } + }, + "project": { + "id": 11, + "name": "review-apps", + "path": "review-apps", + "namespace_id": 1, + "namespace": { + "id": 1, + "name": "root" + } + } + },{ + "id": 18, + "project_id": 11, + "name": "review/test-environment", + "created_at": "2016-10-19T14:59:59.303Z", + "updated_at": "2016-10-19T14:59:59.303Z", + "external_url": "http://test1.com", + "environment_type": "review", + "state": "available", + "project": { + "id": 11, + "name": "review-apps", + "namespace": { + "id": 1, + "name": "root" + } + } + } +]; \ No newline at end of file -- cgit v1.2.1 From a2dbdb88be6fdd363d42f925c2792adb2e4756ab Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 25 Oct 2016 21:00:56 +0100 Subject: Fix tab filtering and counting --- .../environments/environments_bundle.js.es6 | 29 ++++++++++++++-------- .../environments/stores/environmnets_store.js.es6 | 25 ++++++++++++++++--- app/views/projects/environments/index.html.haml | 4 +-- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 3382e7a4b29..59c0dcfe1c2 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -16,14 +16,21 @@ $(() => { gl.EnvironmentsListApp.$destroy(true); } - const filterEnvironments = (environments = [], filter = "") => { - return environments.filter((env) => { - if (env.children) { - return env.children.filter((child) => child.state === filter).length; - } else { - return env.state === filter; - }; - }); + + const filterState = (state) => (environment) => environment.state === state && environment; + + // recursiveMap :: (Function, Array) -> Array + const recursiveMap = (fn, arr) => { + return arr.map((item) => { + if (!item.children) { return fn(item); } + + const filteredChildren = recursiveMap(fn, item.children).filter(Boolean); + if (filteredChildren.length) { + item.children = filteredChildren; + return item; + } + + }).filter(Boolean); }; gl.EnvironmentsListApp = new Vue({ @@ -43,15 +50,15 @@ $(() => { computed: { filteredEnvironments () { - return filterEnvironments(this.state.environments, this.visibility); + return recursiveMap(filterState(this.visibility), this.state.environments); }, countStopped () { - return filterEnvironments(this.state.environments, 'stopped').length; + }, countAvailable () { - return filterEnvironments(this.state.environments, 'available').length; + // return recursiveMap(filterState('available'), this.state.environments).length; } }, diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 9416b944b4d..de51d94d2b5 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -7,6 +7,8 @@ create () { this.state.environments = []; + this.state.stoppedCounter = 0; + this.state.availableCounter = 0; }, /** @@ -42,6 +44,10 @@ * @returns {Array} Tree structured array with the received environments. */ storeEnvironments(environments = []) { + + this.state.stoppedCounter = this.countByState(environments, 'stopped'); + this.state.availableCounter = this.countByState(environments, 'available'); + const environmentsTree = environments.reduce((acc, environment) => { if (environment.last_deployment) { @@ -59,15 +65,14 @@ if (environment.environment_type !== null) { const occurs = acc.find((element, index, array) => { - return element.environment_type === environment.environment_type; + return element.children && element.name === environment.environment_type; }); - - + environment["vue-isChildren"] = true; if (occurs !== undefined) { acc[acc.indexOf(occurs)].children.push(environment); - acc[acc.indexOf(occurs)].children.push(environment).sort(this.sortByName) + acc[acc.indexOf(occurs)].children.sort(this.sortByName) } else { acc.push({ name: environment.environment_type, @@ -88,6 +93,18 @@ return environmentsTree; }, + /** + * Given an array of environments, returns the number of environments + * that have the given state. + * + * @param {Array} environments + * @param {String} state + * @returns {Number} + */ + countByState(environments, state) { + return environments.filter((env) => env.state === state).length; + }, + /** * Sorts the two objects provided by their name. * diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 3538777d11c..81c8fd9d9db 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -12,13 +12,13 @@ = link_to project_environments_path(@project) do Available %span.badge.js-available-environments-count - {{countAvailable}} + {{state.availableCounter}} %li{class: ('active' if @scope == 'stopped')} = link_to project_environments_path(@project, scope: :stopped) do Stopped %span.badge.js-stopped-environments-count - {{countStopped}} + {{state.stoppedCounter}} - if can?(current_user, :create_environment, @project) && !@all_environments.blank? .nav-controls -- cgit v1.2.1 From 3c383f9f76a8cec6ecf69a012567cb70b8466897 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 26 Oct 2016 09:17:32 +0100 Subject: Fixes filter --- .../environments/environments_bundle.js.es6 | 8 -------- .../environments/environments_store_spec.js.es6 | 4 +++- spec/javascripts/environments/mock_data.js.es6 | 20 +++++++++++++++++++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 59c0dcfe1c2..8e13e7e20a7 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -51,14 +51,6 @@ $(() => { computed: { filteredEnvironments () { return recursiveMap(filterState(this.visibility), this.state.environments); - }, - - countStopped () { - - }, - - countAvailable () { - // return recursiveMap(filterState('available'), this.state.environments).length; } }, diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 19c71305aa6..ccf6ae971c3 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,6 +1,8 @@ //= require vue //= require vue-resource //= require lib/utils/url_utility +//= require environments/services/environments_service +//= require environments/stores/environments_store //= require ./mock_data // @@ -14,6 +16,6 @@ it('starts with a blank state', () => { expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(0); }); - + }); })(); diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 8d12965332e..87420a32450 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -73,5 +73,23 @@ const environmentsList = [ "name": "root" } } + }, + { + "id": 18, + "project_id": 11, + "name": "review/test-environment-1", + "created_at": "2016-10-19T14:59:59.303Z", + "updated_at": "2016-10-19T14:59:59.303Z", + "external_url": "http://test-1.com", + "environment_type": "review", + "state": "stopped", + "project": { + "id": 11, + "name": "review-apps", + "namespace": { + "id": 1, + "name": "root" + } + } } -]; \ No newline at end of file +]; -- cgit v1.2.1 From dcafd476dbc11eb6f2e7327d96868bf2c2d165a9 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 26 Oct 2016 16:00:16 +0100 Subject: Removes trailing whitespace --- .../components/environment_item.js.es6 | 20 +++++++------- .../environments/environments_bundle.js.es6 | 31 +++++++++++----------- .../services/environments_service.js.es6 | 8 +++--- .../environments/stores/environmnets_store.js.es6 | 26 +++++++++--------- .../environments/environments_store_spec.js.es6 | 4 +-- 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index df9f28b1c59..ab58e1cc4c0 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,23 +1,23 @@ (() => { - + /** * Envrionment Item Component - * + * * Used in a hierarchical structure to show folders with children * in a table. - * Recursive component based on [Tree View](https://vuejs.org/examples/tree-view.html) - * - * See this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/22539) + * Recursive component based on [Tree View](https://vuejs.org/examples/tree-view.html) + * + * See this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/22539) * for more information. */ - + const Store = gl.environmentsList.EnvironmentsStore; window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; - + gl.environmentsList.EnvironmentItem = Vue.component('environment-item', { - + template: '#environment-item-template', props: { @@ -31,11 +31,11 @@ }, computed: { - + /** * If an item has a `children` entry it means it is a folder. * Folder items have different behaviours - it is possible to toggle - * them and show their children. + * them and show their children. * * @returns {Boolean} */ diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 8e13e7e20a7..286d81bab7f 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -6,30 +6,29 @@ //= require ../boards/vue_resource_interceptor $(() => { - + const environmentsListApp = document.getElementById('environments-list-view'); const Store = gl.environmentsList.EnvironmentsStore; - + window.gl = window.gl || {}; - + if (gl.EnvironmentsListApp) { gl.EnvironmentsListApp.$destroy(true); } - - + const filterState = (state) => (environment) => environment.state === state && environment; - - // recursiveMap :: (Function, Array) -> Array + + // recursiveMap :: (Function, Array) -> Array const recursiveMap = (fn, arr) => { return arr.map((item) => { if (!item.children) { return fn(item); } - + const filteredChildren = recursiveMap(fn, item.children).filter(Boolean); if (filteredChildren.length) { item.children = filteredChildren; return item; } - + }).filter(Boolean); }; @@ -47,18 +46,18 @@ $(() => { loading: true, visibility: 'available' }, - + computed: { filteredEnvironments () { return recursiveMap(filterState(this.visibility), this.state.environments); } }, - + init: Store.create.bind(Store), - + created() { gl.environmentsService = new EnvironmentsService(this.endpoint); - + const scope = this.$options.getQueryParameter('scope'); if (scope) { this.visibility = scope; @@ -67,7 +66,7 @@ $(() => { /** * Fetches all the environmnets and stores them. - * Toggles loading property. + * Toggles loading property. */ ready() { gl.environmentsService.all().then((resp) => { @@ -75,11 +74,11 @@ $(() => { this.loading = false; }); }, - + /** * Transforms the url parameter into an object and * returns the one requested. - * + * * @param {String} param * @returns {String} The value of the requested parameter. */ diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 index 5cc194ac034..6e0f5b431e3 100644 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ b/app/assets/javascripts/environments/services/environments_service.js.es6 @@ -1,16 +1,16 @@ class EnvironmentsService { - + constructor (root) { Vue.http.options.root = root; - + this.environments = Vue.resource(root); - + Vue.http.interceptors.push((request, next) => { request.headers['X-CSRF-Token'] = $.rails.csrfToken(); next(); }); } - + all () { return this.environments.get(); } diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index de51d94d2b5..c0e97413636 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -12,15 +12,15 @@ }, /** - * In order to display a tree view we need to modify the received - * data in to a tree structure based on `environment_type` + * In order to display a tree view we need to modify the received + * data in to a tree structure based on `environment_type` * sorted alphabetically. * In each children a `vue-` property will be added. This property will be - * used to know if an item is a children mostly for css purposes. This is + * used to know if an item is a children mostly for css purposes. This is * needed because the children row is a fragment instance and therfore does * not accept non-prop attributes. - * - * + * + * * @example * it will transform this: * [ @@ -30,7 +30,7 @@ * ] * into this: * [ - * { name: "review", children: + * { name: "review", children: * [ * { name: "environment", environment_type: "review", vue-isChildren: true}, * { name: "environment_2", environment_type: "review", vue-isChildren: true} @@ -38,8 +38,8 @@ * }, * {name: "environment_1", environment_type: null} * ] - * - * + * + * * @param {Array} environments List of environments. * @returns {Array} Tree structured array with the received environments. */ @@ -56,13 +56,13 @@ if (environment.last_deployment.manual_actions) { environment.last_deployment.manual_actions = environment.last_deployment.manual_actions.map((action) => Object.assign({}, action, {name: gl.text.humanize(action.name)})); } - + //transforms created date for deployment in a human readable format if (environment.last_deployment.created_at) { // TODO - how to do this without jquery } } - + if (environment.environment_type !== null) { const occurs = acc.find((element, index, array) => { return element.children && element.name === environment.environment_type; @@ -89,15 +89,15 @@ }, []).sort(this.sortByName); this.state.environments = environmentsTree; - + return environmentsTree; }, /** - * Given an array of environments, returns the number of environments + * Given an array of environments, returns the number of environments * that have the given state. * - * @param {Array} environments + * @param {Array} environments * @param {String} state * @returns {Number} */ diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index ccf6ae971c3..482b562fdce 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -4,14 +4,14 @@ //= require environments/services/environments_service //= require environments/stores/environments_store //= require ./mock_data -// +// (() => { beforeEach(() => { gl.environmentsService = new EnvironmentsService('test/environments'); gl.environmentsList.EnvironmentsStore.create(); }); - + describe('Store', () => { it('starts with a blank state', () => { expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(0); -- cgit v1.2.1 From b1ec3cb8d2776070c80cba21d08774e563b42f84 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 26 Oct 2016 18:17:00 +0100 Subject: Adds tests for environment store. --- .../environments/stores/environmnets_store.js.es6 | 14 ++-- .../environments/environments_store_spec.js.es6 | 51 ++++++++++++-- spec/javascripts/environments/mock_data.js.es6 | 81 ++-------------------- 3 files changed, 56 insertions(+), 90 deletions(-) diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index c0e97413636..11c481c22e3 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -54,7 +54,7 @@ //humanizes actions names if there are any actions if (environment.last_deployment.manual_actions) { - environment.last_deployment.manual_actions = environment.last_deployment.manual_actions.map((action) => Object.assign({}, action, {name: gl.text.humanize(action.name)})); + environment.last_deployment.manual_actions = environment.last_deployment.manual_actions.map((action) => action.name = gl.text.humanize(action.name)); } //transforms created date for deployment in a human readable format @@ -64,21 +64,19 @@ } if (environment.environment_type !== null) { - const occurs = acc.find((element, index, array) => { + const occurs = acc.filter((element, index, array) => { return element.children && element.name === environment.environment_type; }); environment["vue-isChildren"] = true; - if (occurs !== undefined) { - acc[acc.indexOf(occurs)].children.push(environment); - acc[acc.indexOf(occurs)].children.sort(this.sortByName) + if (occurs.length) { + acc[acc.indexOf(occurs[0])].children.push(environment); + acc[acc.indexOf(occurs[0])].children.sort(this.sortByName) } else { acc.push({ name: environment.environment_type, - children: [ - Object.assign(environment) - ] + children: [environment] }); } } else { diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 482b562fdce..db4ce41701c 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,21 +1,58 @@ //= require vue -//= require vue-resource -//= require lib/utils/url_utility -//= require environments/services/environments_service -//= require environments/stores/environments_store +//= require environments/stores/environmnets_store //= require ./mock_data -// (() => { + beforeEach(() => { - gl.environmentsService = new EnvironmentsService('test/environments'); gl.environmentsList.EnvironmentsStore.create(); }); describe('Store', () => { - it('starts with a blank state', () => { + it('should start with a blank state', () => { expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(0); + expect(gl.environmentsList.EnvironmentsStore.state.stoppedCounter).toBe(0); + expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(0) }); + describe('store environments', () => { + beforeEach(() => { + gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList); + }); + + it('should count stopped environments and save the count in the state', () => { + + + expect(gl.environmentsList.EnvironmentsStore.state.stoppedCounter).toBe(1); + }); + + it('should count available environments and save the count in the state', () => { + + expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(2); + }); + + it('should store environments with same environment_type as sibilings', () => { + + expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(2); + + const parentFolder = gl.environmentsList.EnvironmentsStore.state.environments.filter((env) => { + return env.children && env.children.length > 0; + }); + + expect(parentFolder[0].children.length).toBe(2); + expect(parentFolder[0].children[0].environment_type).toBe('review'); + expect(parentFolder[0].children[1].environment_type).toBe('review'); + expect(parentFolder[0].children[0].name).toBe('review/test-environment') + expect(parentFolder[0].children[1].name).toBe('review/test-environment-1'); + }); + + it('should sort the environments alphabetically', () => { + const { environments } = gl.environmentsList.EnvironmentsStore.state; + + expect(environments[0].name).toBe('production'); + expect(environments[1].children[0].name).toBe('review/test-environment'); + expect(environments[1].children[1].name).toBe('review/test-environment-1'); + }); + }); }); })(); diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 87420a32450..35d94e3ab44 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -3,93 +3,24 @@ const environmentsList = [ "id": 15, "project_id": 11, "name": "production", - "created_at": "2016-10-18T10:47:46.840Z", - "updated_at": "2016-10-19T15:49:24.378Z", "external_url": "https://test.com", "environment_type": null, - "state": "available", - "last_deployment": { - "id": 57, - "iid": 5, - "project_id": 11, - "environment_id": 15, - "ref": "master", - "tag": false, - "sha": "edf8704ba6cea79be4634b82927e9ff534068428", - "user_id": 1, - "deployable_id": 1170, - "deployable_type": "CommitStatus", - "on_stop": null, - "short_sha": "edf8704b", - "commit_title": "Update .gitlab-ci.yml", - "commit": { - "id": "edf8704ba6cea79be4634b82927e9ff534068428", - "message": "Update .gitlab-ci.yml", - "parent_ids": ["f215999006bd3d5c89b9b1e8c0873c9aca0f913a"], - "authored_date": "2016-10-19T16:49:09.000+01:00", - "author_name": "Administrator", - "author_email": "admin@example.com", - "committed_date": "2016-10-19T16:49:09.000+01:00", - "committer_name": "Administrator", - "committer_email": "admin@example.com" - }, - "user": { - "id": 1, - "name": "Administrator", - "username": "root", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon" - }, - "deployable": { - "id": 1170, - "name": "deploy", - "tag": false, - "ref": "master" - } - }, - "project": { - "id": 11, - "name": "review-apps", - "path": "review-apps", - "namespace_id": 1, - "namespace": { - "id": 1, - "name": "root" - } - } - },{ + "state": "available" + }, + { "id": 18, "project_id": 11, "name": "review/test-environment", - "created_at": "2016-10-19T14:59:59.303Z", - "updated_at": "2016-10-19T14:59:59.303Z", "external_url": "http://test1.com", "environment_type": "review", - "state": "available", - "project": { - "id": 11, - "name": "review-apps", - "namespace": { - "id": 1, - "name": "root" - } - } + "state": "available" }, { - "id": 18, + "id": 19, "project_id": 11, "name": "review/test-environment-1", - "created_at": "2016-10-19T14:59:59.303Z", - "updated_at": "2016-10-19T14:59:59.303Z", "external_url": "http://test-1.com", "environment_type": "review", - "state": "stopped", - "project": { - "id": 11, - "name": "review-apps", - "namespace": { - "id": 1, - "name": "root" - } - } + "state": "stopped" } ]; -- cgit v1.2.1 From 14345b21509aa874cf8748a2ddcf34d3a632bd6c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 27 Oct 2016 10:51:44 +0100 Subject: Fix whitespace --- .../javascripts/environments/components/environment_item.js.es6 | 2 -- spec/javascripts/environments/environments_store_spec.js.es6 | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index ab58e1cc4c0..76c815e8b9f 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -11,8 +11,6 @@ * for more information. */ - const Store = gl.environmentsList.EnvironmentsStore; - window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index db4ce41701c..8d0fea934c3 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -21,20 +21,16 @@ }); it('should count stopped environments and save the count in the state', () => { - - expect(gl.environmentsList.EnvironmentsStore.state.stoppedCounter).toBe(1); }); it('should count available environments and save the count in the state', () => { - expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(2); }); it('should store environments with same environment_type as sibilings', () => { - expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(2); - + const parentFolder = gl.environmentsList.EnvironmentsStore.state.environments.filter((env) => { return env.children && env.children.length > 0; }); -- cgit v1.2.1 From bd01a5a47c70face953cb2d0a6eb3066abc975fd Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 7 Nov 2016 09:43:43 +0100 Subject: Add EnvironmentSerializer to EnvironmentsController --- app/controllers/projects/environments_controller.rb | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 42f882b55ab..6bd4cb3f2f5 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -13,7 +13,9 @@ class Projects::EnvironmentsController < Projects::ApplicationController respond_to do |format| format.html format.json do - render json: serialize_as_json(@environments) + render json: EnvironmentSerializer + .new(project: @project) + .represent(@environments) end end end @@ -63,19 +65,4 @@ class Projects::EnvironmentsController < Projects::ApplicationController def environment @environment ||= project.environments.find(params[:id]) end - - def serialize_as_json(resource) - resource.as_json( - include: { - last_deployment: { - include: { - user: { only: [:id, :name, :username], methods: [:avatar_url] }, - deployable: { only: [:id, :name, :ref, :tag] } - }, - methods: [:short_sha, :commit_title, :commit] - }, - project: { methods: [:namespace] } - } - ) - end end -- cgit v1.2.1 From 4388d90370310a570c5450b6c10eba7533ce1827 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 7 Nov 2016 10:03:19 +0100 Subject: Add controller specs for environments index action --- .../projects/environments_controller_spec.rb | 33 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 768105cae95..bc5e2711125 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Projects::EnvironmentsController do + include ApiHelpers + let(:environment) { create(:environment) } let(:project) { environment.project } let(:user) { create(:user) } @@ -11,6 +13,27 @@ describe Projects::EnvironmentsController do sign_in(user) end + describe 'GET index' do + context 'when standardrequest has been made' do + it 'responds with status code 200' do + get :index, environment_params + + expect(response).to be_ok + end + end + + context 'when requesting JSON response' do + it 'responds with correct JSON' do + get :index, environment_params(format: :json) + + first_environment = json_response.first + + expect(first_environment).not_to be_empty + expect(first_environment['name']). to eq environment.name + end + end + end + describe 'GET show' do context 'with valid id' do it 'responds with a status code 200' do @@ -48,11 +71,9 @@ describe Projects::EnvironmentsController do end end - def environment_params - { - namespace_id: project.namespace, - project_id: project, - id: environment.id - } + def environment_params(opts = {}) + opts.reverse_merge(namespace_id: project.namespace, + project_id: project, + id: environment.id) end end -- cgit v1.2.1 From 8d171f0a5fbd920b25b5012526e3cdb2c3aee623 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 12:45:35 +0000 Subject: Fix commit column with correct data --- .../environments/components/_commit.html.haml | 33 ++++++++++------------ app/views/projects/environments/index.html.haml | 4 +-- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index 1f923a2d0d6..17bc3dcb379 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -1,30 +1,27 @@ .branch-commit{"v-if" => "!isFolder && model.last_deployment"} + .icon-container{ "v-if" => "model.last_deployment.ref && model.last_deployment.tag" } + =icon("tag") - %div{ "v-if" => "model.last_deployment.ref" } + .icon-container{ "v-if" => "model.last_deployment.ref && !model.last_deployment.tag" } + =icon("code-fork") - .icon-container{ "v-if" => "model.last_deployment.tag" } - =icon("tag") - - .icon-container{ "v-if" => "!model.last_deployment.tag" } - =icon("code-fork") - - %a.monospace.branch-name{":href" => "'/' + model.project.namespace.name + '/' + model.project.name + '/commits/' +model.last_deployment.ref"} - {{model.last_deployment.ref}} + %a.monospace.branch-name{"v-if" => "model.last_deployment.ref", ":href" => "model.last_deployment.ref.ref_url"} + {{model.last_deployment.ref.name}} .icon-container.commit-icon = custom_icon("icon_commit") - %a.commit-id.monospace{":href" => "'/' + model.project.namespace.name + '/' + model.project.name + '/commit/' +model.last_deployment.sha"} - {{model.last_deployment.short_sha}} + %a.commit-id.monospace{":href" => "model.last_deployment.commit.commit_url"} + {{model.last_deployment.commit.short_id}} %p.commit-title - %span{ "v-if" => "model.last_deployment.commit_title"} - - -# need commit author username and avatar_url - commit author goes here - %a.commit-row-message{":href" => "'/' + model.project.namespace.name + '/' + model.project.name + '/commit/' +model.last_deployment.sha"} - {{model.last_deployment.commit_title}} + %span{ "v-if" => "model.last_deployment.commit && model.last_deployment.commit.title"} + %a{"v-if" => "model.last_deployment.commit.author", ":href" => "model.last_deployment.commit.author.web_url"} + %img.avatar.has-tooltip.s20{":title" => "model.last_deployment.commit.author.username", + ":src" => "model.last_deployment.commit.author.avatar_url"} + %a.commit-row-message{":href" => "model.last_deployment.commit.commit_url"} + {{model.last_deployment.commit.title}} - %span{ "v-if" => "!model.last_deployment.commit_title"} + %span{ "v-if" => "!model.last_deployment.commit.title"} Cant find HEAD commit for this branch diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 81c8fd9d9db..fa88d59e3ca 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -20,8 +20,8 @@ %span.badge.js-stopped-environments-count {{state.stoppedCounter}} - - if can?(current_user, :create_environment, @project) && !@all_environments.blank? - .nav-controls + - if can?(current_user, :create_environment, @project) + .nav-controls{ "v-if" => "!loading" } = link_to new_namespace_project_environment_path(@project.namespace, @project), class: "btn btn-create" do New environment -- cgit v1.2.1 From 95490ca379572efc8010019e7b0d7b1a535b7497 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 14:06:01 +0000 Subject: Remove underline styling when hover the user avatar --- app/assets/stylesheets/pages/environments.scss | 4 ++++ app/views/projects/environments/components/_commit.html.haml | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 9d47e96bb69..0ab1066e970 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -20,6 +20,10 @@ margin: 0; } + .avatar-container { + text-decoration: none; + } + .icon-play { height: 13px; width: 12px; diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index 17bc3dcb379..972a4f241f5 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -15,9 +15,8 @@ {{model.last_deployment.commit.short_id}} %p.commit-title - %span{ "v-if" => "model.last_deployment.commit && model.last_deployment.commit.title"} - %a{"v-if" => "model.last_deployment.commit.author", ":href" => "model.last_deployment.commit.author.web_url"} + %a.avatar-container{"v-if" => "model.last_deployment.commit.author", ":href" => "model.last_deployment.commit.author.web_url"} %img.avatar.has-tooltip.s20{":title" => "model.last_deployment.commit.author.username", ":src" => "model.last_deployment.commit.author.avatar_url"} %a.commit-row-message{":href" => "model.last_deployment.commit.commit_url"} -- cgit v1.2.1 From 8dd19c4279eae0266dce2d2dc9057b0ba0f7650f Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 16:15:30 +0000 Subject: Fixes avatar style --- app/assets/stylesheets/pages/environments.scss | 2 +- app/views/projects/environments/components/_commit.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 0ab1066e970..6ce10f1e7ef 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -20,7 +20,7 @@ margin: 0; } - .avatar-container { + .avatar-image-container { text-decoration: none; } diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index 972a4f241f5..c0c54325f7f 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -16,7 +16,7 @@ %p.commit-title %span{ "v-if" => "model.last_deployment.commit && model.last_deployment.commit.title"} - %a.avatar-container{"v-if" => "model.last_deployment.commit.author", ":href" => "model.last_deployment.commit.author.web_url"} + %a.avatar-image-container{"v-if" => "model.last_deployment.commit.author", ":href" => "model.last_deployment.commit.author.web_url"} %img.avatar.has-tooltip.s20{":title" => "model.last_deployment.commit.author.username", ":src" => "model.last_deployment.commit.author.avatar_url"} %a.commit-row-message{":href" => "model.last_deployment.commit.commit_url"} -- cgit v1.2.1 From 1b00f3a5bb556118298a3396437db74dec7b5933 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 16:53:13 +0000 Subject: Adds alt attribute in image tags --- app/views/projects/environments/components/_commit.html.haml | 1 + app/views/projects/environments/components/_environment.html.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml index c0c54325f7f..8233dec7b93 100644 --- a/app/views/projects/environments/components/_commit.html.haml +++ b/app/views/projects/environments/components/_commit.html.haml @@ -18,6 +18,7 @@ %span{ "v-if" => "model.last_deployment.commit && model.last_deployment.commit.title"} %a.avatar-image-container{"v-if" => "model.last_deployment.commit.author", ":href" => "model.last_deployment.commit.author.web_url"} %img.avatar.has-tooltip.s20{":title" => "model.last_deployment.commit.author.username", + ":alt" => "model.last_deployment.commit.author.username + `'s avatar`", ":src" => "model.last_deployment.commit.author.avatar_url"} %a.commit-row-message{":href" => "model.last_deployment.commit.commit_url"} {{model.last_deployment.commit.title}} diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 1aa0d7ac5e2..42c6ae562e0 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -27,7 +27,7 @@ by %a{":href" => "'/' + model.last_deployment.user.username" } %img.avatar.has_tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", - ":alt" => "model.last_deployment.user.username + 'avatar'", + ":alt" => "model.last_deployment.user.username + `'s avatar`", ":title" => "model.last_deployment.user.username", data: {container: "body" }, width: 20, height: 20} -- cgit v1.2.1 From f5d9b994e4a2362140c73f6be5de280f6ec64eaf Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 17:01:40 +0000 Subject: Use urls sent in JSON response --- app/views/projects/environments/components/_environment.html.haml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 42c6ae562e0..a90517f76a0 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -2,7 +2,7 @@ %tr %td{"v-bind:class" => "{ 'children-row': isChildren}" } %a.environment-name{ "v-if" => "!isFolder", - ":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id" } + ":href" => "model.environment_url" } {{model.name}} %span.folder-name{ "v-if" => "isFolder", @@ -25,7 +25,7 @@ %span{ "v-if" => "model.last_deployment.user" } by - %a{":href" => "'/' + model.last_deployment.user.username" } + %a{":href" => "model.last_deployment.user.web_url" } %img.avatar.has_tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", ":alt" => "model.last_deployment.user.username + `'s avatar`", ":title" => "model.last_deployment.user.username", @@ -34,7 +34,7 @@ %td %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", - ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id" } + ":href" => "model.last_deployment.deployable.build_url" } {{model.last_deployment.deployable.name}} = precede "#" do {{model.last_deployment.deployable.id}} @@ -47,7 +47,7 @@ %td %span{ "v-if" => "!isFolder && model.last_deployment" } - {{model.last_deployment.created_at}} + {{model.created_at}} %td.hidden-xs .pull-right{ "v-if" => "!isFolder" } -- cgit v1.2.1 From 4ea04c4035368efa007abbf560e7ca6882a361b8 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 17:21:42 +0000 Subject: Adds tooltip to user image --- .../projects/environments/components/_environment.html.haml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index a90517f76a0..122cea2c3a4 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -26,15 +26,13 @@ %span{ "v-if" => "model.last_deployment.user" } by %a{":href" => "model.last_deployment.user.web_url" } - %img.avatar.has_tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", + %img.avatar.has-tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", ":alt" => "model.last_deployment.user.username + `'s avatar`", - ":title" => "model.last_deployment.user.username", - data: {container: "body" }, - width: 20, height: 20} + ":title" => "model.last_deployment.user.username"} %td %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", - ":href" => "model.last_deployment.deployable.build_url" } + ":href" => "model.last_deployment.deployable.build" } {{model.last_deployment.deployable.name}} = precede "#" do {{model.last_deployment.deployable.id}} @@ -47,7 +45,7 @@ %td %span{ "v-if" => "!isFolder && model.last_deployment" } - {{model.created_at}} + {{model.last_deployment.created_at}} %td.hidden-xs .pull-right{ "v-if" => "!isFolder" } -- cgit v1.2.1 From 2207528c376f0c64469f077f82dfb49a3f7e7993 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 18:44:16 +0000 Subject: Uses vue computed data Fixes some eslint errors Adds some documentation Improves data manipulation --- .../components/environment_item.js.es6 | 99 +++++++++++++++++++--- .../environments/environments_bundle.js.es6 | 14 +-- .../environments/stores/environmnets_store.js.es6 | 36 +++----- .../environments/components/_actions.html.haml | 6 +- .../environments/components/_environment.html.haml | 4 +- .../environments/components/_rollback.html.haml | 8 +- .../environments/components/_stop.html.haml | 4 +- 7 files changed, 114 insertions(+), 57 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 76c815e8b9f..0d541f5989d 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,5 +1,6 @@ +/* globals Vue */ +/* eslint-disable no-param-reassign, no-return-assign */ (() => { - /** * Envrionment Item Component * @@ -19,12 +20,12 @@ template: '#environment-item-template', props: { - model: Object + model: Object, }, - data () { + data() { return { - open: false + open: false, }; }, @@ -37,8 +38,8 @@ * * @returns {Boolean} */ - isFolder () { - return this.model.children && this.model.children.length ? true : false; + isFolder() { + return this.$options.hasKey(this.model, 'children') && this.model.children.length > 0; }, /** @@ -47,7 +48,7 @@ * * @returns {Boolean|undefined} */ - isChildren () { + isChildren() { return this.model['vue-isChildren']; }, @@ -57,9 +58,79 @@ * * @returns {Boolean} The number of environments for the current folder */ - childrenCounter () { - return this.model.children && this.model.children.length; - } + childrenCounter() { + return this.$options.hasKey(this.model, 'children') && this.model.children.length; + }, + + /** + * Returns the value of the `last?` key sent in the API. + * Used to know wich title to render when the environment can be re-deployed + * + * @returns {Boolean} + */ + isLast() { + return this.$options.hasKey(this.model, 'last_deployment') && this.model.last_deployment['last?']; + }, + + /** + * Verifies if `last_deployment` key exists in the current Envrionment. + * This key is required to render most of the html - this method works has + * an helper. + * + * @returns {Boolean} + */ + hasLastDeploymentKey() { + return this.$options.hasKey(this.model, 'last_deployment'); + }, + + /** + * Verifies is the given environment has manual actions. + * Used to verify if we should render them or nor. + * + * @returns {Boolean} description + */ + hasManualActions() { + return this.$options.hasKey(this.model, 'manual_actions') && this.model.manual_actions.length; + }, + + /** + * Returns the value of the `stoppable?` key provided in the response. + * + * @returns {Boolean} + */ + isStoppable() { + return this.model['stoppable?']; + }, + + /** + * Verifies if the `deployable` key is present in `last_deployment` key. + * Used to verify whether we should or not render the rollback partial. + * + * @returns {Boolean} + */ + canRetry() { + return this.hasLastDeploymentKey && this.model.last_deployment && this.$options.hasKey(this.model.last_deployment, 'deployable'); + }, + + createdDate() { + return $.timeago(this.model.created_at); + }, + + manualActions() { + this.model.manual_actions.map(action => action.name = gl.text.humanize(action.name)); + }, + }, + + /** + * Helper to verify if key is present in an object. + * Can be removed once we start using lodash. + * + * @param {Object} obj + * @param {String} key + * @returns {Boolean} + */ + hasKey(obj, key) { + return {}.hasOwnProperty.call(obj, key); }, methods: { @@ -67,11 +138,11 @@ /** * Toggles the visibility of a folders' children. */ - toggle () { + toggle() { if (this.isFolder) { this.open = !this.open; } - } - } - }) + }, + }, + }); })(); diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 286d81bab7f..53a8353a0bf 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -5,8 +5,9 @@ //= require ./components/environment_item //= require ../boards/vue_resource_interceptor -$(() => { +/* eslint-disable */ +$(() => { const environmentsListApp = document.getElementById('environments-list-view'); const Store = gl.environmentsList.EnvironmentsStore; @@ -16,10 +17,11 @@ $(() => { gl.EnvironmentsListApp.$destroy(true); } - const filterState = (state) => (environment) => environment.state === state && environment; + const filterState = state => environment => environment.state === state && environment; // recursiveMap :: (Function, Array) -> Array const recursiveMap = (fn, arr) => { + return arr.map((item) => { if (!item.children) { return fn(item); } @@ -37,20 +39,20 @@ $(() => { el: '#environments-list-view', components: { - 'item': gl.environmentsList.EnvironmentItem + item: gl.environmentsList.EnvironmentItem }, data: { state: Store.state, endpoint: environmentsListApp.dataset.endpoint, loading: true, - visibility: 'available' + visibility: 'available', }, computed: { - filteredEnvironments () { + filteredEnvironments (){ return recursiveMap(filterState(this.visibility), this.state.environments); - } + }, }, init: Store.create.bind(Store), diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 11c481c22e3..587e213a17b 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -5,7 +5,7 @@ gl.environmentsList.EnvironmentsStore = { state: {}, - create () { + create() { this.state.environments = []; this.state.stoppedCounter = 0; this.state.availableCounter = 0; @@ -44,39 +44,23 @@ * @returns {Array} Tree structured array with the received environments. */ storeEnvironments(environments = []) { - this.state.stoppedCounter = this.countByState(environments, 'stopped'); this.state.availableCounter = this.countByState(environments, 'available'); const environmentsTree = environments.reduce((acc, environment) => { - - if (environment.last_deployment) { - - //humanizes actions names if there are any actions - if (environment.last_deployment.manual_actions) { - environment.last_deployment.manual_actions = environment.last_deployment.manual_actions.map((action) => action.name = gl.text.humanize(action.name)); - } - - //transforms created date for deployment in a human readable format - if (environment.last_deployment.created_at) { - // TODO - how to do this without jquery - } - } - if (environment.environment_type !== null) { - const occurs = acc.filter((element, index, array) => { - return element.children && element.name === environment.environment_type; - }); + const occurs = acc.filter(element => element.children && + element.name === environment.environment_type); - environment["vue-isChildren"] = true; + environment['vue-isChildren'] = true; if (occurs.length) { acc[acc.indexOf(occurs[0])].children.push(environment); - acc[acc.indexOf(occurs[0])].children.sort(this.sortByName) + acc[acc.indexOf(occurs[0])].children.sort(this.sortByName); } else { acc.push({ name: environment.environment_type, - children: [environment] + children: [environment], }); } } else { @@ -100,7 +84,7 @@ * @returns {Number} */ countByState(environments, state) { - return environments.filter((env) => env.state === state).length; + return environments.filter(env => env.state === state).length; }, /** @@ -110,7 +94,7 @@ * @param {Object} b * @returns {Number} */ - sortByName (a, b) { + sortByName(a, b) { const nameA = a.name.toUpperCase(); const nameB = b.name.toUpperCase(); @@ -123,6 +107,6 @@ } return 0; - } - } + }, + }; })(); diff --git a/app/views/projects/environments/components/_actions.html.haml b/app/views/projects/environments/components/_actions.html.haml index 82acda0de9c..a2c229f1315 100644 --- a/app/views/projects/environments/components/_actions.html.haml +++ b/app/views/projects/environments/components/_actions.html.haml @@ -1,13 +1,13 @@ - if can?(current_user, :create_deployment, @project) - .inline{ "v-if" => "model.last_deployment && model.last_deployment.manual_actions && model.last_deployment.manual_actions.present"} + .inline{ "v-if" => "hasManualActions"} .dropdown %a.dropdown-new.btn.btn-default{type: "button", "data-toggle" => "dropdown"} = custom_icon('icon_play') = icon('caret-down') %ul.dropdown-menu.dropdown-menu-align-right - %li{ "v-for" => "action in model.last_deployment.manual_actions" } - %a{ ":ref" => "'#{namespace_project_path(@project.namespace, @project)}/' + action.id + '/play'", + %li{ "v-for" => "action in manualActions" } + %a{ ":ref" => "action.play_url", "data-method" => "post", "rel" => "nofollow" } diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml index 122cea2c3a4..2fecfd85f61 100644 --- a/app/views/projects/environments/components/_environment.html.haml +++ b/app/views/projects/environments/components/_environment.html.haml @@ -44,8 +44,8 @@ No deployments yet %td - %span{ "v-if" => "!isFolder && model.last_deployment" } - {{model.last_deployment.created_at}} + %span.environment-created-date-timeago{ "v-if" => "!isFolder && model.last_deployment" } + {{createdDate}} %td.hidden-xs .pull-right{ "v-if" => "!isFolder" } diff --git a/app/views/projects/environments/components/_rollback.html.haml b/app/views/projects/environments/components/_rollback.html.haml index 2258f6ec32d..e3449c5515e 100644 --- a/app/views/projects/environments/components/_rollback.html.haml +++ b/app/views/projects/environments/components/_rollback.html.haml @@ -1,10 +1,10 @@ - if can?(current_user, :create_deployment, @project) - %a.btn.btn-build{ "v-if" => "model.last_deployment && model.last_deployment.deployable", - ":href" => "'#{namespace_project_builds_path(@project.namespace, @project)}/' + model.last_deployment.deployable.id + '/retry'", + %a.btn.btn-build{ "v-if" => "canRetry", + ":href" => "model.last_deployment.deployable.retry_url", "data-method" => "post", "rel" => "nofollow" } - %span{ "v-if" => "model.last_deployment.last" } + %span{ "v-if" => "isLastDeployment" } Re-deploy - %span{ "v-if" => "!model.last_deployment.last" } + %span{ "v-if" => "!isLastDeployment" } Rollback diff --git a/app/views/projects/environments/components/_stop.html.haml b/app/views/projects/environments/components/_stop.html.haml index 55cccf9e72e..a7100f15784 100644 --- a/app/views/projects/environments/components/_stop.html.haml +++ b/app/views/projects/environments/components/_stop.html.haml @@ -1,6 +1,6 @@ - if can?(current_user, :create_deployment, @project) - .inline{ "v-if" => "model.stop_action" } - %a.btn.stop-env-link{":href" => "'#{namespace_project_environments_path(@project.namespace, @project)}/' + model.id", + .inline{ "v-if" => "isStoppable" } + %a.btn.stop-env-link{":href" => "model.environment_url", "method" => ":post", "rel" => "nofollow", "confirm" => "Are you sure you want to stop this environment?"} -- cgit v1.2.1 From 26664203eed786961c47eb23bea4fefd89ac3503 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 20:52:04 +0000 Subject: Small fixes --- .../components/environment_item.js.es6 | 19 ++++++++++++++-- .../environments/environments_bundle.js.es6 | 26 ++++++++++------------ .../services/environments_service.js.es6 | 8 ++++--- .../environments/stores/environmnets_store.js.es6 | 1 + .../environments/components/_actions.html.haml | 16 ++++++------- 5 files changed, 43 insertions(+), 27 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 0d541f5989d..436ac365788 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,5 +1,4 @@ /* globals Vue */ -/* eslint-disable no-param-reassign, no-return-assign */ (() => { /** * Envrionment Item Component @@ -112,12 +111,28 @@ return this.hasLastDeploymentKey && this.model.last_deployment && this.$options.hasKey(this.model.last_deployment, 'deployable'); }, + /** + * Human readable date. + * + * @returns {String} + */ createdDate() { return $.timeago(this.model.created_at); }, + /** + * Returns the manual actions with the name parsed. + * + * @returns {Array.} + */ manualActions() { - this.model.manual_actions.map(action => action.name = gl.text.humanize(action.name)); + return this.model.manual_actions.map((action) => { + const parsedAction = { + name: gl.text.humanize(action.name), + play_url: action.play_url, + }; + return parsedAction; + }); }, }, diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 53a8353a0bf..1299f64182c 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -4,9 +4,9 @@ //= require_tree ./services //= require ./components/environment_item //= require ../boards/vue_resource_interceptor +/* globals Vue, EnvironmentsService */ +/* eslint-disable no-param-reassign */ - -/* eslint-disable */ $(() => { const environmentsListApp = document.getElementById('environments-list-view'); const Store = gl.environmentsList.EnvironmentsStore; @@ -20,26 +20,24 @@ $(() => { const filterState = state => environment => environment.state === state && environment; // recursiveMap :: (Function, Array) -> Array - const recursiveMap = (fn, arr) => { - - return arr.map((item) => { - if (!item.children) { return fn(item); } - + const recursiveMap = (fn, arr) => arr.map((item) => { + if (item.children) { const filteredChildren = recursiveMap(fn, item.children).filter(Boolean); if (filteredChildren.length) { item.children = filteredChildren; return item; } + } + return fn(item); + }).filter(Boolean); - }).filter(Boolean); - }; gl.EnvironmentsListApp = new Vue({ el: '#environments-list-view', components: { - item: gl.environmentsList.EnvironmentItem + item: gl.environmentsList.EnvironmentItem, }, data: { @@ -50,7 +48,7 @@ $(() => { }, computed: { - filteredEnvironments (){ + filteredEnvironments() { return recursiveMap(filterState(this.visibility), this.state.environments); }, }, @@ -84,12 +82,12 @@ $(() => { * @param {String} param * @returns {String} The value of the requested parameter. */ - getQueryParameter(param) { + getQueryParameter(parameter) { return window.location.search.substring(1).split('&').reduce((acc, param) => { const paramSplited = param.split('='); acc[paramSplited[0]] = paramSplited[1]; return acc; - }, {})[param]; - } + }, {})[parameter]; + }, }); }); diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 index 6e0f5b431e3..e10dd87f7ce 100644 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ b/app/assets/javascripts/environments/services/environments_service.js.es6 @@ -1,6 +1,8 @@ +/* globals Vue */ +/* eslint-disable no-unused-vars, no-param-reassign */ class EnvironmentsService { - constructor (root) { + constructor(root) { Vue.http.options.root = root; this.environments = Vue.resource(root); @@ -11,7 +13,7 @@ class EnvironmentsService { }); } - all () { + all() { return this.environments.get(); } -}; +} diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 index 587e213a17b..ef0188c15bf 100644 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 @@ -1,3 +1,4 @@ +/* eslint-disable no-param-reassign */ (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/views/projects/environments/components/_actions.html.haml b/app/views/projects/environments/components/_actions.html.haml index a2c229f1315..f23fdb72353 100644 --- a/app/views/projects/environments/components/_actions.html.haml +++ b/app/views/projects/environments/components/_actions.html.haml @@ -5,12 +5,12 @@ = custom_icon('icon_play') = icon('caret-down') - %ul.dropdown-menu.dropdown-menu-align-right - %li{ "v-for" => "action in manualActions" } - %a{ ":ref" => "action.play_url", - "data-method" => "post", - "rel" => "nofollow" } + %ul.dropdown-menu.dropdown-menu-align-right + %li{ "v-for" => "action in manualActions" } + %a{ ":href" => "action.play_url", + "data-method" => "post", + "rel" => "nofollow" } - = custom_icon('icon_play') - %span - {{action.name}} \ No newline at end of file + = custom_icon('icon_play') + %span + {{action.name}} \ No newline at end of file -- cgit v1.2.1 From a8508608eaf8440da7e55686c649f7209621494c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 21:11:58 +0000 Subject: Fixes the tests --- .../environments/environments_store_spec.js.es6 | 26 ++-- spec/javascripts/environments/mock_data.js.es6 | 148 ++++++++++++++++++--- 2 files changed, 142 insertions(+), 32 deletions(-) diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 8d0fea934c3..bc16c90e9be 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,9 +1,8 @@ //= require vue //= require environments/stores/environmnets_store //= require ./mock_data - +/* globals environmentsList */ (() => { - beforeEach(() => { gl.environmentsList.EnvironmentsStore.create(); }); @@ -12,12 +11,12 @@ it('should start with a blank state', () => { expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(0); expect(gl.environmentsList.EnvironmentsStore.state.stoppedCounter).toBe(0); - expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(0) + expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(0); }); describe('store environments', () => { beforeEach(() => { - gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList); + gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList); }); it('should count stopped environments and save the count in the state', () => { @@ -25,29 +24,30 @@ }); it('should count available environments and save the count in the state', () => { - expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(2); + expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(3); }); it('should store environments with same environment_type as sibilings', () => { - expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(2); + expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(3); - const parentFolder = gl.environmentsList.EnvironmentsStore.state.environments.filter((env) => { - return env.children && env.children.length > 0; - }); + const parentFolder = gl.environmentsList.EnvironmentsStore.state.environments + .filter(env => env.children && env.children.length > 0); expect(parentFolder[0].children.length).toBe(2); expect(parentFolder[0].children[0].environment_type).toBe('review'); expect(parentFolder[0].children[1].environment_type).toBe('review'); - expect(parentFolder[0].children[0].name).toBe('review/test-environment') - expect(parentFolder[0].children[1].name).toBe('review/test-environment-1'); + expect(parentFolder[0].children[0].name).toBe('test-environment'); + expect(parentFolder[0].children[1].name).toBe('test-environment-1'); }); it('should sort the environments alphabetically', () => { const { environments } = gl.environmentsList.EnvironmentsStore.state; expect(environments[0].name).toBe('production'); - expect(environments[1].children[0].name).toBe('review/test-environment'); - expect(environments[1].children[1].name).toBe('review/test-environment-1'); + expect(environments[1].name).toBe('review'); + expect(environments[1].children[0].name).toBe('test-environment'); + expect(environments[1].children[1].name).toBe('test-environment-1'); + expect(environments[2].name).toBe('review_app') }); }); }); diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 35d94e3ab44..1142ace5846 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -1,26 +1,136 @@ +/* eslint-disable no-unused-vars */ const environmentsList = [ { - "id": 15, - "project_id": 11, - "name": "production", - "external_url": "https://test.com", - "environment_type": null, - "state": "available" + id: 31, + name: 'production', + state: 'available', + external_url: 'https://www.gitlab.com', + environment_type: null, + last_deployment: { + id: 64, + iid: 5, + sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + ref: { + name: 'master', + ref_url: 'http://localhost:3000/root/ci-folders/tree/master', + }, + tag: false, + 'last?': true, + user: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit: { + id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + short_id: '500aabcb', + title: 'Update .gitlab-ci.yml', + author_name: 'Administrator', + author_email: 'admin@example.com', + created_at: '2016-11-07T18:28:13.000+00:00', + message: 'Update .gitlab-ci.yml', + author: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit_url: 'http://localhost:3000/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + }, + deployable: { + id: 1278, + name: 'build', + build_url: 'http://localhost:3000/root/ci-folders/builds/1278', + retry_url: 'http://localhost:3000/root/ci-folders/builds/1278/retry', + }, + manual_actions: [], + }, + 'stoppable?': true, + environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-07T11:11:16.525Z', }, { - "id": 18, - "project_id": 11, - "name": "review/test-environment", - "external_url": "http://test1.com", - "environment_type": "review", - "state": "available" + id: 32, + name: 'review_app', + state: 'stopped', + external_url: 'https://www.gitlab.com', + environment_type: null, + last_deployment: { + id: 64, + iid: 5, + sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + ref: { + name: 'master', + ref_url: 'http://localhost:3000/root/ci-folders/tree/master', + }, + tag: false, + 'last?': true, + user: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit: { + id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + short_id: '500aabcb', + title: 'Update .gitlab-ci.yml', + author_name: 'Administrator', + author_email: 'admin@example.com', + created_at: '2016-11-07T18:28:13.000+00:00', + message: 'Update .gitlab-ci.yml', + author: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit_url: 'http://localhost:3000/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + }, + deployable: { + id: 1278, + name: 'build', + build_url: 'http://localhost:3000/root/ci-folders/builds/1278', + retry_url: 'http://localhost:3000/root/ci-folders/builds/1278/retry', + }, + manual_actions: [], + }, + 'stoppable?': false, + environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-07T11:11:16.525Z', }, { - "id": 19, - "project_id": 11, - "name": "review/test-environment-1", - "external_url": "http://test-1.com", - "environment_type": "review", - "state": "stopped" - } + id: 33, + name: 'test-environment', + state: 'available', + environment_type: 'review', + last_deployment: null, + 'stoppable?': true, + environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-07T11:11:16.525Z', + }, + { + id: 34, + name: 'test-environment-1', + state: 'available', + environment_type: 'review', + last_deployment: null, + 'stoppable?': true, + environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-07T11:11:16.525Z', + }, ]; + -- cgit v1.2.1 From c3db10d3fb32babb608bb191596e3462454ac41f Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 7 Nov 2016 21:53:20 +0000 Subject: Removes loading assertions --- .../environments/components/environment_item.js.es6 | 2 +- .../environments/environments_bundle.js.es6 | 1 - spec/features/environments_spec.rb | 18 ------------------ 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 436ac365788..633a71ea9a1 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -86,7 +86,7 @@ * Verifies is the given environment has manual actions. * Used to verify if we should render them or nor. * - * @returns {Boolean} description + * @returns {Boolean} */ hasManualActions() { return this.$options.hasKey(this.model, 'manual_actions') && this.model.manual_actions.length; diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 1299f64182c..645274a8666 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -31,7 +31,6 @@ $(() => { return fn(item); }).filter(Boolean); - gl.EnvironmentsListApp = new Vue({ el: '#environments-list-view', diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index 62fc56f2f46..edabb97e761 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -12,32 +12,14 @@ feature 'Environments', feature: true, js:true do login_as(user) project.team << [user, role] end - - describe 'Loading environments' do - given!(:environment) { } - given!(:deployment) { } - given!(:manual) { } - - context 'loading environments' do - before do - visit namespace_project_environments_path(project.namespace, project) - end - - scenario 'does show loading spinner' do - expect(page).to have_selector('.environments-list-loading') - end - end - end describe 'when showing environments' do - before do visit namespace_project_environments_path(project.namespace, project) wait_for_vue_resource end context 'without environments' do - scenario 'does show "Available" and "Stopped" tab with links' do expect(page).to have_link('Available') expect(page).to have_link('Stopped') -- cgit v1.2.1 From 9bf6d3abeba3b318741ab7ef0d4513c57f5112be Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 8 Nov 2016 10:33:36 +0000 Subject: Adds a list of environments --- spec/features/environments_spec.rb | 49 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index edabb97e761..595cf28ee77 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -1,17 +1,28 @@ -require 'spec_helper' require 'rails_helper' feature 'Environments', feature: true, js:true do include WaitForVueResource - given(:project) { create(:project) } - given(:user) { create(:user) } - given(:role) { :developer } - + let(:json) { serializer.as_json } + let(:project) { create(:empty_project, :public) } + let(:user) { create(:user) } + let(:role) { :developer } + + let(:serializer) do + described_class + .new(user: user, project: project) + .represent(resource) + end + background do login_as(user) project.team << [user, role] end + + before do + visit namespace_project_environments_path(project.namespace, project) + wait_for_vue_resource + end describe 'when showing environments' do before do @@ -36,15 +47,15 @@ feature 'Environments', feature: true, js:true do end context 'with environments' do - given!(:environment) { create(:environment, project: project) } - + let(:resource) { create_list(:environment, 2) } + scenario 'does show "Available" and "Stopped" tab with links' do expect(page).to have_link('Stopped') expect(page).to have_link('Available') end - scenario 'does show environment name' do - expect(page).to have_link(environment.name) + scenario 'does show environments table' do + expect(page).to have_selector('.table-holder') end scenario 'does show number of available and stopped environments' do @@ -53,20 +64,13 @@ feature 'Environments', feature: true, js:true do end context 'without deployments' do - - before do - visit namespace_project_environments_path(project.namespace, project) - wait_for_vue_resource - end - scenario 'does show no deployments' do expect(page).to have_content('No deployments yet') end end - + context 'with deployments' do - let!(:environment) { create(:environment, project: project) } - given(:deployment) { create(:deployment, environment: environment) } + # TODO add environment with deployment scenario 'does show deployment SHA' do expect(page).to have_link(deployment.short_sha) @@ -142,17 +146,12 @@ feature 'Environments', feature: true, js:true do end context 'can create new environment' do - before do - visit namespace_project_environments_path(project.namespace, project) - wait_for_vue_resource - end - scenario 'does have a New environment button' do expect(page).to have_link('New environment') end end end - + describe 'when showing the environment' do given(:environment) { create(:environment, project: project) } given!(:deployment) { } @@ -246,7 +245,7 @@ feature 'Environments', feature: true, js:true do end end end - + describe 'when creating a new environment' do before do visit namespace_project_environments_path(project.namespace, project) -- cgit v1.2.1 From a31578aa505088a347bfc6ae2483d8c563d1fee9 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 8 Nov 2016 11:25:14 +0000 Subject: Remove unused block --- spec/features/environments_spec.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index 595cf28ee77..d60a6be397d 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -18,11 +18,6 @@ feature 'Environments', feature: true, js:true do login_as(user) project.team << [user, role] end - - before do - visit namespace_project_environments_path(project.namespace, project) - wait_for_vue_resource - end describe 'when showing environments' do before do -- cgit v1.2.1 From 3fef5e66dba055e32dda1ccc887ad630d1e61c87 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 10:55:00 +0000 Subject: Adds template functions Adds commit component --- .../components/environment_item.js.es6 | 185 ++++++++++++++++++++- .../environments/environments_bundle.js.es6 | 4 +- .../javascripts/vue_common_component/commit.js.es6 | 173 +++++++++++++++++++ app/views/projects/environments/index.html.haml | 6 +- .../environments/environments_store_spec.js.es6 | 2 +- 5 files changed, 358 insertions(+), 12 deletions(-) create mode 100644 app/assets/javascripts/vue_common_component/commit.js.es6 diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 633a71ea9a1..29c0316228e 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,4 +1,6 @@ +/*= require vue_common_component/commit /* globals Vue */ + (() => { /** * Envrionment Item Component @@ -16,7 +18,9 @@ gl.environmentsList.EnvironmentItem = Vue.component('environment-item', { - template: '#environment-item-template', + components: { + 'commit-component': window.gl.commitComponent, + }, props: { model: Object, @@ -25,6 +29,9 @@ data() { return { open: false, + rowClass: { + 'children-row': this.model['vue-isChildren'], + }, }; }, @@ -38,7 +45,8 @@ * @returns {Boolean} */ isFolder() { - return this.$options.hasKey(this.model, 'children') && this.model.children.length > 0; + return this.$options.hasKey(this.model, 'children') && + this.model.children.length > 0; }, /** @@ -58,7 +66,8 @@ * @returns {Boolean} The number of environments for the current folder */ childrenCounter() { - return this.$options.hasKey(this.model, 'children') && this.model.children.length; + return this.$options.hasKey(this.model, 'children') && + this.model.children.length; }, /** @@ -68,7 +77,8 @@ * @returns {Boolean} */ isLast() { - return this.$options.hasKey(this.model, 'last_deployment') && this.model.last_deployment['last?']; + return this.$options.hasKey(this.model, 'last_deployment') && + this.model.last_deployment['last?']; }, /** @@ -89,7 +99,8 @@ * @returns {Boolean} */ hasManualActions() { - return this.$options.hasKey(this.model, 'manual_actions') && this.model.manual_actions.length; + return this.$options.hasKey(this.model, 'manual_actions') && + this.model.manual_actions.length; }, /** @@ -108,7 +119,9 @@ * @returns {Boolean} */ canRetry() { - return this.hasLastDeploymentKey && this.model.last_deployment && this.$options.hasKey(this.model.last_deployment, 'deployable'); + return this.hasLastDeploymentKey && + this.model.last_deployment && + this.$options.hasKey(this.model.last_deployment, 'deployable'); }, /** @@ -134,6 +147,85 @@ return parsedAction; }); }, + + userImageAltDescription() { + return `${this.model.last_deployment.user.username}'s avatar'`; + }, + + + /** + * 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; + } + }, + + /** + * If provided, returns the commit ref. + * + * @returns {Object|Undefined} + */ + commitRef() { + if (this.model.last_deployment && this.model.last_deployment.ref) { + return this.model.last_deployment.ref + } + }, + + /** + * If provided, returns the commit url. + * + * @returns {String|Undefined} + */ + commitUrl() { + if (this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.commit_url) { + return this.model.last_deployment.commit.commit_url; + } + }, + + /** + * If provided, returns the commit short sha. + * + * @returns {String|Undefined} + */ + commitShortSha() { + if (this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.short_id) { + return this.model.last_deployment.commit.short_id + } + }, + + /** + * If provided, returns the commit title. + * + * @returns {String|Undefined} + */ + commitTitle(){ + if (this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.title) { + return this.model.last_deployment.commit.title + } + }, + + /** + * If provided, returns the commit tag. + * + * @returns {Object|Undefined} + */ + commitAuthor(){ + if (this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.author) { + return this.model.last_deployment.commit.author; + } + }, }, /** @@ -149,7 +241,6 @@ }, methods: { - /** * Toggles the visibility of a folders' children. */ @@ -159,5 +250,85 @@ } }, }, + + template: ` + + + + {{model.name}} + + + + + + + + {{model.name}} + + + {{childrenCounter}} + + + + + + + #{{model.last_deployment.iid}} + + + by + + + + + + + + + + {{model.last_deployment.deployable.name}} #{{model.last_deployment.deployable.id}} + + + + +
+ + +
+

+ No deployments yet +

+ + + + + {{createdDate}} + + + + +
+ +
+ + + + + + `, }); })(); diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 645274a8666..1192f3e5bfb 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -68,8 +68,8 @@ $(() => { * Toggles loading property. */ ready() { - gl.environmentsService.all().then((resp) => { - Store.storeEnvironments(resp.json()); + gl.environmentsService.all().then(resp => resp.json()).then((json) => { + Store.storeEnvironments(json); this.loading = false; }); }, diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6 new file mode 100644 index 00000000000..8847d1d0184 --- /dev/null +++ b/app/assets/javascripts/vue_common_component/commit.js.es6 @@ -0,0 +1,173 @@ +/*= require vue +/* global Vue */ +(() => { + window.gl = window.gl || {}; + + window.gl.commitComponent = Vue.component('commit-component', { + + props: { + /** + * Indicates the existance of a tag. + * Used to render the correct icon, if true will render `fa-tag` icon, + * if false will render `fa-code-fork` icon. + */ + tag: { + type: Boolean, + required: false, + default: false, + }, + + /** + * If provided is used to render the branch name and url. + * Should contain the following properties: + * name + * ref_url + */ + ref: { + type: Object, + required: false, + default: () => {}, + }, + + /** + * Used to link to the commit sha. + */ + commit_url: { + type: String, + required: false, + default: '', + }, + + /** + * Used to show the commit short_sha that links to the commit url. + */ + short_sha: { + type: String, + required: false, + default: '', + }, + + /** + * If provided shows the commit tile. + */ + title: { + type: String, + required: false, + default: '', + }, + + /** + * If provided renders information about the author of the commit. + * When provided should include: + * `avatar_url` to render the avatar icon + * `web_url` to link to user profile + * `username` to render alt and title tags + */ + author: { + type: Object, + required: false, + default: () => {}, + }, + }, + + computed: { + /** + * Used to verify if all the properties needed to render the commit + * ref section were provided. + * + * TODO: Improve this! Use lodash _.has when we have it. + * + * @returns {Boolean} + */ + hasRef() { + return this.ref && this.ref.name && this.ref.ref_url; + }, + + /** + * Used to verify if all the properties needed to render the commit + * author section were provided. + * + * TODO: Improve this! Use lodash _.has when we have it. + * + * @returns {Boolean} + */ + hasAuthor() { + return this.author && + this.author.avatar_url && + this.author.web_url && + this.author.username; + }, + + /** + * If information about the author is provided will return a string + * to be rendered as the alt attribute of the img tag. + * + * @returns {String} + */ + userImageAltDescription() { + return this.author && + this.author.username ? `${this.author.username}'s avatar` : null; + }, + }, + + /** + * In order to reuse the svg instead of copy and paste in this template the html_safe + * we need to render it outside this component using =custom_icon partial. + * Make sure it has this structure: + * .commit-icon-svg.hidden + * svg + * + * TODO: Find a better way to include SVG + */ + ready() { + const commitIconContainer = document.querySelector('.branch-commit .commit-icon-container'); + const commitIcon = document.querySelector('.commit-icon-svg.hidden svg'); + + if (commitIconContainer && commitIcon) { + commitIconContainer.appendChild(commitIcon); + } + }, + + template: ` +
+ +
+ + +
+ + + {{ref.name}} + + +
+ +
+ + + {{short_sha}} + + +

+ + + + + + + + {{title}} + + + + Cant find HEAD commit for this branch + +

+
+ `, + }); +})(); diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index fa88d59e3ca..61a3d76274e 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -40,7 +40,10 @@ - if can?(current_user, :create_environment, @project) = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do New environment - + + .commit-icon-svg.hidden + = custom_icon("icon_commit") + .table-holder{ "v-if" => "!loading && state.environments.length" } %table.table.ci-table.environments %thead @@ -53,4 +56,3 @@ %tbody %tr{"is" => "environment-item", "v-for" => "model in filteredEnvironments", ":model" => "model"} -=render "projects/environments/components/environment" diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index bc16c90e9be..5e35949ac9c 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -47,7 +47,7 @@ expect(environments[1].name).toBe('review'); expect(environments[1].children[0].name).toBe('test-environment'); expect(environments[1].children[1].name).toBe('test-environment-1'); - expect(environments[2].name).toBe('review_app') + expect(environments[2].name).toBe('review_app'); }); }); }); -- cgit v1.2.1 From de8a6c874b86ae5363864855aed24d8d33005c06 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 11:23:04 +0000 Subject: Removes jQuery timeago --- .../javascripts/environments/components/environment_item.js.es6 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 29c0316228e..05f0483c198 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -130,7 +130,9 @@ * @returns {String} */ createdDate() { - return $.timeago(this.model.created_at); + const timeagoInstance = new timeago(); + + return timeagoInstance.format(this.model.created_at); }, /** -- cgit v1.2.1 From 5cfc2d0c1ce3ec170a531e5da39703698c4f8e59 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 11:26:27 +0000 Subject: Fix eslint --- .../components/environment_item.js.es6 | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 05f0483c198..d029cc8c92e 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,5 +1,6 @@ /*= require vue_common_component/commit -/* globals Vue */ +/*= require timeago +/* globals Vue, timeago */ (() => { /** @@ -153,8 +154,7 @@ userImageAltDescription() { return `${this.model.last_deployment.user.username}'s avatar'`; }, - - + /** * If provided, returns the commit tag. * @@ -164,6 +164,7 @@ if (this.model.last_deployment && this.model.last_deployment.tag) { return this.model.last_deployment.tag; } + return undefined; }, /** @@ -173,10 +174,11 @@ */ commitRef() { if (this.model.last_deployment && this.model.last_deployment.ref) { - return this.model.last_deployment.ref + return this.model.last_deployment.ref; } + return undefined; }, - + /** * If provided, returns the commit url. * @@ -188,6 +190,7 @@ this.model.last_deployment.commit.commit_url) { return this.model.last_deployment.commit.commit_url; } + return undefined; }, /** @@ -199,8 +202,9 @@ if (this.model.last_deployment && this.model.last_deployment.commit && this.model.last_deployment.commit.short_id) { - return this.model.last_deployment.commit.short_id + return this.model.last_deployment.commit.short_id; } + return undefined; }, /** @@ -208,12 +212,13 @@ * * @returns {String|Undefined} */ - commitTitle(){ + commitTitle() { if (this.model.last_deployment && this.model.last_deployment.commit && this.model.last_deployment.commit.title) { - return this.model.last_deployment.commit.title + return this.model.last_deployment.commit.title; } + return undefined; }, /** @@ -221,12 +226,14 @@ * * @returns {Object|Undefined} */ - commitAuthor(){ + commitAuthor() { if (this.model.last_deployment && this.model.last_deployment.commit && this.model.last_deployment.commit.author) { return this.model.last_deployment.commit.author; } + + return undefined; }, }, -- cgit v1.2.1 From 60099d9027e3d7816b1fb8de237dfd70a0c5cb3d Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 15:22:11 +0000 Subject: Adds environments actions component --- .../components/environment_actions.js.es6 | 39 ++++++++++++++++++++++ .../components/environment_item.js.es6 | 1 - .../environments/environments_bundle.js.es6 | 4 ++- app/views/projects/environments/index.html.haml | 2 +- 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/environments/components/environment_actions.js.es6 diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 new file mode 100644 index 00000000000..6b0555360b5 --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_actions.js.es6 @@ -0,0 +1,39 @@ +/*= require vue +/* global Vue */ + +(() => { + window.gl = window.gl || {}; + window.gl.environmentsList = window.gl.environmentsList || {}; + + window.gl.environmentsList.ActionsComponent = Vue.component('actions-component', { + props: { + actions: { + type: Array, + required: false, + default: () => [] + } + }, + + template: ` + + ` + }); +})(); \ No newline at end of file diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index d029cc8c92e..c51ea8707dd 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,5 +1,4 @@ /*= require vue_common_component/commit -/*= require timeago /* globals Vue, timeago */ (() => { diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 1192f3e5bfb..9766bd1da27 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -41,7 +41,9 @@ $(() => { data: { state: Store.state, - endpoint: environmentsListApp.dataset.endpoint, + endpoint: environmentsListApp.dataset.environmentsDataEndpoint, + canCreateDeployment: environmentsListApp.dataset.canCreateDeployment, + canReadEnvironment: environmentsListApp.dataset.canReadEnvironment, loading: true, visibility: 'available', }, diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 61a3d76274e..532b617b7b8 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -5,7 +5,7 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag("environments/environments_bundle.js") -#environments-list-view{ data: environments_list_data, class: container_class } +#environments-list-view{ data: { environments_data: environments_list_data, "can-create-deployment" => can?(current_user, :create_deployment, @environment), "can_read_environment" => can?(current_user, :read_environment, @project)}, class: container_class } .top-area %ul.nav-links{ "v-if" => "!loading" } %li{class: ('active' if @scope.nil?)} -- cgit v1.2.1 From 883f65ec998683ae224ab69eb59ee45569e56f44 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 16:45:45 +0000 Subject: Fix commit icon --- app/assets/javascripts/vue_common_component/commit.js.es6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6 index 8847d1d0184..44f94dffb5c 100644 --- a/app/assets/javascripts/vue_common_component/commit.js.es6 +++ b/app/assets/javascripts/vue_common_component/commit.js.es6 @@ -120,11 +120,11 @@ * TODO: Find a better way to include SVG */ ready() { - const commitIconContainer = document.querySelector('.branch-commit .commit-icon-container'); + const commitIconContainer = this.$el.querySelector('.commit-icon-container'); const commitIcon = document.querySelector('.commit-icon-svg.hidden svg'); if (commitIconContainer && commitIcon) { - commitIconContainer.appendChild(commitIcon); + commitIconContainer.appendChild(commitIcon.cloneNode(true)); } }, -- cgit v1.2.1 From 51e791868666cc7c5f196416f97605f968f69874 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 17:36:42 +0000 Subject: Manual actions --- .../components/environment_actions.js.es6 | 44 +++++++++++++++++----- .../components/environment_item.js.es6 | 21 +++++++++-- .../javascripts/vue_common_component/commit.js.es6 | 2 +- app/views/projects/environments/index.html.haml | 2 + 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 index 6b0555360b5..6d49a10eb0e 100644 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ b/app/assets/javascripts/environments/components/environment_actions.js.es6 @@ -4,28 +4,54 @@ (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; - + window.gl.environmentsList.ActionsComponent = Vue.component('actions-component', { props: { actions: { type: Array, required: false, - default: () => [] + default: () => [], + }, + }, + + /** + * Appends the svg icon that were render in the index page. + * In order to reuse the svg instead of copy and paste in this template + * we need to render it outside this component using =custom_icon partial. + * + * TODO: Remove this when webpack is merged. + * + */ + ready() { + const playIcon = document.querySelector('.play-icon-svg.hidden svg'); + + const dropdownContainer = this.$el.querySelector('.dropdown-play-icon-container'); + const actionContainers = this.$el.querySelectorAll('.action-play-icon-container'); + + if (playIcon) { + dropdownContainer.appendChild(playIcon.cloneNode(true)); + actionContainers.forEach((element) => { + element.appendChild(playIcon.cloneNode(true)); + }); } }, - + template: ` - ` - }); -})(); \ No newline at end of file + `, + }); +})(); diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index c51ea8707dd..4476e7689cd 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,4 +1,5 @@ /*= require vue_common_component/commit +/*= require ./environment_actions /* globals Vue, timeago */ (() => { @@ -19,7 +20,8 @@ gl.environmentsList.EnvironmentItem = Vue.component('environment-item', { components: { - 'commit-component': window.gl.commitComponent, + 'commit-component': window.gl.CommitComponent, + 'actions-component': window.gl.environmentsList.ActionsComponent, }, props: { @@ -135,13 +137,24 @@ return timeagoInstance.format(this.model.created_at); }, + /** + * Verifies if the environment has any manual actions to be rendered. + * + * @returns {Boolean} + */ + hasManualActions() { + return this.model.last_deployment && + this.model.last_deployment.manual_actions && + this.model.last_deployment.manual_actions.length > 0; + }, + /** * Returns the manual actions with the name parsed. * * @returns {Array.} */ manualActions() { - return this.model.manual_actions.map((action) => { + return this.model.last_deployment.manual_actions.map((action) => { const parsedAction = { name: gl.text.humanize(action.name), play_url: action.play_url, @@ -327,7 +340,9 @@
- +
+ +
diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6 index 44f94dffb5c..25c1c27bee7 100644 --- a/app/assets/javascripts/vue_common_component/commit.js.es6 +++ b/app/assets/javascripts/vue_common_component/commit.js.es6 @@ -3,7 +3,7 @@ (() => { window.gl = window.gl || {}; - window.gl.commitComponent = Vue.component('commit-component', { + window.gl.CommitComponent = Vue.component('commit-component', { props: { /** diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 532b617b7b8..050c87b8ab0 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -43,6 +43,8 @@ .commit-icon-svg.hidden = custom_icon("icon_commit") + .play-icon-svg.hidden + = custom_icon("icon_play") .table-holder{ "v-if" => "!loading && state.environments.length" } %table.table.ci-table.environments -- cgit v1.2.1 From 8068d977fe123c1c9a08bceb515a9e77acb39cec Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 17:53:06 +0000 Subject: Adds permissions to actions component --- .../components/environment_item.js.es6 | 31 +++++++++++++++++++--- app/views/projects/environments/index.html.haml | 8 ++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 4476e7689cd..7ffc289719e 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -24,9 +24,7 @@ 'actions-component': window.gl.environmentsList.ActionsComponent, }, - props: { - model: Object, - }, + props: ['model', 'can-create-deployment', 'can-create-deployment', 'can-read-environment'], data() { return { @@ -247,6 +245,14 @@ return undefined; }, + + canReadEnvironmentParsed() { + return convertToBoolean(this.canReadEnvironment); + }, + + canCreateDeploymentParsed() { + return convertToBoolean(this.canCreateDeployment); + }, }, /** @@ -261,6 +267,19 @@ return {}.hasOwnProperty.call(obj, key); }, + /** + * Converts permission provided as strings to booleans. + * @param {String} string + * @returns {Boolean} + */ + convertPermissionToBoolean(string) { + if (string === 'true') { + return true; + } + + return false; + }, + methods: { /** * Toggles the visibility of a folders' children. @@ -272,6 +291,10 @@ }, }, + ready() { + debugger; + }, + template: ` @@ -340,7 +363,7 @@
-
+
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 050c87b8ab0..391dc8cdce2 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -5,7 +5,7 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag("environments/environments_bundle.js") -#environments-list-view{ data: { environments_data: environments_list_data, "can-create-deployment" => can?(current_user, :create_deployment, @environment), "can_read_environment" => can?(current_user, :read_environment, @project)}, class: container_class } +#environments-list-view{ data: { environments_data: environments_list_data, "can-create-deployment" => can?(current_user, :create_deployment, @environment), "can-read-environment" => can?(current_user, :read_environment, @project)}, class: container_class } .top-area %ul.nav-links{ "v-if" => "!loading" } %li{class: ('active' if @scope.nil?)} @@ -56,5 +56,9 @@ %th %th.hidden-xs %tbody - %tr{"is" => "environment-item", "v-for" => "model in filteredEnvironments", ":model" => "model"} + %tr{"is" => "environment-item", + "v-for" => "model in filteredEnvironments", + ":model" => "model", + "can-create-deployment" => can?(current_user, :create_deployment, @environment), + "can-read-environment" => can?(current_user, :read_environment, @project)} -- cgit v1.2.1 From 32784d21d36a41f2c22f05b23db68a889b8886c0 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 18:04:57 +0000 Subject: Adds external url component for environment --- .../components/environment_external_url.js.es6 | 22 ++++++++++++++++++++++ .../components/environment_item.js.es6 | 16 ++++++++++------ .../javascripts/vue_common_component/commit.js.es6 | 2 +- 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 app/assets/javascripts/environments/components/environment_external_url.js.es6 diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js.es6 new file mode 100644 index 00000000000..0fd91afb32a --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_external_url.js.es6 @@ -0,0 +1,22 @@ +/*= require vue +/* global Vue */ + +(() => { + window.gl = window.gl || {}; + window.gl.environmentsList = window.gl.environmentsList || {}; + + window.gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', { + props: { + external_url: { + type: String, + default: '', + }, + }, + + template: ` + + + + `, + }); +})(); diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 7ffc289719e..06077c601b5 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,5 +1,6 @@ /*= require vue_common_component/commit /*= require ./environment_actions +/*= require ./environment_external_url /* globals Vue, timeago */ (() => { @@ -22,6 +23,7 @@ components: { 'commit-component': window.gl.CommitComponent, 'actions-component': window.gl.environmentsList.ActionsComponent, + 'external-url-component': window.gl.environmentsList.ExternalUrlComponent, }, props: ['model', 'can-create-deployment', 'can-create-deployment', 'can-read-environment'], @@ -247,11 +249,11 @@ }, canReadEnvironmentParsed() { - return convertToBoolean(this.canReadEnvironment); + return this.$options.convertPermissionToBoolean(this.canReadEnvironment); }, canCreateDeploymentParsed() { - return convertToBoolean(this.canCreateDeployment); + return this.$options.convertPermissionToBoolean(this.canCreateDeployment); }, }, @@ -291,10 +293,6 @@ }, }, - ready() { - debugger; - }, - template: ` @@ -366,6 +364,12 @@
+ +
+ + +
diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6 index 25c1c27bee7..053d08bb089 100644 --- a/app/assets/javascripts/vue_common_component/commit.js.es6 +++ b/app/assets/javascripts/vue_common_component/commit.js.es6 @@ -111,7 +111,7 @@ }, /** - * In order to reuse the svg instead of copy and paste in this template the html_safe + * In order to reuse the svg instead of copy and paste in this template * we need to render it outside this component using =custom_icon partial. * Make sure it has this structure: * .commit-icon-svg.hidden -- cgit v1.2.1 From 05e57a079eba158594f56443f1754eafc122cba6 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 18:52:26 +0000 Subject: Adds rollback and stop component --- .../components/environment_external_url.js.es6 | 2 +- .../components/environment_item.js.es6 | 55 ++++++++++++++++++---- .../components/environment_rollback.js.es6 | 31 ++++++++++++ .../components/environment_stop.js.es6 | 26 ++++++++++ app/assets/stylesheets/pages/environments.scss | 3 +- 5 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 app/assets/javascripts/environments/components/environment_rollback.js.es6 create mode 100644 app/assets/javascripts/environments/components/environment_stop.js.es6 diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js.es6 index 0fd91afb32a..b5d540ea934 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.js.es6 +++ b/app/assets/javascripts/environments/components/environment_external_url.js.es6 @@ -14,7 +14,7 @@ }, template: ` - + `, diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 06077c601b5..07ed282a16d 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,6 +1,9 @@ /*= require vue_common_component/commit /*= require ./environment_actions /*= require ./environment_external_url +/*= require ./environment_stop +/*= require ./environment_rollback + /* globals Vue, timeago */ (() => { @@ -24,6 +27,8 @@ 'commit-component': window.gl.CommitComponent, 'actions-component': window.gl.environmentsList.ActionsComponent, 'external-url-component': window.gl.environmentsList.ExternalUrlComponent, + 'stop-component': window.gl.environmentsList.StopComponent, + 'rollback-component': window.gl.environmentsList.RollbackComponent, }, props: ['model', 'can-create-deployment', 'can-create-deployment', 'can-read-environment'], @@ -248,11 +253,26 @@ return undefined; }, + retryUrl() { + if (this.model.last_deployment && + this.model.last_deployment.deployable && + this.model.last_deployment.deployable.retry_url) { + return this.model.last_deployment.deployable.retry_url; + } + return undefined; + }, + + isLastDeployment() { + return this.model.last_deployment && this.model.last_deployment['last?']; + }, + canReadEnvironmentParsed() { + return true; return this.$options.convertPermissionToBoolean(this.canReadEnvironment); }, canCreateDeploymentParsed() { + return true; return this.$options.convertPermissionToBoolean(this.canCreateDeployment); }, }, @@ -295,7 +315,7 @@ template: ` - + {{model.name}} @@ -313,7 +333,7 @@ - + #{{model.last_deployment.iid}} @@ -329,7 +349,7 @@ - + @@ -337,7 +357,7 @@ - +
- + {{createdDate}} - +
-
- +
+ +
- -
+ +
+ +
+ + +
+ +
+ + +
diff --git a/app/assets/javascripts/environments/components/environment_rollback.js.es6 b/app/assets/javascripts/environments/components/environment_rollback.js.es6 new file mode 100644 index 00000000000..055b0efec56 --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_rollback.js.es6 @@ -0,0 +1,31 @@ +/*= require vue +/* global Vue */ + +(() => { + window.gl = window.gl || {}; + window.gl.environmentsList = window.gl.environmentsList || {}; + + window.gl.environmentsList.RollbackComponent = Vue.component('rollback-component', { + props: { + retry_url: { + type: String, + default: '', + }, + is_last_deployment: { + type: Boolean, + default: true, + }, + }, + + template: ` + + + Re-deploy + + + Rollback + + + `, + }); +})(); diff --git a/app/assets/javascripts/environments/components/environment_stop.js.es6 b/app/assets/javascripts/environments/components/environment_stop.js.es6 new file mode 100644 index 00000000000..c15b669c9c1 --- /dev/null +++ b/app/assets/javascripts/environments/components/environment_stop.js.es6 @@ -0,0 +1,26 @@ +/*= require vue +/* global Vue */ + +(() => { + window.gl = window.gl || {}; + window.gl.environmentsList = window.gl.environmentsList || {}; + + window.gl.environmentsList.StopComponent = Vue.component('stop-component', { + props: { + stop_url: { + type: String, + default: '', + }, + }, + + template: ` + + + + `, + }); +})(); diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 6ce10f1e7ef..e42fa63ba00 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -47,7 +47,8 @@ color: $gl-dark-link-color; } - .stop-env-link { + .stop-env-link, + .external-url { color: $table-text-gray; .stop-env-icon { -- cgit v1.2.1 From 9be7aa0f5e200f8338be8e4c8b0c4a7f72517ced Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 9 Nov 2016 18:54:54 +0000 Subject: Removes unused partials --- .../projects/environments/_environment.html.haml | 35 ------------- .../environments/components/_actions.html.haml | 16 ------ .../environments/components/_commit.html.haml | 27 ---------- .../environments/components/_environment.html.haml | 60 ---------------------- .../components/_external_url.html.haml | 5 -- .../environments/components/_rollback.html.haml | 10 ---- .../environments/components/_stop.html.haml | 7 --- 7 files changed, 160 deletions(-) delete mode 100644 app/views/projects/environments/_environment.html.haml delete mode 100644 app/views/projects/environments/components/_actions.html.haml delete mode 100644 app/views/projects/environments/components/_commit.html.haml delete mode 100644 app/views/projects/environments/components/_environment.html.haml delete mode 100644 app/views/projects/environments/components/_external_url.html.haml delete mode 100644 app/views/projects/environments/components/_rollback.html.haml delete mode 100644 app/views/projects/environments/components/_stop.html.haml diff --git a/app/views/projects/environments/_environment.html.haml b/app/views/projects/environments/_environment.html.haml deleted file mode 100644 index b75d5df4150..00000000000 --- a/app/views/projects/environments/_environment.html.haml +++ /dev/null @@ -1,35 +0,0 @@ -- last_deployment = environment.last_deployment - -%tr.environment - %td - = link_to environment.name, namespace_project_environment_path(@project.namespace, @project, environment) - - %td.deployment-column - - if last_deployment - %span ##{last_deployment.iid} - - if last_deployment.user - by - = user_avatar(user: last_deployment.user, size: 20) - - %td - - if last_deployment && last_deployment.deployable - = link_to [@project.namespace.becomes(Namespace), @project, last_deployment.deployable], class: 'build-link' do - = "#{last_deployment.deployable.name} (##{last_deployment.deployable.id})" - - %td - - if last_deployment - = render 'projects/deployments/commit', deployment: last_deployment - - else - %p.commit-title - No deployments yet - - %td - - if last_deployment - #{time_ago_with_tooltip(last_deployment.created_at)} - - %td.hidden-xs - .pull-right - = render 'projects/environments/external_url', environment: environment - = render 'projects/deployments/actions', deployment: last_deployment - = render 'projects/environments/stop', environment: environment - = render 'projects/deployments/rollback', deployment: last_deployment diff --git a/app/views/projects/environments/components/_actions.html.haml b/app/views/projects/environments/components/_actions.html.haml deleted file mode 100644 index f23fdb72353..00000000000 --- a/app/views/projects/environments/components/_actions.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -- if can?(current_user, :create_deployment, @project) - .inline{ "v-if" => "hasManualActions"} - .dropdown - %a.dropdown-new.btn.btn-default{type: "button", "data-toggle" => "dropdown"} - = custom_icon('icon_play') - = icon('caret-down') - - %ul.dropdown-menu.dropdown-menu-align-right - %li{ "v-for" => "action in manualActions" } - %a{ ":href" => "action.play_url", - "data-method" => "post", - "rel" => "nofollow" } - - = custom_icon('icon_play') - %span - {{action.name}} \ No newline at end of file diff --git a/app/views/projects/environments/components/_commit.html.haml b/app/views/projects/environments/components/_commit.html.haml deleted file mode 100644 index 8233dec7b93..00000000000 --- a/app/views/projects/environments/components/_commit.html.haml +++ /dev/null @@ -1,27 +0,0 @@ -.branch-commit{"v-if" => "!isFolder && model.last_deployment"} - .icon-container{ "v-if" => "model.last_deployment.ref && model.last_deployment.tag" } - =icon("tag") - - .icon-container{ "v-if" => "model.last_deployment.ref && !model.last_deployment.tag" } - =icon("code-fork") - - %a.monospace.branch-name{"v-if" => "model.last_deployment.ref", ":href" => "model.last_deployment.ref.ref_url"} - {{model.last_deployment.ref.name}} - - .icon-container.commit-icon - = custom_icon("icon_commit") - - %a.commit-id.monospace{":href" => "model.last_deployment.commit.commit_url"} - {{model.last_deployment.commit.short_id}} - - %p.commit-title - %span{ "v-if" => "model.last_deployment.commit && model.last_deployment.commit.title"} - %a.avatar-image-container{"v-if" => "model.last_deployment.commit.author", ":href" => "model.last_deployment.commit.author.web_url"} - %img.avatar.has-tooltip.s20{":title" => "model.last_deployment.commit.author.username", - ":alt" => "model.last_deployment.commit.author.username + `'s avatar`", - ":src" => "model.last_deployment.commit.author.avatar_url"} - %a.commit-row-message{":href" => "model.last_deployment.commit.commit_url"} - {{model.last_deployment.commit.title}} - - %span{ "v-if" => "!model.last_deployment.commit.title"} - Cant find HEAD commit for this branch diff --git a/app/views/projects/environments/components/_environment.html.haml b/app/views/projects/environments/components/_environment.html.haml deleted file mode 100644 index 2fecfd85f61..00000000000 --- a/app/views/projects/environments/components/_environment.html.haml +++ /dev/null @@ -1,60 +0,0 @@ -%script#environment-item-template{ "type"=> "text/x-template" } - %tr - %td{"v-bind:class" => "{ 'children-row': isChildren}" } - %a.environment-name{ "v-if" => "!isFolder", - ":href" => "model.environment_url" } - {{model.name}} - - %span.folder-name{ "v-if" => "isFolder", - "@click" => "toggle" } - - %i.folder-icon{ "v-show" => "open" } - =icon ("caret-down") - %i.folder-icon{ "v-show" => "!open" } - =icon("caret-right") - - {{model.name}} - - %span.badge - {{childrenCounter}} - - %td.deployment-column - %span{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.iid" } - = precede "#" do - {{model.last_deployment.iid}} - - %span{ "v-if" => "model.last_deployment.user" } - by - %a{":href" => "model.last_deployment.user.web_url" } - %img.avatar.has-tooltip.s20{ ":src" => "model.last_deployment.user.avatar_url", - ":alt" => "model.last_deployment.user.username + `'s avatar`", - ":title" => "model.last_deployment.user.username"} - - %td - %a.build-link{ "v-if" => "!isFolder && model.last_deployment && model.last_deployment.deployable", - ":href" => "model.last_deployment.deployable.build" } - {{model.last_deployment.deployable.name}} - = precede "#" do - {{model.last_deployment.deployable.id}} - - %td - =render "projects/environments/components/commit" - - %p.commit-title{ "v-if" => "!isFolder && !model.last_deployment" } - No deployments yet - - %td - %span.environment-created-date-timeago{ "v-if" => "!isFolder && model.last_deployment" } - {{createdDate}} - - %td.hidden-xs - .pull-right{ "v-if" => "!isFolder" } - =render "projects/environments/components/external_url" - =render "projects/environments/components/actions" - =render "projects/environments/components/stop" - =render "projects/environments/components/rollback" - - %tr{"v-if" => "open && isFolder", - "is" => "environment-item", - "v-for" => "model in model.children", - ":model" => "model" } diff --git a/app/views/projects/environments/components/_external_url.html.haml b/app/views/projects/environments/components/_external_url.html.haml deleted file mode 100644 index 9b789d0ed5f..00000000000 --- a/app/views/projects/environments/components/_external_url.html.haml +++ /dev/null @@ -1,5 +0,0 @@ --if can?(current_user, :read_environment, @project) - %a.btn.external-url{ "v-if" => "!isFolder && model.external_url", - ":target" => "_blank", - ":href" => "model.external_url"} - = icon("external-link") diff --git a/app/views/projects/environments/components/_rollback.html.haml b/app/views/projects/environments/components/_rollback.html.haml deleted file mode 100644 index e3449c5515e..00000000000 --- a/app/views/projects/environments/components/_rollback.html.haml +++ /dev/null @@ -1,10 +0,0 @@ -- if can?(current_user, :create_deployment, @project) - %a.btn.btn-build{ "v-if" => "canRetry", - ":href" => "model.last_deployment.deployable.retry_url", - "data-method" => "post", - "rel" => "nofollow" } - - %span{ "v-if" => "isLastDeployment" } - Re-deploy - %span{ "v-if" => "!isLastDeployment" } - Rollback diff --git a/app/views/projects/environments/components/_stop.html.haml b/app/views/projects/environments/components/_stop.html.haml deleted file mode 100644 index a7100f15784..00000000000 --- a/app/views/projects/environments/components/_stop.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -- if can?(current_user, :create_deployment, @project) - .inline{ "v-if" => "isStoppable" } - %a.btn.stop-env-link{":href" => "model.environment_url", - "method" => ":post", - "rel" => "nofollow", - "confirm" => "Are you sure you want to stop this environment?"} - = icon("stop", class: "stop-env-icon") -- cgit v1.2.1 From 8cebb71e0a615341b6d3b17214dade0c8c094287 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 10 Nov 2016 15:43:38 +0000 Subject: Add template to environment vue instance --- .../components/environment_item.js.es6 | 31 +----- .../environments/environments_bundle.js.es6 | 106 ++++++++++++++++++++- app/views/projects/environments/index.html.haml | 70 +++----------- 3 files changed, 122 insertions(+), 85 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 07ed282a16d..1451c1f2a56 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -265,16 +265,6 @@ isLastDeployment() { return this.model.last_deployment && this.model.last_deployment['last?']; }, - - canReadEnvironmentParsed() { - return true; - return this.$options.convertPermissionToBoolean(this.canReadEnvironment); - }, - - canCreateDeploymentParsed() { - return true; - return this.$options.convertPermissionToBoolean(this.canCreateDeployment); - }, }, /** @@ -289,19 +279,6 @@ return {}.hasOwnProperty.call(obj, key); }, - /** - * Converts permission provided as strings to booleans. - * @param {String} string - * @returns {Boolean} - */ - convertPermissionToBoolean(string) { - if (string === 'true') { - return true; - } - - return false; - }, - methods: { /** * Toggles the visibility of a folders' children. @@ -381,25 +358,25 @@
-
+
-
+
-
+
-
+
diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 9766bd1da27..7dff4d3ac2a 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -3,7 +3,7 @@ //= require_tree ./stores //= require_tree ./services //= require ./components/environment_item -//= require ../boards/vue_resource_interceptor +//= require ./vue_resource_interceptor /* globals Vue, EnvironmentsService */ /* eslint-disable no-param-reassign */ @@ -44,6 +44,11 @@ $(() => { endpoint: environmentsListApp.dataset.environmentsDataEndpoint, canCreateDeployment: environmentsListApp.dataset.canCreateDeployment, canReadEnvironment: environmentsListApp.dataset.canReadEnvironment, + canCreateEnvironment: environmentsListApp.dataset.canCreateEnvironment, + projectEnvironmentsPath: environmentsListApp.dataset.projectEnvironmentsPath, + projectClosedEnvironmentsPath: environmentsListApp.dataset.projectClosedEnvironmentsPath, + newEnvironmentPath: environmentsListApp.dataset.newEnvironmentPath, + helpPagePath: environmentsListApp.dataset.helpPagePath, loading: true, visibility: 'available', }, @@ -52,6 +57,18 @@ $(() => { filteredEnvironments() { return recursiveMap(filterState(this.visibility), this.state.environments); }, + + scope() { + return this.$options.getQueryParameter('scope'); + }, + + canReadEnvironmentParsed() { + return this.$options.convertPermissionToBoolean(this.canReadEnvironment); + }, + + canCreateDeploymentParsed() { + return this.$options.convertPermissionToBoolean(this.canCreateDeployment); + }, }, init: Store.create.bind(Store), @@ -90,5 +107,92 @@ $(() => { return acc; }, {})[parameter]; }, + + /** + * Converts permission provided as strings to booleans. + * @param {String} string + * @returns {Boolean} + */ + convertPermissionToBoolean(string) { + if (string === 'true') { + return true; + } + + return false; + }, + + template: ` +
+ + +
+
+ +
+ +
+

+ You don't have any environments right now. +

+

+ Environments are places where code gets deployed, such as staging or production. + +
+ + + Read more about environments + + + New Environment + +

+
+ +
+ + + + + + + + + + + + +
EnvironmentLast deploymentBuildCommit
+
+
+
+ `, }); }); diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 391dc8cdce2..be4fc4dcb1b 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -5,60 +5,16 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag("environments/environments_bundle.js") -#environments-list-view{ data: { environments_data: environments_list_data, "can-create-deployment" => can?(current_user, :create_deployment, @environment), "can-read-environment" => can?(current_user, :read_environment, @project)}, class: container_class } - .top-area - %ul.nav-links{ "v-if" => "!loading" } - %li{class: ('active' if @scope.nil?)} - = link_to project_environments_path(@project) do - Available - %span.badge.js-available-environments-count - {{state.availableCounter}} - - %li{class: ('active' if @scope == 'stopped')} - = link_to project_environments_path(@project, scope: :stopped) do - Stopped - %span.badge.js-stopped-environments-count - {{state.stoppedCounter}} - - - if can?(current_user, :create_environment, @project) - .nav-controls{ "v-if" => "!loading" } - = link_to new_namespace_project_environment_path(@project.namespace, @project), class: "btn btn-create" do - New environment - - .environments-container - .environments-list-loading.text-center{ "v-if" => "loading" } - = icon("spinner spin") - - .blank-state.blank-state-no-icon{ "v-if" => "!loading && !state.environments.length" } - %h2.blank-state-title - You don't have any environments right now. - %p.blank-state-text - Environments are places where code gets deployed, such as staging or production. - %br - = succeed "." do - = link_to "Read more about environments", help_page_path("ci/environments") - - if can?(current_user, :create_environment, @project) - = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do - New environment - - .commit-icon-svg.hidden - = custom_icon("icon_commit") - .play-icon-svg.hidden - = custom_icon("icon_play") - - .table-holder{ "v-if" => "!loading && state.environments.length" } - %table.table.ci-table.environments - %thead - %th Environment - %th Last Deployment - %th Build - %th Commit - %th - %th.hidden-xs - %tbody - %tr{"is" => "environment-item", - "v-for" => "model in filteredEnvironments", - ":model" => "model", - "can-create-deployment" => can?(current_user, :create_deployment, @environment), - "can-read-environment" => can?(current_user, :read_environment, @project)} - +.commit-icon-svg.hidden + = custom_icon("icon_commit") +.play-icon-svg.hidden + = custom_icon("icon_play") + +#environments-list-view{ data: { environments_data: environments_list_data, + "can-create-deployment" => can?(current_user, :create_deployment, @environment), + "can-read-environment" => can?(current_user, :read_environment, @project), + "can-create-environmnet" => can?(current_user, :create_environment, @project), + "project-environments-path" => project_environments_path(@project), + "project-closed-environments-path" => project_environments_path(@project, scope: :stopped), + "new-environment-path" => new_namespace_project_environment_path(@project.namespace, @project), + "help-page-path" => help_page_path("ci/environments")}, class: container_class } -- cgit v1.2.1 From 30c6a7d3acf658253af158ff7069081cf4b109ad Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 10 Nov 2016 18:58:35 +0000 Subject: Adds tests Adds tests. Changes instance into a constructor Adds tests for environments component Adds tests assertations Adds external URL test Adds tests for Rollback component Adds tests for stop component Adds tests for actions component Fix environment item Init environment item tests --- .../environments/components/environment.js.es6 | 190 ++++++++++++++++++++ .../components/environment_item.js.es6 | 23 +-- .../components/environment_stop.js.es6 | 14 +- .../environments/environments_bundle.js.es6 | 197 ++------------------- .../environments/stores/environments_store.js.es6 | 115 ++++++++++++ .../environments/stores/environmnets_store.js.es6 | 113 ------------ .../environments/vue_resource_interceptor.js.es6 | 13 ++ app/views/projects/environments/index.html.haml | 2 +- spec/features/environments_spec.rb | 4 + .../environments/environment_actions_spec.js.es6 | 37 ++++ .../environment_external_url_spec.js.es6 | 22 +++ .../environments/environment_item_spec.js.es6 | 157 ++++++++++++++++ .../environments/environment_rollback_spec.js.es6 | 48 +++++ .../environments/environment_spec.js.es6 | 172 ++++++++++++++++++ .../environments/environment_stop_spec.js.es6 | 34 ++++ .../fixtures/environments/element.html.haml | 1 + .../fixtures/environments/environments.html.haml | 9 + .../environments_no_permission.html.haml | 9 + .../fixtures/environments/table.html.haml | 11 ++ .../vue_common_components/commit_spec.js.es6 | 89 ++++++++++ 20 files changed, 938 insertions(+), 322 deletions(-) create mode 100644 app/assets/javascripts/environments/components/environment.js.es6 create mode 100644 app/assets/javascripts/environments/stores/environments_store.js.es6 delete mode 100644 app/assets/javascripts/environments/stores/environmnets_store.js.es6 create mode 100644 app/assets/javascripts/environments/vue_resource_interceptor.js.es6 create mode 100644 spec/javascripts/environments/environment_actions_spec.js.es6 create mode 100644 spec/javascripts/environments/environment_external_url_spec.js.es6 create mode 100644 spec/javascripts/environments/environment_item_spec.js.es6 create mode 100644 spec/javascripts/environments/environment_rollback_spec.js.es6 create mode 100644 spec/javascripts/environments/environment_spec.js.es6 create mode 100644 spec/javascripts/environments/environment_stop_spec.js.es6 create mode 100644 spec/javascripts/fixtures/environments/element.html.haml create mode 100644 spec/javascripts/fixtures/environments/environments.html.haml create mode 100644 spec/javascripts/fixtures/environments/environments_no_permission.html.haml create mode 100644 spec/javascripts/fixtures/environments/table.html.haml create mode 100644 spec/javascripts/vue_common_components/commit_spec.js.es6 diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 new file mode 100644 index 00000000000..9cdc17e8589 --- /dev/null +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -0,0 +1,190 @@ +//= require vue +//= require vue-resource +//= require_tree ../services/ +//= require ./environment_item + +/* globals Vue, EnvironmentsService */ +/* eslint-disable no-param-reassign */ + +$(() => { + window.gl = window.gl || {}; + + const filterState = state => environment => environment.state === state && environment; + + // recursiveMap :: (Function, Array) -> Array + const recursiveMap = (fn, arr) => arr.map((item) => { + if (item.children) { + const filteredChildren = recursiveMap(fn, item.children).filter(Boolean); + if (filteredChildren.length) { + item.children = filteredChildren; + return item; + } + } + return fn(item); + }).filter(Boolean); + + window.gl.environmentsList.EnvironmentsComponent = Vue.extend({ + props: ['store'], + + components: { + 'environment-item': window.gl.environmentsList.EnvironmentItem, + }, + + data() { + const environmentsListApp = document.querySelector('#environments-list-view'); + + return { + state: this.store.state, + endpoint: environmentsListApp.dataset.environmentsDataEndpoint, + canCreateDeployment: environmentsListApp.dataset.canCreateDeployment, + canReadEnvironment: environmentsListApp.dataset.canReadEnvironment, + canCreateEnvironment: environmentsListApp.dataset.canCreateEnvironment, + projectEnvironmentsPath: environmentsListApp.dataset.projectEnvironmentsPath, + projectStoppedEnvironmentsPath: environmentsListApp.dataset.projectStoppedEnvironmentsPath, + newEnvironmentPath: environmentsListApp.dataset.newEnvironmentPath, + helpPagePath: environmentsListApp.dataset.helpPagePath, + loading: true, + visibility: 'available', + }; + }, + + computed: { + filteredEnvironments() { + return recursiveMap(filterState(this.visibility), this.state.environments); + }, + + scope() { + return this.$options.getQueryParameter('scope'); + }, + + canReadEnvironmentParsed() { + return this.$options.convertPermissionToBoolean(this.canReadEnvironment); + }, + + canCreateDeploymentParsed() { + return this.$options.convertPermissionToBoolean(this.canCreateDeployment); + }, + }, + + created() { + window.gl.environmentsService = new EnvironmentsService(this.endpoint); + + const scope = this.$options.getQueryParameter('scope'); + if (scope) { + this.visibility = scope; + } + }, + + /** + * Fetches all the environmnets and stores them. + * Toggles loading property. + */ + ready() { + window.gl.environmentsService.all().then(resp => resp.json()).then((json) => { + this.store.storeEnvironments(json); + this.loading = false; + }); + }, + + /** + * Transforms the url parameter into an object and + * returns the one requested. + * + * @param {String} param + * @returns {String} The value of the requested parameter. + */ + getQueryParameter(parameter) { + return window.location.search.substring(1).split('&').reduce((acc, param) => { + const paramSplited = param.split('='); + acc[paramSplited[0]] = paramSplited[1]; + return acc; + }, {})[parameter]; + }, + + /** + * Converts permission provided as strings to booleans. + * @param {String} string + * @returns {Boolean} + */ + convertPermissionToBoolean(string) { + if (string === 'true') { + return true; + } + return false; + }, + + template: ` +
+ + +
+
+ +
+ +
+

+ You don't have any environments right now. +

+

+ Environments are places where code gets deployed, such as staging or production. + +
+ + + Read more about environments + + + New Environment + +

+
+ +
+ + + + + + + + + + + + +
EnvironmentLast deploymentBuildCommit
+
+
+
+ `, + }); +}); diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 1451c1f2a56..ebe31cbc26b 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -31,7 +31,7 @@ 'rollback-component': window.gl.environmentsList.RollbackComponent, }, - props: ['model', 'can-create-deployment', 'can-create-deployment', 'can-read-environment'], + props: ['model', 'can-create-deployment', 'can-read-environment'], data() { return { @@ -107,7 +107,7 @@ */ hasManualActions() { return this.$options.hasKey(this.model, 'manual_actions') && - this.model.manual_actions.length; + this.model.manual_actions.length > 0; }, /** @@ -142,17 +142,6 @@ return timeagoInstance.format(this.model.created_at); }, - /** - * Verifies if the environment has any manual actions to be rendered. - * - * @returns {Boolean} - */ - hasManualActions() { - return this.model.last_deployment && - this.model.last_deployment.manual_actions && - this.model.last_deployment.manual_actions.length > 0; - }, - /** * Returns the manual actions with the name parsed. * @@ -359,25 +348,25 @@
-
-
-
- diff --git a/app/assets/javascripts/environments/components/environment_stop.js.es6 b/app/assets/javascripts/environments/components/environment_stop.js.es6 index c15b669c9c1..1ae02d8080c 100644 --- a/app/assets/javascripts/environments/components/environment_stop.js.es6 +++ b/app/assets/javascripts/environments/components/environment_stop.js.es6 @@ -13,12 +13,18 @@ }, }, + methods: { + openConfirmDialog() { + return window.confirm('Are you sure you want to stop this environment?'); + }, + }, + template: ` - + rel="nofollow"> `, diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 7dff4d3ac2a..20eee7976ec 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -1,198 +1,21 @@ //= require vue -//= require vue-resource -//= require_tree ./stores -//= require_tree ./services -//= require ./components/environment_item +//= require_tree ./stores/ +//= require ./components/environment //= require ./vue_resource_interceptor -/* globals Vue, EnvironmentsService */ -/* eslint-disable no-param-reassign */ -$(() => { - const environmentsListApp = document.getElementById('environments-list-view'); - const Store = gl.environmentsList.EnvironmentsStore; +$(() => { window.gl = window.gl || {}; - if (gl.EnvironmentsListApp) { - gl.EnvironmentsListApp.$destroy(true); + if (window.gl.EnvironmentsListApp) { + window.gl.EnvironmentsListApp.$destroy(true); } + const Store = window.gl.environmentsList.EnvironmentsStore; - const filterState = state => environment => environment.state === state && environment; - - // recursiveMap :: (Function, Array) -> Array - const recursiveMap = (fn, arr) => arr.map((item) => { - if (item.children) { - const filteredChildren = recursiveMap(fn, item.children).filter(Boolean); - if (filteredChildren.length) { - item.children = filteredChildren; - return item; - } - } - return fn(item); - }).filter(Boolean); - - gl.EnvironmentsListApp = new Vue({ - - el: '#environments-list-view', - - components: { - item: gl.environmentsList.EnvironmentItem, - }, - - data: { - state: Store.state, - endpoint: environmentsListApp.dataset.environmentsDataEndpoint, - canCreateDeployment: environmentsListApp.dataset.canCreateDeployment, - canReadEnvironment: environmentsListApp.dataset.canReadEnvironment, - canCreateEnvironment: environmentsListApp.dataset.canCreateEnvironment, - projectEnvironmentsPath: environmentsListApp.dataset.projectEnvironmentsPath, - projectClosedEnvironmentsPath: environmentsListApp.dataset.projectClosedEnvironmentsPath, - newEnvironmentPath: environmentsListApp.dataset.newEnvironmentPath, - helpPagePath: environmentsListApp.dataset.helpPagePath, - loading: true, - visibility: 'available', - }, - - computed: { - filteredEnvironments() { - return recursiveMap(filterState(this.visibility), this.state.environments); - }, - - scope() { - return this.$options.getQueryParameter('scope'); - }, - - canReadEnvironmentParsed() { - return this.$options.convertPermissionToBoolean(this.canReadEnvironment); - }, - - canCreateDeploymentParsed() { - return this.$options.convertPermissionToBoolean(this.canCreateDeployment); - }, + window.gl.EnvironmentsListApp = new window.gl.environmentsList.EnvironmentsComponent({ + el: document.querySelector('#environments-list-view'), + propsData: { + store: Store.create(), }, - - init: Store.create.bind(Store), - - created() { - gl.environmentsService = new EnvironmentsService(this.endpoint); - - const scope = this.$options.getQueryParameter('scope'); - if (scope) { - this.visibility = scope; - } - }, - - /** - * Fetches all the environmnets and stores them. - * Toggles loading property. - */ - ready() { - gl.environmentsService.all().then(resp => resp.json()).then((json) => { - Store.storeEnvironments(json); - this.loading = false; - }); - }, - - /** - * Transforms the url parameter into an object and - * returns the one requested. - * - * @param {String} param - * @returns {String} The value of the requested parameter. - */ - getQueryParameter(parameter) { - return window.location.search.substring(1).split('&').reduce((acc, param) => { - const paramSplited = param.split('='); - acc[paramSplited[0]] = paramSplited[1]; - return acc; - }, {})[parameter]; - }, - - /** - * Converts permission provided as strings to booleans. - * @param {String} string - * @returns {Boolean} - */ - convertPermissionToBoolean(string) { - if (string === 'true') { - return true; - } - - return false; - }, - - template: ` -
- - -
-
- -
- -
-

- You don't have any environments right now. -

-

- Environments are places where code gets deployed, such as staging or production. - -
- - - Read more about environments - - - New Environment - -

-
- -
- - - - - - - - - - - - -
EnvironmentLast deploymentBuildCommit
-
-
-
- `, }); }); diff --git a/app/assets/javascripts/environments/stores/environments_store.js.es6 b/app/assets/javascripts/environments/stores/environments_store.js.es6 new file mode 100644 index 00000000000..b8fe25ef313 --- /dev/null +++ b/app/assets/javascripts/environments/stores/environments_store.js.es6 @@ -0,0 +1,115 @@ +/* eslint-disable no-param-reassign */ +(() => { + window.gl = window.gl || {}; + window.gl.environmentsList = window.gl.environmentsList || {}; + + gl.environmentsList.EnvironmentsStore = { + state: {}, + + create() { + this.state.environments = []; + this.state.stoppedCounter = 0; + this.state.availableCounter = 0; + + return this; + }, + + /** + * In order to display a tree view we need to modify the received + * data in to a tree structure based on `environment_type` + * sorted alphabetically. + * In each children a `vue-` property will be added. This property will be + * used to know if an item is a children mostly for css purposes. This is + * needed because the children row is a fragment instance and therfore does + * not accept non-prop attributes. + * + * + * @example + * it will transform this: + * [ + * { name: "environment", environment_type: "review" }, + * { name: "environment_1", environment_type: null } + * { name: "environment_2, environment_type: "review" } + * ] + * into this: + * [ + * { name: "review", children: + * [ + * { name: "environment", environment_type: "review", vue-isChildren: true}, + * { name: "environment_2", environment_type: "review", vue-isChildren: true} + * ] + * }, + * {name: "environment_1", environment_type: null} + * ] + * + * + * @param {Array} environments List of environments. + * @returns {Array} Tree structured array with the received environments. + */ + storeEnvironments(environments = []) { + this.state.stoppedCounter = this.countByState(environments, 'stopped'); + this.state.availableCounter = this.countByState(environments, 'available'); + + const environmentsTree = environments.reduce((acc, environment) => { + if (environment.environment_type !== null) { + const occurs = acc.filter(element => element.children && + element.name === environment.environment_type); + + environment['vue-isChildren'] = true; + + if (occurs.length) { + acc[acc.indexOf(occurs[0])].children.push(environment); + acc[acc.indexOf(occurs[0])].children.sort(this.sortByName); + } else { + acc.push({ + name: environment.environment_type, + children: [environment], + }); + } + } else { + acc.push(environment); + } + + return acc; + }, []).sort(this.sortByName); + + this.state.environments = environmentsTree; + + return environmentsTree; + }, + + /** + * Given an array of environments, returns the number of environments + * that have the given state. + * + * @param {Array} environments + * @param {String} state + * @returns {Number} + */ + countByState(environments, state) { + return environments.filter(env => env.state === state).length; + }, + + /** + * Sorts the two objects provided by their name. + * + * @param {Object} a + * @param {Object} b + * @returns {Number} + */ + sortByName(a, b) { + const nameA = a.name.toUpperCase(); + const nameB = b.name.toUpperCase(); + + if (nameA < nameB) { + return -1; + } + + if (nameA > nameB) { + return 1; + } + + return 0; + }, + }; +})(); diff --git a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 b/app/assets/javascripts/environments/stores/environmnets_store.js.es6 deleted file mode 100644 index ef0188c15bf..00000000000 --- a/app/assets/javascripts/environments/stores/environmnets_store.js.es6 +++ /dev/null @@ -1,113 +0,0 @@ -/* eslint-disable no-param-reassign */ -(() => { - window.gl = window.gl || {}; - window.gl.environmentsList = window.gl.environmentsList || {}; - - gl.environmentsList.EnvironmentsStore = { - state: {}, - - create() { - this.state.environments = []; - this.state.stoppedCounter = 0; - this.state.availableCounter = 0; - }, - - /** - * In order to display a tree view we need to modify the received - * data in to a tree structure based on `environment_type` - * sorted alphabetically. - * In each children a `vue-` property will be added. This property will be - * used to know if an item is a children mostly for css purposes. This is - * needed because the children row is a fragment instance and therfore does - * not accept non-prop attributes. - * - * - * @example - * it will transform this: - * [ - * { name: "environment", environment_type: "review" }, - * { name: "environment_1", environment_type: null } - * { name: "environment_2, environment_type: "review" } - * ] - * into this: - * [ - * { name: "review", children: - * [ - * { name: "environment", environment_type: "review", vue-isChildren: true}, - * { name: "environment_2", environment_type: "review", vue-isChildren: true} - * ] - * }, - * {name: "environment_1", environment_type: null} - * ] - * - * - * @param {Array} environments List of environments. - * @returns {Array} Tree structured array with the received environments. - */ - storeEnvironments(environments = []) { - this.state.stoppedCounter = this.countByState(environments, 'stopped'); - this.state.availableCounter = this.countByState(environments, 'available'); - - const environmentsTree = environments.reduce((acc, environment) => { - if (environment.environment_type !== null) { - const occurs = acc.filter(element => element.children && - element.name === environment.environment_type); - - environment['vue-isChildren'] = true; - - if (occurs.length) { - acc[acc.indexOf(occurs[0])].children.push(environment); - acc[acc.indexOf(occurs[0])].children.sort(this.sortByName); - } else { - acc.push({ - name: environment.environment_type, - children: [environment], - }); - } - } else { - acc.push(environment); - } - - return acc; - }, []).sort(this.sortByName); - - this.state.environments = environmentsTree; - - return environmentsTree; - }, - - /** - * Given an array of environments, returns the number of environments - * that have the given state. - * - * @param {Array} environments - * @param {String} state - * @returns {Number} - */ - countByState(environments, state) { - return environments.filter(env => env.state === state).length; - }, - - /** - * Sorts the two objects provided by their name. - * - * @param {Object} a - * @param {Object} b - * @returns {Number} - */ - sortByName(a, b) { - const nameA = a.name.toUpperCase(); - const nameB = b.name.toUpperCase(); - - if (nameA < nameB) { - return -1; - } - - if (nameA > nameB) { - return 1; - } - - return 0; - }, - }; -})(); diff --git a/app/assets/javascripts/environments/vue_resource_interceptor.js.es6 b/app/assets/javascripts/environments/vue_resource_interceptor.js.es6 new file mode 100644 index 00000000000..d19a5969f96 --- /dev/null +++ b/app/assets/javascripts/environments/vue_resource_interceptor.js.es6 @@ -0,0 +1,13 @@ +/* eslint-disable */ +Vue.http.interceptors.push((request, next) => { + Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1; + + next(function (response) { + console.log("this is the repsponse", JSON.stringify(response, null, ' ')); + if (typeof response.data === "string") { + response.data = JSON.parse(response.data) + } + + Vue.activeResources--; + }); +}); diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index be4fc4dcb1b..c47f1a21efa 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -15,6 +15,6 @@ "can-read-environment" => can?(current_user, :read_environment, @project), "can-create-environmnet" => can?(current_user, :create_environment, @project), "project-environments-path" => project_environments_path(@project), - "project-closed-environments-path" => project_environments_path(@project, scope: :stopped), + "project-stopped-environments-path" => project_environments_path(@project, scope: :stopped), "new-environment-path" => new_namespace_project_environment_path(@project.namespace, @project), "help-page-path" => help_page_path("ci/environments")}, class: container_class } diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index d60a6be397d..f4c0b093246 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -43,6 +43,10 @@ feature 'Environments', feature: true, js:true do context 'with environments' do let(:resource) { create_list(:environment, 2) } + before do + endpoint = namespace_project_environments_path(project.namespace, project) + stub_request(:any, endpoint).to_return(body: [{"name": "test"}]) + end scenario 'does show "Available" and "Stopped" tab with links' do expect(page).to have_link('Stopped') diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 new file mode 100644 index 00000000000..1097582a8e9 --- /dev/null +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -0,0 +1,37 @@ +//= require vue +//= require environments/components/environment_actions + +describe('Actions Component', () => { + fixture.preload('environments/element.html'); + + beforeEach(() => { + fixture.load('environments/element.html'); + }); + + it('Should render a dropdown with the provided actions', () => { + const actionsMock = [ + { + name: 'bar', + play_url: 'https://gitlab.com/play', + }, + { + name: 'foo', + play_url: '#', + }, + ]; + + const component = new window.gl.environmentsList.ActionsComponent({ + el: document.querySelector('.test-dom-element'), + propsData: { + actions: actionsMock, + }, + }); + + expect( + component.$el.querySelectorAll('.dropdown-menu li').length + ).toEqual(actionsMock.length); + expect( + component.$el.querySelector('.dropdown-menu li a').getAttribute('href') + ).toEqual(actionsMock[0].play_url); + }); +}); diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 new file mode 100644 index 00000000000..156506ef28f --- /dev/null +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -0,0 +1,22 @@ +//= require vue +//= require environments/components/environment_external_url + +describe('External URL Component', () => { + fixture.preload('environments/element.html'); + beforeEach(() => { + fixture.load('environments/element.html'); + }); + + it('should link to the provided external_url', () => { + const externalURL = 'https://gitlab.com'; + const component = new window.gl.environmentsList.ExternalUrlComponent({ + el: document.querySelector('.test-dom-element'), + propsData: { + external_url: externalURL, + }, + }); + + expect(component.$el.getAttribute('href')).toEqual(externalURL); + expect(component.$el.querySelector('fa-external-link')).toBeDefined(); + }); +}); diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 new file mode 100644 index 00000000000..f357e11dc8e --- /dev/null +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -0,0 +1,157 @@ +//= require vue +//= require environments/components/environment_item + +describe('Environment item', () => { + fixture.preload('environments/table.html'); + beforeEach(() => { + fixture.load('environments/table.html'); + }); + + describe('When item is folder', () => { + let mockItem; + let component; + + beforeEach(() => { + mockItem = { + name: 'review', + children: [ + { + name: 'review-app', + id: 1, + state: 'available', + external_url: '', + last_deployment: {}, + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-10T15:55:58.778Z', + }, + { + name: 'production', + id: 2, + state: 'available', + external_url: '', + last_deployment: {}, + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-10T15:55:58.778Z', + }, + ], + }; + + component = new window.gl.environmentsList.EnvironmentItem({ + el: document.querySelector('tr#environment-row'), + propsData: { + model: mockItem, + 'can-create-deployment': false, + 'can-read-environment': true, + }, + }); + }); + + it('Should render clickable folder icon and name', () => { + expect(document.querySelector('.folder-name').textContent).toContain(mockItem.name); + expect(document.querySelector('.folder-icon')).toBeDefined(); + }); + + it('Should render the number of children in a badge', () => { + expect(document.querySelector('.folder-name .badge').textContent).toContain(mockItem.children.length); + }); + + it('Should not render any information other than the name', () => { + }); + + describe('when clicked', () => { + it('Should render child row', () => { + }); + }); + }); + + describe('when item is not folder', () => { + it('should render environment name', () => { + + }); + + describe('With deployment', () => { + it('should render deployment internal id', () => { + + }); + + it('should link to deployment', () => { + + }); + + describe('With user information', () => { + it('should render user avatar with link to profile', () => { + + }); + }); + + describe('With build url', () => { + it('Should link to build url provided', () => { + + }); + + it('Should render deployable name and id', () => { + + }); + }); + + describe('With commit information', () => { + it('should render commit component', () => {}); + }); + + it('Should render timeago created date', () => { + + }); + }); + + describe('Without deployment', () => { + it('should render no deployments information', () => { + + }); + }); + + describe('With manual actions', () => { + describe('With create deployment permission', () => { + it('Should render actions component', () => { + + }); + }); + describe('Without create deployment permission', () => { + it('should not render actions component', () => { + + }); + }); + }); + + describe('With external URL', () => { + it('should render external url component', () => { + + }); + }); + + describe('With stop action', () => { + describe('With create deployment permission', () => { + it('Should render stop action component', () => { + + }); + }); + describe('Without create deployment permission', () => { + it('should not render stop action component', () => { + + }); + }); + }); + + describe('With retry action', () => { + describe('With create deployment permission', () => { + it('Should render rollback component', () => { + + }); + }); + describe('Without create deployment permission', () => { + it('should not render rollback component', () => { + + }); + }); + }); + }); +}); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 new file mode 100644 index 00000000000..29449bbbd9e --- /dev/null +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -0,0 +1,48 @@ +//= require vue +//= require environments/components/environment_rollback +describe('Rollback Component', () => { + fixture.preload('environments/element.html'); + + const retryURL = 'https://gitlab.com/retry'; + + beforeEach(() => { + fixture.load('environments/element.html'); + }); + + it('Should link to the provided retry_url', () => { + const component = new window.gl.environmentsList.RollbackComponent({ + el: document.querySelector('.test-dom-element'), + propsData: { + retry_url: retryURL, + is_last_deployment: true, + }, + }); + + expect(component.$el.getAttribute('href')).toEqual(retryURL); + }); + + it('Should render Re-deploy label when is_last_deployment is true', () => { + const component = new window.gl.environmentsList.RollbackComponent({ + el: document.querySelector('.test-dom-element'), + propsData: { + retry_url: retryURL, + is_last_deployment: true, + }, + }); + + expect(component.$el.querySelector('span').textContent).toContain('Re-deploy'); + }); + + + it('Should render Rollback label when is_last_deployment is false', () => { + const component = new window.gl.environmentsList.RollbackComponent({ + el: document.querySelector('.test-dom-element'), + propsData: { + retry_url: retryURL, + is_last_deployment: false, + }, + }); + + expect(component.$el.querySelector('span').textContent).toContain('Rollback'); + }); +}); diff --git a/spec/javascripts/environments/environment_spec.js.es6 b/spec/javascripts/environments/environment_spec.js.es6 new file mode 100644 index 00000000000..07eb9938c58 --- /dev/null +++ b/spec/javascripts/environments/environment_spec.js.es6 @@ -0,0 +1,172 @@ +//= require vue +//= require environments/stores/environments_store +//= require environments/components/environment + +/* globals environmentsList */ +describe('Environments', () => { + fixture.preload('environments/environments.html'); + fixture.preload('environments/environments_no_permission.html'); + let Store; + let component; + + beforeEach(() => { + Store = window.gl.environmentsList.EnvironmentsStore; + }); + + describe('While loading', () => { + beforeEach(() => { + fixture.load('environments/environments.html'); + component = new window.gl.environmentsList.EnvironmentsComponent({ + el: document.querySelector('#environments-list-view'), + propsData: { + store: Store.create(), + }, + }); + }); + + it('Should render two tabs', () => { + expect(component.$el.querySelectorAll('ul li').length).toEqual(2); + }); + + it('Should render bagdes with zeros in both tabs indicating the number of available environments', () => { + expect( + component.$el.querySelector('.js-available-environments-count').textContent + ).toContain('0'); + expect( + component.$el.querySelector('.js-stopped-environments-count').textContent + ).toContain('0'); + }); + + it('Should render loading icon', () => { + expect( + component.$el.querySelector('environments-list-loading') + ).toBeDefined(); + }); + }); + + describe('Without environments', () => { + beforeEach(() => { + fixture.load('environments/environments.html'); + + spyOn(component, 'ready').and.callFake(() => { + return { + then: callback => callback([]), + json: () => ({ then: cb => cb([]) }), + }; + }); + + component = new window.gl.environmentsList.EnvironmentsComponent({ + el: document.querySelector('#environments-list-view'), + propsData: { + store: Store.create(), + }, + }); + }); + + it('Should render two tabs', () => { + expect(component.$el.querySelectorAll('ul li').length).toEqual(2); + }); + + it('Should render bagdes with zeros in both tabs indicating the number of available environments', () => { + expect( + component.$el.querySelector('.js-available-environments-count').textContent + ).toContain('0'); + expect( + component.$el.querySelector('.js-stopped-environments-count').textContent + ).toContain('0'); + }); + + it('Should render blank state information', () => { + expect( + component.$el.querySelector('.blank-state-title').textContent + ).toEqual('You don\'t have any environments right now.'); + + expect( + component.$el.querySelector('.blank-state-text').textContent + ).toEqual('Environments are places where code gets deployed, such as staging or production.'); + }); + + it('Should render the provided help url', () => { + expect( + component.$el.querySelector('.blank-state a').getAttribute('href') + ).toEqual(component.$data.helpPagePath); + }); + + describe('With create permission', () => { + it('Should render new environment button', () => { + expect( + component.$el.querySelector('a.btn-create').getAttribute('href') + ).toEqual(component.$data.newEnvironmentPath); + expect( + component.$el.querySelector('a.btn-create').textContent + ).toEqual('New environment'); + }); + }); + + describe('Without create permission', () => { + beforeEach('Load fixture without permission', () => { + fixture.load('environments/environments_no_permission.html'); + component = new window.gl.environmentsList.EnvironmentsComponent({ + el: document.querySelector('#environments-list-view'), + propsData: { + store: Store.create(), + }, + }); + }); + + it('Should not render new environment button', () => { + + }); + }); + }); + + describe('With environments', () => { + describe('Tabs behavior', () => { + it('Should render two tabs', () => { + + }); + + it('Should render badges with the correct count', () => { + + }); + + describe('When clicking in the available tab', () => { + it('Should make Available tab active', () => { + + }); + + it('Should make visible only available environments', () => { + + }); + }); + + describe('When clicking in the stopped tab', () => { + it('Should make Stopped tab active', () => { + + }); + + it('Should make visible only stopped environments', () => { + + }); + }); + }); + + describe('With create permissions', () => { + it('Should render new environment button', () => { + + }); + }); + + describe('Without create permissions', () => { + it('Should not render the new environment button', () => { + }); + }); + + it('Should render a table', () => { + }); + + it('Should render table pagination', () => { + + }); + }); +}); diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 new file mode 100644 index 00000000000..07a68bf28fb --- /dev/null +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -0,0 +1,34 @@ +//= require vue +//= require environments/components/environment_stop +describe('Stop Component', () => { + fixture.preload('environments/element.html'); + beforeEach(() => { + fixture.load('environments/element.html'); + }); + + it('should link to the provided URL', () => { + const stopURL = 'https://gitlab.com/stop'; + const component = new window.gl.environmentsList.StopComponent({ + el: document.querySelector('.test-dom-element'), + propsData: { + stop_url: stopURL, + }, + }); + expect(component.$el.getAttribute('href')).toEqual(stopURL); + }); + + describe('When clicked', () => { + it('Should open popup with confirmation warning', () => { + const component = new window.gl.environmentsList.StopComponent({ + el: document.querySelector('.test-dom-element'), + propsData: { + stop_url: '#', + }, + }); + + const spy = spyOn(window, 'confirm'); + component.$el.click(); + expect(spy).toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/javascripts/fixtures/environments/element.html.haml b/spec/javascripts/fixtures/environments/element.html.haml new file mode 100644 index 00000000000..d709c863137 --- /dev/null +++ b/spec/javascripts/fixtures/environments/element.html.haml @@ -0,0 +1 @@ +.test-dom-element \ No newline at end of file diff --git a/spec/javascripts/fixtures/environments/environments.html.haml b/spec/javascripts/fixtures/environments/environments.html.haml new file mode 100644 index 00000000000..dd1d6855ce2 --- /dev/null +++ b/spec/javascripts/fixtures/environments/environments.html.haml @@ -0,0 +1,9 @@ +%div + #environments-list-view{ data: { environments_data: "https://gitlab.com/foo/environments", + "can-create-deployment" => "true", + "can-read-environment" => "true", + "can-create-environmnet" => "true", + "project-environments-path" => "https://gitlab.com/foo/environments", + "project-stopped-environments-path" => "https://gitlab.com/foo/environments?scope=stopped", + "new-environment-path" => "https://gitlab.com/foo/environments/new", + "help-page-path" => "https://gitlab.com/help_page"}} \ No newline at end of file diff --git a/spec/javascripts/fixtures/environments/environments_no_permission.html.haml b/spec/javascripts/fixtures/environments/environments_no_permission.html.haml new file mode 100644 index 00000000000..71cf7db7a34 --- /dev/null +++ b/spec/javascripts/fixtures/environments/environments_no_permission.html.haml @@ -0,0 +1,9 @@ +%div + #environments-list-view{ data: { environments_data: "https://gitlab.com/foo/environments", + "can-create-deployment" => "false", + "can-read-environment" => "true", + "can-create-environmnet" => "false", + "project-environments-path" => "https://gitlab.com/foo/environments", + "project-stopped-environments-path" => "https://gitlab.com/foo/environments?scope=stopped", + "new-environment-path" => "https://gitlab.com/foo/environments/new", + "help-page-path" => "https://gitlab.com/help_page"}} \ No newline at end of file diff --git a/spec/javascripts/fixtures/environments/table.html.haml b/spec/javascripts/fixtures/environments/table.html.haml new file mode 100644 index 00000000000..1ea1725c561 --- /dev/null +++ b/spec/javascripts/fixtures/environments/table.html.haml @@ -0,0 +1,11 @@ +%table + %thead + %tr + %th Environment + %th Last deployment + %th Build + %th Commit + %th + %th + %tbody + %tr#environment-row diff --git a/spec/javascripts/vue_common_components/commit_spec.js.es6 b/spec/javascripts/vue_common_components/commit_spec.js.es6 new file mode 100644 index 00000000000..4f158e8ffa5 --- /dev/null +++ b/spec/javascripts/vue_common_components/commit_spec.js.es6 @@ -0,0 +1,89 @@ +/*= require vue_common_components/commit */ +/* eslint-disable */ + +describe('Commit component', () => { + const getRenderedText = (Component, propsData) => { + const Constructor = Vue.extend(Component); + const vm = new Constructor({propsData}).$mount(); + return vm.$el.textContent; + }; + + const MyComponent = window.gl.commitComponent; + + describe('When `ref` is provided', () => { + const props = { + tag: true, + ref: { + name: 'master', + ref_url: 'http://localhost/namespace2/gitlabhq/tree/master' + }, + commit_url: 'https://gitlab.com/gitlab-org/gitlab-ce/commit/b7836eddf62d663c665769e1b0960197fd215067', + short_sha: 'b7836edd', + title: 'Commit message', + author: { + avatar_url: 'https://gitlab.com/uploads/user/avatar/300478/avatar.png', + web_url: 'https://gitlab.com/jschatz1', + username: 'jschatz1' + } + }; + + it('should render a tag icon if it represents a tag', () => { + const renderedText = getRenderedText(MyComponent, props); + + }); + + it('should render a code-fork icon if it does not represent a tag', () => { + + }); + + it('should render a link to the ref url', () => { + + }); + + it('should render the ref name', () => { + + }); + }); +}); + +it('should render the commit icon as an svg', () => { + +}); + +it('should render the commit short sha with a link to the commit url', () => { + +}); + +describe('Given commit title and author props', () => { + it('Should render a link to the author profile', () => { + + }); + + it('Should render the author avatar with title and alt attributes', () => { + + }); +}); + +describe('When commit title is not provided', () => { + it('Should render default message', () => { + + }); +}); + +describe('Given no ref prop', () => { + it('Should render without errors', () => { + + }); +}); + +describe('Given no title prop', () => { + it('Should render without errors', () => { + + }); +}); + +describe('Given no author prop', () => { + it('Should render without errors', () => { + + }); +}); \ No newline at end of file -- cgit v1.2.1 From a7a13ed3ef281f36dcd0c15540437aaf9aac39dc Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 14 Nov 2016 11:17:02 +0000 Subject: Update to vue 2 --- .../environments/components/environment.js.es6 | 13 +++---- .../components/environment_actions.js.es6 | 6 ++-- .../components/environment_item.js.es6 | 40 +++++++++++++++------- .../environments/vue_resource_interceptor.js.es6 | 3 +- .../javascripts/vue_common_component/commit.js.es6 | 21 +++++++----- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 index 9cdc17e8589..53fd9891a60 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -45,6 +45,7 @@ $(() => { helpPagePath: environmentsListApp.dataset.helpPagePath, loading: true, visibility: 'available', + isLoading: this.loading, }; }, @@ -79,7 +80,7 @@ $(() => { * Fetches all the environmnets and stores them. * Toggles loading property. */ - ready() { + mounted() { window.gl.environmentsService.all().then(resp => resp.json()).then((json) => { this.store.storeEnvironments(json); this.loading = false; @@ -120,17 +121,13 @@ $(() => {
  • Available - - {{state.availableCounter}} - +
  • Stopped - - {{state.stoppedCounter}} - +
  • @@ -179,7 +176,7 @@ $(() => { v-for="model in filteredEnvironments" :model="model" :can-create-deployment="canCreateDeploymentParsed" - :can-read-environment="canReadEnvironmentParsed"> + :can-read-environment="canReadEnvironmentParsed">
    diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 index 6d49a10eb0e..1d04b8a4701 100644 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ b/app/assets/javascripts/environments/components/environment_actions.js.es6 @@ -22,7 +22,7 @@ * TODO: Remove this when webpack is merged. * */ - ready() { + mounted() { const playIcon = document.querySelector('.play-icon-svg.hidden svg'); const dropdownContainer = this.$el.querySelector('.dropdown-play-icon-container'); @@ -52,9 +52,7 @@ - - {{action.name}} - + diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index ebe31cbc26b..414bbd4d623 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -254,6 +254,20 @@ isLastDeployment() { return this.model.last_deployment && this.model.last_deployment['last?']; }, + + buildName() { + if (this.model.last_deployment && this.model.last_deployment.deployable) { + return `${this.model.last_deployment.deployable.name} #${this.model.last_deployment.deployable.id}`; + } + return undefined; + }, + + deploymentInternalId() { + if (this.model.last_deployment) { + return `#${this.model.last_deployment.iid}`; + } + return ''; + }, }, /** @@ -282,8 +296,11 @@ template: ` - - {{model.name}} + @@ -291,17 +308,14 @@ - {{model.name}} + - - {{childrenCounter}} - + - - #{{model.last_deployment.iid}} + by @@ -318,8 +332,8 @@ - {{model.last_deployment.deployable.name}} #{{model.last_deployment.deployable.id}} + :href="model.last_deployment.deployable.build_url" + v-html="buildName"> @@ -340,8 +354,10 @@ - - {{createdDate}} + diff --git a/app/assets/javascripts/environments/vue_resource_interceptor.js.es6 b/app/assets/javascripts/environments/vue_resource_interceptor.js.es6 index d19a5969f96..6d3e71d0110 100644 --- a/app/assets/javascripts/environments/vue_resource_interceptor.js.es6 +++ b/app/assets/javascripts/environments/vue_resource_interceptor.js.es6 @@ -3,11 +3,10 @@ Vue.http.interceptors.push((request, next) => { Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1; next(function (response) { - console.log("this is the repsponse", JSON.stringify(response, null, ' ')); if (typeof response.data === "string") { response.data = JSON.parse(response.data) } - + Vue.activeResources--; }); }); diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6 index 053d08bb089..8d4949cda69 100644 --- a/app/assets/javascripts/vue_common_component/commit.js.es6 +++ b/app/assets/javascripts/vue_common_component/commit.js.es6 @@ -119,7 +119,7 @@ * * TODO: Find a better way to include SVG */ - ready() { + mounted() { const commitIconContainer = this.$el.querySelector('.commit-icon-container'); const commitIcon = document.querySelector('.commit-icon-svg.hidden svg'); @@ -136,22 +136,27 @@
    - - {{ref.name}} +
    - - {{short_sha}} +

    - + - - {{title}} + -- cgit v1.2.1 From 09c4542946fb5ba8f7ac12bd8952f5669156a27e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 14 Nov 2016 15:38:41 +0000 Subject: Refactor to work with vue 2 with just one root element --- .../environments/components/environment.js.es6 | 72 ++++++++++++++++------ .../components/environment_item.js.es6 | 38 +++--------- .../environments/stores/environments_store.js.es6 | 24 ++++++++ 3 files changed, 87 insertions(+), 47 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 index 53fd9891a60..296e18ae8fd 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -81,7 +81,9 @@ $(() => { * Toggles loading property. */ mounted() { - window.gl.environmentsService.all().then(resp => resp.json()).then((json) => { + window.gl.environmentsService.all() + .then(resp => resp.json()) + .then((json) => { this.store.storeEnvironments(json); this.loading = false; }); @@ -114,20 +116,30 @@ $(() => { return false; }, + methods: { + toggleRow(model) { + return this.store.toggleFolder(model.name); + }, + }, + template: ` -

    +
    @@ -143,7 +155,9 @@ $(() => {
    -
    +

    You don't have any environments right now.

    @@ -155,28 +169,48 @@ $(() => { Read more about environments - + New Environment

    -
    +
    - - - - - - + + + + + + + + - +
    EnvironmentLast deploymentBuildCommit
    EnvironmentLast deploymentBuildCommit
    diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 414bbd4d623..3f976ca19e8 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -31,11 +31,10 @@ 'rollback-component': window.gl.environmentsList.RollbackComponent, }, - props: ['model', 'can-create-deployment', 'can-read-environment'], + props: ['model', 'toggleRow', 'can-create-deployment', 'can-read-environment'], data() { return { - open: false, rowClass: { 'children-row': this.model['vue-isChildren'], }, @@ -282,30 +281,19 @@ return {}.hasOwnProperty.call(obj, key); }, - methods: { - /** - * Toggles the visibility of a folders' children. - */ - toggle() { - if (this.isFolder) { - this.open = !this.open; - } - }, - }, - template: ` - + - + - - + + @@ -314,7 +302,7 @@ - + @@ -329,7 +317,7 @@ - + - +
    - + - +
    - - - `, }); })(); diff --git a/app/assets/javascripts/environments/stores/environments_store.js.es6 b/app/assets/javascripts/environments/stores/environments_store.js.es6 index b8fe25ef313..928786f0741 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environments_store.js.es6 @@ -64,6 +64,8 @@ acc.push({ name: environment.environment_type, children: [environment], + isOpen: false, + 'vue-isChildren': environment['vue-isChildren'], }); } } else { @@ -78,6 +80,28 @@ return environmentsTree; }, + /** + * Toggles folder open property given the environment type. + * + * @param {String} envType + * @return {Array} + */ + toggleFolder(envType) { + const environments = this.state.environments; + + const environmnetsCopy = environments.map((env) => { + if (env['vue-isChildren'] === true && env.name === envType) { + env.isOpen = !env.isOpen; + } + + return env; + }); + + this.state.environments = environmnetsCopy; + + return environmnetsCopy; + }, + /** * Given an array of environments, returns the number of environments * that have the given state. -- cgit v1.2.1 From 56aaa3973b5e62ee8527be073246c138ab83fdc6 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 14 Nov 2016 15:58:51 +0000 Subject: Revert changes made on rspec tests for environment --- spec/features/environments_spec.rb | 163 +++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 89 deletions(-) diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index f4c0b093246..b565586ee14 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -1,36 +1,32 @@ -require 'rails_helper' - -feature 'Environments', feature: true, js:true do - include WaitForVueResource - - let(:json) { serializer.as_json } - let(:project) { create(:empty_project, :public) } - let(:user) { create(:user) } - let(:role) { :developer } - - let(:serializer) do - described_class - .new(user: user, project: project) - .represent(resource) - end - +require 'spec_helper' + +feature 'Environments', feature: true do + given(:project) { create(:empty_project) } + given(:user) { create(:user) } + given(:role) { :developer } + background do login_as(user) project.team << [user, role] end describe 'when showing environments' do + given!(:environment) { } + given!(:deployment) { } + given!(:manual) { } + before do visit namespace_project_environments_path(project.namespace, project) - wait_for_vue_resource end - context 'without environments' do - scenario 'does show "Available" and "Stopped" tab with links' do + context 'shows two tabs' do + scenario 'shows "Available" and "Stopped" tab with links' do expect(page).to have_link('Available') expect(page).to have_link('Stopped') end + end + context 'without environments' do scenario 'does show no environments' do expect(page).to have_content('You don\'t have any environments right now.') end @@ -42,99 +38,90 @@ feature 'Environments', feature: true, js:true do end context 'with environments' do - let(:resource) { create_list(:environment, 2) } - before do - endpoint = namespace_project_environments_path(project.namespace, project) - stub_request(:any, endpoint).to_return(body: [{"name": "test"}]) - end - - scenario 'does show "Available" and "Stopped" tab with links' do - expect(page).to have_link('Stopped') - expect(page).to have_link('Available') - end - - scenario 'does show environments table' do - expect(page).to have_selector('.table-holder') + given(:environment) { create(:environment, project: project) } + + scenario 'does show environment name' do + expect(page).to have_link(environment.name) end - + scenario 'does show number of available and stopped environments' do expect(page.find('.js-available-environments-count').text).to eq('1') expect(page.find('.js-stopped-environments-count').text).to eq('0') end - + context 'without deployments' do scenario 'does show no deployments' do expect(page).to have_content('No deployments yet') end end - + context 'with deployments' do - # TODO add environment with deployment - + given(:deployment) { create(:deployment, environment: environment) } + scenario 'does show deployment SHA' do expect(page).to have_link(deployment.short_sha) end - + scenario 'does show deployment internal id' do expect(page).to have_content(deployment.iid) end - + context 'with build and manual actions' do given(:pipeline) { create(:ci_pipeline, project: project) } given(:build) { create(:ci_build, pipeline: pipeline) } given(:deployment) { create(:deployment, environment: environment, deployable: build) } given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } - + scenario 'does show a play button' do expect(page).to have_link(manual.name.humanize) end - + scenario 'does allow to play manual action' do expect(manual).to be_skipped expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } expect(page).to have_content(manual.name) expect(manual.reload).to be_pending end - + scenario 'does show build name and id' do expect(page).to have_link("#{build.name} (##{build.id})") end - + scenario 'does not show stop button' do expect(page).not_to have_selector('.stop-env-link') end - + scenario 'does not show external link button' do expect(page).not_to have_css('external-url') end - - context 'with external_url' do + + context 'with external_url' do given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } given(:build) { create(:ci_build, pipeline: pipeline) } given(:deployment) { create(:deployment, environment: environment, deployable: build) } - + scenario 'does show an external link button' do expect(page).to have_link(nil, href: environment.external_url) end end - - context 'with stop action' do + + context 'with stop action' do given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - + scenario 'does show stop button' do expect(page).to have_selector('.stop-env-link') end - + scenario 'starts build when stop button clicked' do first('.stop-env-link').click - + expect(page).to have_content('close_app') end - + context 'for reporter' do let(:role) { :reporter } - + scenario 'does not show stop button' do expect(page).not_to have_selector('.stop-env-link') end @@ -143,98 +130,96 @@ feature 'Environments', feature: true, js:true do end end end - - context 'can create new environment' do - scenario 'does have a New environment button' do - expect(page).to have_link('New environment') - end + + scenario 'does have a New environment button' do + expect(page).to have_link('New environment') end end - - describe 'when showing the environment' do + + describe 'when showing the environment' do given(:environment) { create(:environment, project: project) } given!(:deployment) { } given!(:manual) { } - + before do visit namespace_project_environment_path(project.namespace, project, environment) end - + context 'without deployments' do scenario 'does show no deployments' do expect(page).to have_content('You don\'t have any deployments right now.') end end - + context 'with deployments' do given(:deployment) { create(:deployment, environment: environment) } - + scenario 'does show deployment SHA' do expect(page).to have_link(deployment.short_sha) end - + scenario 'does not show a re-deploy button for deployment without build' do expect(page).not_to have_link('Re-deploy') end - + context 'with build' do given(:pipeline) { create(:ci_pipeline, project: project) } given(:build) { create(:ci_build, pipeline: pipeline) } given(:deployment) { create(:deployment, environment: environment, deployable: build) } - + scenario 'does show build name' do expect(page).to have_link("#{build.name} (##{build.id})") end - + scenario 'does show re-deploy button' do expect(page).to have_link('Re-deploy') end - + scenario 'does not show stop button' do expect(page).not_to have_link('Stop') end - + context 'with manual action' do given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } - + scenario 'does show a play button' do expect(page).to have_link(manual.name.humanize) end - + scenario 'does allow to play manual action' do expect(manual).to be_skipped expect{ click_link(manual.name.humanize) }.not_to change { Ci::Pipeline.count } expect(page).to have_content(manual.name) expect(manual.reload).to be_pending end - + context 'with external_url' do given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } given(:build) { create(:ci_build, pipeline: pipeline) } given(:deployment) { create(:deployment, environment: environment, deployable: build) } - + scenario 'does show an external link button' do expect(page).to have_link(nil, href: environment.external_url) end end - + context 'with stop action' do given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } - + scenario 'does show stop button' do expect(page).to have_link('Stop') end - + scenario 'does allow to stop environment' do click_link('Stop') - + expect(page).to have_content('close_app') end - + context 'for reporter' do let(:role) { :reporter } - + scenario 'does not show stop button' do expect(page).not_to have_link('Stop') end @@ -244,43 +229,43 @@ feature 'Environments', feature: true, js:true do end end end - + describe 'when creating a new environment' do before do visit namespace_project_environments_path(project.namespace, project) end - + context 'when logged as developer' do before do click_link 'New environment' end - + context 'for valid name' do before do fill_in('Name', with: 'production') click_on 'Save' end - + scenario 'does create a new pipeline' do expect(page).to have_content('Production') end end - + context 'for invalid name' do before do fill_in('Name', with: 'name,with,commas') click_on 'Save' end - + scenario 'does show errors' do expect(page).to have_content('Name can contain only letters') end end end - + context 'when logged as reporter' do given(:role) { :reporter } - + scenario 'does not have a New environment link' do expect(page).not_to have_link('New environment') end -- cgit v1.2.1 From dd80e09a7bcd4da9d4505090499e0da6e8555a9c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 14 Nov 2016 17:22:21 +0000 Subject: Adds tests --- .../environments/environment_item_spec.js.es6 | 118 +++++++++++++++++++-- 1 file changed, 108 insertions(+), 10 deletions(-) diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index f357e11dc8e..1029d632054 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -9,7 +9,6 @@ describe('Environment item', () => { describe('When item is folder', () => { let mockItem; - let component; beforeEach(() => { mockItem = { @@ -35,38 +34,137 @@ describe('Environment item', () => { }, ], }; + }); - component = new window.gl.environmentsList.EnvironmentItem({ + it('Should render clickable folder icon and name', () => { + const component = new window.gl.environmentsList.EnvironmentItem({ el: document.querySelector('tr#environment-row'), propsData: { model: mockItem, + toggleRow: () => {}, 'can-create-deployment': false, 'can-read-environment': true, }, }); - }); - it('Should render clickable folder icon and name', () => { - expect(document.querySelector('.folder-name').textContent).toContain(mockItem.name); - expect(document.querySelector('.folder-icon')).toBeDefined(); + expect(component.$el.querySelector('.folder-name').textContent).toContain(mockItem.name); + expect(component.$el.querySelector('.folder-icon')).toBeDefined(); }); it('Should render the number of children in a badge', () => { - expect(document.querySelector('.folder-name .badge').textContent).toContain(mockItem.children.length); - }); + const component = new window.gl.environmentsList.EnvironmentItem({ + el: document.querySelector('tr#environment-row'), + propsData: { + model: mockItem, + toggleRow: () => {}, + 'can-create-deployment': false, + 'can-read-environment': true, + }, + }); - it('Should not render any information other than the name', () => { + expect(component.$el.querySelector('.folder-name .badge').textContent).toContain(mockItem.children.length); }); describe('when clicked', () => { - it('Should render child row', () => { + it('Should call the given prop', () => { + const component = new window.gl.environmentsList.EnvironmentItem({ + el: document.querySelector('tr#environment-row'), + propsData: { + model: mockItem, + toggleRow: () => { + console.log('here!'); + }, + 'can-create-deployment': false, + 'can-read-environment': true, + }, + }); + + spyOn(component.$options.propsData, 'toggleRow'); + component.$el.querySelector('.folder-name').click(); + + expect(component.$options.propsData.toggleRow).toHaveBeenCalled(); }); }); }); describe('when item is not folder', () => { + let environment; + + beforeEach(() => { + environment = { + id: 31, + name: 'production', + state: 'stopped', + external_url: 'http://external.com', + environment_type: null, + last_deployment: { + id: 66, + iid: 6, + sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + ref: { + name: 'master', + ref_url: 'http://localhost:3000/root/ci-folders/tree/master', + }, + tag: true, + 'last?': true, + user: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit: { + id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + short_id: '500aabcb', + title: 'Update .gitlab-ci.yml', + author_name: 'Administrator', + author_email: 'admin@example.com', + created_at: '2016-11-07T18:28:13.000+00:00', + message: 'Update .gitlab-ci.yml', + author: { + name: 'Administrator', + username: 'root', + id: 1, + state: 'active', + avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', + web_url: 'http://localhost:3000/root', + }, + commit_url: 'http://localhost:3000/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + }, + deployable: { + id: 1279, + name: 'deploy', + build_url: 'http://localhost:3000/root/ci-folders/builds/1279', + retry_url: 'http://localhost:3000/root/ci-folders/builds/1279/retry', + }, + manual_actions: [ + { + name: 'action', + play_url: 'http://localhost:3000/play', + }, + ], + }, + 'stoppable?': true, + environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + created_at: '2016-11-07T11:11:16.525Z', + updated_at: '2016-11-10T15:55:58.778Z', + }; + }); + it('should render environment name', () => { + const component = new window.gl.environmentsList.EnvironmentItem({ + el: document.querySelector('tr#environment-row'), + propsData: { + model: environment, + toggleRow: () => {}, + 'can-create-deployment': false, + 'can-read-environment': true, + }, + }); + debugger; }); describe('With deployment', () => { -- cgit v1.2.1 From bebbf12a085b09caeaea98e7247d460364a6cfef Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 15 Nov 2016 10:12:59 +0000 Subject: Fix JSON problem --- app/helpers/environments_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 7c09c20d118..515e802e01e 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -1,7 +1,7 @@ module EnvironmentsHelper - def environments_list_data() + def environments_list_data { - endpoint: namespace_project_environments_path(@project.namespace, @project) + endpoint: namespace_project_environments_path(@project.namespace, @project, format: :json) } end end -- cgit v1.2.1 From ed07264532cac11b1f7cc4c68627cb7bfb7e41fc Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 15 Nov 2016 12:07:11 +0000 Subject: Adds props validation Improves documentation Adds tests Fix prop validation for objects Finish tests for environment item Adds tests for toggle folder function Environment tests Adds tests --- .../boards/services/board_service.js.es6 | 1 + .../environments/components/environment.js.es6 | 45 +++-- .../components/environment_external_url.js.es6 | 2 +- .../components/environment_item.js.es6 | 198 ++++++++++++++------- .../services/environments_service.js.es6 | 5 +- .../javascripts/vue_common_component/commit.js.es6 | 4 +- db/schema.rb | 3 + spec/features/environments_spec.rb | 3 +- .../environments/environment_item_spec.js.es6 | 136 +++++--------- .../environments/environment_spec.js.es6 | 172 ------------------ .../environments/environments_store_spec.js.es6 | 17 +- .../fixtures/environments/environments.html.haml | 8 +- .../environments_no_permission.html.haml | 9 - 13 files changed, 244 insertions(+), 359 deletions(-) delete mode 100644 spec/javascripts/environments/environment_spec.js.es6 delete mode 100644 spec/javascripts/fixtures/environments/environments_no_permission.html.haml diff --git a/app/assets/javascripts/boards/services/board_service.js.es6 b/app/assets/javascripts/boards/services/board_service.js.es6 index f59a2ed7937..570944e132d 100644 --- a/app/assets/javascripts/boards/services/board_service.js.es6 +++ b/app/assets/javascripts/boards/services/board_service.js.es6 @@ -11,6 +11,7 @@ class BoardService { this.issues = Vue.resource(`${root}/${boardId}/lists{/id}/issues`, {}); Vue.http.interceptors.push((request, next) => { + debugger; request.headers['X-CSRF-Token'] = $.rails.csrfToken(); next(); }); diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 index 296e18ae8fd..42b32811e4f 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -23,8 +23,14 @@ $(() => { return fn(item); }).filter(Boolean); - window.gl.environmentsList.EnvironmentsComponent = Vue.extend({ - props: ['store'], + window.gl.environmentsList.EnvironmentsComponent = Vue.component('environment-component', { + props: { + store: { + type: Object, + required: true, + default: () => ({}), + }, + }, components: { 'environment-item': window.gl.environmentsList.EnvironmentItem, @@ -43,9 +49,8 @@ $(() => { projectStoppedEnvironmentsPath: environmentsListApp.dataset.projectStoppedEnvironmentsPath, newEnvironmentPath: environmentsListApp.dataset.newEnvironmentPath, helpPagePath: environmentsListApp.dataset.helpPagePath, - loading: true, visibility: 'available', - isLoading: this.loading, + isLoading: false, }; }, @@ -65,6 +70,10 @@ $(() => { canCreateDeploymentParsed() { return this.$options.convertPermissionToBoolean(this.canCreateDeployment); }, + + canCreateEnvironmentParsed() { + return this.$options.convertPermissionToBoolean(this.canCreateEnvironment); + }, }, created() { @@ -74,6 +83,15 @@ $(() => { if (scope) { this.visibility = scope; } + + this.isLoading = true; + + return window.gl.environmentsService.all() + .then(resp => resp.json()) + .then((json) => { + this.store.storeEnvironments(json); + this.isLoading = false; + }); }, /** @@ -81,12 +99,7 @@ $(() => { * Toggles loading property. */ mounted() { - window.gl.environmentsService.all() - .then(resp => resp.json()) - .then((json) => { - this.store.storeEnvironments(json); - this.loading = false; - }); + }, /** @@ -143,21 +156,21 @@ $(() => { -
    -
    +
    + v-if="!isLoading && state.environments.length === 0">

    You don't have any environments right now.

    @@ -170,7 +183,7 @@ $(() => { Read more about environments New Environment @@ -180,7 +193,7 @@ $(() => {
    + v-if="!isLoading && state.environments.length > 0"> diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js.es6 index b5d540ea934..eca0c368622 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.js.es6 +++ b/app/assets/javascripts/environments/components/environment_external_url.js.es6 @@ -14,7 +14,7 @@ }, template: ` - + `, diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 3f976ca19e8..bea6d09aacc 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -1,3 +1,5 @@ +/*= require lib/utils/timeago +/*= require lib/utils/text_utility /*= require vue_common_component/commit /*= require ./environment_actions /*= require ./environment_external_url @@ -31,7 +33,30 @@ 'rollback-component': window.gl.environmentsList.RollbackComponent, }, - props: ['model', 'toggleRow', 'can-create-deployment', 'can-read-environment'], + props: { + model: { + type: Object, + required: true, + default: () => ({}), + }, + + toggleRow: { + type: Function, + required: false, + }, + + canCreateDeployment: { + type: Boolean, + required: false, + default: false, + }, + + canReadEnvironment: { + type: Boolean, + required: false, + default: false, + }, + }, data() { return { @@ -48,10 +73,10 @@ * Folder items have different behaviours - it is possible to toggle * them and show their children. * - * @returns {Boolean} + * @returns {Boolean|Undefined} */ isFolder() { - return this.$options.hasKey(this.model, 'children') && + return this.model.children && this.model.children.length > 0; }, @@ -69,24 +94,13 @@ * Counts the number of environments in each folder. * Used to show a badge with the counter. * - * @returns {Boolean} The number of environments for the current folder + * @returns {Number|Undefined} The number of environments for the current folder. */ childrenCounter() { - return this.$options.hasKey(this.model, 'children') && + return this.model.children && this.model.children.length; }, - /** - * Returns the value of the `last?` key sent in the API. - * Used to know wich title to render when the environment can be re-deployed - * - * @returns {Boolean} - */ - isLast() { - return this.$options.hasKey(this.model, 'last_deployment') && - this.model.last_deployment['last?']; - }, - /** * Verifies if `last_deployment` key exists in the current Envrionment. * This key is required to render most of the html - this method works has @@ -95,18 +109,21 @@ * @returns {Boolean} */ hasLastDeploymentKey() { - return this.$options.hasKey(this.model, 'last_deployment'); + if (this.model.last_deployment && this.model.last_deployment !== {}) { + return true; + } + return false; }, /** * Verifies is the given environment has manual actions. * Used to verify if we should render them or nor. * - * @returns {Boolean} + * @returns {Boolean|Undefined} */ hasManualActions() { - return this.$options.hasKey(this.model, 'manual_actions') && - this.model.manual_actions.length > 0; + return this.model.last_deployment && this.model.last_deployment.manual_actions && + this.model.last_deployment.manual_actions.length > 0; }, /** @@ -122,12 +139,12 @@ * Verifies if the `deployable` key is present in `last_deployment` key. * Used to verify whether we should or not render the rollback partial. * - * @returns {Boolean} + * @returns {Boolean|Undefined} */ canRetry() { return this.hasLastDeploymentKey && this.model.last_deployment && - this.$options.hasKey(this.model.last_deployment, 'deployable'); + this.model.last_deployment.deployable; }, /** @@ -144,20 +161,33 @@ /** * Returns the manual actions with the name parsed. * - * @returns {Array.} + * @returns {Array.|Undefined} */ manualActions() { - return this.model.last_deployment.manual_actions.map((action) => { - const parsedAction = { - name: gl.text.humanize(action.name), - play_url: action.play_url, - }; - return parsedAction; - }); + if (this.hasManualActions) { + return this.model.last_deployment.manual_actions.map((action) => { + const parsedAction = { + name: gl.text.humanize(action.name), + play_url: action.play_url, + }; + return parsedAction; + }); + } + return []; }, + /** + * Builds the string used in the user image alt attribute. + * + * @returns {String} + */ userImageAltDescription() { - return `${this.model.last_deployment.user.username}'s avatar'`; + if (this.model.last_deployment && + this.model.last_deployment.user && + this.model.last_deployment.user.username) { + return `${this.model.last_deployment.user.username}'s avatar'`; + } + return ''; }, /** @@ -166,7 +196,8 @@ * @returns {String|Undefined} */ commitTag() { - if (this.model.last_deployment && this.model.last_deployment.tag) { + if (this.model.last_deployment && + this.model.last_deployment.tag) { return this.model.last_deployment.tag; } return undefined; @@ -178,7 +209,8 @@ * @returns {Object|Undefined} */ commitRef() { - if (this.model.last_deployment && this.model.last_deployment.ref) { + if (this.model.last_deployment && + this.model.last_deployment.ref) { return this.model.last_deployment.ref; } return undefined; @@ -241,6 +273,11 @@ return undefined; }, + /** + * Verifies if the `retry_url` key is present and returns its value. + * + * @returns {String|Undefined} + */ retryUrl() { if (this.model.last_deployment && this.model.last_deployment.deployable && @@ -250,35 +287,66 @@ return undefined; }, + /** + * Verifies if the `last?` key is present and returns its value. + * + * @returns {Boolean|Undefined} + */ isLastDeployment() { return this.model.last_deployment && this.model.last_deployment['last?']; }, + /** + * Builds the name of the builds needed to display both the name and the id. + * + * @returns {String} + */ buildName() { - if (this.model.last_deployment && this.model.last_deployment.deployable) { + if (this.model.last_deployment && + this.model.last_deployment.deployable) { return `${this.model.last_deployment.deployable.name} #${this.model.last_deployment.deployable.id}`; } - return undefined; + return ''; }, + /** + * Builds the needed string to show the internal id. + * + * @returns {String} + */ deploymentInternalId() { - if (this.model.last_deployment) { + if (this.model.last_deployment && + this.model.last_deployment.iid) { return `#${this.model.last_deployment.iid}`; } return ''; }, - }, - /** - * Helper to verify if key is present in an object. - * Can be removed once we start using lodash. - * - * @param {Object} obj - * @param {String} key - * @returns {Boolean} - */ - hasKey(obj, key) { - return {}.hasOwnProperty.call(obj, key); + /** + * Verifies if the user object is present under last_deployment object. + * + * @returns {Boolean} + */ + deploymentHasUser() { + if (this.model.last_deployment && + this.model.last_deployment.user) { + return true; + } + return false; + }, + + /** + * Returns the user object nested with the last_deployment object. + * Used to render the template. + * + * @returns {Object} + */ + deploymentUser() { + if (this.model.last_deployment && this.model.last_deployment.user) { + return this.model.last_deployment.user; + } + return {}; + }, }, template: ` @@ -303,17 +371,19 @@ @@ -326,7 +396,7 @@ @@ -351,25 +421,25 @@ @@ -435,7 +435,7 @@
    + :stop_url="model.environment_path">
    -- cgit v1.2.1 From 9d3949abaa304c2c7e6b75b213e6ff0ac5128a8f Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 16:20:52 +0000 Subject: inline conditions --- .../javascripts/environments/components/environment_item.js.es6 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 0e29350d7e4..871da5790ec 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -76,8 +76,7 @@ * @returns {Boolean|Undefined} */ isFolder() { - return this.model.children && - this.model.children.length > 0; + return this.model.children && this.model.children.length > 0; }, /** @@ -97,8 +96,7 @@ * @returns {Number|Undefined} The number of environments for the current folder. */ childrenCounter() { - return this.model.children && - this.model.children.length; + return this.model.children && this.model.children.length; }, /** -- cgit v1.2.1 From 551d86c09817baf783f5ac4d52bb0d8991a26f63 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 17:12:13 +0000 Subject: Fix broken button in empty state --- .../environments/components/environment.js.es6 | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 index 89ac1cb42c0..a94fe41dede 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -193,19 +193,18 @@

    Environments are places where code gets deployed, such as staging or production. -
    - Read more about environments - - New Environment -

    + + + New Environment +
    Date: Thu, 17 Nov 2016 17:29:53 +0000 Subject: Adds fixed layout to prevent the columns from jumping when opening a folder --- .../environments/stores/environments_store.js.es6 | 236 +++++++++++++++++++++ 1 file changed, 236 insertions(+) diff --git a/app/assets/javascripts/environments/stores/environments_store.js.es6 b/app/assets/javascripts/environments/stores/environments_store.js.es6 index 928786f0741..0ef0d99e38d 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environments_store.js.es6 @@ -47,6 +47,242 @@ * @returns {Array} Tree structured array with the received environments. */ storeEnvironments(environments = []) { + environments = [{ + "id": 31, + "name": "production", + "state": "stopped", + "external_url": null, + "environment_type": null, + "last_deployment": { + "id": 66, + "iid": 6, + "sha": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", + "ref": { + "name": "master", + "ref_path": "/root/ci-folders/tree/master" + }, + "tag": false, + "last?": true, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit": { + "id": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", + "short_id": "500aabcb", + "title": "Update .gitlab-ci.yml", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-11-07T18:28:13.000+00:00", + "message": "Update .gitlab-ci.yml", + "author": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit_path": "/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd" + }, + "deployable": { + "id": 1279, + "name": "deploy", + "build_path": "/root/ci-folders/builds/1279", + "retry_path": "/root/ci-folders/builds/1279/retry" + }, + "manual_actions": [] + }, + "stoppable?": false, + "environment_path": "/root/ci-folders/environments/31", + "created_at": "2016-11-07T11:11:16.525Z", + "updated_at": "2016-11-10T15:55:58.778Z" +}, { + "id": 33, + "name": "folder/foo", + "state": "available", + "external_url": "http://bar.filipa.com", + "environment_type": "folder", + "last_deployment": { + "id": 66, + "iid": 6, + "sha": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", + "ref": { + "name": "master", + "ref_path": "/root/ci-folders/tree/master" + }, + "tag": false, + "last?": true, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit": { + "id": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", + "short_id": "500aabcb", + "title": "Real big commi message adasdasdas asdasd sd sdsdfdsf Update .gitlab-ci.yml", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-11-07T18:28:13.000+00:00", + "message": "Update .gitlab-ci.yml", + "author": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit_path": "/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd" + }, + "deployable": { + "id": 1279, + "name": "deploy", + "build_path": "/root/ci-folders/builds/1279", + "retry_path": "/root/ci-folders/builds/1279/retry" + }, + "manual_actions": [] + }, + "stoppable?": false, + "environment_path": "/root/ci-folders/environments/33", + "created_at": "2016-11-07T11:17:20.604Z", + "updated_at": "2016-11-07T11:17:20.604Z" +}, { + "id": 34, + "name": "folder/bar", + "last_deployment": { + "id": 66, + "iid": 6, + "sha": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", + "ref": { + "name": "master", + "ref_path": "/root/ci-folders/tree/master" + }, + "tag": false, + "last?": true, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit": { + "id": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", + "short_id": "500aabcb", + "title": "Update .gitlab-ci.yml", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-11-07T18:28:13.000+00:00", + "message": "Update .gitlab-ci.yml", + "author": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit_path": "/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd" + }, + "deployable": { + "id": 1279, + "name": "deploy", + "build_path": "/root/ci-folders/builds/1279", + "retry_path": "/root/ci-folders/builds/1279/retry" + }, + "manual_actions": [] + }, + "state": "available", + "external_url": null, + "environment_type": "folder", + + "stoppable?": false, + "environment_path": "/root/ci-folders/environments/34", + "created_at": "2016-11-07T11:31:59.481Z", + "updated_at": "2016-11-07T11:31:59.481Z" +}, { + "id": 35, + "name": "review", + "state": "available", + "external_url": null, + "environment_type": null, + "last_deployment": { + "id": 67, + "iid": 7, + "sha": "9dcecbafd2514b555ad2ef9be1f40c6b46009613", + "ref": { + "name": "master", + "ref_path": "/root/ci-folders/tree/master" + }, + "tag": false, + "last?": true, + "user": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit": { + "id": "9dcecbafd2514b555ad2ef9be1f40c6b46009613", + "short_id": "9dcecbaf", + "title": "aa Update .gitlab-ci.yml", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-11-09T15:53:06.000+00:00", + "message": "aa Update .gitlab-ci.yml", + "author": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", + "web_url": "http://localhost:3000/root" + }, + "commit_path": "/root/ci-folders/tree/9dcecbafd2514b555ad2ef9be1f40c6b46009613" + }, + "deployable": { + "id": 1283, + "name": "test", + "build_path": "/root/ci-folders/builds/1283", + "retry_path": "/root/ci-folders/builds/1283/retry" + }, + "manual_actions": [{ + "id": 1292, + "name": "stop_review_app", + "build_path": "/root/ci-folders/builds/1292", + "retry_path": "/root/ci-folders/builds/1292/retry", + "play_path": "/root/ci-folders/builds/1292/play" + }] + }, + "stoppable?": true, + "environment_path": "/root/ci-folders/environments/35", + "created_at": "2016-11-09T15:53:45.108Z", + "updated_at": "2016-11-09T15:53:45.108Z" +}, { + "id": 36, + "name": "review", + "state": "stopped", + "external_url": null, + "environment_type": null, + "last_deployment": null, + "stoppable?": false, + "environment_path": "/root/ci-folders/environments/36", + "created_at": "2016-11-09T15:53:45.220Z", + "updated_at": "2016-11-09T15:53:45.273Z" +}]; + this.state.stoppedCounter = this.countByState(environments, 'stopped'); this.state.availableCounter = this.countByState(environments, 'available'); -- cgit v1.2.1 From c5a16f45d599bb9b97136b01558fcffc449b1a2a Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 17:35:27 +0000 Subject: Undo last commit --- .../environments/stores/environments_store.js.es6 | 236 --------------------- 1 file changed, 236 deletions(-) diff --git a/app/assets/javascripts/environments/stores/environments_store.js.es6 b/app/assets/javascripts/environments/stores/environments_store.js.es6 index 0ef0d99e38d..928786f0741 100644 --- a/app/assets/javascripts/environments/stores/environments_store.js.es6 +++ b/app/assets/javascripts/environments/stores/environments_store.js.es6 @@ -47,242 +47,6 @@ * @returns {Array} Tree structured array with the received environments. */ storeEnvironments(environments = []) { - environments = [{ - "id": 31, - "name": "production", - "state": "stopped", - "external_url": null, - "environment_type": null, - "last_deployment": { - "id": 66, - "iid": 6, - "sha": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", - "ref": { - "name": "master", - "ref_path": "/root/ci-folders/tree/master" - }, - "tag": false, - "last?": true, - "user": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit": { - "id": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", - "short_id": "500aabcb", - "title": "Update .gitlab-ci.yml", - "author_name": "Administrator", - "author_email": "admin@example.com", - "created_at": "2016-11-07T18:28:13.000+00:00", - "message": "Update .gitlab-ci.yml", - "author": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit_path": "/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd" - }, - "deployable": { - "id": 1279, - "name": "deploy", - "build_path": "/root/ci-folders/builds/1279", - "retry_path": "/root/ci-folders/builds/1279/retry" - }, - "manual_actions": [] - }, - "stoppable?": false, - "environment_path": "/root/ci-folders/environments/31", - "created_at": "2016-11-07T11:11:16.525Z", - "updated_at": "2016-11-10T15:55:58.778Z" -}, { - "id": 33, - "name": "folder/foo", - "state": "available", - "external_url": "http://bar.filipa.com", - "environment_type": "folder", - "last_deployment": { - "id": 66, - "iid": 6, - "sha": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", - "ref": { - "name": "master", - "ref_path": "/root/ci-folders/tree/master" - }, - "tag": false, - "last?": true, - "user": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit": { - "id": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", - "short_id": "500aabcb", - "title": "Real big commi message adasdasdas asdasd sd sdsdfdsf Update .gitlab-ci.yml", - "author_name": "Administrator", - "author_email": "admin@example.com", - "created_at": "2016-11-07T18:28:13.000+00:00", - "message": "Update .gitlab-ci.yml", - "author": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit_path": "/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd" - }, - "deployable": { - "id": 1279, - "name": "deploy", - "build_path": "/root/ci-folders/builds/1279", - "retry_path": "/root/ci-folders/builds/1279/retry" - }, - "manual_actions": [] - }, - "stoppable?": false, - "environment_path": "/root/ci-folders/environments/33", - "created_at": "2016-11-07T11:17:20.604Z", - "updated_at": "2016-11-07T11:17:20.604Z" -}, { - "id": 34, - "name": "folder/bar", - "last_deployment": { - "id": 66, - "iid": 6, - "sha": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", - "ref": { - "name": "master", - "ref_path": "/root/ci-folders/tree/master" - }, - "tag": false, - "last?": true, - "user": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit": { - "id": "500aabcb17c97bdcf2d0c410b70cb8556f0362dd", - "short_id": "500aabcb", - "title": "Update .gitlab-ci.yml", - "author_name": "Administrator", - "author_email": "admin@example.com", - "created_at": "2016-11-07T18:28:13.000+00:00", - "message": "Update .gitlab-ci.yml", - "author": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit_path": "/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd" - }, - "deployable": { - "id": 1279, - "name": "deploy", - "build_path": "/root/ci-folders/builds/1279", - "retry_path": "/root/ci-folders/builds/1279/retry" - }, - "manual_actions": [] - }, - "state": "available", - "external_url": null, - "environment_type": "folder", - - "stoppable?": false, - "environment_path": "/root/ci-folders/environments/34", - "created_at": "2016-11-07T11:31:59.481Z", - "updated_at": "2016-11-07T11:31:59.481Z" -}, { - "id": 35, - "name": "review", - "state": "available", - "external_url": null, - "environment_type": null, - "last_deployment": { - "id": 67, - "iid": 7, - "sha": "9dcecbafd2514b555ad2ef9be1f40c6b46009613", - "ref": { - "name": "master", - "ref_path": "/root/ci-folders/tree/master" - }, - "tag": false, - "last?": true, - "user": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit": { - "id": "9dcecbafd2514b555ad2ef9be1f40c6b46009613", - "short_id": "9dcecbaf", - "title": "aa Update .gitlab-ci.yml", - "author_name": "Administrator", - "author_email": "admin@example.com", - "created_at": "2016-11-09T15:53:06.000+00:00", - "message": "aa Update .gitlab-ci.yml", - "author": { - "name": "Administrator", - "username": "root", - "id": 1, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon", - "web_url": "http://localhost:3000/root" - }, - "commit_path": "/root/ci-folders/tree/9dcecbafd2514b555ad2ef9be1f40c6b46009613" - }, - "deployable": { - "id": 1283, - "name": "test", - "build_path": "/root/ci-folders/builds/1283", - "retry_path": "/root/ci-folders/builds/1283/retry" - }, - "manual_actions": [{ - "id": 1292, - "name": "stop_review_app", - "build_path": "/root/ci-folders/builds/1292", - "retry_path": "/root/ci-folders/builds/1292/retry", - "play_path": "/root/ci-folders/builds/1292/play" - }] - }, - "stoppable?": true, - "environment_path": "/root/ci-folders/environments/35", - "created_at": "2016-11-09T15:53:45.108Z", - "updated_at": "2016-11-09T15:53:45.108Z" -}, { - "id": 36, - "name": "review", - "state": "stopped", - "external_url": null, - "environment_type": null, - "last_deployment": null, - "stoppable?": false, - "environment_path": "/root/ci-folders/environments/36", - "created_at": "2016-11-09T15:53:45.220Z", - "updated_at": "2016-11-09T15:53:45.273Z" -}]; - this.state.stoppedCounter = this.countByState(environments, 'stopped'); this.state.availableCounter = this.countByState(environments, 'available'); -- cgit v1.2.1 From 4dbed5a249265b3690888b3fcfc91da44412f7f1 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 17:37:55 +0000 Subject: Adds fixed layout to prevent the columns from jumping when opening a folder --- app/assets/stylesheets/pages/environments.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index dc45fbba61f..e9ff43a8adb 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -16,6 +16,8 @@ } .environments { + table-layout: fixed; + .deployment-column { .avatar { float: none; -- cgit v1.2.1 From 67c833e90fa39b4a648828b884bb14454ccc7c9b Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 17 Nov 2016 20:19:57 +0100 Subject: Fix Rubocop offense for lines in environment specs --- spec/features/environment_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/features/environment_spec.rb b/spec/features/environment_spec.rb index 51bd1d4bdfc..0c1939fd885 100644 --- a/spec/features/environment_spec.rb +++ b/spec/features/environment_spec.rb @@ -64,7 +64,6 @@ feature 'Environment', :feature do given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } scenario 'does show a play button' do - expect(page).to have_link(manual.name.humanize) end -- cgit v1.2.1 From 8bd3f52667f4682ebfefa62024b901cabc928ed1 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 20:58:38 +0000 Subject: Swaps url for paths in mock data --- spec/javascripts/environments/mock_data.js.es6 | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 1142ace5846..9e16bc3e6a5 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -40,18 +40,18 @@ const environmentsList = [ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', web_url: 'http://localhost:3000/root', }, - commit_url: 'http://localhost:3000/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', }, deployable: { id: 1278, name: 'build', - build_url: 'http://localhost:3000/root/ci-folders/builds/1278', - retry_url: 'http://localhost:3000/root/ci-folders/builds/1278/retry', + build_path: '/root/ci-folders/builds/1278', + retry_path: '/root/ci-folders/builds/1278/retry', }, manual_actions: [], }, 'stoppable?': true, - environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + environment_path: '/root/ci-folders/environments/31', created_at: '2016-11-07T11:11:16.525Z', updated_at: '2016-11-07T11:11:16.525Z', }, @@ -95,18 +95,18 @@ const environmentsList = [ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon', web_url: 'http://localhost:3000/root', }, - commit_url: 'http://localhost:3000/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', + commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd', }, deployable: { id: 1278, name: 'build', - build_url: 'http://localhost:3000/root/ci-folders/builds/1278', - retry_url: 'http://localhost:3000/root/ci-folders/builds/1278/retry', + build_path: '/root/ci-folders/builds/1278', + retry_path: '/root/ci-folders/builds/1278/retry', }, manual_actions: [], }, 'stoppable?': false, - environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + environment_path: '/root/ci-folders/environments/31', created_at: '2016-11-07T11:11:16.525Z', updated_at: '2016-11-07T11:11:16.525Z', }, @@ -117,7 +117,7 @@ const environmentsList = [ environment_type: 'review', last_deployment: null, 'stoppable?': true, - environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + environment_path: '/root/ci-folders/environments/31', created_at: '2016-11-07T11:11:16.525Z', updated_at: '2016-11-07T11:11:16.525Z', }, @@ -128,9 +128,8 @@ const environmentsList = [ environment_type: 'review', last_deployment: null, 'stoppable?': true, - environment_url: 'http://localhost:3000/root/ci-folders/environments/31', + environment_path: '/root/ci-folders/environments/31', created_at: '2016-11-07T11:11:16.525Z', updated_at: '2016-11-07T11:11:16.525Z', }, ]; - -- cgit v1.2.1 From f9237abb66aa92825c17bc6864e16783c1e54450 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 21:26:34 +0000 Subject: Fix after review --- app/assets/javascripts/environments/components/environment.js.es6 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 index a94fe41dede..28377cd5183 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -140,10 +140,7 @@ * @returns {Boolean} */ convertPermissionToBoolean(string) { - if (string === 'true') { - return true; - } - return false; + return string === 'true'; }, methods: { -- cgit v1.2.1 From a22f5161146d94f548d305f053531882f866a951 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 21:32:43 +0000 Subject: Adds helper to verify empty object --- .../environments/components/environment_item.js.es6 | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 871da5790ec..4358ce96a13 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -107,7 +107,8 @@ * @returns {Boolean} */ hasLastDeploymentKey() { - if (this.model.last_deployment && this.model.last_deployment !== {}) { + if (this.model.last_deployment && + !this.$options.isObjectEmpty(this.model.last_deployment)) { return true; } return false; @@ -326,8 +327,7 @@ * @returns {Boolean} */ deploymentHasUser() { - if (this.model.last_deployment && - this.model.last_deployment.user) { + if (this.model.last_deployment && this.model.last_deployment.user) { return true; } return false; @@ -347,6 +347,21 @@ }, }, + /** + * Helper to verify if certain given object are empty. + * Should be replaced by lodash _.isEmpty - https://lodash.com/docs/4.17.2#isEmpty + * @param {Object} object + * @returns {Bollean} + */ + isObjectEmpty(object) { + for (const key in object) { // eslint-disable-line + if (hasOwnProperty.call(object, key)) { + return false; + } + } + return true; + }, + template: `
    - - - - by - - - - + + + + + by + + + -
    +
    -

    +

    No deployments yet

    -- cgit v1.2.1 From 92cff96f86597f86614116436d4b11d8a325032a Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 17 Nov 2016 21:46:41 +0000 Subject: Improvements after review --- .../components/environment_item.js.es6 | 54 ++++++++++++++++------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 4358ce96a13..9241b5472a7 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -208,8 +208,7 @@ * @returns {Object|Undefined} */ commitRef() { - if (this.model.last_deployment && - this.model.last_deployment.ref) { + if (this.model.last_deployment && this.model.last_deployment.ref) { return this.model.last_deployment.ref; } return undefined; @@ -327,10 +326,8 @@ * @returns {Boolean} */ deploymentHasUser() { - if (this.model.last_deployment && this.model.last_deployment.user) { - return true; - } - return false; + return !this.$options.isObjectEmpty(this.model.last_deployment) && + !this.$options.isObjectEmpty(this.model.last_deployment.user); }, /** @@ -340,11 +337,38 @@ * @returns {Object} */ deploymentUser() { - if (this.model.last_deployment && this.model.last_deployment.user) { + if (!this.$options.isObjectEmpty(this.model.last_deployment) && + !this.$options.isObjectEmpty(this.model.last_deployment.user)) { return this.model.last_deployment.user; } return {}; }, + + /** + * Verifies if the build name column should be rendered by verifing + * if all the information needed is present + * and if the environment is not a folder. + * + * @returns {Boolean} + */ + shouldRenderBuildName() { + return !this.isFolder && + !this.$options.isObjectEmpty(this.model.last_deployment) && + !this.$options.isObjectEmpty(this.model.last_deployment.deployable); + }, + + /** + * Verifies if deplyment internal ID should be rendered by verifing + * if all the information needed is present + * and if the environment is not a folder. + * + * @returns {Boolean} + */ + shouldRenderDeploymentID() { + return !this.isFolder && + !this.$options.isObjectEmpty(this.model.last_deployment) && + this.model.last_deployment.iid !== undefined; + }, }, /** @@ -385,7 +409,7 @@ @@ -401,7 +425,7 @@ - @@ -434,25 +458,29 @@