Mercurial > gemma
changeset 2462:9ae2a2f758bb
client: make use of new table header/body components
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Mon, 04 Mar 2019 14:50:23 +0100 |
parents | b60efa7d4cee |
children | 8cc3cd1b27f2 |
files | client/src/components/Bottlenecks.vue client/src/components/ImportStretches.vue client/src/components/importschedule/Importschedule.vue client/src/components/systemconfiguration/PDFTemplates.vue client/src/components/ui/UITableBody.vue |
diffstat | 5 files changed, 251 insertions(+), 328 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/Bottlenecks.vue Mon Mar 04 13:53:09 2019 +0100 +++ b/client/src/components/Bottlenecks.vue Mon Mar 04 14:50:23 2019 +0100 @@ -5,123 +5,109 @@ title="Bottlenecks" :closeCallback="$parent.close" /> - <div class="row p-2 text-left small"> - <div class="col-5"> - <a href="#" @click="sortBy('name')" class="sort-link"> - <translate>Name</translate> - </a> - <font-awesome-icon - :icon="sortIcon" - class="ml-1" - v-if="sortColumn === 'name'" - ></font-awesome-icon> + <UITableHeader + :columns="[ + { id: 'name', title: 'Name', class: 'col-4' }, + { + id: 'latestMeasurement', + title: 'Latest Measurement', + class: 'col-3' + }, + { id: 'chainage', title: 'Chainage', class: 'col-3' } + ]" + @sortingChanged="sortBy" + /> + <UITableBody + :data="filteredAndSortedBottlenecks()" + :maxHeight="(showSplitscreen ? 18 : 35) + 'rem'" + :active="openBottleneck" + v-slot="{ item: bottleneck }" + > + <div class="col-4 py-2 text-left"> + <a href="#" @click="selectBottleneck(bottleneck)">{{ + bottleneck.properties.name + }}</a> </div> - <div class="col-2"> - <a href="#" @click="sortBy('latestMeasurement')" class="sort-link"> - <translate>Latest</translate> <br /> - <translate>Measurement</translate> - </a> - <font-awesome-icon - :icon="sortIcon" - class="ml-1" - v-if="sortColumn === 'latestMeasurement'" - ></font-awesome-icon> + <div class="col-3 py-2"> + {{ formatSurveyDate(bottleneck.properties.current) }} + </div> + <div class="col-3 py-2"> + {{ + displayCurrentChainage( + bottleneck.properties.from, + bottleneck.properties.to + ) + }} </div> - <div class="col-3"> - <a href="#" @click="sortBy('chainage')" class="sort-link"> - <translate>Chainage</translate> + <div class="col-2 pr-0 text-right d-flex flex-column"> + <a + class="text-info mt-auto mb-auto mr-2" + @click="loadSurveys(bottleneck)" + v-if="bottleneck.properties.current" + > + <font-awesome-icon + class="pointer" + icon="spinner" + fixed-width + spin + v-if="loading === bottleneck" + ></font-awesome-icon> + <font-awesome-icon + class="pointer" + icon="angle-down" + fixed-width + v-if="loading !== bottleneck && openBottleneck !== bottleneck" + ></font-awesome-icon> + <font-awesome-icon + class="pointer" + icon="angle-up" + fixed-width + v-if="loading !== bottleneck && openBottleneck === bottleneck" + ></font-awesome-icon> </a> - <font-awesome-icon - :icon="sortIcon" - class="ml-1" - v-if="sortColumn === 'chainage'" - ></font-awesome-icon> </div> - <div class="col-2"></div> - </div> - <div - class="bottleneck-list small text-left" - :style="'max-height: ' + (showSplitscreen ? 18 : 35) + 'rem'" - v-if="filteredAndSortedBottlenecks().length" - > <div - v-for="bottleneck in filteredAndSortedBottlenecks()" - :key="bottleneck.properties.name" - class="border-top row bottleneck-row mx-0" + :class="[ + 'col-12 p-0', + 'surveys', + { open: openBottleneck === bottleneck } + ]" > - <div class="col-5 py-2 text-left"> - <a href="#" @click="selectBottleneck(bottleneck)">{{ - bottleneck.properties.name - }}</a> - </div> - <div class="col-2 py-2"> - {{ formatSurveyDate(bottleneck.properties.current) }} - </div> - <div class="col-3 py-2"> - {{ - displayCurrentChainage( - bottleneck.properties.from, - bottleneck.properties.to - ) - }} - </div> - <div class="col-2 pr-0 text-right d-flex flex-column"> - <a - class="text-info mt-auto mb-auto mr-2" - @click="loadSurveys(bottleneck.properties.name)" - v-if="bottleneck.properties.current" - > - <font-awesome-icon - class="pointer" - icon="spinner" - fixed-width - spin - v-if="loading === bottleneck.properties.name" - ></font-awesome-icon> - <font-awesome-icon - class="pointer" - icon="angle-down" - fixed-width - v-if=" - loading !== bottleneck.properties.name && - openBottleneck !== bottleneck.properties.name - " - ></font-awesome-icon> - <font-awesome-icon - class="pointer" - icon="angle-up" - fixed-width - v-if=" - loading !== bottleneck.properties.name && - openBottleneck === bottleneck.properties.name - " - ></font-awesome-icon> - </a> - </div> - <div - :class="[ - 'col-12 p-0', - 'surveys', - { open: openBottleneck === bottleneck.properties.name } - ]" + <a + href="#" + class="d-inline-block px-3 py-2" + v-for="(survey, index) in openBottleneckSurveys" + :key="index" + @click="selectSurvey(survey, bottleneck)" > - <a - href="#" - class="d-block px-3 py-2" - v-for="(survey, index) in openBottleneckSurveys" - :key="index" - @click="selectSurvey(survey, bottleneck)" - >{{ formatSurveyDate(survey.date_info) }}</a - > - </div> + {{ formatSurveyDate(survey.date_info) }} + </a> </div> - </div> - <div v-else class="small text-center py-3 border-top"> - <translate>No results.</translate> - </div> + </UITableBody> </div> </template> +<style lang="sass" scoped> +.table-body + .row + > div:not(:last-child) + transition: background-color 0.3s, color 0.3s + &.active + > div:not(:last-child) + background-color: $color-info + color: #fff + a + color: #fff !important + .surveys + border-bottom: solid 1px $color-info + .surveys + overflow: hidden + max-height: 0 + &.open + overflow-y: auto + max-height: 5rem +</style> + <script> /* This is Free Software under GNU Affero General Public License v >= 3.0 * without warranty, see README.md and license for details. @@ -249,19 +235,18 @@ }); }); }, - sortBy(column) { - this.sortColumn = column; - this.sortDirection = this.sortDirection === "ASC" ? "DESC" : "ASC"; + sortBy(sorting) { + this.sortColumn = sorting.sortColumn; + this.sortDirection = sorting.sortDirection; }, - loadSurveys(name) { - this.openBottleneckSurveys = null; - if (name === this.openBottleneck) { + loadSurveys(bottleneck) { + if (bottleneck === this.openBottleneck) { this.openBottleneck = null; + this.openBottleneckSurveys = null; } else { - this.openBottleneck = name; - this.loading = name; + this.loading = bottleneck; - HTTP.get("/surveys/" + name, { + HTTP.get("/surveys/" + bottleneck.properties.name, { headers: { "X-Gemma-Auth": localStorage.getItem("token"), "Content-type": "text/xml; charset=UTF-8" @@ -271,6 +256,7 @@ this.openBottleneckSurveys = response.data.surveys.sort((a, b) => { return a.date_info < b.date_info ? 1 : -1; }); + this.openBottleneck = bottleneck; }) .catch(error => { const { status, data } = error.response; @@ -291,37 +277,3 @@ } }; </script> - -<style lang="scss" scoped> -.bottleneck-list { - overflow-y: auto; -} - -.bottleneck-list .bottleneck-row a { - text-decoration: none; -} - -.bottleneck-list .bottleneck-row:hover { - background: #fbfbfb; -} - -.surveys { - max-height: 0; - min-height: 0; - overflow: hidden; -} - -.surveys a:hover { - background: #f3f3f3; -} - -.surveys.open { - max-height: 250px; - overflow: auto; -} - -.sort-link { - color: #444; - font-weight: bold; -} -</style>
--- a/client/src/components/ImportStretches.vue Mon Mar 04 13:53:09 2019 +0100 +++ b/client/src/components/ImportStretches.vue Mon Mar 04 14:50:23 2019 +0100 @@ -5,60 +5,52 @@ title="Define Stretches" :closeCallback="$parent.close" /> - <div v-if="!edit" class="mb-3 mr-3 ml-3 text-left"> - <table v-if="stretches.length > 0" class="table"> - <thead> - <tr> - <th class="header"><translate>Name</translate></th> - <th class="header"><translate>Datum</translate></th> - <th class="header"><translate>Source organization</translate></th> - <th></th> - </tr> - </thead> - <tbody> - <tr class="small" v-for="(stretch, index) in stretches" :key="index"> - <td class=""> - <a - class="linkto text-info" - v-if="isInStaging(stretch.properties.name)" - @click="gotoStaging(getStagingLink(stretch.properties.name))" - > - {{ stretch.properties.name - }}<font-awesome-icon - class="ml-1 text-danger" - icon="exclamation-triangle" - fixed-width - ></font-awesome-icon - ><small class="ml-1">review</small> - </a> - <a v-else @click="moveMapToStretch(index)" href="#">{{ - stretch.properties.name - }}</a> - </td> - <td class=""> - {{ formatSurveyDate(stretch.properties["date_info"]) }} - </td> - <td>{{ stretch.properties["source_organization"] }}</td> - <td class="text-right"> - <button - class="btn btn-sm btn-dark mr-1" - @click="editStretch(index)" - > - <font-awesome-icon icon="pencil-alt" fixed-width /> - </button> - <button - class="btn btn-sm btn-dark" - @click="deleteStretch(stretch)" - > - <font-awesome-icon icon="trash" fixed-width /> - </button> - </td> - </tr> - </tbody> - </table> - <div class="mt-3" v-if="stretches.length == 0"> - <translate>No results.</translate> - </div> + <div v-if="!edit" class="mb-3"> + <UITableHeader + :columns="[ + { id: 'name', title: 'Name', class: 'col-4' }, + { id: 'date', title: 'Date', class: 'col-2' }, + { id: 'srcorg', title: 'Source organization', class: 'col-3' } + ]" + :sortable="false" + /> + <UITableBody :data="stretches" v-slot="{ item: stretch }"> + <div class="py-2 col-4 "> + <a + class="linkto text-info" + v-if="isInStaging(stretch.properties.name)" + @click="gotoStaging(getStagingLink(stretch.properties.name))" + > + {{ stretch.properties.name + }}<font-awesome-icon + class="ml-1 text-danger" + icon="exclamation-triangle" + fixed-width + ></font-awesome-icon + ><small class="ml-1">review</small> + </a> + <a v-else @click="moveMapToStretch(stretch)" href="#">{{ + stretch.properties.name + }}</a> + </div> + <div class="py-2 col-2"> + {{ formatSurveyDate(stretch.properties["date_info"]) }} + </div> + <div class="py-2 col-3"> + {{ stretch.properties["source_organization"] }} + </div> + <div class="py-2 col text-right"> + <button + class="btn btn-sm btn-dark mr-1" + @click="editStretch(stretch)" + > + <font-awesome-icon icon="pencil-alt" fixed-width /> + </button> + <button class="btn btn-sm btn-dark" @click="deleteStretch(stretch)"> + <font-awesome-icon icon="trash" fixed-width /> + </button> + </div> + </UITableBody> </div> <div v-if="edit"> <div class="ml-3 mr-3"> @@ -337,8 +329,8 @@ }); }); }, - editStretch(index) { - const properties = this.stretches[index].properties; + editStretch(stretch) { + const properties = stretch.properties; this.date_info = properties.date_info.split("T")[0]; this.id = properties.name; this.nobjbn = properties.nobjnam; @@ -376,10 +368,10 @@ } }); }, - moveMapToStretch(index) { + moveMapToStretch(stretch) { this.$store.commit("map/setLayerVisible", LAYERS.STRETCHES); this.$store.commit("map/moveToExtent", { - feature: this.stretches[index], + feature: stretch, zoom: 17, preventZoomOut: true });
--- a/client/src/components/importschedule/Importschedule.vue Mon Mar 04 13:53:09 2019 +0100 +++ b/client/src/components/importschedule/Importschedule.vue Mon Mar 04 14:50:23 2019 +0100 @@ -4,100 +4,81 @@ <div class="mt-3 w-100"> <div class="card flex-grow-1 schedulecard shadow-xs"> <UIBoxHeader icon="clock" title="Imports" /> - <div class="card-body schedulecardbody"> - <div class="card-body schedulecardbody"> - <div class="searchandfilter mb-3 w-50 d-flex flex-row"> - <div class="searchgroup input-group"> - <div class="input-group-prepend"> - <span class="input-group-text" id="search"> - <font-awesome-icon icon="search"></font-awesome-icon> - </span> - </div> - <input - v-model="searchQuery" - type="text" - class="form-control" - placeholder - aria-label="Search" - aria-describedby="search" - /> - </div> + <div class="searchandfilter p-3 w-50 mx-auto"> + <div class="searchgroup input-group"> + <div class="input-group-prepend"> + <span class="input-group-text" id="search"> + <font-awesome-icon icon="search"></font-awesome-icon> + </span> </div> - <transition name="fade"> - <table v-if="schedules.length" class="table table-hover"> - <thead> - <tr> - <th><translate>ID</translate></th> - <th><translate>Type</translate></th> - <th><translate>Author</translate></th> - <th><translate>Schedule</translate></th> - <th><translate>Email</translate></th> - <th style="width: 140px"></th> - </tr> - </thead> - <transition-group name="fade" tag="tbody"> - <tr v-for="schedule in schedules" :key="schedule.id"> - <td>{{ schedule.id }}</td> - <td>{{ schedule.kind.toUpperCase() }}</td> - <td>{{ schedule.user }}</td> - <td>{{ schedule.config.cron }}</td> - <td> - <font-awesome-icon - v-if="schedule.config['send-email']" - class="fa-fw mr-2" - fixed-width - icon="check" - ></font-awesome-icon> - </td> - <td class="text-right"> - <button - @click="editSchedule(schedule.id)" - class="btn btn-sm btn-dark mr-1" - :disabled="importScheduleDetailVisible" - > - <font-awesome-icon - icon="pencil-alt" - fixed-width - ></font-awesome-icon> - </button> - <button - @click="deleteSchedule(schedule)" - class="btn btn-sm btn-dark mr-1" - :disabled="importScheduleDetailVisible" - > - <font-awesome-icon - icon="trash" - fixed-width - ></font-awesome-icon> - </button> - <button - @click="triggerManualImport(schedule.id)" - class="btn btn-sm btn-dark" - :disabled="importScheduleDetailVisible" - > - <font-awesome-icon - icon="play" - fixed-width - ></font-awesome-icon> - </button> - </td> - </tr> - </transition-group> - </table> - <div v-else class="mt-4 small text-center py-3"> - <translate>No scheduled imports</translate> - </div> - </transition> - <div class="text-right"> - <button - :disabled="importScheduleDetailVisible" - @click="newImport" - class="btn btn-info newbutton" - > - <translate>New Import</translate> - </button> - </div> + <input + v-model="searchQuery" + type="text" + class="form-control" + placeholder + aria-label="Search" + aria-describedby="search" + /> + </div> + </div> + <UITableHeader + :columns="[ + { id: 'id', title: 'ID', class: 'col-1' }, + { id: 'type', title: 'Type', class: 'col-2' }, + { id: 'author', title: 'Author', class: 'col-2' }, + { id: 'schedule', title: 'Schedule', class: 'col-2' }, + { id: 'email', title: 'Email', class: 'col-2' } + ]" + :sortable="false" + /> + <UITableBody :data="schedules" v-slot="{ item: schedule }"> + <div class="py-2 col-1">{{ schedule.id }}</div> + <div class="py-2 col-2">{{ schedule.kind.toUpperCase() }}</div> + <div class="py-2 col-2">{{ schedule.user }}</div> + <div class="py-2 col-2">{{ schedule.config.cron }}</div> + <div class="py-2 col-2"> + <font-awesome-icon + v-if="schedule.config['send-email']" + class="fa-fw mr-2" + fixed-width + icon="check" + ></font-awesome-icon> </div> + <div class="py-2 col text-right"> + <button + @click="editSchedule(schedule.id)" + class="btn btn-sm btn-dark mr-1" + :disabled="importScheduleDetailVisible" + > + <font-awesome-icon + icon="pencil-alt" + fixed-width + ></font-awesome-icon> + </button> + <button + @click="deleteSchedule(schedule)" + class="btn btn-sm btn-dark mr-1" + :disabled="importScheduleDetailVisible" + > + <font-awesome-icon icon="trash" fixed-width></font-awesome-icon> + </button> + <button + @click="triggerManualImport(schedule.id)" + class="btn btn-sm btn-dark" + :disabled="importScheduleDetailVisible" + > + <font-awesome-icon icon="play" fixed-width></font-awesome-icon> + </button> + </div> + </UITableBody> + <div class="p-3 text-right"> + <button + :disabled="importScheduleDetailVisible" + @click="newImport" + class="btn btn-info newbutton" + > + <translate>New Import</translate> + </button> </div> </div> </div>
--- a/client/src/components/systemconfiguration/PDFTemplates.vue Mon Mar 04 13:53:09 2019 +0100 +++ b/client/src/components/systemconfiguration/PDFTemplates.vue Mon Mar 04 14:50:23 2019 +0100 @@ -11,34 +11,27 @@ /> </div> <div class="mt-1 border-bottom pb-4"> - <transition name="fade"> - <table class="table table-sm table-hover" v-if="templates.length"> - <thead> - <tr> - <th><translate>Name</translate></th> - <th><translate>Date</translate></th> - <th><translate>Country</translate></th> - <th></th> - </tr> - </thead> - <transition-group name="fade" tag="tbody"> - <tr v-for="template in templates" :key="template.name"> - <td>{{ template.name }}</td> - <td>{{ template.time }}</td> - <td v-if="template.country">{{ template.country }}</td> - <td v-else><i>global</i></td> - <td class="text-right"> - <button - class="btn btn-sm btn-dark" - @click="deleteTemplate(template)" - > - <font-awesome-icon icon="trash" /> - </button> - </td> - </tr> - </transition-group> - </table> - </transition> + <UITableHeader + :columns="[ + { id: 'name', title: 'Name', class: 'col-4' }, + { id: 'date', title: 'Date', class: 'col-4' }, + { id: 'country', title: 'Country', class: 'col-2' } + ]" + :sortable="false" + /> + <UITableBody :data="templates" v-slot="{ item: template }"> + <div class="py-2 col-4">{{ template.name }}</div> + <div class="py-2 col-4">{{ template.time }}</div> + <div class="py-2 col-2" v-if="template.country"> + {{ template.country }} + </div> + <div class="py-2 col-2" v-else><i>global</i></div> + <div class="col py-2 text-right"> + <button class="btn btn-sm btn-dark" @click="deleteTemplate(template)"> + <font-awesome-icon icon="trash" /> + </button> + </div> + </UITableBody> <button class="btn btn-info mt-2" @click="$refs.uploadTemplate.click()"> <font-awesome-icon icon="spinner"
--- a/client/src/components/ui/UITableBody.vue Mon Mar 04 13:53:09 2019 +0100 +++ b/client/src/components/ui/UITableBody.vue Mon Mar 04 14:50:23 2019 +0100 @@ -8,7 +8,7 @@ > <div v-for="(item, index) in data" - :key="index" + :key="key(index)" :class="['border-top row mx-0', { active: active === item }]" > <slot :item="item" :index="index"></slot> @@ -46,6 +46,11 @@ active: { type: [Object, Array] } + }, + methods: { + key(index) { + return index; + } } }; </script>