summaryrefslogtreecommitdiffstats
path: root/webapp/src/components/DataTable.vue
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/src/components/DataTable.vue')
-rw-r--r--webapp/src/components/DataTable.vue194
1 files changed, 194 insertions, 0 deletions
diff --git a/webapp/src/components/DataTable.vue b/webapp/src/components/DataTable.vue
new file mode 100644
index 0000000..721f137
--- /dev/null
+++ b/webapp/src/components/DataTable.vue
@@ -0,0 +1,194 @@
+<i18n>
+{
+ "en": {
+ "search": "Search",
+ "all": "All",
+ "pageText": "{0}-{1} of {2}",
+ "pageTextZero": "0 of 0",
+ "rowsPerPageText": "Rows per page:"
+ },
+ "de": {
+ "search": "Suche",
+ "all": "Alle",
+ "pageText": "{0}-{1} von {2}",
+ "pageTextZero": "0 von 0",
+ "rowsPerPageText": "Reihen pro page:"
+ }
+}
+</i18n>
+
+<template>
+ <div>
+ <v-layout wrap align-center class="actions-container">
+ <v-flex md3 sm5 xs12 order-md1 order-sm1 order-xs1 class="text-xs-left">
+ <v-text-field
+ class="search-field"
+ :placeholder="$t('search')"
+ v-model="search"
+ hide-details
+ prepend-inner-icon="search"
+ ></v-text-field>
+ </v-flex>
+ <v-flex md4 sm12 xs12 offset-md1 offset-sm0 offset-xs0 order-md2 order-sm3 order-xs3
+ class="text-md-center text-xs-right caption font-weight-thin">
+ {{ $t('rowsPerPageText') }}
+ <v-select
+ v-model="rowCount"
+ :items="[ 5, 10, 20, 50, 100, { text: $t('all'), value: '-1' }]"
+ color="primary"
+ hide-details
+ :menu-props="{
+ offsetY: ''
+ }"
+ ></v-select>
+ </v-flex>
+ </v-layout>
+ <v-divider></v-divider>
+
+ <RecycleScroller
+ class="scroller"
+ :style="scrollerStyle"
+ :items="filterdRows"
+ :item-height="48"
+ :page-mode="rowCount <= 0"
+ >
+ <div slot-scope="{ item }" class="table-row"
+ :style="item.selected && { backgroundColor: $vuetify.theme.primary + '11' }"
+ @click="selectItem(item)"
+ >
+ <div>
+ <v-icon style="cursor: pointer">{{ item.selected ? 'check_box' : 'check_box_outline_blank' }}</v-icon>
+ </div>
+ <div v-for="header in headers" :key="header.key" :style="{ width: header.width || headerWidthPercent }">
+ {{ item.data[header.key] }}
+ </div>
+ </div>
+ </RecycleScroller>
+
+ </div>
+</template>
+
+<script>
+import DataTableItem from '@/components/DataTableItem'
+
+export default {
+ name: 'DataTable',
+ components: { DataTableItem },
+ props: {
+ headers: {
+ type: Array
+ },
+ items: {
+ type: Array,
+ required: true
+ },
+ value: {
+ type: Array,
+ default: () => []
+ },
+ minWidth: {
+ type: Number,
+ default: 600
+ }
+ },
+ data () {
+ return {
+ search: '',
+ lastSelectId: null,
+ shiftKey: false,
+ rowCount: 10
+ }
+ },
+ computed: {
+ scrollerStyle () {
+ const style = { '--min-table-width': this.minWidth + 'px' }
+ if (this.rowCount > 0) style.height = Math.min(this.rowCount, this.filterdRows.length) * 48 + 'px'
+ return style
+ },
+ headerWidthPercent () { return 100/this.headers.length + '%' },
+ dataKeys () { return this.headers.map(x => x.key) },
+ rows () {
+ return this.items.map(item => ({ data: item, selected: false, id: item.id }))
+ },
+ filterdRows () {
+ const search = String(this.search).toLowerCase().trim()
+ return search === '' ? this.rows : this.rows.filter(row => {
+ return Object.keys(row.data).some(key => {
+ return this.dataKeys.includes(key) && String(row.data[key]).toLowerCase().includes(search)
+ })
+ })
+ }
+ },
+ watch: {
+ value (v) {
+
+ },
+ items () {
+ this.$emit('input', [])
+ }
+ },
+ methods: {
+ setShiftState (event) {
+ this.shiftKey = event.shiftKey
+ },
+ selectItem (item) {
+ item.selected = !item.selected
+ var tmp = this.value
+ if (item.selected) {
+ tmp.push(item.data)
+ } else {
+ tmp.splice(tmp.indexOf(item.data), 1)
+ }
+ this.$emit('input', tmp)
+ }
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+
+.scroller-wrapper {
+ overflow-x: auto;
+}
+
+.scroller {
+ overflow-x: auto;
+}
+
+.scroller >>> .vue-recycle-scroller__item-wrapper {
+ min-width: var(--min-table-width);
+}
+
+.table-row {
+ height: 48px;
+ display: flex;
+ align-items: center;
+}
+
+.table-row > div {
+ padding: 0 24px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.theme--dark .table-row {
+ border-bottom: 1px solid hsla(0,0%,100%,.12);
+}
+
+.theme--light .table-row {
+ border-bottom: 1px solid rgba(0,0,0,.12);
+}
+
+
+.theme--dark .scroller >>> .hover > .table-row {
+ background-color: #616161;
+}
+
+.theme--light .scroller >>> .hover > .table-row {
+ background-color: #eee;
+}
+
+</style>
+