From 3fef5e66dba055e32dda1ccc887ad630d1e61c87 Mon Sep 17 00:00:00 2001
From: Filipa Lacerda <filipa@gitlab.com>
Date: Wed, 9 Nov 2016 10:55:00 +0000
Subject: [PATCH] Adds template functions Adds commit component

---
 .../components/environment_item.js.es6        | 185 +++++++++++++++++-
 .../environments/environments_bundle.js.es6   |   4 +-
 .../vue_common_component/commit.js.es6        | 173 ++++++++++++++++
 .../projects/environments/index.html.haml     |   6 +-
 .../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: `
+      <tr>
+        <td v-bind:class="rowClass">
+          <a v-if="!isFolder" class="environment-name" :href="model.environment_url">
+            {{model.name}}
+          </a>
+          <span v-else v-on:click="toggle" class="folder-name">
+            <span class="folder-icon">
+              <i v-show="open" class="fa fa-caret-down"></i>
+              <i v-show="!open" class="fa fa-caret-right"></i>
+            </span>
+
+            {{model.name}}
+
+            <span class="badge">
+              {{childrenCounter}}
+            </span>
+          </span>
+        </td>
+
+        <td class="deployment-column">
+          <span v-if="!isFolder && model.last_deployment && model.last_deployment.iid">
+            #{{model.last_deployment.iid}}
+
+            <span v-if="model.last_deployment.user">
+              by
+              <a :href="model.last_deployment.user.web_url">
+                <img class="avatar has-tooltip s20"
+                  :src="model.last_deployment.user.avatar_url"
+                  :alt="userImageAltDescription"
+                  :title="model.last_deployment.user.username" />
+              </a>
+            </span>
+          </span>
+        </td>
+
+        <td>
+          <a v-if="!isFolder && model.last_deployment && model.last_deployment.deployable"
+            class="build-link"
+            :href="model.last_deployment.deployable.build_url">
+            {{model.last_deployment.deployable.name}} #{{model.last_deployment.deployable.id}}
+          </a>
+        </td>
+
+        <td>
+          <div v-if="!isFolder && model.last_deployment">
+            <commit-component
+              :tag="commitTag"
+              :ref="commitRef"
+              :commit_url="commitUrl"
+              :short_sha="commitShortSha"
+              :title="commitTitle"
+              :author="commitAuthor">
+            </commit-component>
+          </div>
+          <p v-if="!isFolder && !model.last_deployment" class="commit-title">
+            No deployments yet
+          </p>
+        </td>
+
+        <td>
+          <span v-if="!isFolder && model.last_deployment" class="environment-created-date-timeago">
+            {{createdDate}}
+          </span>
+        </td>
+
+        <td class="hidden-xs">
+          <div v-if="!isFolder">
+
+          </div>
+        </td>
+      </tr>
+
+      <tr v-if="open && isFolder"
+        is="environment-item"
+        v-for="model in model.children"
+        :model="model">
+      </tr>
+    `,
   });
 })();
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: `
+      <div class="branch-commit">
+
+        <div v-if="hasRef" class="icon-container">
+          <i v-if="tag" class="fa fa-tag"></i>
+          <i v-else class="fa fa-code-fork"></i>
+        </div>
+
+        <a v-if="hasRef" class="monospace branch-name" :href="ref.ref_url">
+          {{ref.name}}
+        </a>
+
+        <div class="icon-container commit-icon commit-icon-container">
+          <!-- svg goes here -->
+        </div>
+
+        <a class="commit-id monospace" :href="commit_url">
+          {{short_sha}}
+        </a>
+
+        <p class="commit-title">
+          <span v-if="title">
+            <!-- commit author info-->
+            <a v-if="hasAuthor" class="avatar-image-container" :href="author.web_url">
+              <img
+              class="avatar has-tooltip s20"
+                :src="author.avatar_url"
+                :alt="userImageAltDescription"
+                :title="author.username" />
+            </a>
+
+            <a class="commit-row-message" :href="commit_url">
+              {{title}}
+            </a>
+          </span>
+          <span v-else>
+            Cant find HEAD commit for this branch
+          </span>
+        </p>
+      </div>
+    `,
+  });
+})();
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');
       });
     });
   });
-- 
GitLab