Compare commits
10 Commits
5ed3d074b0
...
7a83bf1216
Author | SHA1 | Date | |
---|---|---|---|
|
7a83bf1216 | ||
|
58077874c6 | ||
|
870c6b079e | ||
|
cbd28d7841 | ||
|
7a4cf37c2a | ||
|
dd1c2b299a | ||
|
f19d5d72d5 | ||
|
a5ba94ad25 | ||
|
cd8a18090f | ||
|
547aefe2e1 |
15
server/package-lock.json
generated
15
server/package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "ifms-pti-svr",
|
"name": "ifms-pti-svr",
|
||||||
"version": "3.4.9",
|
"version": "3.6.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ifms-pti-svr",
|
"name": "ifms-pti-svr",
|
||||||
"version": "3.4.9",
|
"version": "3.6.1",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^4.7.1",
|
"@prisma/client": "^4.7.1",
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
"bcrypt": "^5.0.0",
|
"bcrypt": "^5.0.0",
|
||||||
"core-js": "^3.19.1",
|
"core-js": "^3.19.1",
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
|
"dataloader": "^2.2.1",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"graphql": "^14.6.0",
|
"graphql": "^14.6.0",
|
||||||
|
@ -3226,6 +3227,11 @@
|
||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dataloader": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-Zn+tVZo1RKu120rgoe0JsRk56UiKdefPSH47QROJsMHrX8/S9UJvi5A/A6+Sbuk6rE88z5JoM/wIJ09Z7BTfYA=="
|
||||||
|
},
|
||||||
"node_modules/date-fns": {
|
"node_modules/date-fns": {
|
||||||
"version": "2.29.3",
|
"version": "2.29.3",
|
||||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
|
||||||
|
@ -8785,6 +8791,11 @@
|
||||||
"assert-plus": "^1.0.0"
|
"assert-plus": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dataloader": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-Zn+tVZo1RKu120rgoe0JsRk56UiKdefPSH47QROJsMHrX8/S9UJvi5A/A6+Sbuk6rE88z5JoM/wIJ09Z7BTfYA=="
|
||||||
|
},
|
||||||
"date-fns": {
|
"date-fns": {
|
||||||
"version": "2.29.3",
|
"version": "2.29.3",
|
||||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ifms-pti-svr",
|
"name": "ifms-pti-svr",
|
||||||
"version": "3.4.9",
|
"version": "3.6.1",
|
||||||
"description": "Servidor do Portal de TI do IFMS",
|
"description": "Servidor do Portal de TI do IFMS",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"prisma": {
|
"prisma": {
|
||||||
|
@ -48,6 +48,7 @@
|
||||||
"bcrypt": "^5.0.0",
|
"bcrypt": "^5.0.0",
|
||||||
"core-js": "^3.19.1",
|
"core-js": "^3.19.1",
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
|
"dataloader": "^2.2.1",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"graphql": "^14.6.0",
|
"graphql": "^14.6.0",
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "AccessPoint" ADD COLUMN "networkId" INTEGER;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "AccessPoint" ADD CONSTRAINT "AccessPoint_networkId_fkey" FOREIGN KEY ("networkId") REFERENCES "Network"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
@ -153,6 +153,9 @@ model AccessPoint {
|
||||||
uplinkSpeed Int?
|
uplinkSpeed Int?
|
||||||
stats AccessPointStats[] @relation("accesspointstats_to_ap")
|
stats AccessPointStats[] @relation("accesspointstats_to_ap")
|
||||||
wifiDevices WifiDevice[] @relation("wifidevice_to_ap")
|
wifiDevices WifiDevice[] @relation("wifidevice_to_ap")
|
||||||
|
|
||||||
|
network Network? @relation(fields: [networkId], references: [id])
|
||||||
|
networkId Int?
|
||||||
}
|
}
|
||||||
|
|
||||||
model AccessPointStats {
|
model AccessPointStats {
|
||||||
|
@ -196,6 +199,7 @@ model Network {
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
NetworkStats NetworkStats[]
|
NetworkStats NetworkStats[]
|
||||||
WifiDevice WifiDevice[]
|
WifiDevice WifiDevice[]
|
||||||
|
AccessPoint AccessPoint[]
|
||||||
|
|
||||||
@@index([id])
|
@@index([id])
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import prisma from '../prisma'
|
||||||
|
|
||||||
import { getAccessPoints as getCiscoAccessPoints } from './ciscoController'
|
import { getAccessPoints as getCiscoAccessPoints } from './ciscoController'
|
||||||
import { logInfo, logSuccess } from './logger'
|
import { logInfo, logSuccess } from './logger'
|
||||||
|
import { getSubnetInfo } from './subnetInfo'
|
||||||
import { getAccessPoints as getUnifiAccessPoints } from './unifiController'
|
import { getAccessPoints as getUnifiAccessPoints } from './unifiController'
|
||||||
|
|
||||||
async function getAccessPoints() {
|
async function getAccessPoints() {
|
||||||
|
@ -20,11 +21,19 @@ async function updateDB(accessPoints) {
|
||||||
const dbAccessPoints = []
|
const dbAccessPoints = []
|
||||||
|
|
||||||
for (const accessPoint of accessPoints) {
|
for (const accessPoint of accessPoints) {
|
||||||
|
const network = getSubnetInfo(accessPoint.ip)
|
||||||
|
|
||||||
dbAccessPoints.push(
|
dbAccessPoints.push(
|
||||||
await prisma.accessPoint.upsert({
|
await prisma.accessPoint.upsert({
|
||||||
where: { mac: accessPoint.mac },
|
where: { mac: accessPoint.mac },
|
||||||
create: accessPoint,
|
create: {
|
||||||
update: accessPoint
|
...accessPoint,
|
||||||
|
networkId: network.id || undefined
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
...accessPoint,
|
||||||
|
networkId: network.id || undefined
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,8 +205,6 @@ export async function getOnlineWifiDevices() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fs = require('fs')
|
|
||||||
|
|
||||||
export async function getAccessPoints() {
|
export async function getAccessPoints() {
|
||||||
try {
|
try {
|
||||||
const [accessPoints] = await unifiController.getAccessDevices('default')
|
const [accessPoints] = await unifiController.getAccessDevices('default')
|
||||||
|
|
|
@ -2,6 +2,9 @@ import prisma from '../prisma'
|
||||||
import { getSubnetInfo } from '../lib/subnetInfo'
|
import { getSubnetInfo } from '../lib/subnetInfo'
|
||||||
import { subMinutes } from 'date-fns'
|
import { subMinutes } from 'date-fns'
|
||||||
import { distributedCopy } from '../utils/distributedCopy'
|
import { distributedCopy } from '../utils/distributedCopy'
|
||||||
|
import Dataloader from 'dataloader'
|
||||||
|
|
||||||
|
const statsLoader = new Dataloader(getStatsUsingAccessPointId)
|
||||||
|
|
||||||
export const AccessPoint = {
|
export const AccessPoint = {
|
||||||
updatedAt: (parent, data, context, info) => parent.updatedAt?.toISOString(),
|
updatedAt: (parent, data, context, info) => parent.updatedAt?.toISOString(),
|
||||||
|
@ -26,19 +29,14 @@ export const AccessPoint = {
|
||||||
stats: async (parent, { take, minutesIn = 60, dateOut }, context, info) => {
|
stats: async (parent, { take, minutesIn = 60, dateOut }, context, info) => {
|
||||||
const dateIn = subMinutes(dateOut || Date.now(), minutesIn)
|
const dateIn = subMinutes(dateOut || Date.now(), minutesIn)
|
||||||
|
|
||||||
const stats = await prisma.accessPointStats.findMany({
|
const accessPoint = await statsLoader.load({
|
||||||
where: {
|
id: parent.id,
|
||||||
accessPoint: {
|
minutesIn,
|
||||||
id: parent.id
|
dateIn,
|
||||||
},
|
dateOut
|
||||||
timestamp: { gte: dateIn, lte: dateOut }
|
|
||||||
},
|
|
||||||
orderBy: { timestamp: 'desc' }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (take) return distributedCopy(stats, take)
|
return distributedCopy(accessPoint.stats, take)
|
||||||
|
|
||||||
return stats
|
|
||||||
},
|
},
|
||||||
|
|
||||||
latestStats: async (parent, data, context, info) =>
|
latestStats: async (parent, data, context, info) =>
|
||||||
|
@ -47,3 +45,33 @@ export const AccessPoint = {
|
||||||
orderBy: { timestamp: 'desc' }
|
orderBy: { timestamp: 'desc' }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getStatsUsingAccessPointId(keys) {
|
||||||
|
const ids = keys.map(key => key.id)
|
||||||
|
|
||||||
|
const dateIn = keys[0].dateIn
|
||||||
|
const dateOut = keys[0].dateOut
|
||||||
|
|
||||||
|
const accessPointsWithStats = await prisma.accessPoint.findMany({
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
in: ids
|
||||||
|
}
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
stats: {
|
||||||
|
where: {
|
||||||
|
timestamp: { gte: dateIn, lte: dateOut }
|
||||||
|
},
|
||||||
|
orderBy: { timestamp: 'desc' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// order accessPointsWithStats in the same order as keys
|
||||||
|
const accessPointsWithStatsOrdered = ids.map(id =>
|
||||||
|
accessPointsWithStats.find(accessPoint => accessPoint.id === id)
|
||||||
|
)
|
||||||
|
|
||||||
|
return accessPointsWithStatsOrdered
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
import { updateAccessPoints } from '../../lib/accessPoints'
|
import { updateAccessPoints } from '../../lib/accessPoints'
|
||||||
import prisma from '../../prisma'
|
import prisma from '../../prisma'
|
||||||
|
|
||||||
export async function accessPoints() {
|
export async function accessPoints(_, { networkShortName }) {
|
||||||
updateAccessPoints()
|
updateAccessPoints()
|
||||||
|
|
||||||
return prisma.accessPoint.findMany({
|
return prisma.accessPoint.findMany({
|
||||||
|
where: {
|
||||||
|
network: {
|
||||||
|
shortName: networkShortName
|
||||||
|
}
|
||||||
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
hostname: 'asc'
|
hostname: 'asc'
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
|
network: true,
|
||||||
wifiDevices: {
|
wifiDevices: {
|
||||||
where: {
|
where: {
|
||||||
status: 'ONLINE'
|
status: 'ONLINE'
|
||||||
|
|
|
@ -59,7 +59,8 @@ const typeDefs = gql`
|
||||||
pAHosts: [PAHost!]! @auth(roles: ["superAdmin"])
|
pAHosts: [PAHost!]! @auth(roles: ["superAdmin"])
|
||||||
|
|
||||||
"All Access Points"
|
"All Access Points"
|
||||||
accessPoints: [AccessPoint!]! @auth(roles: ["superAdmin"])
|
accessPoints(networkShortName: String): [AccessPoint!]!
|
||||||
|
@auth(roles: ["superAdmin"])
|
||||||
|
|
||||||
"One Access Point"
|
"One Access Point"
|
||||||
accessPoint(id: ID!): AccessPoint! @auth(roles: ["superAdmin"])
|
accessPoint(id: ID!): AccessPoint! @auth(roles: ["superAdmin"])
|
||||||
|
|
4
web/package-lock.json
generated
4
web/package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "ifms-pti",
|
"name": "ifms-pti",
|
||||||
"version": "3.4.9",
|
"version": "3.6.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "ifms-pti",
|
"name": "ifms-pti",
|
||||||
"version": "3.4.9",
|
"version": "3.6.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdi/font": "^6.9.96",
|
"@mdi/font": "^6.9.96",
|
||||||
"apollo-link-ws": "^1.0.20",
|
"apollo-link-ws": "^1.0.20",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ifms-pti",
|
"name": "ifms-pti",
|
||||||
"version": "3.4.9",
|
"version": "3.6.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
|
|
|
@ -217,6 +217,18 @@ const routes = [
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "wifi-stats" */ '../views/WifiStats.vue')
|
import(/* webpackChunkName: "wifi-stats" */ '../views/WifiStats.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/access-points/stats',
|
||||||
|
name: 'access-points-stats',
|
||||||
|
meta: {
|
||||||
|
title: 'Status dos Access Points',
|
||||||
|
roles: ['superAdmin']
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "access-points-stats" */ '../views/AccessPoints/stats.vue'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/access-points/:id/clients',
|
path: '/access-points/:id/clients',
|
||||||
|
|
|
@ -62,6 +62,15 @@
|
||||||
hide-details
|
hide-details
|
||||||
:label="`Somente ${me.campusFull}`"
|
:label="`Somente ${me.campusFull}`"
|
||||||
/>
|
/>
|
||||||
|
<v-btn
|
||||||
|
class="ml-2"
|
||||||
|
text
|
||||||
|
color="secondary"
|
||||||
|
:to="{ name: 'access-points-stats' }"
|
||||||
|
>
|
||||||
|
<v-icon left>mdi-chart-line</v-icon>
|
||||||
|
Status
|
||||||
|
</v-btn>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
|
|
||||||
<v-data-table
|
<v-data-table
|
||||||
|
@ -394,8 +403,8 @@ export default {
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-and-network',
|
||||||
debounce: 200,
|
debounce: 200,
|
||||||
query: gql`
|
query: gql`
|
||||||
query accessPoints {
|
query accessPoints($networkShortName: String) {
|
||||||
accessPoints {
|
accessPoints(networkShortName: $networkShortName) {
|
||||||
id
|
id
|
||||||
mac
|
mac
|
||||||
hostname
|
hostname
|
||||||
|
@ -420,6 +429,11 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
variables() {
|
||||||
|
return {
|
||||||
|
networkShortName: (this.sameCampus && this.me?.campus) || undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
subscribeToMore: {
|
subscribeToMore: {
|
||||||
document: gql`
|
document: gql`
|
||||||
subscription {
|
subscription {
|
||||||
|
|
259
web/src/views/AccessPoints/stats.vue
Normal file
259
web/src/views/AccessPoints/stats.vue
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-toolbar dense flat>
|
||||||
|
<v-select
|
||||||
|
v-model="subnet"
|
||||||
|
class="mr-2"
|
||||||
|
:items="subnetSelectItems"
|
||||||
|
style="max-width: 250px"
|
||||||
|
hide-details
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
prepend-inner-icon="mdi-home-group"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-spacer />
|
||||||
|
<v-select
|
||||||
|
v-model="orderBy"
|
||||||
|
class="mr-2"
|
||||||
|
style="max-width: 250px"
|
||||||
|
:items="orderByOptions"
|
||||||
|
hide-details
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
prepend-inner-icon="mdi-sort"
|
||||||
|
/>
|
||||||
|
<v-select
|
||||||
|
v-model="minutesIn"
|
||||||
|
style="max-width: 250px"
|
||||||
|
:items="minutesInItems"
|
||||||
|
hide-details
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
prepend-inner-icon="mdi-timer-outline"
|
||||||
|
/>
|
||||||
|
</v-toolbar>
|
||||||
|
<v-expand-transition>
|
||||||
|
<v-progress-linear
|
||||||
|
v-if="$apollo.queries.accessPoints.loading"
|
||||||
|
class="pa-0 ma-0"
|
||||||
|
indeterminate
|
||||||
|
/>
|
||||||
|
</v-expand-transition>
|
||||||
|
<v-container fluid>
|
||||||
|
<v-row dense>
|
||||||
|
<v-col
|
||||||
|
v-for="ap in orderedAccessPoints"
|
||||||
|
:key="ap.id"
|
||||||
|
sm="12"
|
||||||
|
md="6"
|
||||||
|
lg="4"
|
||||||
|
>
|
||||||
|
<v-card class="mb-1" flat outlined>
|
||||||
|
<v-btn
|
||||||
|
block
|
||||||
|
text
|
||||||
|
class="font-weight-light"
|
||||||
|
:to="{
|
||||||
|
name: 'access-point-clients',
|
||||||
|
params: { id: ap.id }
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ ap.name || ap.hostname }}
|
||||||
|
<span v-if="ap.local"> ({{ ap.local }}) </span>
|
||||||
|
</v-btn>
|
||||||
|
<v-card-text class="pa-0">
|
||||||
|
<ClientsChart
|
||||||
|
:stats="ap.stats"
|
||||||
|
:subnet="ap.subnet"
|
||||||
|
:height="90"
|
||||||
|
hide-labels
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import ClientsChart from '../../components/charts/ClientsChart.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AccessPointsStats',
|
||||||
|
components: {
|
||||||
|
ClientsChart
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
subnet: null,
|
||||||
|
minutesIn: 720,
|
||||||
|
minutesInItems: [
|
||||||
|
{
|
||||||
|
text: 'Última hora',
|
||||||
|
value: 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Últimas 3 horas',
|
||||||
|
value: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Últimas 6 horas',
|
||||||
|
value: 360
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Últimas 12 horas',
|
||||||
|
value: 720
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Últimas 24 horas',
|
||||||
|
value: 1440
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Últimos 7 dias',
|
||||||
|
value: 10080
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Últimos 30 dias',
|
||||||
|
value: 43200
|
||||||
|
}
|
||||||
|
],
|
||||||
|
orderByOptions: [
|
||||||
|
'Alfabética',
|
||||||
|
'Clientes atualmente',
|
||||||
|
'Pico de clientes',
|
||||||
|
'Média de clientes'
|
||||||
|
],
|
||||||
|
orderBy: 'Pico de clientes'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
subnetSelectItems() {
|
||||||
|
return this.subnets?.map(network => {
|
||||||
|
return {
|
||||||
|
text: network.name,
|
||||||
|
value: network.shortName
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
orderedAccessPoints() {
|
||||||
|
const accessPoints = this.accessPoints
|
||||||
|
if (!accessPoints) return []
|
||||||
|
|
||||||
|
const orderBy = this.orderBy
|
||||||
|
|
||||||
|
if (orderBy === 'Alfabética') {
|
||||||
|
return accessPoints.sort((a, b) => {
|
||||||
|
const aName = a.name || a.hostname
|
||||||
|
const bName = b.name || b.hostname
|
||||||
|
return aName.localeCompare(bName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderBy === 'Clientes atualmente') {
|
||||||
|
return accessPoints.sort((a, b) => {
|
||||||
|
const aClients = a.clients || 0
|
||||||
|
const bClients = b.clients || 0
|
||||||
|
return bClients - aClients
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderBy === 'Pico de clientes') {
|
||||||
|
return accessPoints.sort((a, b) => {
|
||||||
|
const aStats = a.stats || []
|
||||||
|
const bStats = b.stats || []
|
||||||
|
const aMaxClients = aStats.reduce((max, stat) => {
|
||||||
|
return Math.max(max, stat.clients)
|
||||||
|
}, 0)
|
||||||
|
const bMaxClients = bStats.reduce((max, stat) => {
|
||||||
|
return Math.max(max, stat.clients)
|
||||||
|
}, 0)
|
||||||
|
return bMaxClients - aMaxClients
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderBy === 'Média de clientes') {
|
||||||
|
return accessPoints.sort((a, b) => {
|
||||||
|
const aStats = a.stats || []
|
||||||
|
const bStats = b.stats || []
|
||||||
|
const aAvgClients =
|
||||||
|
aStats.reduce((sum, stat) => {
|
||||||
|
return sum + stat.clients
|
||||||
|
}, 0) / aStats.length
|
||||||
|
const bAvgClients =
|
||||||
|
bStats.reduce((sum, stat) => {
|
||||||
|
return sum + stat.clients
|
||||||
|
}, 0) / bStats.length
|
||||||
|
return bAvgClients - aAvgClients
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return accessPoints
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
apollo: {
|
||||||
|
me: {
|
||||||
|
query: gql`
|
||||||
|
{
|
||||||
|
me {
|
||||||
|
campus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
result({ data }) {
|
||||||
|
this.subnet = data?.me.campus
|
||||||
|
}
|
||||||
|
},
|
||||||
|
subnets: {
|
||||||
|
query: gql`
|
||||||
|
{
|
||||||
|
subnets {
|
||||||
|
shortName
|
||||||
|
name
|
||||||
|
cidr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
},
|
||||||
|
accessPoints: {
|
||||||
|
pollInterval: 10000,
|
||||||
|
debounce: 500,
|
||||||
|
cachePolicy: 'cache-and-network',
|
||||||
|
skip() {
|
||||||
|
return !this.subnet
|
||||||
|
},
|
||||||
|
query: gql`
|
||||||
|
query accessPoints($networkShortName: String!, $minutesIn: Int!) {
|
||||||
|
accessPoints(networkShortName: $networkShortName) {
|
||||||
|
id
|
||||||
|
mac
|
||||||
|
name
|
||||||
|
hostname
|
||||||
|
clients
|
||||||
|
local
|
||||||
|
subnetInfo {
|
||||||
|
shortName
|
||||||
|
}
|
||||||
|
stats(minutesIn: $minutesIn, take: 64) {
|
||||||
|
timestamp
|
||||||
|
id
|
||||||
|
clients
|
||||||
|
avgUsage
|
||||||
|
sumUsage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables() {
|
||||||
|
return {
|
||||||
|
networkShortName: this.subnet,
|
||||||
|
minutesIn: this.minutesIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -3,8 +3,8 @@
|
||||||
<v-toolbar dense flat>
|
<v-toolbar dense flat>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-select
|
<v-select
|
||||||
class="mr-2"
|
|
||||||
v-model="orderBy"
|
v-model="orderBy"
|
||||||
|
class="mr-2"
|
||||||
style="max-width: 250px"
|
style="max-width: 250px"
|
||||||
:items="orderByOptions"
|
:items="orderByOptions"
|
||||||
hide-details
|
hide-details
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
<v-progress-linear
|
<v-progress-linear
|
||||||
v-if="$apollo.queries.subnets.loading"
|
v-if="$apollo.queries.subnets.loading"
|
||||||
class="pa-0 ma-0"
|
class="pa-0 ma-0"
|
||||||
:indeterminate="$apollo.queries.subnets.loading"
|
indeterminate
|
||||||
/>
|
/>
|
||||||
</v-expand-transition>
|
</v-expand-transition>
|
||||||
<v-container fluid>
|
<v-container fluid>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user