From 14fadb2703ee1e047bbc6dc9db9bb7eefbcb4b57 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Sun, 13 Dec 2020 11:38:42 +0100
Subject: [PATCH] UI: implemented jobs listing

---
 vospace-ui-frontend/src/App.vue               |  3 +++
 .../src/api/mock/data/job.json                |  3 ++-
 .../src/api/mock/data/jobs.json               | 11 +++++++++
 vospace-ui-frontend/src/api/mock/index.js     |  4 ++++
 vospace-ui-frontend/src/components/Jobs.vue   | 24 +++++++++++++++++++
 .../src/components/JobsMenuItem.vue           | 16 +++++++++++++
 .../src/components/TopMenu.vue                | 13 +++++++++-
 vospace-ui-frontend/src/router.js             |  4 ++++
 vospace-ui-frontend/src/store.js              | 23 +++++++++++++++---
 9 files changed, 96 insertions(+), 5 deletions(-)
 create mode 100644 vospace-ui-frontend/src/api/mock/data/jobs.json
 create mode 100644 vospace-ui-frontend/src/components/Jobs.vue
 create mode 100644 vospace-ui-frontend/src/components/JobsMenuItem.vue

diff --git a/vospace-ui-frontend/src/App.vue b/vospace-ui-frontend/src/App.vue
index 1aced9b..4081bff 100644
--- a/vospace-ui-frontend/src/App.vue
+++ b/vospace-ui-frontend/src/App.vue
@@ -28,6 +28,9 @@ export default {
   }),
   components: {
     TopMenu
+  },
+  mounted() {
+    this.$store.dispatch('loadJobs');
   }
 }
 </script>
diff --git a/vospace-ui-frontend/src/api/mock/data/job.json b/vospace-ui-frontend/src/api/mock/data/job.json
index 633abc9..946c270 100644
--- a/vospace-ui-frontend/src/api/mock/data/job.json
+++ b/vospace-ui-frontend/src/api/mock/data/job.json
@@ -1,4 +1,5 @@
 {
   "id": "1234",
-  "status": "EXECUTING"
+  "status": "EXECUTING",
+  "read": true
 }
diff --git a/vospace-ui-frontend/src/api/mock/data/jobs.json b/vospace-ui-frontend/src/api/mock/data/jobs.json
new file mode 100644
index 0000000..1c4c53b
--- /dev/null
+++ b/vospace-ui-frontend/src/api/mock/data/jobs.json
@@ -0,0 +1,11 @@
+[{
+    "id": "1",
+    "status": "COMPLETED",
+    "read": true
+  },
+  {
+    "id": "2",
+    "status": "COMPLETED",
+    "read": true
+  }
+]
diff --git a/vospace-ui-frontend/src/api/mock/index.js b/vospace-ui-frontend/src/api/mock/index.js
index 45c0226..ed27af4 100644
--- a/vospace-ui-frontend/src/api/mock/index.js
+++ b/vospace-ui-frontend/src/api/mock/index.js
@@ -2,6 +2,7 @@ import root from 'raw-loader!./data/nodes/root.html';
 import folder1 from 'raw-loader!./data/nodes/folder1.html';
 import folder2 from 'raw-loader!./data/nodes/folder2.html';
 import job from './data/job';
+import jobs from './data/jobs';
 import store from '../../store';
 
 const fetch = (mockData, showLoading = true, time = 500) => {
@@ -36,5 +37,8 @@ export default {
   },
   startRecallFromTapeJob() {
     return fetch(job);
+  },
+  loadJobs() {
+    return fetch(jobs, false);
   }
 }
