summaryrefslogtreecommitdiffstats
path: root/webapp/src/components/ComponentSearchTable.vue
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/src/components/ComponentSearchTable.vue')
-rw-r--r--webapp/src/components/ComponentSearchTable.vue168
1 files changed, 168 insertions, 0 deletions
diff --git a/webapp/src/components/ComponentSearchTable.vue b/webapp/src/components/ComponentSearchTable.vue
new file mode 100644
index 0000000..2e3846d
--- /dev/null
+++ b/webapp/src/components/ComponentSearchTable.vue
@@ -0,0 +1,168 @@
+<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 v-if="actionsNeeded" 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
+ class="rows-per-page-select body-1"
+ v-model="pagination.rowsPerPage"
+ :items="rowsPerPageItems.concat({ text: $t('all'), value: -1 })"
+ offset-y
+ color="primary"
+ hide-details
+ content-class="search-table-rows-per-page-select-content"
+ ></v-select>
+ </v-flex>
+ <v-flex md4 sm6 xs12 offset-md0 offset-sm1 offset-xs0 order-md3 order-sm2 order-xs2
+ class="text-xs-right caption font-weight-thin">
+ <span class="page-text">{{
+ pagination.totalItems > 0 ? $t('pageText', [
+ (pagination.page - 1) * pagination.rowsPerPage + 1,
+ Math.min(pagination.page * pagination.rowsPerPage, pagination.totalItems),
+ pagination.totalItems
+ ]) : $t('pageTextZero')
+ }}</span>
+ <v-btn class="page-button" icon @click="prevPage"><v-icon>keyboard_arrow_left</v-icon></v-btn>
+ <v-btn class="page-button" icon @click="nextPage"><v-icon>keyboard_arrow_right</v-icon></v-btn>
+ </v-flex>
+ </v-layout>
+ <v-divider v-if="actionsNeeded"></v-divider>
+ <v-data-table
+ v-bind="computedDataTableProps"
+ :value="value"
+ @input="$emit('input', $event)"
+ :search="search"
+ :pagination.sync="pagination"
+ :custom-filter="customFilter"
+ >
+ <template v-if="$scopedSlots.items" slot="items" slot-scope="props">
+ <slot name="items" :data="props" ></slot>
+ </template>
+ </v-data-table>
+ </div>
+</template>
+
+<script>
+
+export default {
+ name: 'ComponentSearchTable',
+ props: {
+ value: {
+ type: Array,
+ default: () => []
+ },
+ dataTableProps: {
+ type: Object,
+ default: () => {}
+ },
+ rowsPerPageItems: {
+ type: Array,
+ default: () => [10, 25, 50]
+ }
+ },
+ data () {
+ return {
+ search: '',
+ pagination: {},
+ selected: []
+ }
+ },
+ computed: {
+ computedDataTableProps () {
+ return { ...this.dataTableProps, hideActions: true }
+ },
+ headersValues () { return this.dataTableProps.headers.map(x => x.value) },
+ headerCount () { return this.dataTableProps.headers.length + (this.dataTableProps.selectAll ? 1 : 0) },
+ rowsPerPage () { return this.pagination.rowsPerPage },
+ actionsNeeded () {
+ return this.dataTableProps.items && this.rowsPerPageItems.length > 0 && this.dataTableProps.items.length > this.rowsPerPageItems[0]
+ }
+ },
+ watch: {
+ rowsPerPage () {
+ this.pagination.page = 1
+ }
+ },
+ methods: {
+ prevPage () {
+ if (this.pagination.page > 1) this.pagination.page -= 1
+ },
+ nextPage () {
+ if (this.pagination.page * this.pagination.rowsPerPage < this.pagination.totalItems) this.pagination.page += 1
+ },
+ customFilter (items, search) {
+ search = String(search).toLowerCase().trim()
+ let matchedItems = search === '' ? items : items.filter(item => {
+ return Object.keys(item).some(key => {
+ return this.headersValues.includes(key) && String(item[key]).toLowerCase().includes(search)
+ })
+ })
+ this.pagination.totalItems = matchedItems.length
+ return matchedItems
+ }
+ },
+ created () {
+ this.pagination.rowsPerPage = this.rowsPerPageItems[0] || -1
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.actions-container {
+ padding: 20px;
+}
+.search-field {
+ margin-top: 0;
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-bottom: 5px;
+}
+.rows-per-page-select {
+ display: inline-block;
+ margin: 0 10px 0 20px;
+ width: min-content;
+}
+.page-text {
+ margin-right: 20px;
+}
+.page-button {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+</style>
+
+<style>
+.search-table-rows-per-page-select-content .v-list__tile {
+ height: 38px;
+}
+</style> \ No newline at end of file