Mercurial > gemma
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> |