summaryrefslogblamecommitdiffstats
path: root/webapp/src/components/LogModule.vue
blob: 69b16644054844559173dee60181862d23b92465 (plain) (tree)







































































































































































































































































































































                                                                                                                                                                                     
<i18n>
{
  "en": {
    "systemLog": "System Log",
    "from": "From",
    "to": "To",
    "today": "Today",
    "now": "Now",
    "log": "Log",
    "filter": "Filter",
    "timestamp": "Timestamp",
    "category": "Category",
    "categories": "Categories",
    "description": "Description",
    "group": "Group",
    "groups": "Groups",
    "client": "Client",
    "clients": "Clients",
    "includeSubgroups": "Include Subgroups"
  },
  "de": {
    "systemLog": "System Protokoll",
    "from": "Von",
    "to": "Bis",
    "today": "Heute",
    "now": "Jetzt",
    "log": "Protokoll",
    "filter": "Filter",
    "timestamp": "Zeitstempel",
    "category": "Kategorie",
    "categories": "Kategorien",
    "description": "Beschreibung",
    "group": "Gruppe",
    "groups": "Gruppen",
    "client": "Client",
    "clients": "Clients",
    "includeSubgroups": "Inklusive Untergruppen"
  }
}
</i18n>

<template>
  <v-container fill-height>
    <v-layout>
      <v-flex xl10 offset-xl1 lg12>
        <v-card class="tabbar-card">
          <v-tabs v-model="tabs" grow hide-slider :dark="tabsDark" :color="tabsColor" :slider-color="tabsSliderColor">
              <v-tab><v-icon class="tabbar-tabicon">error_outline</v-icon>{{ $t('systemLog') }}</v-tab>
          </v-tabs>
        </v-card>
        <v-tabs-items v-model="tabs" style="padding-bottom: 20px">
          <v-tab-item>
            <v-subheader>{{ $t('filter') }}</v-subheader>
            <v-card>
              <v-card-text>
                <v-layout wrap>
                  <v-flex xs12 md5 order-xs2 order-md1>
                    <select-box
                      class="select-box"
                      v-model="categoryFilter"
                      :items="categories"
                      :max-columns="selectBoxColumnCount"
                      prepend-icon="all_inbox"
                      :label="$t('categories')"
                      hide-details
                    ></select-box>
                  </v-flex>
                  <v-flex xs12 md7 order-xs1 order-md2 class="text-md-right">
                    <div style="display: inline-block; white-space: nowrap">
                      <span class="text-xs-right picker-label">{{ $t('from') }}</span>

                      <v-menu left offset-y :close-on-content-click="false" style="display: inline-block">
                        <template #activator="{ on }">
                          <v-btn v-on="on" small class="date-picker-button"><v-icon small class="mr-1">today</v-icon>{{ fromDate }}</v-btn>
                        </template>
                        <v-date-picker
                          v-model="fromDate"
                          color="primary"
                          :locale="locale"
                          :width="pickerWidth"
                        ></v-date-picker>
                      </v-menu>

                      <v-menu left offset-y :close-on-content-click="false" style="display: inline-block">
                        <template #activator="{ on }">
                          <v-btn v-on="on" small class="time-picker-button"><v-icon small class="mr-1">schedule</v-icon>{{ fromTime }}</v-btn>
                        </template>
                        <v-time-picker
                          v-model="fromTime"
                          color="primary"
                          :locale="locale"
                          format="24hr"
                          :width="pickerWidth"
                        ></v-time-picker>
                      </v-menu>

                    </div>
                    <div style="display: inline-block; white-space: nowrap">
                      <span class="text-xs-right picker-label">{{ $t('to') }}</span>

                      <v-menu v-model="toDateMenu" left offset-y :close-on-content-click="false" style="display: inline-block">
                        <template #activator="{ on }">
                          <v-btn v-on="on" small class="date-picker-button">
                            <v-icon small class="mr-1">today</v-icon>
                            {{ toDate ? toDate : $t('today') }}
                          </v-btn>
                        </template>
                        <template #default>
                          <div style="position: relative">
                            <v-btn @click="toNow" dark color="primary" small style="position: absolute; z-index: 1; top: 0; right: 0; min-width: fit-content">{{ $t('now') }}</v-btn>
                            <v-date-picker
                              v-model="toDate"
                              color="primary"
                              :locale="locale"
                              :width="pickerWidth"
                            ></v-date-picker>
                          </div>
                        </template>
                      </v-menu>
                      <v-menu v-model="toTimeMenu" left offset-y :close-on-content-click="false" style="display: inline-block">
                        <template #activator="{ on }">
                          <v-btn v-on="on" small class="time-picker-button">
                            <v-icon small class="mr-1">schedule</v-icon>
                            {{ toTime ? toTime : $t('now') }}
                          </v-btn>
                        </template>
                        <template #default>
                          <div style="position: relative">
                            <v-btn @click="toNow" dark color="primary" small style="position: absolute; z-index: 1; top: 0; left: 0; min-width: fit-content">{{ $t('now') }}</v-btn>
                            <v-time-picker
                              v-model="toTime"
                              color="primary"
                              :locale="locale"
                              format="24hr"
                              :width="pickerWidth"
                            ></v-time-picker>
                          </div>
                        </template>
                      </v-menu>

                    </div>
                  </v-flex>

                  <v-flex xs12 md5 order-xs3>
                    <select-box
                      class="select-box"
                      v-model="groupFilter"
                      :items="groupList"
                      :max-columns="selectBoxColumnCount"
                      prepend-icon="device_hub"
                      :label="$t('groups')"
                      hide-details
                    ></select-box>
                  </v-flex>
                  <v-flex xs12 md5 order-xs4>
                    <select-box
                      class="select-box"
                      v-model="clientFilter"
                      :items="clientList"
                      :max-columns="selectBoxColumnCount"
                      prepend-icon="computer"
                      :label="$t('clients')"
                      hide-details
                    ></select-box>
                  </v-flex>
                  <v-flex xs12 md2 order-xs5 style="display: flex; align-items: flex-end; justify-content: flex-end">
                    <v-btn color="primary" :loading="loading" @click="loadLog"><v-icon left>filter_list</v-icon>{{ $t('filter') }}</v-btn>
                  </v-flex>
                </v-layout>
              </v-card-text>
            </v-card>
            <v-subheader>{{ $t('log') }}</v-subheader>
            <v-card>
              <data-table :headers="headers" :items="log" min-width="1100px" no-select no-sort></data-table>
            </v-card>
          </v-tab-item>
        </v-tabs-items>
      </v-flex>
    </v-layout>
  </v-container>
