admin-users.vue 5.89 KB
Newer Older
1
<template lang='pug'>
2 3 4 5
  v-container(fluid, grid-list-lg)
    v-layout(row, wrap)
      v-flex(xs12)
        .admin-header
6
          img.animated.fadeInUp(src='/_assets/svg/icon-customer.svg', alt='Users', style='width: 80px;')
7
          .admin-header-title
Nick's avatar
Nick committed
8
            .headline.blue--text.text--darken-2.animated.fadeInLeft Users
9
            .subtitle-1.grey--text.animated.fadeInLeft.wait-p2s Manage users
10
          v-spacer
NGPixel's avatar
NGPixel committed
11
          v-btn.animated.fadeInDown.wait-p2s.mr-3(outlined, color='grey', icon, @click='refresh')
12 13 14
            v-icon mdi-refresh
          v-btn.animated.fadeInDown(color='primary', large, depressed, @click='createUser')
            v-icon(left) mdi-plus
15
            span New User
NGPixel's avatar
NGPixel committed
16 17
        v-card.mt-3.animated.fadeInUp
          .pa-2.d-flex.align-center(:class='$vuetify.theme.dark ? `grey darken-3-d5` : `grey lighten-3`')
Nick's avatar
Nick committed
18
            v-text-field(
NGPixel's avatar
NGPixel committed
19 20
              solo
              flat
Nick's avatar
Nick committed
21
              v-model='search'
22
              prepend-inner-icon='mdi-account-search-outline'
Nick's avatar
Nick committed
23 24
              label='Search Users...'
              hide-details
NGPixel's avatar
NGPixel committed
25 26
              style='max-width: 400px;'
              dense
Nick's avatar
Nick committed
27
              )
NGPixel's avatar
NGPixel committed
28 29 30 31
            v-spacer
            v-select(
              solo
              flat
Nick's avatar
Nick committed
32 33 34 35 36 37
              hide-details
              label='Identity Provider'
              :items='strategies'
              v-model='filterStrategy'
              item-text='title'
              item-value='key'
NGPixel's avatar
NGPixel committed
38 39
              style='max-width: 300px;'
              dense
Nick's avatar
Nick committed
40 41
            )
          v-divider
42 43
          v-data-table(
            v-model='selected'
Nick's avatar
Nick committed
44
            :items='usersFiltered',
45 46
            :headers='headers',
            :search='search',
47 48
            :page.sync='pagination'
            :items-per-page='15'
Nick's avatar
Nick committed
49
            :loading='loading'
50 51 52 53
            @page-count='pageCount = $event'
            hide-default-footer
            )
            template(slot='item', slot-scope='props')
54
              tr.is-clickable(:active='props.selected', @click='$router.push("/users/" + props.item.id)')
55
                //- td
56
                  v-checkbox(hide-details, :input-value='props.selected', color='blue darken-2', @click='props.selected = !props.selected')
57
                td {{ props.item.id }}
58
                td: strong {{ props.item.name }}
59
                td {{ props.item.email }}
60 61 62
                td {{ props.item.providerKey }}
                td {{ props.item.createdAt | moment('from') }}
                td
63 64 65 66 67 68
                  span(v-if='props.item.lastLoginAt') {{ props.item.lastLoginAt | moment('from') }}
                  em.grey--text(v-else) Never
                td.text-right
                  v-icon.mr-3(v-if='props.item.isSystem') mdi-lock-outline
                  status-indicator(positive, pulse, v-if='props.item.isActive')
                  status-indicator(negative, pulse, v-else)
69
            template(slot='no-data')
70
              .pa-3
71 72 73
                v-alert.text-left(icon='mdi-alert', outlined, color='grey')
                  em.body-2 No users to display!
          v-card-chin(v-if='pageCount > 1')
74
            v-spacer
75
            v-pagination(v-model='pagination', :length='pageCount')
76
            v-spacer
77

78
    user-create(v-model='isCreateDialogShown', @refresh='refresh(false)')
79 80 81
</template>

<script>
Nick's avatar
Nick committed
82
import _ from 'lodash'
83
import gql from 'graphql-tag'
Nick's avatar
Nick committed
84

85
import { StatusIndicator } from 'vue-status-indicator'
86 87
import UserCreate from './admin-users-create.vue'

88
export default {
89
  components: {
90
    StatusIndicator,
91 92
    UserCreate
  },
93 94 95
  data() {
    return {
      selected: [],
96 97
      pagination: 1,
      pageCount: 0,
98
      users: [],
99
      headers: [
100 101 102 103 104
        { text: 'ID', value: 'id', width: 80, sortable: true },
        { text: 'Name', value: 'name', sortable: true },
        { text: 'Email', value: 'email', sortable: true },
        { text: 'Provider', value: 'provider', sortable: true },
        { text: 'Created', value: 'createdAt', sortable: true },
105 106
        { text: 'Last Login', value: 'lastLoginAt', sortable: true },
        { text: '', value: 'actions', sortable: false, width: 80 }
107
      ],
Nick's avatar
Nick committed
108 109
      strategies: [],
      filterStrategy: 'all',
110
      search: '',
Nick's avatar
Nick committed
111
      loading: false,
112
      isCreateDialogShown: false
113 114 115
    }
  },
  computed: {
Nick's avatar
Nick committed
116 117 118
    usersFiltered () {
      const all = this.filterStrategy === 'all' || this.filterStrategy === ''
      return _.filter(this.users, u => all || u.providerKey === this.filterStrategy)
119
    }
120 121
  },
  methods: {
122 123 124
    createUser() {
      this.isCreateDialogShown = true
    },
125
    async refresh(notify = true) {
126
      await this.$apollo.queries.users.refetch()
127 128 129 130 131 132
      if (notify) {
        this.$store.commit('showNotification', {
          message: 'Users list has been refreshed.',
          style: 'success',
          icon: 'cached'
        })
133 134
      }
    }
135 136 137
  },
  apollo: {
    users: {
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
      query: gql`
        query {
          users {
            list {
              id
              name
              email
              providerKey
              isSystem
              isActive
              createdAt
              lastLoginAt
            }
          }
        }
      `,
154 155 156
      fetchPolicy: 'network-only',
      update: (data) => data.users.list,
      watchLoading (isLoading) {
Nick's avatar
Nick committed
157
        this.loading = isLoading
158 159
        this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-users-refresh')
      }
Nick's avatar
Nick committed
160 161
    },
    strategies: {
162 163 164 165 166 167 168 169 170 171 172 173 174 175
      query: gql`
        query {
          authentication {
            strategies(
              isEnabled: true
            ) {
              key
              title
              icon
              color
            }
          }
        }
      `,
Nick's avatar
Nick committed
176 177 178 179
      fetchPolicy: 'network-only',
      update: (data) => {
        return _.concat({
          key: 'all',
NGPixel's avatar
NGPixel committed
180
          title: 'All Providers'
Nick's avatar
Nick committed
181 182 183 184 185
        }, data.authentication.strategies)
      },
      watchLoading (isLoading) {
        this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-users-strategies-refresh')
      }
186
    }
187 188 189 190 191 192 193
  }
}
</script>

<style lang='scss'>

</style>