Redesign file browser, file upload (server)
This commit is contained in:
242
package-lock.json
generated
242
package-lock.json
generated
@@ -1,242 +0,0 @@
|
||||
{
|
||||
"name": "eventmaster",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"jspdf": "^2.5.2",
|
||||
"jspdf-autotable": "^3.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
||||
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/raf": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
|
||||
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/atob": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||
"license": "(MIT OR Apache-2.0)",
|
||||
"bin": {
|
||||
"atob": "bin/atob.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/btoa": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
|
||||
"license": "(MIT OR Apache-2.0)",
|
||||
"bin": {
|
||||
"btoa": "bin/btoa.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/canvg": {
|
||||
"version": "3.0.10",
|
||||
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
|
||||
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@types/raf": "^3.4.0",
|
||||
"core-js": "^3.8.3",
|
||||
"raf": "^3.4.1",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"rgbcolor": "^1.0.1",
|
||||
"stackblur-canvas": "^2.0.0",
|
||||
"svg-pathdata": "^6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/canvg/node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.39.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz",
|
||||
"integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/css-line-break": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.7.tgz",
|
||||
"integrity": "sha512-2q4bEI+coQM8f5ez7kt2xclg1XsecaV9ASJk/54vwlfRRNQfDqJz2pzQ8t0Ix/ToBpXlVjrRIx7pFC/o8itG2Q==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/fflate": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/html2canvas": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"css-line-break": "^2.1.0",
|
||||
"text-segmentation": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jspdf": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz",
|
||||
"integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2",
|
||||
"atob": "^2.1.2",
|
||||
"btoa": "^1.2.1",
|
||||
"fflate": "^0.8.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"canvg": "^3.0.6",
|
||||
"core-js": "^3.6.0",
|
||||
"dompurify": "^2.5.4",
|
||||
"html2canvas": "^1.0.0-rc.5"
|
||||
}
|
||||
},
|
||||
"node_modules/jspdf-autotable": {
|
||||
"version": "3.8.4",
|
||||
"resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.8.4.tgz",
|
||||
"integrity": "sha512-rSffGoBsJYX83iTRv8Ft7FhqfgEL2nLpGAIiqruEQQ3e4r0qdLFbPUB7N9HAle0I3XgpisvyW751VHCqKUVOgQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"jspdf": "^2.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"performance-now": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rgbcolor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
|
||||
"license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.8.15"
|
||||
}
|
||||
},
|
||||
"node_modules/stackblur-canvas": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
|
||||
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.1.14"
|
||||
}
|
||||
},
|
||||
"node_modules/svg-pathdata": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/text-segmentation": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"utrie": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/utrie": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "^1.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"jspdf": "^2.5.2",
|
||||
"jspdf-autotable": "^3.8.4"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express'
|
||||
import { deleteAllTables, deleteExerciseProgressTables, prepopulateDatabase, prepopulateExerciseDatabase } from '../scripts/databaseHelper'
|
||||
import fs from "fs"
|
||||
|
||||
export const api = Router()
|
||||
|
||||
/**
|
||||
* Status check endpoint
|
||||
*/
|
||||
api.get("/", (req: Request, res: Response, next: NextFunction) => {
|
||||
res.status(200).send()
|
||||
})
|
||||
|
||||
/**
|
||||
* Reset the whole database to factory state
|
||||
* Doesn't effect ExerciseTable and ExerciseGroupTable
|
||||
*/
|
||||
api.get("/resetdatabase", async (req: Request, res: Response, next: NextFunction) => {
|
||||
// Step 1: Delete all data tables
|
||||
deleteAllTables()
|
||||
@@ -19,6 +25,9 @@ api.get("/resetdatabase", async (req: Request, res: Response, next: NextFunction
|
||||
res.status(200).send()
|
||||
})
|
||||
|
||||
/**
|
||||
* Reset ExerciseTable and ExerciseGroupTable to factory state
|
||||
*/
|
||||
api.get("/resetExerciseProgress", async (req: Request, res: Response, next: NextFunction) => {
|
||||
deleteExerciseProgressTables()
|
||||
|
||||
@@ -26,28 +35,3 @@ api.get("/resetExerciseProgress", async (req: Request, res: Response, next: Next
|
||||
|
||||
res.status(200).send()
|
||||
})
|
||||
|
||||
/**
|
||||
* Get all uploaded file names
|
||||
*/
|
||||
api.get("/files", async (req: Request, res: Response) => {
|
||||
let dirNames = fs.readdirSync("./backend/images")
|
||||
let result = []
|
||||
|
||||
dirNames.forEach(dir => {
|
||||
let fileNames = fs.readdirSync("./backend/images/" + dir)
|
||||
|
||||
result.push({
|
||||
folder: dir,
|
||||
files: fileNames.map(file => {
|
||||
return {
|
||||
name: file,
|
||||
size: fs.statSync("./backend/images/" + dir + "/" + file).size,
|
||||
url: "http://localhost:3000/static/" + dir + "/" + file
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
res.status(200).json(result)
|
||||
})
|
||||
@@ -11,7 +11,9 @@ import { calcOverallRating, calcRatingValues } from "../scripts/calcScripts";
|
||||
|
||||
export const band = Router()
|
||||
|
||||
// Get all bands
|
||||
/**
|
||||
* Get all bands
|
||||
*/
|
||||
band.get("/", (req: Request, res: Response) => {
|
||||
let sort = req.query.sort
|
||||
let count = req.query.count
|
||||
@@ -64,7 +66,9 @@ band.get("/", (req: Request, res: Response) => {
|
||||
})
|
||||
})
|
||||
|
||||
// Get all information about one band
|
||||
/**
|
||||
* Get all information about one band
|
||||
*/
|
||||
band.get("/band/:name", (req: Request, res: Response) => {
|
||||
Band.findOne({
|
||||
where: {
|
||||
@@ -123,7 +127,9 @@ band.get("/band/:name", (req: Request, res: Response) => {
|
||||
})
|
||||
|
||||
|
||||
// Band search
|
||||
/**
|
||||
* Band search
|
||||
*/
|
||||
band.get("/search", (req: Request, res: Response) => {
|
||||
Band.findAll({
|
||||
where: {
|
||||
@@ -139,7 +145,9 @@ band.get("/search", (req: Request, res: Response) => {
|
||||
})
|
||||
|
||||
|
||||
// Edit band
|
||||
/**
|
||||
* Edit band
|
||||
*/
|
||||
band.patch("/", (req: Request, res: Response) => {
|
||||
Band.update(req.body, {
|
||||
where: {
|
||||
@@ -152,7 +160,9 @@ band.patch("/", (req: Request, res: Response) => {
|
||||
})
|
||||
|
||||
|
||||
// New band
|
||||
/**
|
||||
* New band
|
||||
*/
|
||||
band.post("/", (req: Request, res: Response) => {
|
||||
Band.create(req.body)
|
||||
.then(result => {
|
||||
@@ -160,6 +170,9 @@ band.post("/", (req: Request, res: Response) => {
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Delete a band
|
||||
*/
|
||||
band.delete("/", (req: Request, res: Response) => {
|
||||
Band.destroy({
|
||||
where: {
|
||||
|
||||
52
software/backend/routes/files.routes.ts
Normal file
52
software/backend/routes/files.routes.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express'
|
||||
import fs from "fs"
|
||||
import multer from "multer"
|
||||
const upload = multer({ dest: './backend/images/' })
|
||||
|
||||
export const files = Router()
|
||||
|
||||
/**
|
||||
* Get all folders
|
||||
*/
|
||||
files.get("/folders", async (req: Request, res: Response) => {
|
||||
let dirNames = fs.readdirSync("./backend/images")
|
||||
let result = []
|
||||
|
||||
dirNames.forEach(dir => {
|
||||
result.push({
|
||||
name: dir,
|
||||
nrOfItems: fs.readdirSync("./backend/images/" + dir).length
|
||||
})
|
||||
})
|
||||
|
||||
res.status(200).json(result)
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Get all uploaded file names by file name
|
||||
*/
|
||||
files.get("/:folder", async (req: Request, res: Response) => {
|
||||
let result = []
|
||||
let fileNames = fs.readdirSync("./backend/images/" + req.params.folder + "/")
|
||||
|
||||
fileNames.forEach(file => {
|
||||
result.push({
|
||||
name: file,
|
||||
size: fs.statSync("./backend/images/" + req.params.folder + "/" + file).size,
|
||||
url: "http://localhost:3000/static/" + req.params.folder + "/" + file
|
||||
})
|
||||
})
|
||||
|
||||
res.status(200).json(result)
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Upload a file
|
||||
*/
|
||||
files.post("/", upload.single("file"), function (req: Request, res: Response, next: NextFunction) {
|
||||
console.log(req.file)
|
||||
|
||||
res.status(200).send()
|
||||
})
|
||||
@@ -11,6 +11,7 @@ import { genre } from './routes/genre.routes'
|
||||
import { location } from './routes/location.routes'
|
||||
import { city } from './routes/city.routes'
|
||||
import { exercises } from './routes/exercise.routes'
|
||||
import { files } from './routes/files.routes'
|
||||
|
||||
const app = express()
|
||||
const port = 3000
|
||||
@@ -43,7 +44,7 @@ app.use("/accounts", account)
|
||||
app.use("/cities", city)
|
||||
app.use("/concerts", concert)
|
||||
app.use("/exercises", exercises)
|
||||
|
||||
app.use("/files", files)
|
||||
|
||||
// Start server
|
||||
const server = app.listen(port, () => {
|
||||
|
||||
3864
software/package-lock.json
generated
3864
software/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "^7.4.47",
|
||||
"@types/multer": "^1.4.12",
|
||||
"@vueuse/core": "^11.1.0",
|
||||
"axios": "^1.7.7",
|
||||
"body-parser": "^1.20.2",
|
||||
@@ -41,6 +42,7 @@
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"express": "^4.21.1",
|
||||
"moment": "^2.30.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"pinia": "^2.2.4",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"sequelize": "^6.37.4",
|
||||
|
||||
45
software/src/data/api/files.api.ts
Normal file
45
software/src/data/api/files.api.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import axios from "axios"
|
||||
|
||||
const BASE_URL = "http://localhost:3000/files"
|
||||
|
||||
/**
|
||||
* Fetch all public folders on server
|
||||
*
|
||||
* @returns Response from server
|
||||
*/
|
||||
export function fetchFolderNames() {
|
||||
return axios.get(BASE_URL + "/folders")
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all static file names
|
||||
*
|
||||
* @param dirName Name of folder where to scan files
|
||||
*
|
||||
* @returns Response from server
|
||||
*/
|
||||
export function fetchFileNames(dirName: string) {
|
||||
return axios.get(BASE_URL + "/" + dirName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a file to the server
|
||||
*
|
||||
* @param file File to store on server
|
||||
*
|
||||
* @returns Response from server
|
||||
*/
|
||||
export function postFile(file, folder: string) {
|
||||
let formData = new FormData()
|
||||
|
||||
formData.append("file", file)
|
||||
formData.append("folder", folder)
|
||||
|
||||
console.log(formData)
|
||||
|
||||
return axios.post(BASE_URL, formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data"
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -28,12 +28,3 @@ export function resetDatabase() {
|
||||
export function resetExerciseProgress() {
|
||||
return axios.get(BASE_URL + "/resetExerciseProgress")
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all static file names
|
||||
*
|
||||
* @returns Response from server
|
||||
*/
|
||||
export function fetchFileNames() {
|
||||
return axios.get(BASE_URL + "/files")
|
||||
}
|
||||
@@ -238,7 +238,10 @@
|
||||
},
|
||||
"user": "Angaben zur Person",
|
||||
"registrationNumber": "Matrikelnummer",
|
||||
"yourFullName": "Vollständiger Name"
|
||||
"yourFullName": "Vollständiger Name",
|
||||
"chooseFile": "Datei auswählen",
|
||||
"chooseDestinationFolder": "Zielordner auswählen",
|
||||
"upload": "Hochladen"
|
||||
},
|
||||
"genre": {
|
||||
"withoutBand": "ohne Band"
|
||||
|
||||
@@ -238,7 +238,10 @@
|
||||
},
|
||||
"user": "About person",
|
||||
"registrationNumber": "Matrikel number",
|
||||
"yourFullName": "Full name"
|
||||
"yourFullName": "Full name",
|
||||
"chooseFile": "Choose file",
|
||||
"chooseDestinationFolder": "Choose destination folder",
|
||||
"upload": "Upload"
|
||||
},
|
||||
"genre": {
|
||||
"withoutBand": "without Band"
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useGenreStore } from '@/stores/genre.store';
|
||||
import { usePreferencesStore } from '@/stores/preferences.store';
|
||||
import dashboardCard from './dashboardCard.vue';
|
||||
import { useOrderStore } from '@/stores/order.store';
|
||||
import { useFilesStore } from '@/stores/files.store';
|
||||
|
||||
const concertStore = useConcertStore()
|
||||
const bandStore = useBandStore()
|
||||
@@ -17,10 +18,11 @@ const locationStore = useLocationStore()
|
||||
const exerciseStore = useExerciseStore()
|
||||
const preferencesStore = usePreferencesStore()
|
||||
const orderStore = useOrderStore()
|
||||
const filesStore = useFilesStore()
|
||||
|
||||
exerciseStore.solveExercise(2, 1)
|
||||
|
||||
preferencesStore.getStaticFiles()
|
||||
filesStore.getStaticFolders()
|
||||
bandStore.getBands()
|
||||
locationStore.getLocations()
|
||||
genreStore.getGenres()
|
||||
@@ -98,10 +100,10 @@ orderStore.getAllOrders()
|
||||
<dashboard-card
|
||||
:title="$t('misc.file', 2)"
|
||||
icon="mdi-file"
|
||||
:first-line="preferencesStore.staticFiles.reduce((counter, obj) => {
|
||||
return counter += obj.files.length
|
||||
:first-line="filesStore.staticFolders.reduce((counter, obj) => {
|
||||
return counter + obj.nrOfItems
|
||||
}, 0) + ' ' + $t('misc.file', 2)"
|
||||
:second-line="preferencesStore.staticFiles.length + ' ' + $t('misc.folder', 2)"
|
||||
:second-line="filesStore.staticFolders.length + ' ' + $t('misc.folder', 2)"
|
||||
button-route="/admin/files"
|
||||
:loading="preferencesStore.fetchInProgress"
|
||||
/>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import actionDialog from '@/components/basics/actionDialog.vue';
|
||||
|
||||
const showDialog = defineModel("showDialog")
|
||||
|
||||
defineProps({
|
||||
url: String
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<action-dialog v-model="showDialog" max-width="500">
|
||||
<v-img :src="url" max-height="400" />
|
||||
</action-dialog>
|
||||
</template>
|
||||
64
software/src/pages/admin/filesAdminPage/fileUploadDialog.vue
Normal file
64
software/src/pages/admin/filesAdminPage/fileUploadDialog.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import actionDialog from '@/components/basics/actionDialog.vue';
|
||||
import outlinedButton from '@/components/basics/outlinedButton.vue';
|
||||
import { useFilesStore } from '@/stores/files.store';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const filesStore = useFilesStore()
|
||||
|
||||
const test = ref()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<action-dialog
|
||||
v-model="filesStore.showFileUploadDialog"
|
||||
:title="$t('misc.uploadFile')"
|
||||
icon="mdi-file"
|
||||
max-width="800"
|
||||
>
|
||||
<v-form :model-value="test">
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-file-input
|
||||
v-model="filesStore.fileUpload"
|
||||
clearable
|
||||
:label="$t('misc.chooseFile')"
|
||||
:disabled="filesStore.fetchInProgress"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-radio-group
|
||||
v-model="filesStore.fileUploadDir"
|
||||
:label="$t('misc.chooseDestinationFolder')"
|
||||
:disabled="filesStore.fetchInProgress"
|
||||
>
|
||||
<v-radio
|
||||
v-for="folder of filesStore.staticFolders"
|
||||
:label="folder.name + '/'"
|
||||
:value="folder.name"
|
||||
/>
|
||||
</v-radio-group>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
<v-btn type="submit">Submit</v-btn>
|
||||
</v-form>
|
||||
|
||||
<template #actions>
|
||||
<outlined-button
|
||||
@click="filesStore.uploadFile"
|
||||
prepend-icon="mdi-file-upload"
|
||||
color="green"
|
||||
:disabled="filesStore.fileUploadDir.length == 0 || filesStore.fileUpload == undefined"
|
||||
:loading="filesStore.fetchInProgress"
|
||||
>
|
||||
{{ $t('misc.upload') }}
|
||||
</outlined-button>
|
||||
</template>
|
||||
</action-dialog>
|
||||
</template>
|
||||
@@ -1,44 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import adminDataLayout from '@/layouts/adminDataLayout.vue';
|
||||
import { usePreferencesStore } from '@/stores/preferences.store';
|
||||
import filePreviewDialog from './filePreviewDialog.vue';
|
||||
import { ref } from 'vue';
|
||||
import FileUploadDialog from './fileUploadDialog.vue';
|
||||
import { useFilesStore } from '@/stores/files.store';
|
||||
|
||||
const preferencesStore = usePreferencesStore()
|
||||
const showDialog = ref(false)
|
||||
const filesStore = useFilesStore()
|
||||
const showPreviewDialog = ref(false)
|
||||
const previewFile = ref("")
|
||||
|
||||
preferencesStore.getStaticFiles()
|
||||
filesStore.getStaticFolders()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<admin-data-layout
|
||||
:add-button-string="$t('misc.uploadFile')"
|
||||
:fetch-in-progress="preferencesStore.fetchInProgress"
|
||||
:on-add-click="() => { /** todo */ }"
|
||||
:fetch-in-progress="filesStore.fetchInProgress"
|
||||
:on-add-click="() => { filesStore.showFileUploadDialog = true }"
|
||||
>
|
||||
<v-row >
|
||||
<v-col
|
||||
v-for="folder of preferencesStore.staticFiles"
|
||||
cols="12"
|
||||
md="3"
|
||||
sm="6"
|
||||
>
|
||||
<v-col cols="2" class="border">
|
||||
<v-list>
|
||||
<v-list-subheader>{{ folder.folder }}/</v-list-subheader>
|
||||
<v-list-item
|
||||
v-for="file of folder.files"
|
||||
:title="file.name"
|
||||
:subtitle="Math.round(file.size / 1024) + ' KB'"
|
||||
@click="() => { previewFile = file.url; showDialog = true }"
|
||||
v-for="folder of filesStore.staticFolders"
|
||||
:key="folder.name"
|
||||
:value="folder"
|
||||
:title="folder.name + '/'"
|
||||
@click="filesStore.selectedFolder = folder; filesStore.getStaticFiles()"
|
||||
/>
|
||||
</v-list>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="4" class="border">
|
||||
<v-skeleton-loader
|
||||
:loading="filesStore.fetchInProgress"
|
||||
type="list-item-two-line"
|
||||
>
|
||||
<v-list max-height="800" class="w-100">
|
||||
<v-list-item
|
||||
v-for="file of filesStore.staticFiles"
|
||||
:title="file.name"
|
||||
:value="file.name"
|
||||
:subtitle="Math.round(file.size / 1024) + ' KB'"
|
||||
@click="() => { filesStore.selectedFile = file }"
|
||||
/>
|
||||
</v-list>
|
||||
</v-skeleton-loader>
|
||||
</v-col>
|
||||
|
||||
<v-col class="border">
|
||||
<v-img
|
||||
v-if="filesStore.selectedFile != undefined"
|
||||
:src="filesStore.selectedFile.url" max-height="400" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</admin-data-layout>
|
||||
|
||||
<file-preview-dialog
|
||||
v-model:show-dialog="showDialog"
|
||||
v-model:show-dialog="showPreviewDialog"
|
||||
:url="previewFile"
|
||||
/>
|
||||
|
||||
<file-upload-dialog />
|
||||
</template>
|
||||
61
software/src/stores/files.store.ts
Normal file
61
software/src/stores/files.store.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { fetchFileNames, fetchFolderNames, postFile } from "@/data/api/files.api";
|
||||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
|
||||
export const useFilesStore = defineStore('filesStore', {
|
||||
state: () => ({
|
||||
/** Request to server sent, waiting for data response */
|
||||
fetchInProgress: ref(false),
|
||||
|
||||
staticFolders: ref<Array<{name: string, nrOfItems: number}>>([]),
|
||||
|
||||
selectedFolder: ref<{name: string, nrOfItems: number}>(),
|
||||
|
||||
/** List of files on the server */
|
||||
staticFiles: ref<Array<{name: string, size: number, url: string}>>([]),
|
||||
|
||||
selectedFile: ref<{name: string, size: number, url: string}>(),
|
||||
|
||||
showFileUploadDialog: ref(false),
|
||||
|
||||
fileUpload: ref(),
|
||||
|
||||
fileUploadDir: ref(""),
|
||||
}),
|
||||
|
||||
actions: {
|
||||
async getStaticFolders() {
|
||||
this.fetchInProgress = true
|
||||
|
||||
fetchFolderNames()
|
||||
.then(res => {
|
||||
this.staticFolders = res.data
|
||||
this.fetchInProgress = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Request all available static files on server
|
||||
*/
|
||||
async getStaticFiles() {
|
||||
this.fetchInProgress = true
|
||||
|
||||
fetchFileNames(this.selectedFolder.name)
|
||||
.then(res => {
|
||||
this.staticFiles = res.data
|
||||
this.fetchInProgress = false
|
||||
})
|
||||
},
|
||||
|
||||
async uploadFile() {
|
||||
this.fetchInProgress = true
|
||||
|
||||
postFile(this.uploadFile, this.fileUploadDir)
|
||||
.then(response => {
|
||||
console.log(response)
|
||||
this.showFileUploadDialog = false
|
||||
this.fetchInProgress = false
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -3,7 +3,7 @@ import { useLocalStorage } from "@vueuse/core";
|
||||
import { ThemeEnum } from "../data/enums/themeEnums";
|
||||
import { LanguageEnum } from "../data/enums/languageEnum";
|
||||
import { ref } from "vue";
|
||||
import { fetchFileNames, fetchServerState, resetDatabase, resetExerciseProgress } from "@/data/api/mainApi";
|
||||
import { fetchServerState,resetDatabase, resetExerciseProgress } from "@/data/api/mainApi";
|
||||
import { ServerStateEnum } from "@/data/enums/serverStateEnum";
|
||||
import { BannerStateEnum } from "@/data/enums/bannerStateEnum";
|
||||
import { useFeedbackStore } from "./feedback.store";
|
||||
@@ -32,9 +32,6 @@ export const usePreferencesStore = defineStore('preferencesStore', {
|
||||
/** Show the "Factory reset" confirm dialog */
|
||||
showFactoryResetDialog: ref(false),
|
||||
|
||||
/** List of files on the server */
|
||||
staticFiles: ref([]),
|
||||
|
||||
/** Marks the first run of the app */
|
||||
firstStartup: useLocalStorage<Boolean>("hackmycart/preferencesStore/firstStartup", true),
|
||||
|
||||
@@ -108,19 +105,6 @@ export const usePreferencesStore = defineStore('preferencesStore', {
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Request all available static files on server
|
||||
*/
|
||||
async getStaticFiles() {
|
||||
this.fetchInProgress = true
|
||||
|
||||
fetchFileNames()
|
||||
.then(res => {
|
||||
this.staticFiles = res.data
|
||||
this.fetchInProgress = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset all store values to factory state
|
||||
*/
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
"backend/**/*.ts",
|
||||
"backend/**/*.json",
|
||||
"backend/images/**/**/*"
|
||||
]
|
||||
, "backend/server.js" ]
|
||||
}
|
||||
Reference in New Issue
Block a user