Refactor
This commit is contained in:
parent
fcd61655ce
commit
cfab03d1ea
|
@ -83,11 +83,11 @@ class User {
|
|||
const rolesGroups = [
|
||||
{
|
||||
role: 'superAdmin',
|
||||
adGroup: process.env.SUPER_ADMIN_GROUP || 'PP-SERTI'
|
||||
adGroup: process.env.SUPER_ADMIN_GROUP || 'PP-PTI-Admins'
|
||||
},
|
||||
{
|
||||
role: 'tokenCreator',
|
||||
adGroup: process.env.TOKEN_CREATOR_GROUP || 'PTI-TokenGen'
|
||||
adGroup: process.env.TOKEN_CREATOR_GROUP || 'PP-PTI-TokenCreators'
|
||||
},
|
||||
{
|
||||
role: 'student',
|
||||
|
@ -99,7 +99,7 @@ class User {
|
|||
},
|
||||
{
|
||||
role: 'watcher',
|
||||
adGroup: process.env.WATCHER_GROUP || 'PTI-Vigias'
|
||||
adGroup: process.env.WATCHER_GROUP || 'PP-PTI-Watchers'
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -392,9 +392,8 @@ class User {
|
|||
})
|
||||
|
||||
logSuccess({
|
||||
message: `Importado ${index + 1}/${allAdUsers.length} (${
|
||||
user.sAMAccountName
|
||||
}) ${user.displayName}`,
|
||||
message: `Importado ${index + 1}/${allAdUsers.length} (${user.sAMAccountName
|
||||
}) ${user.displayName}`,
|
||||
data: dbUser
|
||||
})
|
||||
}
|
||||
|
@ -403,12 +402,11 @@ class User {
|
|||
|
||||
logSuccess({
|
||||
tags: ['user', 'AD'],
|
||||
message: `${
|
||||
allAdUsers.length
|
||||
} usuários importados do Active Directory em ${(
|
||||
(endTime - startTime) /
|
||||
1000
|
||||
).toFixed(2)}s`
|
||||
message: `${allAdUsers.length
|
||||
} usuários importados do Active Directory em ${(
|
||||
(endTime - startTime) /
|
||||
1000
|
||||
).toFixed(2)}s`
|
||||
})
|
||||
|
||||
return allAdUsers.length
|
||||
|
|
|
@ -34,6 +34,7 @@ export async function wifiUsers(parent, { take = 10, skip = 0, search }) {
|
|||
]
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
data:
|
||||
prisma.user.findMany({
|
||||
|
|
|
@ -60,7 +60,26 @@ const User = {
|
|||
const campus = parent.extensionAttribute1?.split('-')[0]
|
||||
|
||||
return campus || '--'
|
||||
}
|
||||
},
|
||||
|
||||
onlineWifiDevicesCount: (parent, data, { auth }) => prisma.wifiDevice.count({
|
||||
where: {
|
||||
status: 'ONLINE',
|
||||
user: { id: parent.id }
|
||||
}
|
||||
}),
|
||||
|
||||
offlineWifiDevicesCount: (parent, data, { auth }) => prisma.wifiDevice.count({
|
||||
where: {
|
||||
OR: [
|
||||
{ status: 'OFFLINE' },
|
||||
{ status: 'RECENT' },
|
||||
],
|
||||
|
||||
user: { id: parent.id }
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
export { User }
|
||||
|
|
|
@ -121,6 +121,10 @@ const typeDefs = gql`
|
|||
type User {
|
||||
id: ID
|
||||
wifiDevices: [WifiDevice!]
|
||||
|
||||
onlineWifiDevicesCount: Int!
|
||||
offlineWifiDevicesCount: Int!
|
||||
|
||||
lastLogin: String
|
||||
lastLoginPrior: String
|
||||
roles: [String!]
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import SignalStrength from '../signalStrength.vue'
|
||||
import SignalStrength from '../ui/signalStrength.vue'
|
||||
import UserTD from './UserTD.vue'
|
||||
import Bytes from '../ui/Bytes.vue'
|
||||
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
<template>
|
||||
<div v-if="user" class="d-flex">
|
||||
<router-link
|
||||
v-if="user"
|
||||
class="d-flex text-decoration-none"
|
||||
:to="{
|
||||
name: 'wifi-user-single',
|
||||
params: { sAMAccountName: user.sAMAccountName }
|
||||
}"
|
||||
>
|
||||
<Avatar
|
||||
class="flex-column center-block"
|
||||
left
|
||||
|
@ -10,7 +17,7 @@
|
|||
{{ user.displayName }} <br />
|
||||
{{ user.sAMAccountName }}
|
||||
</small>
|
||||
</div>
|
||||
</router-link>
|
||||
<span v-else>
|
||||
<Avatar left size="28" no-auth /><small>Não autenticado</small>
|
||||
</span>
|
||||
|
@ -23,7 +30,8 @@ export default {
|
|||
components: { Avatar },
|
||||
props: {
|
||||
user: {
|
||||
type: Object
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import SignalStrength from '../signalStrength.vue'
|
||||
import SignalStrength from '../ui/signalStrength.vue'
|
||||
import Bytes from '../ui/Bytes.vue'
|
||||
|
||||
export default {
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import SignalStrength from '../signalStrength.vue'
|
||||
import SignalStrength from '../ui/signalStrength.vue'
|
||||
import UserTD from './UserTD.vue'
|
||||
import Bytes from '../ui/Bytes.vue'
|
||||
|
||||
|
|
45
web/src/components/DataTables/WifiUsersDataTable.vue
Normal file
45
web/src/components/DataTables/WifiUsersDataTable.vue
Normal file
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<v-data-table :items="items" :headers="headers">
|
||||
<template #[`item.combinedUser`]="{ item }">
|
||||
<UserTD :user="item" />
|
||||
</template>
|
||||
</v-data-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserTD from './UserTD.vue'
|
||||
export default {
|
||||
components: { UserTD },
|
||||
props: {
|
||||
wifiUsers: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
headers: [
|
||||
{ text: 'Usuário', value: 'combinedUser', sortable: false },
|
||||
{
|
||||
text: 'Dispositivos Online',
|
||||
value: 'onlineWifiDevicesCount',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
text: 'Dispositivos Offline',
|
||||
value: 'offlineWifiDevicesCount',
|
||||
sortable: false
|
||||
}
|
||||
]
|
||||
}),
|
||||
computed: {
|
||||
items() {
|
||||
return this.wifiUsers.map(wifiUser => ({
|
||||
...wifiUser,
|
||||
combinedUser: `${wifiUser.displayName} (${wifiUser.sAMAccountName})`
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
46
web/src/components/ui/DistinguishedNameBreadcrumb.vue
Normal file
46
web/src/components/ui/DistinguishedNameBreadcrumb.vue
Normal file
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-icon v-if="showIcon" left>mdi-file-tree-outline</v-icon>
|
||||
<span
|
||||
v-for="(item, index) in items"
|
||||
:key="index"
|
||||
class="path text--secondary"
|
||||
>
|
||||
{{ item.text }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
dn: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
showIcon: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
items() {
|
||||
const dirs = this.dn.split(',OU=IFMS,DC=ifms')[0].split(',').reverse()
|
||||
|
||||
return dirs.map(dir => ({
|
||||
text: dir.split('=')[1]
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.path {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
.path::after {
|
||||
content: '/';
|
||||
}
|
||||
</style>
|
59
web/src/components/ui/RoleBadge.vue
Normal file
59
web/src/components/ui/RoleBadge.vue
Normal file
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<v-chip label :color="color + ' darken-4'" small dark outlined>
|
||||
{{ text }}</v-chip
|
||||
>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
role: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
roles: [
|
||||
{
|
||||
text: 'Administrador',
|
||||
value: 'superAdmin',
|
||||
color: 'error'
|
||||
},
|
||||
{
|
||||
text: 'Criador de token',
|
||||
value: 'tokenCreator',
|
||||
color: 'warning'
|
||||
},
|
||||
{
|
||||
text: 'Servidor',
|
||||
value: 'servant',
|
||||
color: 'success'
|
||||
},
|
||||
{
|
||||
text: 'Aluno',
|
||||
value: 'student',
|
||||
color: 'teal'
|
||||
},
|
||||
{
|
||||
text: 'Localizador',
|
||||
value: 'watcher',
|
||||
color: 'amber'
|
||||
}
|
||||
]
|
||||
}),
|
||||
computed: {
|
||||
text() {
|
||||
const text = this.roles.find(role => role.value == this.role).text
|
||||
|
||||
return text ? text : this.role
|
||||
},
|
||||
color() {
|
||||
const color = this.roles.find(role => role.value == this.role).color
|
||||
|
||||
return color ? color : 'grey'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
|
@ -55,7 +55,8 @@ export default {
|
|||
return 'mdi-signal-cellular-outline'
|
||||
},
|
||||
signalStrengthColor(signalStrength) {
|
||||
if (signalStrength > -50) return 'green'
|
||||
if (signalStrength > -30) return 'teal'
|
||||
else if (signalStrength > -50) return 'green'
|
||||
else if (signalStrength > -60) return 'light-green'
|
||||
else if (signalStrength > -67) return 'lime'
|
||||
else if (signalStrength > -70) return 'amber'
|
||||
|
@ -64,7 +65,8 @@ export default {
|
|||
else return 'red'
|
||||
},
|
||||
signalStrengthText(signalStrength) {
|
||||
if (signalStrength > -50) return 'Excelente'
|
||||
if (signalStrength > -30) return 'Excelente'
|
||||
else if (signalStrength > -50) return 'Muito bom'
|
||||
else if (signalStrength > -60) return 'Bom'
|
||||
else if (signalStrength > -67) return 'Regular'
|
||||
else if (signalStrength > -70) return 'Fraco'
|
|
@ -228,7 +228,16 @@ const routes = [
|
|||
roles: ['superAdmin']
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "wifi-users" */ '../views/WifiUsers.vue')
|
||||
import(/* webpackChunkName: "wifi-users" */ '../views/WifiUsers')
|
||||
},
|
||||
|
||||
{
|
||||
path: '/wifi-users/:sAMAccountName/',
|
||||
name: 'wifi-user-single',
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "wifi-user-single" */ '../views/WifiUsers/single.vue'
|
||||
)
|
||||
},
|
||||
|
||||
{
|
||||
|
|
9
web/src/views/UserWifiDevices.vue
Normal file
9
web/src/views/UserWifiDevices.vue
Normal file
|
@ -0,0 +1,9 @@
|
|||
<template>
|
||||
<v-container> </v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style></style>
|
|
@ -1,223 +0,0 @@
|
|||
<template>
|
||||
<v-container fluid>
|
||||
<v-toolbar flat outlined>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
label="Pesquisar"
|
||||
prepend-icon="mdi-devices"
|
||||
clearable
|
||||
hide-details
|
||||
:loading="$apollo.queries.wifiUsers.loading && !!search"
|
||||
/>
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<v-select
|
||||
v-model="itemsPerPage"
|
||||
class="shrink"
|
||||
:items="[5, 10, 20, 30, 50, 100]"
|
||||
label="Items por página"
|
||||
hide-details
|
||||
outlined
|
||||
dense
|
||||
/>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<span>Atualizar</span>
|
||||
<template #activator="{ on }">
|
||||
<v-btn
|
||||
class="ml-2"
|
||||
:loading="$apollo.queries.wifiUsers.loading"
|
||||
icon
|
||||
large
|
||||
v-on="on"
|
||||
@click="$apollo.queries.wifiUsers.refetch()"
|
||||
>
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</v-toolbar>
|
||||
<div v-if="stats" class="text-center my-4">
|
||||
<v-chip color="primary" class="mr-2" dark>
|
||||
{{ stats.onlineUsers }}
|
||||
</v-chip>
|
||||
usuários online de
|
||||
<v-chip class="ml-2">
|
||||
{{ stats.totalUsers }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<div v-else class="text-center my-4">
|
||||
<v-chip color="primary" class="mr-2" dark>
|
||||
<v-progress-circular indeterminate size="12" width="1" />
|
||||
</v-chip>
|
||||
usuários online de
|
||||
<v-chip class="ml-2">
|
||||
<v-progress-circular indeterminate size="12" width="1" />
|
||||
</v-chip>
|
||||
</div>
|
||||
|
||||
<v-data-iterator
|
||||
:loading="$apollo.queries.wifiUsers.loading"
|
||||
:items="sortedWifiUsers"
|
||||
hide-default-footer
|
||||
:items-per-page="itemsPerPage"
|
||||
>
|
||||
<template #loading>
|
||||
<v-expansion-panels disabled>
|
||||
<v-expansion-panel v-for="i in 10" :key="i">
|
||||
<v-expansion-panel-header class="pa-1">
|
||||
<v-skeleton-loader class="ma-0 pa-0" type="list-item-avatar" />
|
||||
</v-expansion-panel-header>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
|
||||
<template #default="{ items }">
|
||||
<v-expansion-panels>
|
||||
<v-expansion-panel v-for="user in items" :key="user.sAMAccountName">
|
||||
<v-expansion-panel-header>
|
||||
<div class="ml-1">
|
||||
<v-badge color="grey darken-1" bottom left offset-y="12">
|
||||
<template #badge>
|
||||
<small>
|
||||
{{
|
||||
user.wifiDevices
|
||||
.filter(wifiDevice => wifiDevice.status != 'ONLINE')
|
||||
.length.toString()
|
||||
}}
|
||||
</small>
|
||||
</template>
|
||||
<v-badge color="green darken-1" top left offset-y="12">
|
||||
<template #badge>
|
||||
<small>
|
||||
{{
|
||||
user.wifiDevices
|
||||
.filter(wifiDevice => wifiDevice.status == 'ONLINE')
|
||||
.length.toString()
|
||||
}}
|
||||
</small>
|
||||
</template>
|
||||
<Avatar left size="32" :src="user.thumbnailPhoto" />
|
||||
</v-badge>
|
||||
</v-badge>
|
||||
{{ user.displayName }} ({{ user.sAMAccountName }})
|
||||
</div>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<v-expansion-panels accordion>
|
||||
<UserWifiDevicesDataTable
|
||||
class="grow"
|
||||
:wifi-devices="user.wifiDevices"
|
||||
/>
|
||||
</v-expansion-panels>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</template>
|
||||
</v-data-iterator>
|
||||
<v-pagination
|
||||
v-model="page"
|
||||
class="my-4"
|
||||
:length="pagesTotal"
|
||||
:total-visible="7"
|
||||
/>
|
||||
</v-container>
|
||||
</template>
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import Avatar from '../components/Avatar.vue'
|
||||
import UserWifiDevicesDataTable from '../components/DataTables/UserWifiDevicesDataTable.vue'
|
||||
|
||||
export default {
|
||||
components: { Avatar, UserWifiDevicesDataTable },
|
||||
data: () => ({
|
||||
search: '',
|
||||
page: 1,
|
||||
itemsPerPage: 10
|
||||
}),
|
||||
computed: {
|
||||
sortedWifiUsers() {
|
||||
return this.wifiUsers?.data?.map(user => ({
|
||||
...user,
|
||||
ips: user.wifiDevices.reduce((ips, device) => ` ${device.ip}`, ''),
|
||||
wifiDevices: user.wifiDevices.sort(a => (a.status == 'ONLINE' ? -1 : 1))
|
||||
}))
|
||||
},
|
||||
pagesTotal() {
|
||||
if (this.wifiUsers?.total)
|
||||
return Math.ceil(this.wifiUsers.total / this.itemsPerPage)
|
||||
else return 1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
search(newValue) {
|
||||
if (!newValue) this.$router.push({ query: {} })
|
||||
else if (this.$route.query.search != newValue)
|
||||
this.$router.push({ query: { search: newValue } })
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search = this.$route.query.search || ''
|
||||
},
|
||||
apollo: {
|
||||
wifiUsers: {
|
||||
fetchPolicy: 'cache-and-network',
|
||||
query: gql`
|
||||
query wifiUsers($search: String, $skip: Int, $take: Int) {
|
||||
wifiUsers(search: $search, skip: $skip, take: $take) {
|
||||
total
|
||||
data {
|
||||
displayName
|
||||
sAMAccountName
|
||||
thumbnailPhoto
|
||||
wifiDevices {
|
||||
mac
|
||||
oui
|
||||
controller
|
||||
hostname
|
||||
firstSeen
|
||||
lastSeen
|
||||
status
|
||||
apName
|
||||
essid
|
||||
ip
|
||||
uptime
|
||||
signalStrength
|
||||
frequency
|
||||
protocol
|
||||
speed
|
||||
usage
|
||||
|
||||
accessPoint {
|
||||
id
|
||||
name
|
||||
hostname
|
||||
local
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
search: this.search,
|
||||
skip: this.page * this.itemsPerPage - this.itemsPerPage,
|
||||
take: this.itemsPerPage
|
||||
}
|
||||
}
|
||||
},
|
||||
stats: {
|
||||
query: gql`
|
||||
query {
|
||||
stats {
|
||||
onlineUsers
|
||||
totalUsers
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
141
web/src/views/WifiUsers/index.vue
Normal file
141
web/src/views/WifiUsers/index.vue
Normal file
|
@ -0,0 +1,141 @@
|
|||
<template>
|
||||
<v-container fluid>
|
||||
<v-toolbar flat outlined>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
label="Pesquisar"
|
||||
prepend-icon="mdi-devices"
|
||||
clearable
|
||||
hide-details
|
||||
:loading="$apollo.queries.wifiUsers.loading && !!search"
|
||||
/>
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<v-select
|
||||
v-model="itemsPerPage"
|
||||
class="shrink"
|
||||
:items="[5, 10, 20, 30, 50, 100]"
|
||||
label="Items por página"
|
||||
hide-details
|
||||
outlined
|
||||
dense
|
||||
/>
|
||||
|
||||
<v-tooltip bottom>
|
||||
<span>Atualizar</span>
|
||||
<template #activator="{ on }">
|
||||
<v-btn
|
||||
class="ml-2"
|
||||
:loading="$apollo.queries.wifiUsers.loading"
|
||||
icon
|
||||
large
|
||||
v-on="on"
|
||||
@click="$apollo.queries.wifiUsers.refetch()"
|
||||
>
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</v-toolbar>
|
||||
<div v-if="stats" class="text-center my-4">
|
||||
<v-chip color="primary" class="mr-2" dark>
|
||||
{{ stats.onlineUsers }}
|
||||
</v-chip>
|
||||
usuários online de
|
||||
<v-chip class="ml-2">
|
||||
{{ stats.totalUsers }}
|
||||
</v-chip>
|
||||
</div>
|
||||
<div v-else class="text-center my-4">
|
||||
<v-chip color="primary" class="mr-2" dark>
|
||||
<v-progress-circular indeterminate size="12" width="1" />
|
||||
</v-chip>
|
||||
usuários online de
|
||||
<v-chip class="ml-2">
|
||||
<v-progress-circular indeterminate size="12" width="1" />
|
||||
</v-chip>
|
||||
</div>
|
||||
|
||||
<WifiUsersDataTable v-if="wifiUsers" :wifi-users="wifiUsers.data" />
|
||||
|
||||
<v-pagination
|
||||
v-model="page"
|
||||
class="my-4"
|
||||
:length="pagesTotal"
|
||||
:total-visible="7"
|
||||
/>
|
||||
</v-container>
|
||||
</template>
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import WifiUsersDataTable from '../../components/DataTables/WifiUsersDataTable.vue'
|
||||
|
||||
export default {
|
||||
components: { WifiUsersDataTable },
|
||||
data: () => ({
|
||||
search: '',
|
||||
page: 1,
|
||||
itemsPerPage: 10
|
||||
}),
|
||||
computed: {
|
||||
items() {
|
||||
return this.wifiUsers.data.map(wifiUser => ({
|
||||
...wifiUser,
|
||||
combinedUser: `${wifiUser.displayName} (${wifiUser.sAMAccountName})`
|
||||
}))
|
||||
},
|
||||
pagesTotal() {
|
||||
if (this.wifiUsers?.total)
|
||||
return Math.ceil(this.wifiUsers.total / this.itemsPerPage)
|
||||
else return 1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
search(newValue) {
|
||||
if (!newValue) this.$router.push({ query: {} })
|
||||
else if (this.$route.query.search != newValue)
|
||||
this.$router.push({ query: { search: newValue } })
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.search = this.$route.query.search || ''
|
||||
},
|
||||
apollo: {
|
||||
wifiUsers: {
|
||||
fetchPolicy: 'cache-and-network',
|
||||
query: gql`
|
||||
query wifiUsers($search: String, $skip: Int, $take: Int) {
|
||||
wifiUsers(search: $search, skip: $skip, take: $take) {
|
||||
total
|
||||
data {
|
||||
displayName
|
||||
sAMAccountName
|
||||
thumbnailPhoto
|
||||
onlineWifiDevicesCount
|
||||
offlineWifiDevicesCount
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
search: this.search,
|
||||
skip: this.page * this.itemsPerPage - this.itemsPerPage,
|
||||
take: this.itemsPerPage
|
||||
}
|
||||
}
|
||||
},
|
||||
stats: {
|
||||
query: gql`
|
||||
query {
|
||||
stats {
|
||||
onlineUsers
|
||||
totalUsers
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
99
web/src/views/WifiUsers/single.vue
Normal file
99
web/src/views/WifiUsers/single.vue
Normal file
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-btn class="ma-2" icon @click="$router.back()">
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
<v-container v-if="user">
|
||||
<v-card class="mb-2">
|
||||
<v-card-title class="font-weight-regular">
|
||||
<Avatar :src="user.thumbnailPhoto" size="56" left />
|
||||
<div>
|
||||
{{ user.displayName }}
|
||||
<DistinguishedNameBreadcrumb :dn="user.dn" />
|
||||
<RoleBadge
|
||||
v-for="role in user.roles"
|
||||
:key="role"
|
||||
class="mr-1"
|
||||
:role="role"
|
||||
/>
|
||||
</div>
|
||||
<v-spacer />
|
||||
</v-card-title>
|
||||
<v-divider />
|
||||
|
||||
<v-card-text>
|
||||
<UserWifiDevicesDataTable :wifi-devices="user.wifiDevices" />
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
<v-container v-else indeterminate>
|
||||
<v-progress-linear indeterminate />
|
||||
<v-skeleton-loader class="my-4" type="card-heading, card" />
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import UserWifiDevicesDataTable from '../../components/DataTables/UserWifiDevicesDataTable.vue'
|
||||
import Avatar from '../../components/Avatar.vue'
|
||||
import DistinguishedNameBreadcrumb from '../../components/ui/DistinguishedNameBreadcrumb.vue'
|
||||
import RoleBadge from '../../components/ui/RoleBadge.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
UserWifiDevicesDataTable,
|
||||
Avatar,
|
||||
DistinguishedNameBreadcrumb,
|
||||
RoleBadge
|
||||
},
|
||||
apollo: {
|
||||
user: {
|
||||
query: gql`
|
||||
query user($sAMAccountName: String!) {
|
||||
user(sAMAccountName: $sAMAccountName) {
|
||||
displayName
|
||||
sAMAccountName
|
||||
thumbnailPhoto
|
||||
dn
|
||||
roles
|
||||
wifiDevices {
|
||||
mac
|
||||
oui
|
||||
controller
|
||||
hostname
|
||||
firstSeen
|
||||
lastSeen
|
||||
status
|
||||
apName
|
||||
essid
|
||||
ip
|
||||
uptime
|
||||
signalStrength
|
||||
frequency
|
||||
protocol
|
||||
speed
|
||||
usage
|
||||
|
||||
accessPoint {
|
||||
id
|
||||
name
|
||||
hostname
|
||||
local
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
sAMAccountName: this.$route.params.sAMAccountName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
Loading…
Reference in New Issue
Block a user