diff --git a/package-lock.json b/package-lock.json index 05ae7c4..1dc2adf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1439,6 +1439,19 @@ "node": ">= 8" } }, + "node_modules/apexcharts": { + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.41.0.tgz", + "integrity": "sha512-FJXA7NVjxs1q+ptR3b1I+pN8K/gWuXn+qLZjFz8EHvJOokdgcuwa/HSe5aC465HW/LWnrjWLSTsOQejQbQ42hQ==", + "dependencies": { + "svg.draggable.js": "^2.2.2", + "svg.easing.js": "^2.0.0", + "svg.filter.js": "^2.0.2", + "svg.pathmorphing.js": "^0.1.3", + "svg.resize.js": "^1.4.3", + "svg.select.js": "^3.0.1" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -4533,6 +4546,89 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/svg.draggable.js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", + "integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==", + "dependencies": { + "svg.js": "^2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.easing.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz", + "integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==", + "dependencies": { + "svg.js": ">=2.3.x" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.filter.js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz", + "integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==", + "dependencies": { + "svg.js": "^2.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.js": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz", + "integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==" + }, + "node_modules/svg.pathmorphing.js": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz", + "integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==", + "dependencies": { + "svg.js": "^2.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.resize.js": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz", + "integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==", + "dependencies": { + "svg.js": "^2.6.5", + "svg.select.js": "^2.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.resize.js/node_modules/svg.select.js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz", + "integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==", + "dependencies": { + "svg.js": "^2.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/svg.select.js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz", + "integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==", + "dependencies": { + "svg.js": "^2.6.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4990,6 +5086,15 @@ "typescript": "*" } }, + "node_modules/vue3-apexcharts": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/vue3-apexcharts/-/vue3-apexcharts-1.4.1.tgz", + "integrity": "sha512-96qP8JDqB9vwU7bkG5nVU+E0UGQn7yYQVqUUCLQMYWDuQyu2vE77H/UFZ1yI+hwzlSTBKT9BqnNG8JsFegB3eg==", + "peerDependencies": { + "apexcharts": "> 3.0.0", + "vue": "> 3.0.0" + } + }, "node_modules/vuetify": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.3.5.tgz", @@ -5263,10 +5368,12 @@ "version": "0.0.0", "dependencies": { "@mdi/font": "7.0.96", + "apexcharts": "^3.41.0", "pinia": "^2.0.23", "roboto-fontface": "*", "vue": "^3.2.0", "vue-router": "^4.0.0", + "vue3-apexcharts": "^1.4.1", "vuetify": "^3.0.0", "webfontloader": "^1.0.0" }, diff --git a/src/controllers/PrinterStatusController.ts b/src/controllers/PrinterStatusController.ts index b659014..b88d805 100644 --- a/src/controllers/PrinterStatusController.ts +++ b/src/controllers/PrinterStatusController.ts @@ -2,6 +2,7 @@ import { Router, Request, Response } from 'express' import { prisma } from '../prisma.js' import { PrinterStatusService } from '../services/PrinterStatusService.js' import { hasRolesMiddleware } from '../middlewares/hasRolesMiddleware.js' +import { distributedCopy } from '../utils/distributedCopy.js' const router = Router() @@ -15,10 +16,33 @@ class PrinterStatusController { res.json({ message: 'Updating printer status' }) } + + static async status(req: Request, res: Response) { + const { printerId } = req.params + + const { take = 32, days = 60 } = req.query + + const gte = new Date(Date.now() - 1000 * 60 * 60 * 24 * Number(days)) + + const status = await prisma.printerStatus.findMany({ + where: { + printerId: Number(printerId), + timestamp: { + gte + } + }, + orderBy: { timestamp: 'desc' } + }) + + const distributedStatus = distributedCopy(status, Number(take)) + + res.json(distributedStatus) + } } router.use(hasRolesMiddleware(['ADMIN', 'INSPECTOR'])) router.post('/update', PrinterStatusController.update) +router.get('/:printerId', PrinterStatusController.status) export default router diff --git a/src/server.ts b/src/server.ts index 72c9dd5..6b8cbfd 100644 --- a/src/server.ts +++ b/src/server.ts @@ -3,7 +3,6 @@ import bodyParser from 'body-parser' import cors from 'cors' import { populateUserMiddleware } from './middlewares/populateUserMiddleware.js' -import { authMiddleware } from './middlewares/authMiddleware.js' import { loggerMiddleware } from './middlewares/loggerMiddleware.js' import LoginRouter from './controllers/LoginController.js' @@ -21,7 +20,7 @@ app.use('/api', bodyParser.json()) app.use('/api/login', LoginRouter) app.use('/api/printer', PrinterRouter) -app.use('/api/printer-status', PrinterStatusRouter) +app.use('/api/status', PrinterStatusRouter) app.use('/api/discovery', PrinterDiscoveryRouter) app.use('/', express.static('public')) diff --git a/web/package.json b/web/package.json index f5e7000..a6e5a20 100644 --- a/web/package.json +++ b/web/package.json @@ -9,10 +9,12 @@ }, "dependencies": { "@mdi/font": "7.0.96", + "apexcharts": "^3.41.0", "pinia": "^2.0.23", "roboto-fontface": "*", "vue": "^3.2.0", "vue-router": "^4.0.0", + "vue3-apexcharts": "^1.4.1", "vuetify": "^3.0.0", "webfontloader": "^1.0.0" }, diff --git a/web/src/components/PrinterCard.vue b/web/src/components/PrinterCard.vue index 9f99ec1..d4f7c97 100644 --- a/web/src/components/PrinterCard.vue +++ b/web/src/components/PrinterCard.vue @@ -1,7 +1,11 @@ diff --git a/web/src/layouts/default/View.vue b/web/src/layouts/default/View.vue index 05ddbf0..fa6a347 100644 --- a/web/src/layouts/default/View.vue +++ b/web/src/layouts/default/View.vue @@ -29,6 +29,14 @@ hide-details /> + import('@/layouts/default/Default.vue'), children: [ { - path: '', + path: 'home', name: 'Home', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route @@ -27,6 +27,15 @@ const routes = [ component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue') }, + { + path: ':id', + name: 'Printer', + // route level code-splitting + // this generates a separate chunk (about.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: () => + import(/* webpackChunkName: "home" */ '@/views/Printer.vue') + }, { path: '/:pathMatch(.*)*', diff --git a/web/src/views/Printer.vue b/web/src/views/Printer.vue new file mode 100644 index 0000000..89eb55f --- /dev/null +++ b/web/src/views/Printer.vue @@ -0,0 +1,3 @@ +