Compare commits
162 Commits
bb1635a5b4
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| c35726bf5c | |||
| e82208fc5e | |||
| 9bdca3317c | |||
| 61abd44328 | |||
| acb9876d9b | |||
| 10d88f53eb | |||
| bba0aa2ee4 | |||
| b7773ec02a | |||
| b9dd6e3ae2 | |||
| f940bcdc9d | |||
| 2ae3c8ba59 | |||
| 97b9c4db4a | |||
| d8eddafcae | |||
| 58b58424ab | |||
| 72d52d9256 | |||
| 5dfece09b7 | |||
| 97eb73c6d1 | |||
| bb6d523abb | |||
| 09d3a7041a | |||
| 132e8d0146 | |||
| d0a0d08902 | |||
| 208cd615af | |||
| e82ef76316 | |||
| 4db4eea2d1 | |||
| edcfff6cc6 | |||
| 61860c759e | |||
| 08c9b3404f | |||
| 93ed2e9ee8 | |||
| fb9ee15bda | |||
| 76bc0db3dd | |||
| 2e5de34cb5 | |||
| 07e47e64ae | |||
| 73eb70538e | |||
| 8b8c9acb69 | |||
| cb3ab668d8 | |||
| f6654067f5 | |||
| 532a722763 | |||
| 38d1043606 | |||
| 18daca904e | |||
| e833c48cc8 | |||
| 0bd217c727 | |||
| 74974323f0 | |||
| f3c4c26ef9 | |||
| 74bcd6e805 | |||
| eb2c34c557 | |||
| 808e3d84ef | |||
| 7a22b52c91 | |||
| e17b8e7bbe | |||
| e597968777 | |||
| bbd7a17144 | |||
| 5945ace9f2 | |||
| 316b27e3e0 | |||
| 7165c959b9 | |||
| ae7e3fd54e | |||
| 7ec5c5beb0 | |||
| c9aa41ab00 | |||
| 4696835c65 | |||
| 2d3f308877 | |||
| 3d083986ae | |||
| 92b47f03d9 | |||
| 3b8f18093e | |||
| 1cd1d3a3e9 | |||
| 8324fffeb6 | |||
| 354f3260a5 | |||
| ab5af4deac | |||
| 7a15b160ac | |||
| ca0ba7fe59 | |||
| 0914b53341 | |||
| 34b80cf236 | |||
| 196ea00972 | |||
| 807a4ca699 | |||
| d98a659262 | |||
| 6dd5f4b61f | |||
| 751b9d5701 | |||
| b0634d9427 | |||
| 8a143fbb19 | |||
| 8b72a1b47e | |||
| f4c44fb02b | |||
| 03aa7e5aee | |||
| f035e6f14a | |||
| 227e2aa00c | |||
| 4a48dd2bb5 | |||
| 9796947db5 | |||
| 1e02d4fa4f | |||
| 26ea8d5e89 | |||
| 8fb06c71d3 | |||
| e258aaead9 | |||
| 491de26a0b | |||
| f1979f0fc9 | |||
| f4433f4192 | |||
| bff0e77766 | |||
| 43ca16dc80 | |||
| 121bed59fd | |||
| 4e885ce74c | |||
| 4908d6644a | |||
| 21c374903b | |||
| ed11b2b26f | |||
| 357c118396 | |||
| 866b6d5120 | |||
| 739e6bbe9f | |||
| 0975f4e499 | |||
| 2990a330dd | |||
| cb59f58926 | |||
| 1a79a97929 | |||
| 4b92a28dfa | |||
| 4aae659ee4 | |||
| 7bfb48b81f | |||
| 7432decd3c | |||
| 04a607d3bc | |||
| d178e04362 | |||
| 020fdc83af | |||
| 33803a69a6 | |||
| 3ea6dc5bc4 | |||
| b484a0c5ea | |||
| a73c63cefa | |||
| 5b97d078c5 | |||
| 7529cc5b0c | |||
| df252e72b3 | |||
| 359427824b | |||
| cbdd218fe4 | |||
| 35acd2b0b3 | |||
| 625d5969be | |||
| 2370d45220 | |||
| cb7a4068fc | |||
| e4d15ef051 | |||
| f3fa617aa5 | |||
| ab16059387 | |||
| b6f1cfdc6c | |||
| 1ce5f9acf7 | |||
| 44da09d22c | |||
| 0b72ffa935 | |||
| a2fb845e2e | |||
| bcd65b4b91 | |||
| b1d25c7ba2 | |||
| c9a5203131 | |||
| 246b5a17bd | |||
| 245ba19cdc | |||
| e5e6aa3fee | |||
| 81eb10e021 | |||
| 51b81b97bc | |||
| 242494a4ea | |||
| 542c08f10b | |||
| 0578d28669 | |||
| 5696871b8d | |||
| 125f7f5046 | |||
| 1cb8b70430 | |||
| 200ec975f7 | |||
| 5f5757c784 | |||
| 571b74f0e7 | |||
| 8363cc2816 | |||
| d852e9e573 | |||
| bd4ca7ba63 | |||
| df85a30dff | |||
| d5e9176d53 | |||
| 45b1f7c0a6 | |||
| eaac8143e9 | |||
| dd88f258ed | |||
| c2c43b1e22 | |||
| 4b53700603 | |||
| a18cf652fa | |||
| 84ce009310 | |||
| dc04d97229 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -4,6 +4,12 @@ server/dist
|
|||||||
dist
|
dist
|
||||||
apiDocsLSTV2
|
apiDocsLSTV2
|
||||||
testFiles
|
testFiles
|
||||||
|
builds
|
||||||
|
nssm.exe
|
||||||
|
backend-0.1.2-217.zip
|
||||||
|
backend-0.1.2-218.zip
|
||||||
|
backend-0.1.2.zip
|
||||||
|
postgresql-17.2-3-windows-x64.exe
|
||||||
|
|
||||||
|
|
||||||
# ---> Node
|
# ---> Node
|
||||||
@@ -142,8 +148,4 @@ dist
|
|||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
backend-0.1.3.zip
|
||||||
nssm.exe
|
|
||||||
|
|
||||||
backend-0.1.2-217.zip
|
|
||||||
postgresql-17.2-3-windows-x64.exe
|
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
{
|
{
|
||||||
"types": [
|
"types": [
|
||||||
{"type": "feat", "section": "🌟 Enhancements"},
|
{ "type": "feat", "section": "🌟 Enhancements" },
|
||||||
{"type": "fix", "section": "🐛 Bug fixes"},
|
{ "type": "fix", "section": "🐛 Bug fixes" },
|
||||||
{"type": "chore", "hidden": false, "section": "📝 Chore"},
|
{ "type": "chore", "hidden": false, "section": "📝 Chore" },
|
||||||
{"type": "docs", "section": "📚 Documentation"},
|
{ "type": "docs", "section": "📚 Documentation" },
|
||||||
{"type": "style", "hidden": true},
|
{ "type": "style", "hidden": true },
|
||||||
{"type": "refactor", "section": "🛠️ Code Refactor"},
|
{ "type": "refactor", "section": "🛠️ Code Refactor" },
|
||||||
{"type": "perf", "hidden": false, "section": "🚀 Performance"},
|
{ "type": "perf", "hidden": false, "section": "🚀 Performance" },
|
||||||
{"type": "test", "section": "📝 Testing Code"},
|
{ "type": "test", "section": "📝 Testing Code" },
|
||||||
{"type": "ci", "section": "📈 Project changes"}
|
{ "type": "ci", "hidden": false, "section": "📈 Project changes" },
|
||||||
],
|
{ "type": "build", "hidden": true, "section": "📈 Project Builds" }
|
||||||
"commitUrlFormat": "https://git.tuffraid.net/cowch/lstV2/commits/{{hash}}",
|
],
|
||||||
"compareUrlFormat": "https://git.tuffraid.net/cowch/lstV2/compare/{{previousTag}}...{{currentTag}}",
|
"commitUrlFormat": "https://git.tuffraid.net/cowch/lstV2/commits/{{hash}}",
|
||||||
"header": "# All CHanges to LST can be found below.\n"
|
"compareUrlFormat": "https://git.tuffraid.net/cowch/lstV2/compare/{{previousTag}}...{{currentTag}}",
|
||||||
|
"header": "# All CHanges to LST can be found below.\n"
|
||||||
}
|
}
|
||||||
|
|||||||
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"[javascriptreact]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"[typescriptreact]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"[json]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"[graphql]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
},
|
||||||
|
"[handlebars]": {
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
}
|
||||||
|
}
|
||||||
285
CHANGELOG.md
285
CHANGELOG.md
@@ -1,5 +1,290 @@
|
|||||||
# All CHanges to LST can be found below.
|
# All CHanges to LST can be found below.
|
||||||
|
|
||||||
|
## [2.9.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.8.0...v2.9.0) (2025-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### 📈 Project changes
|
||||||
|
|
||||||
|
* **frontend:** added ocme as a proxy in the dev ([eb2c34c](https://git.tuffraid.net/cowch/lstV2/commits/eb2c34c557b72c3387b70addac30a4d8291402d4))
|
||||||
|
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
* **install:** added more env params and an install install stuff ([09d3a70](https://git.tuffraid.net/cowch/lstV2/commits/09d3a7041a18283a5add86ea845a8d7249522769))
|
||||||
|
* **install:** removed the super secret key ([357c118](https://git.tuffraid.net/cowch/lstV2/commits/357c1183964be0f3c02207c24bc8f83347282211))
|
||||||
|
* **logs:** changes how logs are put into the db they will be there name vs key ([18daca9](https://git.tuffraid.net/cowch/lstV2/commits/18daca904e0305371c6128988b48d54e3aec9a2a))
|
||||||
|
* **migration:** added more documents on the install md ([0bd217c](https://git.tuffraid.net/cowch/lstV2/commits/0bd217c727d726d62ddf06a0e44e95c4606361cf))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **ocme:** cycle count intital improvements ([7a22b52](https://git.tuffraid.net/cowch/lstV2/commits/7a22b52c916335c748598b82e78819c325bb8c4c))
|
||||||
|
* **ocp dash:** more work on the dashboard ([f3c4c26](https://git.tuffraid.net/cowch/lstV2/commits/f3c4c26ef957e6fe359a77f139ad36cdacefb8ef))
|
||||||
|
* **ocp:** more work on the dashboard ([8324fff](https://git.tuffraid.net/cowch/lstV2/commits/8324fffeb664bff3751ffc26e988a4a506b658a9))
|
||||||
|
* **returnres:** tryed to make a standard return res but will come back to this later ([58b5842](https://git.tuffraid.net/cowch/lstV2/commits/58b58424abbf98feec0c5442a59f4d055bbd1811))
|
||||||
|
* **rfid:** more work on the rfid service ([21c3749](https://git.tuffraid.net/cowch/lstV2/commits/21c374903b5cba56ced44b7eb2066ee902fc7bc3))
|
||||||
|
* **server:** start/stop/restart buttons added. comment [#14](https://git.tuffraid.net/cowch/lstV2/issues/14) ([76bc0db](https://git.tuffraid.net/cowch/lstV2/commits/76bc0db3dd9c48b69e4f6f571181a1f07c48bdeb))
|
||||||
|
* **streaming logs:** more test but failed again ([08c9b34](https://git.tuffraid.net/cowch/lstV2/commits/08c9b3404f548a167464445ec2f19288a092b0dc))
|
||||||
|
* **streaming logs:** test for streaming logs ([73eb705](https://git.tuffraid.net/cowch/lstV2/commits/73eb70538e36601cf436aaba244f99d5bd873d34))
|
||||||
|
* **streaming logs:** will come back to this later this is killing me inside ([97eb73c](https://git.tuffraid.net/cowch/lstV2/commits/97eb73c6d1aef747ef98f5f666fe47622795746f))
|
||||||
|
* **streaming:** more streaming test ([4db4eea](https://git.tuffraid.net/cowch/lstV2/commits/4db4eea2d12e37809879e96ed4279d6e23e83acc))
|
||||||
|
* **streaming:** more testing on streaming the lofs ([e82ef76](https://git.tuffraid.net/cowch/lstV2/commits/e82ef76316f0562b57124eb977c86fd2c6a3f332))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **admincheck:** this check is so we dont use stuff on the wrong servers ([3d08398](https://git.tuffraid.net/cowch/lstV2/commits/3d083986aed528c2f881d6f673c0be03b8986c0b))
|
||||||
|
* **auth:** add, update were added for adm account in backend only ([d8eddaf](https://git.tuffraid.net/cowch/lstV2/commits/d8eddafcaea9141e9413a122a320649c7dd325e5))
|
||||||
|
* **auth:** remove all old localstorage if no session ([8fb06c7](https://git.tuffraid.net/cowch/lstV2/commits/8fb06c71d370a27697628077474a261596b567e0))
|
||||||
|
* **db:** logs, manualprints added ([0914b53](https://git.tuffraid.net/cowch/lstV2/commits/0914b5334119fa705eedddc6c9e8303cb82da551))
|
||||||
|
* **installer:** added a check for lstv2 already installed ([4696835](https://git.tuffraid.net/cowch/lstV2/commits/4696835c6557c2eae3be6a292144493be9d98f67))
|
||||||
|
* **logger:** logger service created with its endpoints ([7ec5c5b](https://git.tuffraid.net/cowch/lstV2/commits/7ec5c5beb0a9b02e8b8761908ee75ac2cfd317ee))
|
||||||
|
* **logger:** streaming logs works server side not frontend for now ([e833c48](https://git.tuffraid.net/cowch/lstV2/commits/e833c48cc8f68af40888ea161100e02f6ad19604))
|
||||||
|
* **lst:** added in delay global function ([7497432](https://git.tuffraid.net/cowch/lstV2/commits/74974323f0a7bd7c2eaa22024b7a8e91db2868e2))
|
||||||
|
* **lst:** added prettier config so we have the same formatting across all computers ([132e8d0](https://git.tuffraid.net/cowch/lstV2/commits/132e8d0146318fa9deb673bbcabf0d80c2a6d39f))
|
||||||
|
* **ocme:** added in ocme service so we can utlize 2 ports ([ae7e3fd](https://git.tuffraid.net/cowch/lstV2/commits/ae7e3fd54e5c256fb82e68f2e935e3b914e43d13))
|
||||||
|
* **ocme:** cycle count implemeneted ([74bcd6e](https://git.tuffraid.net/cowch/lstV2/commits/74bcd6e805c34e181f0c48310a799daf3afaee66))
|
||||||
|
* **ocmeserver:** the server was just migrated so it can be upgraded to lstv2 ([e258aae](https://git.tuffraid.net/cowch/lstV2/commits/e258aaead9a56cc4de36c17ed60b0bdaa91019cb))
|
||||||
|
* **ocp:** added in service plus manual print log ([7165c95](https://git.tuffraid.net/cowch/lstV2/commits/7165c959b9d5b37c0d4b01cb3f5bc27b40cec71d))
|
||||||
|
* **ports:** added in production port if in production ([121bed5](https://git.tuffraid.net/cowch/lstV2/commits/121bed59fda04b2ad134feb0895428515a1c56d8))
|
||||||
|
* **scripts:** made moving scripts more proper ([d0a0d08](https://git.tuffraid.net/cowch/lstV2/commits/d0a0d0890255acf890ba402386847b19566c92df))
|
||||||
|
* **serverdata:** added in huston, sherman. and corrected contact info in westbend ([4908d66](https://git.tuffraid.net/cowch/lstV2/commits/4908d6644a392395e660d382536c0fd31e3d0647))
|
||||||
|
* **server:** ocpService and loggerService added ([2d3f308](https://git.tuffraid.net/cowch/lstV2/commits/2d3f30887744bddfe22dc764188cf727a5e476df))
|
||||||
|
* **servers:** added dayton in ([bbd7a17](https://git.tuffraid.net/cowch/lstV2/commits/bbd7a17144e1e1a0faa192139cb1539c2f1ecc5c))
|
||||||
|
* **settings:** added in setting store ([1cd1d3a](https://git.tuffraid.net/cowch/lstV2/commits/1cd1d3a3e9e1ec1bf16ac2552caf24aa299959bf))
|
||||||
|
* **settings:** more seed settings ([e597968](https://git.tuffraid.net/cowch/lstV2/commits/e597968777e88289d361fdc01ec683a1f4c80192))
|
||||||
|
* **trycatch:** added in theo's try catch to reduce the code and love it ([72d52d9](https://git.tuffraid.net/cowch/lstV2/commits/72d52d925677eeeac6d158028114201862b6e2a2))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **auth:** added in correct bycrptjs ([208cd61](https://git.tuffraid.net/cowch/lstV2/commits/208cd615af8250686745aa5b6779706ae267e423))
|
||||||
|
* **auth:** moved prod back to server as we run 2 instances during migration ([7a15b16](https://git.tuffraid.net/cowch/lstV2/commits/7a15b160ac2393cd66a932e598ffaa5aeda5812f))
|
||||||
|
* **consume materail:** get token from localstorage as the store isnt wokring properly ([354f326](https://git.tuffraid.net/cowch/lstV2/commits/354f3260a55b53bfb461a37db9d64550bacbfe04))
|
||||||
|
* **frontend:** added date-fns into the frontend ([bba0aa2](https://git.tuffraid.net/cowch/lstV2/commits/bba0aa2ee4e9b9be1db184da894ce6e96fd2e38f))
|
||||||
|
* **login:** removed all the data from teh login dropdown as it could cause issues ([5dfece0](https://git.tuffraid.net/cowch/lstV2/commits/5dfece09b7285dda96875bbc740df803d816b92a))
|
||||||
|
* **login:** removed roles from the login to shrink the jwt ([c9aa41a](https://git.tuffraid.net/cowch/lstV2/commits/c9aa41ab0099b7a05d50d9a981cf7e8a42a04733))
|
||||||
|
* **production:** changes ocp to viewwer ([ab5af4d](https://git.tuffraid.net/cowch/lstV2/commits/ab5af4deacbeaf1ed93c6231fb98b187f7540ca4))
|
||||||
|
* **server query:** bumped the refresh from 500ms to 2500ms ([866b6d5](https://git.tuffraid.net/cowch/lstV2/commits/866b6d5120810252b089580d341f3fb1b62e951a))
|
||||||
|
* **serverdata:** remapped the server list to all be on the E drive and deactivated ([8b8c9ac](https://git.tuffraid.net/cowch/lstV2/commits/8b8c9acb6969b63f157ea95b7d61923bf4bb4eae))
|
||||||
|
* **server:** removed the websocket wrapper going wiht normal ws ([bb6d523](https://git.tuffraid.net/cowch/lstV2/commits/bb6d523abbd3c9423eddbaab96e297b4850e2aa8))
|
||||||
|
* **settings:** refactored the admincheck so we can reuse it ([ca0ba7f](https://git.tuffraid.net/cowch/lstV2/commits/ca0ba7fe59f7e19d0de4924a419cce461de4b7a1))
|
||||||
|
* **settings:** removed the need to login to get the settings ([5945ace](https://git.tuffraid.net/cowch/lstV2/commits/5945ace9f259f6ef418c1621c246982b5b572dc1))
|
||||||
|
* **settings:** used the common response function created ([316b27e](https://git.tuffraid.net/cowch/lstV2/commits/316b27e3e011a0c0b4ce88ea579290807b8927c5))
|
||||||
|
* **stores:** added in axios ([3b8f180](https://git.tuffraid.net/cowch/lstV2/commits/3b8f18093ead2a988b2b19d1e8f25db6eaeaaee8))
|
||||||
|
* **view access:** if role [] then allow them to see it ([e17b8e7](https://git.tuffraid.net/cowch/lstV2/commits/e17b8e7bbe94c25c1bd3414b1db31191c87553d6))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **auth:** added in the correct function for days between logins ([ed11b2b](https://git.tuffraid.net/cowch/lstV2/commits/ed11b2b26ff80fde9f94615f740eb5152b16744d))
|
||||||
|
* **auth:** fixed the getaccess to be getuseraccess as it was orignally ([b9dd6e3](https://git.tuffraid.net/cowch/lstV2/commits/b9dd6e3ae2f5c158dd4827ae0c9db2c6747c57e1))
|
||||||
|
* **calendar:** this component had a bug and needed a lib update ([93ed2e9](https://git.tuffraid.net/cowch/lstV2/commits/93ed2e9ee8c98edd6a8c47d6e7a0caf6a8e93278))
|
||||||
|
* **consume material:** when we consumed material the button was never reenabled ([07e47e6](https://git.tuffraid.net/cowch/lstV2/commits/07e47e64ae2f4ddd325a2fdb34c82143c9adf84b)), closes [#15](https://git.tuffraid.net/cowch/lstV2/issues/15)
|
||||||
|
* **frontend:** removed unwanted import ([10d88f5](https://git.tuffraid.net/cowch/lstV2/commits/10d88f53ebaf670c9f6b3ca59cbbaf4d88f26b9f))
|
||||||
|
* **loginform:** removed the console log that was left by accident ([2ae3c8b](https://git.tuffraid.net/cowch/lstV2/commits/2ae3c8ba5916b5249135b86b374ac1bf32837478))
|
||||||
|
* **login:** if we have a wrong password or username we didnt properly error instead we crashed ([2e5de34](https://git.tuffraid.net/cowch/lstV2/commits/2e5de34cb50c79cd60e038492b2397eee69def11))
|
||||||
|
* **scaler:** fix due to update ([edcfff6](https://git.tuffraid.net/cowch/lstV2/commits/edcfff6cc6cf81e56b5532f0876383659b951a5d))
|
||||||
|
* **serverlist:** corrected the time by removing teh Z at the end of the time ([f940bcd](https://git.tuffraid.net/cowch/lstV2/commits/f940bcdc9df2d3e9989d49feae88036a6f8c7013))
|
||||||
|
* **sqlserver:** if we already have a connection just return we dont want to try a second time ([b7773ec](https://git.tuffraid.net/cowch/lstV2/commits/b7773ec02aa26c01530723dc146e0c9f4dae41d3))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* **builds:** bummped lstv1 build ([739e6bb](https://git.tuffraid.net/cowch/lstV2/commits/739e6bbe9fa48fae682f9931a2c8bcb763feb636))
|
||||||
|
* bump build number to 20 ([0975f4e](https://git.tuffraid.net/cowch/lstV2/commits/0975f4e499a8a2aec0662352cb4496299292d4ea))
|
||||||
|
* bump build number to 21 ([4e885ce](https://git.tuffraid.net/cowch/lstV2/commits/4e885ce74c02ee1fd95a93402d1d32ecf357b1cb))
|
||||||
|
* bump build number to 22 ([43ca16d](https://git.tuffraid.net/cowch/lstV2/commits/43ca16dc807b9fa3496498e90a871568f0e5f54c))
|
||||||
|
* bump build number to 23 ([bff0e77](https://git.tuffraid.net/cowch/lstV2/commits/bff0e77766b49c72d77fa55cfaab2d347a1a75dc))
|
||||||
|
* bump build number to 24 ([f4433f4](https://git.tuffraid.net/cowch/lstV2/commits/f4433f41926dab72a239fc585ddd1e14acb80c7e))
|
||||||
|
* bump build number to 25 ([f1979f0](https://git.tuffraid.net/cowch/lstV2/commits/f1979f0fc914f3b94bad1816cd405a6431d1ba4a))
|
||||||
|
* bump build number to 26 ([491de26](https://git.tuffraid.net/cowch/lstV2/commits/491de26a0bbe6dfca9e1cb068991789c29a09ac0))
|
||||||
|
* bump build number to 27 ([26ea8d5](https://git.tuffraid.net/cowch/lstV2/commits/26ea8d5e89bb1b44ceb6b205da3ad158c603fca0))
|
||||||
|
* bump build number to 28 ([1e02d4f](https://git.tuffraid.net/cowch/lstV2/commits/1e02d4fa4fc1a007634da49fe2697d63c89cba18))
|
||||||
|
* bump build number to 29 ([9796947](https://git.tuffraid.net/cowch/lstV2/commits/9796947db5443c8b5678d7502037458d680e4018))
|
||||||
|
* bump build number to 30 ([4a48dd2](https://git.tuffraid.net/cowch/lstV2/commits/4a48dd2bb57064953ef6e192c76b91bb844a24de))
|
||||||
|
* bump build number to 31 ([227e2aa](https://git.tuffraid.net/cowch/lstV2/commits/227e2aa00c2a3e5526e0347c76676de345dfea5d))
|
||||||
|
* bump build number to 32 ([f035e6f](https://git.tuffraid.net/cowch/lstV2/commits/f035e6f14a9e2123a10010d4f515f78f0c222599))
|
||||||
|
* bump build number to 33 ([03aa7e5](https://git.tuffraid.net/cowch/lstV2/commits/03aa7e5aeee39b1b390b4da2019f44459487e0a0))
|
||||||
|
* bump build number to 34 ([f4c44fb](https://git.tuffraid.net/cowch/lstV2/commits/f4c44fb02ba857890af66a2747381ef1c3def25b))
|
||||||
|
* bump build number to 35 ([8b72a1b](https://git.tuffraid.net/cowch/lstV2/commits/8b72a1b47e715f4146e586e9fdd6abcabd97743d))
|
||||||
|
* bump build number to 36 ([8a143fb](https://git.tuffraid.net/cowch/lstV2/commits/8a143fbb19d2270b0139a7a4edbce745c477b6b1))
|
||||||
|
* bump build number to 37 ([b0634d9](https://git.tuffraid.net/cowch/lstV2/commits/b0634d9427f6fff3a239680204b5e6daf6163e37))
|
||||||
|
* bump build number to 38 ([751b9d5](https://git.tuffraid.net/cowch/lstV2/commits/751b9d5701cf7e81641f154a02041869e1b80c49))
|
||||||
|
* bump build number to 39 ([6dd5f4b](https://git.tuffraid.net/cowch/lstV2/commits/6dd5f4b61f3a27779980cf14915c4394256eae20))
|
||||||
|
* bump build number to 40 ([d98a659](https://git.tuffraid.net/cowch/lstV2/commits/d98a6592628f36c654039ccea25db163ddf15e8c))
|
||||||
|
* bump build number to 41 ([807a4ca](https://git.tuffraid.net/cowch/lstV2/commits/807a4ca6993b5dfa82a45aaf44a2d661c3e03428))
|
||||||
|
* bump build number to 42 ([196ea00](https://git.tuffraid.net/cowch/lstV2/commits/196ea009720a65c520f5626658ac7885a41796cb))
|
||||||
|
* bump build number to 43 ([34b80cf](https://git.tuffraid.net/cowch/lstV2/commits/34b80cf2368228b70cd6a79d44ba0f95b5c5941a))
|
||||||
|
* bump build number to 44 ([808e3d8](https://git.tuffraid.net/cowch/lstV2/commits/808e3d84efa0889077a12cbf8e28df794a51f2bc))
|
||||||
|
* bump build number to 45 ([38d1043](https://git.tuffraid.net/cowch/lstV2/commits/38d10436069d3db1612a622d9b9e0c7aec04f6dd))
|
||||||
|
* bump build number to 46 ([532a722](https://git.tuffraid.net/cowch/lstV2/commits/532a7227631cf67664ca41133330d8cfa59f429b))
|
||||||
|
* bump build number to 47 ([f665406](https://git.tuffraid.net/cowch/lstV2/commits/f6654067f5f01c3ee4855f0cbe07593f13263ce7))
|
||||||
|
* bump build number to 48 ([97b9c4d](https://git.tuffraid.net/cowch/lstV2/commits/97b9c4db4a67faf68edae4dc1217b28f87d003e8))
|
||||||
|
* bump build number to 49 ([acb9876](https://git.tuffraid.net/cowch/lstV2/commits/acb9876d9b715894481d31d9bb104e54561710d0))
|
||||||
|
* **pkg updates:** updated all pkgs ([fb9ee15](https://git.tuffraid.net/cowch/lstV2/commits/fb9ee15bda89257815012023ed5543ef55b5f379))
|
||||||
|
* **updatescript:** added in so we can do a full install with an env creation for old ([cb3ab66](https://git.tuffraid.net/cowch/lstV2/commits/cb3ab668d866ea9e3428e548d9065a9681174e82))
|
||||||
|
|
||||||
|
## [2.8.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.7.0...v2.8.0) (2025-03-16)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* bump build number to 19 ([3ea6dc5](https://git.tuffraid.net/cowch/lstV2/commits/3ea6dc5bc46b6a060548566ea606095d0e30c96c))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **api:** testing api options to reduce the code as we keep repeating same functions ([7432dec](https://git.tuffraid.net/cowch/lstV2/commits/7432decd3ce9033ad310850fe5b0cbba076526a5))
|
||||||
|
* **printers:** started printer migration ([04a607d](https://git.tuffraid.net/cowch/lstV2/commits/04a607d3bcf2020624e45ba5ddf83f0b13acbbc7))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **reader:** added in missing columns needed in the table ([020fdc8](https://git.tuffraid.net/cowch/lstV2/commits/020fdc83af2b5e90b76fa43b884965f82b5db466))
|
||||||
|
* **rfid tags:** update tag table to include what is needed and changed columns to be correct ([d178e04](https://git.tuffraid.net/cowch/lstV2/commits/d178e0436247d83b3e33dc7c92bb49aa023b6198))
|
||||||
|
* **rfid:** cleaned up contorller folder ([1a79a97](https://git.tuffraid.net/cowch/lstV2/commits/1a79a9792913bb984f230f29fede1bfa6da2991f))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **api:** added in a response function to reduce the over responses as they are always the same ([7bfb48b](https://git.tuffraid.net/cowch/lstV2/commits/7bfb48b81fcfe759e8f448db30db93b1c320de1a))
|
||||||
|
* **rfid:** add/update readers now possible ([4aae659](https://git.tuffraid.net/cowch/lstV2/commits/4aae659ee41d952e823ba4582b4d3fab05bd2500))
|
||||||
|
* **rfid:** no read console log for now but will show in frontend as well ([4b92a28](https://git.tuffraid.net/cowch/lstV2/commits/4b92a28dfa3db011a451aff913175ff8d21feb1b))
|
||||||
|
* **rfid:** reader and tag db completed ([33803a6](https://git.tuffraid.net/cowch/lstV2/commits/33803a69a6b9b0d24297f7a9d463d16dbae4ca44))
|
||||||
|
* **tag reading:** more tag reading updates, with more contorl now ([cb59f58](https://git.tuffraid.net/cowch/lstV2/commits/cb59f589264583b2ee6d8f0255d3ceb33f101a01))
|
||||||
|
|
||||||
|
## [2.7.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.6.0...v2.7.0) (2025-03-15)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* bump build number to 10 ([245ba19](https://git.tuffraid.net/cowch/lstV2/commits/245ba19cdc7e67fec9343bb9eba90287d8951854))
|
||||||
|
* bump build number to 11 ([c9a5203](https://git.tuffraid.net/cowch/lstV2/commits/c9a520313160959ed929351f55bd18606b6500a9))
|
||||||
|
* bump build number to 12 ([b1d25c7](https://git.tuffraid.net/cowch/lstV2/commits/b1d25c7ba27a72c42803a3b482234c41670a07a2))
|
||||||
|
* bump build number to 13 ([bcd65b4](https://git.tuffraid.net/cowch/lstV2/commits/bcd65b4b91cf6cb24a32323ead5ff6a73d3c9d3d))
|
||||||
|
* bump build number to 14 ([a2fb845](https://git.tuffraid.net/cowch/lstV2/commits/a2fb845e2efbeb8becf91082343770b2d730330c))
|
||||||
|
* bump build number to 15 ([0b72ffa](https://git.tuffraid.net/cowch/lstV2/commits/0b72ffa935be81476a15166fd60ae8cabe29d297))
|
||||||
|
* bump build number to 16 ([44da09d](https://git.tuffraid.net/cowch/lstV2/commits/44da09d22c4d946c981d408d797ea121d26690b6))
|
||||||
|
* bump build number to 17 ([1ce5f9a](https://git.tuffraid.net/cowch/lstV2/commits/1ce5f9acf752f5f4bcb4b2ff1c71f54ffb9331f3))
|
||||||
|
* bump build number to 18 ([b6f1cfd](https://git.tuffraid.net/cowch/lstV2/commits/b6f1cfdc6c71e351fb90ec7729e0d0f89322174f))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **frontend:** removed tanstack devTools ([3594278](https://git.tuffraid.net/cowch/lstV2/commits/359427824bae319b7f2f406eb52b8f9c43be198f))
|
||||||
|
* **frontend:** removed the caption from settings table ([35acd2b](https://git.tuffraid.net/cowch/lstV2/commits/35acd2b0b3af7b9d010cb8f78f088ab3a539c54b))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **frontend:** added in proper links for settings and servers to the sidebar ([cbdd218](https://git.tuffraid.net/cowch/lstV2/commits/cbdd218fe454e38a7cf0c4d0ddf60d1f20e15ee2))
|
||||||
|
* **frontend:** added in update server page only for sysAdmin ([625d596](https://git.tuffraid.net/cowch/lstV2/commits/625d5969be2dbde9e97f6607c33c5e5b14e3d192))
|
||||||
|
* **new setting:** added in devDir ment for updating servers ([5b97d07](https://git.tuffraid.net/cowch/lstV2/commits/5b97d078c583f3e78d52dbc135da99a0175c8e54))
|
||||||
|
* **server upgrade:** added in a catch incase we try to upgrade again ([ab16059](https://git.tuffraid.net/cowch/lstV2/commits/ab16059387b7cb46e2a3d86f6da09a31899bd5d6))
|
||||||
|
* **server:** added in update server as well as get serverdata ([df252e7](https://git.tuffraid.net/cowch/lstV2/commits/df252e72b39d811ffbbb0af49aaf43ff22081f48))
|
||||||
|
* **serverdata:** added catch if we are not on localhost we cant actaully see the devDir in set ([f3fa617](https://git.tuffraid.net/cowch/lstV2/commits/f3fa617aa53ed35f461b71f5e479ea521412936e))
|
||||||
|
* **serverdata:** added in bowling green 2 ([7529cc5](https://git.tuffraid.net/cowch/lstV2/commits/7529cc5b0cc2c6542e8f4af07d465b6a9f4295b1))
|
||||||
|
* **sql query:** added 2 catches if not connected dont run ([cb7a406](https://git.tuffraid.net/cowch/lstV2/commits/cb7a4068fcffc7a1d85c2e04f2eeaebdc264705c))
|
||||||
|
* **sql server:** added in the ping check to not spam if we are not connected ([e4d15ef](https://git.tuffraid.net/cowch/lstV2/commits/e4d15ef051f6c72d2cca9bb9fb61ff78849db8c4))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **frontend:** if the modules returns and error we want to use an empty array ([2370d45](https://git.tuffraid.net/cowch/lstV2/commits/2370d45220c5e1c3215a3f2fce9582d8f2bbd3ed))
|
||||||
|
* **rfid:** correction to the params and incorrect naming ([a73c63c](https://git.tuffraid.net/cowch/lstV2/commits/a73c63cefa67f43300f4695f40f2248bcab8f40e))
|
||||||
|
* **zippaths:** corrected the paths to the src that were moved the the env ([246b5a1](https://git.tuffraid.net/cowch/lstV2/commits/246b5a17bd4ffe47654416fa4a1be446f8bffbd0))
|
||||||
|
|
||||||
|
## [2.6.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.5.1...v2.6.0) (2025-03-14)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* bump build number to 9 ([542c08f](https://git.tuffraid.net/cowch/lstV2/commits/542c08f10ba590e7174864c7970fd0ac03ffebf9))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **pkg:** removed dir stuff and moved to env ([242494a](https://git.tuffraid.net/cowch/lstV2/commits/242494a4eaaca0aaf12e9a309e5611e17ac9ccb0))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **app update:** finished the app build / deploy functions and a scripts migration ([81eb10e](https://git.tuffraid.net/cowch/lstV2/commits/81eb10e021fd29e33ee3f7393439c72427df9561))
|
||||||
|
* **pkgdata:** moved the pkg info to a global function ([51b81b9](https://git.tuffraid.net/cowch/lstV2/commits/51b81b97bc4c4b112b128818d203deba49fb5011))
|
||||||
|
|
||||||
|
### [2.5.1](https://git.tuffraid.net/cowch/lstV2/compare/v2.5.0...v2.5.1) (2025-03-14)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **lst:** readded prodBuild ([5696871](https://git.tuffraid.net/cowch/lstV2/commits/5696871b8d56374b508df77e3c6b18421865605f))
|
||||||
|
|
||||||
|
## [2.5.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.4.0...v2.5.0) (2025-03-14)
|
||||||
|
|
||||||
|
|
||||||
|
### 🚀 Performance
|
||||||
|
|
||||||
|
* **auth:** changed the way logs look in the setRoles ([d95b81d](https://git.tuffraid.net/cowch/lstV2/commits/d95b81d303192f176a970ee1de5ffd7afd5d475c))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **auth:** added in timeout for adding new roles to make sure everything else is connected 1st ([2130ade](https://git.tuffraid.net/cowch/lstV2/commits/2130adedb3a766268a73950cd21ac3a21e20bdeb))
|
||||||
|
* **sql:** reduced the time before start up ([80567d2](https://git.tuffraid.net/cowch/lstV2/commits/80567d2dd95fa141fea21fbaf8f9bc22386f92d0))
|
||||||
|
* **system:** checks now in time out to ensure everything connected ([78dc597](https://git.tuffraid.net/cowch/lstV2/commits/78dc597477a51a8b86f7b3dde1e02b9cdb732afa))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **auth:** proper logging for errors in role check ([90d0760](https://git.tuffraid.net/cowch/lstV2/commits/90d0760352bf9d77dd2c1c3c449f1e7f4a5a4056))
|
||||||
|
* **consumption:** correction to the status code to always be 200 on success: true ([5c2d79c](https://git.tuffraid.net/cowch/lstV2/commits/5c2d79c125d051e44cf4e5aa8316127d1619af3e))
|
||||||
|
* **crash alerts:** remmoved close sql as it spammed bad when we couldnt connect ([84ce009](https://git.tuffraid.net/cowch/lstV2/commits/84ce009310b2ddd5daf5af25a38ca78c7469ebff))
|
||||||
|
* **query:** shipmentPallets change from last move to production date ([155b7d9](https://git.tuffraid.net/cowch/lstV2/commits/155b7d92aa876cf9e313dc4cd2cd68193f4a9772))
|
||||||
|
* **serverdata:** fixed a bug in the serverData check ([4b53700](https://git.tuffraid.net/cowch/lstV2/commits/4b53700603ab2110f5abd2dbc9354a99e5950971))
|
||||||
|
* **sql server:** correct return when we cant connect to the server ([d5e9176](https://git.tuffraid.net/cowch/lstV2/commits/d5e9176d53b396a9dc16686ad2cfa8b59e4672eb))
|
||||||
|
* **sql server:** reduced the risk of error when missing data ([6158f25](https://git.tuffraid.net/cowch/lstV2/commits/6158f254b7de890a2262a59d0aeb32411d17d6fd))
|
||||||
|
* **sql:** oops forgot to remove the returns i put in to ignore an error ([bb1635a](https://git.tuffraid.net/cowch/lstV2/commits/bb1635a5b4dc0e6ca324bdf7ea8ecd89c33a9d3d))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **build and zip:** migrated build and zip process from v1 ([df85a30](https://git.tuffraid.net/cowch/lstV2/commits/df85a30dffdc87e5c0475e45559ec81921605d60))
|
||||||
|
* **db:** serverData added in ([3c2b10b](https://git.tuffraid.net/cowch/lstV2/commits/3c2b10b28cdafd269c0f24dcb1dfa79471eb52d0))
|
||||||
|
* **install:** added install instructions ([f69a40a](https://git.tuffraid.net/cowch/lstV2/commits/f69a40af3af932c0e4e8552b17b099edd64b280a))
|
||||||
|
* **ocme:** added in shipment data with increased checked ([c386c5e](https://git.tuffraid.net/cowch/lstV2/commits/c386c5ea8b5500a99c49c2750d9b1f3e2816521a))
|
||||||
|
* **ping:** added in 3 new funcitons to ping devices to see if they are alive before doing something ([a18cf65](https://git.tuffraid.net/cowch/lstV2/commits/a18cf652fad80c3c5b22e3ec50999831930c211b))
|
||||||
|
* **rfid:** added tables to the db for tags and readers ([dc04d97](https://git.tuffraid.net/cowch/lstV2/commits/dc04d97229f61bfeab59d0cf27135d9e0efada8a))
|
||||||
|
* **server:** added a missing db prevention crash ([b9724aa](https://git.tuffraid.net/cowch/lstV2/commits/b9724aa89c47edaf1dbbf730e0605166626c9936))
|
||||||
|
* **serverdata:** all server info will be in all servers now for reduncay ([58975ca](https://git.tuffraid.net/cowch/lstV2/commits/58975ca117158e9f017343f938b8943694433ed3))
|
||||||
|
* **settings:** added in more settings ([d6942dd](https://git.tuffraid.net/cowch/lstV2/commits/d6942dd9826cfa4497a60a67eeb67d0957a904ed))
|
||||||
|
* **sql server:** added ping check to make sure the server is online before we try to connect ([c2c43b1](https://git.tuffraid.net/cowch/lstV2/commits/c2c43b1e2248bb2c48599f8f83f29568dc102a4d))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* bump build number to 4 ([bd4ca7b](https://git.tuffraid.net/cowch/lstV2/commits/bd4ca7ba63a9dafd1b96dd1672ef221da558a7c2))
|
||||||
|
* bump build number to 5 ([d852e9e](https://git.tuffraid.net/cowch/lstV2/commits/d852e9e57370a9f77664eb74999c87b494b56c4e))
|
||||||
|
* bump build number to 6 ([8363cc2](https://git.tuffraid.net/cowch/lstV2/commits/8363cc2816b64f60d66926bb006c2079b2968cfb))
|
||||||
|
* bump build number to 7 ([571b74f](https://git.tuffraid.net/cowch/lstV2/commits/571b74f0e7a5f1e6ef1a13548c21c6f8c7d0c770))
|
||||||
|
* bump build number to 8 ([5f5757c](https://git.tuffraid.net/cowch/lstV2/commits/5f5757c7848903abfce50e2992ed31f3ecfb99ac))
|
||||||
|
* **ignore:** ignoring build folder as we dont want this to push to the server ([eaac814](https://git.tuffraid.net/cowch/lstV2/commits/eaac8143e9fe0e93f59e6229b39a8aa6bc49d79e))
|
||||||
|
* **pkg:** added admin section as well as correct a couple areas for builds ([45b1f7c](https://git.tuffraid.net/cowch/lstV2/commits/45b1f7c0a6a529fdde9624b257021ea30997ffdd))
|
||||||
|
|
||||||
|
|
||||||
|
### 📈 Project changes
|
||||||
|
|
||||||
|
* **lst:** changes to improve the build process ([200ec97](https://git.tuffraid.net/cowch/lstV2/commits/200ec975f742de8a4c7d28bdc1362dba9e15a582))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **apihits:** monitoring this still to make sure its working as intended but low priority ([9c66e6a](https://git.tuffraid.net/cowch/lstV2/commits/9c66e6aac6200c34afa74d8c4d178374dd5ef5ca))
|
||||||
|
* **buildserver:** build serer checks ([dd88f25](https://git.tuffraid.net/cowch/lstV2/commits/dd88f258edf4d7c0cefd8d6baa290c7cf2b9b805))
|
||||||
|
* **pkg:** removed the combined command to deploy ([1cb8b70](https://git.tuffraid.net/cowch/lstV2/commits/1cb8b7043008b1e396b0fe43175459284ce35561))
|
||||||
|
* **rfid:** intial trials built ([da04e9d](https://git.tuffraid.net/cowch/lstV2/commits/da04e9d35d2aecbc9c4a930fe9a217409c35aef2))
|
||||||
|
* **updates:** rewrite of update system ([0054c8f](https://git.tuffraid.net/cowch/lstV2/commits/0054c8f7d44745bdf710696764ff909bed6f3647))
|
||||||
|
|
||||||
## [2.4.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.3.0...v2.4.0) (2025-03-10)
|
## [2.4.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.3.0...v2.4.0) (2025-03-10)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
20
database/migrations/0015_wonderful_lady_vermin.sql
Normal file
20
database/migrations/0015_wonderful_lady_vermin.sql
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
CREATE TABLE "rfidReaders" (
|
||||||
|
"rfidReader_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"reader" text,
|
||||||
|
"readerIP" text,
|
||||||
|
"lastHeartBeat" timestamp DEFAULT now()
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "rfidTags" (
|
||||||
|
"rfidTag_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"tagHex" text,
|
||||||
|
"tag" text,
|
||||||
|
"timeStamp" timestamp DEFAULT now(),
|
||||||
|
"counts" jsonb NOT NULL,
|
||||||
|
"lastareaIn" text NOT NULL,
|
||||||
|
"runningNumber" numeric NOT NULL,
|
||||||
|
"created_at" timestamp DEFAULT now()
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "reader" ON "rfidReaders" USING btree ("reader");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "tagHex" ON "rfidTags" USING btree ("tagHex");
|
||||||
1
database/migrations/0016_wet_doctor_strange.sql
Normal file
1
database/migrations/0016_wet_doctor_strange.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "serverData" ADD COLUMN "isUpgrading" boolean DEFAULT false;
|
||||||
1
database/migrations/0017_bitter_brood.sql
Normal file
1
database/migrations/0017_bitter_brood.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "rfidReaders" ADD COLUMN "lastTrigger" timestamp DEFAULT now();
|
||||||
1
database/migrations/0018_lovely_landau.sql
Normal file
1
database/migrations/0018_lovely_landau.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "rfidReaders" ADD COLUMN "active" boolean DEFAULT true;
|
||||||
2
database/migrations/0019_greedy_justice.sql
Normal file
2
database/migrations/0019_greedy_justice.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "rfidTags" ADD COLUMN "antenna" numeric;--> statement-breakpoint
|
||||||
|
ALTER TABLE "rfidTags" ADD COLUMN "tagStrength" numeric;
|
||||||
2
database/migrations/0020_empty_thundra.sql
Normal file
2
database/migrations/0020_empty_thundra.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "rfidTags" ALTER COLUMN "counts" SET DEFAULT '[]'::jsonb;--> statement-breakpoint
|
||||||
|
ALTER TABLE "rfidTags" ALTER COLUMN "counts" DROP NOT NULL;
|
||||||
4
database/migrations/0021_premium_albert_cleary.sql
Normal file
4
database/migrations/0021_premium_albert_cleary.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE "rfidTags" ALTER COLUMN "runningNumber" SET DATA TYPE integer;--> statement-breakpoint
|
||||||
|
ALTER TABLE "rfidTags" ALTER COLUMN "runningNumber" DROP NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "rfidTags" ALTER COLUMN "antenna" SET DATA TYPE integer;--> statement-breakpoint
|
||||||
|
ALTER TABLE "rfidTags" ALTER COLUMN "tagStrength" SET DATA TYPE integer;
|
||||||
1
database/migrations/0022_amused_true_believers.sql
Normal file
1
database/migrations/0022_amused_true_believers.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "rfidReaders" ADD COLUMN "lastTiggerGood" boolean DEFAULT true;
|
||||||
2
database/migrations/0023_wealthy_marvel_boy.sql
Normal file
2
database/migrations/0023_wealthy_marvel_boy.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "logs" ADD COLUMN "checked" boolean DEFAULT false;--> statement-breakpoint
|
||||||
|
ALTER TABLE "logs" ADD COLUMN "checkedAt" timestamp;
|
||||||
9
database/migrations/0024_curved_venom.sql
Normal file
9
database/migrations/0024_curved_venom.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE "manualPrinting" (
|
||||||
|
"print_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"line" integer,
|
||||||
|
"printReason" text NOT NULL,
|
||||||
|
"initials" text NOT NULL,
|
||||||
|
"additionalComments" text NOT NULL,
|
||||||
|
"add_date" timestamp DEFAULT now(),
|
||||||
|
"add_user" text
|
||||||
|
);
|
||||||
2
database/migrations/0025_amusing_sugar_man.sql
Normal file
2
database/migrations/0025_amusing_sugar_man.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DROP TABLE "apiHits" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TABLE "eom" CASCADE;
|
||||||
1033
database/migrations/meta/0015_snapshot.json
Normal file
1033
database/migrations/meta/0015_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1040
database/migrations/meta/0016_snapshot.json
Normal file
1040
database/migrations/meta/0016_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1047
database/migrations/meta/0017_snapshot.json
Normal file
1047
database/migrations/meta/0017_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1054
database/migrations/meta/0018_snapshot.json
Normal file
1054
database/migrations/meta/0018_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1066
database/migrations/meta/0019_snapshot.json
Normal file
1066
database/migrations/meta/0019_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1067
database/migrations/meta/0020_snapshot.json
Normal file
1067
database/migrations/meta/0020_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1067
database/migrations/meta/0021_snapshot.json
Normal file
1067
database/migrations/meta/0021_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1074
database/migrations/meta/0022_snapshot.json
Normal file
1074
database/migrations/meta/0022_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1087
database/migrations/meta/0023_snapshot.json
Normal file
1087
database/migrations/meta/0023_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1144
database/migrations/meta/0024_snapshot.json
Normal file
1144
database/migrations/meta/0024_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1056
database/migrations/meta/0025_snapshot.json
Normal file
1056
database/migrations/meta/0025_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -106,6 +106,83 @@
|
|||||||
"when": 1741892067501,
|
"when": 1741892067501,
|
||||||
"tag": "0014_illegal_thundra",
|
"tag": "0014_illegal_thundra",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 15,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1741952150913,
|
||||||
|
"tag": "0015_wonderful_lady_vermin",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 16,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742051878587,
|
||||||
|
"tag": "0016_wet_doctor_strange",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 17,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742133439717,
|
||||||
|
"tag": "0017_bitter_brood",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 18,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742133828291,
|
||||||
|
"tag": "0018_lovely_landau",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 19,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742139737945,
|
||||||
|
"tag": "0019_greedy_justice",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 20,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742143798267,
|
||||||
|
"tag": "0020_empty_thundra",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 21,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742144973347,
|
||||||
|
"tag": "0021_premium_albert_cleary",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 22,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742156466912,
|
||||||
|
"tag": "0022_amused_true_believers",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 23,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742346003832,
|
||||||
|
"tag": "0023_wealthy_marvel_boy",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 24,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742408812383,
|
||||||
|
"tag": "0024_curved_venom",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 25,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1742655504936,
|
||||||
|
"tag": "0025_amusing_sugar_man",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,8 @@ export const logs = pgTable(
|
|||||||
username: text("username").default("LST_Serivce"),
|
username: text("username").default("LST_Serivce"),
|
||||||
service: text("service").notNull().default("system"),
|
service: text("service").notNull().default("system"),
|
||||||
message: text("message").notNull(),
|
message: text("message").notNull(),
|
||||||
|
checked: boolean("checked").default(false),
|
||||||
|
checkedAt: timestamp("checkedAt"),
|
||||||
created_at: timestamp("add_Date").defaultNow(),
|
created_at: timestamp("add_Date").defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
|
|||||||
20
database/schema/ocpManualPrint.ts
Normal file
20
database/schema/ocpManualPrint.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import {text, pgTable, timestamp, uuid, integer} from "drizzle-orm/pg-core";
|
||||||
|
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
||||||
|
import {z} from "zod";
|
||||||
|
|
||||||
|
export const manualPrinting = pgTable("manualPrinting", {
|
||||||
|
print_id: uuid("print_id").defaultRandom().primaryKey(),
|
||||||
|
line: integer("line"),
|
||||||
|
printReason: text("printReason").notNull(),
|
||||||
|
initials: text("initials").notNull(),
|
||||||
|
additionalComments: text("additionalComments").notNull(),
|
||||||
|
add_date: timestamp("add_date").defaultNow(),
|
||||||
|
add_user: text("add_user"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Schema for inserting a user - can be used to validate API requests
|
||||||
|
// export const insertRolesSchema = createInsertSchema(roles, {
|
||||||
|
// name: z.string().min(3, {message: "Role name must be more than 3 letters"}),
|
||||||
|
// });
|
||||||
|
// Schema for selecting a Expenses - can be used to validate API responses
|
||||||
|
export const selectRolesSchema = createSelectSchema(manualPrinting);
|
||||||
@@ -9,6 +9,9 @@ export const rfidReaders = pgTable(
|
|||||||
reader: text("reader"),
|
reader: text("reader"),
|
||||||
readerIP: text("readerIP"),
|
readerIP: text("readerIP"),
|
||||||
lastHeartBeat: timestamp("lastHeartBeat").defaultNow(),
|
lastHeartBeat: timestamp("lastHeartBeat").defaultNow(),
|
||||||
|
lastTrigger: timestamp("lastTrigger").defaultNow(),
|
||||||
|
lastTriggerGood: boolean("lastTiggerGood").default(true),
|
||||||
|
active: boolean("active").default(true),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex, jsonb} from "drizzle-orm/pg-core";
|
import {text, pgTable, timestamp, uuid, uniqueIndex, jsonb, integer} from "drizzle-orm/pg-core";
|
||||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
|
|
||||||
@@ -9,9 +9,11 @@ export const rfidTags = pgTable(
|
|||||||
tagHex: text("tagHex"),
|
tagHex: text("tagHex"),
|
||||||
tag: text("tag"),
|
tag: text("tag"),
|
||||||
lastRead: timestamp("timeStamp").defaultNow(),
|
lastRead: timestamp("timeStamp").defaultNow(),
|
||||||
counts: jsonb("counts").notNull(), //.default([{area: 1, timesHere: 5}]).notNull(),
|
counts: jsonb("counts").default([]), // example [{area: Line3.2, count: 1}, {area: line3.1, count: 6}]
|
||||||
lastareaIn: text("lastareaIn").notNull(),
|
lastareaIn: text("lastareaIn").notNull(),
|
||||||
runningNumber: numeric("runningNumber").notNull(),
|
runningNumber: integer("runningNumber"),
|
||||||
|
antenna: integer("antenna"),
|
||||||
|
tagStrength: integer("tagStrength"),
|
||||||
created_at: timestamp("created_at").defaultNow(),
|
created_at: timestamp("created_at").defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
@@ -21,8 +23,8 @@ export const rfidTags = pgTable(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Schema for inserting a user - can be used to validate API requests
|
// Schema for inserting a user - can be used to validate API requests
|
||||||
// export const insertRolesSchema = createInsertSchema(roles, {
|
export const insertRolesSchema = createInsertSchema(rfidTags, {
|
||||||
// name: z.string().min(3, {message: "Role name must be more than 3 letters"}),
|
tagHex: z.string().min(3, {message: "Tag Should have more than 3 characters"}),
|
||||||
// });
|
});
|
||||||
// Schema for selecting a Expenses - can be used to validate API responses
|
// Schema for selecting a Expenses - can be used to validate API responses
|
||||||
export const selectRolesSchema = createSelectSchema(rfidTags);
|
export const selectRolesSchema = createSelectSchema(rfidTags);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export const serverData = pgTable(
|
|||||||
shippingHours: text("shippingHours").default('[{"early": "06:30", "late": "23:00"}]'),
|
shippingHours: text("shippingHours").default('[{"early": "06:30", "late": "23:00"}]'),
|
||||||
tiPostTime: text("tiPostTime").default('[{"from": "24", "to": "24"}]'),
|
tiPostTime: text("tiPostTime").default('[{"from": "24", "to": "24"}]'),
|
||||||
otherSettings: jsonb("otherSettings").default([{specialInstructions: "something for ti", active: false}]),
|
otherSettings: jsonb("otherSettings").default([{specialInstructions: "something for ti", active: false}]),
|
||||||
|
isUpgrading: boolean("isUpgrading").default(false),
|
||||||
},
|
},
|
||||||
|
|
||||||
(table) => [
|
(table) => [
|
||||||
|
|||||||
842
frontend/package-lock.json
generated
842
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -8,10 +8,11 @@
|
|||||||
"build": "rimraf dist && tsc -b && vite build",
|
"build": "rimraf dist && tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"shad": "npx shadcn@canary add "
|
"shad": "npx shadcn@canary add ",
|
||||||
|
"checkupdates": "npm-check-updates"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^4.1.2",
|
"@hookform/resolvers": "^4.1.3",
|
||||||
"@radix-ui/react-avatar": "^1.1.3",
|
"@radix-ui/react-avatar": "^1.1.3",
|
||||||
"@radix-ui/react-checkbox": "^1.1.4",
|
"@radix-ui/react-checkbox": "^1.1.4",
|
||||||
"@radix-ui/react-collapsible": "^1.1.3",
|
"@radix-ui/react-collapsible": "^1.1.3",
|
||||||
@@ -19,49 +20,52 @@
|
|||||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.2",
|
||||||
"@radix-ui/react-popover": "^1.1.6",
|
"@radix-ui/react-popover": "^1.1.6",
|
||||||
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-tabs": "^1.1.3",
|
"@radix-ui/react-tabs": "^1.1.3",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
"@tailwindcss/vite": "^4.0.9",
|
"@tailwindcss/vite": "^4.0.15",
|
||||||
"@tanstack/react-query": "^5.66.9",
|
"@tanstack/react-query": "^5.69.0",
|
||||||
"@tanstack/react-router": "^1.111.11",
|
"@tanstack/react-router": "^1.114.27",
|
||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
"date-fns-tz": "^3.2.0",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"hono": "^4.7.2",
|
"hono": "^4.7.5",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lucide-react": "^0.476.0",
|
"lucide-react": "^0.483.0",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.6",
|
||||||
|
"npm-check-updates": "^17.1.16",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-grid-layout": "^1.5.0",
|
"react-grid-layout": "^1.5.1",
|
||||||
"react-hook-form": "^7.54.2",
|
"react-hook-form": "^7.54.2",
|
||||||
"sonner": "^2.0.1",
|
"sonner": "^2.0.1",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
"tailwindcss": "^4.0.9",
|
"tailwindcss": "^4.0.15",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod": "^3.24.2",
|
"zod": "^3.24.2",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.21.0",
|
"@eslint/js": "^9.23.0",
|
||||||
"@tanstack/router-devtools": "^1.106.0",
|
"@tanstack/router-devtools": "^1.114.27",
|
||||||
"@tanstack/router-plugin": "^1.106.0",
|
"@tanstack/router-plugin": "^1.114.27",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.0.12",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@types/react-grid-layout": "^1.3.5",
|
"@types/react-grid-layout": "^1.3.5",
|
||||||
"@vitejs/plugin-react-swc": "^3.8.0",
|
"@vitejs/plugin-react-swc": "^3.8.1",
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-plugin-react-hooks": "^5.0.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^15.15.0",
|
"globals": "^16.0.0",
|
||||||
"typescript": "~5.7.2",
|
"typescript": "~5.8.2",
|
||||||
"typescript-eslint": "^8.24.1",
|
"typescript-eslint": "^8.27.0",
|
||||||
"vite": "^6.2.0"
|
"vite": "^6.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
frontend/src/components/admin/servers/RestartServer.tsx
Normal file
22
frontend/src/components/admin/servers/RestartServer.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
|
||||||
|
import {RotateCcw} from "lucide-react";
|
||||||
|
|
||||||
|
export default function RestartServer() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button variant={"outline"} size={"icon"}>
|
||||||
|
<RotateCcw />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>Restart Server ... Needs added still</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
125
frontend/src/components/admin/servers/ServerPage.tsx
Normal file
125
frontend/src/components/admin/servers/ServerPage.tsx
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import { useSessionStore } from "@/lib/store/sessionStore";
|
||||||
|
import { useModuleStore } from "@/lib/store/useModuleStore";
|
||||||
|
import { getServers } from "@/utils/querys/servers";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useRouter } from "@tanstack/react-router";
|
||||||
|
import { format } from "date-fns";
|
||||||
|
import UpdateServer from "./UpdateServer";
|
||||||
|
import { adminUrlCheck } from "@/utils/adminUrlCheck";
|
||||||
|
import RestartServer from "./RestartServer";
|
||||||
|
import StopServer from "./StopServer";
|
||||||
|
import StartServer from "./StartServer";
|
||||||
|
|
||||||
|
export type Servers = {
|
||||||
|
server_id?: string;
|
||||||
|
sName?: string;
|
||||||
|
serverDNS?: string;
|
||||||
|
plantToken?: string;
|
||||||
|
idAddress: string;
|
||||||
|
lastUpdated: string;
|
||||||
|
isUpgrading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ServerPage() {
|
||||||
|
const { user, token } = useSessionStore();
|
||||||
|
const { modules } = useModuleStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { data, isError, error, isLoading } = useQuery(getServers(token ?? ""));
|
||||||
|
|
||||||
|
const adminModule = modules.filter((n) => n.name === "admin");
|
||||||
|
const userLevel =
|
||||||
|
user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) || [];
|
||||||
|
|
||||||
|
if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
|
||||||
|
router.navigate({ to: "/" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
return <div>{JSON.stringify(error)}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
return (
|
||||||
|
<LstCard className="m-2 flex place-content-center w-dvh">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead>Name</TableHead>
|
||||||
|
<TableHead>Server</TableHead>
|
||||||
|
<TableHead>PlantToken</TableHead>
|
||||||
|
<TableHead>IP Address</TableHead>
|
||||||
|
<TableHead>Date Last updated</TableHead>
|
||||||
|
<TableHead>Update Server</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<TableBody>
|
||||||
|
{Array(10)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<TableBody>
|
||||||
|
{data?.map((server: Servers) => {
|
||||||
|
const strippedDate = server.lastUpdated.replace("Z", ""); // Remove Z
|
||||||
|
const formattedDate = format(strippedDate, "MM/dd/yyyy hh:mm a");
|
||||||
|
return (
|
||||||
|
<TableRow key={server.server_id}>
|
||||||
|
<TableCell className="font-medium">{server.sName}</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{server.serverDNS}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{server.plantToken}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{server.idAddress}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">{formattedDate}</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{adminUrlCheck() && (
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<UpdateServer server={server} token={token as string} />
|
||||||
|
<StartServer />
|
||||||
|
<StopServer />
|
||||||
|
<RestartServer />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableBody>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
</LstCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
22
frontend/src/components/admin/servers/StartServer.tsx
Normal file
22
frontend/src/components/admin/servers/StartServer.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
|
||||||
|
import {Play} from "lucide-react";
|
||||||
|
|
||||||
|
export default function StartServer() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button variant={"outline"} size={"icon"}>
|
||||||
|
<Play />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>Start Server ... Needs added still</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
22
frontend/src/components/admin/servers/StopServer.tsx
Normal file
22
frontend/src/components/admin/servers/StopServer.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
|
||||||
|
import {Octagon} from "lucide-react";
|
||||||
|
|
||||||
|
export default function StopServer() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button variant={"outline"} size={"icon"}>
|
||||||
|
<Octagon />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>Stop Server ... Needs added still</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
51
frontend/src/components/admin/servers/UpdateServer.tsx
Normal file
51
frontend/src/components/admin/servers/UpdateServer.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import {CircleFadingArrowUp} from "lucide-react";
|
||||||
|
import {toast} from "sonner";
|
||||||
|
import {Servers} from "./ServerPage";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {getSettings} from "@/utils/querys/settings";
|
||||||
|
import axios from "axios";
|
||||||
|
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
|
||||||
|
|
||||||
|
export default function UpdateServer({server, token}: {server: Servers; token: string}) {
|
||||||
|
const {data} = useQuery(getSettings(token ?? ""));
|
||||||
|
const upgrade = async () => {
|
||||||
|
let devDir = data.filter((n: any) => n.name === "devDir");
|
||||||
|
toast.success("Server being upgraded in the background please wait.");
|
||||||
|
try {
|
||||||
|
const result = await axios.post(
|
||||||
|
`/api/server/update/${server.plantToken}`,
|
||||||
|
{devDir: devDir[0].value},
|
||||||
|
{
|
||||||
|
headers: {Authorization: `Bearer ${token}`},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.data.success) {
|
||||||
|
toast.success(result.data.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.data.success) {
|
||||||
|
toast.success(result.data.message);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(`There was an error updating the server: ${error.data.message}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button variant={"outline"} size={"icon"} onClick={upgrade} disabled={server.isUpgrading}>
|
||||||
|
<CircleFadingArrowUp />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>Update {server.sName}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||||
import {Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||||
import {useModuleStore} from "@/lib/store/useModuleStore";
|
import {useModuleStore} from "@/lib/store/useModuleStore";
|
||||||
import {useQuery} from "@tanstack/react-query";
|
import {useQuery} from "@tanstack/react-query";
|
||||||
@@ -37,9 +37,8 @@ export default function SettingsPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LstCard className="m-2 flex place-content-center w-dvh">
|
<LstCard className="m-2 flex place-content-center w-fit">
|
||||||
<Table>
|
<Table>
|
||||||
<TableCaption>All Settings</TableCaption>
|
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Name</TableHead>
|
<TableHead>Name</TableHead>
|
||||||
|
|||||||
@@ -1,143 +1,164 @@
|
|||||||
import {useSessionStore} from "../../lib/store/sessionStore";
|
import { useSessionStore } from "../../lib/store/sessionStore";
|
||||||
import {LstCard} from "../extendedUI/LstCard";
|
import { LstCard } from "../extendedUI/LstCard";
|
||||||
import {CardHeader} from "../ui/card";
|
import { CardHeader } from "../ui/card";
|
||||||
import {toast} from "sonner";
|
import { toast } from "sonner";
|
||||||
import {z} from "zod";
|
import { z } from "zod";
|
||||||
import {useRouter} from "@tanstack/react-router";
|
import { useRouter } from "@tanstack/react-router";
|
||||||
import {Controller, useForm} from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import {zodResolver} from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import {Label} from "../ui/label";
|
import { Label } from "../ui/label";
|
||||||
import {Input} from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
import {Checkbox} from "../ui/checkbox";
|
import { Checkbox } from "../ui/checkbox";
|
||||||
import {Button} from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
username: z.string().min(1, "You must enter a valid username"),
|
username: z.string().min(1, "You must enter a valid username"),
|
||||||
password: z.string().min(4, "You must enter a valid password"),
|
password: z.string().min(4, "You must enter a valid password"),
|
||||||
rememberMe: z.boolean(),
|
rememberMe: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const LoginForm = () => {
|
const LoginForm = () => {
|
||||||
const {setSession} = useSessionStore();
|
const { setSession } = useSessionStore();
|
||||||
const rememeberMe = localStorage.getItem("rememberMe") === "true";
|
const rememeberMe = localStorage.getItem("rememberMe") === "true";
|
||||||
const username = localStorage.getItem("username") || "";
|
const username = localStorage.getItem("username") || "";
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
formState: {errors},
|
formState: { errors },
|
||||||
} = useForm<z.infer<typeof FormSchema>>({
|
} = useForm<z.infer<typeof FormSchema>>({
|
||||||
resolver: zodResolver(FormSchema),
|
resolver: zodResolver(FormSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
username: username || "",
|
username: username || "",
|
||||||
password: "",
|
password: "",
|
||||||
rememberMe: rememeberMe,
|
rememberMe: rememeberMe,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => {
|
||||||
|
// Do something with form data
|
||||||
|
|
||||||
|
// first update the rememberMe incase it was selected
|
||||||
|
if (value.rememberMe) {
|
||||||
|
localStorage.setItem("rememberMe", value.rememberMe.toString());
|
||||||
|
localStorage.setItem("username", value.username);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("rememberMe");
|
||||||
|
localStorage.removeItem("username");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/auth/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
});
|
body: JSON.stringify({
|
||||||
|
username: value.username,
|
||||||
|
password: value.password,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => {
|
const data = await response.json();
|
||||||
// Do something with form data
|
|
||||||
|
|
||||||
// first update the rememberMe incase it was selected
|
// Store token in localStorage
|
||||||
if (value.rememberMe) {
|
// localStorage.setItem("auth_token", data.data.token);
|
||||||
localStorage.setItem("rememberMe", value.rememberMe.toString());
|
if (data.success) {
|
||||||
localStorage.setItem("username", value.username);
|
const prod = btoa(`${value.username.toLowerCase()}:${value.password}`);
|
||||||
} else {
|
const prodUser = { ...data.user, prod: prod };
|
||||||
localStorage.removeItem("rememberMe");
|
|
||||||
localStorage.removeItem("username");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
setSession(prodUser, data.token);
|
||||||
const response = await fetch("/api/auth/login", {
|
toast.success(`You are logged in as ${data.user.username}`);
|
||||||
method: "POST",
|
router.navigate({ to: "/" });
|
||||||
headers: {
|
}
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({username: value.username, password: value.password}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
if (!data.success) {
|
||||||
|
toast.error(`${data.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Store token in localStorage
|
//console.log(data);
|
||||||
// localStorage.setItem("auth_token", data.data.token);
|
} catch (err) {
|
||||||
|
toast.error("Invalid credentials");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
setSession(data.user, data.token);
|
return (
|
||||||
toast.success(`You are logged in as ${data.user.username}`);
|
<div className="ml-[25%]">
|
||||||
router.navigate({to: "/"});
|
<LstCard className="p-3 w-96">
|
||||||
} catch (err) {
|
<CardHeader>
|
||||||
toast.error("Invalid credentials");
|
<div>
|
||||||
}
|
<p className="text-2xl">Login to LST</p>
|
||||||
};
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<hr className="rounded"></hr>
|
||||||
|
<form onSubmit={handleSubmit(onSubmitLogin)}>
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="username" className="m-1">
|
||||||
|
Username
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
placeholder="smith001"
|
||||||
|
{...register("username")}
|
||||||
|
className={errors.username ? "border-red-500" : ""}
|
||||||
|
aria-invalid={!!errors.username}
|
||||||
|
/>
|
||||||
|
{errors.username && (
|
||||||
|
<p className="text-red-500 text-sm mt-1">
|
||||||
|
{errors.username.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<>
|
||||||
|
<Label htmlFor={"password"} className="m-1">
|
||||||
|
Password
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
{...register("password")}
|
||||||
|
className={errors.password ? "border-red-500" : ""}
|
||||||
|
aria-invalid={!!errors.password}
|
||||||
|
/>
|
||||||
|
{errors.password && (
|
||||||
|
<p className="text-red-500 text-sm mt-1">
|
||||||
|
{errors.password.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between pt-2">
|
||||||
|
<div className="flex">
|
||||||
|
<Controller
|
||||||
|
render={({ field }) => (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
id="remember"
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="remember"
|
||||||
|
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||||
|
>
|
||||||
|
remember me
|
||||||
|
</label>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
control={control}
|
||||||
|
name="rememberMe"
|
||||||
|
defaultValue={rememeberMe}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
return (
|
<div className="flex justify-end">
|
||||||
<div className="ml-[25%]">
|
<Button type="submit">Submit</Button>
|
||||||
<LstCard className="p-3 w-96">
|
</div>
|
||||||
<CardHeader>
|
</div>
|
||||||
<div>
|
</form>
|
||||||
<p className="text-2xl">Login to LST</p>
|
</LstCard>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
);
|
||||||
<hr className="rounded"></hr>
|
|
||||||
<form onSubmit={handleSubmit(onSubmitLogin)}>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="username" className="m-1">
|
|
||||||
Username
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
placeholder="smith001"
|
|
||||||
{...register("username")}
|
|
||||||
className={errors.username ? "border-red-500" : ""}
|
|
||||||
aria-invalid={!!errors.username}
|
|
||||||
/>
|
|
||||||
{errors.username && <p className="text-red-500 text-sm mt-1">{errors.username.message}</p>}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<>
|
|
||||||
<Label htmlFor={"password"} className="m-1">
|
|
||||||
Password
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
type="password"
|
|
||||||
{...register("password")}
|
|
||||||
className={errors.password ? "border-red-500" : ""}
|
|
||||||
aria-invalid={!!errors.password}
|
|
||||||
/>
|
|
||||||
{errors.password && <p className="text-red-500 text-sm mt-1">{errors.password.message}</p>}
|
|
||||||
</>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-between pt-2">
|
|
||||||
<div className="flex">
|
|
||||||
<Controller
|
|
||||||
render={({field}) => (
|
|
||||||
<>
|
|
||||||
<Checkbox
|
|
||||||
id="remember"
|
|
||||||
checked={field.value}
|
|
||||||
onCheckedChange={field.onChange}
|
|
||||||
/>
|
|
||||||
<label
|
|
||||||
htmlFor="remember"
|
|
||||||
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
||||||
>
|
|
||||||
remember me
|
|
||||||
</label>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
control={control}
|
|
||||||
name="rememberMe"
|
|
||||||
defaultValue={rememeberMe}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-end">
|
|
||||||
<Button type="submit">Submit</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</LstCard>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LoginForm;
|
export default LoginForm;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {Collapsible, CollapsibleContent, CollapsibleTrigger} from "../../ui/coll
|
|||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
title: "Servers",
|
title: "Servers",
|
||||||
url: "#",
|
url: "/servers",
|
||||||
icon: Server,
|
icon: Server,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
},
|
},
|
||||||
@@ -31,13 +31,19 @@ const data = {
|
|||||||
title: "Settings",
|
title: "Settings",
|
||||||
url: "/settings",
|
url: "/settings",
|
||||||
icon: Settings,
|
icon: Settings,
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Modules",
|
||||||
|
url: "/modules",
|
||||||
|
icon: Settings,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Swagger",
|
title: "Swagger",
|
||||||
url: "#",
|
url: "#",
|
||||||
icon: Webhook,
|
icon: Webhook,
|
||||||
isActive: false,
|
isActive: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Logs",
|
title: "Logs",
|
||||||
@@ -91,12 +97,17 @@ export function AdminSideBar() {
|
|||||||
<SidebarMenuSub>
|
<SidebarMenuSub>
|
||||||
{item.items.map((item) => (
|
{item.items.map((item) => (
|
||||||
<SidebarMenuSubItem key={item.title}>
|
<SidebarMenuSubItem key={item.title}>
|
||||||
<SidebarMenuSubButton asChild isActive={item.isActive}>
|
{item.isActive && (
|
||||||
<a href={item.url} target={item.newWindow ? "_blank" : "_self"}>
|
<SidebarMenuSubButton asChild>
|
||||||
<item.icon />
|
<a
|
||||||
<span>{item.title}</span>
|
href={item.url}
|
||||||
</a>
|
target={item.newWindow ? "_blank" : "_self"}
|
||||||
</SidebarMenuSubButton>
|
>
|
||||||
|
<item.icon />
|
||||||
|
<span>{item.title}</span>
|
||||||
|
</a>
|
||||||
|
</SidebarMenuSubButton>
|
||||||
|
)}
|
||||||
</SidebarMenuSubItem>
|
</SidebarMenuSubItem>
|
||||||
))}
|
))}
|
||||||
</SidebarMenuSub>
|
</SidebarMenuSub>
|
||||||
|
|||||||
@@ -51,6 +51,14 @@ const items = [
|
|||||||
module: "logistics",
|
module: "logistics",
|
||||||
active: true,
|
active: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Ocme Cyclecount",
|
||||||
|
url: "/cyclecount",
|
||||||
|
icon: Package,
|
||||||
|
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||||
|
module: "logistics",
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function LogisticsSideBar({user, moduleID}: {user: User | null; moduleID: string}) {
|
export function LogisticsSideBar({user, moduleID}: {user: User | null; moduleID: string}) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const items = [
|
|||||||
title: "One Click Print",
|
title: "One Click Print",
|
||||||
url: "/ocp",
|
url: "/ocp",
|
||||||
icon: Printer,
|
icon: Printer,
|
||||||
role: ["systemAdmin"],
|
role: ["viewer"],
|
||||||
module: "ocp",
|
module: "ocp",
|
||||||
active: true,
|
active: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {Button} from "@/components/ui/button";
|
|||||||
import {CardHeader} from "@/components/ui/card";
|
import {CardHeader} from "@/components/ui/card";
|
||||||
import {Input} from "@/components/ui/input";
|
import {Input} from "@/components/ui/input";
|
||||||
import {Label} from "@/components/ui/label";
|
import {Label} from "@/components/ui/label";
|
||||||
|
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
|
|
||||||
@@ -12,27 +13,28 @@ import {toast} from "sonner";
|
|||||||
export default function ConsumeMaterial() {
|
export default function ConsumeMaterial() {
|
||||||
const {register: register1, handleSubmit: handleSubmit1, reset} = useForm();
|
const {register: register1, handleSubmit: handleSubmit1, reset} = useForm();
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const token = localStorage.getItem("auth_token");
|
const {token} = useSessionStore();
|
||||||
|
|
||||||
const handleConsume = async (data: any) => {
|
const handleConsume = async (data: any) => {
|
||||||
setSubmitting(!submitting);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
const result = await axios.post(`/api/logistics/consume`, data, {
|
const result = await axios.post(`/api/logistics/consume`, data, {
|
||||||
headers: {Authorization: `Bearer ${token}`},
|
headers: {Authorization: `Bearer ${token}`},
|
||||||
});
|
});
|
||||||
if (result.data.success) {
|
if (result.data.success) {
|
||||||
toast.success(result.data.message);
|
toast.success(result.data.message);
|
||||||
setSubmitting(!submitting);
|
setSubmitting(false);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
if (!result.data.success) {
|
if (!result.data.success) {
|
||||||
//console.log(result.data);
|
//console.log(result.data);
|
||||||
setSubmitting(!submitting);
|
setSubmitting(false);
|
||||||
|
|
||||||
toast.error(result.data.message);
|
toast.error(result.data.message);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
//console.log(error);
|
//console.log(error);
|
||||||
setSubmitting(!submitting);
|
setSubmitting(false);
|
||||||
if (error.status === 401) {
|
if (error.status === 401) {
|
||||||
toast.error("Unauthorized to do this task.");
|
toast.error("Unauthorized to do this task.");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
71
frontend/src/components/ocme/CycleCountLog.tsx
Normal file
71
frontend/src/components/ocme/CycleCountLog.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* we will do a very sloppy way for this just keep fetching the logs we spent to much time on this :()
|
||||||
|
*/
|
||||||
|
|
||||||
|
// //import {useEffect, useState} from "react";
|
||||||
|
// import {LstCard} from "../extendedUI/LstCard";
|
||||||
|
// import {CardContent, CardHeader} from "../ui/card";
|
||||||
|
// import {Skeleton} from "../ui/skeleton";
|
||||||
|
// import {Button} from "../ui/button";
|
||||||
|
// import {toast} from "sonner";
|
||||||
|
// import {useEffect} from "react";
|
||||||
|
|
||||||
|
// export default function CycleCountLog() {
|
||||||
|
// //const [logs, setLogs] = useState([]);
|
||||||
|
// //const [streaming, setStreaming] = useState(false); // Track if streaming is active
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// // Start streaming when the button is clicked
|
||||||
|
// let es;
|
||||||
|
|
||||||
|
// const url = `http://localhost:4000/api/logger/logs/stream?service=ocme-count&level=info`;
|
||||||
|
|
||||||
|
// es = new EventSource(url);
|
||||||
|
// es.onopen = () => console.log(">>> Connection opened!");
|
||||||
|
// es.onerror = (e) => console.log("ERROR!", e);
|
||||||
|
// es.onmessage = (e) => {
|
||||||
|
// const data = JSON.parse(e.data);
|
||||||
|
|
||||||
|
// console.log(e);
|
||||||
|
// console.log(data);
|
||||||
|
// switch (data.type) {
|
||||||
|
// case "time-update":
|
||||||
|
// console.log(data);
|
||||||
|
// break;
|
||||||
|
// case "error":
|
||||||
|
// console.log(data);
|
||||||
|
// break;
|
||||||
|
// case "done":
|
||||||
|
// console.log(data);
|
||||||
|
// es.close(); // Close the connection when done
|
||||||
|
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// return () => es.close();
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
// // const handleStartStreaming = () => {
|
||||||
|
// // setStreaming(true); // Start streaming when button is clicked
|
||||||
|
// // };
|
||||||
|
// return (
|
||||||
|
// <LstCard className="w-48">
|
||||||
|
// <CardHeader className="flex justify-center">
|
||||||
|
// <span>Cycle Count logs</span>
|
||||||
|
// </CardHeader>
|
||||||
|
// <CardContent>
|
||||||
|
// {Array(10)
|
||||||
|
// .fill(0)
|
||||||
|
// .map((_, i) => (
|
||||||
|
// <div key={i}>
|
||||||
|
// <Skeleton className="m-2 h-4" />
|
||||||
|
// </div>
|
||||||
|
// ))}
|
||||||
|
// </CardContent>
|
||||||
|
// <Button onClick={() => toast.success("SOmething")}>Start Stream</Button>
|
||||||
|
// </LstCard>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
185
frontend/src/components/ocme/ocmeCycleCount.tsx
Normal file
185
frontend/src/components/ocme/ocmeCycleCount.tsx
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
import {toast} from "sonner";
|
||||||
|
import {LstCard} from "../extendedUI/LstCard";
|
||||||
|
import {Button} from "../ui/button";
|
||||||
|
import {Input} from "../ui/input";
|
||||||
|
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "../ui/table";
|
||||||
|
import {Skeleton} from "../ui/skeleton";
|
||||||
|
//import CycleCountLog from "./CycleCountLog";
|
||||||
|
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "../ui/select";
|
||||||
|
import {Controller, useForm} from "react-hook-form";
|
||||||
|
import axios from "axios";
|
||||||
|
import {useState} from "react";
|
||||||
|
|
||||||
|
export default function OcmeCycleCount() {
|
||||||
|
const token = localStorage.getItem("auth_token");
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
const [counting, setCounting] = useState(false);
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
//watch,
|
||||||
|
formState: {errors},
|
||||||
|
reset,
|
||||||
|
control,
|
||||||
|
} = useForm();
|
||||||
|
|
||||||
|
const onSubmit = async (data: any) => {
|
||||||
|
setData([]);
|
||||||
|
setCounting(true);
|
||||||
|
toast.success(`Cycle count started`);
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/ocme/api/v1/cyclecount", data, {
|
||||||
|
headers: {Authorization: `Bearer ${token}`},
|
||||||
|
});
|
||||||
|
toast.success(res.data.message);
|
||||||
|
setData(res.data.data);
|
||||||
|
setCounting(false);
|
||||||
|
reset();
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("There was an error cycle counting");
|
||||||
|
setCounting(false);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="flex flex-row w-screen">
|
||||||
|
<div className="m-2 w-5/6">
|
||||||
|
<LstCard>
|
||||||
|
<p className="ml-2">Please enter the name or laneID you want to cycle count.</p>
|
||||||
|
<div>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<div className="m-2 flex flex-row">
|
||||||
|
<Input
|
||||||
|
placeholder="enter lane: L064"
|
||||||
|
className={errors.lane ? "border-red-500" : ""}
|
||||||
|
aria-invalid={!!errors.lane}
|
||||||
|
{...register("lane", {
|
||||||
|
required: true,
|
||||||
|
minLength: {
|
||||||
|
value: 3,
|
||||||
|
message: "The lane is too short!",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<div className="ml-2">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="laneType"
|
||||||
|
defaultValue={""}
|
||||||
|
render={({
|
||||||
|
field: {onChange},
|
||||||
|
fieldState: {},
|
||||||
|
//formState,
|
||||||
|
}) => (
|
||||||
|
<Select onValueChange={onChange}>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue placeholder="Select name or id" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="name">Name</SelectItem>
|
||||||
|
<SelectItem value="laneId">Lane ID</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button className="m-2" type="submit" disabled={counting}>
|
||||||
|
{counting ? <span>Counting...</span> : <span>CycleCount</span>}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead>LaneID</TableHead>
|
||||||
|
<TableHead>Lane</TableHead>
|
||||||
|
<TableHead>AV</TableHead>
|
||||||
|
<TableHead>Description</TableHead>
|
||||||
|
<TableHead>Running Number</TableHead>
|
||||||
|
<TableHead>In Ocme</TableHead>
|
||||||
|
<TableHead>In Stock</TableHead>
|
||||||
|
<TableHead>Result</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
{data.length === 0 ? (
|
||||||
|
<TableBody>
|
||||||
|
{Array(10)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{data.map((i: any) => {
|
||||||
|
let classname = ``;
|
||||||
|
if (i.info === "Quality Check Required") {
|
||||||
|
classname = `bg-red-500`;
|
||||||
|
}
|
||||||
|
if (i.info === "Sent to Inv") {
|
||||||
|
classname = `bg-amber-700`;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TableRow key={i.runningNumber}>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>
|
||||||
|
{i.alpla_laneID}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>
|
||||||
|
{i.alpla_laneDescription}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>
|
||||||
|
{i.Article}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>
|
||||||
|
{i.alpla_laneDescription}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>
|
||||||
|
{i.runningNumber}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>{i.ocme}</TableCell>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>{i.stock}</TableCell>
|
||||||
|
<TableCell className={`font-medium ${classname}`}>{i.info}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
{/* <div className="m-2">
|
||||||
|
<CycleCountLog />
|
||||||
|
</div> */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,125 @@
|
|||||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||||
|
|
||||||
|
import {Skeleton} from "@/components/ui/skeleton";
|
||||||
|
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
// import {useSessionStore} from "@/lib/store/sessionStore";
|
||||||
|
// import {useSettingStore} from "@/lib/store/useSettings";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import {getlabels} from "@/utils/querys/production/labels";
|
||||||
|
import {format} from "date-fns";
|
||||||
|
|
||||||
|
const labelLogs = [
|
||||||
|
{key: "line", label: "Line"},
|
||||||
|
{key: "printerName", label: "Printer"},
|
||||||
|
{key: "runningNr", label: "Running #"},
|
||||||
|
{key: "upd_date", label: "Label date"},
|
||||||
|
{key: "status", label: "Label Status"},
|
||||||
|
//{key: "reprint", label: "Reprint"}, // removing the reprint button for now until repritning is working as intended
|
||||||
|
];
|
||||||
export default function LabelLog() {
|
export default function LabelLog() {
|
||||||
return <LstCard className="m-2 p-2"> label logs here</LstCard>;
|
const {data, isError, isLoading} = useQuery(getlabels("4"));
|
||||||
|
//const {user} = useSessionStore();
|
||||||
|
//const {settings} = useSettingStore();
|
||||||
|
//const server = settings.filter((n) => n.name === "server")[0]?.value || "";
|
||||||
|
|
||||||
|
//const roles = ["admin", "manager", "operator"];
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
return (
|
||||||
|
<div className="m-2 p-2 min-h-2/5">
|
||||||
|
<LstCard>
|
||||||
|
<p className="text-center">Labels for the last 2 hours</p>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{labelLogs.map((l) => (
|
||||||
|
<TableHead key={l.key}>{l.label}</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
|
||||||
|
<TableBody>
|
||||||
|
{Array(7)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LstCard className="m-2 p-2 min-h-2/5">
|
||||||
|
<p className="text-center">Labels for the last 2 hours</p>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{labelLogs.map((l) => (
|
||||||
|
<TableHead key={l.key}>{l.label}</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<TableBody>
|
||||||
|
{Array(7)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<TableBody>
|
||||||
|
{data?.map((label: any) => (
|
||||||
|
<TableRow key={label.runningNr}>
|
||||||
|
<TableCell className="font-medium">{label.line}</TableCell>
|
||||||
|
<TableCell className="font-medium">{label.printerName}</TableCell>
|
||||||
|
<TableCell className="font-medium">{label.runningNr}</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{format(label.upd_date, "M/d/yyyy hh:mm")}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">{label.status}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
|
</LstCard>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,222 @@
|
|||||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||||
|
|
||||||
|
import {Skeleton} from "@/components/ui/skeleton";
|
||||||
|
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||||
|
import {useSettingStore} from "@/lib/store/useSettings";
|
||||||
|
import {LotType} from "@/types/lots";
|
||||||
|
import {getlots} from "@/utils/querys/production/lots";
|
||||||
|
import {useQuery} from "@tanstack/react-query";
|
||||||
|
import ManualPrint from "./ManualPrinting/ManualPrint";
|
||||||
|
import ManualPrintForm from "./ManualPrinting/ManualPrintForm";
|
||||||
|
|
||||||
|
let lotColumns = [
|
||||||
|
{
|
||||||
|
key: "MachineDescription",
|
||||||
|
label: "Machine",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "AV",
|
||||||
|
label: "AV",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Alias",
|
||||||
|
label: "AvDescription",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "LOT",
|
||||||
|
label: "LotNumber",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ProlinkLot",
|
||||||
|
label: "ProlinkLot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "PlannedQTY",
|
||||||
|
label: "PlannedQTY",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Produced",
|
||||||
|
label: "Produced",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Remaining",
|
||||||
|
label: "Remaining",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "overPrinting",
|
||||||
|
label: "Overprinting",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// key: "lastProlinkUpdate",
|
||||||
|
// label: "Last ProlinkCheck",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// key: "printLabel",
|
||||||
|
// label: "Print Label",
|
||||||
|
// },
|
||||||
|
];
|
||||||
export default function Lots() {
|
export default function Lots() {
|
||||||
|
const {data, isError, isLoading} = useQuery(getlots());
|
||||||
|
const {user} = useSessionStore();
|
||||||
|
const {settings} = useSettingStore();
|
||||||
|
const server = settings.filter((n) => n.name === "server")[0]?.value || "";
|
||||||
|
|
||||||
|
console.log(server);
|
||||||
|
|
||||||
|
const roles = ["admin", "manager", "operator"];
|
||||||
|
|
||||||
|
if (user && roles.includes(user.role)) {
|
||||||
|
//width = 1280;
|
||||||
|
const checkCol = lotColumns.some((l) => l.key === "printLabel");
|
||||||
|
if (!checkCol) {
|
||||||
|
lotColumns = [
|
||||||
|
...lotColumns,
|
||||||
|
{
|
||||||
|
key: "printLabel",
|
||||||
|
label: "Print Label",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
return (
|
||||||
|
<div className="m-2 p-2 min-h-2/5">
|
||||||
|
<LstCard>
|
||||||
|
<p className="text-center">Current Assigned lots</p>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{lotColumns.map((l) => (
|
||||||
|
<TableHead key={l.key}>{l.label}</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
|
||||||
|
<TableBody>
|
||||||
|
{Array(10)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LstCard className="m-2 p-2 min-h-2/5">
|
<LstCard className="m-2 p-2 min-h-2/5">
|
||||||
<h1>Lots</h1>
|
<p className="text-center">Current Assigned lots</p>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{lotColumns.map((l) => (
|
||||||
|
<TableHead key={l.key}>{l.label}</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<TableBody>
|
||||||
|
{Array(10)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<TableBody>
|
||||||
|
{data?.map((lot: LotType) => (
|
||||||
|
<TableRow key={lot.LabelOnlineID}>
|
||||||
|
<TableCell className="font-medium">{lot.MachineLocation}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.AV}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.Alias}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.LOT}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.ProlinkLot}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.PlannedQTY}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.Produced}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.Remaining}</TableCell>
|
||||||
|
<TableCell className="font-medium">{lot.overPrinting}</TableCell>
|
||||||
|
{user && roles.includes(user.role) && (
|
||||||
|
<>
|
||||||
|
{server === "usday1vms006" || server === "localhost" ? (
|
||||||
|
<>
|
||||||
|
<TableCell className="flex justify-center">
|
||||||
|
<ManualPrintForm lot={lot} />
|
||||||
|
</TableCell>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<TableCell className="flex justify-center">
|
||||||
|
<ManualPrint lot={lot} />
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
)}
|
||||||
|
</Table>
|
||||||
</LstCard>
|
</LstCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||||
|
//import {useSettingStore} from "@/lib/store/useSettings";
|
||||||
|
import {LotType} from "@/types/lots";
|
||||||
|
import {Tag} from "lucide-react";
|
||||||
|
import {toast} from "sonner";
|
||||||
|
import {manualPrintLabels} from "./ManualPrintLabel";
|
||||||
|
|
||||||
|
export default function ManualPrint({lot}: {lot: LotType}) {
|
||||||
|
const {user} = useSessionStore();
|
||||||
|
//const {settings} = useSettingStore();
|
||||||
|
//const server = settings.filter((n) => n.name === "server")[0]?.value;
|
||||||
|
//const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
|
||||||
|
//const serverUrl = `http://${server}:${serverPort}`;
|
||||||
|
|
||||||
|
const handlePrintLabel = async (lot: LotType) => {
|
||||||
|
//console.log(lot);
|
||||||
|
|
||||||
|
const labels: any = await manualPrintLabels(lot, user);
|
||||||
|
|
||||||
|
if (labels.success) {
|
||||||
|
toast.success(labels.message);
|
||||||
|
} else {
|
||||||
|
toast.error(labels.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Button variant="outline" size="icon" onClick={() => handlePrintLabel(lot)}>
|
||||||
|
<Tag className="h-[16px] w-[16px]" />
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
import {Button} from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import {Input} from "@/components/ui/input";
|
||||||
|
import {Label} from "@/components/ui/label";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectLabel,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import {Textarea} from "@/components/ui/textarea";
|
||||||
|
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||||
|
import {useSettingStore} from "@/lib/store/useSettings";
|
||||||
|
import {LotType} from "@/types/lots";
|
||||||
|
import axios from "axios";
|
||||||
|
import {Tag} from "lucide-react";
|
||||||
|
import {useState} from "react";
|
||||||
|
import {Controller, useForm} from "react-hook-form";
|
||||||
|
import {toast} from "sonner";
|
||||||
|
import {manualPrintLabels} from "./ManualPrintLabel";
|
||||||
|
|
||||||
|
const printReason = [
|
||||||
|
{key: "printerIssue", label: "Printer Related"},
|
||||||
|
{key: "strapper", label: "Strapper Error"},
|
||||||
|
{key: "manualCheck", label: "20th pallet check"},
|
||||||
|
{key: "outOfSync", label: "Labeler Out of Sync"},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function ManualPrintForm({lot}: {lot: LotType}) {
|
||||||
|
const {user} = useSessionStore();
|
||||||
|
const token = localStorage.getItem("auth_token");
|
||||||
|
const {settings} = useSettingStore();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const server = settings.filter((n) => n.name === "server")[0]?.value;
|
||||||
|
// const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
|
||||||
|
// const serverUrl = `http://${server}:${serverPort}`;
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
//watch,
|
||||||
|
formState: {errors},
|
||||||
|
reset,
|
||||||
|
control,
|
||||||
|
} = useForm();
|
||||||
|
|
||||||
|
const handlePrintLabel = async (lot: LotType) => {
|
||||||
|
//console.log(lot);
|
||||||
|
const labels: any = await manualPrintLabels(lot, user);
|
||||||
|
|
||||||
|
if (labels.success) {
|
||||||
|
toast.success(labels.message);
|
||||||
|
} else {
|
||||||
|
toast.error(labels.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleManualPrintLog = async (logData: any, lot: LotType) => {
|
||||||
|
// toast.success(`A new label was sent to printer: ${lot.PrinterName} for line ${lot.MachineDescription} `);
|
||||||
|
const logdataUrl = `/api/ocp/manualLabelLog`;
|
||||||
|
axios
|
||||||
|
.post(logdataUrl, logData, {headers: {Authorization: `Bearer ${token}`}})
|
||||||
|
.then((d) => {
|
||||||
|
//console.log(d);
|
||||||
|
toast.success(d.data.message);
|
||||||
|
handlePrintLabel(lot);
|
||||||
|
reset();
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
if (e.response.status === 500) {
|
||||||
|
toast.error(`Internal Server error please try again.`);
|
||||||
|
return {sucess: false};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.response.status === 401) {
|
||||||
|
//console.log(e.response);
|
||||||
|
toast.error(`You are not authorized to do this.`);
|
||||||
|
return {sucess: false};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSubmit = (data: any) => {
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
handleManualPrintLog(data, lot);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onOpenChange={(isOpen) => {
|
||||||
|
if (!open) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
setOpen(isOpen);
|
||||||
|
// toast.message("Model was something", {
|
||||||
|
// description: isOpen ? "Modal is open" : "Modal is closed",
|
||||||
|
// });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="outline" size="icon">
|
||||||
|
<Tag className="h-[16px] w-[16px]" />
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-[425px]">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Edit profile</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Make changes to your profile here. Click save when you're done.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<p>
|
||||||
|
To manually print a label you must complete all the required fields below.
|
||||||
|
<br />
|
||||||
|
If you clicked this in error just click close
|
||||||
|
</p>
|
||||||
|
<hr className="mt-2 mb-2" />
|
||||||
|
{server == "usday1vms006" ? (
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="printReason"
|
||||||
|
defaultValue={""}
|
||||||
|
render={({
|
||||||
|
field: {onChange},
|
||||||
|
fieldState: {},
|
||||||
|
//formState,
|
||||||
|
}) => (
|
||||||
|
<Select onValueChange={onChange}>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue placeholder="Select Reason" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>Print Reasons</SelectLabel>
|
||||||
|
{printReason.map((printReason: any) => (
|
||||||
|
<SelectItem value={printReason.key}>{printReason.label}</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="printRason" className="m-1">
|
||||||
|
Why are you manually printing?
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className={errors.printReason ? "border-red-500" : ""}
|
||||||
|
aria-invalid={!!errors.printReason}
|
||||||
|
{...register("printReason", {
|
||||||
|
required: true,
|
||||||
|
minLength: {
|
||||||
|
value: 5,
|
||||||
|
message: "To short of a reason please try again!",
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="line" className="m-1">
|
||||||
|
"What is the line number you are printing?"
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
//variant="underlined"
|
||||||
|
type="number"
|
||||||
|
className={errors.line ? "border-red-500" : ""}
|
||||||
|
aria-invalid={!!errors.line}
|
||||||
|
{...register("line", {required: true})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="initials" className="m-1">
|
||||||
|
Enter intials
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
//variant="underlined"
|
||||||
|
//label="Enter intials"
|
||||||
|
|
||||||
|
{...register("initials", {required: true})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Textarea
|
||||||
|
//label="Comments"
|
||||||
|
placeholder="add more info as needed."
|
||||||
|
{...register("additionalComments")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DialogFooter>
|
||||||
|
<Button color="danger" variant="default" onClick={() => setOpen(!open)}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
<Button color="primary" type="submit">
|
||||||
|
Print
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import {LotType} from "@/types/lots";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export const manualPrintLabels = async (lot: LotType, user: any) => {
|
||||||
|
//console.log(lot);
|
||||||
|
const labelUrl = `/ocp/manualPrintAndFollow`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axios.post(
|
||||||
|
labelUrl,
|
||||||
|
{line: lot.MachineLocation, printerName: lot.PrinterName},
|
||||||
|
{headers: {Authorization: `Basic ${user?.prod}`}}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `A new label was printed for ${lot.MachineDescription} to printer: ${lot.PrinterName}`,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `Line ${lot.MachineDescription} encountered an error printing labels: ${res.data.message}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error.response.status === 500) {
|
||||||
|
//toast.error(`Internal Server error please try again.`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Internal Server error please try again.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
//console.log(e.response);
|
||||||
|
//toast.error(`You are not authorized to do this.`);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `You are not authorized to do this.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,5 +1,52 @@
|
|||||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||||
|
import {Skeleton} from "@/components/ui/skeleton";
|
||||||
|
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||||
|
|
||||||
|
let printerCols = [
|
||||||
|
{
|
||||||
|
key: "status",
|
||||||
|
label: "Status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "printer",
|
||||||
|
label: "Printer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "statusMessage",
|
||||||
|
label: "Status Message",
|
||||||
|
},
|
||||||
|
];
|
||||||
export default function PrinterStatus() {
|
export default function PrinterStatus() {
|
||||||
return <LstCard className="m-2 p-2">Printer Status</LstCard>;
|
return (
|
||||||
|
<LstCard className="m-2 p-2">
|
||||||
|
<p className="text-center">Printer Status</p>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{printerCols.map((l) => (
|
||||||
|
<TableHead key={l.key}>{l.label}</TableHead>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
|
||||||
|
<TableBody>
|
||||||
|
{Array(10)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Skeleton className="h-4" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</LstCard>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
||||||
import {useModuleStore} from "../../lib/store/useModuleStore";
|
import {useModuleStore} from "../../lib/store/useModuleStore";
|
||||||
import {useEffect} from "react";
|
import {useEffect} from "react";
|
||||||
|
import {useSettingStore} from "@/lib/store/useSettings";
|
||||||
//import {useGetUserRoles} from "@/lib/store/useGetRoles";
|
//import {useGetUserRoles} from "@/lib/store/useGetRoles";
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
export const SessionProvider = ({children}: {children: React.ReactNode}) => {
|
export const SessionProvider = ({children}: {children: React.ReactNode}) => {
|
||||||
const {fetchModules} = useModuleStore();
|
const {fetchModules} = useModuleStore();
|
||||||
|
const {fetchSettings} = useSettingStore();
|
||||||
//const {fetchUserRoles} = useGetUserRoles();
|
//const {fetchUserRoles} = useGetUserRoles();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchModules();
|
fetchModules();
|
||||||
|
fetchSettings();
|
||||||
//fetchUserRoles();
|
//fetchUserRoles();
|
||||||
}, []);
|
}, []);
|
||||||
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
||||||
|
|||||||
@@ -5,19 +5,20 @@ import { cva, type VariantProps } from "class-variance-authority"
|
|||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default:
|
default:
|
||||||
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||||
outline:
|
outline:
|
||||||
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
||||||
secondary:
|
secondary:
|
||||||
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
ghost:
|
||||||
|
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
||||||
link: "text-primary underline-offset-4 hover:underline",
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
|
|||||||
183
frontend/src/components/ui/select.tsx
Normal file
183
frontend/src/components/ui/select.tsx
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||||
|
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Select({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||||
|
return <SelectPrimitive.Root data-slot="select" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectGroup({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||||
|
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectValue({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||||
|
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectTrigger({
|
||||||
|
className,
|
||||||
|
size = "default",
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||||
|
size?: "sm" | "default"
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<SelectPrimitive.Trigger
|
||||||
|
data-slot="select-trigger"
|
||||||
|
data-size={size}
|
||||||
|
className={cn(
|
||||||
|
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<SelectPrimitive.Icon asChild>
|
||||||
|
<ChevronDownIcon className="size-4 opacity-50" />
|
||||||
|
</SelectPrimitive.Icon>
|
||||||
|
</SelectPrimitive.Trigger>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectContent({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
position = "popper",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||||
|
return (
|
||||||
|
<SelectPrimitive.Portal>
|
||||||
|
<SelectPrimitive.Content
|
||||||
|
data-slot="select-content"
|
||||||
|
className={cn(
|
||||||
|
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||||
|
position === "popper" &&
|
||||||
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
position={position}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SelectScrollUpButton />
|
||||||
|
<SelectPrimitive.Viewport
|
||||||
|
className={cn(
|
||||||
|
"p-1",
|
||||||
|
position === "popper" &&
|
||||||
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SelectPrimitive.Viewport>
|
||||||
|
<SelectScrollDownButton />
|
||||||
|
</SelectPrimitive.Content>
|
||||||
|
</SelectPrimitive.Portal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectLabel({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||||
|
return (
|
||||||
|
<SelectPrimitive.Label
|
||||||
|
data-slot="select-label"
|
||||||
|
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectItem({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||||
|
return (
|
||||||
|
<SelectPrimitive.Item
|
||||||
|
data-slot="select-item"
|
||||||
|
className={cn(
|
||||||
|
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
||||||
|
<SelectPrimitive.ItemIndicator>
|
||||||
|
<CheckIcon className="size-4" />
|
||||||
|
</SelectPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
|
</SelectPrimitive.Item>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectSeparator({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||||
|
return (
|
||||||
|
<SelectPrimitive.Separator
|
||||||
|
data-slot="select-separator"
|
||||||
|
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectScrollUpButton({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||||
|
return (
|
||||||
|
<SelectPrimitive.ScrollUpButton
|
||||||
|
data-slot="select-scroll-up-button"
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronUpIcon className="size-4" />
|
||||||
|
</SelectPrimitive.ScrollUpButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectScrollDownButton({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||||
|
return (
|
||||||
|
<SelectPrimitive.ScrollDownButton
|
||||||
|
data-slot="select-scroll-down-button"
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronDownIcon className="size-4" />
|
||||||
|
</SelectPrimitive.ScrollDownButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectLabel,
|
||||||
|
SelectScrollDownButton,
|
||||||
|
SelectScrollUpButton,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
}
|
||||||
18
frontend/src/components/ui/textarea.tsx
Normal file
18
frontend/src/components/ui/textarea.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
data-slot="textarea"
|
||||||
|
className={cn(
|
||||||
|
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Textarea }
|
||||||
@@ -44,7 +44,7 @@ function TooltipContent({
|
|||||||
data-slot="tooltip-content"
|
data-slot="tooltip-content"
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance",
|
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -17,6 +17,16 @@ const fetchSession = async () => {
|
|||||||
});
|
});
|
||||||
// console.log(res);
|
// console.log(res);
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
localStorage.removeItem("auth_token");
|
||||||
|
// remove these for a while if no session just until fully to 2.0 and clearly no one has ran lstv1 in a long time
|
||||||
|
localStorage.removeItem("ally-supports-cache");
|
||||||
|
localStorage.removeItem("auth-storage");
|
||||||
|
localStorage.removeItem("nextauth.message");
|
||||||
|
localStorage.removeItem("prod");
|
||||||
|
localStorage.removeItem("cards");
|
||||||
|
localStorage.removeItem("rememberMe");
|
||||||
|
localStorage.removeItem("username");
|
||||||
|
|
||||||
throw new Error("Session not found");
|
throw new Error("Session not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {User} from "@/types/users";
|
import {User} from "@/types/users";
|
||||||
|
import axios from "axios";
|
||||||
import {create} from "zustand";
|
import {create} from "zustand";
|
||||||
|
|
||||||
export type SessionState = {
|
export type SessionState = {
|
||||||
@@ -16,9 +17,14 @@ export const useSessionStore = create<SessionState>((set) => {
|
|||||||
user: null, // User is NOT stored in localStorage
|
user: null, // User is NOT stored in localStorage
|
||||||
token: storedToken || null,
|
token: storedToken || null,
|
||||||
|
|
||||||
setSession: (user, token) => {
|
setSession: async (user: any, token) => {
|
||||||
if (token) {
|
if (token) {
|
||||||
localStorage.setItem("auth_token", token);
|
localStorage.setItem("auth_token", token);
|
||||||
|
const response = await axios.get("/api/auth/getuseraccess", {
|
||||||
|
headers: {Authorization: `Bearer ${token}`},
|
||||||
|
});
|
||||||
|
const data = response.data; //await response.json();
|
||||||
|
user = {...user, roles: data.data};
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem("auth_token");
|
localStorage.removeItem("auth_token");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {create} from "zustand";
|
import {create} from "zustand";
|
||||||
import {useSessionStore} from "./sessionStore";
|
import {useSessionStore} from "./sessionStore";
|
||||||
import {Modules} from "@/types/modules";
|
import {Modules} from "@/types/modules";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
interface SettingState {
|
interface SettingState {
|
||||||
userRoles: Modules[];
|
userRoles: Modules[];
|
||||||
@@ -19,15 +20,8 @@ export const useGetUserRoles = create<SettingState>()((set) => ({
|
|||||||
try {
|
try {
|
||||||
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||||
const {token} = useSessionStore();
|
const {token} = useSessionStore();
|
||||||
const response = await fetch(`/api/auth/getuseraccess`, {
|
const response = await axios.get("/api/auth/getuseraccess", {headers: {Authorization: `Bearer ${token}`}});
|
||||||
method: "GET",
|
const data: FetchModulesResponse = response.data; //await response.json();
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authentication: `Beaer ${token}`,
|
|
||||||
// You can add other headers here if necessary
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const data: FetchModulesResponse = await response.json();
|
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
set({userRoles: data.data});
|
set({userRoles: data.data});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {Modules} from "@/types/modules";
|
import {Modules} from "@/types/modules";
|
||||||
|
import axios from "axios";
|
||||||
import {create} from "zustand";
|
import {create} from "zustand";
|
||||||
|
|
||||||
interface SettingState {
|
interface SettingState {
|
||||||
@@ -17,18 +18,13 @@ export const useModuleStore = create<SettingState>()((set) => ({
|
|||||||
fetchModules: async () => {
|
fetchModules: async () => {
|
||||||
try {
|
try {
|
||||||
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||||
const response = await fetch(`/api/server/modules`, {
|
const response = await axios.get(`/api/server/modules`, {});
|
||||||
method: "GET",
|
const data: FetchModulesResponse = response.data; //await response.json();
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
// You can add other headers here if necessary
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const data: FetchModulesResponse = await response.json();
|
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
set({modules: data.data});
|
set({modules: data.data});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch settings:", error);
|
console.error("Failed to fetch settings:", error);
|
||||||
|
set({modules: []});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
29
frontend/src/lib/store/useSettings.ts
Normal file
29
frontend/src/lib/store/useSettings.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import {create} from "zustand";
|
||||||
|
|
||||||
|
interface SettingState {
|
||||||
|
settings: any[];
|
||||||
|
|
||||||
|
fetchSettings: () => Promise<void>;
|
||||||
|
setSettings: (settings: any[]) => void;
|
||||||
|
}
|
||||||
|
interface FetchModulesResponse {
|
||||||
|
data: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSettingStore = create<SettingState>()((set) => ({
|
||||||
|
settings: [],
|
||||||
|
setSettings: (settings) => set({settings}),
|
||||||
|
fetchSettings: async () => {
|
||||||
|
try {
|
||||||
|
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||||
|
const response = await axios.get(`/api/server/settings`, {});
|
||||||
|
const data: FetchModulesResponse = response.data; //await response.json();
|
||||||
|
//console.log(data);
|
||||||
|
set({settings: data.data});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch settings:", error);
|
||||||
|
set({settings: []});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
@@ -18,11 +18,12 @@ import { Route as AuthImport } from './routes/_auth'
|
|||||||
import { Route as AdminImport } from './routes/_admin'
|
import { Route as AdminImport } from './routes/_admin'
|
||||||
import { Route as IndexImport } from './routes/index'
|
import { Route as IndexImport } from './routes/index'
|
||||||
import { Route as OcpIndexImport } from './routes/ocp/index'
|
import { Route as OcpIndexImport } from './routes/ocp/index'
|
||||||
import { Route as OcpLotsImport } from './routes/ocp/lots'
|
|
||||||
import { Route as EomEomImport } from './routes/_eom/eom'
|
import { Route as EomEomImport } from './routes/_eom/eom'
|
||||||
import { Route as AuthProfileImport } from './routes/_auth/profile'
|
import { Route as AuthProfileImport } from './routes/_auth/profile'
|
||||||
import { Route as AdminSettingsImport } from './routes/_admin/settings'
|
import { Route as AdminSettingsImport } from './routes/_admin/settings'
|
||||||
|
import { Route as AdminServersImport } from './routes/_admin/servers'
|
||||||
import { Route as AdminModulesImport } from './routes/_admin/modules'
|
import { Route as AdminModulesImport } from './routes/_admin/modules'
|
||||||
|
import { Route as ocmeCyclecountIndexImport } from './routes/(ocme)/cyclecount/index'
|
||||||
import { Route as logisticsMaterialHelperIndexImport } from './routes/(logistics)/materialHelper/index'
|
import { Route as logisticsMaterialHelperIndexImport } from './routes/(logistics)/materialHelper/index'
|
||||||
import { Route as EomArticleAvImport } from './routes/_eom/article/$av'
|
import { Route as EomArticleAvImport } from './routes/_eom/article/$av'
|
||||||
import { Route as logisticsMaterialHelperSiloLinkIndexImport } from './routes/(logistics)/materialHelper/siloLink/index'
|
import { Route as logisticsMaterialHelperSiloLinkIndexImport } from './routes/(logistics)/materialHelper/siloLink/index'
|
||||||
@@ -69,12 +70,6 @@ const OcpIndexRoute = OcpIndexImport.update({
|
|||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
const OcpLotsRoute = OcpLotsImport.update({
|
|
||||||
id: '/ocp/lots',
|
|
||||||
path: '/ocp/lots',
|
|
||||||
getParentRoute: () => rootRoute,
|
|
||||||
} as any)
|
|
||||||
|
|
||||||
const EomEomRoute = EomEomImport.update({
|
const EomEomRoute = EomEomImport.update({
|
||||||
id: '/eom',
|
id: '/eom',
|
||||||
path: '/eom',
|
path: '/eom',
|
||||||
@@ -93,12 +88,24 @@ const AdminSettingsRoute = AdminSettingsImport.update({
|
|||||||
getParentRoute: () => AdminRoute,
|
getParentRoute: () => AdminRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const AdminServersRoute = AdminServersImport.update({
|
||||||
|
id: '/servers',
|
||||||
|
path: '/servers',
|
||||||
|
getParentRoute: () => AdminRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const AdminModulesRoute = AdminModulesImport.update({
|
const AdminModulesRoute = AdminModulesImport.update({
|
||||||
id: '/modules',
|
id: '/modules',
|
||||||
path: '/modules',
|
path: '/modules',
|
||||||
getParentRoute: () => AdminRoute,
|
getParentRoute: () => AdminRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const ocmeCyclecountIndexRoute = ocmeCyclecountIndexImport.update({
|
||||||
|
id: '/(ocme)/cyclecount/',
|
||||||
|
path: '/cyclecount/',
|
||||||
|
getParentRoute: () => rootRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const logisticsMaterialHelperIndexRoute =
|
const logisticsMaterialHelperIndexRoute =
|
||||||
logisticsMaterialHelperIndexImport.update({
|
logisticsMaterialHelperIndexImport.update({
|
||||||
id: '/(logistics)/materialHelper/',
|
id: '/(logistics)/materialHelper/',
|
||||||
@@ -179,6 +186,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AdminModulesImport
|
preLoaderRoute: typeof AdminModulesImport
|
||||||
parentRoute: typeof AdminImport
|
parentRoute: typeof AdminImport
|
||||||
}
|
}
|
||||||
|
'/_admin/servers': {
|
||||||
|
id: '/_admin/servers'
|
||||||
|
path: '/servers'
|
||||||
|
fullPath: '/servers'
|
||||||
|
preLoaderRoute: typeof AdminServersImport
|
||||||
|
parentRoute: typeof AdminImport
|
||||||
|
}
|
||||||
'/_admin/settings': {
|
'/_admin/settings': {
|
||||||
id: '/_admin/settings'
|
id: '/_admin/settings'
|
||||||
path: '/settings'
|
path: '/settings'
|
||||||
@@ -200,13 +214,6 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof EomEomImport
|
preLoaderRoute: typeof EomEomImport
|
||||||
parentRoute: typeof EomImport
|
parentRoute: typeof EomImport
|
||||||
}
|
}
|
||||||
'/ocp/lots': {
|
|
||||||
id: '/ocp/lots'
|
|
||||||
path: '/ocp/lots'
|
|
||||||
fullPath: '/ocp/lots'
|
|
||||||
preLoaderRoute: typeof OcpLotsImport
|
|
||||||
parentRoute: typeof rootRoute
|
|
||||||
}
|
|
||||||
'/ocp/': {
|
'/ocp/': {
|
||||||
id: '/ocp/'
|
id: '/ocp/'
|
||||||
path: '/ocp'
|
path: '/ocp'
|
||||||
@@ -228,6 +235,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof logisticsMaterialHelperIndexImport
|
preLoaderRoute: typeof logisticsMaterialHelperIndexImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
|
'/(ocme)/cyclecount/': {
|
||||||
|
id: '/(ocme)/cyclecount/'
|
||||||
|
path: '/cyclecount'
|
||||||
|
fullPath: '/cyclecount'
|
||||||
|
preLoaderRoute: typeof ocmeCyclecountIndexImport
|
||||||
|
parentRoute: typeof rootRoute
|
||||||
|
}
|
||||||
'/(logistics)/materialHelper/consumption/': {
|
'/(logistics)/materialHelper/consumption/': {
|
||||||
id: '/(logistics)/materialHelper/consumption/'
|
id: '/(logistics)/materialHelper/consumption/'
|
||||||
path: '/materialHelper/consumption'
|
path: '/materialHelper/consumption'
|
||||||
@@ -249,11 +263,13 @@ declare module '@tanstack/react-router' {
|
|||||||
|
|
||||||
interface AdminRouteChildren {
|
interface AdminRouteChildren {
|
||||||
AdminModulesRoute: typeof AdminModulesRoute
|
AdminModulesRoute: typeof AdminModulesRoute
|
||||||
|
AdminServersRoute: typeof AdminServersRoute
|
||||||
AdminSettingsRoute: typeof AdminSettingsRoute
|
AdminSettingsRoute: typeof AdminSettingsRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdminRouteChildren: AdminRouteChildren = {
|
const AdminRouteChildren: AdminRouteChildren = {
|
||||||
AdminModulesRoute: AdminModulesRoute,
|
AdminModulesRoute: AdminModulesRoute,
|
||||||
|
AdminServersRoute: AdminServersRoute,
|
||||||
AdminSettingsRoute: AdminSettingsRoute,
|
AdminSettingsRoute: AdminSettingsRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,13 +303,14 @@ export interface FileRoutesByFullPath {
|
|||||||
'/about': typeof AboutRoute
|
'/about': typeof AboutRoute
|
||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
'/modules': typeof AdminModulesRoute
|
'/modules': typeof AdminModulesRoute
|
||||||
|
'/servers': typeof AdminServersRoute
|
||||||
'/settings': typeof AdminSettingsRoute
|
'/settings': typeof AdminSettingsRoute
|
||||||
'/profile': typeof AuthProfileRoute
|
'/profile': typeof AuthProfileRoute
|
||||||
'/eom': typeof EomEomRoute
|
'/eom': typeof EomEomRoute
|
||||||
'/ocp/lots': typeof OcpLotsRoute
|
|
||||||
'/ocp': typeof OcpIndexRoute
|
'/ocp': typeof OcpIndexRoute
|
||||||
'/article/$av': typeof EomArticleAvRoute
|
'/article/$av': typeof EomArticleAvRoute
|
||||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||||
|
'/cyclecount': typeof ocmeCyclecountIndexRoute
|
||||||
'/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute
|
'/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||||
'/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
'/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||||
}
|
}
|
||||||
@@ -304,13 +321,14 @@ export interface FileRoutesByTo {
|
|||||||
'/about': typeof AboutRoute
|
'/about': typeof AboutRoute
|
||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
'/modules': typeof AdminModulesRoute
|
'/modules': typeof AdminModulesRoute
|
||||||
|
'/servers': typeof AdminServersRoute
|
||||||
'/settings': typeof AdminSettingsRoute
|
'/settings': typeof AdminSettingsRoute
|
||||||
'/profile': typeof AuthProfileRoute
|
'/profile': typeof AuthProfileRoute
|
||||||
'/eom': typeof EomEomRoute
|
'/eom': typeof EomEomRoute
|
||||||
'/ocp/lots': typeof OcpLotsRoute
|
|
||||||
'/ocp': typeof OcpIndexRoute
|
'/ocp': typeof OcpIndexRoute
|
||||||
'/article/$av': typeof EomArticleAvRoute
|
'/article/$av': typeof EomArticleAvRoute
|
||||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||||
|
'/cyclecount': typeof ocmeCyclecountIndexRoute
|
||||||
'/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute
|
'/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||||
'/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
'/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||||
}
|
}
|
||||||
@@ -324,13 +342,14 @@ export interface FileRoutesById {
|
|||||||
'/about': typeof AboutRoute
|
'/about': typeof AboutRoute
|
||||||
'/login': typeof LoginRoute
|
'/login': typeof LoginRoute
|
||||||
'/_admin/modules': typeof AdminModulesRoute
|
'/_admin/modules': typeof AdminModulesRoute
|
||||||
|
'/_admin/servers': typeof AdminServersRoute
|
||||||
'/_admin/settings': typeof AdminSettingsRoute
|
'/_admin/settings': typeof AdminSettingsRoute
|
||||||
'/_auth/profile': typeof AuthProfileRoute
|
'/_auth/profile': typeof AuthProfileRoute
|
||||||
'/_eom/eom': typeof EomEomRoute
|
'/_eom/eom': typeof EomEomRoute
|
||||||
'/ocp/lots': typeof OcpLotsRoute
|
|
||||||
'/ocp/': typeof OcpIndexRoute
|
'/ocp/': typeof OcpIndexRoute
|
||||||
'/_eom/article/$av': typeof EomArticleAvRoute
|
'/_eom/article/$av': typeof EomArticleAvRoute
|
||||||
'/(logistics)/materialHelper/': typeof logisticsMaterialHelperIndexRoute
|
'/(logistics)/materialHelper/': typeof logisticsMaterialHelperIndexRoute
|
||||||
|
'/(ocme)/cyclecount/': typeof ocmeCyclecountIndexRoute
|
||||||
'/(logistics)/materialHelper/consumption/': typeof logisticsMaterialHelperConsumptionIndexRoute
|
'/(logistics)/materialHelper/consumption/': typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||||
'/(logistics)/materialHelper/siloLink/': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
'/(logistics)/materialHelper/siloLink/': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||||
}
|
}
|
||||||
@@ -343,13 +362,14 @@ export interface FileRouteTypes {
|
|||||||
| '/about'
|
| '/about'
|
||||||
| '/login'
|
| '/login'
|
||||||
| '/modules'
|
| '/modules'
|
||||||
|
| '/servers'
|
||||||
| '/settings'
|
| '/settings'
|
||||||
| '/profile'
|
| '/profile'
|
||||||
| '/eom'
|
| '/eom'
|
||||||
| '/ocp/lots'
|
|
||||||
| '/ocp'
|
| '/ocp'
|
||||||
| '/article/$av'
|
| '/article/$av'
|
||||||
| '/materialHelper'
|
| '/materialHelper'
|
||||||
|
| '/cyclecount'
|
||||||
| '/materialHelper/consumption'
|
| '/materialHelper/consumption'
|
||||||
| '/materialHelper/siloLink'
|
| '/materialHelper/siloLink'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
@@ -359,13 +379,14 @@ export interface FileRouteTypes {
|
|||||||
| '/about'
|
| '/about'
|
||||||
| '/login'
|
| '/login'
|
||||||
| '/modules'
|
| '/modules'
|
||||||
|
| '/servers'
|
||||||
| '/settings'
|
| '/settings'
|
||||||
| '/profile'
|
| '/profile'
|
||||||
| '/eom'
|
| '/eom'
|
||||||
| '/ocp/lots'
|
|
||||||
| '/ocp'
|
| '/ocp'
|
||||||
| '/article/$av'
|
| '/article/$av'
|
||||||
| '/materialHelper'
|
| '/materialHelper'
|
||||||
|
| '/cyclecount'
|
||||||
| '/materialHelper/consumption'
|
| '/materialHelper/consumption'
|
||||||
| '/materialHelper/siloLink'
|
| '/materialHelper/siloLink'
|
||||||
id:
|
id:
|
||||||
@@ -377,13 +398,14 @@ export interface FileRouteTypes {
|
|||||||
| '/about'
|
| '/about'
|
||||||
| '/login'
|
| '/login'
|
||||||
| '/_admin/modules'
|
| '/_admin/modules'
|
||||||
|
| '/_admin/servers'
|
||||||
| '/_admin/settings'
|
| '/_admin/settings'
|
||||||
| '/_auth/profile'
|
| '/_auth/profile'
|
||||||
| '/_eom/eom'
|
| '/_eom/eom'
|
||||||
| '/ocp/lots'
|
|
||||||
| '/ocp/'
|
| '/ocp/'
|
||||||
| '/_eom/article/$av'
|
| '/_eom/article/$av'
|
||||||
| '/(logistics)/materialHelper/'
|
| '/(logistics)/materialHelper/'
|
||||||
|
| '/(ocme)/cyclecount/'
|
||||||
| '/(logistics)/materialHelper/consumption/'
|
| '/(logistics)/materialHelper/consumption/'
|
||||||
| '/(logistics)/materialHelper/siloLink/'
|
| '/(logistics)/materialHelper/siloLink/'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
@@ -396,9 +418,9 @@ export interface RootRouteChildren {
|
|||||||
EomRoute: typeof EomRouteWithChildren
|
EomRoute: typeof EomRouteWithChildren
|
||||||
AboutRoute: typeof AboutRoute
|
AboutRoute: typeof AboutRoute
|
||||||
LoginRoute: typeof LoginRoute
|
LoginRoute: typeof LoginRoute
|
||||||
OcpLotsRoute: typeof OcpLotsRoute
|
|
||||||
OcpIndexRoute: typeof OcpIndexRoute
|
OcpIndexRoute: typeof OcpIndexRoute
|
||||||
logisticsMaterialHelperIndexRoute: typeof logisticsMaterialHelperIndexRoute
|
logisticsMaterialHelperIndexRoute: typeof logisticsMaterialHelperIndexRoute
|
||||||
|
ocmeCyclecountIndexRoute: typeof ocmeCyclecountIndexRoute
|
||||||
logisticsMaterialHelperConsumptionIndexRoute: typeof logisticsMaterialHelperConsumptionIndexRoute
|
logisticsMaterialHelperConsumptionIndexRoute: typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||||
logisticsMaterialHelperSiloLinkIndexRoute: typeof logisticsMaterialHelperSiloLinkIndexRoute
|
logisticsMaterialHelperSiloLinkIndexRoute: typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||||
}
|
}
|
||||||
@@ -410,9 +432,9 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
EomRoute: EomRouteWithChildren,
|
EomRoute: EomRouteWithChildren,
|
||||||
AboutRoute: AboutRoute,
|
AboutRoute: AboutRoute,
|
||||||
LoginRoute: LoginRoute,
|
LoginRoute: LoginRoute,
|
||||||
OcpLotsRoute: OcpLotsRoute,
|
|
||||||
OcpIndexRoute: OcpIndexRoute,
|
OcpIndexRoute: OcpIndexRoute,
|
||||||
logisticsMaterialHelperIndexRoute: logisticsMaterialHelperIndexRoute,
|
logisticsMaterialHelperIndexRoute: logisticsMaterialHelperIndexRoute,
|
||||||
|
ocmeCyclecountIndexRoute: ocmeCyclecountIndexRoute,
|
||||||
logisticsMaterialHelperConsumptionIndexRoute:
|
logisticsMaterialHelperConsumptionIndexRoute:
|
||||||
logisticsMaterialHelperConsumptionIndexRoute,
|
logisticsMaterialHelperConsumptionIndexRoute,
|
||||||
logisticsMaterialHelperSiloLinkIndexRoute:
|
logisticsMaterialHelperSiloLinkIndexRoute:
|
||||||
@@ -435,9 +457,9 @@ export const routeTree = rootRoute
|
|||||||
"/_eom",
|
"/_eom",
|
||||||
"/about",
|
"/about",
|
||||||
"/login",
|
"/login",
|
||||||
"/ocp/lots",
|
|
||||||
"/ocp/",
|
"/ocp/",
|
||||||
"/(logistics)/materialHelper/",
|
"/(logistics)/materialHelper/",
|
||||||
|
"/(ocme)/cyclecount/",
|
||||||
"/(logistics)/materialHelper/consumption/",
|
"/(logistics)/materialHelper/consumption/",
|
||||||
"/(logistics)/materialHelper/siloLink/"
|
"/(logistics)/materialHelper/siloLink/"
|
||||||
]
|
]
|
||||||
@@ -449,6 +471,7 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "_admin.tsx",
|
"filePath": "_admin.tsx",
|
||||||
"children": [
|
"children": [
|
||||||
"/_admin/modules",
|
"/_admin/modules",
|
||||||
|
"/_admin/servers",
|
||||||
"/_admin/settings"
|
"/_admin/settings"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -475,6 +498,10 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "_admin/modules.tsx",
|
"filePath": "_admin/modules.tsx",
|
||||||
"parent": "/_admin"
|
"parent": "/_admin"
|
||||||
},
|
},
|
||||||
|
"/_admin/servers": {
|
||||||
|
"filePath": "_admin/servers.tsx",
|
||||||
|
"parent": "/_admin"
|
||||||
|
},
|
||||||
"/_admin/settings": {
|
"/_admin/settings": {
|
||||||
"filePath": "_admin/settings.tsx",
|
"filePath": "_admin/settings.tsx",
|
||||||
"parent": "/_admin"
|
"parent": "/_admin"
|
||||||
@@ -487,9 +514,6 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "_eom/eom.tsx",
|
"filePath": "_eom/eom.tsx",
|
||||||
"parent": "/_eom"
|
"parent": "/_eom"
|
||||||
},
|
},
|
||||||
"/ocp/lots": {
|
|
||||||
"filePath": "ocp/lots.tsx"
|
|
||||||
},
|
|
||||||
"/ocp/": {
|
"/ocp/": {
|
||||||
"filePath": "ocp/index.tsx"
|
"filePath": "ocp/index.tsx"
|
||||||
},
|
},
|
||||||
@@ -500,6 +524,9 @@ export const routeTree = rootRoute
|
|||||||
"/(logistics)/materialHelper/": {
|
"/(logistics)/materialHelper/": {
|
||||||
"filePath": "(logistics)/materialHelper/index.tsx"
|
"filePath": "(logistics)/materialHelper/index.tsx"
|
||||||
},
|
},
|
||||||
|
"/(ocme)/cyclecount/": {
|
||||||
|
"filePath": "(ocme)/cyclecount/index.tsx"
|
||||||
|
},
|
||||||
"/(logistics)/materialHelper/consumption/": {
|
"/(logistics)/materialHelper/consumption/": {
|
||||||
"filePath": "(logistics)/materialHelper/consumption/index.tsx"
|
"filePath": "(logistics)/materialHelper/consumption/index.tsx"
|
||||||
},
|
},
|
||||||
|
|||||||
14
frontend/src/routes/(ocme)/cyclecount/index.tsx
Normal file
14
frontend/src/routes/(ocme)/cyclecount/index.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import OcmeCycleCount from "@/components/ocme/ocmeCycleCount";
|
||||||
|
import {createFileRoute} from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/(ocme)/cyclecount/")({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div className="m-2">
|
||||||
|
<OcmeCycleCount />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,91 +1,94 @@
|
|||||||
import {createRootRoute, Link, Outlet} from "@tanstack/react-router";
|
import { createRootRoute, Link, Outlet } from "@tanstack/react-router";
|
||||||
import {TanStackRouterDevtools} from "@tanstack/router-devtools";
|
//import {TanStackRouterDevtools} from "@tanstack/router-devtools";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import {SidebarProvider} from "../components/ui/sidebar";
|
import { SidebarProvider } from "../components/ui/sidebar";
|
||||||
import {ThemeProvider} from "../components/layout/theme-provider";
|
import { ThemeProvider } from "../components/layout/theme-provider";
|
||||||
import {ModeToggle} from "../components/layout/mode-toggle";
|
import { ModeToggle } from "../components/layout/mode-toggle";
|
||||||
import {AppSidebar} from "../components/layout/lst-sidebar";
|
import { AppSidebar } from "../components/layout/lst-sidebar";
|
||||||
import {Avatar, AvatarFallback, AvatarImage} from "../components/ui/avatar";
|
import { Avatar, AvatarFallback, AvatarImage } from "../components/ui/avatar";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuLabel,
|
DropdownMenuLabel,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "../components/ui/dropdown-menu";
|
} from "../components/ui/dropdown-menu";
|
||||||
import {SessionProvider} from "../components/providers/Providers";
|
import { SessionProvider } from "../components/providers/Providers";
|
||||||
import {Toaster} from "sonner";
|
import { Toaster } from "sonner";
|
||||||
import {Button} from "../components/ui/button";
|
//import { Button } from "../components/ui/button";
|
||||||
|
|
||||||
import {useSessionStore} from "../lib/store/sessionStore";
|
import { useSessionStore } from "../lib/store/sessionStore";
|
||||||
import {useSession} from "@/hooks/useSession";
|
import { useSession } from "@/hooks/useSession";
|
||||||
import {useLogout} from "@/hooks/useLogout";
|
import { useLogout } from "@/hooks/useLogout";
|
||||||
|
|
||||||
// same as the layout
|
// same as the layout
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
component: () => {
|
component: () => {
|
||||||
const sidebarState = Cookies.get("sidebar_state") === "true";
|
const sidebarState = Cookies.get("sidebar_state") === "true";
|
||||||
const {session} = useSession();
|
const { session } = useSession();
|
||||||
const {user} = useSessionStore();
|
const { user } = useSessionStore();
|
||||||
const logout = useLogout();
|
const logout = useLogout();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SessionProvider>
|
<SessionProvider>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<nav className="flex justify-end">
|
<nav className="flex justify-end">
|
||||||
<div className="m-2 flex flex-row">
|
<div className="m-2 flex flex-row">
|
||||||
<div className="m-auto pr-2">
|
<div className="m-auto pr-2">
|
||||||
<p>Add Card</p>
|
<p>Add Card</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
<ModeToggle />
|
<ModeToggle />
|
||||||
</div>
|
</div>
|
||||||
{session ? (
|
{session ? (
|
||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger>
|
<DropdownMenuTrigger>
|
||||||
<Avatar>
|
<Avatar>
|
||||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
<AvatarImage
|
||||||
<AvatarFallback>CN</AvatarFallback>
|
src="https://github.com/shadcn.png"
|
||||||
</Avatar>
|
alt="@shadcn"
|
||||||
</DropdownMenuTrigger>
|
/>
|
||||||
<DropdownMenuContent>
|
<AvatarFallback>CN</AvatarFallback>
|
||||||
<DropdownMenuLabel>Hello {user?.username}</DropdownMenuLabel>
|
</Avatar>
|
||||||
<DropdownMenuSeparator />
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
<DropdownMenuContent>
|
||||||
|
<DropdownMenuLabel>
|
||||||
|
Hello {user?.username}
|
||||||
|
</DropdownMenuLabel>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
{/* <DropdownMenuItem>Profile</DropdownMenuItem>
|
||||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||||
<DropdownMenuItem>Team</DropdownMenuItem>
|
<DropdownMenuItem>Team</DropdownMenuItem>
|
||||||
<DropdownMenuItem>Subscription</DropdownMenuItem>
|
<DropdownMenuItem>Subscription</DropdownMenuItem> */}
|
||||||
<hr className="solid"></hr>
|
<hr className="solid"></hr>
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem>
|
||||||
<div className="m-auto mt-3">
|
<div className="m-auto">
|
||||||
<Button onClick={() => logout()} variant="ghost">
|
<button onClick={() => logout()}>Logout</button>
|
||||||
Logout
|
</div>
|
||||||
</Button>
|
</DropdownMenuItem>
|
||||||
</div>
|
</DropdownMenuContent>
|
||||||
</DropdownMenuItem>
|
</DropdownMenu>
|
||||||
</DropdownMenuContent>
|
</div>
|
||||||
</DropdownMenu>
|
) : (
|
||||||
</div>
|
<div>
|
||||||
) : (
|
<Link to="/login">Login</Link>
|
||||||
<>
|
</div>
|
||||||
<Link to="/login">Login</Link>
|
)}
|
||||||
</>
|
</div>
|
||||||
)}
|
</nav>
|
||||||
</div>
|
<SidebarProvider defaultOpen={sidebarState}>
|
||||||
</nav>
|
<AppSidebar />
|
||||||
<SidebarProvider defaultOpen={sidebarState}>
|
<Toaster expand={true} richColors closeButton />
|
||||||
<AppSidebar />
|
<Outlet />
|
||||||
<Toaster expand={true} richColors closeButton />
|
</SidebarProvider>
|
||||||
<Outlet />
|
</ThemeProvider>
|
||||||
</SidebarProvider>
|
</SessionProvider>
|
||||||
</ThemeProvider>
|
|
||||||
</SessionProvider>
|
|
||||||
|
|
||||||
<TanStackRouterDevtools position="bottom-right" />
|
{/* <TanStackRouterDevtools position="bottom-right" /> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
14
frontend/src/routes/_admin/servers.tsx
Normal file
14
frontend/src/routes/_admin/servers.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import ServerPage from "@/components/admin/servers/ServerPage";
|
||||||
|
import {createFileRoute} from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/_admin/servers")({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ServerPage />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/ocp/lots')({
|
|
||||||
component: RouteComponent,
|
|
||||||
})
|
|
||||||
|
|
||||||
function RouteComponent() {
|
|
||||||
return <div>Hello "/ocp/lots"!</div>
|
|
||||||
}
|
|
||||||
19
frontend/src/types/lots.ts
Normal file
19
frontend/src/types/lots.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
export type LotType = {
|
||||||
|
AV: number;
|
||||||
|
Alias: string;
|
||||||
|
LOT: number;
|
||||||
|
LabelOnlineID: number;
|
||||||
|
MachineDescription: string;
|
||||||
|
MachineID: number;
|
||||||
|
MachineLocation: number;
|
||||||
|
PlannedQTY: number;
|
||||||
|
PrinterName: string;
|
||||||
|
Produced: number;
|
||||||
|
ProlinkLot: number;
|
||||||
|
Remaining: number;
|
||||||
|
machineID: number;
|
||||||
|
overPrinting: string;
|
||||||
|
pallerCopies: number;
|
||||||
|
palletLabel: string;
|
||||||
|
printerID: number;
|
||||||
|
};
|
||||||
@@ -6,4 +6,5 @@ export type User = {
|
|||||||
username: string;
|
username: string;
|
||||||
roles: Roles[];
|
roles: Roles[];
|
||||||
role: string;
|
role: string;
|
||||||
|
prod?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
8
frontend/src/utils/adminUrlCheck.ts
Normal file
8
frontend/src/utils/adminUrlCheck.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export const adminUrlCheck = () => {
|
||||||
|
const host = window.location.host.split(":")[0];
|
||||||
|
const okHost = ["localhost", "usmcd1vms036"];
|
||||||
|
if (okHost.includes(host)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
20
frontend/src/utils/querys/production/labels.tsx
Normal file
20
frontend/src/utils/querys/production/labels.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import {queryOptions} from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getlabels(hours: string) {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["labels"],
|
||||||
|
queryFn: () => fetchSettings(hours),
|
||||||
|
|
||||||
|
staleTime: 1000,
|
||||||
|
//refetchInterval: 2500,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettings = async (hours: string) => {
|
||||||
|
const {data} = await axios.get(`/api/v1/ocp/labels?hours=${hours}`);
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
21
frontend/src/utils/querys/production/lots.tsx
Normal file
21
frontend/src/utils/querys/production/lots.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import {queryOptions} from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getlots() {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["lots"],
|
||||||
|
queryFn: () => fetchSettings(),
|
||||||
|
|
||||||
|
staleTime: 10 * 1000,
|
||||||
|
//refetchInterval: 10 * 1000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettings = async () => {
|
||||||
|
const {data} = await axios.get("/api/v1/ocp/lots");
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
let lotData = data.data;
|
||||||
|
return lotData ?? [];
|
||||||
|
};
|
||||||
19
frontend/src/utils/querys/servers.tsx
Normal file
19
frontend/src/utils/querys/servers.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import {queryOptions} from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getServers(token: string) {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["servers"],
|
||||||
|
queryFn: () => fetchSettings(token),
|
||||||
|
enabled: !!token,
|
||||||
|
staleTime: 1000,
|
||||||
|
refetchInterval: 2500,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettings = async (token: string) => {
|
||||||
|
const {data} = await axios.get("/api/server/servers", {headers: {Authorization: `Bearer ${token}`}});
|
||||||
|
|
||||||
|
return data.data;
|
||||||
|
};
|
||||||
@@ -13,6 +13,11 @@ export function getSettings(token: string) {
|
|||||||
|
|
||||||
const fetchSettings = async (token: string) => {
|
const fetchSettings = async (token: string) => {
|
||||||
const {data} = await axios.get("/api/server/settings", {headers: {Authorization: `Bearer ${token}`}});
|
const {data} = await axios.get("/api/server/settings", {headers: {Authorization: `Bearer ${token}`}});
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
return data.data;
|
const url: string = window.location.host.split(":")[0];
|
||||||
|
let settingsData = data.data;
|
||||||
|
if (url != "localhost") {
|
||||||
|
settingsData.filter((n: any) => n.name === "devDir");
|
||||||
|
}
|
||||||
|
return settingsData;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,14 +13,13 @@ export function hasAccess(user: User | null, moduleName: string | null, modules:
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hasPageAccess(user: User | null, role: any, module_id: string): boolean {
|
export function hasPageAccess(user: User | null, role: any, module_id: string): boolean {
|
||||||
|
if (role.includes("viewer")) return true;
|
||||||
if (!user) return false;
|
if (!user) return false;
|
||||||
|
|
||||||
// get only the module in the user profile
|
// get only the module in the user profile
|
||||||
const userRole = user?.roles.filter((role) => role.module_id === module_id);
|
const userRole = user?.roles.filter((role) => role.module_id === module_id);
|
||||||
|
|
||||||
if (role.includes(userRole[0]?.role)) {
|
if (role.includes(userRole[0]?.role)) return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,16 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api": {target: `http://localhost:${Number(process.env.VITE_SERVER_PORT || 4400)}`, changeOrigin: true},
|
"/api": {
|
||||||
|
target: `http://localhost:${Number(process.env.VITE_SERVER_PORT || 4400)}`,
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
|
"/ocme": {
|
||||||
|
target: `http://localhost:${Number(process.env.VITE_SERVER_PORT || 4400)}`,
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
20231
package-lock.json
generated
20231
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
144
package.json
144
package.json
@@ -1,67 +1,81 @@
|
|||||||
{
|
{
|
||||||
"name": "fullstack-app",
|
"name": "lstv2",
|
||||||
"version": "2.4.0",
|
"version": "2.9.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
|
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
|
||||||
"dev:server": "dotenvx run -f .env -- tsx watch server/index.ts",
|
"dev:server": "dotenvx run -f .env -- tsx watch server/index.ts",
|
||||||
"dev:frontend": "cd frontend && npm run dev",
|
"dev:frontend": "cd frontend && npm run dev",
|
||||||
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
|
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
|
||||||
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
|
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
|
||||||
"build": "npm run build:server && npm run build:frontend",
|
"build": "npm run build:server && npm run build:frontend",
|
||||||
"build:server": "rimraf dist && tsc --build && xcopy server\\scripts dist\\server\\scripts /E /I /Y",
|
"build:server": "rimraf dist && tsc --build && npm run copy:scripts",
|
||||||
"build:frontend": "cd frontend && npm run build",
|
"build:frontend": "cd frontend && npm run build",
|
||||||
"start": "set NODE_ENV=production && npm run start:server",
|
"copy:scripts": "tsx server/scripts/copyScripts.ts",
|
||||||
"start:server": "dotenvx run -f .env -- node dist/server/index.js",
|
"copy:servers": "xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y",
|
||||||
"db:generate": "npx drizzle-kit generate",
|
"start": "set NODE_ENV=production && npm run start:server",
|
||||||
"db:migrate": "npx drizzle-kit push",
|
"start:server": "dotenvx run -f .env -- node dist/server/index.js",
|
||||||
"deploy": "standard-version --conventional-commits",
|
"db:generate": "npx drizzle-kit generate",
|
||||||
"commit": "cz",
|
"db:migrate": "npx drizzle-kit push",
|
||||||
"prodinstall": "npm i --omit=dev && npm run db:migrate"
|
"db:dev": "npm run build && npm run db:generate && npm run db:migrate",
|
||||||
},
|
"deploy": "standard-version --conventional-commits && npm run prodBuild",
|
||||||
"dependencies": {
|
"zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"",
|
||||||
"@dotenvx/dotenvx": "^1.38.3",
|
"v1Build": "cd C:\\Users\\matthes01\\Documents\\logisticsSupportTool && npm run oldBuilder",
|
||||||
"@hono/node-server": "^1.13.8",
|
"prodBuild": "npm run v1Build && powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\" && npm run zipServer",
|
||||||
"@hono/zod-openapi": "^0.18.4",
|
"commit": "cz",
|
||||||
"@scalar/hono-api-reference": "^0.5.175",
|
"prodinstall": "npm i --omit=dev && npm run db:migrate",
|
||||||
"@types/jsonwebtoken": "^9.0.8",
|
"checkupdates": "npx npm-check-updates"
|
||||||
"axios": "^1.7.9",
|
},
|
||||||
"bcrypt": "^5.1.1",
|
"config": {
|
||||||
"compression": "^1.8.0",
|
"commitizen": {
|
||||||
"cookie": "^1.0.2",
|
"path": "./node_modules/cz-conventional-changelog"
|
||||||
"date-fns": "^4.1.0",
|
|
||||||
"dotenv": "^16.4.7",
|
|
||||||
"drizzle-kit": "^0.30.4",
|
|
||||||
"drizzle-orm": "^0.39.3",
|
|
||||||
"drizzle-zod": "^0.7.0",
|
|
||||||
"jsonwebtoken": "^9.0.2",
|
|
||||||
"mssql": "^11.0.1",
|
|
||||||
"nodemailer": "^6.10.0",
|
|
||||||
"nodemailer-express-handlebars": "^7.0.0",
|
|
||||||
"pg": "^8.13.3",
|
|
||||||
"pino": "^9.6.0",
|
|
||||||
"pino-abstract-transport": "^2.0.0",
|
|
||||||
"pino-pretty": "^13.0.0",
|
|
||||||
"postgres": "^3.4.5",
|
|
||||||
"zod": "^3.24.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/bcrypt": "^5.0.2",
|
|
||||||
"@types/js-cookie": "^3.0.6",
|
|
||||||
"@types/mssql": "^9.1.7",
|
|
||||||
"@types/node": "^22.13.5",
|
|
||||||
"@types/pg": "^8.11.11",
|
|
||||||
"concurrently": "^8.2.0",
|
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
|
||||||
"dotenv": "^16.3.1",
|
|
||||||
"rimraf": "^6.0.1",
|
|
||||||
"standard-version": "^9.5.0",
|
|
||||||
"tsx": "^4.7.1",
|
|
||||||
"typescript": "~5.7.3"
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"commitizen": {
|
|
||||||
"path": "./node_modules/cz-conventional-changelog"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"admConfig": {
|
||||||
|
"build": 50,
|
||||||
|
"oldBuild": "backend-0.1.3.zip"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/adm-zip": "^0.5.7",
|
||||||
|
"@types/bcrypt": "^5.0.2",
|
||||||
|
"@types/fs-extra": "^11.0.4",
|
||||||
|
"@types/js-cookie": "^3.0.6",
|
||||||
|
"@types/mssql": "^9.1.7",
|
||||||
|
"@types/node": "^22.13.11",
|
||||||
|
"@types/pg": "^8.11.11",
|
||||||
|
"@types/ws": "^8.18.0",
|
||||||
|
"concurrently": "^9.1.2",
|
||||||
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
|
"drizzle-kit": "^0.30.5",
|
||||||
|
"fs-extra": "^11.3.0",
|
||||||
|
"standard-version": "^9.5.0",
|
||||||
|
"tsx": "^4.19.3",
|
||||||
|
"typescript": "^5.8.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@dotenvx/dotenvx": "^1.39.0",
|
||||||
|
"@hono/node-server": "^1.14.0",
|
||||||
|
"@hono/zod-openapi": "^0.19.2",
|
||||||
|
"@scalar/hono-api-reference": "^0.7.2",
|
||||||
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
|
"adm-zip": "^0.5.16",
|
||||||
|
"axios": "^1.8.4",
|
||||||
|
"bcryptjs": "^3.0.2",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
|
"drizzle-orm": "^0.41.0",
|
||||||
|
"drizzle-zod": "^0.7.0",
|
||||||
|
"fast-xml-parser": "^5.0.9",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
"mssql": "^11.0.1",
|
||||||
|
"nodemailer": "^6.10.0",
|
||||||
|
"nodemailer-express-handlebars": "^7.0.0",
|
||||||
|
"pg": "^8.14.1",
|
||||||
|
"pino": "^9.6.0",
|
||||||
|
"pino-abstract-transport": "^2.0.0",
|
||||||
|
"pino-pretty": "^13.0.0",
|
||||||
|
"postgres": "^3.4.5",
|
||||||
|
"rimraf": "^6.0.1",
|
||||||
|
"ws": "^8.18.1",
|
||||||
|
"zod": "^3.24.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
15
server/globalUtils/appInfo.ts
Normal file
15
server/globalUtils/appInfo.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import path from "path";
|
||||||
|
import {createLog} from "../services/logger/logger.js";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
export const getAppInfo = async (appLock: string) => {
|
||||||
|
try {
|
||||||
|
const packagePath = path.join(appLock, "package.json");
|
||||||
|
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
||||||
|
//const version = packageJson.version;
|
||||||
|
return packageJson;
|
||||||
|
} catch (error) {
|
||||||
|
createLog("error", "lst", "zipUpBuild", `Error in getting the version: ${error}`);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
};
|
||||||
3
server/globalUtils/delay.ts
Normal file
3
server/globalUtils/delay.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const delay = (ms: number) => {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
|
};
|
||||||
65
server/globalUtils/pingServer.ts
Normal file
65
server/globalUtils/pingServer.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import dns from "dns";
|
||||||
|
import net from "net";
|
||||||
|
|
||||||
|
// Usage example
|
||||||
|
//const hostnamePort = "example.com:80"; // Replace with your hostname:port
|
||||||
|
//checkHostnamePort(hostnamePort);
|
||||||
|
|
||||||
|
// Function to resolve a hostname to an IP address
|
||||||
|
export function resolveHostname(hostname: string) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
dns.lookup(hostname, (err, address) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to check if a port is open
|
||||||
|
export function checkPort(ip: string, port: number): Promise<boolean> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const socket = new net.Socket();
|
||||||
|
|
||||||
|
socket.setTimeout(2000); // Set a timeout for the connection attempt
|
||||||
|
|
||||||
|
socket.on("connect", () => {
|
||||||
|
socket.destroy(); // Close the connection
|
||||||
|
resolve(true); // Port is open
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("timeout", () => {
|
||||||
|
socket.destroy(); // Close the connection
|
||||||
|
reject(new Error("Connection timed out")); // Port is not reachable
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("error", (err: any) => {
|
||||||
|
reject(new Error(`Unknown error: ${err}`)); // Handle non-Error types
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.connect(port, ip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function to check hostname:port
|
||||||
|
export async function checkHostnamePort(hostnamePort: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
// Split the input into hostname and port
|
||||||
|
const [hostname, port] = hostnamePort.split(":");
|
||||||
|
if (!hostname || !port) {
|
||||||
|
return false; // Invalid format
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the hostname to an IP address
|
||||||
|
const ip = (await resolveHostname(hostname)) as string;
|
||||||
|
|
||||||
|
// Check if the port is open
|
||||||
|
const portCheck = await checkPort(ip, parseInt(port, 10));
|
||||||
|
|
||||||
|
return true; // Hostname:port is reachable
|
||||||
|
} catch (err) {
|
||||||
|
return false; // Any error means the hostname:port is not reachable
|
||||||
|
}
|
||||||
|
}
|
||||||
8
server/globalUtils/routeDefs/options.ts
Normal file
8
server/globalUtils/routeDefs/options.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export const apiOptions = () => {
|
||||||
|
return {
|
||||||
|
tags: ["rfid"],
|
||||||
|
summary: "Add new reader",
|
||||||
|
method: "post",
|
||||||
|
path: "/addreader",
|
||||||
|
};
|
||||||
|
};
|
||||||
45
server/globalUtils/routeDefs/responses.ts
Normal file
45
server/globalUtils/routeDefs/responses.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import {z} from "@hono/zod-openapi";
|
||||||
|
|
||||||
|
const responseSchema = z.object({
|
||||||
|
success: z.boolean().openapi({example: true}),
|
||||||
|
message: z.string().optional(),
|
||||||
|
data: z
|
||||||
|
.array(z.object({}).optional())
|
||||||
|
.optional()
|
||||||
|
.openapi({example: [{data: "hi"}]}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const responses = () => {
|
||||||
|
return {
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
"application/json": {schema: responseSchema},
|
||||||
|
},
|
||||||
|
description: "Response message",
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: "Internal Server Error",
|
||||||
|
},
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: "Unauthorized",
|
||||||
|
},
|
||||||
|
500: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: "Internal Server Error",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
29
server/globalUtils/routeDefs/returnRes.ts
Normal file
29
server/globalUtils/routeDefs/returnRes.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import type { Context } from "hono";
|
||||||
|
|
||||||
|
export type ReturnRes<T> =
|
||||||
|
| { success: true; message: string; data: T }
|
||||||
|
| { success: false; message: string; error: any };
|
||||||
|
|
||||||
|
export const returnRes = <T>(
|
||||||
|
success: boolean,
|
||||||
|
message: string,
|
||||||
|
data: T | null = null
|
||||||
|
): ReturnRes<T> => {
|
||||||
|
/**
|
||||||
|
* just a simple return to reduce the typing and make sure we are always consitant with our returns.
|
||||||
|
*
|
||||||
|
* data can be an error as well.
|
||||||
|
*/
|
||||||
|
return success
|
||||||
|
? { success, message, data: data as T }
|
||||||
|
: { success, message, error: data ?? "An unknown error occurred" };
|
||||||
|
};
|
||||||
|
|
||||||
|
// export const returnApi = (c:Context,success: boolean, message: string, data?: any, code: number)=>{
|
||||||
|
// /**
|
||||||
|
// * just a simple return to reduce the typing and make sure we are always consitant with our returns.
|
||||||
|
// *
|
||||||
|
// * data can be an error as well.
|
||||||
|
// */
|
||||||
|
// return c.json({success, message, data}, code);
|
||||||
|
// }
|
||||||
24
server/globalUtils/tryCatch.ts
Normal file
24
server/globalUtils/tryCatch.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Types for the result object with discriminated union
|
||||||
|
type Success<T> = {
|
||||||
|
data: T;
|
||||||
|
error: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Failure<E> = {
|
||||||
|
data: null;
|
||||||
|
error: E;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Result<T, E = Error> = Success<T> | Failure<E>;
|
||||||
|
|
||||||
|
// Main wrapper function
|
||||||
|
export async function tryCatch<T, E = Error>(
|
||||||
|
promise: Promise<T>
|
||||||
|
): Promise<Result<T, E>> {
|
||||||
|
try {
|
||||||
|
const data = await promise;
|
||||||
|
return { data, error: null };
|
||||||
|
} catch (error) {
|
||||||
|
return { data: null, error: error as E };
|
||||||
|
}
|
||||||
|
}
|
||||||
193
server/index.ts
193
server/index.ts
@@ -1,12 +1,12 @@
|
|||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
import {serve} from "@hono/node-server";
|
import { serve } from "@hono/node-server";
|
||||||
import {OpenAPIHono} from "@hono/zod-openapi";
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import {serveStatic} from "@hono/node-server/serve-static";
|
import { proxy } from "hono/proxy";
|
||||||
import {logger} from "hono/logger";
|
import { serveStatic } from "@hono/node-server/serve-static";
|
||||||
import {cors} from "hono/cors";
|
import { logger } from "hono/logger";
|
||||||
import {createLog} from "./services/logger/logger.js";
|
import { cors } from "hono/cors";
|
||||||
import {closePool} from "./services/sqlServer/prodSqlServer.js";
|
import { createLog } from "./services/logger/logger.js";
|
||||||
|
import { WebSocketServer } from "ws";
|
||||||
// custom routes
|
// custom routes
|
||||||
import scalar from "./services/general/route/scalar.js";
|
import scalar from "./services/general/route/scalar.js";
|
||||||
import system from "./services/server/systemServer.js";
|
import system from "./services/server/systemServer.js";
|
||||||
@@ -16,10 +16,12 @@ import ocme from "./services/ocme/ocmeService.js";
|
|||||||
import sqlService from "./services/sqlServer/sqlService.js";
|
import sqlService from "./services/sqlServer/sqlService.js";
|
||||||
import logistics from "./services/logistics/logisticsService.js";
|
import logistics from "./services/logistics/logisticsService.js";
|
||||||
import rfid from "./services/rfid/rfidService.js";
|
import rfid from "./services/rfid/rfidService.js";
|
||||||
|
import printers from "./services/printers/printerService.js";
|
||||||
import {db} from "../database/dbclient.js";
|
import loggerService from "./services/logger/loggerService.js";
|
||||||
import {settings} from "../database/schema/settings.js";
|
import ocpService from "./services/ocp/ocpService.js";
|
||||||
import {count, eq} from "drizzle-orm";
|
import { db } from "../database/dbclient.js";
|
||||||
|
import { settings } from "../database/schema/settings.js";
|
||||||
|
import { count } from "drizzle-orm";
|
||||||
|
|
||||||
// create the main prodlogin here
|
// create the main prodlogin here
|
||||||
const username = "lst_user";
|
const username = "lst_user";
|
||||||
@@ -27,115 +29,148 @@ const password = "Alpla$$Prod";
|
|||||||
export const lstAuth = btoa(`${username}:${password}`);
|
export const lstAuth = btoa(`${username}:${password}`);
|
||||||
|
|
||||||
// checking to make sure we have the settings intialized
|
// checking to make sure we have the settings intialized
|
||||||
const serverIntialized = await db.select({count: count()}).from(settings);
|
const serverIntialized = await db.select({ count: count() }).from(settings);
|
||||||
export const installed = serverIntialized[0].count === 0 && process.env.NODE_ENV !== "development" ? false : true;
|
export const installed =
|
||||||
|
serverIntialized[0].count === 0 && process.env.NODE_ENV !== "development"
|
||||||
|
? false
|
||||||
|
: true;
|
||||||
createLog("info", "LST", "server", `Server is installed: ${installed}`);
|
createLog("info", "LST", "server", `Server is installed: ${installed}`);
|
||||||
|
|
||||||
const allowedOrigins = [
|
const app = new OpenAPIHono({ strict: false });
|
||||||
"http://localhost:3000",
|
|
||||||
"http://localhost:4000",
|
|
||||||
"http://localhost:5173",
|
|
||||||
`http://usmcd1vms006:4000`,
|
|
||||||
];
|
|
||||||
const app = new OpenAPIHono();
|
|
||||||
|
|
||||||
// middle ware
|
// middle ware
|
||||||
app.use("*", logger());
|
app.use("*", logger());
|
||||||
app.use(
|
app.use(
|
||||||
"*",
|
"*",
|
||||||
cors({
|
cors({
|
||||||
origin: allowedOrigins,
|
origin: "*", // Allow all origins
|
||||||
allowHeaders: ["X-Custom-Header", "Upgrade-Insecure-Requests"],
|
allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
|
||||||
allowMethods: ["POST", "GET", "OPTIONS"],
|
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
|
||||||
exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
|
//exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
|
||||||
maxAge: 600,
|
credentials: true, // Allow credentials if needed
|
||||||
credentials: true,
|
maxAge: 600,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Middleware to normalize route case
|
// Middleware to normalize route case
|
||||||
app.use("*", async (c, next) => {
|
app.use("*", async (c, next) => {
|
||||||
const lowercasedUrl = c.req.url.toLowerCase();
|
const lowercasedUrl = c.req.url.toLowerCase();
|
||||||
|
//console.log("Incoming Request:", c.req.url, c.req.method);
|
||||||
|
// If the URL is already lowercase, continue as usual
|
||||||
|
if (c.req.url === lowercasedUrl) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
// If the URL is already lowercase, continue as usual
|
// Otherwise, re-route internally
|
||||||
if (c.req.url === lowercasedUrl) {
|
return c.redirect(lowercasedUrl, 308); // 308 preserves the HTTP method
|
||||||
return next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, re-route internally
|
|
||||||
return c.redirect(lowercasedUrl, 308); // 308 preserves the HTTP method
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.doc("/api/ref", {
|
app.doc("/api/ref", {
|
||||||
openapi: "3.0.0",
|
openapi: "3.0.0",
|
||||||
info: {
|
info: {
|
||||||
version: "2.0.0",
|
version: "2.0.0",
|
||||||
title: "LST API",
|
title: "LST API",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
scalar,
|
scalar,
|
||||||
auth,
|
auth,
|
||||||
// apiHits,
|
// apiHits,
|
||||||
system,
|
system,
|
||||||
tcpServer,
|
tcpServer,
|
||||||
sqlService,
|
sqlService,
|
||||||
logistics,
|
logistics,
|
||||||
rfid,
|
rfid,
|
||||||
|
printers,
|
||||||
|
loggerService,
|
||||||
|
ocpService,
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const appRoutes = routes.forEach((route) => {
|
const appRoutes = routes.forEach((route) => {
|
||||||
app.route("/api/", route);
|
app.route("/api/", route);
|
||||||
});
|
});
|
||||||
|
|
||||||
// the catch all api route
|
|
||||||
app.all("/api/*", (c) => c.json({error: "API route not found"}, 404));
|
|
||||||
|
|
||||||
app.route("/ocme/", ocme);
|
app.route("/ocme/", ocme);
|
||||||
|
|
||||||
// async (c) => {
|
//--------------- lst v1 proxy ----------------------\\
|
||||||
// //return ocmeService(c);
|
// app.all("/api/v1/*", (c) => {
|
||||||
// c.json({error: "Ocme route not found"}, 404);
|
// const path = c.req.path.replace("/api/v1/", ""); // Extract the subpath
|
||||||
|
// const query = c.req.query() ? "?" + new URLSearchParams(c.req.query()).toString() : ""; // Get query params
|
||||||
|
// return proxy(`http://localhost:4900/${path}${query}`, {
|
||||||
|
// headers: {
|
||||||
|
// ...c.req.header(),
|
||||||
|
// "X-Forwarded-For": "127.0.0.1",
|
||||||
|
// "X-Forwarded-Host": c.req.header("host"),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
// app.all("/system/*", (c) => {
|
||||||
|
// const path = c.req.path.replace("/system/", ""); // Extract the subpath
|
||||||
|
// const query = c.req.query() ? "?" + new URLSearchParams(c.req.query()).toString() : ""; // Get query params
|
||||||
|
// return proxy(`http://localhost:4200/${path}${query}`, {
|
||||||
|
// headers: {
|
||||||
|
// ...c.req.header(),
|
||||||
|
// "X-Forwarded-For": "127.0.0.1",
|
||||||
|
// "X-Forwarded-Host": c.req.header("host"),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
//---------------------------------------------------\\
|
||||||
|
|
||||||
|
// the catch all api route
|
||||||
|
app.all("/api/*", (c) => c.json({ error: "API route not found" }, 404));
|
||||||
|
|
||||||
// front end static files
|
// front end static files
|
||||||
app.use("/*", serveStatic({root: "./frontend/dist"}));
|
app.use("/*", serveStatic({ root: "./frontend/dist" }));
|
||||||
app.use("*", serveStatic({path: "./frontend/dist/index.html"}));
|
app.use("*", serveStatic({ path: "./frontend/dist/index.html" }));
|
||||||
|
|
||||||
// Handle app exit signals
|
// Handle app exit signals
|
||||||
process.on("SIGINT", async () => {
|
process.on("SIGINT", async () => {
|
||||||
console.log("\nGracefully shutting down...");
|
console.log("\nGracefully shutting down...");
|
||||||
await closePool();
|
//await closePool();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("SIGTERM", async () => {
|
process.on("SIGTERM", async () => {
|
||||||
console.log("Received termination signal, closing database...");
|
console.log("Received termination signal, closing database...");
|
||||||
await closePool();
|
//await closePool();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("uncaughtException", async (err) => {
|
process.on("uncaughtException", async (err) => {
|
||||||
console.log("Uncaught Exception:", err);
|
console.log("Uncaught Exception:", err);
|
||||||
await closePool();
|
//await closePool();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("beforeExit", async () => {
|
process.on("beforeExit", async () => {
|
||||||
console.log("Process is about to exit...");
|
console.log("Process is about to exit...");
|
||||||
await closePool();
|
//await closePool();
|
||||||
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const port =
|
||||||
|
process.env.NODE_ENV === "development"
|
||||||
|
? process.env.VITE_SERVER_PORT
|
||||||
|
: process.env.PROD_PORT;
|
||||||
|
|
||||||
serve(
|
serve(
|
||||||
{
|
{
|
||||||
fetch: app.fetch,
|
fetch: app.fetch,
|
||||||
port: Number(process.env.VITE_SERVER_PORT),
|
port: Number(port),
|
||||||
hostname: "0.0.0.0",
|
hostname: "0.0.0.0",
|
||||||
},
|
},
|
||||||
(info) => {
|
(info) => {
|
||||||
createLog("info", "LST", "server", `Server is running on http://${info.address}:${info.port}`);
|
createLog(
|
||||||
}
|
"info",
|
||||||
|
"LST",
|
||||||
|
"server",
|
||||||
|
`Server is running on http://${info.address}:${info.port}`
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export type AppRoutes = typeof appRoutes;
|
export type AppRoutes = typeof appRoutes;
|
||||||
|
|||||||
35
server/scripts/build.ps1
Normal file
35
server/scripts/build.ps1
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
param (
|
||||||
|
[string]$dir,
|
||||||
|
[string]$app
|
||||||
|
)
|
||||||
|
# dir is the location of the root folder.
|
||||||
|
|
||||||
|
# Store the original directory
|
||||||
|
$originalDir = Get-Location
|
||||||
|
|
||||||
|
Write-Host $originalDir
|
||||||
|
|
||||||
|
# Check if the directory is provided
|
||||||
|
if (-not $dir) {
|
||||||
|
Write-Host "Error: Directory parameter is required."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if the directory exists
|
||||||
|
if (-not (Test-Path $dir)) {
|
||||||
|
Write-Host "Error: Directory '$dir' does not exist."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Navigate to the directory
|
||||||
|
Set-Location -Path $dir
|
||||||
|
|
||||||
|
# Run npm run build
|
||||||
|
Write-Host "Running 'npm run build' in directory: $dir"
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
Write-Host "Build completed successfully."
|
||||||
|
|
||||||
|
# Restore the original directory
|
||||||
|
Set-Location -Path $originalDir
|
||||||
|
exit 0
|
||||||
65
server/scripts/copyScripts.ts
Normal file
65
server/scripts/copyScripts.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import fs from "fs-extra";
|
||||||
|
import path from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
// Get the current directory of the module
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
const sourceDir = path.join(__dirname, "/");
|
||||||
|
const destDir = path.join("./", "dist", "server", "scripts");
|
||||||
|
|
||||||
|
// Copy only .ps1 files
|
||||||
|
fs.readdir(sourceDir)
|
||||||
|
.then((files) => {
|
||||||
|
files.forEach((file) => {
|
||||||
|
if (path.extname(file) === ".ps1") {
|
||||||
|
const sourceFile = path.join(sourceDir, file);
|
||||||
|
const destFile = path.join(destDir, file);
|
||||||
|
|
||||||
|
// Copy each .ps1 file
|
||||||
|
fs.copy(sourceFile, destFile)
|
||||||
|
.then(() => {
|
||||||
|
console.log(`Copied: ${file}`);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(`Error copying file: ${file}`, err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Error reading source directory:", err);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Paths for source and destination of serverData.json
|
||||||
|
const sourceFile = path.join(
|
||||||
|
"./",
|
||||||
|
"server",
|
||||||
|
"services",
|
||||||
|
"server",
|
||||||
|
"utils",
|
||||||
|
"serverData.json"
|
||||||
|
);
|
||||||
|
const serverDataDest = path.join(
|
||||||
|
"./",
|
||||||
|
"dist",
|
||||||
|
"server",
|
||||||
|
"services",
|
||||||
|
"server",
|
||||||
|
"utils"
|
||||||
|
);
|
||||||
|
const destFile = path.join(serverDataDest, "serverData.json");
|
||||||
|
|
||||||
|
// Ensure the destination directory exists
|
||||||
|
fs.ensureDir(destDir)
|
||||||
|
.then(() => {
|
||||||
|
// Copy the serverData.json file
|
||||||
|
return fs.copy(sourceFile, destFile);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
console.log("serverData.json copied successfully!");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error("Error copying serverData.json:", err);
|
||||||
|
});
|
||||||
@@ -1,37 +1,56 @@
|
|||||||
# Install
|
# Install
|
||||||
|
|
||||||
## Files needed to be downloaded before install.
|
## Files needed to be downloaded before install.
|
||||||
|
|
||||||
### To run the server
|
### To run the server
|
||||||
* [PostgresSQL](https://www.postgresql.org/download/windows/) - current version using is 17
|
|
||||||
* [NodeJS](https://nodejs.org)
|
- [PostgresSQL](https://www.postgresql.org/download/windows/) - current version using is 17
|
||||||
* [NSSM](https://nssm.cc/)
|
- [NodeJS](https://nodejs.org)
|
||||||
|
- [NSSM](https://nssm.cc/)
|
||||||
|
|
||||||
### To manage the server
|
### To manage the server
|
||||||
* [VSCODE](https://code.visualstudio.com/)
|
|
||||||
* [Postman](https://www.postman.com/downloads/)
|
- [VSCODE](https://code.visualstudio.com/)
|
||||||
|
- [Postman](https://www.postman.com/downloads/)
|
||||||
|
|
||||||
## Creating directories needed
|
## Creating directories needed
|
||||||
* Create a new folder where we will host the server files.
|
|
||||||
* Copy the nssm.exe into this folder
|
- Create a new folder where we will host the server files.
|
||||||
* Copy the build files to the server (only needed for intial install).
|
- Copy the nssm.exe into this folder
|
||||||
* This will house all the compiles and minified files needed to start the server up, this includes the frontend.
|
- Copy the build files to the server (only needed for intial install).
|
||||||
* Save the nssm.exe into this folder as well, this will be used to control the service.
|
- This will house all the compiles and minified files needed to start the server up, this includes the frontend.
|
||||||
|
- Save the nssm.exe into this folder as well, this will be used to control the service.
|
||||||
|
|
||||||
## Do the intial install
|
## Do the intial install
|
||||||
|
|
||||||
### DB instal setup
|
### DB instal setup
|
||||||
|
|
||||||
1. Install postgres
|
1. Install postgres
|
||||||
2. Open pgAdmin
|
2. Open pgAdmin
|
||||||
3. create a new Database named lst_db
|
3. create a new Database named lst_db
|
||||||
|
|
||||||
### Intial server setup
|
### Intial server setup
|
||||||
|
|
||||||
1. Open VSCode and navigate to the folder where you extracted the files.
|
1. Open VSCode and navigate to the folder where you extracted the files.
|
||||||
2. Click trusted when it pops up.
|
2. Click trusted when it pops up.
|
||||||
3. Open a terminal window inside vscode.
|
3. Open a terminal window inside vscode.
|
||||||
4. Run the install script this will install all dependaceys needed as well as do all the database migrations
|
4. Run the install script this will install all dependaceys needed as well as do all the database migrations
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run prodinstall
|
npm run prodinstall
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Next we want to do an intial build for the db
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
### Create the .env file
|
### Create the .env file
|
||||||
|
|
||||||
In the root of the folder create a new .env file
|
In the root of the folder create a new .env file
|
||||||
add in the below and change each setting area that says change me to something that suits your needs
|
add in the below and change each setting area that says change me to something that suits your needs
|
||||||
|
|
||||||
```env
|
```env
|
||||||
# PORTS
|
# PORTS
|
||||||
# To keep it all simple we will pass VITE to the ports that are used on both sides.
|
# To keep it all simple we will pass VITE to the ports that are used on both sides.
|
||||||
@@ -39,7 +58,9 @@ VITE_SERVER_PORT=4400
|
|||||||
|
|
||||||
# logLevel
|
# logLevel
|
||||||
LOG_LEVEL=debug
|
LOG_LEVEL=debug
|
||||||
|
PROD_PORT=4000
|
||||||
|
# DUE to lstv1 we need 3000
|
||||||
|
SEC_PORT=3000
|
||||||
# Auth stuff
|
# Auth stuff
|
||||||
SALTING=12
|
SALTING=12
|
||||||
SECRET=CHANGEME
|
SECRET=CHANGEME
|
||||||
@@ -47,13 +68,13 @@ JWT_SECRET=CHANGEME
|
|||||||
JWT_REFRESH_SECRET=CHANGEME
|
JWT_REFRESH_SECRET=CHANGEME
|
||||||
|
|
||||||
# Expire info plus refresh change as needed
|
# Expire info plus refresh change as needed
|
||||||
JWT_EXPIRES=60
|
JWT_EXPIRES=60
|
||||||
JWT_REFRESH_THRESHOLD=30
|
JWT_REFRESH_THRESHOLD=30
|
||||||
JWT_ACCESS_EXPIRATION="1h"
|
JWT_ACCESS_EXPIRATION="1h"
|
||||||
JWT_REFRESH_EXPIRATION="7d"
|
JWT_REFRESH_EXPIRATION="7d"
|
||||||
|
|
||||||
# this code will need to be used when a user needs to have access to everything.
|
# this code will need to be used when a user needs to have access to everything.
|
||||||
SECRETOVERRIDECODE="mVSDCpBdxreIJ979ziI71GRubBc2mqVqvZdfA22CB7smBfqlE9S3rKTE909yCHte"
|
SECRETOVERRIDECODE="supersecretKey"
|
||||||
|
|
||||||
# Database url - please change the password if this is all you changed
|
# Database url - please change the password if this is all you changed
|
||||||
DATABASE_URL="postgresql://postgres:PASSWORD@localhost:5432/lst_db"
|
DATABASE_URL="postgresql://postgres:PASSWORD@localhost:5432/lst_db"
|
||||||
@@ -64,62 +85,80 @@ MAXLOTS=3
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Run the start command to get all the basic settings and modules installed
|
### Run the start command to get all the basic settings and modules installed
|
||||||
|
|
||||||
1. Run the below
|
1. Run the below
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
This command will start up the server and seed the database.
|
This command will start up the server and seed the database.
|
||||||
* Settings will be set here.
|
|
||||||
* All modules will be added.
|
- Settings will be set here.
|
||||||
|
- All modules will be added.
|
||||||
|
|
||||||
2. Press CTRL + C to stop the server.
|
2. Press CTRL + C to stop the server.
|
||||||
3. Reopen postgres and review the settings make the changes to match the server your going to be running in.
|
3. Reopen postgres and review the settings make the changes to match the server your going to be running in.
|
||||||
* Change the server
|
- Change the server
|
||||||
* change the dbServer
|
- change the dbServer
|
||||||
* change plantToken
|
- change plantToken
|
||||||
* then the remaining settings confirm if you need on or want to leave as default.
|
- then the remaining settings confirm if you need on or want to leave as default.
|
||||||
|
|
||||||
### Creating first user.
|
### Creating first user.
|
||||||
|
|
||||||
1. Start the server back up.
|
1. Start the server back up.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Open http://[SERVER]:[PORT]/api/docs or postman and create a user.
|
2. Open http://[SERVER]:[PORT]/api/docs or postman and create a user.
|
||||||
* Please do not try to manually enter a new user this is due to how the password is hashed, as well as setting systemAdmin for the first user.
|
- Please do not try to manually enter a new user this is due to how the password is hashed, as well as setting systemAdmin for the first user.
|
||||||
* Change the server and port to what you changed in the DB.
|
- Change the server and port to what you changed in the DB.
|
||||||
3. Stop the server again with CTRL + C.
|
3. Stop the server again with CTRL + C.
|
||||||
|
|
||||||
### Running as a serivice.
|
### Running as a serivice.
|
||||||
|
|
||||||
You want to CD into the scripts folder.
|
You want to CD into the scripts folder.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd .\dist\server\scripts\
|
cd .\dist\server\scripts\
|
||||||
```
|
```
|
||||||
|
|
||||||
Next use the example command below to get the service up and running.
|
Next use the example command below to get the service up and running.
|
||||||
* Options legend
|
|
||||||
* serviceName = not recommended to change to reduce issues with the update process
|
- Options legend
|
||||||
* option = use install for the install, but you can use this script later to stop, start, restart the service.
|
- serviceName = not recommended to change to reduce issues with the update process
|
||||||
* appPath = where did you extract the server files
|
- option = use install for the install, but you can use this script later to stop, start, restart the service.
|
||||||
* description = no need to change this unless you want it to be something else
|
- appPath = where did you extract the server files
|
||||||
* command = do not change this unless you know what your doing and really need to change this.
|
- description = no need to change this unless you want it to be something else
|
||||||
|
- command = do not change this unless you know what your doing and really need to change this.
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\services.ps1 -serviceName "LSTV2" -option "install" -appPath "E:\LST\lstV2" -description "Logistics Support Tool V2" -command "run start"
|
.\services.ps1 -serviceName "LSTV2" -option "install" -appPath "E:\LST\lstV2" -description "Logistics Support Tool V2" -command "run start"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Migrating From V1 to V2
|
# Migrating From V1 to V2
|
||||||
|
|
||||||
## User migration
|
## User migration
|
||||||
|
|
||||||
1. Open the sqlite db and export to sql the users table
|
1. Open the sqlite db and export to sql the users table
|
||||||
2. OPen the sql in notepad++ or your editor of choice and change the query to be similar to below.
|
2. OPen the sql in notepad++ or your editor of choice and change the query to be similar to below.
|
||||||
* we only need to have save the username, role, email, password
|
- we only need to have save the username, role, email, password
|
||||||
|
|
||||||
An example new query will look like
|
An example new query will look like
|
||||||
* Below is how it looks when exported from sqlite
|
|
||||||
|
- Below is how it looks when exported from sqlite
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
INSERT INTO "User" ("id", "username", "email", "role", "password", "passwordToken", "tokenExpire", "active", "pinCode", "lastLogin", "add_user", "add_date", "upd_user", "upd_date") VALUES
|
INSERT INTO "User" ("id", "username", "email", "role", "password", "passwordToken", "tokenExpire", "active", "pinCode", "lastLogin", "add_user", "add_date", "upd_user", "upd_date") VALUES
|
||||||
(1, 'matthes01', 'blake.matthes@alpla.com', 'admin', 'JDJiJDEMUJEdGtL', NULL, NULL, '1', NULL, '1721075647687', 'LST_System', '1721075647687', 'LST_System', '1721075647687');
|
(1, 'matthes01', 'blake.matthes@alpla.com', 'admin', 'JDJiJDEMUJEdGtL', NULL, NULL, '1', NULL, '1721075647687', 'LST_System', '1721075647687', 'LST_System', '1721075647687');
|
||||||
```
|
```
|
||||||
|
|
||||||
The way we want to put recreate the query to work with the new db
|
The way we want to put recreate the query to work with the new db
|
||||||
* Below example
|
|
||||||
|
- Below example
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
INSERT INTO "users" ("username", "email", "role", "password") VALUES
|
INSERT INTO "users" ("username", "email", "role", "password") VALUES
|
||||||
('matthes01','blake.matthes@alpla.com','admin','JDJiJDE1FuNFpkYlk4NGdHUXpEMzlHR1BD'),
|
('matthes01','blake.matthes@alpla.com','admin','JDJiJDE1FuNFpkYlk4NGdHUXpEMzlHR1BD'),
|
||||||
@@ -127,4 +166,12 @@ INSERT INTO "users" ("username", "email", "role", "password") VALUES
|
|||||||
('brandon001','brandon.harry@alpla.com','manager','wdm1RSXJlZnJDYTZP');
|
('brandon001','brandon.harry@alpla.com','manager','wdm1RSXJlZnJDYTZP');
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
* You could have many users and just add like above with the identical info from the db
|
|
||||||
|
- You could have many users and just add like above with the identical info from the db
|
||||||
|
|
||||||
|
## Running v1 along Side V2 for the interm
|
||||||
|
|
||||||
|
- change v2 prod port to 4000 in the env and db
|
||||||
|
- change v1 env to 4400 in the env. and in the db you will need to change the auth server to 4000 and the serverPort to 4400
|
||||||
|
|
||||||
|
This will change so that v2 is the main server now, this is needed for ocme mainly.
|
||||||
|
|||||||
@@ -1,14 +1,424 @@
|
|||||||
$serverDataFile = "..\services\server\utils\serverData.json"
|
param (
|
||||||
|
[string]$server,
|
||||||
|
[string]$token,
|
||||||
|
[string]$location,
|
||||||
|
[string]$devFolder,
|
||||||
|
[string]$serverIP,
|
||||||
|
[string]$build,
|
||||||
|
[string]$type,
|
||||||
|
[string]$username,
|
||||||
|
[string]$admpass,
|
||||||
|
[string]$obslst,
|
||||||
|
[string]$obsBuild
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert the plain-text password to a SecureString
|
||||||
|
$securePass = ConvertTo-SecureString $admpass -AsPlainText -Force
|
||||||
|
$credentials = New-Object System.Management.Automation.PSCredential($username, $securePass)
|
||||||
|
|
||||||
|
# lets get the version of the app we are updating
|
||||||
|
$pkgFile = "$devFolder\package.json"
|
||||||
|
$package = Get-Content -Path $pkgFile -Raw | ConvertFrom-Json
|
||||||
|
|
||||||
|
$version = "$($package.version)-$($package.admConfig.build -1)"
|
||||||
|
|
||||||
|
# Checking to make sure the server is up and online
|
||||||
|
Write-Output "Checking if $($token) is online to update."
|
||||||
|
$pingResult = Test-Connection -ComputerName $serverIP -Count 2 -Quiet
|
||||||
|
|
||||||
|
if (-not $pingResult) {
|
||||||
|
Write-Output "Server $($server) $($serverIP) is NOT reachable. Exiting script."
|
||||||
|
exit 1 # Terminate the script with a non-zero exit code
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Server $($server) ($serverIP) is online."
|
||||||
|
|
||||||
|
# get the file name we want to grab
|
||||||
|
|
||||||
|
$buildZip = "lstv2-$version.zip"
|
||||||
|
|
||||||
|
if (-Not (Test-Path -Path "$($build)\$($buildZip)")) {
|
||||||
|
Write-Host "Build is missing from the build folder."
|
||||||
|
Write-host $buildZip
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "---------------Starting the update Process----------------------------------"
|
||||||
|
Write-Host "File to be copied over is $buildZip"
|
||||||
|
Write-Host "Coping files to $($server)"
|
||||||
|
$destination = "\\$($server)\$($location)" -replace ":", "$"
|
||||||
|
Write-Host $destination
|
||||||
|
Write-Host "Forcing the removal of the mapped drive."
|
||||||
|
Get-PSDrive -Name "z" -ErrorAction SilentlyContinue | Remove-PSDrive -Force
|
||||||
|
|
||||||
|
# Create a mapped drive with credentials using New-PSDrive for the current session
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
New-PSDrive -Name "z" -PSProvider FileSystem -Root $destination -Credential $credentials
|
||||||
|
|
||||||
|
# Create the update folder if it doesn't exist
|
||||||
|
if (-not (Test-Path -Path $destination)) {
|
||||||
|
New-Item -ItemType Directory -Path $destination -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copying files to the server
|
||||||
|
Write-Host "Copying files to $($server)"
|
||||||
|
Copy-Item -Path "$($build)\$($buildZip)" -Destination "z:\" -Recurse -Force
|
||||||
|
Write-Host "Files copied to $($server)"
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_"
|
||||||
|
} finally {
|
||||||
|
# Remove the mapped drive after copying
|
||||||
|
if (Get-PSDrive -Name "z" -ErrorAction SilentlyContinue) {
|
||||||
|
Write-Host "Removing mapped drive..."
|
||||||
|
Remove-PSDrive -Name "z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write-Host $extractedFolderPath = "$server\$location$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
|
||||||
|
# The script that runs inside the plant.
|
||||||
|
$plantFunness = {
|
||||||
|
param ($server, $token, $location, $buildFile, $buildLoc, $obslst, $obsBuild)
|
||||||
|
|
||||||
|
$localPath = $location -replace '\$', ':'
|
||||||
|
$serverFile = "$($localPath)\$buildFile"
|
||||||
|
$serverPath = "$($localPath)"
|
||||||
|
|
||||||
|
Write-Host "In the plant we go!!!!!"
|
||||||
|
Write-Host "Unzipping the folder..."
|
||||||
|
|
||||||
|
$extractedFolderPath = $serverPath
|
||||||
|
|
||||||
|
# Extract the files to the build path
|
||||||
|
try {
|
||||||
|
# Expand the archive
|
||||||
|
Expand-Archive -Path $serverFile -DestinationPath $extractedFolderPath -Force
|
||||||
|
|
||||||
|
# Delete the zip file after extraction
|
||||||
|
Write-Host "Deleting the zip file..."
|
||||||
|
Remove-Item -Path $serverFile -Force
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_"
|
||||||
|
exit 1 # Exit with a non-zero code if there's an error
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "-----------------------Dealing with LSTv1 Stuff ------------------------------------"
|
||||||
|
try {
|
||||||
|
# Expand the archive
|
||||||
|
Expand-Archive -Path "$($localPath)\$($obsBuild)" -DestinationPath $obslst -Force
|
||||||
|
|
||||||
|
# Delete the zip file after extraction
|
||||||
|
Write-Host "Deleting the zip file..."
|
||||||
|
Remove-Item -Path "$($localPath)\$($obsBuild)" -Force
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_"
|
||||||
|
exit 1 # Exit with a non-zero code if there's an error
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
Write-Host "Stopping the services to do the updates, pkgs and db changes."
|
||||||
|
|
||||||
|
Write-Host "Stopping services to update"
|
||||||
|
$serviceGateway = "LST-Gateway$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
$serviceAuth = "LST-Auth$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
$serviceSystem = "LST-System$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
$serviceApp = "LST-App$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
$serviceFrontEnd = "LST-frontend$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
$serviceOcme = "LST-Ocme$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
$serviceLstV2 = "LSTV2$(if ($token -eq "usiow2") { "_2" })"
|
||||||
|
|
||||||
|
if($token -eq "usday1"){
|
||||||
|
Write-Host "Stopping $($serviceOcme)"
|
||||||
|
Stop-Service -DisplayName $serviceOcme -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Stopping $($serviceGateway)"
|
||||||
|
Stop-Service -DisplayName $serviceGateway -Force
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
Write-Host "Stopping $($serviceAuth)"
|
||||||
|
Stop-Service -DisplayName $serviceAuth -Force
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
Write-Host "Stopping $($serviceSystem)"
|
||||||
|
Stop-Service -DisplayName $serviceSystem -Force
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
Write-Host "Stopping $($serviceApp)"
|
||||||
|
Stop-Service -DisplayName $serviceApp -Force
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
Write-Host "Stopping $($serviceFrontEnd)"
|
||||||
|
Stop-Service -DisplayName $serviceFrontEnd -Force
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
Write-Host "Stopping $($serviceLstV2)"
|
||||||
|
Stop-Service -DisplayName $serviceLstV2 -Force
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
# Service removoal and making sure we have the new version added
|
||||||
|
#################################################################
|
||||||
|
|
||||||
|
$appPath = $extractedFolderPath
|
||||||
|
$nssmPath = $serverPath + "\nssm.exe"
|
||||||
|
$npmPath = "C:\Program Files\nodejs\npm.cmd" # Path to npm.cmd
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
# Removing all the old services
|
||||||
|
#################################################################
|
||||||
|
Write-Host "Removing services that are no longer used."
|
||||||
|
& $nssmPath remove "LogisticsSupportTool" confirm
|
||||||
|
& $nssmPath remove $serviceAuth confirm
|
||||||
|
# & $nssmPath remove $serviceGateway confirm
|
||||||
|
# if($token -eq "usday1"){
|
||||||
|
# & $nssmPath remove $serviceOcme confirm
|
||||||
|
# }
|
||||||
|
Start-Sleep -Seconds 5
|
||||||
|
|
||||||
|
$service = Get-Service -Name $serviceLstV2 -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if(-not $service){
|
||||||
|
## adding in lstAdm
|
||||||
|
Write-Host "Adding $($serviceLstV2)... incase its missing."
|
||||||
|
$commandToRun = "run start"
|
||||||
|
$description = "logistics Support Tool"
|
||||||
|
& $nssmPath install $serviceLstV2 $npmPath $commandToRun
|
||||||
|
Write-Host "Setting the app directory"
|
||||||
|
& $nssmPath set $serviceLstV2 AppDirectory $appPath
|
||||||
|
Write-Host "Setting the description"
|
||||||
|
& $nssmPath set $serviceLstV2 Description $description
|
||||||
|
Write-Host "Setting recovery options"
|
||||||
|
# Set recovery options
|
||||||
|
sc.exe failure $serviceLstV2 reset= 0 actions= restart/5000/restart/5000/restart/5000
|
||||||
|
}
|
||||||
|
# Doing an install
|
||||||
|
Write-Host "Running the install to make sure everything is updated."
|
||||||
|
Set-Location $serverPath
|
||||||
|
npm run prodinstall # --omit=dev
|
||||||
|
Write-Host "Finished doing updates"
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
# Old system still active until we have everything off it
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
# Frontend env
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
Write-Host "Creating the env file in the front end"
|
||||||
|
$envContentTemplatef = @"
|
||||||
|
NEXTAUTH_SECRET= "12348fssad5sdg2f2354afvfw34"
|
||||||
|
NEXTAUTH_URL_INTERNAL= "http://localhost:3000"
|
||||||
|
NEXTAUTH_URL="{url}"
|
||||||
|
API_KEY= "E3ECD3619A943B98C6F33E3322362"
|
||||||
|
"@
|
||||||
|
|
||||||
|
try {
|
||||||
|
$url = "http://$($token)vms006:3000"
|
||||||
|
|
||||||
|
if ($token -eq "usiow2") {
|
||||||
|
$url = "http://usiow1vms006:3001"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token -in @("test1", "test2", "test3")) {
|
||||||
|
$url = "http://usmcd1vms036:3000"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Replace {url} with the actual $url
|
||||||
|
$envContentf = $envContentTemplatef -replace "{url}", $url
|
||||||
|
|
||||||
|
# Define the path where the .env file should be created
|
||||||
|
$envFilePathf = $obslst + "\apps\frontend\.env"
|
||||||
|
Write-Host "Final URL: $url"
|
||||||
|
# Write the content to the .env file
|
||||||
|
$envContentf | Out-File -FilePath $envFilePathf -Encoding UTF8 -Force
|
||||||
|
|
||||||
|
# Optional: Verify the file was created
|
||||||
|
if (Test-Path $envFilePathf) {
|
||||||
|
Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathf"
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
# DB env
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
Write-Host "Creating the env file in the front end"
|
||||||
|
$envContentTemplateb = @"
|
||||||
|
DATABASE_URL="file:E:\LST\db\{dbLink}.db"
|
||||||
|
"@
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$dbLink = "lstBackendDB"
|
||||||
|
|
||||||
|
if ($token -eq "usiow2") {
|
||||||
|
$dbLink = "lstBackendDB_2"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token -in @("test1", "test2", "test3")) {
|
||||||
|
$dbLink = "lstBackendDB"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Replace {url} with the actual $url
|
||||||
|
$envContentb = $envContentTemplateb -replace "{dbLink}", $dbLink
|
||||||
|
|
||||||
|
# Define the path where the .env file should be created
|
||||||
|
$envFilePathb = $obslst + "\packages\database\.env"
|
||||||
|
|
||||||
|
# Write the content to the .env file
|
||||||
|
$envContentb | Out-File -FilePath $envFilePathb -Encoding UTF8 -Force
|
||||||
|
|
||||||
|
# Optional: Verify the file was created
|
||||||
|
if (Test-Path $envFilePathb) {
|
||||||
|
Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathb"
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
# backend env
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
Write-Host "Creating the env file in the front end"
|
||||||
|
$envContentTemplated = @"
|
||||||
|
# Server env
|
||||||
|
NODE_ENV = production
|
||||||
|
# server apiKey
|
||||||
|
API_KEY = E3ECD3619A943B98C6F33E3322362
|
||||||
|
# Prisma DB link
|
||||||
|
DATABASE_URL="file:E:\LST\db\{dbLink}.db"
|
||||||
|
# if you still want the db in the same folder as the server install you need to do like the example below else use the relevent link
|
||||||
|
DATEBASE_LOC="E:\LST\db\{dbLink}.db"
|
||||||
|
DATABASE_BACKUP_LOC="E:\LST\backups"
|
||||||
|
# Server port
|
||||||
|
GATEWAY_PORT={gatewayport}
|
||||||
|
AUTH_PORT=4100
|
||||||
|
SYSTEM_APP_PORT={systemport}
|
||||||
|
OCME_PORT={ocme}
|
||||||
|
|
||||||
|
# This should me removed once we have the entire app broke out to its own apps
|
||||||
|
OLD_APP_PORT={appPort}
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_LEVEL = info
|
||||||
|
LOG_LOC ="E:\\LST\\logs"
|
||||||
|
|
||||||
|
# authentication
|
||||||
|
SALTING = 12
|
||||||
|
SECRET = E3ECD3619A943B98C6F33E3322362
|
||||||
|
JWT_SECRET = 12348fssad5sdg2f2354afvfw34
|
||||||
|
JWT_EXPIRES_TIME = 1h
|
||||||
|
|
||||||
|
# cookie time is in min please take this into consideration when creating all the times
|
||||||
|
COOKIE_EXPIRES_TIME = 60
|
||||||
|
|
||||||
|
# password token reset in mintues
|
||||||
|
RESET_TOKEN = 330
|
||||||
|
"@
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$dbLink = "lstBackendDB"
|
||||||
|
$gatewayport = "4400"
|
||||||
|
$systemport = "4200"
|
||||||
|
$ocmeport = "4300"
|
||||||
|
$appport = "4900"
|
||||||
|
|
||||||
|
if ($token -eq "usiow2") {
|
||||||
|
$dbLink = "lstBackendDB_2"
|
||||||
|
$gatewayport = "4401"
|
||||||
|
$systemport = "4201"
|
||||||
|
$ocmeport = "4301"
|
||||||
|
$appport = "4901"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($token -in @("test1", "test2", "test3")) {
|
||||||
|
$dbLink = "lstBackendDB"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
$port1 = $envContentTemplated -replace "{gatewayport}", $gatewayport
|
||||||
|
$port2 = $port1 -replace "{systemport}", $systemport
|
||||||
|
$port3 = $port2 -replace "{ocme}", $ocmeport
|
||||||
|
$port4 = $port3 -replace "{appPort}", $appport
|
||||||
|
$envContentd = $port4 -replace "{dbLink}", $dbLink
|
||||||
|
|
||||||
|
|
||||||
$jsonContent = Get-Content -Path $serverDataFile -Raw
|
# Define the path where the .env file should be created
|
||||||
|
$envFilePathd = $obslst + "\.env"
|
||||||
# Convert the JSON content to a PowerShell object
|
|
||||||
$jsonObject = $jsonContent | ConvertFrom-Json
|
# Write the content to the .env file
|
||||||
|
$envContentd | Out-File -FilePath $envFilePathd -Encoding UTF8 -Force
|
||||||
# Access the data in the JSON object
|
|
||||||
$servers = $jsonObject.servers
|
# Optional: Verify the file was created
|
||||||
|
if (Test-Path $envFilePathd) {
|
||||||
|
Write-Host "`.env` file created successfully on $env:COMPUTERNAME at $envFilePathd"
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to create `.env` file on $env:COMPUTERNAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: Failed to create `.env` file on $server - $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Write-Host "Running install on obs server."
|
||||||
|
Set-Location $obslst
|
||||||
|
npm run newinstall # --omit=dev
|
||||||
|
Write-Host "Update the frontend"
|
||||||
|
npm run install:front
|
||||||
|
npm run install:ui
|
||||||
|
npm run install:db
|
||||||
|
|
||||||
Write-Host $servers
|
Write-Host "Running db updates"
|
||||||
|
npm run db:migrate
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
npm run db:gen
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
Write-Host "incase a new default setting was added we want to add it in."
|
||||||
|
npm run db:init
|
||||||
|
|
||||||
|
###########################################################
|
||||||
|
# Starting the services back up.
|
||||||
|
###########################################################
|
||||||
|
Write-Host "Starting the services"
|
||||||
|
Write-Host "Starting $($serviceSystem)"
|
||||||
|
Start-Service -DisplayName $serviceSystem
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
Write-Host "Starting $($serviceGateway)"
|
||||||
|
Start-Service -DisplayName $serviceGateway
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
#Write-Host "Starting $($serviceAuth)"
|
||||||
|
#Start-Service -DisplayName $serviceAuth
|
||||||
|
#Start-Sleep -Seconds 1
|
||||||
|
Write-Host "Starting $($serviceApp)"
|
||||||
|
Start-Service -DisplayName $serviceApp
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
Write-Host "Starting $($serviceFrontEnd)"
|
||||||
|
Start-Service -DisplayName $serviceFrontEnd
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
Write-Host "Starting $( $serviceLstV2)"
|
||||||
|
Start-Service -DisplayName $serviceLstV2
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
Write-Host "$($server) finished updating"
|
||||||
|
if($token -eq "usday1"){
|
||||||
|
Write-Host "Starting $($serviceOcme)"
|
||||||
|
Start-Service -DisplayName $serviceOcme
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Invoke-Command -ComputerName $server -ScriptBlock $plantFunness -ArgumentList $server, $token, $location, $buildZip, $buildLoc, $obslst, $obsBuild -Credential $credentials
|
||||||
173
server/scripts/updateServers.ts
Normal file
173
server/scripts/updateServers.ts
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
import {spawn} from "child_process";
|
||||||
|
import {getAppInfo} from "../globalUtils/appInfo.js";
|
||||||
|
import {db} from "../../database/dbclient.js";
|
||||||
|
import {serverData} from "../../database/schema/serverData.js";
|
||||||
|
import {eq, sql} from "drizzle-orm";
|
||||||
|
import {createLog} from "../services/logger/logger.js";
|
||||||
|
|
||||||
|
type UpdateServerResponse = {
|
||||||
|
success: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateServer = async (devApp: string, server: string | null): Promise<UpdateServerResponse> => {
|
||||||
|
const app = await getAppInfo(devApp);
|
||||||
|
const serverInfo = await db
|
||||||
|
.select()
|
||||||
|
.from(serverData)
|
||||||
|
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
|
||||||
|
|
||||||
|
if (serverInfo.length === 0) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"serverUpdater",
|
||||||
|
`Looks like you are missing the plant token or have entered an incorrect one please try again.`
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "Looks like you are missing the plant token or have entered an incorrect one please try again.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverInfo[0].isUpgrading) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"serverUpdater",
|
||||||
|
`Looks like ${serverInfo[0].plantToken} is upgrading already you cant do this again.`
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: `Looks like ${serverInfo[0].plantToken} is upgrading already you cant do this again.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const scriptPath = `${process.env.DEVFOLDER}\\server\\scripts\\update.ps1 `;
|
||||||
|
const args = [
|
||||||
|
"-NoProfile",
|
||||||
|
"-ExecutionPolicy",
|
||||||
|
"Bypass",
|
||||||
|
"-File",
|
||||||
|
scriptPath,
|
||||||
|
"-username",
|
||||||
|
process.env.ADMUSER, // needs moved to somewhere else.
|
||||||
|
"-admpass",
|
||||||
|
process.env.ADMPASSWORD, // needs moved to somewhere else.
|
||||||
|
"-devFolder",
|
||||||
|
process.env.DEVFOLDER,
|
||||||
|
"-server",
|
||||||
|
serverInfo[0].serverDNS,
|
||||||
|
"-serverIP",
|
||||||
|
serverInfo[0].idAddress,
|
||||||
|
"-token",
|
||||||
|
serverInfo[0].plantToken,
|
||||||
|
"-build",
|
||||||
|
`${process.env.DEVFOLDER}\\builds`,
|
||||||
|
"-location",
|
||||||
|
serverInfo[0].serverLoc,
|
||||||
|
"-obslst",
|
||||||
|
serverInfo[0].oldVersion,
|
||||||
|
"-obsBuild",
|
||||||
|
app.admConfig.oldBuild,
|
||||||
|
,
|
||||||
|
];
|
||||||
|
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
const process = spawn("powershell", args);
|
||||||
|
// change the server to upgradeing
|
||||||
|
await db
|
||||||
|
.update(serverData)
|
||||||
|
.set({isUpgrading: true})
|
||||||
|
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
|
||||||
|
//let stdout = "";
|
||||||
|
//let stderr = "";
|
||||||
|
|
||||||
|
// Collect stdout data
|
||||||
|
process.stdout.on("data", (data) => {
|
||||||
|
const output = data.toString().trim();
|
||||||
|
createLog("info", "lst", "serverUpdater", `${output}`);
|
||||||
|
//onData(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Collect stderr data
|
||||||
|
process.stderr.on("data", (data) => {
|
||||||
|
const output = data.toString().trim();
|
||||||
|
createLog("info", "lst", "serverUpdater", `${output}`);
|
||||||
|
//onData(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle process close
|
||||||
|
process.on("close", async (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
// if (count >= servers) {
|
||||||
|
// //onClose(`Server completed with code: ${code}`);
|
||||||
|
// }
|
||||||
|
createLog("info", "lst", "serverUpdater", `${server}`);
|
||||||
|
|
||||||
|
//update the last build.
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.update(serverData)
|
||||||
|
.set({lastUpdated: sql`NOW()`, isUpgrading: false})
|
||||||
|
.where(eq(serverData.plantToken, server?.toLowerCase() ?? ""));
|
||||||
|
createLog(
|
||||||
|
"info",
|
||||||
|
"lst",
|
||||||
|
"serverUpdater",
|
||||||
|
`${server?.toLowerCase()}, has been updated and can now be used again.`
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"serverUpdater",
|
||||||
|
`There was an error updating the last time the server was updated: ${error}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
message: `${server?.toLowerCase()}, has been updated and can now be used again.`,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const errorMessage = `Process exited with code ${code}`;
|
||||||
|
|
||||||
|
// if (count >= servers) {
|
||||||
|
// //onClose(code);
|
||||||
|
// }
|
||||||
|
|
||||||
|
reject({
|
||||||
|
success: false,
|
||||||
|
message: `${server?.toLowerCase()}, Has encounted an error while updating.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle errors with the process itself
|
||||||
|
process.on("error", (error) => {
|
||||||
|
//onError(err.message);
|
||||||
|
createLog("error", "lst", "serverUpdater", `${error}`);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function processAllServers(devApp: string) {
|
||||||
|
const servers = await db.select().from(serverData);
|
||||||
|
|
||||||
|
createLog("info", "lst", "serverUpdater", `Running the update on all servers`);
|
||||||
|
let count = 1;
|
||||||
|
for (const server of servers) {
|
||||||
|
try {
|
||||||
|
const updateToServer = await updateServer(devApp, server.plantToken);
|
||||||
|
createLog("info", "lst", "serverUpdater", `${server.sName} was updated.`);
|
||||||
|
count = count + 1;
|
||||||
|
|
||||||
|
//return {success: true, message: `${server.sName} was updated.`, data: updateToServer};
|
||||||
|
} catch (error: any) {
|
||||||
|
createLog("info", "lst", "serverUpdater", `Error updating ${server.sName}: ${error.message}`);
|
||||||
|
//return {success: false, message: `Error updating ${server.sName}: ${error.message}`};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
210
server/scripts/zipUpBuild.ts
Normal file
210
server/scripts/zipUpBuild.ts
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import AdmZip from "adm-zip";
|
||||||
|
import path from "path";
|
||||||
|
import fs from "fs";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
import { createLog } from "../services/logger/logger.js";
|
||||||
|
import { getAppInfo } from "../globalUtils/appInfo.js";
|
||||||
|
|
||||||
|
// create the ignore list
|
||||||
|
const ignoreList = [
|
||||||
|
".git",
|
||||||
|
"builds",
|
||||||
|
"server",
|
||||||
|
"node_modules",
|
||||||
|
"apiDocsLSTV2",
|
||||||
|
"testFiles",
|
||||||
|
".env",
|
||||||
|
".gitignore",
|
||||||
|
".versionrc.json",
|
||||||
|
"drizzle-dev.config.ts",
|
||||||
|
"nssm.exe",
|
||||||
|
"postgresql-17.2-3-windows-x64.exe",
|
||||||
|
// front end ignore
|
||||||
|
"frontend/node_modules",
|
||||||
|
"fonrtend/.env",
|
||||||
|
"frontend/public",
|
||||||
|
"frontend/src",
|
||||||
|
"frontend/.gitignore",
|
||||||
|
"frontend/eslint.config.js",
|
||||||
|
"frontend/index.html",
|
||||||
|
"frontend/package.json",
|
||||||
|
"frontend/package-lock.json",
|
||||||
|
"frontend/README.md",
|
||||||
|
"frontend/tsconfig.json",
|
||||||
|
"frontend/tsconfig.app.json",
|
||||||
|
"frontend/tsconfig.node.json",
|
||||||
|
"frontend/vite.config.ts",
|
||||||
|
"frontend/components.json",
|
||||||
|
];
|
||||||
|
|
||||||
|
const shouldIgnore = (itemPath: any) => {
|
||||||
|
const normalizedItemPath = itemPath.replace(/\\/g, "/");
|
||||||
|
|
||||||
|
return ignoreList.some((ignorePattern) => {
|
||||||
|
const normalizedIgnorePatther = ignorePattern.replace(/\\/g, "/");
|
||||||
|
return (
|
||||||
|
normalizedItemPath === normalizedIgnorePatther ||
|
||||||
|
normalizedItemPath.startsWith(`${normalizedIgnorePatther}/`)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToZip = (zip: any, currentPath: string, rootPath: string) => {
|
||||||
|
const items = fs.readdirSync(currentPath);
|
||||||
|
|
||||||
|
items.forEach((item) => {
|
||||||
|
const itemPath = path.join(currentPath, item);
|
||||||
|
const relativePath = path.relative(rootPath, itemPath);
|
||||||
|
|
||||||
|
// Skip if the item is in the ignore list
|
||||||
|
if (shouldIgnore(relativePath)) {
|
||||||
|
createLog("info", "lst", "zipUpBuild", `Ignoring: ${relativePath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stat = fs.statSync(itemPath);
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
// If it's a directory, recursively add its contents
|
||||||
|
addToZip(zip, itemPath, rootPath);
|
||||||
|
} else {
|
||||||
|
// If it's a file, add it to the zip with the preserved folder structure
|
||||||
|
zip.addLocalFile(itemPath, path.dirname(relativePath));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateBuildNumber = (appLock: string) => {
|
||||||
|
const packagePath = path.join(appLock, "package.json"); // Adjust path if necessary
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Read package.json
|
||||||
|
const pkgData = fs.readFileSync(packagePath, "utf8");
|
||||||
|
const pkgJson = JSON.parse(pkgData);
|
||||||
|
|
||||||
|
// Ensure admConfig exists
|
||||||
|
if (pkgJson.admConfig && typeof pkgJson.admConfig.build === "number") {
|
||||||
|
// Increment the build number
|
||||||
|
pkgJson.admConfig.build += 1;
|
||||||
|
|
||||||
|
// Write the updated data back
|
||||||
|
fs.writeFileSync(packagePath, JSON.stringify(pkgJson, null, 2), "utf8");
|
||||||
|
|
||||||
|
createLog(
|
||||||
|
"info",
|
||||||
|
"lst",
|
||||||
|
"zipUpBuild",
|
||||||
|
`Build number updated to: ${pkgJson.admConfig.build}`
|
||||||
|
);
|
||||||
|
// Auto-commit changes
|
||||||
|
execSync("git add package.json");
|
||||||
|
execSync(
|
||||||
|
`git commit -m "build: bump build number to ${pkgJson.admConfig.build}"`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"zipUpBuild",
|
||||||
|
"admConfig.build is missing or not a number"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"zipUpBuild",
|
||||||
|
`Error updating build number: ${error}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createZip = async (appLock: string) => {
|
||||||
|
const app = await getAppInfo(appLock);
|
||||||
|
const zip = new AdmZip();
|
||||||
|
|
||||||
|
//dest path for this app... hard coded for meow will be in db later
|
||||||
|
const destPath = `${process.env.DEVFOLDER}\\builds`;
|
||||||
|
const srcPath = `${process.env.DEVFOLDER}`;
|
||||||
|
|
||||||
|
addToZip(zip, srcPath, srcPath);
|
||||||
|
|
||||||
|
// Write the zip file to disk
|
||||||
|
const outputZipPath = path.join(
|
||||||
|
destPath,
|
||||||
|
`${app.name}-${app.version}-${app.admConfig.build}.zip`
|
||||||
|
);
|
||||||
|
zip.writeZip(outputZipPath);
|
||||||
|
|
||||||
|
createLog(
|
||||||
|
"info",
|
||||||
|
"lst",
|
||||||
|
"zipUpBuild",
|
||||||
|
`Zip file created at ${outputZipPath}`
|
||||||
|
);
|
||||||
|
updateBuildNumber(appLock);
|
||||||
|
|
||||||
|
// only keep the last 5 builds for the type we have.
|
||||||
|
try {
|
||||||
|
const appFiles = fs
|
||||||
|
.readdirSync(destPath)
|
||||||
|
.filter((file) => file.startsWith(app.name)) // Ensure only backend files are matched
|
||||||
|
.map((file) => ({
|
||||||
|
name: file,
|
||||||
|
time: fs.statSync(path.join(destPath, file)).mtime.getTime(),
|
||||||
|
}))
|
||||||
|
.sort((a, b) => a.time - b.time); // Sort by modification time (oldest first)
|
||||||
|
|
||||||
|
createLog(
|
||||||
|
"info",
|
||||||
|
"lst",
|
||||||
|
"zipUpBuild",
|
||||||
|
`app Files (sorted by time):", ${JSON.stringify(appFiles)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (appFiles.length > 5) {
|
||||||
|
appFiles.slice(0, -5).forEach((file) => {
|
||||||
|
const filePath = path.join(destPath, file.name);
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(filePath);
|
||||||
|
createLog("info", "lst", "zipUpBuild", `Deleted: ${file.name}`);
|
||||||
|
} catch (error: any) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"zipUpBuild",
|
||||||
|
`Failed to delete ${file.name}: ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
createLog("info", "lst", "zipUpBuild", "No files to delete.");
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
createLog(
|
||||||
|
"error",
|
||||||
|
"lst",
|
||||||
|
"zipUpBuild",
|
||||||
|
`Error reading directory or deleting files:", ${error.message}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//createZip("C:\\Users\\matthes01\\Documents\\lstv2");
|
||||||
|
|
||||||
|
// Only call `createZip` if the script is executed directly
|
||||||
|
|
||||||
|
if (process.argv.length > 2) {
|
||||||
|
const location = process.argv[2];
|
||||||
|
|
||||||
|
if (!location) {
|
||||||
|
createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
createLog("info", "lst", "zipUpBuild", "Startiing the zip process.");
|
||||||
|
}
|
||||||
|
|
||||||
|
createZip(location);
|
||||||
|
} else {
|
||||||
|
createLog("error", "lst", "zipUpBuild", "Error: No location provided.");
|
||||||
|
}
|
||||||
@@ -1,30 +1,37 @@
|
|||||||
import {OpenAPIHono} from "@hono/zod-openapi";
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import {authMiddleware} from "./middleware/authMiddleware.js";
|
|
||||||
|
|
||||||
import login from "./routes/login.js";
|
import login from "./routes/login.js";
|
||||||
import register from "./routes/register.js";
|
import register from "./routes/register.js";
|
||||||
import session from "./routes/session.js";
|
import session from "./routes/session.js";
|
||||||
import getAccess from "./routes/userRoles/getUserRoles.js";
|
import getAccess from "./routes/user/getUserRoles.js";
|
||||||
import setAccess from "./routes/userRoles/setUserRoles.js";
|
import setAccess from "./routes/userAdmin/setUserRoles.js";
|
||||||
import profile from "./routes/user/profileUpdate.js";
|
import profile from "./routes/user/profileUpdate.js";
|
||||||
import {areRolesIn} from "./utils/roleCheck.js";
|
import { areRolesIn } from "./utils/roleCheck.js";
|
||||||
|
import createUser from "./routes/userAdmin/createUser.js";
|
||||||
|
import allUsers from "./routes/userAdmin/getUsers.js";
|
||||||
|
import updateUser from "./routes/userAdmin/updateUser.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
// run the role check
|
// run the role check
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
areRolesIn();
|
areRolesIn();
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
app.route("auth/login", login);
|
const routes = [
|
||||||
app.route("auth/register", register);
|
login,
|
||||||
app.route("auth/session", session);
|
register,
|
||||||
|
session,
|
||||||
|
profile,
|
||||||
|
getAccess,
|
||||||
|
setAccess,
|
||||||
|
createUser,
|
||||||
|
allUsers,
|
||||||
|
updateUser,
|
||||||
|
] as const;
|
||||||
|
|
||||||
// required to login
|
// app.route("/server", modules);
|
||||||
/* User area just needs to be logged in to enter here */
|
const appRoutes = routes.forEach((route) => {
|
||||||
app.route("auth/profileupdate", profile);
|
app.route("/auth", route);
|
||||||
|
});
|
||||||
|
|
||||||
/* will need to increase to make sure the person coming here has the correct permissions */
|
|
||||||
app.route("auth/getuseraccess", getAccess);
|
|
||||||
app.route("auth/setuseraccess", setAccess);
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {eq, sql} from "drizzle-orm";
|
|||||||
import {checkPassword} from "../utils/checkPassword.js";
|
import {checkPassword} from "../utils/checkPassword.js";
|
||||||
import {roleCheck} from "./userRoles/getUserAccess.js";
|
import {roleCheck} from "./userRoles/getUserAccess.js";
|
||||||
import {createLog} from "../../logger/logger.js";
|
import {createLog} from "../../logger/logger.js";
|
||||||
|
import {differenceInDays} from "date-fns";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate a user and return a JWT.
|
* Authenticate a user and return a JWT.
|
||||||
@@ -38,7 +39,7 @@ export async function login(
|
|||||||
user_id: user[0].user_id,
|
user_id: user[0].user_id,
|
||||||
username: user[0].username,
|
username: user[0].username,
|
||||||
email: user[0].email,
|
email: user[0].email,
|
||||||
roles: roles || null,
|
//roles: roles || null,
|
||||||
role: user[0].role || null, // this should be removed onces full migration to v2 is completed
|
role: user[0].role || null, // this should be removed onces full migration to v2 is completed
|
||||||
prod: btoa(`${username.toLowerCase()}:${password}`),
|
prod: btoa(`${username.toLowerCase()}:${password}`),
|
||||||
};
|
};
|
||||||
@@ -50,7 +51,14 @@ export async function login(
|
|||||||
.set({lastLogin: sql`NOW()`})
|
.set({lastLogin: sql`NOW()`})
|
||||||
.where(eq(users.user_id, user[0].user_id))
|
.where(eq(users.user_id, user[0].user_id))
|
||||||
.returning({lastLogin: users.lastLogin});
|
.returning({lastLogin: users.lastLogin});
|
||||||
createLog("info", "lst", "auth", `Its been 5days since ${user[0].username} has logged in`);
|
createLog(
|
||||||
|
"info",
|
||||||
|
"lst",
|
||||||
|
"auth",
|
||||||
|
`Its been ${differenceInDays(lastLog[0]?.lastLogin ?? "", new Date(Date.now()))} days since ${
|
||||||
|
user[0].username
|
||||||
|
} has logged in`
|
||||||
|
);
|
||||||
//]);
|
//]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
createLog("error", "lst", "auth", "There was an error updating the user last login");
|
createLog("error", "lst", "auth", "There was an error updating the user last login");
|
||||||
|
|||||||
24
server/services/auth/controllers/userAdmin/getUsers.ts
Normal file
24
server/services/auth/controllers/userAdmin/getUsers.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
|
import { users } from "../../../../../database/schema/users.js";
|
||||||
|
import { returnRes } from "../../../../globalUtils/routeDefs/returnRes.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
|
||||||
|
export const getAllUsers = async () => {
|
||||||
|
/**
|
||||||
|
* returns all users that are in lst
|
||||||
|
*/
|
||||||
|
createLog("info", "apiAuthedRoute", "auth", "Get all users");
|
||||||
|
const { data, error } = await tryCatch(db.select().from(users));
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
returnRes(
|
||||||
|
false,
|
||||||
|
"There was an error getting users",
|
||||||
|
new Error("No user exists.")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
returnRes(true, "All users.", data);
|
||||||
|
return { success: true, message: "All users", data };
|
||||||
|
};
|
||||||
68
server/services/auth/controllers/userAdmin/updateUserAdm.ts
Normal file
68
server/services/auth/controllers/userAdmin/updateUserAdm.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { db } from "../../../../../database/dbclient.js";
|
||||||
|
import { users } from "../../../../../database/schema/users.js";
|
||||||
|
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
|
||||||
|
import type { User } from "../../../../types/users.js";
|
||||||
|
import { createPassword } from "../../utils/createPassword.js";
|
||||||
|
import { createLog } from "../../../logger/logger.js";
|
||||||
|
|
||||||
|
export const updateUserADM = async (userData: User) => {
|
||||||
|
/**
|
||||||
|
* The user model will need to be passed over so we can update per the request on the user.
|
||||||
|
* password, username, email.
|
||||||
|
*/
|
||||||
|
|
||||||
|
createLog(
|
||||||
|
"info",
|
||||||
|
"apiAuthedRoute",
|
||||||
|
"auth",
|
||||||
|
`${userData.user_id} is being updated.`
|
||||||
|
);
|
||||||
|
// get the orignal user info
|
||||||
|
const { data: user, error: userError } = await tryCatch(
|
||||||
|
db.select().from(users).where(eq(users.user_id, userData.user_id!))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userError) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "There was an error getting the user",
|
||||||
|
userError,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (user?.length === 0) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message:
|
||||||
|
"The user you are looking for has either been deleted or dose not exist.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const upd_user = user as User;
|
||||||
|
const password: string = userData.password
|
||||||
|
? await createPassword(userData.password!)
|
||||||
|
: upd_user.password!;
|
||||||
|
const data = {
|
||||||
|
username: userData.username ? userData.username : upd_user?.username,
|
||||||
|
password: password,
|
||||||
|
email: userData.email ? userData.email : upd_user.email,
|
||||||
|
};
|
||||||
|
|
||||||
|
// term ? ilike(posts.title, term) : undefined
|
||||||
|
const { data: updData, error: updError } = await tryCatch(
|
||||||
|
db.update(users).set(data).where(eq(users.user_id, userData.user_id!))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (updError) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: "There was an error getting the user",
|
||||||
|
updError,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: `${userData.username} has been updated.`,
|
||||||
|
updData,
|
||||||
|
};
|
||||||
|
};
|
||||||
85
server/services/auth/middleware/roleCheck.ts
Normal file
85
server/services/auth/middleware/roleCheck.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { createMiddleware } from "hono/factory";
|
||||||
|
|
||||||
|
import type { CustomJwtPayload } from "../../../types/jwtToken.js";
|
||||||
|
import { verify } from "hono/jwt";
|
||||||
|
import { db } from "../../../../database/dbclient.js";
|
||||||
|
import { modules } from "../../../../database/schema/modules.js";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import { userRoles } from "../../../../database/schema/userRoles.js";
|
||||||
|
import { tryCatch } from "../../../globalUtils/tryCatch.js";
|
||||||
|
|
||||||
|
const hasCorrectRole = (requiredRole: string[], module: string) =>
|
||||||
|
createMiddleware(async (c, next) => {
|
||||||
|
/**
|
||||||
|
* We want to check to make sure you have the correct role to be here
|
||||||
|
*/
|
||||||
|
const authHeader = c.req.header("Authorization");
|
||||||
|
|
||||||
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||||
|
return c.json({ error: "Unauthorized" }, 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = authHeader.split(" ")[1];
|
||||||
|
|
||||||
|
// deal with token data
|
||||||
|
const { data: tokenData, error: tokenError } = await tryCatch(
|
||||||
|
verify(token, process.env.JWT_SECRET!)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tokenError) {
|
||||||
|
return c.json({ error: "Invalid token" }, 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const customToken = tokenData as CustomJwtPayload;
|
||||||
|
|
||||||
|
// Get the module
|
||||||
|
const { data: mod, error: modError } = await tryCatch(
|
||||||
|
db.select().from(modules).where(eq(modules.name, module))
|
||||||
|
);
|
||||||
|
if (modError) {
|
||||||
|
console.log(modError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod.length === 0) {
|
||||||
|
return c.json({ error: "You have entered an invalid module name" }, 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the user has the role needed to get into this module
|
||||||
|
const { data: userRole, error: userRoleError } = await tryCatch(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(userRoles)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userRoles.module_id, mod[0].module_id),
|
||||||
|
eq(userRoles.user_id, customToken.user?.user_id!)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userRoleError) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userRole) {
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
error:
|
||||||
|
"The module you are trying to access is not active or is invalid.",
|
||||||
|
},
|
||||||
|
403
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requiredRole.includes(userRole[0]?.role)) {
|
||||||
|
return c.json(
|
||||||
|
{ error: "You do not have access to this part of the app." },
|
||||||
|
403
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
export default hasCorrectRole;
|
||||||
@@ -1,90 +1,97 @@
|
|||||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import {login} from "../controllers/login.js";
|
import { login } from "../controllers/login.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
const UserSchema = z
|
const UserSchema = z
|
||||||
.object({
|
.object({
|
||||||
username: z.string().optional().openapi({example: "smith002"}),
|
username: z.string().optional().openapi({ example: "smith002" }),
|
||||||
//email: z.string().optional().openapi({example: "s.smith@example.com"}),
|
//email: z.string().optional().openapi({example: "s.smith@example.com"}),
|
||||||
password: z.string().openapi({example: "password123"}),
|
password: z.string().openapi({ example: "password123" }),
|
||||||
})
|
})
|
||||||
.openapi("User");
|
.openapi("User");
|
||||||
|
|
||||||
const route = createRoute({
|
const route = createRoute({
|
||||||
tags: ["Auth"],
|
tags: ["Auth"],
|
||||||
summary: "Login as user",
|
summary: "Login as user",
|
||||||
description: "Login as a user to get a JWT token",
|
description: "Login as a user to get a JWT token",
|
||||||
method: "post",
|
method: "post",
|
||||||
path: "/",
|
path: "/login",
|
||||||
request: {
|
request: {
|
||||||
body: {
|
body: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": {schema: UserSchema},
|
"application/json": { schema: UserSchema },
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
responses: {
|
},
|
||||||
200: {
|
responses: {
|
||||||
content: {
|
200: {
|
||||||
"application/json": {
|
content: {
|
||||||
schema: z.object({
|
"application/json": {
|
||||||
success: z.boolean().openapi({example: true}),
|
schema: z.object({
|
||||||
message: z.string().openapi({example: "Logged in"}),
|
success: z.boolean().openapi({ example: true }),
|
||||||
}),
|
message: z.string().openapi({ example: "Logged in" }),
|
||||||
},
|
}),
|
||||||
},
|
|
||||||
description: "Response message",
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
description: "Response message",
|
||||||
|
},
|
||||||
|
|
||||||
400: {
|
400: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
schema: z.object({
|
schema: z.object({
|
||||||
success: z.boolean().openapi({example: false}),
|
success: z.boolean().openapi({ example: false }),
|
||||||
message: z.string().openapi({example: "Username and password required"}),
|
message: z
|
||||||
}),
|
.string()
|
||||||
},
|
.openapi({ example: "Username and password required" }),
|
||||||
},
|
}),
|
||||||
description: "Bad request",
|
|
||||||
},
|
|
||||||
401: {
|
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
schema: z.object({
|
|
||||||
success: z.boolean().openapi({example: false}),
|
|
||||||
message: z.string().openapi({example: "Username and password required"}),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
description: "Bad request",
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
description: "Bad request",
|
||||||
},
|
},
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: z.object({
|
||||||
|
success: z.boolean().openapi({ example: false }),
|
||||||
|
message: z
|
||||||
|
.string()
|
||||||
|
.openapi({ example: "Username and password required" }),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: "Bad request",
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
app.openapi(route, async (c) => {
|
app.openapi(route, async (c) => {
|
||||||
const {username, password, email} = await c.req.json();
|
const { username, password, email } = await c.req.json();
|
||||||
|
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
return c.json(
|
return c.json(
|
||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
message: "Username and password are required",
|
message: "Username and password are required",
|
||||||
},
|
},
|
||||||
400
|
400
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const {token, user} = await login(username.toLowerCase(), password);
|
const { token, user } = await login(username.toLowerCase(), password);
|
||||||
|
|
||||||
// Set the JWT as an HTTP-only cookie
|
// Set the JWT as an HTTP-only cookie
|
||||||
//c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
|
//c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
|
||||||
|
|
||||||
return c.json({success: true, message: "Login successful", user, token}, 200);
|
return c.json(
|
||||||
} catch (err) {
|
{ success: true, message: "Login successful", user, token },
|
||||||
return c.json({success: false, message: "Incorrect Credentials"}, 401);
|
200
|
||||||
}
|
);
|
||||||
|
} catch (err) {
|
||||||
|
return c.json({ success: false, message: "Incorrect Credentials" }, 401);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
@@ -1,97 +1,110 @@
|
|||||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
|
||||||
import {apiHit} from "../../../globalUtils/apiHits.js";
|
import { apiHit } from "../../../globalUtils/apiHits.js";
|
||||||
import {registerUser} from "../controllers/register.js";
|
import { registerUser } from "../controllers/register.js";
|
||||||
|
|
||||||
const app = new OpenAPIHono();
|
const app = new OpenAPIHono();
|
||||||
|
|
||||||
const UserSchema = z.object({
|
const UserSchema = z.object({
|
||||||
username: z
|
username: z
|
||||||
.string()
|
.string()
|
||||||
.regex(/^[a-zA-Z0-9_]{3,30}$/)
|
.regex(/^[a-zA-Z0-9_]{3,30}$/)
|
||||||
.openapi({example: "smith034"}),
|
.openapi({ example: "smith034" }),
|
||||||
email: z.string().email().openapi({example: "smith@example.com"}),
|
email: z.string().email().openapi({ example: "smith@example.com" }),
|
||||||
password: z
|
password: z
|
||||||
.string()
|
.string()
|
||||||
.min(6, {message: "Passwords must be longer than 3 characters"})
|
.min(6, { message: "Passwords must be longer than 3 characters" })
|
||||||
.regex(/[A-Z]/, {message: "Password must contain at least one uppercase letter"})
|
.regex(/[A-Z]/, {
|
||||||
.regex(/[\W_]/, {message: "Password must contain at least one special character"})
|
message: "Password must contain at least one uppercase letter",
|
||||||
.openapi({example: "Password1!"}),
|
})
|
||||||
|
.regex(/[\W_]/, {
|
||||||
|
message: "Password must contain at least one special character",
|
||||||
|
})
|
||||||
|
.openapi({ example: "Password1!" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
type User = z.infer<typeof UserSchema>;
|
type User = z.infer<typeof UserSchema>;
|
||||||
|
|
||||||
const responseSchema = z.object({
|
const responseSchema = z.object({
|
||||||
success: z.boolean().optional().openapi({example: true}),
|
success: z.boolean().optional().openapi({ example: true }),
|
||||||
message: z.string().optional().openapi({example: "User Created"}),
|
message: z.string().optional().openapi({ example: "User Created" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
app.openapi(
|
app.openapi(
|
||||||
createRoute({
|
createRoute({
|
||||||
tags: ["Auth"],
|
tags: ["Auth"],
|
||||||
summary: "Register a new user",
|
summary: "Register a new user",
|
||||||
method: "post",
|
method: "post",
|
||||||
path: "/",
|
path: "/register",
|
||||||
request: {
|
request: {
|
||||||
body: {
|
body: {
|
||||||
content: {
|
content: {
|
||||||
"application/json": {schema: UserSchema},
|
"application/json": { schema: UserSchema },
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
responses: {
|
},
|
||||||
200: {
|
},
|
||||||
content: {"application/json": {schema: responseSchema}},
|
responses: {
|
||||||
description: "Retrieve the user",
|
200: {
|
||||||
},
|
content: { "application/json": { schema: responseSchema } },
|
||||||
400: {
|
description: "Retrieve the user",
|
||||||
content: {
|
},
|
||||||
"application/json": {
|
400: {
|
||||||
schema: z.object({
|
content: {
|
||||||
success: z.boolean().openapi({example: false}),
|
"application/json": {
|
||||||
message: z.string().openapi({example: "Invalid credentials passed"}),
|
schema: z.object({
|
||||||
}),
|
success: z.boolean().openapi({ example: false }),
|
||||||
},
|
message: z
|
||||||
},
|
.string()
|
||||||
description: "Retrieve the user",
|
.openapi({ example: "Invalid credentials passed" }),
|
||||||
},
|
}),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
description: "Retrieve the user",
|
||||||
async (c) => {
|
},
|
||||||
// apit hit
|
},
|
||||||
apiHit(c, {endpoint: "api/auth/register"});
|
}),
|
||||||
let {username, email, password} = await c.req.json();
|
async (c) => {
|
||||||
|
// apit hit
|
||||||
|
apiHit(c, { endpoint: "api/auth/register" });
|
||||||
|
let { username, email, password } = await c.req.json();
|
||||||
|
|
||||||
if (!username || !email || !password) {
|
if (!username || !email || !password) {
|
||||||
return c.json({success: false, message: "Credentials missing"}, 400);
|
return c.json({ success: false, message: "Credentials missing" }, 400);
|
||||||
}
|
|
||||||
|
|
||||||
// some usernames that should be ignored
|
|
||||||
const badActors = ["admin", "root"];
|
|
||||||
if (badActors.includes(username)) {
|
|
||||||
return c.json(
|
|
||||||
{
|
|
||||||
success: false,
|
|
||||||
message: `${username} is not a valid name to be registerd please try again`,
|
|
||||||
},
|
|
||||||
400
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const register = await registerUser(username, password, email);
|
|
||||||
|
|
||||||
return c.json({success: register.success, message: register.message, user: register?.user}, 200);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
return c.json(
|
|
||||||
{
|
|
||||||
success: false,
|
|
||||||
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
|
|
||||||
},
|
|
||||||
400
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// some usernames that should be ignored
|
||||||
|
const badActors = ["admin", "root"];
|
||||||
|
if (badActors.includes(username)) {
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: `${username} is not a valid name to be registerd please try again`,
|
||||||
|
},
|
||||||
|
400
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const register = await registerUser(username, password, email);
|
||||||
|
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: register.success,
|
||||||
|
message: register.message,
|
||||||
|
user: register?.user,
|
||||||
|
},
|
||||||
|
200
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
|
||||||
|
},
|
||||||
|
400
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user