Mercurial > gemma
changeset 2874:b9a6abef9f1c
client: more unified table layout
Expandable/collapsible rows are now also handled by the component
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Mon, 01 Apr 2019 11:51:03 +0200 |
parents | b1707f60f241 |
children | 84effca50751 |
files | client/src/components/Bottlenecks.vue client/src/components/ImportStretches.vue client/src/components/importoverview/ImportOverview.vue client/src/components/importoverview/LogEntry.vue client/src/components/importschedule/Importschedule.vue client/src/components/systemconfiguration/PDFTemplates.vue client/src/components/ui/UITableBody.vue client/src/components/ui/UITableHeader.vue client/src/components/usermanagement/Usermanagement.vue |
diffstat | 9 files changed, 267 insertions(+), 276 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/Bottlenecks.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/Bottlenecks.vue Mon Apr 01 11:51:03 2019 +0200 @@ -7,11 +7,11 @@ /> <UITableHeader :columns="[ - { id: 'properties.name', title: `${nameLabel}`, width: '200px' }, + { id: 'properties.name', title: `${nameLabel}`, width: '230px' }, { id: 'properties.responsible_country', title: `${countryLabel}`, - width: '80px' + width: '100px' }, { id: 'properties.current', @@ -25,61 +25,56 @@ :data="filteredBottlenecks() | sortTable(sortColumn, sortDirection)" :maxHeight="(showSplitscreen ? 18 : 35) + 'rem'" :active="openBottleneck" - v-slot="{ item: bottleneck }" > - <div class="table-cell truncate text-left" style="width: 200px"> - <a href="#" @click="selectBottleneck(bottleneck)">{{ - bottleneck.properties.name - }}</a> - </div> - <div class="table-cell text-center" style="width: 80px"> - {{ bottleneck.properties.responsible_country }} - </div> - <div class="table-cell" style="width: 150px"> - {{ bottleneck.properties.current | surveyDate }} - </div> - <div class="table-cell" style="width: 150px"> - {{ - displayCurrentChainage( - bottleneck.properties.from, - bottleneck.properties.to - ) - }} - </div> - <div - class="table-cell pr-0 text-right d-flex flex-column" - style="width: 30px" - > - <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> - </div> - <div - :class="['p-0', 'surveys', { open: openBottleneck === bottleneck }]" - style="width: 100%" - > + <template v-slot:row="{ item: bottleneck }"> + <div class="table-cell truncate text-left" style="width: 230px"> + <a href="#" @click="selectBottleneck(bottleneck)">{{ + bottleneck.properties.name + }}</a> + </div> + <div class="table-cell text-center" style="width: 100px"> + {{ bottleneck.properties.responsible_country }} + </div> + <div class="table-cell" style="width: 150px"> + {{ bottleneck.properties.current | surveyDate }} + </div> + <div class="table-cell" style="width: 150px"> + {{ + displayCurrentChainage( + bottleneck.properties.from, + bottleneck.properties.to + ) + }} + </div> + <div class="table-cell center" style="width: 30px"> + <a + class="text-info" + @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> + </div> + </template> + <template v-slot:expand="{ item: bottleneck }"> <a href="#" class="d-inline-block px-3 py-2" @@ -89,37 +84,11 @@ > {{ survey.date_info | surveyDate }} </a> - </div> + </template> </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 - .table-cell - padding: 0 3px - border-right: solid 1px #dee2e6 - &:last-child - border-right: none - .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.
--- a/client/src/components/ImportStretches.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/ImportStretches.vue Mon Apr 01 11:51:03 2019 +0200 @@ -19,43 +19,44 @@ /> <UITableBody :data="filteredStretches() | sortTable(sortColumn, sortDirection)" - v-slot="{ item: stretch }" > - <div class="py-1 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-1 col-2"> - {{ stretch.properties.date_info | surveyDate }} - </div> - <div class="py-1 col-3"> - {{ stretch.properties.source_organization }} - </div> - <div class="py-1 col text-right"> - <button - class="btn btn-xs btn-dark mr-1" - @click="editStretch(stretch)" - > - <font-awesome-icon icon="pencil-alt" fixed-width /> - </button> - <button class="btn btn-xs btn-dark" @click="deleteStretch(stretch)"> - <font-awesome-icon icon="trash" fixed-width /> - </button> - </div> + <template v-slot:row="{ item: stretch }"> + <div class="py-1 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-1 col-2"> + {{ stretch.properties.date_info | surveyDate }} + </div> + <div class="py-1 col-3"> + {{ stretch.properties.source_organization }} + </div> + <div class="py-1 col text-right"> + <button + class="btn btn-xs btn-dark mr-1" + @click="editStretch(stretch)" + > + <font-awesome-icon icon="pencil-alt" fixed-width /> + </button> + <button class="btn btn-xs btn-dark" @click="deleteStretch(stretch)"> + <font-awesome-icon icon="trash" fixed-width /> + </button> + </div> + </template> </UITableBody> </div> <div v-if="edit">
--- a/client/src/components/importoverview/ImportOverview.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/importoverview/ImportOverview.vue Mon Apr 01 11:51:03 2019 +0200 @@ -96,9 +96,10 @@ <UITableBody :data="filteredImports() | sortTable(sortColumn, sortDirection)" maxHeight="73vh" - v-slot="{ item: entry }" > - <LogEntry :entry="entry"></LogEntry> + <template v-slot:row="{ item: entry }"> + <LogEntry :entry="entry"></LogEntry> + </template> </UITableBody> </div> </div>
--- a/client/src/components/importoverview/LogEntry.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/importoverview/LogEntry.vue Mon Apr 01 11:51:03 2019 +0200 @@ -1,5 +1,5 @@ <template> - <div class="logentry"> + <div> <div class="row no-gutters text-left"> <div style="width: 79px;" @@ -71,34 +71,25 @@ </template> <style lang="sass" scoped> -.logentry - width: 100% - &:hover - background: #fafafa - .actions - height: 100% - width: 50% - border: 0 - background: transparent - outline: none - &.approved - color: green - &.active, - &:hover - color: white - background: green - &.rejected - border-left: 1px solid #dee2e6 - color: red - &.active, - &:hover - color: white - background: red -.table-cell - padding: 0 3px - border-right: solid 1px #dee2e6 - &:last-child - border-right: none +.actions + height: 100% + width: 50% + border: 0 + background: transparent + outline: none + &.approved + color: green + &.active, + &:hover + color: white + background: green + &.rejected + border-left: 1px solid #dee2e6 + color: red + &.active, + &:hover + color: white + background: red </style> <script>
--- a/client/src/components/importschedule/Importschedule.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/importschedule/Importschedule.vue Mon Apr 01 11:51:03 2019 +0200 @@ -32,46 +32,47 @@ /> <UITableBody :data="filteredSchedules() | sortTable(sortColumn, sortDirection)" - v-slot="{ item: schedule }" > - <div class="py-1 col-1">{{ schedule.id }}</div> - <div class="py-1 col-2">{{ schedule.kind.toUpperCase() }}</div> - <div class="py-1 col-2">{{ schedule.user }}</div> - <div class="py-1 col-2">{{ schedule.config.cron }}</div> - <div class="py-1 col-2 text-center"> - <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-1 col text-right"> - <button - @click="editSchedule(schedule.id)" - class="btn btn-xs btn-dark mr-1" - :disabled="importScheduleDetailVisible" - > + <template v-slot:row="{ item: schedule }"> + <div class="py-1 col-1">{{ schedule.id }}</div> + <div class="py-1 col-2">{{ schedule.kind.toUpperCase() }}</div> + <div class="py-1 col-2">{{ schedule.user }}</div> + <div class="py-1 col-2">{{ schedule.config.cron }}</div> + <div class="py-1 col-2 text-center"> <font-awesome-icon - icon="pencil-alt" + v-if="schedule.config['send-email']" + class="fa-fw mr-2" fixed-width + icon="check" ></font-awesome-icon> - </button> - <button - @click="deleteSchedule(schedule)" - class="btn btn-xs 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-xs btn-dark" - :disabled="importScheduleDetailVisible" - > - <font-awesome-icon icon="play" fixed-width></font-awesome-icon> - </button> - </div> + </div> + <div class="py-1 col text-right"> + <button + @click="editSchedule(schedule.id)" + class="btn btn-xs 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-xs 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-xs btn-dark" + :disabled="importScheduleDetailVisible" + > + <font-awesome-icon icon="play" fixed-width></font-awesome-icon> + </button> + </div> + </template> </UITableBody> <div class="p-3 text-right"> <button
--- a/client/src/components/systemconfiguration/PDFTemplates.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/systemconfiguration/PDFTemplates.vue Mon Apr 01 11:51:03 2019 +0200 @@ -18,28 +18,30 @@ { id: 'country', title: `${countryLabel}`, class: 'col-2' } ]" /> - <UITableBody - :data="templates | sortTable(sortColumn, sortDirection)" - v-slot="{ item: template }" - > - <div class="py-1 col-4">{{ template.name }}</div> - <div class="py-1 col-4">{{ template.time }}</div> - <div class="py-1 col-2" v-if="template.country"> - {{ template.country }} - </div> - <div class="py-1 col-2" v-else><i>global</i></div> - <div class="col py-1 text-right"> - <button - class="btn btn-xs btn-info mr-1" - ref="downloadTemplate" - @click="downloadTemplate(template)" - > - <font-awesome-icon icon="download" fixed-width /> - </button> - <button class="btn btn-xs btn-dark" @click="deleteTemplate(template)"> - <font-awesome-icon icon="trash" fixed-width /> - </button> - </div> + <UITableBody :data="templates | sortTable(sortColumn, sortDirection)"> + <template v-slot:row="{ item: template }"> + <div class="py-1 col-4">{{ template.name }}</div> + <div class="py-1 col-4">{{ template.time }}</div> + <div class="py-1 col-2" v-if="template.country"> + {{ template.country }} + </div> + <div class="py-1 col-2" v-else><i>global</i></div> + <div class="col py-1 text-right"> + <button + class="btn btn-xs btn-info mr-1" + ref="downloadTemplate" + @click="downloadTemplate(template)" + > + <font-awesome-icon icon="download" fixed-width /> + </button> + <button + class="btn btn-xs btn-dark" + @click="deleteTemplate(template)" + > + <font-awesome-icon icon="trash" fixed-width /> + </button> + </div> + </template> </UITableBody> <button class="btn btn-info mt-2" @click="$refs.uploadTemplate.click()"> <font-awesome-icon
--- a/client/src/components/ui/UITableBody.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/ui/UITableBody.vue Mon Apr 01 11:51:03 2019 +0200 @@ -7,12 +7,14 @@ <div v-for="(item, index) in data" :key="key(index)" - :class="[ - 'border-top row mx-0 align-items-center', - { active: active === item } - ]" + :class="['row-container border-top', { active: active === item }]" > - <slot :item="item" :index="index"></slot> + <div class="row mx-0"> + <slot :item="item" :index="index" name="row"></slot> + </div> + <div class="expand" v-if="active === item"> + <slot :item="item" :index="index" name="expand"></slot> + </div> </div> </div> <div v-else class="small text-center py-3 border-top"> @@ -20,6 +22,37 @@ </div> </template> +<style lang="sass"> +.table-body + .row-container + > .row + &:hover + background-color: #fafafa + .table-cell + display: flex + align-items: center + padding: 1.5px 3px + border-right: solid 1px #dee2e6 + &:hover + background-color: #f2f2f2 + &:last-child + border-right: none + &.center + justify-content: center + .expand + border-bottom: solid 1px $color-info + + &.active + > .row + color: #fff + .table-cell + border-right-color: rgba(255, 255, 255, 0.3) + background-color: $color-info + color: #fff + a + color: #fff !important +</style> + <script> /* This is Free Software under GNU Affero General Public License v >= 3.0 * without warranty, see README.md and license for details.
--- a/client/src/components/ui/UITableHeader.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/ui/UITableHeader.vue Mon Apr 01 11:51:03 2019 +0200 @@ -5,7 +5,7 @@ @click.prevent="!column.disableSorting && sortTable(column.id)" :key="column.id" :class="[ - 'd-flex py-1 align-items-center justify-content-center small ' + + 'd-inline-block py-1 text-center truncate small ' + (column.class || '') + ' ' + (column.disableSorting ? ' sorting-disabled' : ''),
--- a/client/src/components/usermanagement/Usermanagement.vue Mon Apr 01 10:46:18 2019 +0200 +++ b/client/src/components/usermanagement/Usermanagement.vue Mon Apr 01 11:51:03 2019 +0200 @@ -8,7 +8,7 @@ <UITableHeader :columns="[ { id: 'role', title: `${roleForColumLabel}`, class: 'col-1' }, - { id: 'user', title: `${usernameLabel}`, class: 'col-3' }, + { id: 'user', title: `${usernameLabel}`, class: 'col-4' }, { id: 'country', title: `${countryLabel}`, class: 'col-2' }, { id: 'email', title: `${emailLabel}`, class: 'col-3' } ]" @@ -17,60 +17,68 @@ :data="users | sortTable(sortColumn, sortDirection, page, pageSize)" maxHeight="47rem" :active="currentUser" - v-slot="{ item: user }" > - <div class="py-1 col-1" @click="selectUser(user.user)"> - <font-awesome-icon - v-tooltip="roleLabel(user.role)" - :icon="roleIcon(user.role)" - class="fa-lg" - ></font-awesome-icon> - </div> - <div class="py-1 col-3" @click="selectUser(user.user)"> - {{ user.user }} - </div> - <div class="py-1 col-2" @click="selectUser(user.user)"> - {{ user.country }} - </div> - <div class="py-1 col-3" @click="selectUser(user.user)"> - {{ user.email }} - </div> - <div class="py-1 col text-right"> + <template v-slot:row="{ item: user }"> + <div + class="table-cell center col-1" + @click="selectUser(user.user)" + > + <font-awesome-icon + v-tooltip="roleLabel(user.role)" + :icon="roleIcon(user.role)" + class="fa-lg" + ></font-awesome-icon> + </div> + <div class="table-cell col-4" @click="selectUser(user.user)"> + {{ user.user }} + </div> + <div + class="table-cell center col-2" + @click="selectUser(user.user)" + > + {{ user.country }} + </div> + <div class="table-cell col-3" @click="selectUser(user.user)"> + {{ user.email }} + </div> + <div class="table-cell col text-right justify-content-end"> + <button + @click="sendTestMail(user.user)" + class="btn btn-xs btn-dark mr-1" + v-tooltip="sendMailLabel" + v-if="user.email" + > + <font-awesome-icon icon="paper-plane" fixed-width /> + </button> + <button + @click="deleteUser(user.user)" + class="btn btn-xs btn-dark" + v-tooltip="deleteUserLabel" + > + <font-awesome-icon icon="trash" fixed-width /> + </button> + </div> + </template> + </UITableBody> + <div class="p-3 border-top d-flex justify-content-between"> + <div></div> + <div> <button - @click="sendTestMail(user.user)" - class="btn btn-xs btn-dark mr-1" - v-tooltip="sendMailLabel" - v-if="user.email" + @click="prevPage" + v-if="this.page !== 1" + class="mr-2 btn btn-sm btn-light align-self-center" > - <font-awesome-icon icon="paper-plane" fixed-width /> + <font-awesome-icon icon="angle-left"></font-awesome-icon> </button> + {{ this.page }} / {{ this.pages }} <button - @click="deleteUser(user.user)" - class="btn btn-xs btn-dark" - v-tooltip="deleteUserLabel" + @click="nextPage" + v-if="this.page !== this.pages" + class="ml-2 btn btn-sm btn-light align-self-center" > - <font-awesome-icon icon="trash" fixed-width /> + <font-awesome-icon icon="angle-right"></font-awesome-icon> </button> </div> - </UITableBody> - <div class="d-flex mx-auto align-items-center"> - <button - @click="prevPage" - v-if="this.page !== 1" - class="mr-2 btn btn-sm btn-light align-self-center" - > - <font-awesome-icon icon="angle-left"></font-awesome-icon> - </button> - {{ this.page }} / {{ this.pages }} - <button - @click="nextPage" - v-if="this.page !== this.pages" - class="ml-2 btn btn-sm btn-light align-self-center" - > - <font-awesome-icon icon="angle-right"></font-awesome-icon> - </button> - </div> - <div class="mr-3 py-3 text-right"> <button @click="addUser" class="btn btn-info addbutton shadow-sm"> <translate>Add User</translate> </button> @@ -83,11 +91,6 @@ </template> <style lang="sass" scoped> -.addbutton - position: absolute - bottom: $offset - right: $offset - .content width: 100% @@ -109,16 +112,6 @@ .userlistextended width: 100% - -.table-body - /deep/.row - > div - transition: background-color 0.3s, color 0.3s - &.active - background-color: $color-info - color: #fff - a - color: #fff !important </style> <script>