summaryrefslogtreecommitdiffstats
path: root/webapp/src/components/DataTable.vue
diff options
context:
space:
mode:
authorUdo Walter2019-03-04 06:17:17 +0100
committerUdo Walter2019-03-04 06:17:17 +0100
commiteff95f0a279aabe5b3ae0d9ee20cccd46da6554b (patch)
tree251f2af21b346bb4822c7390b0ead3cc07cc5c63 /webapp/src/components/DataTable.vue
parentForgot to remove the console log. -.- (diff)
downloadbas-eff95f0a279aabe5b3ae0d9ee20cccd46da6554b.tar.gz
bas-eff95f0a279aabe5b3ae0d9ee20cccd46da6554b.tar.xz
bas-eff95f0a279aabe5b3ae0d9ee20cccd46da6554b.zip
[webapp/log] first system log implementation (wip, frontend only atm)
Diffstat (limited to 'webapp/src/components/DataTable.vue')
-rw-r--r--webapp/src/components/DataTable.vue112
1 files changed, 70 insertions, 42 deletions
diff --git a/webapp/src/components/DataTable.vue b/webapp/src/components/DataTable.vue
index 03684d1..c55ed96 100644
--- a/webapp/src/components/DataTable.vue
+++ b/webapp/src/components/DataTable.vue
@@ -30,8 +30,9 @@
<data-table-search
ref="search"
@filter="filteredRows = $event"
- :rows="sortedRows"
- :headers="headers"
+ :items="sortedRows"
+ :data-keys="headers.filter(h => h.text !== undefined)"
+ nested-data
:regex="regex"
:case-sensitive="caseSensitive"
:only-show-selected="onlyShowSelected"
@@ -45,28 +46,34 @@
<div class="d-flex align-center" style="font-size: 12px">
<div class="nowrap">
<v-tooltip top open-delay="800">
- <v-btn icon class="toggle-button" @click="regex = !regex" slot="activator">
- <span :class="regex ? 'primary--text' : ''">.*?</span>
- </v-btn>
+ <template #activator="{ on }">
+ <v-btn v-on="on" icon class="toggle-button" @click="regex = !regex">
+ <span :class="regex ? 'primary--text' : ''">.*?</span>
+ </v-btn>
+ </template>
<span>{{ $t('regex') }}</span>
</v-tooltip>
<v-tooltip top open-delay="800">
- <v-btn icon class="toggle-button" @click="caseSensitive = !caseSensitive" slot="activator">
- <span :class="caseSensitive ? 'primary--text' : ''">Aa</span>
- </v-btn>
+ <template #activator="{ on }">
+ <v-btn v-on="on" icon class="toggle-button" @click="caseSensitive = !caseSensitive">
+ <span :class="caseSensitive ? 'primary--text' : ''">Aa</span>
+ </v-btn>
+ </template>
<span>{{ $t('caseSensitive') }}</span>
</v-tooltip>
- <v-tooltip top open-delay="800">
- <v-btn icon class="toggle-button" @click="onlyShowSelected = !onlyShowSelected" slot="activator">
- <v-icon small :class="onlyShowSelected ? 'primary--text' : ''">{{ singleSelect ? 'radio_button_checked' : 'check_box' }}</v-icon>
- </v-btn>
+ <v-tooltip v-if="!noSelect" top open-delay="800">
+ <template #activator="{ on }">
+ <v-btn v-on="on" icon class="toggle-button" @click="onlyShowSelected = !onlyShowSelected">
+ <v-icon small :class="onlyShowSelected ? 'primary--text' : ''">{{ singleSelect ? 'radio_button_checked' : 'check_box' }}</v-icon>
+ </v-btn>
+ </template>
<span>{{ $t('onlyShowSelected') }}</span>
</v-tooltip>
</div>
<div :class="{ 'text-xs-center': rowCount === undefined, 'text-xs-right': rowCount !== undefined }">
<span class="nowrap">{{ filteredRows.length + ' ' + $t('entries') }}</span>
- <span class="nowrap">{{ '(' + selected.length + ' ' + $t('selected') + ')' }}</span>
+ <span v-if="!noSelect" class="nowrap">{{ '(' + selected.length + ' ' + $t('selected') + ')' }}</span>
</div>
<div v-if="rowCount === undefined" class="text-xs-right hidden-xs-only">
@@ -101,20 +108,21 @@
:page-mode="computedRowCount <= 0"
@click.native.capture.passive="setShiftState"
>
- <template slot="before">
+ <template #before>
<div class="table-head-wrapper" :style="{ 'min-width': computedMinWidth }">
<div class="table-head">
- <div class="header-cell" style="width: 24px">
+ <div v-if="!noSelect" class="header-cell" style="width: 24px">
<v-icon v-if="!singleSelect" @click="toggleSelectAll">
{{ selectState === 0 ? 'check_box_outline_blank' : selectState === 1 ? 'indeterminate_check_box' : 'check_box' }}
</v-icon>
</div>
<div v-for="header in headers" :key="header.key" class="header-cell"
@click="toggleHeaderSort(header)"
- :style="{ width: header.width, cursor: header.text !== undefined ? 'pointer' : '' }"
+ :style="{ width: header.width }"
:class="{
- 'header-sorted': headerSortState[header.key] !== undefined,
- 'header-sorted-desc': headerSortState[header.key] === 'desc',
+ 'sortable-header': !noSort && header.text !== undefined,
+ 'header-sorted': headerSortState[header.sortKey || header.key] !== undefined,
+ 'header-sorted-desc': headerSortState[header.sortKey || header.key] === 'desc',
'auto-width': header.width === undefined
}"
>
@@ -129,20 +137,24 @@
</div>
</div>
</template>
- <div slot-scope="{ item, index }" class="table-row"
- :style="item.selected && { backgroundColor: $vuetify.theme.primary + '11' }"
- @click="selectItem(item, index)"
- @dblclick="$emit('dblclick', item.data)"
- >
- <div class="non-selectable">
- <v-icon style="cursor: pointer" :color="item.selected ? 'primary' : ''">{{ selectedIconMap[item.selected] }}</v-icon>
- </div>
- <div v-for="header in headers" :key="header.key" :style="{ width: header.width }" :class="{ 'auto-width': header.width === undefined }">
- <span style="user-select: text" v-if="$scopedSlots[header.key] === undefined" @dblclick.stop>{{ item.data[header.key] }}</span>
- <slot v-else :name="header.key" :item="item.data" />
+ <template #default="{ item, index }">
+ <div class="table-row"
+ :style="item.selected && { backgroundColor: $vuetify.theme.primary + '11' }"
+ @click="selectItem(item, index)"
+ @dblclick="$emit('dblclick', item.data)"
+ >
+ <div v-if="!noSelect" class="non-selectable">
+ <v-icon style="cursor: pointer" :color="item.selected ? 'primary' : ''">{{ selectedIconMap[item.selected] }}</v-icon>
+ </div>
+ <div v-for="header in headers" :key="header.key" :style="{ width: header.width }" :class="{ 'auto-width': header.width === undefined }">
+ <span style="user-select: text" v-if="$scopedSlots[header.key] === undefined" @dblclick.stop>{{ item.data[header.key] }}</span>
+ <slot v-else :name="header.key" :item="item.data" />
+ </div>
</div>
- </div>
- <div v-if="filteredRows.length === 0" slot="after" class="no-result">{{ $t('noResult') }}</div>
+ </template>
+ <template #after>
+ <div v-if="filteredRows.length === 0" class="no-result">{{ $t('noResult') }}</div>
+ </template>
</RecycleScroller>
</div>
</template>
@@ -186,6 +198,14 @@ export default {
singleSelect: {
type: Boolean,
default: false
+ },
+ noSelect: {
+ type: Boolean,
+ default: false
+ },
+ noSort: {
+ type: Boolean,
+ default: false
}
},
data () {
@@ -222,7 +242,7 @@ export default {
sortedRows () {
const rows = this.rows.slice(0)
for (let key in this.headerSortState) {
- if (!this.headers.some(header => header.key === key)) continue
+ if (!this.headers.some(header => header.sortKey || header.key === key)) continue
const direction = this.headerSortState[key]
if (direction === 'asc') rows.sort((a, b) => String(a.data[key]).localeCompare(String(b.data[key])))
if (direction === 'desc') rows.sort((b, a) => String(a.data[key]).localeCompare(String(b.data[key])))
@@ -236,17 +256,19 @@ export default {
},
watch: {
rows () {
+ if (this.noSelect) return
this.processSelected(this.value)
this.$emit('input', this.selected)
},
value: {
immediate: true,
handler (newValue) {
+ if (this.noSelect) return
this.processSelected(newValue)
}
},
filteredRows () {
- if (this.singleSelect) return
+ if (this.noSelect || this.singleSelect) return
this.lastSelectIndex = null
this.calcSelectState()
}
@@ -266,6 +288,7 @@ export default {
if (this.$refs.scroller) this.$refs.scroller.$el.scrollTop = 0
},
selectItem (row, index) {
+ if (this.noSelect) return
if (this.singleSelect) {
this.$emit('input', [row.data])
return
@@ -341,13 +364,14 @@ export default {
this.selectState = seenTrue && seenFalse ? 1 : seenTrue && !seenFalse ? 2 : 0
},
toggleHeaderSort (header) {
- if (header.text === undefined) return
- const state = this.headerSortState[header.key]
+ if (header.text === undefined || this.noSort) return
+ const key = header.sortKey || header.key
+ const state = this.headerSortState[key]
const newSortState = {}
if (state === undefined || state === 'desc') {
- newSortState[header.key] = 'asc'
+ newSortState[key] = 'asc'
} else if (state === 'asc') {
- newSortState[header.key] = 'desc'
+ newSortState[key] = 'desc'
}
this.headerSortState = newSortState
},
@@ -454,23 +478,27 @@ export default {
transition: color .3s cubic-bezier(.25,.8,.5,1);
}
-.table-head > .header-cell.header-sorted.header-sorted-desc > .header-sort-icon {
+.table-head > .sortable-header {
+ cursor: pointer;
+}
+
+.table-head > .sortable-header.header-sorted.header-sorted-desc > .header-sort-icon {
transform: rotate(180deg);
}
-.table-head > .header-cell:hover > .header-sort-icon {
+.table-head > .sortable-header:hover > .header-sort-icon {
opacity: 0.6 !important;
}
-.table-head > .header-cell.header-sorted > .header-sort-icon {
+.table-head > .sortable-header.header-sorted > .header-sort-icon {
opacity: 1 !important;
}
-.theme--dark .table-head > .header-cell:hover, .theme--dark .table-head > .header-cell.header-sorted {
+.theme--dark .table-head > .sortable-header:hover, .theme--dark .table-head > .sortable-header.header-sorted {
color: rgb(255,255,255);
}
-.theme--light .table-head > .header-cell:hover, .theme--light .table-head > .header-cell.header-sorted {
+.theme--light .table-head > .sortable-header:hover, .theme--light .table-head > .sortable-header.header-sorted {
color: rgba(0,0,0,.87);
}