comparison client/src/components/importqueue/Importqueue.vue @ 1559:5d84dcb79a54

layout importqueue
author Thomas Junk <thomas.junk@intevation.de>
date Wed, 12 Dec 2018 09:48:37 +0100
parents client/src/components/Importqueue.vue@0ded4c56978e
children 7ac802add1b9
comparison
equal deleted inserted replaced
1558:0ded4c56978e 1559:5d84dcb79a54
1 <template>
2 <div class="d-flex flex-row">
3 <div :class="spacerStyle"></div>
4 <div class="mt-3 importqueuecard flex-grow-1">
5 <div class="card shadow-xs">
6 <h6
7 class="mb-0 py-2 px-3 border-bottom d-flex text-info align-items-center"
8 >
9 <font-awesome-icon icon="tasks" class="mr-2"></font-awesome-icon>
10 <translate class="headline">Importqueue</translate>
11 </h6>
12 <div class="card-body importcardbody">
13 <div class="card-body importcardbody">
14 <div class="searchandfilter d-flex flex-row">
15 <div class="searchgroup input-group">
16 <div class="input-group-prepend">
17 <span class="input-group-text" id="search">
18 <font-awesome-icon icon="search"></font-awesome-icon>
19 </span>
20 </div>
21 <input
22 v-model="searchQuery"
23 type="text"
24 class="form-control"
25 placeholder
26 aria-label="Search"
27 aria-describedby="search"
28 />
29 </div>
30 <div class="filters">
31 <button
32 @click="setFilter('successful')"
33 :class="successfulStyle"
34 >
35 <translate>Successful</translate>
36 </button>
37 <button @click="setFilter('failed')" :class="failedStyle">
38 <translate>Failed</translate>
39 </button>
40 <button @click="setFilter('pending')" :class="pendingStyle">
41 <translate>Pending</translate>
42 </button>
43 <button @click="setFilter('rejected')" :class="rejectedStyle">
44 <translate>Rejected</translate>
45 </button>
46 <button @click="setFilter('accepted')" :class="acceptedStyle">
47 <translate>Accepted</translate>
48 </button>
49 </div>
50 </div>
51 <div class="text-left d-flex flex-row w-50 border-bottom">
52 <div class="header py-1 jobid mr-2">
53 <translate>Id</translate>
54 </div>
55 <div class="header py-1 enqueued mr-2">
56 <translate>Enqueued</translate>
57 </div>
58 <div class="header py-1 kind mr-2">
59 <translate>Kind</translate>
60 </div>
61 <div class="header py-1 user mr-2">
62 <translate>User</translate>
63 </div>
64 <div class="header py-1 signer mr-2">
65 <translate>Signer</translate>
66 </div>
67 <div class="header py-1 state mr-2">
68 <translate>State</translate>
69 </div>
70 </div>
71 <div class="text-left" v-for="job in filteredImports" :key="job.id">
72 <Importqueuedetail :job="job"></Importqueuedetail>
73 </div>
74 <div>
75 <button @click="refresh" class="btn btn-info refresh">
76 <translate>Refresh</translate>
77 </button>
78 </div>
79 </div>
80 </div>
81 </div>
82 </div>
83 </div>
84 </template>
85
86 <script>
87 /* This is Free Software under GNU Affero General Public License v >= 3.0
88 * without warranty, see README.md and license for details.
89 *
90 * SPDX-License-Identifier: AGPL-3.0-or-later
91 * License-Filename: LICENSES/AGPL-3.0.txt
92 *
93 * Copyright (C) 2018 by via donau
94 * – Österreichische Wasserstraßen-Gesellschaft mbH
95 * Software engineering by Intevation GmbH
96 *
97 * Author(s):
98 * Markus Kottländer <markus@intevation.de>
99 */
100 import { displayError } from "../../lib/errors.js";
101 import { mapState } from "vuex";
102 import { HTTP } from "../../lib/http.js";
103 import Importqueuedetail from "./Importqueuedetail";
104
105 export default {
106 name: "importqueue",
107 components: {
108 Importqueuedetail
109 },
110 data() {
111 return {
112 searchQuery: "",
113 successful: false,
114 failed: false,
115 pending: false,
116 rejected: false,
117 accepted: false
118 };
119 },
120 mounted() {
121 this.loadQueue();
122 },
123 methods: {
124 setFilter(name) {
125 this[name] = !this[name];
126 const allSet =
127 this.successful &&
128 this.failed &&
129 this.pending &&
130 this.accepted &&
131 this.rejected;
132 if (allSet) {
133 this.successful = false;
134 this.failed = false;
135 this.pending = false;
136 this.accepted = false;
137 this.rejected = false;
138 }
139 },
140 loadQueue() {
141 this.$store.dispatch("imports/getImports").catch(error => {
142 const { status, data } = error.response;
143 displayError({
144 title: this.$gettext("Backend Error"),
145 message: `${status}: ${data.message || data}`
146 });
147 });
148 },
149 refresh() {
150 this.loadQueue();
151 },
152 showDetails(id) {
153 HTTP.get("/imports/" + id, {
154 headers: { "X-Gemma-Auth": localStorage.getItem("token") }
155 })
156 .then(response => {
157 const { entries } = response.data;
158 this.entries = entries;
159 this.$modal.show("details");
160 })
161 .catch(error => {
162 const { status, data } = error.response;
163 displayError({
164 title: this.$gettext("Backend Error"),
165 message: `${status}: ${data.message || data}`
166 });
167 });
168 },
169 close() {
170 this.$modal.hide("details");
171 }
172 },
173 computed: {
174 ...mapState("imports", ["imports"]),
175 ...mapState("application", ["showSidebar"]),
176 sortIcon() {
177 return this.sortAsc ? "sort-amount-down" : "sort-amount-up";
178 },
179 filteredImports() {
180 const filtered = this.imports
181 .filter(element => {
182 if (!this.searchQuery) return true;
183 return [(element.kind, element.user, element.enqueued)].some(x => {
184 return x.toLowerCase().includes(this.searchQuery.toLowerCase());
185 });
186 })
187 .filter(y => {
188 if (
189 !this.successful &&
190 !this.failed &&
191 !this.pending &&
192 !this.accepted &&
193 !this.rejected
194 )
195 return true;
196 let filterCriteria = [];
197 if (this.successful) filterCriteria.push("successful");
198 if (this.failed) filterCriteria.push("failed");
199 if (this.pending) filterCriteria.push("pending");
200 if (this.accepted) filterCriteria.push("accepted");
201 if (this.rejected) filterCriteria.push("rejected");
202 const result = filterCriteria.map(selectedState => {
203 return y.state === selectedState;
204 });
205 return result.some(x => x);
206 });
207 return filtered;
208 },
209 spacerStyle() {
210 return [
211 "spacer ml-3",
212 {
213 "spacer-expanded": this.showSidebar,
214 "spacer-collapsed": !this.showSidebar
215 }
216 ];
217 },
218 successfulStyle() {
219 return {
220 btn: true,
221 "btn-light": !this.successful,
222 "btn-dark": this.successful
223 };
224 },
225 pendingStyle() {
226 return {
227 btn: true,
228 "btn-light": !this.pending,
229 "btn-dark": this.pending
230 };
231 },
232 failedStyle() {
233 return {
234 btn: true,
235 "btn-light": !this.failed,
236 "btn-dark": this.failed
237 };
238 },
239 rejectedStyle() {
240 return {
241 btn: true,
242 "btn-light": !this.rejected,
243 "btn-dark": this.rejected
244 };
245 },
246 acceptedStyle() {
247 return {
248 btn: true,
249 "btn-light": !this.accepted,
250 "btn-dark": this.accepted
251 };
252 }
253 }
254 };
255 </script>
256
257 <style lang="scss" scoped>
258 .jobid {
259 width: 80px;
260 }
261
262 .enqueued {
263 width: 120px;
264 }
265
266 .user {
267 width: 80px;
268 }
269
270 .signer {
271 width: 80px;
272 }
273
274 .kind {
275 width: 80px;
276 }
277
278 .state {
279 width: 80px;
280 }
281
282 .header {
283 font-weight: bold;
284 font-size: 0.9em;
285 }
286
287 .details thead {
288 display: block;
289 }
290 .details tbody {
291 display: block;
292 }
293
294 .details tbody {
295 height: 260px;
296 overflow-y: auto;
297 overflow-x: hidden;
298 }
299
300 .closebutton {
301 top: $small-offset;
302 }
303
304 .refresh {
305 position: absolute;
306 right: $offset;
307 bottom: $offset;
308 }
309
310 .spacer {
311 height: 100vh;
312 }
313
314 .spacer-collapsed {
315 min-width: $icon-width + $offset;
316 transition: $transition-fast;
317 }
318
319 .spacer-expanded {
320 min-width: $sidebar-width;
321 }
322
323 .importqueuecard {
324 width: 97%;
325 margin-left: $offset;
326 margin-right: $offset;
327 min-height: 20rem;
328 }
329
330 .card-body {
331 width: 100%;
332 margin-left: auto;
333 margin-right: auto;
334 }
335
336 .searchandfilter {
337 position: relative;
338 margin-bottom: $xx-large-offset;
339 }
340
341 .filters {
342 position: absolute;
343 right: 0;
344 }
345
346 .filters button {
347 margin-right: $small-offset;
348 }
349
350 .table td,
351 .table th {
352 border-top: 0 !important;
353 text-align: left;
354 padding: $small-offset !important;
355 }
356
357 .searchgroup {
358 position: absolute;
359 left: 0;
360 width: 45%;
361 }
362 </style>