Mercurial > gemma
changeset 1554:15d736a402c9
importqueue as collapsible
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Tue, 11 Dec 2018 13:33:52 +0100 |
parents | 35f85da41fdb |
children | a3c2b192daa2 |
files | client/package.json client/src/components/admin/Importqueue.vue client/src/components/admin/Importqueuedetail.vue client/src/main.js client/yarn.lock |
diffstat | 5 files changed, 265 insertions(+), 103 deletions(-) [+] |
line wrap: on
line diff
--- a/client/package.json Tue Dec 11 09:59:23 2018 +0100 +++ b/client/package.json Tue Dec 11 13:33:52 2018 +0100 @@ -41,7 +41,6 @@ "vue-clipboard2": "^0.2.1", "vue-color": "^2.6.0", "vue-highlightjs": "^1.3.3", - "vue-js-modal": "^1.3.27", "vue-js-toggle-button": "^1.3.0", "vue-router": "^3.0.2", "vue-snotify": "^3.2.1",
--- a/client/src/components/admin/Importqueue.vue Tue Dec 11 09:59:23 2018 +0100 +++ b/client/src/components/admin/Importqueue.vue Tue Dec 11 13:33:52 2018 +0100 @@ -48,30 +48,29 @@ </button> </div> </div> - <table class="table"> - <thead> - <tr> - <th><translate>Enqueued</translate></th> - <th><translate>Kind</translate></th> - <th><translate>User</translate></th> - <th><translate>Signer</translate></th> - <th><translate>State</translate></th> - </tr> - </thead> - <tbody> - <tr - @click="showDetails(job.id)" - v-for="job in filteredImports" - :key="job.id" - > - <td>{{ formatSurveyDate(job.enqueued) }}</td> - <td>{{ job.kind }}</td> - <td>{{ job.user }}</td> - <td>{{ job.signer }}</td> - <td>{{ job.state }}</td> - </tr> - </tbody> - </table> + <div class="text-left d-flex flex-row border-bottom"> + <div class="header py-1 jobid mr-2"> + <translate>Id</translate> + </div> + <div class="header py-1 enqueued mr-2"> + <translate>Enqueued</translate> + </div> + <div class="header py-1 kind mr-2"> + <translate>Kind</translate> + </div> + <div class="header py-1 user mr-2"> + <translate>User</translate> + </div> + <div class="header py-1 signer mr-2"> + <translate>Signer</translate> + </div> + <div class="header py-1 state mr-2"> + <translate>State</translate> + </div> + </div> + <div class="text-left" v-for="job in filteredImports" :key="job.id"> + <Importqueuedetail :job="job"></Importqueuedetail> + </div> <div> <button @click="refresh" class="btn btn-info refresh"> <translate>Refresh</translate> @@ -81,37 +80,6 @@ </div> </div> </div> - <modal name="details" :heigth="400" :width="600" :scrollable="true"> - <div @click="close" class="ui-element closebutton"> - <font-awesome-icon icon="times"></font-awesome-icon> - </div> - <div class="details"> - <table class="table"> - <thead> - <tr> - <th class="first"><translate>Kind</translate></th> - <th class="second"> - <a href="#" @click="sortAsc = !sortAsc" class="sort-link" - ><translate>Date</translate> - <font-awesome-icon - :icon="sortIcon" - class="ml-1" - ></font-awesome-icon - ></a> - </th> - <th class="third"><translate>Message</translate></th> - </tr> - </thead> - <tbody> - <tr v-for="(entry, index) in sortedEntries" :key="index"> - <td class="first">{{ entry.kind }}</td> - <td class="second">{{ formatSurveyDate(entry.time) }}</td> - <td class="third">{{ entry.message }}</td> - </tr> - </tbody> - </table> - </div> - </modal> </div> </template> @@ -132,10 +100,13 @@ import { displayError } from "../../lib/errors.js"; import { mapState } from "vuex"; import { HTTP } from "../../lib/http.js"; -import { formatSurveyDate } from "../../lib/date.js"; +import Importqueuedetail from "./Importqueuedetail"; export default { name: "importqueue", + components: { + Importqueuedetail + }, data() { return { searchQuery: "", @@ -143,21 +114,13 @@ failed: false, pending: false, rejected: false, - accepted: false, - entries: [], - sortAsc: true + accepted: false }; }, mounted() { this.loadQueue(); }, methods: { - formatSurveyDate(date) { - return formatSurveyDate(date); - }, - clearEntries() { - this.entries = []; - }, setFilter(name) { this[name] = !this[name]; const allSet = @@ -210,21 +173,6 @@ computed: { ...mapState("imports", ["imports"]), ...mapState("application", ["showSidebar"]), - sortedEntries() { - let sorted = this.entries.slice(); - sorted.sort((r1, r2) => { - let d1 = new Date(r1.time); - let d2 = new Date(r2.time); - if (d2 < d1) { - return !this.sortAsc ? -1 : 1; - } - if (d2 > d1) { - return !this.sortAsc ? 1 : -1; - } - return 0; - }); - return sorted; - }, sortIcon() { return this.sortAsc ? "sort-amount-down" : "sort-amount-up"; }, @@ -307,6 +255,35 @@ </script> <style lang="scss" scoped> +.jobid { + width: 80px; +} + +.enqueued { + width: 120px; +} + +.user { + width: 80px; +} + +.signer { + width: 80px; +} + +.kind { + width: 80px; +} + +.state { + width: 80px; +} + +.header { + font-weight: bold; + font-size: 0.9em; +} + .details thead { display: block; } @@ -320,21 +297,6 @@ overflow-x: hidden; } -.first { - width: 65px; - padding-left: 0px; -} - -.second { - width: 180px; - padding-left: 0px; -} - -.third { - width: 355px; - padding-left: 0px; -} - .closebutton { top: $small-offset; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/admin/Importqueuedetail.vue Tue Dec 11 13:33:52 2018 +0100 @@ -0,0 +1,208 @@ +<template> + <div class="d-flex flex-column py-1"> + <div class="d-flex flex-row"> + <div @click="showDetails(job.id)" class="jobid mr-2">{{ job.id }}</div> + <div @click="showDetails(job.id)" class="enqueued mr-2"> + {{ formatDate(job.enqueued) }} + </div> + <div @click="showDetails(job.id)" class="kind mr-2">{{ job.kind }}</div> + <div @click="showDetails(job.id)" class="user mr-2">{{ job.user }}</div> + <div @click="showDetails(job.id)" class="signer mr-2"> + {{ job.signer }} + </div> + <div @click="showDetails(job.id)" class="state mr-2">{{ job.state }}</div> + </div> + <div class="d-flex flex-row"> + <div :class="collapse"> + <table class="table table-responsive"> + <thead> + <tr> + <th class="first"> + <small><translate>Kind</translate></small> + </th> + <th class="second"> + <a href="#" @click="sortAsc = !sortAsc" class="sort-link" + ><small><translate>Date</translate></small> + <small + ><font-awesome-icon + :icon="sortIcon" + class="ml-1" + ></font-awesome-icon></small + ></a> + </th> + <th class="third"> + <small><translate>Message</translate></small> + </th> + </tr> + </thead> + <tbody> + <tr + v-for="(entry, index) in sortedEntries" + :key="index" + class="detailsrow" + > + <td class="first"> + <small>{{ entry.kind }}</small> + </td> + <td class="second"> + <small>{{ formatDate(entry.time) }}</small> + </td> + <td class="third"> + <small>{{ entry.message }}</small> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> +</template> + +<script> +/* This is Free Software under GNU Affero General Public License v >= 3.0 + * without warranty, see README.md and license for details. + * + * SPDX-License-Identifier: AGPL-3.0-or-later + * License-Filename: LICENSES/AGPL-3.0.txt + * + * Copyright (C) 2018 by via donau + * – Österreichische Wasserstraßen-Gesellschaft mbH + * Software engineering by Intevation GmbH + * + * Author(s): + * Thomas Junk <thomas.junk@intevation.de> + */ + +import { HTTP } from "../../lib/http.js"; +import { displayError } from "../../lib/errors.js"; +import locale2 from "locale2"; + +export default { + name: "importqueuedetail", + props: ["job"], + data() { + return { + show: false, + entries: [], + sortAsc: true + }; + }, + methods: { + formatDate(date) { + return date + ? new Date(date).toLocaleDateString(locale2, { + day: "2-digit", + month: "2-digit", + year: "numeric" + }) + : ""; + }, + showDetails(id) { + if (this.show) { + this.show = false; + return; + } + HTTP.get("/imports/" + id, { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + const { entries } = response.data; + this.entries = entries; + this.show = true; + }) + .catch(error => { + const { status, data } = error.response; + displayError({ + title: this.$gettext("Backend Error"), + message: `${status}: ${data.message || data}` + }); + }); + } + }, + computed: { + sortedEntries() { + let sorted = this.entries.slice(); + sorted.sort((r1, r2) => { + let d1 = new Date(r1.time); + let d2 = new Date(r2.time); + if (d2 < d1) { + return !this.sortAsc ? -1 : 1; + } + if (d2 > d1) { + return !this.sortAsc ? 1 : -1; + } + return 0; + }); + return sorted; + }, + sortIcon() { + return this.sortAsc ? "sort-amount-down" : "sort-amount-up"; + }, + collapse() { + return { + animated: true, + fadeIn: this.show, + details: true, + collapse: true, + show: this.show + }; + } + } +}; +</script> + +<style lang="scss" scoped> +.jobid { + width: 80px; +} + +.enqueued { + width: 120px; +} + +.user { + width: 80px; +} + +.signer { + width: 80px; +} + +.kind { + width: 80px; +} + +.state { + width: 80px; +} + +.details { + background-color: #fafafa; + width: 50%; +} + +.detailsrow { + line-height: 0.1em; +} + +.first { + width: 65px; + padding-left: 0px; + border-top: 0px; + padding-bottom: $small-offset; +} + +.second { + width: 100px; + padding-left: 0px; + border-top: 0px; + padding-bottom: $small-offset; +} + +.third { + width: 355px; + padding-left: 0px; + border-top: 0px; + padding-bottom: $small-offset; +} +</style>
--- a/client/src/main.js Tue Dec 11 09:59:23 2018 +0100 +++ b/client/src/main.js Tue Dec 11 13:33:52 2018 +0100 @@ -120,9 +120,7 @@ faWrench ); import ToggleButton from "vue-js-toggle-button"; -import VModal from "vue-js-modal"; -Vue.use(VModal); Vue.use(ToggleButton); Vue.component("font-awesome-icon", FontAwesomeIcon);
--- a/client/yarn.lock Tue Dec 11 09:59:23 2018 +0100 +++ b/client/yarn.lock Tue Dec 11 13:33:52 2018 +0100 @@ -10768,11 +10768,6 @@ tsconfig "^7.0.0" vue-template-es2015-compiler "^1.6.0" -vue-js-modal@^1.3.27: - version "1.3.27" - resolved "https://registry.yarnpkg.com/vue-js-modal/-/vue-js-modal-1.3.27.tgz#c0733d439c9f3c0f0e6a271b3d85604d5328e039" - integrity sha512-w27jHJWTRlcA7qQLs3yM6mi2wFsMHdqHTfyTxO7ENOCInoBY2bIECpAZZ9e8mD8Ka39AaBVkECf95NHE7/oqNg== - vue-js-toggle-button@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/vue-js-toggle-button/-/vue-js-toggle-button-1.3.0.tgz#59240f215fd502f54f0c210c5fac878960b0131c"