current state
This commit is contained in:
parent
b5314cb552
commit
3b9813a680
@ -10,7 +10,8 @@
|
|||||||
"/@popperjs/core/dist/umd/popper.min.js",
|
"/@popperjs/core/dist/umd/popper.min.js",
|
||||||
"/@popperjs/core/dist/umd/popper.min.js.map",
|
"/@popperjs/core/dist/umd/popper.min.js.map",
|
||||||
"/bootstrap/dist/js/bootstrap.bundle.min.js.map",
|
"/bootstrap/dist/js/bootstrap.bundle.min.js.map",
|
||||||
"/bootstrap-icons/font/fonts/bootstrap-icons.woff"
|
"/bootstrap-icons/font/fonts/bootstrap-icons.woff",
|
||||||
|
"/tsparticles-confetti/tsparticles.confetti.bundle.min.js"
|
||||||
],
|
],
|
||||||
"debugMode": false
|
"debugMode": false
|
||||||
}
|
}
|
||||||
|
351
package-lock.json
generated
351
package-lock.json
generated
@ -21,7 +21,8 @@
|
|||||||
"jquery": "^3.6.4",
|
"jquery": "^3.6.4",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"prisma": "^4.13.0",
|
"prisma": "^4.13.0",
|
||||||
"signale": "^1.4.0"
|
"signale": "^1.4.0",
|
||||||
|
"tsparticles-confetti": "^2.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
@ -32,6 +33,7 @@
|
|||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"prisma-dbml-generator": "^0.10.0",
|
"prisma-dbml-generator": "^0.10.0",
|
||||||
"prisma-docs-generator": "^0.7.0",
|
"prisma-docs-generator": "^0.7.0",
|
||||||
|
"sass": "^1.62.1",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -958,6 +960,19 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/anymatch": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"picomatch": "^2.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/archiver": {
|
"node_modules/archiver": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz",
|
||||||
@ -1097,6 +1112,15 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/binary-extensions": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/bl": {
|
"node_modules/bl": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||||
@ -1342,6 +1366,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chokidar": {
|
||||||
|
"version": "3.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
|
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"anymatch": "~3.1.2",
|
||||||
|
"braces": "~3.0.2",
|
||||||
|
"glob-parent": "~5.1.2",
|
||||||
|
"is-binary-path": "~2.1.0",
|
||||||
|
"is-glob": "~4.0.1",
|
||||||
|
"normalize-path": "~3.0.0",
|
||||||
|
"readdirp": "~3.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.10.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ci-info": {
|
"node_modules/ci-info": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
|
||||||
@ -2304,6 +2355,20 @@
|
|||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
@ -2686,6 +2751,12 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immutable": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/import-fresh": {
|
"node_modules/import-fresh": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||||
@ -2760,6 +2831,18 @@
|
|||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||||
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/is-binary-path": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"binary-extensions": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.12.0",
|
"version": "2.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
|
||||||
@ -4633,6 +4716,18 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readdirp": {
|
||||||
|
"version": "3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
|
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"picomatch": "^2.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/redent": {
|
"node_modules/redent": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
|
||||||
@ -4787,6 +4882,23 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/sass": {
|
||||||
|
"version": "1.62.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
|
||||||
|
"integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
|
"immutable": "^4.0.0",
|
||||||
|
"source-map-js": ">=0.6.2 <2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sass": "sass.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
@ -4992,6 +5104,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/spdx-correct": {
|
"node_modules/spdx-correct": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
|
||||||
@ -5322,6 +5443,234 @@
|
|||||||
"integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==",
|
"integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tsparticles-confetti": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-confetti/-/tsparticles-confetti-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-+w35tEgfCHHuu9kDVM5tcXV9nXS0KNzJXldfDaVeMUh/SQs3Hv7d2ZaeC6CnxEVDfioTPv2EFAV0V/dwHgL+Kg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3",
|
||||||
|
"tsparticles-move-base": "^2.9.3",
|
||||||
|
"tsparticles-plugin-emitters": "^2.9.3",
|
||||||
|
"tsparticles-plugin-motion": "^2.9.3",
|
||||||
|
"tsparticles-shape-cards": "^2.9.3",
|
||||||
|
"tsparticles-shape-circle": "^2.9.3",
|
||||||
|
"tsparticles-shape-heart": "^2.9.3",
|
||||||
|
"tsparticles-shape-image": "^2.9.3",
|
||||||
|
"tsparticles-shape-polygon": "^2.9.3",
|
||||||
|
"tsparticles-shape-square": "^2.9.3",
|
||||||
|
"tsparticles-shape-star": "^2.9.3",
|
||||||
|
"tsparticles-shape-text": "^2.9.3",
|
||||||
|
"tsparticles-updater-angle": "^2.9.3",
|
||||||
|
"tsparticles-updater-color": "^2.9.3",
|
||||||
|
"tsparticles-updater-life": "^2.9.3",
|
||||||
|
"tsparticles-updater-opacity": "^2.9.3",
|
||||||
|
"tsparticles-updater-out-modes": "^2.9.3",
|
||||||
|
"tsparticles-updater-roll": "^2.9.3",
|
||||||
|
"tsparticles-updater-size": "^2.9.3",
|
||||||
|
"tsparticles-updater-tilt": "^2.9.3",
|
||||||
|
"tsparticles-updater-wobble": "^2.9.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/matteobruni"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-engine": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-engine/-/tsparticles-engine-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-iAD8LyRH//kx10fDMm6AfQV6dRHs1ZacUUHqVwfutcqM4x1IV2ygpjk0X87LKCnBxYeIMG78+tlxXpnpwUccOg==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/matteobruni"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "buymeacoffee",
|
||||||
|
"url": "https://www.buymeacoffee.com/matteobruni"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hasInstallScript": true
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-move-base": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-move-base/-/tsparticles-move-base-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-6/uO7N9HbVJokG8sjPF8YjJzkcnwELoZEkaiABX0mGxdICYCyjpjOdOfwF7UCf8Ctqh2/kxQjv4fk0Aj2Z3nag==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-plugin-emitters": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-plugin-emitters/-/tsparticles-plugin-emitters-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-G0rs7lL9xjbFGkWr+XDsDpyghTjiHq7oPAZyUe0c/3p0JETwQgZ63/egluYU1p3uWJj34KjgjHD3GZqjyfI95Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-plugin-motion": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-plugin-motion/-/tsparticles-plugin-motion-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-VUDhNO5PTCkub392FPFDEri1hTpUFJDFMUuLF537gUlpft57lgEtTetoNCyR/6q9gLl2M/jcMZgiQkFqLa1Qgg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-cards": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-cards/-/tsparticles-shape-cards-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-1agei5hqZ6xsn8UAEnCvlGZcoTTgy9Dle2sDpFBR17KxRmtJkD/XgtQrDv9xWiB6JIG5FiLpGXDGR65KgeEKyA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/matteobruni"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "buymeacoffee",
|
||||||
|
"url": "https://www.buymeacoffee.com/matteobruni"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-circle": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-circle/-/tsparticles-shape-circle-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-d+PjFELhoCzPf2G+XKIew3Ho/Ql2fHzY0TrrIKVHzHufqWdQCWrhxNri2v0POLJFkcIYqvFThxM23I/cyKPgQw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-heart": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-heart/-/tsparticles-shape-heart-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-AsRbzKYIB5rLyXU3vBS4uDthCSCwb9KMdRI2OV3sawPxtWAprYnjtTDDAhnz8ETxbw0E0lNMoDf6qYioTlRwJQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/matteobruni"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "buymeacoffee",
|
||||||
|
"url": "https://www.buymeacoffee.com/matteobruni"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-image": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-image/-/tsparticles-shape-image-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-yV3FAcqJ91EYG59OJ1SmShbogVs/uyk12u6LFTJnD2pmfdNwTeGpKMr3Cus5xJHQwJnFWufwkpOlBUxw55J/5g==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-polygon": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-polygon/-/tsparticles-shape-polygon-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-qw580qr2VQveN1Q3kllhieW4GzB3t8fjlIRKZ0QG05npCG+ewBdXbD5G/9yfjGa1fTwCbHCfLoAFojjV15MBmg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-square": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-square/-/tsparticles-shape-square-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-VjRNALTt34arsN2UAxaWa43gvdaQQbk7OluLB912u1UzLFbdCccE/sr7pjyLqYaf6F+ndnjnzVygNb/kRxX1uQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-star": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-star/-/tsparticles-shape-star-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-/nJdrHEq05dcVwLK+8i+QD3do+RNWrSvU1efVsOMzgLajH5s2mlSfyFcUSCQrmnmP7d6MpYZpbxa2KnpDSfW8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-shape-text": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-shape-text/-/tsparticles-shape-text-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-V9U8VE2am1JWabiHAhTzAg0uG8j92BnfwmgRfWjg/w4eMFF2uyyBHQDHIFzhZFDbDbqIxttXngkfivAqRdUzhw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-angle": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-angle/-/tsparticles-updater-angle-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-Z8VLOw2UUxrvV3YH44My5kmeBUcJUHTSCMRUIqFvgvxDs0Q/g2eVWkr1L+Crpw6PE5FJMdDGWRjWwxMwNdVfuQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-color": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-color/-/tsparticles-updater-color-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-eBJ7ZNsG3uCQlpfEf2FocsHLlMnd/vgWPZtOr2Iu7KA2OR3zy7u62D/oiRZkZEWtjhh5GlPrsy7njo6oToRBNQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-life": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-life/-/tsparticles-updater-life-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-VUeWBCLKoLd69+C9CFHjVG0SaqCbMgQqag6NIGMqTmaaZNFcn1H8rheIG9NU70UOTsYRMPfwmZK1SKnqAK6jQQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-opacity": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-opacity/-/tsparticles-updater-opacity-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-ON5t2qeegnm+MsmaF6ZvhUmKLzk/zXozsw9Dsgw8iJYX8WmQmp2VC72COTzADW495ovwGjBiR1KFelM/GVfHgg==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-out-modes": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-out-modes/-/tsparticles-updater-out-modes-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-LEcAIeK8b3ovLGuuTob1L3o57XodqRuvDjtUT2TiNIC6cf3QMAnqujwAyvBLJrYAuwr7rG1fXEEt9tovFYg+tw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-roll": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-roll/-/tsparticles-updater-roll-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-I/9vB1wA3RKwfeRPlw7nrxUW8uxcajwba+gxFEcIDx2C+OA2UVIuGzOQE59O2sppqLqwrcLOm3ayTt5se1qbpw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-size": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-size/-/tsparticles-updater-size-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-6qQ8T+7wt/B4BD5K1LWEXrfan+h2utSY1zNhE1cTcAQUDrrU06g/tfMkbrpMdduu6RWwGtoC4OsciCnBuiLEYQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-tilt": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-tilt/-/tsparticles-updater-tilt-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-x1EDyvBfqgBh1021lohf2shn+V6U9WhMasGD+fKugwRxNZ0nAe5DK0wop/26L2MUIb+AbIg2sXPdxuv1zE7G7w==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tsparticles-updater-wobble": {
|
||||||
|
"version": "2.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsparticles-updater-wobble/-/tsparticles-updater-wobble-2.9.3.tgz",
|
||||||
|
"integrity": "sha512-/Doid0P/OjaO9cUzD/Z3j0GNA+8X3DUvVsOo/5mPt914PJBbcWYGpweE8u75ZPcHe9OM5u6CHFMf3PMurCEBCw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tsparticles-engine": "^2.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc && sass src/sass/dashboard-mod.scss static/css/dashboard-mod.css",
|
||||||
"prestart": "npm run build",
|
"prestart": "npm run build",
|
||||||
"start": "node .",
|
"start": "node .",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
@ -29,7 +29,8 @@
|
|||||||
"jquery": "^3.6.4",
|
"jquery": "^3.6.4",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"prisma": "^4.13.0",
|
"prisma": "^4.13.0",
|
||||||
"signale": "^1.4.0"
|
"signale": "^1.4.0",
|
||||||
|
"tsparticles-confetti": "^2.9.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
@ -40,6 +41,7 @@
|
|||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"prisma-dbml-generator": "^0.10.0",
|
"prisma-dbml-generator": "^0.10.0",
|
||||||
"prisma-docs-generator": "^0.7.0",
|
"prisma-docs-generator": "^0.7.0",
|
||||||
|
"sass": "^1.62.1",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.0.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-light" role="alert">A new version is available. <a href="#" class="alert-link">Click here to update</a></div>
|
|
||||||
|
|
||||||
<!-- TODO: Center table content -->
|
<!-- TODO: Center table content -->
|
||||||
<h2>Recent items</h2>
|
<h2>Recent items</h2>
|
||||||
|
8
src/frontend/errors/400.eta.html
Normal file
8
src/frontend/errors/400.eta.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<%~ E.includeFile("../partials/head.eta.html", {"title": "Error 400"}) %> <%~ E.includeFile("../partials/controls.eta.html", {"active": "error_400"}) %>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<i class="bi bi-bug-fill " style="font-size: 5rem"></i>
|
||||||
|
<p class="mt-2 mb-0 fs-4">Bad Request!</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%~ E.includeFile("../partials/controlsFoot.eta.html") %> <%~ E.includeFile("../partials/foot.eta.html") %>
|
@ -1,5 +1,23 @@
|
|||||||
<%~ E.includeFile("../partials/head.eta.html", {"title": "Settings - Category"}) %> <%~ E.includeFile("../partials/controls.eta.html", {"active": "SETT_CAT"}) %>
|
<%~ E.includeFile("../partials/head.eta.html", {"title": "Settings - Category"}) %> <%~ E.includeFile("../partials/controls.eta.html", {"active": "SETT_CAT"}) %>
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="staticBackdropLabel">Do you really want to delete <strong id="deleteNamePlaceholder">Placeholder</strong>?</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">This will permanently delete the category and all its associated data.<br />Items will be kept but will be unassigned from this category.</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancle</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="deleteActionBtn"><i class="bi bi-trash"></i> Yes, delete.</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1>Categories</h1>
|
<h1>Categories</h1>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- Create new category button -->
|
<!-- Create new category button -->
|
||||||
@ -17,8 +35,8 @@
|
|||||||
<h1 class="modal-title fs-5" id="createNewCategoryModalLabel">Create a new category</h1>
|
<h1 class="modal-title fs-5" id="createNewCategoryModalLabel">Create a new category</h1>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<form class="frontendForm" method="post" data-target="/api/v1/categories">
|
||||||
<form method="post">
|
<div class="modal-body">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="createNewCategoryModalName" class="form-label">Name</label>
|
<label for="createNewCategoryModalName" class="form-label">Name</label>
|
||||||
<input type="text" class="form-control" id="createNewCategoryModalName" name="name" required />
|
<input type="text" class="form-control" id="createNewCategoryModalName" name="name" required />
|
||||||
@ -29,13 +47,20 @@
|
|||||||
<input type="text" class="form-control" id="createNewCategoryModalDescription" name="description" />
|
<input type="text" class="form-control" id="createNewCategoryModalDescription" name="description" />
|
||||||
<div id="createNewCategoryModalDescText" class="form-text">Optional</div>
|
<div id="createNewCategoryModalDescText" class="form-text">Optional</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
<div class="modal-footer">
|
||||||
<div class="modal-footer">
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
<button type="submit" class="btn btn-primary">Save changes</button>
|
||||||
<button type="submit" class="btn btn-primary">Save changes</button>
|
</div>
|
||||||
</div>
|
<!-- loader overlay -->
|
||||||
</form>
|
<div class="loader-overlay">
|
||||||
|
<div class="loader">
|
||||||
|
<div class="spinner-border text-primary" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -47,8 +72,8 @@
|
|||||||
<h1 class="modal-title fs-5" id="editCategoryModalLabel">Edit a category</h1>
|
<h1 class="modal-title fs-5" id="editCategoryModalLabel">Edit a category</h1>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<form class="frontendForm" method="patch" data-target="/api/v1/categories">
|
||||||
<form method="post">
|
<div class="modal-body">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="editCategoryModalName" class="form-label">Name</label>
|
<label for="editCategoryModalName" class="form-label">Name</label>
|
||||||
<input type="text" class="form-control" id="editCategoryModalName" name="name" required />
|
<input type="text" class="form-control" id="editCategoryModalName" name="name" required />
|
||||||
@ -59,25 +84,22 @@
|
|||||||
<input type="text" class="form-control" id="editCategoryModalDescription" name="description" />
|
<input type="text" class="form-control" id="editCategoryModalDescription" name="description" />
|
||||||
<div id="editCategoryModalDescText" class="form-text">Optional</div>
|
<div id="editCategoryModalDescText" class="form-text">Optional</div>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" id="editCategoryModalIsEdit" name="editCategoryModalIsEdit" hidden value="isEdit"/>
|
<input type="text" id="editCategoryModalId" name="id" hidden />
|
||||||
<input type="text" id="editCategoryModalId" name="editCategoryModalId" hidden/>
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
</div>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
<div class="modal-footer">
|
<button type="submit" class="btn btn-primary">Save changes</button>
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Save changes</button>
|
</form>
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Table with all categories -->
|
<!-- Table with all categories -->
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<!-- <th scope="col">#</th> -->
|
||||||
<th scope="col">Name</th>
|
<th scope="col">Name</th>
|
||||||
<th scope="col">Description</th>
|
<th scope="col">Description</th>
|
||||||
<th scope="col">Action</th>
|
<th scope="col">Action</th>
|
||||||
@ -86,10 +108,12 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<% it.items.forEach(function(user){ %>
|
<% it.items.forEach(function(user){ %>
|
||||||
<tr id="listEntry-<%= user.id %>">
|
<tr id="listEntry-<%= user.id %>">
|
||||||
<th scope="row"><%= user.id %></th>
|
<td scope="row" data-bs-toggle="tooltip" data-bs-placement="left" data-bs-title="ID: <%= user.id %>"><%= user.name %></td>
|
||||||
<td><%= user.name %></td>
|
|
||||||
<td><%= user.description %></td>
|
<td><%= user.description %></td>
|
||||||
<td><button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#editCategoryModal" onclick="selectDataForEdit('<%= user.id %>')"><i class="bi bi-pencil"></i></button></td>
|
<td>
|
||||||
|
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#editCategoryModal" onclick="getDataForEdit('<%= user.name %>')"><i class="bi bi-pencil"></i></button>
|
||||||
|
<button class="btn btn-danger" onclick="preFillDeleteModal('<%= user.name %>')" data-bs-toggle="modal" data-bs-target="#staticBackdrop"><i class="bi bi-trash"></i></button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% }) %>
|
<% }) %>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
45
src/frontend/manage/imports/jsonImport.eta.html
Normal file
45
src/frontend/manage/imports/jsonImport.eta.html
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<%~ E.includeFile("../../partials/head.eta.html", {"title": "Importer - JSON" }) %> <%~ E.includeFile("../../partials/controls.eta.html", {"active": "SETT_IMPORT_JSON" }) %>
|
||||||
|
|
||||||
|
<h1>JSON Import</h1>
|
||||||
|
Upload a JSON file to import into the database. The JSON file must have the following columns:
|
||||||
|
<ul>
|
||||||
|
<li>name</li>
|
||||||
|
<li>amount</li>
|
||||||
|
<li>manufacturer</li>
|
||||||
|
<li>category</li>
|
||||||
|
</ul>
|
||||||
|
The following columns are optional:
|
||||||
|
<ul>
|
||||||
|
<li>sku</li>
|
||||||
|
<li>comment</li>
|
||||||
|
<li>StorageLocation (import currently not supported)</li>
|
||||||
|
</ul>
|
||||||
|
It should be formated as a list of objects, like this:
|
||||||
|
<pre>
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Item 1",
|
||||||
|
"amount": 1,
|
||||||
|
"manufacturer": "Manufacturer 1",
|
||||||
|
"category": "Category 1",
|
||||||
|
"sku": "SKU 1",
|
||||||
|
"comment": "Comment 1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Item 2",
|
||||||
|
"amount": 2,
|
||||||
|
"manufacturer": "Manufacturer 2",
|
||||||
|
"category": "Category 2",
|
||||||
|
"sku": "SKU 2",
|
||||||
|
"comment": "Comment 2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</pre>
|
||||||
|
<form method="post" enctype="multipart/form-data">
|
||||||
|
<label for="formFile" class="form-label">JSON Inventory File Upload</label>
|
||||||
|
<input class="form-control" type="file" id="formFile" name="formFile" /><br />
|
||||||
|
|
||||||
|
<input type="submit" value="Run import" class="btn btn-primary" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<%~ E.includeFile("../../partials/controlsFoot.eta.html") %> <%~ E.includeFile("../../partials/foot.eta.html") %>
|
@ -1,7 +1,7 @@
|
|||||||
<%~ E.includeFile("../partials/head.eta.html", {"title": "Settings"}) %> <%~ E.includeFile("../partials/controls.eta.html", {"active": "SETT"}) %>
|
<%~ E.includeFile("../partials/head.eta.html", {"title": "Settings"}) %> <%~ E.includeFile("../partials/controls.eta.html", {"active": "SETT"}) %>
|
||||||
|
|
||||||
<h1>Manage your AssetFlow instance</h1>
|
<h1>Manage your AssetFlow instance</h1>
|
||||||
|
<div class="alert alert-success" role="alert">A new version is available. <a href="#" class="alert-link">Click here to update</a></div>
|
||||||
<div class="container text-center">
|
<div class="container text-center">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<a class="card col m-2" href="/manage/categories">
|
<a class="card col m-2" href="/manage/categories">
|
||||||
@ -15,12 +15,19 @@
|
|||||||
<h1 class="card-title"><i class="bi bi-box-seam"></i></h1>
|
<h1 class="card-title"><i class="bi bi-box-seam"></i></h1>
|
||||||
<p class="card-text">Manage storages</p>
|
<p class="card-text">Manage storages</p>
|
||||||
</div>
|
</div>
|
||||||
</a><a class="card col m-2" href="/manage/import/csv">
|
</a>
|
||||||
|
<a class="card col m-2" href="/manage/import/csv">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h1 class="card-title"><i class="bi bi-filetype-csv"></i></h1>
|
<h1 class="card-title"><i class="bi bi-filetype-csv"></i></h1>
|
||||||
<p class="card-text">Import data via CSV</p>
|
<p class="card-text">Import data via CSV</p>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="card col m-2" href="/manage/import/json">
|
||||||
|
<div class="card-body">
|
||||||
|
<h1 class="card-title"><i class="bi bi-filetype-json"></i></h1>
|
||||||
|
<p class="card-text">Import data via JSON</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,5 +1,19 @@
|
|||||||
<header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
|
<header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
|
||||||
<a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 test-white-50" href="https://shattereddisk.github.io/rickroll/rickroll.mp4">AssetFlow</a>
|
<a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 test-white-50" onclick="doTheConfetti()">AssetFlow</a>
|
||||||
|
<script>
|
||||||
|
function randomInRange(min, max) {
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doTheConfetti() {
|
||||||
|
confetti({
|
||||||
|
angle: randomInRange(40, 150),
|
||||||
|
spread: randomInRange(50, 100),
|
||||||
|
particleCount: randomInRange(50, 150),
|
||||||
|
origin: { y: 0.6 }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<button
|
<button
|
||||||
class="navbar-toggler position-absolute d-md-none collapsed"
|
class="navbar-toggler position-absolute d-md-none collapsed"
|
||||||
type="button"
|
type="button"
|
||||||
@ -20,6 +34,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||||
|
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" id="generalToast" style="z-index: 2000">
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="toast-body">Hello, world! This is a toast message.</div>
|
||||||
|
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||||
<div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
<div id="liveToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
@ -33,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
let texti = 0;
|
let texti = 0;
|
||||||
alltexts = ['Nope, still useless', 'Stop pressing me!', 'There are NO USERS!', 'Please stop.', 'PLEASE!'];
|
alltexts = ['Nope, still useless', 'Stop pressing me!', 'There are NO USERS!', 'Please stop.', 'PLEASE!', 'Do you want an achivment or what?', 'This is not a game, please stop.', 'This is not the stanley parable.'];
|
||||||
const toastLiveExample = document.getElementById('liveToast');
|
const toastLiveExample = document.getElementById('liveToast');
|
||||||
const logoutButton = document.getElementById('logoutButton');
|
const logoutButton = document.getElementById('logoutButton');
|
||||||
logoutButton.addEventListener('click', () => {
|
logoutButton.addEventListener('click', () => {
|
||||||
@ -58,7 +80,7 @@
|
|||||||
<div class="position-sticky pt-3">
|
<div class="position-sticky pt-3">
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link <%= it.active == 'Dashboard' ? 'active' : ''%>" aria-current="page" href="/"> <i class="bi bi-house"></i> Dashboard </a>
|
<a class="nav-link <%= it.active == 'Dashboard' ? 'active' : ''%>" aria-current="page" href="/"> <i class="bi bi-house"></i> <strong>Dashboard</strong> </a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link <%= it.active == 'Items' ? 'active' : ''%>" href="/items"> <i class="bi bi-list-ul"></i> Items </a>
|
<a class="nav-link <%= it.active == 'Items' ? 'active' : ''%>" href="/items"> <i class="bi bi-list-ul"></i> Items </a>
|
||||||
@ -78,7 +100,13 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||||
<a href="/manage/" class="nav-link">Settings</a>
|
<a href="/manage/" class="nav-link"
|
||||||
|
>Settings
|
||||||
|
<span class="badge rounded-pill bg-danger invisible">
|
||||||
|
2
|
||||||
|
<span class="visually-hidden">changes or updates</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</h6>
|
</h6>
|
||||||
|
|
||||||
<ul class="nav flex-column mb-2">
|
<ul class="nav flex-column mb-2">
|
||||||
@ -92,9 +120,7 @@
|
|||||||
data-bs-target="#collapseSettingsStorages"
|
data-bs-target="#collapseSettingsStorages"
|
||||||
aria-expanded="<%= it.active == 'SETT_STORE' ? 'true' : 'false'%>"
|
aria-expanded="<%= it.active == 'SETT_STORE' ? 'true' : 'false'%>"
|
||||||
aria-controls="collapseSettingsStorages">
|
aria-controls="collapseSettingsStorages">
|
||||||
<span class="dropdownIndicator" data-ref-target="#collapseSettingsStorages">
|
<i class="bi bi-caret-left-fill magicalTriangle"></i>
|
||||||
<i class="bi bi-caret-left-fill" ></i>
|
|
||||||
</span>
|
|
||||||
<!-- TODO: This little triangle does not care if it is collapsed or not. But it should so -->
|
<!-- TODO: This little triangle does not care if it is collapsed or not. But it should so -->
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
@ -118,7 +144,7 @@
|
|||||||
aria-expanded="<%= it.active.includes('SETT_IMPORT') ? 'true' : 'false'%>"
|
aria-expanded="<%= it.active.includes('SETT_IMPORT') ? 'true' : 'false'%>"
|
||||||
aria-controls="collapseSettingsImport">
|
aria-controls="collapseSettingsImport">
|
||||||
<i class="bi bi-box-seam"></i> Import
|
<i class="bi bi-box-seam"></i> Import
|
||||||
<i class="bi bi-caret-left-fill dropdownIndicator" data-ref-target="#collapseSettingsImport"></i>
|
<i class="bi bi-caret-left-fill dropdownIndicator magicalTriangle" data-ref-target="#collapseSettingsImport"></i>
|
||||||
<!-- TODO: This little triangle does not care if it is collapsed or not. But it should so -->
|
<!-- TODO: This little triangle does not care if it is collapsed or not. But it should so -->
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="/js/searchBox.js"></script>
|
<script src="/js/searchBox.js"></script>
|
||||||
<script src="/js/handleSidebarTriangles.js"></script>
|
<script src="/js/handleSidebarTriangles.js"></script>
|
||||||
|
<script src="/js/formHandler.js"></script>
|
@ -1,4 +1,3 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script>
|
|
||||||
<script>
|
<script>
|
||||||
// Enable all bootstrap tooltips.
|
// Enable all bootstrap tooltips.
|
||||||
// https://getbootstrap.com/docs/5.3/components/tooltips/#enable-tooltips
|
// https://getbootstrap.com/docs/5.3/components/tooltips/#enable-tooltips
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
<link href="/css/dashboard.css" rel="stylesheet" />
|
<link href="/css/dashboard.css" rel="stylesheet" />
|
||||||
<script src="/static/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="/static/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/static/@popperjs/core/dist/umd/popper.min.js"></script>
|
<script src="/static/@popperjs/core/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="/static/tsparticles-confetti/tsparticles.confetti.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Listen for changes in the prefers-color-scheme media query and update the "data-bs-theme" attribute on the <html> element.
|
// Listen for changes in the prefers-color-scheme media query and update the "data-bs-theme" attribute on the <html> element.
|
||||||
|
|
||||||
|
109
src/routes/api/v1/categories.ts
Normal file
109
src/routes/api/v1/categories.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { Request, Response } from 'express';
|
||||||
|
import { prisma, __path, log } from '../../../index.js';
|
||||||
|
|
||||||
|
// Get category.
|
||||||
|
function get(req: Request, res: Response) {
|
||||||
|
// Check if required fields are present.
|
||||||
|
if (!req.query.name) {
|
||||||
|
res.status(400).render(__path + '/src/frontend/errors/400.eta.html');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prisma.itemCategory
|
||||||
|
.findUnique({
|
||||||
|
where: {
|
||||||
|
name: req.query.name.toString()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((item) => {
|
||||||
|
if (item) {
|
||||||
|
res.status(200).json(JSON.stringify(item));
|
||||||
|
} else {
|
||||||
|
res.status(410).json({error: 'Item does not exist'});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).render(__path + '/src/frontend/errors/dbError.eta.html', { error: err });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create category.
|
||||||
|
function post(req: Request, res: Response) {
|
||||||
|
// Check if required fields are present.
|
||||||
|
if (!req.body.name) {
|
||||||
|
res.status(400).render(__path + '/src/frontend/errors/400.eta.html');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save data.
|
||||||
|
prisma.itemCategory
|
||||||
|
.create({
|
||||||
|
data: {
|
||||||
|
name: req.body.name,
|
||||||
|
description: req.body.description
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
res.status(201).json({ status: 'created' });
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
// TODO Catch if is a duplicate error and show a message to the user
|
||||||
|
log.db.error(err);
|
||||||
|
res.status(500).render(__path + '/src/frontend/errors/dbError.eta.html', { error: err });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update category.
|
||||||
|
function patch(req: Request, res: Response) {
|
||||||
|
// Check if required fields are present.
|
||||||
|
if (!req.body.id || !req.body.name) {
|
||||||
|
res.status(400).render(__path + '/src/frontend/errors/400.eta.html');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prisma.itemCategory
|
||||||
|
.update({
|
||||||
|
where: {
|
||||||
|
id: parseInt(req.body.id)
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
name: req.body.name,
|
||||||
|
description: req.body.description
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
res.status(201).json({ status: 'updated' });
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
// TODO Catch if is a duplicate error and show a message to the user
|
||||||
|
log.db.error(err);
|
||||||
|
res.status(500).render(__path + '/src/frontend/errors/dbError.eta.html', { error: err });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete category.
|
||||||
|
function del(req: Request, res: Response) {
|
||||||
|
// Check if required fields are present.
|
||||||
|
if (!req.body.id) {
|
||||||
|
res.status(400).render(__path + '/src/frontend/errors/400.eta.html');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prisma.itemCategory
|
||||||
|
.delete({
|
||||||
|
where: {
|
||||||
|
id: parseInt(req.body.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
res.status(201).json({ status: 'deleted' });
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
// TODO Catch if is a duplicate error and show a message to the user
|
||||||
|
log.db.error(err);
|
||||||
|
res.status(500).render(__path + '/src/frontend/errors/dbError.eta.html', { error: err });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { get, post, patch, del };
|
@ -2,11 +2,12 @@ import express from 'express';
|
|||||||
|
|
||||||
// Route imports
|
// Route imports
|
||||||
import testRoute from './test.js';
|
import testRoute from './test.js';
|
||||||
|
import categoryRoute from './categories.js';
|
||||||
|
|
||||||
// Router base is '/api/v1'
|
// Router base is '/api/v1'
|
||||||
const Router = express.Router({ strict: false });
|
const Router = express.Router({ strict: false });
|
||||||
|
|
||||||
|
Router.route('/categories').get(categoryRoute.get).post(categoryRoute.post).patch(categoryRoute.patch).delete(categoryRoute.del);
|
||||||
Router.route('/test').get(testRoute.get);
|
Router.route('/test').get(testRoute.get);
|
||||||
|
|
||||||
|
|
||||||
export default Router;
|
export default Router;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import express, { Request, Response } from 'express';
|
import { Request, Response } from 'express';
|
||||||
import { prisma, __path, log } from '../../../index.js';
|
import { prisma, __path, log } from '../../../index.js';
|
||||||
|
|
||||||
function get(req: Request, res: Response) {
|
function get(req: Request, res: Response) {
|
||||||
@ -15,53 +15,4 @@ function get(req: Request, res: Response) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function post(req: Request, res: Response) {
|
export default { get };
|
||||||
console.log(req.body);
|
|
||||||
// Check if required fields are filled in
|
|
||||||
if (!req.body.name) {
|
|
||||||
res.status(400).render(__path + '/src/frontend/errors/400.eta.html');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.body.editCategoryModalIsEdit) {
|
|
||||||
console.log('is not edit');
|
|
||||||
// Save data to category table
|
|
||||||
prisma.itemCategory
|
|
||||||
.create({
|
|
||||||
data: {
|
|
||||||
name: req.body.name,
|
|
||||||
description: req.body.description
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
res.redirect('categories');
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
// TODO Catch if is a duplicate error and show a message to the user
|
|
||||||
log.db.error(err);
|
|
||||||
res.status(500).render(__path + '/src/frontend/errors/dbError.eta.html', { error: err });
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Save data to category table
|
|
||||||
prisma.itemCategory
|
|
||||||
.update({
|
|
||||||
where: {
|
|
||||||
id: parseInt(req.body.editCategoryModalId)
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
name: req.body.name,
|
|
||||||
description: req.body.description
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
res.redirect('categories');
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
// TODO Catch if is a duplicate error and show a message to the user
|
|
||||||
log.db.error(err);
|
|
||||||
res.status(500).render(__path + '/src/frontend/errors/dbError.eta.html', { error: err });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default { get, post };
|
|
||||||
|
102
src/routes/frontend/manage/import/jsonImport.ts
Normal file
102
src/routes/frontend/manage/import/jsonImport.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import express, { Request, Response } from 'express';
|
||||||
|
import { prisma, __path, log } from '../../../../index.js';
|
||||||
|
import { UploadedFile } from 'express-fileupload';
|
||||||
|
import { itemStatus, itemCategory, PrismaPromise } from '@prisma/client';
|
||||||
|
|
||||||
|
function post(req: Request, res: Response) {
|
||||||
|
// Handle file upload and import
|
||||||
|
console.log(req.files);
|
||||||
|
if (!req.files || Object.keys(req.files).length === 0) {
|
||||||
|
return res.status(400).send('No files were uploaded.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const file: UploadedFile = req.files.formFile as UploadedFile;
|
||||||
|
const jsonRaw = file.data.toString();
|
||||||
|
const json = JSON.parse(jsonRaw);
|
||||||
|
// Get all unqiue categories
|
||||||
|
const categories = new Set<string>();
|
||||||
|
json.forEach((item: any) => {
|
||||||
|
categories.add(item.category);
|
||||||
|
});
|
||||||
|
log.db.debug(categories);
|
||||||
|
|
||||||
|
prisma.itemCategory
|
||||||
|
.findMany({
|
||||||
|
where: {
|
||||||
|
name: {
|
||||||
|
in: Array.from(categories)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((values) => {
|
||||||
|
values.forEach((value) => {
|
||||||
|
categories.delete(value.name);
|
||||||
|
});
|
||||||
|
log.db.debug(categories);
|
||||||
|
const categoryPromises: PrismaPromise<itemCategory>[] = [];
|
||||||
|
categories.forEach((category: string) => {
|
||||||
|
const promise = prisma.itemCategory.create({
|
||||||
|
data: {
|
||||||
|
name: category,
|
||||||
|
description: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
categoryPromises.push(promise);
|
||||||
|
});
|
||||||
|
Promise.all(categoryPromises)
|
||||||
|
.then((values) => {
|
||||||
|
// Create items
|
||||||
|
const listOfPromises = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < json.length; i++) {
|
||||||
|
const record = json[i];
|
||||||
|
const promise = prisma.item.create({
|
||||||
|
data: {
|
||||||
|
name: record.name,
|
||||||
|
amount: parseInt(record.amount),
|
||||||
|
comment: record.comment,
|
||||||
|
category: {
|
||||||
|
connect: {
|
||||||
|
name: record.category,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SKU: record.sku,
|
||||||
|
manufacturer: record.manufacturer,
|
||||||
|
status: itemStatus.normal,
|
||||||
|
importedBy: 'CSV_IMPORT'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
listOfPromises.push(promise);
|
||||||
|
}
|
||||||
|
Promise.all(listOfPromises)
|
||||||
|
.then((values) => {
|
||||||
|
console.log(values);
|
||||||
|
res.send('ok');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
res.send('failed to create items');
|
||||||
|
log.db.error(err);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
// res.send('failed to create categories');
|
||||||
|
log.db.error(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
res.send('failed to find categories');
|
||||||
|
log.db.error(err);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
// res.status(501).end("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(req: Request, res: Response) {
|
||||||
|
// Render page
|
||||||
|
res.render(__path + '/src/frontend/manage/imports/jsonImport.eta.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { get, post };
|
@ -3,6 +3,7 @@ import express from 'express';
|
|||||||
// Route imports
|
// Route imports
|
||||||
import testRoute from './test.js';
|
import testRoute from './test.js';
|
||||||
import csvImportRoute from './import/csvImport.js';
|
import csvImportRoute from './import/csvImport.js';
|
||||||
|
import jsonImportRoute from './import/jsonImport.js';
|
||||||
import categoryManager from './categoryManager.js';
|
import categoryManager from './categoryManager.js';
|
||||||
import storageManager from './storageManager.js';
|
import storageManager from './storageManager.js';
|
||||||
import startpageRoute from './startpage.js';
|
import startpageRoute from './startpage.js';
|
||||||
@ -11,9 +12,10 @@ import startpageRoute from './startpage.js';
|
|||||||
const Router = express.Router({ strict: false });
|
const Router = express.Router({ strict: false });
|
||||||
|
|
||||||
Router.route('/test').get(testRoute.get);
|
Router.route('/test').get(testRoute.get);
|
||||||
Router.route('/categories').get(categoryManager.get).post(categoryManager.post);
|
Router.route('/categories').get(categoryManager.get);
|
||||||
Router.route('/storages').get(storageManager.get);
|
Router.route('/storages').get(storageManager.get);
|
||||||
Router.route('/import/csv').get(csvImportRoute.get).post(csvImportRoute.post);
|
Router.route('/import/csv').get(csvImportRoute.get).post(csvImportRoute.post);
|
||||||
|
Router.route('/import/json').get(jsonImportRoute.get).post(jsonImportRoute.post);
|
||||||
Router.route('/').get(startpageRoute.get);
|
Router.route('/').get(startpageRoute.get);
|
||||||
|
|
||||||
export default Router;
|
export default Router;
|
||||||
|
5
src/sass/dashboard-mod.scss
Normal file
5
src/sass/dashboard-mod.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.magicalTriangle[aria-expanded=true] {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
|
||||||
|
}
|
6
static/css/dashboard-mod.css
Normal file
6
static/css/dashboard-mod.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.magicalTriangle[aria-expanded=true] {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*# sourceMappingURL=dashboard-mod.css.map */
|
1
static/css/dashboard-mod.css.map
Normal file
1
static/css/dashboard-mod.css.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"sourceRoot":"","sources":["../../src/sass/dashboard-mod.scss"],"names":[],"mappings":"AAAA;EACC;EACA","file":"dashboard-mod.css"}
|
@ -105,3 +105,31 @@ body {
|
|||||||
color: red;
|
color: red;
|
||||||
transition: 1s;
|
transition: 1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
.loader-overlay {
|
||||||
|
border-radius: var(--bs-modal-inner-border-radius);
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.678);
|
||||||
|
z-index: 9999;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaderActive {
|
||||||
|
display: block !important;
|
||||||
|
}
|
@ -1,12 +1,116 @@
|
|||||||
function selectDataForEdit(id) {
|
function getDataForEdit(name) {
|
||||||
const titleForm = document.getElementById('editCategoryModalName');
|
$.ajax({
|
||||||
const descriptionForm = document.getElementById('editCategoryModalDescription');
|
type: 'get',
|
||||||
const idForm = document.getElementById('editCategoryModalId');
|
url: `/api/v1/categories?name=${name}`,
|
||||||
const trData = document.getElementById('listEntry-' + id);
|
success: function (data) {
|
||||||
const title = trData.children[1].innerText;
|
const result = JSON.parse(data);
|
||||||
const description = trData.children[2].innerText;
|
|
||||||
const idData = trData.children[0].innerText;
|
// Get elements inside the editCategoryModal
|
||||||
titleForm.value = title;
|
const modal_categoryName = document.getElementById('editCategoryModalName');
|
||||||
descriptionForm.value = description;
|
const modal_categoryDescription = document.getElementById('editCategoryModalDescription');
|
||||||
idForm.value = idData;
|
const modal_categoryid = document.getElementById('editCategoryModalId');
|
||||||
}
|
|
||||||
|
modal_categoryName.value = result.name;
|
||||||
|
modal_categoryDescription.value = result.description;
|
||||||
|
modal_categoryid.value = result.id;
|
||||||
|
},
|
||||||
|
error: function (data) {
|
||||||
|
console.log('!!!! ERROR !!!!', data);
|
||||||
|
// Hide overlay with spinner
|
||||||
|
$('.loader-overlay').removeClass('active');
|
||||||
|
// Close the modal
|
||||||
|
$('.modal').modal('hide');
|
||||||
|
$('#generalToast').removeClass('text-bg-primary');
|
||||||
|
$('#generalToast').addClass('text-bg-danger');
|
||||||
|
$('#generalToast').toast('show');
|
||||||
|
$('#generalToast').children('.d-flex').children('.toast-body').html('<i class="bi bi-exclamation-triangle-fill"></i> Something went wrong. The category does no longer exist.');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteEntry(id) {
|
||||||
|
$.ajax({
|
||||||
|
type: 'delete',
|
||||||
|
url: `/api/v1/categories`,
|
||||||
|
data: { id: id },
|
||||||
|
success: function (data) {
|
||||||
|
$('#staticBackdrop').modal('hide');
|
||||||
|
$('#generalToast').removeClass('text-bg-primary');
|
||||||
|
$('#generalToast').addClass('text-bg-success');
|
||||||
|
$('#generalToast').toast('show');
|
||||||
|
$('#generalToast').children('.d-flex').children('.toast-body').html('<i class="bi bi-check2"></i> Category deleted successfully.');
|
||||||
|
confetti({
|
||||||
|
spread: 360,
|
||||||
|
ticks: 100,
|
||||||
|
gravity: 0.1,
|
||||||
|
decay: 0.94,
|
||||||
|
startVelocity: 30,
|
||||||
|
particleCount: 20,
|
||||||
|
scalar: 2,
|
||||||
|
shapes: ['text'],
|
||||||
|
shapeOptions: {
|
||||||
|
text: {
|
||||||
|
value: ['❌', '🗑️', '🚫']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
$('#generalToast').toast('hide');
|
||||||
|
$('#generalToast').removeClass('text-bg-success');
|
||||||
|
$('#generalToast').addClass('text-bg-primary');
|
||||||
|
window.location.reload();
|
||||||
|
}, 2000);
|
||||||
|
},
|
||||||
|
error: function (data) {
|
||||||
|
// hide the staticBackdrop modal
|
||||||
|
$('#staticBackdrop').modal('hide');
|
||||||
|
$('#generalToast').removeClass('text-bg-primary');
|
||||||
|
$('#generalToast').addClass('text-bg-danger');
|
||||||
|
$('#generalToast').toast('show');
|
||||||
|
$('#generalToast').children('.d-flex').children('.toast-body').html('<i class="bi bi-exclamation-triangle-fill"></i> Something went wrong. Please try again later.');
|
||||||
|
setTimeout(() => {
|
||||||
|
$('#generalToast').toast('hide');
|
||||||
|
$('#generalToast').removeClass('text-bg-danger');
|
||||||
|
$('#generalToast').addClass('text-bg-primary');
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function preFillDeleteModal(name) {
|
||||||
|
$.ajax({
|
||||||
|
type: 'get',
|
||||||
|
url: `/api/v1/categories?name=${name}`,
|
||||||
|
success: function (data) {
|
||||||
|
const result = JSON.parse(data);
|
||||||
|
|
||||||
|
// Get elements inside the editCategoryModal
|
||||||
|
const modal_categoryName = document.getElementById('deleteNamePlaceholder');
|
||||||
|
const modal_deleteButton = document.getElementById('deleteActionBtn');
|
||||||
|
//const modal_categoryDescription = document.getElementById('editCategoryModalDescription');
|
||||||
|
//const modal_categoryid = document.getElementById('editCategoryModalId');
|
||||||
|
|
||||||
|
modal_categoryName.innerText = result.name;
|
||||||
|
modal_deleteButton.setAttribute('onclick', `deleteEntry(${result.id})`);
|
||||||
|
|
||||||
|
//modal_categoryDescription.value = result.description;
|
||||||
|
//modal_categoryid.value = result.id;
|
||||||
|
},
|
||||||
|
error: function (data) {
|
||||||
|
console.log('!!!! ERROR !!!!', data);
|
||||||
|
document.getElementById('deleteNamePlaceholder').innerText = 'Deleted';
|
||||||
|
|
||||||
|
$('#staticBackdrop').modal('hide');
|
||||||
|
$('#generalToast').removeClass('text-bg-primary');
|
||||||
|
$('#generalToast').addClass('text-bg-danger');
|
||||||
|
$('#generalToast').toast('show');
|
||||||
|
$('#generalToast').children('.d-flex').children('.toast-body').html('<i class="bi bi-exclamation-triangle-fill"></i> Something went wrong. The category does no longer exist.');
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
57
static/js/formHandler.js
Normal file
57
static/js/formHandler.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
$('.frontendForm').each(function() {
|
||||||
|
console.log('frontendForm found');
|
||||||
|
$(this).on('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var form = $(this);
|
||||||
|
|
||||||
|
// Show overlay with spinner
|
||||||
|
$('.loader-overlay').addClass('loaderActive');
|
||||||
|
|
||||||
|
|
||||||
|
formData = form.serializeArray();
|
||||||
|
console.log(formData, $(this).attr('method'), $(this).attr('data-target'));
|
||||||
|
console.log('submitting form');
|
||||||
|
$.ajax({
|
||||||
|
type: $(this).attr('method'),
|
||||||
|
url: $(this).attr('data-target'),
|
||||||
|
data: formData,
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data) {
|
||||||
|
console.log('success');
|
||||||
|
// Hide overlay with spinner
|
||||||
|
$('.loader-overlay').removeClass('loaderActive');
|
||||||
|
// Close the modal
|
||||||
|
$('.modal').modal('hide');
|
||||||
|
// Clear all fields
|
||||||
|
form.find('input, textarea').val('');
|
||||||
|
|
||||||
|
$('#generalToast').removeClass('text-bg-primary');
|
||||||
|
$('#generalToast').addClass('text-bg-success');
|
||||||
|
$('#generalToast').toast('show');
|
||||||
|
$('#generalToast').children('.d-flex').children('.toast-body').html('<i class="bi bi-check2"></i> Changes saved successfully.');
|
||||||
|
setTimeout(() => {
|
||||||
|
$('#generalToast').toast('hide');;
|
||||||
|
$('#generalToast').removeClass('text-bg-success');
|
||||||
|
$('#generalToast').addClass('text-bg-primary');
|
||||||
|
window.location.reload();
|
||||||
|
}, 1500);
|
||||||
|
},
|
||||||
|
error: function(data) {
|
||||||
|
console.log('error');
|
||||||
|
// Hide overlay with spinner
|
||||||
|
$('.loader-overlay').removeClass('loaderActive');
|
||||||
|
|
||||||
|
$('#generalToast').removeClass('text-bg-primary');
|
||||||
|
$('#generalToast').addClass('text-bg-danger');
|
||||||
|
$('#generalToast').toast('show');
|
||||||
|
$('#generalToast').children('.d-flex').children('.toast-body').html('<i class="bi bi-exclamation-triangle-fill"></i> Something went wrong. Please try again later.');
|
||||||
|
setTimeout(() => {
|
||||||
|
$('#generalToast').toast('hide');
|
||||||
|
$('#generalToast').removeClass('text-bg-danger');
|
||||||
|
$('#generalToast').addClass('text-bg-primary');
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user