diff --git a/vospace-ui-frontend/src/components/Jobs.vue b/vospace-ui-frontend/src/components/Jobs.vue
new file mode 100644
index 0000000..b0abb7e
--- /dev/null
+++ b/vospace-ui-frontend/src/components/Jobs.vue
@@ -0,0 +1,24 @@
+<template>
+<table class="table b-table table-striped table-hover">
+  <thead>
+    <tr>
+      <th>Id</th>
+      <th>Status</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr v-for="job in jobs" :key="job.id">
+      <td>{{job.id}}</td>
+      <td>{{job.status}}</td>
+    </tr>
+  </tbody>
+</table>
+</template>
+
+<script>
+export default {
+  computed: {
+    jobs() { return this.$store.state.jobs }
+  }
+}
+</script>
diff --git a/vospace-ui-frontend/src/components/JobsMenuItem.vue b/vospace-ui-frontend/src/components/JobsMenuItem.vue
new file mode 100644
index 0000000..688688f
--- /dev/null
+++ b/vospace-ui-frontend/src/components/JobsMenuItem.vue
@@ -0,0 +1,16 @@
+<template>
+<b-navbar-nav>
+  <b-nav-item href="#/jobs">
+    <strong>Jobs</strong>&nbsp;
+    <b-badge variant="light">{{jobs.length}} <span class="sr-only">unread messages</span></b-badge>
+  </b-nav-item>
+</b-navbar-nav>
+</template>
+
+<script>
+export default {
+  computed: {
+    jobs() { return this.$store.state.jobs }
+  }
+}
+</script>
diff --git a/vospace-ui-frontend/src/components/TopMenu.vue b/vospace-ui-frontend/src/components/TopMenu.vue
index 1115343..813bddf 100644
--- a/vospace-ui-frontend/src/components/TopMenu.vue
+++ b/vospace-ui-frontend/src/components/TopMenu.vue
@@ -1,11 +1,22 @@
 <template>
 <div>
   <b-navbar toggleable="lg" type="dark" id="top-menu">
-    <b-navbar-brand href="#" class="d-none d-md-block">VOSpace</b-navbar-brand>
+    <b-navbar-brand href="#/" class="d-none d-md-block">VOSpace</b-navbar-brand>
+    <JobsMenuItem />
   </b-navbar>
 </div>
 </template>
 
+<script>
+import JobsMenuItem from './JobsMenuItem.vue';
+
+export default {
+  components: {
+    JobsMenuItem
+  }
+}
+</script>
+
 <style>
 #top-menu {
   background-color: #093784;
diff --git a/vospace-ui-frontend/src/router.js b/vospace-ui-frontend/src/router.js
index 2bb82a7..6b8ab99 100644
--- a/vospace-ui-frontend/src/router.js
+++ b/vospace-ui-frontend/src/router.js
@@ -1,6 +1,7 @@
 import VueRouter from 'vue-router';
 
 import Main from './components/Main.vue';
+import Jobs from './components/Jobs.vue';
 
 export default new VueRouter({
   routes: [{
@@ -10,5 +11,8 @@ export default new VueRouter({
     name: 'nodes',
     path: '/nodes/:path(.*)',
     component: Main
+  }, {
+    path: '/jobs',
+    component: Jobs
   }]
 })
diff --git a/vospace-ui-frontend/src/store.js b/vospace-ui-frontend/src/store.js
index f4b4a33..14255d7 100644
--- a/vospace-ui-frontend/src/store.js
+++ b/vospace-ui-frontend/src/store.js
@@ -11,7 +11,8 @@ export default new Vuex.Store({
   state: {
     path: '',
     loading: true,
-    tapeButtonEnabled: false
+    tapeButtonEnabled: false,
+    jobs: []
   },
   mutations: {
     setLoading(state, loading) {
@@ -25,6 +26,17 @@ export default new Vuex.Store({
     },
     setTapeButtonEnabled(state, value) {
       state.tapeButtonEnabled = value;
+    },
+    setJobs(state, jobs) {
+      // empty the array
+      state.jobs.splice(0, jobs.length);
+      // fill again
+      for (let i = 0; i < jobs.length; i++) {
+        state.jobs.push(jobs[i]);
+      }
+    },
+    addJob(state, job) {
+      state.jobs.push(job);
     }
   },
   actions: {
@@ -45,16 +57,21 @@ export default new Vuex.Store({
     computeButtonVisibility({ commit }) {
       commit('setTapeButtonEnabled', document.querySelectorAll('#nodes input.tape:checked').length > 0);
     },
-    startRecallFromTapeJob() {
+    startRecallFromTapeJob({ commit }) {
       let tapeCheckboxes = document.querySelectorAll('#nodes input.tape:checked');
       let paths = [];
       for (let i = 0; i < tapeCheckboxes.length; i++) {
         paths.push(tapeCheckboxes[i].getAttribute('data-node'));
       }
       client.startRecallFromTapeJob(paths)
-        .then(() => {
+        .then(job => {
           main.showInfo('Job started');
+          commit('addJob', job);
         });
+    },
+    loadJobs({ commit }) {
+      client.loadJobs()
+        .then(jobs => commit('setJobs', jobs));
     }
   }
 });
-- 
GitLab