summaryrefslogblamecommitdiffstats
path: root/webapp/src/components/DataTable.vue
blob: 721f1370f1f9740e09b3ec210da5385bd7326af9 (plain) (tree)

































































































































































































                                                                                                                  
<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>