</template>

<script>
import SelectBox from '@/components/SelectBox'
import DataTable from '@/components/DataTable'
import { mapState, mapGetters } from 'vuex'

export default {
  name: 'LogModule',
  components: {
    SelectBox,
    DataTable
  },
  data () {
    return {
      tabs: 0,
      categories: [],
      log: [],
      headers: [
        { key: 'timestamp', text: this.$t('timestamp'), width: '160px' },
        { key: 'category', text: this.$t('category'), width: '160px' },
        { key: 'description', text: this.$t('description') },
        { key: 'group', text: this.$t('group'), width: '180px' },
        { key: 'client', text: this.$t('client'), width: '180px' }
      ],
      loading: false,
      fromDate: null,
      fromTime: null,
      toDate: null,
      toTime: null,
      toDateMenu: false,
      toTimeMenu: false,
      categoryFilter: [],
      groupFilter: [],
      groupRecursive: false,
      clientFilter: []
    }
  },
  computed: {
    ...mapState('groups', ['groupList', 'clientList']),
    ...mapGetters(['tabsDark', 'tabsColor', 'tabsSliderColor']),
    locale () { return this.$store.state.settings.locale },
    selectBoxColumnCount () {
      if (this.$vuetify.breakpoint.mdOnly || this.$vuetify.breakpoint.xsOnly) return 1
      return 2
    },
    pickerWidth () {
      return this.$vuetify.breakpoint.xsOnly ? 250 : undefined
    },
    defaultStartDate () {
      const date = new Date()
      date.setDate(date.getDate() - 7)
      return date
    }
  },
  watch: {
    toDate (value) {
      if (value) this.toTime = this.formatDate(new Date(), { date: false, seconds: false })
    },
    toTime (value) {
      if (value) this.toDate = this.formatDate(new Date(), { time: false })
    }
  },
  methods: {
    formatDate(date, options = {}) {
      var result = ''
      const pad = x => x < 10 ? '0' + x : x
      if (options.date !== false) {
        result += date.getFullYear() + '-' + pad(date.getMonth() + 1) + '-' + pad(date.getDate())
      }
      if (options.time !== false) {
        if (result !== '') result += ' '
        result += pad(date.getHours()) + ':' + pad(date.getMinutes() + 1)
        if (options.seconds !== false)  result += ':' + pad(date.getSeconds())
      }
      return result
    },
    toNow () {
      this.toDate = null
      this.toTime = null
      this.toDateMenu = false
      this.toTimeMenu = false
    },
    loadLog () {
      this.loading = true
      this.$http.get('/api/log').then(response => {
        response.data.forEach(item => {
          item.timestamp = new Date(item.timestamp * 1000).toISOString().split('.')[0].replace('T', ' ')
          if (item.group) item.group = item.group.name
          if (item.client) item.client = item.client.name
        })
        this.log = response.data
        this.loading = false
      })
    }
  },
  created () {
    this.$store.dispatch('groups/loadLists')
    this.$http.get('/api/log/categories').then(response => {
      this.categories = response.data.map((category, index) => ({ id: index, name: category }))
    })
    const date = new Date()
    date.setDate(date.getDate() - 7)
    this.fromDate = this.formatDate(this.defaultStartDate, { time: false }),
    this.fromTime = this.formatDate(this.defaultStartDate, { date: false, seconds: false })
    this.loadLog()
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.select-box {
  margin: 6px !important;
}

.picker-label {
  display: inline-block;
  width: 40px;
}

.date-picker-button {
  min-width: 110px;
  width: 110px;
  margin-right: 0;
}

.time-picker-button {
  min-width: 70px;
  width: 70px;
}

.search-wrapper {
  display: flex;
  align-items: center;
}

.search-box {
  flex: 1;
}

.toggle-button {
  min-width: 36px;
  text-transform: none;
  font-size: 14px;
  font-weight: 600;
}
</style>