Mercurial > gemma
changeset 2543:a542045f28a6
staging: imports/overview2 alternative implementation
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Thu, 07 Mar 2019 16:54:29 +0100 |
parents | fc7d828695c9 |
children | c61339e676e0 |
files | client/src/components/Contextbox.vue client/src/components/importoverview/ImportOverviewAlt.vue client/src/router.js |
diffstat | 3 files changed, 477 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/Contextbox.vue Thu Mar 07 15:55:25 2019 +0100 +++ b/client/src/components/Contextbox.vue Thu Mar 07 16:54:29 2019 +0100 @@ -6,6 +6,9 @@ <ImportOverview v-if="contextBoxContent === 'importoverview'" ></ImportOverview> + <ImportOverviewAlt + v-if="contextBoxContent === 'importoverview2'" + ></ImportOverviewAlt> </div> </template> @@ -31,7 +34,9 @@ Bottlenecks: () => import("@/components/Bottlenecks"), Stretches: () => import("@/components/ImportStretches.vue"), ImportOverview: () => - import("@/components/importoverview/ImportOverview.vue") + import("@/components/importoverview/ImportOverview.vue"), + ImportOverviewAlt: () => + import("@/components/importoverview/ImportOverviewAlt.vue") }, computed: { ...mapState("application", [
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/src/components/importoverview/ImportOverviewAlt.vue Thu Mar 07 16:54:29 2019 +0100 @@ -0,0 +1,452 @@ +<template> + <div class="overview"> + <UIBoxHeader + icon="clipboard-check" + title="Staging Area" + :closeCallback="$parent.close" + /> + <div class="imports text-left ml-1 mr-1"> + <div class="mt-3 d-flex flex-row border-bottom"> + <div class="icons small condensed"> </div> + <div class="id small condensed">Id</div> + <div class="kind small condensed">Kind</div> + <div class="date small condensed"> + Date + </div> + <div class="enqueued small condensed"> + Imported + </div> + <div class="user small condensed">User</div> + <div class="actions small condensed"> </div> + </div> + <div class="d-flex flex-row" v-for="entry in importQueue" :key="entry.id"> + <div class="d-flex flex-column w-100"> + <div class="d-flex flex-row"> + <div class="icons"> + <font-awesome-icon + @click="toggleDetails(entry.id)" + class="pointer text-info" + v-if="show != entry.id" + icon="angle-right" + fixed-width + ></font-awesome-icon> + <font-awesome-icon + @click="toggleDetails(entry.id)" + class="pointer text-info" + v-if="show == entry.id" + icon="angle-down" + fixed-width + ></font-awesome-icon> + </div> + <div class="id small condensed">{{ entry.id }}</div> + <div class="kind small condensed"> + {{ entry.kind.toUpperCase() }} + </div> + <div class="date small condensed"> + {{ formatSurveyDate(entry.summary.date) }} + </div> + <div class="enqueued small condensed"> + {{ formatSurveyDate(entry.enqueued.split("T")[0]) }} + </div> + <div class="user small condensed">{{ entry.user }}</div> + <div class="actions small condensed"> + <font-awesome-icon + v-if="entry.warnings" + class="ml-1 text-warning text-info" + icon="exclamation-triangle" + fixed-width + ></font-awesome-icon> + </div> + </div> + <div class="d-flex flex-row" v-if="show == entry.id"> + <div class="ml-1 details d-flex flex-column"> + <div + v-if="isApprovedGaugeMeasurement(entry.kind.toUpperCase())" + class="d-flex flex-row" + > + <font-awesome-icon + @click="toggleAdditional(entry.id)" + class="pointer text-info" + v-if="showAdditional != entry.id" + icon="angle-right" + fixed-width + ></font-awesome-icon> + <font-awesome-icon + @click="toggleAdditional(entry.id)" + class="pointer text-info" + v-if="showAdditional == entry.id" + icon="angle-down" + fixed-width + ></font-awesome-icon> + <small class="condensed">Additional Info</small> + </div> + <div + v-if="showAdditional == entry.id" + class="additionalinfo ml-4" + > + <div v-for="(result, index) in entry.summary" :key="index"> + <font-awesome-icon + @click="toggleDiff(index)" + class="pointer text-info" + v-if="showDiff != index" + icon="angle-right" + fixed-width + ></font-awesome-icon> + <font-awesome-icon + @click="toggleDiff(index)" + class="pointer text-info" + v-if="showDiff == index" + icon="angle-down" + fixed-width + ></font-awesome-icon> + <span + v-if="result.versions.length == 1" + class="agmcode text-left" + ><small + >{{ result["fk-gauge-id"] }} + <translate class="mr-1">( New )</translate></small + ></span + > + <span + v-if="result.versions.length == 2" + class="agmcode text-left" + ><small>{{ result["fk-gauge-id"] }}</small></span + > + <span class="agmdetail text-left" + ><small>{{ + formatDateTime(result["measure-date"]) + }}</small></span + > + <div v-if="showDiff == index" class="ml-1"> + <div> + <div class="d-flex flex-row pl-3 text-left"> + <div class="header border-bottom agmdetailskeys"> + <small><translate>Value</translate></small> + </div> + <div + v-if="result.versions.length == 2" + class="header border-bottom agmdetailsvalues" + > + <small><translate>Old</translate></small> + </div> + <div class="header border-bottom agmdetailsvalues"> + <small><translate>New</translate></small> + </div> + </div> + <div + class="d-flex flex-row pl-3 text-left" + v-for="(entry, index) in Object.keys( + result.versions[0] + )" + :key="index" + > + <div + v-if=" + result.versions.length == 1 || + result.versions[0][entry] != + result.versions[1][entry] + " + class="agmdetailskeys" + > + <small>{{ entry }}</small> + </div> + <div + v-if=" + result.versions.length == 1 || + result.versions[0][entry] != + result.versions[1][entry] + " + class="agmdetailsvalues" + > + <small>{{ result.versions[0][entry] }}</small> + </div> + <div + v-if=" + result.versions.length == 2 && + result.versions[0][entry] != + result.versions[1][entry] + " + class="agmdetailsvalues" + > + <small>{{ result.versions[1][entry] }}</small> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="d-flex flex-row"> + <div class="d-flex flex-column"> + <div class="d-flex flex-row"> + <font-awesome-icon + @click="toggleLogs(entry.id)" + class="pointer text-info" + v-if="showLogs != entry.id" + icon="angle-right" + fixed-width + ></font-awesome-icon> + <font-awesome-icon + @click="toggleLogs(entry.id)" + class="pointer text-info" + v-if="showLogs == entry.id" + icon="angle-down" + fixed-width + ></font-awesome-icon> + <small class="condensed">Logs</small> + </div> + <div v-if="showLogs == entry.id" class="ml-4 logentries"> + <div + v-for="(logentry, index) in logEntries" + :key="index" + class="d-flex flex-row" + > + <small + :class="[ + 'condensed type', + { + 'text-danger': + logentry.kind.toUpperCase() == 'ERROR', + 'text-warning': + logentry.kind.toUpperCase() == 'WARN' + } + ]" + >{{ logentry.kind.toUpperCase() }}</small + > + <small + :class="[ + 'condensed type', + { + 'text-danger': + logentry.kind.toUpperCase() == 'ERROR', + 'text-warning': + logentry.kind.toUpperCase() == 'WARN' + } + ]" + >{{ logentry.time }}</small + > + <small + :class="[ + 'condensed type', + { + 'text-danger': + logentry.kind.toUpperCase() == 'ERROR', + 'text-warning': + logentry.kind.toUpperCase() == 'WARN' + } + ]" + >{{ logentry.message }}</small + > + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</template> + +<script> +import { displayError } from "@/lib/errors.js"; +import { HTTP } from "@/lib/http"; +import { formatSurveyDate, formatDateTime } from "@/lib/date.js"; + +//import { mapState } from "vuex"; + +const NODETAILS = -1; +const NODIFF = -1; + +export default { + name: "importoverviewalt", + data() { + return { + showDiff: NODIFF, + importQueue: [], + logEntries: [], + show: NODETAILS, + showAdditional: NODETAILS, + showLogs: NODETAILS + }; + }, + methods: { + isFairwayDimension(kind) { + return kind === "FD"; + }, + isApprovedGaugeMeasurement(kind) { + return kind === "AGM"; + }, + isBottleneck(kind) { + return kind === "BN" || kind === "UBN"; + }, + isStretch(kind) { + return kind === "ST"; + }, + toggleAdditional(id) { + if (id === this.showAdditional) { + this.showAdditional = NODETAILS; + return; + } + this.showAdditional = id; + }, + toggleDiff(id) { + if (id === this.showDiff) { + this.showDiff = NODIFF; + return; + } + this.showDiff = id; + }, + toggleLogs(id) { + if (id === this.showLogs) { + this.showLogs = NODETAILS; + return; + } + this.loadLogEntries(id); + }, + toggleDetails(id) { + if (id === this.show) { + this.show = NODETAILS; + this.showAdditional = NODETAILS; + this.showLogs = NODETAILS; + return; + } + this.show = id; + }, + refresh() { + this.reload = true; + this.loadImportQueue(); + this.loadLogs(); + }, + formatSurveyDate(date) { + return formatSurveyDate(date); + }, + formatDateTime(date) { + return formatDateTime(date); + }, + loadLogEntries(id) { + HTTP.get("/imports/" + id, { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + const { entries } = response.data; + this.logEntries = entries; + this.showLogs = id; + }) + .catch(error => { + const { status, data } = error.response; + displayError({ + title: this.$gettext("Backend Error"), + message: `${status}: ${data.message || data}` + }); + }); + }, + loadImportQueue() { + HTTP.get("/imports?states=running,pending", { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + this.importQueue = response.data.imports; + }) + .catch(error => { + const { status, data } = error.response; + displayError({ + title: "Backend Error", + message: `${status}: ${data.message || data}` + }); + }); + }, + loadLogs() { + this.$store + .dispatch("imports/getImports") + .then(() => { + this.reload = false; + }) + .catch(error => { + const { status, data } = error.response; + displayError({ + title: this.$gettext("Backend Error"), + message: `${status}: ${data.message || data}` + }); + }); + } + }, + mounted() { + this.refresh(); + }, + NODETAILS: NODETAILS +}; +</script> + +<style lang="scss" scoped> +.agmdetailskeys { + width: 100px; +} + +.agmdetailsvalues { + width: 200px; +} + +.overview { + max-height: 800px; +} +.logentries { + max-height: 400px; + max-width: 600px; + font-size: smaller; + white-space: nowrap; + line-height: 1.1em; + overflow: auto; +} + +.additionalinfo { + max-width: 650px; + max-height: 200px; + overflow-y: auto; +} + +.additionalinfo > div:hover { + background: #eee; +} + +.logentries > div:hover { + background: #eee; +} + +.details { + width: 100%; + padding: 5px; + cursor: pointer; +} + +.imports { + line-height: 0.8rem; +} + +.icons { + width: 4%; +} + +.id { + width: 10%; +} + +.kind { + width: 10%; +} + +.date { + width: 20%; +} + +.enqueued { + width: 20%; +} + +.user { + width: 10%; +} +.actions { + width: 16%; +} +</style>
--- a/client/src/router.js Thu Mar 07 15:55:25 2019 +0100 +++ b/client/src/router.js Thu Mar 07 16:54:29 2019 +0100 @@ -194,6 +194,25 @@ } }, { + path: "/imports/overview2/:id?", + name: "importoverview2", + component: Main, + meta: { + requiresAuth: true + }, + beforeEnter: (to, from, next) => { + const isWaterwayAdmin = store.getters["user/isWaterwayAdmin"]; + if (!isWaterwayAdmin) { + next("/"); + } else { + store.commit("application/showContextBox", true); + store.commit("application/contextBoxContent", "importoverview2"); + store.commit("application/showSearchbar", true); + next(); + } + } + }, + { path: "/stretches", name: "stretches", component: Main,