Compare commits
364 Commits
292eb324c5
...
migration
| Author | SHA1 | Date | |
|---|---|---|---|
| 8943407f27 | |||
| 0bbe411db0 | |||
| 99b3ad633c | |||
| c892348d19 | |||
| 360549aaf4 | |||
| bdc1e72fc1 | |||
| 4cae96b1ee | |||
| 1cde8ab2e6 | |||
| 03e8378213 | |||
| 275c93dc79 | |||
| fbb8c21d5c | |||
| dce93d3de2 | |||
| faf4e9f9ab | |||
| a9783a7d35 | |||
| e9ca6dbbb2 | |||
| e996f99400 | |||
| 3b939ff2d3 | |||
| a7ff88025e | |||
| 00899a5b77 | |||
| 99ecf52218 | |||
| a6920d7cd8 | |||
| 788efdf4b3 | |||
| a2a17beeeb | |||
| 6c793c66a4 | |||
| 6918a5a7d4 | |||
| ddd9b0e372 | |||
| 41d921756b | |||
| d86ca7d3bf | |||
| 932a72ba88 | |||
| b9c6d0ba57 | |||
| 592e4c8cd7 | |||
| b772666905 | |||
| a6edcb71bf | |||
| 76d929abea | |||
| da17defe82 | |||
| 669f5ca33f | |||
| b649dca4c9 | |||
| 04b8d041f9 | |||
| 71bc7c29bc | |||
| 79f1f8f91b | |||
| b677bc1498 | |||
| a53915ad8c | |||
| b3ce767b32 | |||
| 6caa5984e7 | |||
| 415d2e4a1d | |||
| 271cdbdbfa | |||
| 796a8dccd2 | |||
| e03e92c18d | |||
| dd2e5d04ae | |||
| 708b57b926 | |||
| 0444da8bbc | |||
| 6d49fae16d | |||
| be8a44f2dc | |||
| a3994a1f69 | |||
| 00eaf62d4c | |||
| 6851777faf | |||
| f9e97fc224 | |||
| 4e3c5e4191 | |||
| 172fd1d5c2 | |||
| 1094de2ebd | |||
| 7462b3d90b | |||
| 2045c13ef2 | |||
| 5fa9e83d5b | |||
| f48c944bd0 | |||
| dddd1d422e | |||
| 8133443ec9 | |||
| 28c7d30c1a | |||
| 57966ac9de | |||
| 6910550de7 | |||
| 1f8b8a7248 | |||
| cfed981928 | |||
| 0efe74d4b1 | |||
| c35db2e209 | |||
| e1cdeb740b | |||
| 3c9e75dc3c | |||
| 64b5b0d248 | |||
| 668eae9719 | |||
| 7cc3778506 | |||
| af47c1582e | |||
| 081572c421 | |||
| c6f6ef6262 | |||
| 34849e15d1 | |||
| 9bd66942f5 | |||
| 795da35141 | |||
| 468f933168 | |||
| 8c296c5b78 | |||
| 53ed2c4e6a | |||
| 0a6ddea8c0 | |||
| df423192bf | |||
| 2f908398bc | |||
| bf8203bbee | |||
| e92eccf785 | |||
| f4f3de49ca | |||
| 788d6367a3 | |||
| 24a97afe06 | |||
| 37f82a9710 | |||
| 369d16018c | |||
| 68901a857a | |||
| 171763184c | |||
| b7de2a8dbe | |||
| e78083f496 | |||
| 3f3b64bf2b | |||
| 123bb127e8 | |||
| 8d6ead3aa1 | |||
| 3148aa79d7 | |||
| 4486fe2436 | |||
| 0ba338d480 | |||
| 846ac479b1 | |||
| 73d38ba3fe | |||
| 27586e923a | |||
| 662a951b98 | |||
| 0c54cecbd4 | |||
| bcf5378966 | |||
| c5668e6cf1 | |||
| 213814b868 | |||
| 7d5b0c46c1 | |||
| 595e22e8e9 | |||
| a6f18554b8 | |||
| 88f61c8eaa | |||
| a183279268 | |||
| 5156c8bf7b | |||
| 4669ff95dc | |||
| ed93992165 | |||
| f16e2bf53b | |||
| a84998438c | |||
| 83469105f0 | |||
| 835ae58f04 | |||
| 1498a19121 | |||
| ca96849991 | |||
| 27b37f9849 | |||
| 7f81a2e09a | |||
| e14abd3644 | |||
| 2ff7b9baf9 | |||
| 8145dc800d | |||
| 6ccf500e5e | |||
| 103171c924 | |||
| 2eb6fa7794 | |||
| 397f1da595 | |||
| 8d63f7f6b0 | |||
| 52345bc94c | |||
| a8a1c1d7fb | |||
| 83ff2641f3 | |||
| 7c48f608bc | |||
| 1802b9ba4e | |||
| 67a12ccc5c | |||
| 15e2a65cbb | |||
| 9e5577e6bb | |||
| c52e2a8671 | |||
| 8f76d6998c | |||
| e209686d3c | |||
| 803c963f96 | |||
| 078f35626b | |||
| 2288884829 | |||
| 69fc7418c9 | |||
| a0179a41ba | |||
| a36552fd9b | |||
| c7bb12822b | |||
| 98a5ca7bb8 | |||
| 74ac2864c9 | |||
| 1f93eca561 | |||
| 1f44750346 | |||
| 0d17fef1a1 | |||
| f574645b44 | |||
| 998e84f564 | |||
| 3e51ebc18b | |||
| 8129dbb787 | |||
| b5561635dd | |||
| ff340161d6 | |||
| 39d0768d50 | |||
| d40ed30f55 | |||
| 8594d72d2c | |||
| 3e680a5a50 | |||
| e1113c49b3 | |||
| e964bb70ae | |||
| f01b6941ba | |||
| e78f3ffdb5 | |||
| 713df0b615 | |||
| f2615fbcea | |||
| 4f7d6fe4af | |||
| 96a3fd451b | |||
| d1befadd1c | |||
| fa99eb41dd | |||
| 11cc3662cf | |||
| d9a2f90056 | |||
| 23ee0468ad | |||
| 83ba84cf6f | |||
| 96d2a25081 | |||
| d54f85cf3d | |||
| 371870cbe5 | |||
| dd31763fdd | |||
| c9a64e2e7c | |||
| 733603fffa | |||
| bc92f8be0e | |||
| 9ced82b154 | |||
| d9bc68d6ac | |||
| 248e4cfeef | |||
| 9707990211 | |||
| 60672ba751 | |||
| 3b8190b080 | |||
| c1577ff432 | |||
| 40b382ca62 | |||
| 1ec3de0f02 | |||
| f5c035081c | |||
| 885e0ce348 | |||
| 7a59da77f2 | |||
| 82fb85ba0d | |||
| 0d263f6941 | |||
| 1762c70859 | |||
| c196b1d612 | |||
| 8926bfde00 | |||
| 256405b5a5 | |||
| eecf35fc9c | |||
| 700b18160c | |||
| 2dd6947bd6 | |||
| fe8ab62e94 | |||
| a0d476042b | |||
| 8e99a2e5e5 | |||
| 4b9f96f3b0 | |||
| 390107a1fb | |||
| e3a4ef7a80 | |||
| c224e30b8d | |||
| 16b710dc91 | |||
| a9e788f438 | |||
| 3aa4191b0f | |||
| 260d513ee3 | |||
| e9f729d5e2 | |||
| e43ac65d04 | |||
| 5199a9ce69 | |||
| 5ce78222b9 | |||
| 904de61e5a | |||
| c1ed482073 | |||
| f57426cf13 | |||
| 7079b151da | |||
| b87cd8dd7c | |||
| 531b343d17 | |||
| e2b549714c | |||
| e6f3a9b4d0 | |||
| 33295dc3c3 | |||
| 49fd9d65c9 | |||
| 0510f13885 | |||
| 588f264854 | |||
| 8afa4176ef | |||
| 611183fc19 | |||
| c31856ac3e | |||
| 61f0b7f06b | |||
| a7f8e39bac | |||
| 4923b3c698 | |||
| 28f34a6a31 | |||
| b81675e445 | |||
| c6d80dbc8a | |||
| bc54b365ea | |||
| 41308788fd | |||
| d6232cb358 | |||
| d89a336fb1 | |||
| e84ae42c83 | |||
| 6ec8f0863b | |||
| 4f231b343c | |||
| 454039e60c | |||
| c7c148fede | |||
| e30adc6612 | |||
| f7b4de8130 | |||
| 6584b37cb0 | |||
| 6a082d9737 | |||
| 58711becf2 | |||
| f757085fc2 | |||
| 8f5e1cb094 | |||
| 7497ee454c | |||
| c0ede8714c | |||
| 1a6a05112b | |||
| 97c6631eab | |||
| 1ae506939c | |||
| f0294942a7 | |||
| e323607b39 | |||
| df0851414e | |||
| a9b860a34d | |||
| ead35b4360 | |||
| d6b1a75afa | |||
| 1b661a6685 | |||
| f597142ee3 | |||
| 18780d872c | |||
| ba02ee42c5 | |||
| f573f4f721 | |||
| 1d6bf7215b | |||
| e616574fa6 | |||
| 08109f500f | |||
| ab8102afbf | |||
| e13b5a4283 | |||
| 7a4dea9d87 | |||
| a19ac539e7 | |||
| 1c910d80ea | |||
| 56e0f3eb47 | |||
| e50e9af839 | |||
| e34f273acb | |||
| 2c5f8a3a8c | |||
| 9e4729690a | |||
| 26ab6ecd8d | |||
| 05fa774d68 | |||
| b1acd97232 | |||
| edc874c302 | |||
| 4abecd0455 | |||
| 6c7193bc7a | |||
| c6739b6a73 | |||
| 13992bde68 | |||
| 7ed9db1bdb | |||
| f4dd572a8f | |||
| 3b56a5e3e2 | |||
| 2eea2911bc | |||
| c155e89bc7 | |||
| 7d9ea42f8d | |||
| 974f6587fc | |||
| 2ac48138cb | |||
| d6d19f8e5b | |||
| 3cafbd92d0 | |||
| 77d9e5d095 | |||
| 4a02bbc368 | |||
| f75da6525d | |||
| 26ceb95dae | |||
| bd5bad3cba | |||
| c5bd5a7c0a | |||
| 095d724e65 | |||
| 7df512acaa | |||
| 3073df342f | |||
| b9ff0a4138 | |||
| c555172d68 | |||
| e432f0b3ae | |||
| bc25e835b4 | |||
| a71167e598 | |||
| 53945402ce | |||
| aa42819cc1 | |||
| c36e4e66b3 | |||
| 11ae3cc0bc | |||
| f80e742e27 | |||
| 37f2518589 | |||
| 90be86d972 | |||
| 68d75277c2 | |||
| 84aacd5b71 | |||
| c72b4d3261 | |||
| b397fd7f32 | |||
| f90ce8cba7 | |||
| 88c1c29437 | |||
| f7c9f93d30 | |||
| 83f31b97f5 | |||
| b97f8175f9 | |||
| 92901a8762 | |||
| 0071237b24 | |||
| d32289c833 | |||
| 3c45010b26 | |||
| 4927428607 | |||
| 04298c9f54 | |||
| 6759a1bf8f | |||
| 92624cbac9 | |||
| f79ff26958 | |||
| e865c1dcaf | |||
| 99ad79c662 | |||
| 3283972809 | |||
| 1cb285bea8 | |||
| 4f5d5faecb | |||
| def97360be | |||
| a1229b4dee | |||
| 8d04c8f7de | |||
| 27eb96cc15 | |||
| 4187264e30 | |||
| bade51d57d | |||
| 078c2ec12f |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -11,6 +11,10 @@ backend-0.1.2-218.zip
|
|||||||
backend-0.1.2.zip
|
backend-0.1.2.zip
|
||||||
postgresql-17.2-3-windows-x64.exe
|
postgresql-17.2-3-windows-x64.exe
|
||||||
jsTesting
|
jsTesting
|
||||||
|
dotnetwrapper/bin
|
||||||
|
dotnetwrapper/obj
|
||||||
|
dotnetwrapper/wwwroot
|
||||||
|
prodBuild
|
||||||
|
|
||||||
|
|
||||||
# ---> Node
|
# ---> Node
|
||||||
@@ -152,3 +156,5 @@ dist
|
|||||||
backend-0.1.3.zip
|
backend-0.1.3.zip
|
||||||
BulkForecastTemplate
|
BulkForecastTemplate
|
||||||
BulkOrdersTemplate
|
BulkOrdersTemplate
|
||||||
|
check.json
|
||||||
|
server/services/ocp/controller/materials/materialcheck.bak
|
||||||
|
|||||||
8
.includes
Normal file
8
.includes
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
database
|
||||||
|
dist
|
||||||
|
frontend/dist
|
||||||
|
CHANGELOG.md
|
||||||
|
drizzle.config.ts
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
README.md
|
||||||
224
CHANGELOG.md
224
CHANGELOG.md
@@ -1,5 +1,229 @@
|
|||||||
# All CHanges to LST can be found below.
|
# All CHanges to LST can be found below.
|
||||||
|
|
||||||
|
## [2.27.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.26.0...v2.27.0) (2025-09-10)
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **eom:** lastSales, lastPurch added to be pulled with new template ([7cc3778](https://git.tuffraid.net/cowch/lstV2/commits/7cc3778506fc92392ca8431aee0edb203861e10d))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **cosume:** changes to allow non logged in users to use this function ([271cdbd](https://git.tuffraid.net/cowch/lstV2/commits/271cdbdbfa2478ecf56e9b01a4474508acacda2e))
|
||||||
|
* **mm query:** changes to the query to see pkg and materials properly and not duplicates ([57966ac](https://git.tuffraid.net/cowch/lstV2/commits/57966ac9de72543014451b7ccd75539296ccaa51))
|
||||||
|
* **rfid:** changes to show all tags vs only 3 if there are more ([b677bc1](https://git.tuffraid.net/cowch/lstV2/commits/b677bc14981faff30c91f6ffe4602319dd3c6016))
|
||||||
|
* **silo card:** changes to allow viewers to see and able to attach and detach ([796a8dc](https://git.tuffraid.net/cowch/lstV2/commits/796a8dccd2807890abdff7c8dacf8b2246eb265e))
|
||||||
|
* **sql:** articles added in UOM ([cfed981](https://git.tuffraid.net/cowch/lstV2/commits/cfed981928a56389e09ef428c43ceabc1caec28e))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **article check:** corrected the query to not have a specfic plant in it ([79f1f8f](https://git.tuffraid.net/cowch/lstV2/commits/79f1f8f91ba33533de7f4a7cc91503cfd8dd4ce5))
|
||||||
|
* **bookin:** corrected the bookin in error response ([1f8b8a7](https://git.tuffraid.net/cowch/lstV2/commits/1f8b8a7248c11c7e264c8c5ae7c042c5a0878c46))
|
||||||
|
* **bookin:** corrections to only show the message on error vs the json ([b3ce767](https://git.tuffraid.net/cowch/lstV2/commits/b3ce767b323c990c0ccf35ad6c2c67136a27272e))
|
||||||
|
* **db:** changes to the user so it deletes correctly ([932a72b](https://git.tuffraid.net/cowch/lstV2/commits/932a72ba884673471f0056e721cc3f2c8e34b4f3))
|
||||||
|
* **eomservice:** changes to stop a crash incase the sql returned nothing due to start up ([6caa598](https://git.tuffraid.net/cowch/lstV2/commits/6caa5984e7a3e7b48b119c176835663ffec71151))
|
||||||
|
* **frontend:** typos ([c6f6ef6](https://git.tuffraid.net/cowch/lstV2/commits/c6f6ef626295f452cdf26f6776b74cfb3b1a10f5))
|
||||||
|
* **label query:** fixes to only pull in active layouts ([99ecf52](https://git.tuffraid.net/cowch/lstV2/commits/99ecf52218556e048ba9262e74f9b3d020dea31d))
|
||||||
|
* **main material check:** corrections to properly ignore pkg during color checks ([6910550](https://git.tuffraid.net/cowch/lstV2/commits/6910550de769dce04b1045f96ab19cf7b8d1ef8c))
|
||||||
|
* **material check:** split manual material out of the mm to properly catch it ([a53915a](https://git.tuffraid.net/cowch/lstV2/commits/a53915ad8cbec5bd8d6ba4643c460ad0162249e2))
|
||||||
|
* **materials:** more fixes to try and please all plants to use this version and not call me ([00899a5](https://git.tuffraid.net/cowch/lstV2/commits/00899a5b778eab792b350a0b47589de1524d91c8))
|
||||||
|
* **register:** changes to not give everyone system admin ([415d2e4](https://git.tuffraid.net/cowch/lstV2/commits/415d2e4a1d851cc46ac64ffc814a280a02293bbc))
|
||||||
|
|
||||||
|
## [2.26.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.25.0...v2.26.0) (2025-08-28)
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **labeling:** moved bookin fails inside bookin as it could be off ([df42319](https://git.tuffraid.net/cowch/lstV2/commits/df423192bfc5e2389872147e92b7d22e648a2927))
|
||||||
|
* **labeling:** removed the wrong import ([788d636](https://git.tuffraid.net/cowch/lstV2/commits/788d6367a380a81722a76bd6adbe18831d88eeb5))
|
||||||
|
* **materials:** changes for permissions on material consume ([3148aa7](https://git.tuffraid.net/cowch/lstV2/commits/3148aa79d73823499824cc0601fcabec97bb4f9d))
|
||||||
|
* **materials:** changes to allow exact and eom transfers ([0a6ddea](https://git.tuffraid.net/cowch/lstV2/commits/0a6ddea8c0d2773aba00266df7e2839879d10cb1))
|
||||||
|
* **notifcations:** changed hour to min in ti intergrations ([73d38ba](https://git.tuffraid.net/cowch/lstV2/commits/73d38ba3fe7ab4d5ca3a4a1e1c99fdd7bf5e92dc))
|
||||||
|
* **tms intergration:** corrected how we added gl coding ([37f82a9](https://git.tuffraid.net/cowch/lstV2/commits/37f82a9710cf20e6d0d056893c9da43c70b9e619))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **materials:** added in a bigger window on eom transfer lots ([53ed2c4](https://git.tuffraid.net/cowch/lstV2/commits/53ed2c4e6a0d3fafafbcb655b5d06cff6324363d))
|
||||||
|
* **ocp:** zechetti 1 added in ([27586e9](https://git.tuffraid.net/cowch/lstV2/commits/27586e923a106f2b8dd804e9c8292edd5d009cf0))
|
||||||
|
* **rfid:** new check to remove tags that have been at a line longer than 6 hours ([0ba338d](https://git.tuffraid.net/cowch/lstV2/commits/0ba338d48037f7def74196ca3f41de5807e2cb31))
|
||||||
|
* **tms:** a clean up function was added to remove releases added as blockers older than 45d ([662a951](https://git.tuffraid.net/cowch/lstV2/commits/662a951b9871d5dfc21f01a76ba23be77b475757))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **forklifts:** forklift starting process ([8c296c5](https://git.tuffraid.net/cowch/lstV2/commits/8c296c5b783f42f85c30a955d6e9d540c50dcfbe))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **bookin:** corrected the error received from the book in fail ([369d160](https://git.tuffraid.net/cowch/lstV2/commits/369d16018c8be9fdb936afbc3749b3f9fcea58c8))
|
||||||
|
* **dm:** corrected the remark section so its properly sent over ([68901a8](https://git.tuffraid.net/cowch/lstV2/commits/68901a857ae5161f024da9cdefc0a981a4907205))
|
||||||
|
* **eom stats:** corrections to the eom inv stuff to be proper tiems ([468f933](https://git.tuffraid.net/cowch/lstV2/commits/468f933168cc40be0c1b159c31948a2c97600390))
|
||||||
|
* **fake edi:** removed console log ([24a97af](https://git.tuffraid.net/cowch/lstV2/commits/24a97afe064d5c44872e24e6e3299ed5f2977a78))
|
||||||
|
* **material check:** alt mm causing issues and utilizing an 80% to just be ok ([f4f3de4](https://git.tuffraid.net/cowch/lstV2/commits/f4f3de49cae277ffa158116d1802495b27fa8e75))
|
||||||
|
* **ocp:** zechetti type correction to include the printer name ([4486fe2](https://git.tuffraid.net/cowch/lstV2/commits/4486fe24362b4811d7cff0467c7f2f85e0c9e3c4))
|
||||||
|
* **produser:** changes to include DM ([8d6ead3](https://git.tuffraid.net/cowch/lstV2/commits/8d6ead3aa11aed95ffa3537fbe72cfa9bbceb380))
|
||||||
|
* **transferlots:** missed adding this ([846ac47](https://git.tuffraid.net/cowch/lstV2/commits/846ac479b1bf211a7891ae362525ea14580ff0cc))
|
||||||
|
|
||||||
|
## [2.25.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.24.1...v2.25.0) (2025-08-21)
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **dm page:** correction to the insturcitons ([a36552f](https://git.tuffraid.net/cowch/lstV2/commits/a36552fd9b9c77f8ecee8b36f45e613383841f95))
|
||||||
|
* **dyco:** correction to disable the camera if ocme is off ([c7bb128](https://git.tuffraid.net/cowch/lstV2/commits/c7bb12822b13c0c1c929d2c8a9ab150cd0feeff2))
|
||||||
|
* **gotransport:** error handling so we dont get spammed with errors ([2eb6fa7](https://git.tuffraid.net/cowch/lstV2/commits/2eb6fa77946d5f8572ffc5baa47da602482bce2b))
|
||||||
|
* **https fixes:** made it so the settings can be grabbed via https ([803c963](https://git.tuffraid.net/cowch/lstV2/commits/803c963f964f26095b2aa6a7d0a60e03615d4c17))
|
||||||
|
* **inv cards:** correction to properly display the names ([2288884](https://git.tuffraid.net/cowch/lstV2/commits/22888848291aa3df4ebbdd224656731fbb305fa7))
|
||||||
|
* **inv query:** error in improper placed , in the query ([397f1da](https://git.tuffraid.net/cowch/lstV2/commits/397f1da595fd8a1e1c2a630a3650eb8715604c82))
|
||||||
|
* **mainmaterial check:** if the machine dose not require mm to be staged properly ignore ([0d17fef](https://git.tuffraid.net/cowch/lstV2/commits/0d17fef1a1c75dd0f27988fd2e3527b508b915cb))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **migration progress:** moved to start looking at the go backedn ([a0179a4](https://git.tuffraid.net/cowch/lstV2/commits/a0179a41bac93d2a7320802e9d70aa966ed79ae4))
|
||||||
|
* **migrations:** not needed but we have it and needed to correct the settings ([2ff7b9b](https://git.tuffraid.net/cowch/lstV2/commits/2ff7b9baf9ca288f8a33bec3ab1a2ba331ace6b9))
|
||||||
|
* **notifications:** refactored the cron job system so we can utilize outside the service ([103171c](https://git.tuffraid.net/cowch/lstV2/commits/103171c924a9de78b0a7600abb455fdd6f4bfea1))
|
||||||
|
* **siloadjustment:** refactored to get the settings from the state vs direct from db ([8145dc8](https://git.tuffraid.net/cowch/lstV2/commits/8145dc800dced31860a926c80eca72cb39433b29))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **dm:** changes to have a default time if nothing is passed in the excel ([9e5577e](https://git.tuffraid.net/cowch/lstV2/commits/9e5577e6bb4ff3b6c4004288e177fbab322a4b44))
|
||||||
|
* **eom:** added in hostorical data and deletion for data over 45 days ([52345bc](https://git.tuffraid.net/cowch/lstV2/commits/52345bc94c9e8abc82150fb371a9ba0d0757f16a))
|
||||||
|
* **migration start:** this starts the migration of all settings to look at the go backend vs this ([998e84f](https://git.tuffraid.net/cowch/lstV2/commits/998e84f5648148c9a94df7177a3d311e16bf4614))
|
||||||
|
* **ocp:** materials contorls and transfer to next lot logic ([88f61c8](https://git.tuffraid.net/cowch/lstV2/commits/88f61c8eaa32a581094b04b5e18c654040dbeb92))
|
||||||
|
* **prodrole:** added in planner role ([6ccf500](https://git.tuffraid.net/cowch/lstV2/commits/6ccf500e5eb82125f7bcd3d764282a4b8a750be9))
|
||||||
|
* **psi:** psi querys added and av grab right now ([8d63f7f](https://git.tuffraid.net/cowch/lstV2/commits/8d63f7f6b0981d604b628ff2f710b8eb41d32837))
|
||||||
|
|
||||||
|
### [2.24.1](https://git.tuffraid.net/cowch/lstV2/compare/v2.24.0...v2.24.1) (2025-07-25)
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **serverdata:** moved stp1 to d drive ([f57426c](https://git.tuffraid.net/cowch/lstV2/commits/f57426cf13b11b357a1436317f592286084e0fb1))
|
||||||
|
* **zip builds:** removed the c# wrapper as it wont be used on this build anymore ([e3a4ef7](https://git.tuffraid.net/cowch/lstV2/commits/e3a4ef7a804390cf1e381766baf7baf60b873a57))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **create labels:** better logging to know where the error came from ([d40ed30](https://git.tuffraid.net/cowch/lstV2/commits/d40ed30f55b1fb1a3c7a4ecde6dc40c535f3c0ed))
|
||||||
|
* **mm check:** correction to know if a machine is required to have mm or not ([39d0768](https://git.tuffraid.net/cowch/lstV2/commits/39d0768d503c415b5d1ca845db2a292613f4fbed))
|
||||||
|
* **submodules:** correction to accessing when changes made to roles ([3e680a5](https://git.tuffraid.net/cowch/lstV2/commits/3e680a5a503761a4a358b4a62e07c4aa545a6f10))
|
||||||
|
|
||||||
|
## [2.24.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.23.0...v2.24.0) (2025-07-15)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* **updated packages:** all pacakges were just updated ([4a02bbc](https://git.tuffraid.net/cowch/lstV2/commits/4a02bbc3686f6ed150f1f22146c924aacf1f6b1b))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **material returns:** added type check ([d6d19f8](https://git.tuffraid.net/cowch/lstV2/commits/d6d19f8e5b81d34652c9b7421cb934a81ef03136))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **default accounts:** added in a default account run this will create a bunch of system admins ([b9ff0a4](https://git.tuffraid.net/cowch/lstV2/commits/b9ff0a4138843e191351f2bcec75e8305a78d6f2))
|
||||||
|
* **labeling:** ratios reset for labeling implemeneted ([61f0b7f](https://git.tuffraid.net/cowch/lstV2/commits/61f0b7f06b8f0a811387dc3f17fcacb00804d146))
|
||||||
|
* **labelratio:** new feature to monitor label ratio from auto and manual ([4130878](https://git.tuffraid.net/cowch/lstV2/commits/41308788fdc5e918450db0721199bd4ac7da17e7))
|
||||||
|
* **logistics:** get sscc based on runnning number ([7df512a](https://git.tuffraid.net/cowch/lstV2/commits/7df512acaa3a2b3cc30131d61563580c124d4f05))
|
||||||
|
* **notifcations:** pallets booked as waste brought back in via cycle count ([095d724](https://git.tuffraid.net/cowch/lstV2/commits/095d724e65f211253ccdb075a2afb3c5ad267932))
|
||||||
|
* **notify:** shortage bookings based on time and article type ([c5bd5a7](https://git.tuffraid.net/cowch/lstV2/commits/c5bd5a7c0a074ac1b94fa5435992f2b9a8e65132))
|
||||||
|
* **prodroles:** added in quality manager ([4abecd0](https://git.tuffraid.net/cowch/lstV2/commits/4abecd045556c98b42cd6ac132958a32a3279a54))
|
||||||
|
* **prodroles:** new cto role added ([ab8102a](https://git.tuffraid.net/cowch/lstV2/commits/ab8102afbfc62ba41de38c021ab7c0a78e972a90))
|
||||||
|
* **readers:** added in good and bad reads to monitor eff ([c0ede87](https://git.tuffraid.net/cowch/lstV2/commits/c0ede8714cd99e9b92b4169b9eaf90de3e1d46ab))
|
||||||
|
* **rfid:** added in manual trigger for rfid reader at the wrapper ([7497ee4](https://git.tuffraid.net/cowch/lstV2/commits/7497ee454c792fabe2c5bd0427f63e725b4a781e))
|
||||||
|
* **rfid:** front end view of the readers and there status ([f7b4de8](https://git.tuffraid.net/cowch/lstV2/commits/f7b4de813051f1bd28fea98c6473a156024b1a1c))
|
||||||
|
* **rfid:** more rfid topics while monitoring the system run ([6a082d9](https://git.tuffraid.net/cowch/lstV2/commits/6a082d97375be872ecec33c2045d37c8368d790a))
|
||||||
|
* **silo attached detach:** added in silo attach detach setup in the silo card ([2ac4813](https://git.tuffraid.net/cowch/lstV2/commits/2ac48138cba961fc09853ab16b4bb2f1dc2972f0))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **consume material:** changes to use api vs prod user ([bc54b36](https://git.tuffraid.net/cowch/lstV2/commits/bc54b365ea9472170a1d22364ac3d9b635175386))
|
||||||
|
* **datamart:** changes to customer inventory to include specific whse ([3073df3](https://git.tuffraid.net/cowch/lstV2/commits/3073df342ff2ede979d2e7f4b2bb16dacb99c093))
|
||||||
|
* **dbscheme:** refactoring from opening and saving ([c155e89](https://git.tuffraid.net/cowch/lstV2/commits/c155e89bc7e62a4beb09b4978445075c088d0133))
|
||||||
|
* **dyco:** change the plc check time from 5 > 8 ([e50e9af](https://git.tuffraid.net/cowch/lstV2/commits/e50e9af839caf9aca8bf71419433bee41702a656))
|
||||||
|
* **dyco:** pickup changed to let spam again so we dont miss anything ([49fd9d6](https://git.tuffraid.net/cowch/lstV2/commits/49fd9d65c9cf23c1524ec2d4c16628cb742a6077))
|
||||||
|
* **finance query:** changes to include article type ([26ceb95](https://git.tuffraid.net/cowch/lstV2/commits/26ceb95daefa1615dbc4e41f68763283c1ae91a3))
|
||||||
|
* **lim:** shipping hours change ([7ed9db1](https://git.tuffraid.net/cowch/lstV2/commits/7ed9db1bdb2c5a1fee867d1501fc909f47e8ddaf))
|
||||||
|
* **mm check:** added in a check that if we dont need mm we return mm checked ([58711be](https://git.tuffraid.net/cowch/lstV2/commits/58711becf2eec518ebca9a0239c2b97f23b38372))
|
||||||
|
* **ocp page:** changes to the layout so it can better be moved for the tiles ([f757085](https://git.tuffraid.net/cowch/lstV2/commits/f757085fc2936c929fbfce19e9784ab14654193d))
|
||||||
|
* **printers:** addedin daily check for printers used to only be on a restart ([588f264](https://git.tuffraid.net/cowch/lstV2/commits/588f264854a5898f633114032398608985e4371c))
|
||||||
|
* **rfid:** ratio resets implemeneted ([a7f8e39](https://git.tuffraid.net/cowch/lstV2/commits/a7f8e39bac684b94a68ed484987b9c6c1693e3ec))
|
||||||
|
* **rfid:** reduced teh rssi peak -50 > -40 ([a19ac53](https://git.tuffraid.net/cowch/lstV2/commits/a19ac539e7e65741858730e2089517756962c558))
|
||||||
|
* **server data:** changes to bet and stp1 ([bd5bad3](https://git.tuffraid.net/cowch/lstV2/commits/bd5bad3cba587f53c8c6e31555c6433620c7a474))
|
||||||
|
* **serverdb:** format changes ([77d9e5d](https://git.tuffraid.net/cowch/lstV2/commits/77d9e5d095a1f31fcbdd094b2dd39b89ddabce87))
|
||||||
|
* **wrapper card:** changes to include the rfid and remove the manual trigger as no one used it ([8f5e1cb](https://git.tuffraid.net/cowch/lstV2/commits/8f5e1cb0948354d13b7def478226e3e82b377829))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **dashboard:** some more rending fixes due to some strange behaivers ([f4dd572](https://git.tuffraid.net/cowch/lstV2/commits/f4dd572a8f8889c5938145ef9d74621da27ae206))
|
||||||
|
* **db:** lastRead column was named incorrectly ([1a6a051](https://git.tuffraid.net/cowch/lstV2/commits/1a6a05112b869358b3f2e87e688670ab95eb27a7))
|
||||||
|
* **detach silo:** when pressing cancel the detach funciton would not work ([05fa774](https://git.tuffraid.net/cowch/lstV2/commits/05fa774d68c5bb006dd7fb317138bbc630a1cf55))
|
||||||
|
* **dm:** missing api key call, and better logging on the post orders section ([531b343](https://git.tuffraid.net/cowch/lstV2/commits/531b343d17a0706bb18f8c7fc047422c5348fb92))
|
||||||
|
* **label ratio:** missed a manual spot that was not considered ([e6f3a9b](https://git.tuffraid.net/cowch/lstV2/commits/e6f3a9b4d07765264d788a261a7b10c731d19987))
|
||||||
|
* **logs:** time crap ([e13b5a4](https://git.tuffraid.net/cowch/lstV2/commits/e13b5a42836f337607f2fc0fd359c3f8cfdf4443))
|
||||||
|
* **ocp page:** server info error added check to make sure was there ([3cafbd9](https://git.tuffraid.net/cowch/lstV2/commits/3cafbd92d0d1fd6dbdb8d92cfa811b9eaa7c60d0))
|
||||||
|
* **renderfixes:** some strange rendering fixes that should have been caught long time ago ([3b56a5e](https://git.tuffraid.net/cowch/lstV2/commits/3b56a5e3e2d37858be4c4ce08f33abbf31f141d0))
|
||||||
|
* **rfid reader:** ratio to be fixed 2 digits so it dose not span across the entire page ([c6d80db](https://git.tuffraid.net/cowch/lstV2/commits/c6d80dbc8a0dcb5a8b219913c9dec1065208012e))
|
||||||
|
* **rfid:** corrections to the manual tag to no fail on manual when a tag already exists but failed ([33295dc](https://git.tuffraid.net/cowch/lstV2/commits/33295dc3c39569d818d4c7245390891e34080c9d))
|
||||||
|
* **rfid:** existing tags were trying to be inserted and instead of updating failed corrected ([1c910d8](https://git.tuffraid.net/cowch/lstV2/commits/1c910d80ead6b9196dd4181534c6044a007e81b5))
|
||||||
|
* **rfid:** lots of changes to the wrapper area ([7a4dea9](https://git.tuffraid.net/cowch/lstV2/commits/7a4dea9d87fa15def544d810b8da422acd142e6c))
|
||||||
|
* **rfid:** typos in station 3 logging ([56e0f3e](https://git.tuffraid.net/cowch/lstV2/commits/56e0f3eb47a1c34b9b07121bc6189e793e08eea5))
|
||||||
|
* **settings page:** error with the store not starting as fast as the page ([edc874c](https://git.tuffraid.net/cowch/lstV2/commits/edc874c302a8693b5d7a3abdb98cd95f44134e49))
|
||||||
|
|
||||||
|
## [2.23.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.22.0...v2.23.0) (2025-06-17)
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Testing Code
|
||||||
|
|
||||||
|
* **added in commands:** relocate and updated to remove ([e865c1d](https://git.tuffraid.net/cowch/lstV2/commits/e865c1dcaf8e9ee3710f8d9f65e95118bb3fa3e7))
|
||||||
|
* **return preforms:** start to preform return ([3283972](https://git.tuffraid.net/cowch/lstV2/commits/328397280954fbf6668e2014b0ce28c885ee417d))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **datamart:** fix for delivery date by range error for hardcoded date ([7b60ddc](https://git.tuffraid.net/cowch/lstV2/commits/7b60ddcadf0b6b6e9c9d4e7efd928cf48bcfee0f))
|
||||||
|
* **forecast:** changes to png to allow different address id for the portal ([e1332e7](https://git.tuffraid.net/cowch/lstV2/commits/e1332e754a163bfc882ffb54e6e2bd741579fad1)), closes [#21](https://git.tuffraid.net/cowch/lstV2/issues/21)
|
||||||
|
* **lots:** corrections to role issue where user logged in but no role set yet ([68d7527](https://git.tuffraid.net/cowch/lstV2/commits/68d75277c2490cd25c6f52dd18663fba0c5cd932))
|
||||||
|
* **notification template:** forgot to remove a end time field data ([12d0c69](https://git.tuffraid.net/cowch/lstV2/commits/12d0c6923d1b177d60bf34b5c70168d0e7eb982d))
|
||||||
|
* **produser:** changes to get correct response from errors ([3c45010](https://git.tuffraid.net/cowch/lstV2/commits/3c45010b268ba9aaa0b0b165a8ac06d7d58de9ad))
|
||||||
|
* **removed roles:** changes to remove the roles and use userRoles instead ([826c44c](https://git.tuffraid.net/cowch/lstV2/commits/826c44c9967130f26ddbcfc2e8f4d43673819a71))
|
||||||
|
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **command log:** added new log for all commands used ([aadf255](https://git.tuffraid.net/cowch/lstV2/commits/aadf255e343bb10bed399f6db20671b15e88ce8a))
|
||||||
|
* **common commands:** added in a common commands just the barecode ([6156a1a](https://git.tuffraid.net/cowch/lstV2/commits/6156a1a5bb6ce2dfd160a7877c4cb1d8c91fac3f))
|
||||||
|
* **datamart:** finance inventory audit added ([90be86d](https://git.tuffraid.net/cowch/lstV2/commits/90be86d972d4660d87e0b8f41e7f2b1a22838e9c))
|
||||||
|
* **dotnet:** added in wrapper so we could run in iis for ssl :D ([84aacd5](https://git.tuffraid.net/cowch/lstV2/commits/84aacd5b71b0efab36eb91c0ba7f2d362dd6b736))
|
||||||
|
* **helpercommands:** added in helpercommnands link ([078c2ec](https://git.tuffraid.net/cowch/lstV2/commits/078c2ec12f3a08094d661d1839373b9adf00f07d))
|
||||||
|
* **new command:** helper command to remove as non reusable pallets ([353960b](https://git.tuffraid.net/cowch/lstV2/commits/353960bd267e55b24c59a4a654cc37411c9986c7))
|
||||||
|
* **nofitication:** bow2 henkel orders ([ab23dcd](https://git.tuffraid.net/cowch/lstV2/commits/ab23dcdfb81fddf6881ddaa17111c8115c7002b0))
|
||||||
|
* **prod roles:** added in quality tech and plant manager ([292eb32](https://git.tuffraid.net/cowch/lstV2/commits/292eb324c549c6febc58af8b0a587d241d458c9e))
|
||||||
|
* **produser:** added in prodSupervisor to the list ([136bf98](https://git.tuffraid.net/cowch/lstV2/commits/136bf9820d6df837c1db37b4e38bcdd9375730d3))
|
||||||
|
* **produser:** added in the function to create a standard user based on there username ([99ad79c](https://git.tuffraid.net/cowch/lstV2/commits/99ad79c662cfeddd78bc86792852e8e97b14e287))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **bookin card:** changes to move the button to the right side ([ed77743](https://git.tuffraid.net/cowch/lstV2/commits/ed777437eb6b5a9d8b179c8182883dac3c731683))
|
||||||
|
* **command log:** added in the command log tracking into the 3 we currently have ([0caf809](https://git.tuffraid.net/cowch/lstV2/commits/0caf8094de588e64b3dcda99d023d39e62bbbf5a))
|
||||||
|
* **forcast:** changes to consider a plants different addresses ([92c8fc2](https://git.tuffraid.net/cowch/lstV2/commits/92c8fc25544f4b56fde1348d7040498bd650dcb1))
|
||||||
|
* **ocme:** changes in the pickup to no longer handle all but specific area ([d32289c](https://git.tuffraid.net/cowch/lstV2/commits/d32289c8337eed71d5abb29d0dd8c8741af52ac9))
|
||||||
|
* **ocme:** picked up per location now vs picked up all ([37f2518](https://git.tuffraid.net/cowch/lstV2/commits/37f2518589935788c142965dff1ff5b9fb6ab902))
|
||||||
|
* **picked up pallets:** changes to start picking up only area from spot ([f79ff26](https://git.tuffraid.net/cowch/lstV2/commits/f79ff26958c7f3e4560da73d2a5fb0fd9a6443e6))
|
||||||
|
* **printers:** added in processes for the upcoming reprint function ([1cb285b](https://git.tuffraid.net/cowch/lstV2/commits/1cb285bea86828d0f3fa7cc42a25495681b0e336))
|
||||||
|
* **serverdata:** changes to limas tms data and activation ([51e6864](https://git.tuffraid.net/cowch/lstV2/commits/51e68648681981aee393ee9c1a729534b9a3983a))
|
||||||
|
|
||||||
## [2.22.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.21.0...v2.22.0) (2025-06-10)
|
## [2.22.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.21.0...v2.22.0) (2025-06-10)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# THIS VERSION IS NO LONGER BEING UPDATED PLEASE GO TO THE NEW REPO LINK BELOW
|
||||||
|
|
||||||
|
[NEW LST REPO](https://git.tuffraid.net/cowch/lst)
|
||||||
|
|
||||||
# lstV2
|
# lstV2
|
||||||
|
|
||||||
Logistics Support Tool V2
|
Logistics Support Tool V2
|
||||||
|
|||||||
1
database/migrations/0067_shallow_trish_tilby.sql
Normal file
1
database/migrations/0067_shallow_trish_tilby.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "printerData" ADD COLUMN "processes" jsonb DEFAULT '[]'::jsonb;
|
||||||
1
database/migrations/0068_last_caretaker.sql
Normal file
1
database/migrations/0068_last_caretaker.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "rfidTags" RENAME COLUMN "timeStamp" TO "lastRead";
|
||||||
2
database/migrations/0069_chemical_maximus.sql
Normal file
2
database/migrations/0069_chemical_maximus.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "rfidReaders" ADD COLUMN "goodReads" integer DEFAULT 0;--> statement-breakpoint
|
||||||
|
ALTER TABLE "rfidReaders" ADD COLUMN "badReads" integer DEFAULT 0;
|
||||||
10
database/migrations/0070_brief_mephisto.sql
Normal file
10
database/migrations/0070_brief_mephisto.sql
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE "labelRatio" (
|
||||||
|
" ratio_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"name" text DEFAULT 'labels',
|
||||||
|
"autoLabel" integer DEFAULT 0,
|
||||||
|
"manualLabel" integer DEFAULT 0,
|
||||||
|
"lastReset" timestamp DEFAULT now()
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "invHistoricalData" ADD COLUMN "lot_number" text;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "labelname" ON "labelRatio" USING btree ("name");
|
||||||
2
database/migrations/0071_fantastic_old_lace.sql
Normal file
2
database/migrations/0071_fantastic_old_lace.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "invHistoricalData" ALTER COLUMN "upd_user" SET DEFAULT 'lst';--> statement-breakpoint
|
||||||
|
ALTER TABLE "invHistoricalData" ALTER COLUMN "upd_date" SET DEFAULT now();
|
||||||
3
database/migrations/0072_round_black_knight.sql
Normal file
3
database/migrations/0072_round_black_knight.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE "userRoles" DROP CONSTRAINT "userRoles_user_id_users_user_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "userRoles" ADD CONSTRAINT "userRoles_user_id_users_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("user_id") ON DELETE cascade ON UPDATE no action;
|
||||||
2166
database/migrations/meta/0067_snapshot.json
Normal file
2166
database/migrations/meta/0067_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2166
database/migrations/meta/0068_snapshot.json
Normal file
2166
database/migrations/meta/0068_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2180
database/migrations/meta/0069_snapshot.json
Normal file
2180
database/migrations/meta/0069_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2250
database/migrations/meta/0070_snapshot.json
Normal file
2250
database/migrations/meta/0070_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2252
database/migrations/meta/0071_snapshot.json
Normal file
2252
database/migrations/meta/0071_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2252
database/migrations/meta/0072_snapshot.json
Normal file
2252
database/migrations/meta/0072_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -470,6 +470,48 @@
|
|||||||
"when": 1749671243377,
|
"when": 1749671243377,
|
||||||
"tag": "0066_nosy_dark_beast",
|
"tag": "0066_nosy_dark_beast",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 67,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1749744049457,
|
||||||
|
"tag": "0067_shallow_trish_tilby",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 68,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1752195741709,
|
||||||
|
"tag": "0068_last_caretaker",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 69,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1752195894698,
|
||||||
|
"tag": "0069_chemical_maximus",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 70,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1754767718941,
|
||||||
|
"tag": "0070_brief_mephisto",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 71,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1754768521841,
|
||||||
|
"tag": "0071_fantastic_old_lace",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 72,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1757167736042,
|
||||||
|
"tag": "0072_round_black_knight",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
0
database/schema/forkliftHours.ts
Normal file
0
database/schema/forkliftHours.ts
Normal file
0
database/schema/forkliftLeases.ts
Normal file
0
database/schema/forkliftLeases.ts
Normal file
0
database/schema/forklifts.ts
Normal file
0
database/schema/forklifts.ts
Normal file
@@ -12,7 +12,7 @@ export const invHistoricalData = pgTable(
|
|||||||
"invHistoricalData",
|
"invHistoricalData",
|
||||||
{
|
{
|
||||||
inv_id: uuid("inv_id").defaultRandom().primaryKey(),
|
inv_id: uuid("inv_id").defaultRandom().primaryKey(),
|
||||||
histDate: date("histDate").notNull(), // what month are we running in should just be the first of current month
|
histDate: date("histDate").notNull(), // this date should always be yesterday when we post it.
|
||||||
plantToken: text("plantToken"),
|
plantToken: text("plantToken"),
|
||||||
article: text("article").notNull(),
|
article: text("article").notNull(),
|
||||||
articleDescription: text("articleDescription").notNull(),
|
articleDescription: text("articleDescription").notNull(),
|
||||||
@@ -21,10 +21,11 @@ export const invHistoricalData = pgTable(
|
|||||||
avaliable_QTY: text("avaliable_QTY"),
|
avaliable_QTY: text("avaliable_QTY"),
|
||||||
coa_QTY: text("coa_QTY"),
|
coa_QTY: text("coa_QTY"),
|
||||||
held_QTY: text("held_QTY"),
|
held_QTY: text("held_QTY"),
|
||||||
|
lot_Number: text("lot_number"),
|
||||||
consignment: text("consignment"),
|
consignment: text("consignment"),
|
||||||
location: text("location"),
|
location: text("location"),
|
||||||
upd_user: text("upd_user"),
|
upd_user: text("upd_user").default("lst"),
|
||||||
upd_date: timestamp("upd_date"),
|
upd_date: timestamp("upd_date").defaultNow(),
|
||||||
}
|
}
|
||||||
// (table) => [
|
// (table) => [
|
||||||
// // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
// // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
boolean,
|
boolean,
|
||||||
uuid,
|
uuid,
|
||||||
uniqueIndex,
|
uniqueIndex,
|
||||||
|
jsonb,
|
||||||
} from "drizzle-orm/pg-core";
|
} 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";
|
||||||
@@ -26,6 +27,7 @@ export const printerData = pgTable(
|
|||||||
remark: text("remark"),
|
remark: text("remark"),
|
||||||
printDelay: numeric("printDelay").default("90"),
|
printDelay: numeric("printDelay").default("90"),
|
||||||
monitorState: boolean("monitorState").default(false),
|
monitorState: boolean("monitorState").default(false),
|
||||||
|
processes: jsonb("processes").default([]),
|
||||||
add_Date: timestamp("add_Date").defaultNow(),
|
add_Date: timestamp("add_Date").defaultNow(),
|
||||||
upd_date: timestamp("upd_date").defaultNow(),
|
upd_date: timestamp("upd_date").defaultNow(),
|
||||||
},
|
},
|
||||||
|
|||||||
32
database/schema/ratios.ts
Normal file
32
database/schema/ratios.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
integer,
|
||||||
|
jsonb,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uniqueIndex,
|
||||||
|
uuid,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createSelectSchema } from "drizzle-zod";
|
||||||
|
|
||||||
|
export const labelRatio = pgTable(
|
||||||
|
"labelRatio",
|
||||||
|
{
|
||||||
|
ratio_id: uuid(" ratio_id").defaultRandom().primaryKey(),
|
||||||
|
name: text("name").default("labels"),
|
||||||
|
autoLabel: integer("autoLabel").default(0),
|
||||||
|
manualLabel: integer("manualLabel").default(0),
|
||||||
|
lastReset: timestamp().defaultNow(),
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||||
|
uniqueIndex("labelname").on(table.name),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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(labelRatio);
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
uuid,
|
uuid,
|
||||||
uniqueIndex,
|
uniqueIndex,
|
||||||
jsonb,
|
jsonb,
|
||||||
|
integer,
|
||||||
} from "drizzle-orm/pg-core";
|
} 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";
|
||||||
@@ -23,6 +24,8 @@ export const rfidReaders = pgTable(
|
|||||||
lastTriggerGood: boolean("lastTiggerGood").default(true),
|
lastTriggerGood: boolean("lastTiggerGood").default(true),
|
||||||
active: boolean("active").default(true),
|
active: boolean("active").default(true),
|
||||||
lastTagScanned: text("lastTagScanned"),
|
lastTagScanned: text("lastTagScanned"),
|
||||||
|
goodReads: integer("goodReads").default(0),
|
||||||
|
badReads: integer("badReads").default(0),
|
||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import {text, pgTable, timestamp, uuid, uniqueIndex, jsonb, integer} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
text,
|
||||||
import {z} from "zod";
|
pgTable,
|
||||||
|
timestamp,
|
||||||
|
uuid,
|
||||||
|
uniqueIndex,
|
||||||
|
jsonb,
|
||||||
|
integer,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export const rfidTags = pgTable(
|
export const rfidTags = pgTable(
|
||||||
"rfidTags",
|
"rfidTags",
|
||||||
@@ -8,7 +16,7 @@ export const rfidTags = pgTable(
|
|||||||
rfidTag_id: uuid("rfidTag_id").defaultRandom().primaryKey(),
|
rfidTag_id: uuid("rfidTag_id").defaultRandom().primaryKey(),
|
||||||
tagHex: text("tagHex"),
|
tagHex: text("tagHex"),
|
||||||
tag: text("tag"),
|
tag: text("tag"),
|
||||||
lastRead: timestamp("timeStamp").defaultNow(),
|
lastRead: timestamp("lastRead").defaultNow(), // cahnge this and hope we dont loose the data.
|
||||||
counts: jsonb("counts").default([]), // example [{area: Line3.2, count: 1}, {area: line3.1, count: 6}]
|
counts: jsonb("counts").default([]), // example [{area: Line3.2, count: 1}, {area: line3.1, count: 6}]
|
||||||
lastareaIn: text("lastareaIn").notNull(),
|
lastareaIn: text("lastareaIn").notNull(),
|
||||||
runningNumber: integer("runningNumber"),
|
runningNumber: integer("runningNumber"),
|
||||||
@@ -23,8 +31,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(rfidTags, {
|
// export const insertRolesSchema = createInsertSchema(rfidTags, {
|
||||||
tagHex: z.string().min(3, {message: "Tag Should have more than 3 characters"}),
|
// 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);
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
import {boolean, date, jsonb, numeric, pgTable, text, timestamp, uniqueIndex, uuid} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createSelectSchema} from "drizzle-zod";
|
boolean,
|
||||||
|
date,
|
||||||
|
jsonb,
|
||||||
|
numeric,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
uniqueIndex,
|
||||||
|
uuid,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createSelectSchema } from "drizzle-zod";
|
||||||
|
|
||||||
export const serverData = pgTable(
|
export const serverData = pgTable(
|
||||||
"serverData",
|
"serverData",
|
||||||
@@ -21,9 +31,13 @@ export const serverData = pgTable(
|
|||||||
serverLoc: text("serverLoc"),
|
serverLoc: text("serverLoc"),
|
||||||
oldVersion: text("oldVersion"),
|
oldVersion: text("oldVersion"),
|
||||||
lastUpdated: timestamp("lastUpdated").defaultNow(),
|
lastUpdated: timestamp("lastUpdated").defaultNow(),
|
||||||
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),
|
isUpgrading: boolean("isUpgrading").default(false),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
text,
|
||||||
import {z} from "zod";
|
pgTable,
|
||||||
import {users} from "./users.js";
|
numeric,
|
||||||
import {roles} from "./roles.js";
|
index,
|
||||||
import {modules} from "./modules.js";
|
timestamp,
|
||||||
|
boolean,
|
||||||
|
uuid,
|
||||||
|
uniqueIndex,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { users } from "./users.js";
|
||||||
|
import { roles } from "./roles.js";
|
||||||
|
import { modules } from "./modules.js";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
we will add the user
|
we will add the user
|
||||||
@@ -17,14 +26,14 @@ export const userRoles = pgTable(
|
|||||||
"userRoles",
|
"userRoles",
|
||||||
{
|
{
|
||||||
user_id: uuid("user_id")
|
user_id: uuid("user_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.user_id),
|
.references(() => users.user_id, { onDelete: "cascade" }),
|
||||||
role_id: uuid("role_id")
|
role_id: uuid("role_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => roles.role_id),
|
.references(() => roles.role_id),
|
||||||
module_id: uuid("module_id")
|
module_id: uuid("module_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => modules.module_id),
|
.references(() => modules.module_id),
|
||||||
role: text("role").notNull(), // "view", "technician", "supervisor","manager", "admin", "systemAdmin"
|
role: text("role").notNull(), // "view", "technician", "supervisor","manager", "admin", "systemAdmin"
|
||||||
add_User: text("add_User").default("LST_System").notNull(),
|
add_User: text("add_User").default("LST_System").notNull(),
|
||||||
add_Date: timestamp("add_Date").defaultNow(),
|
add_Date: timestamp("add_Date").defaultNow(),
|
||||||
@@ -33,13 +42,18 @@ export const userRoles = pgTable(
|
|||||||
},
|
},
|
||||||
(table) => {
|
(table) => {
|
||||||
// ensures only one user gets permissions to one role
|
// ensures only one user gets permissions to one role
|
||||||
return [uniqueIndex("user_module_unique").on(table.user_id, table.module_id)];
|
return [
|
||||||
|
uniqueIndex("user_module_unique").on(
|
||||||
|
table.user_id,
|
||||||
|
table.module_id
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 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 insertUserRolesSchema = createInsertSchema(userRoles, {
|
// export const insertUserRolesSchema = createInsertSchema(userRoles, {
|
||||||
role: z.string().min(3, {message: "Role must be at least 3 characters"}),
|
// role: z.string().min(3, {message: "Role must be at least 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 selectUserRolesSchema = createSelectSchema(userRoles);
|
export const selectUserRolesSchema = createSelectSchema(userRoles);
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex} from "drizzle-orm/pg-core";
|
import {
|
||||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
text,
|
||||||
import {z} from "zod";
|
pgTable,
|
||||||
|
numeric,
|
||||||
|
index,
|
||||||
|
timestamp,
|
||||||
|
boolean,
|
||||||
|
uuid,
|
||||||
|
uniqueIndex,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export const users = pgTable(
|
export const users = pgTable(
|
||||||
"users",
|
"users",
|
||||||
@@ -27,10 +36,10 @@ export const users = 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 insertUsersSchema = createInsertSchema(users, {
|
// export const insertUsersSchema = createInsertSchema(users, {
|
||||||
username: z.string().min(3, {message: "Username must be at least 3 characters"}),
|
// username: z.string().min(3, {message: "Username must be at least 3 characters"}),
|
||||||
email: z.string().email({message: "Invalid email"}),
|
// email: z.string().email({message: "Invalid email"}),
|
||||||
password: z.string().min(8, {message: "Password must be at least 8 characters"}),
|
// password: z.string().min(8, {message: "Password must be at least 8 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 selectUsersSchema = createSelectSchema(users);
|
export const selectUsersSchema = createSelectSchema(users);
|
||||||
|
|||||||
26
dotnetwrapper/Program.cs
Normal file
26
dotnetwrapper/Program.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Add services to the container.
|
||||||
|
builder.Services.AddControllersWithViews();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
// if (!app.Environment.IsDevelopment())
|
||||||
|
// {
|
||||||
|
// // app.UseExceptionHandler("/Home/Error");
|
||||||
|
// // app.UseHsts();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// app.UseHttpsRedirection(); // to force https
|
||||||
|
|
||||||
|
app.UseStaticFiles();
|
||||||
|
app.UseRouting();
|
||||||
|
app.MapFallbackToFile("index.html");
|
||||||
|
|
||||||
|
app.Run();
|
||||||
23
dotnetwrapper/Properties/launchSettings.json
Normal file
23
dotnetwrapper/Properties/launchSettings.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "http://localhost:3000",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"https": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "https://localhost:3000;http://localhost:3000",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
dotnetwrapper/appsettings.json
Normal file
9
dotnetwrapper/appsettings.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
27
dotnetwrapper/lst-wrapper.csproj
Normal file
27
dotnetwrapper/lst-wrapper.csproj
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Target Name="CopyToProjectWwwRoot" AfterTargets="BuildViteApp">
|
||||||
|
<ItemGroup>
|
||||||
|
<ViteDistFiles Include="..\my-vite-app\dist\**\*.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Copy SourceFiles="@(ViteDistFiles)" DestinationFolder="wwwroot\%(RecursiveDir)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!-- <Target Name="CopyViteFiles" AfterTargets="Build">
|
||||||
|
<ItemGroup>
|
||||||
|
<ViteDistFiles Include="..\my-vite-app\dist\**\*.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Copy SourceFiles="@(ViteDistFiles)" DestinationFolder="$(OutDir)wwwroot\%(RecursiveDir)" SkipUnchangedFiles="true" />
|
||||||
|
</Target> -->
|
||||||
|
<!-- <ItemGroup>
|
||||||
|
<Content Include="..\my-vite-app\dist\**" LinkBase="wwwroot" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup> -->
|
||||||
|
</Project>
|
||||||
24
dotnetwrapper/lst-wrapper.sln
Normal file
24
dotnetwrapper/lst-wrapper.sln
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.2.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lst-wrapper", "lst-wrapper.csproj", "{073770C2-0E50-484C-BB72-0A7B602D10B7}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{073770C2-0E50-484C-BB72-0A7B602D10B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{073770C2-0E50-484C-BB72-0A7B602D10B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{073770C2-0E50-484C-BB72-0A7B602D10B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{073770C2-0E50-484C-BB72-0A7B602D10B7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {39D31A4B-FECC-425A-9AD5-95EF563F5BE7}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
3394
frontend/package-lock.json
generated
3394
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,69 +12,73 @@
|
|||||||
"checkupdates": "npm-check-updates"
|
"checkupdates": "npm-check-updates"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^4.1.3",
|
"@hookform/resolvers": "^5.1.1",
|
||||||
"@radix-ui/react-accordion": "^1.2.3",
|
"@radix-ui/react-accordion": "^1.2.11",
|
||||||
"@radix-ui/react-avatar": "^1.1.3",
|
"@radix-ui/react-avatar": "^1.1.10",
|
||||||
"@radix-ui/react-checkbox": "^1.1.4",
|
"@radix-ui/react-checkbox": "^1.3.2",
|
||||||
"@radix-ui/react-collapsible": "^1.1.3",
|
"@radix-ui/react-collapsible": "^1.1.11",
|
||||||
"@radix-ui/react-dialog": "^1.1.6",
|
"@radix-ui/react-dialog": "^1.1.14",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
"@radix-ui/react-popover": "^1.1.6",
|
"@radix-ui/react-popover": "^1.1.14",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
"@radix-ui/react-scroll-area": "^1.2.9",
|
||||||
"@radix-ui/react-select": "^2.1.6",
|
"@radix-ui/react-select": "^2.2.5",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
"@radix-ui/react-tabs": "^1.1.3",
|
"@radix-ui/react-switch": "^1.2.6",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tabs": "^1.1.12",
|
||||||
|
"@radix-ui/react-tooltip": "^1.2.7",
|
||||||
"@react-pdf/renderer": "^4.3.0",
|
"@react-pdf/renderer": "^4.3.0",
|
||||||
"@tailwindcss/vite": "^4.0.15",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"@tanstack/react-form": "^1.2.1",
|
"@tanstack/react-form": "^1.12.3",
|
||||||
"@tanstack/react-query": "^5.69.0",
|
"@tanstack/react-query": "^5.81.2",
|
||||||
"@tanstack/react-router": "^1.114.27",
|
"@tanstack/react-router": "^1.121.34",
|
||||||
"@tanstack/react-table": "^8.21.2",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"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",
|
"date-fns-tz": "^3.2.0",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.5.0",
|
||||||
"hono": "^4.7.5",
|
"hono": "^4.8.2",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"jsbarcode": "^3.11.6",
|
"jsbarcode": "^3.12.1",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lucide-react": "^0.483.0",
|
"lucide-react": "^0.522.0",
|
||||||
"marked": "^15.0.8",
|
"marked": "^15.0.12",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"npm-check-updates": "^17.1.16",
|
"npm-check-updates": "^18.0.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.1.0",
|
||||||
"react-barcode": "^1.6.1",
|
"react-barcode": "^1.6.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^9.7.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-grid-layout": "^1.5.1",
|
"react-grid-layout": "^1.5.1",
|
||||||
"react-hook-form": "^7.54.2",
|
"react-hook-form": "^7.58.1",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^3.0.3",
|
||||||
"recharts": "^2.15.2",
|
"recharts": "^2.15.2",
|
||||||
"sonner": "^2.0.1",
|
"sonner": "^2.0.5",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.3.1",
|
||||||
"tailwindcss": "^4.0.15",
|
"tailwindcss": "^4.1.10",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod": "^3.24.2",
|
"zod": "^3.25.67",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.23.0",
|
"@eslint/js": "^9.29.0",
|
||||||
"@tanstack/router-devtools": "^1.114.27",
|
"@tanstack/router-devtools": "^1.121.34",
|
||||||
"@tanstack/router-plugin": "^1.114.27",
|
"@tanstack/router-plugin": "^1.121.34",
|
||||||
"@types/react": "^19.0.12",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.1.6",
|
||||||
"@types/react-grid-layout": "^1.3.5",
|
"@types/react-grid-layout": "^1.3.5",
|
||||||
"@vitejs/plugin-react-swc": "^3.8.1",
|
"@vitejs/plugin-react-swc": "^3.10.2",
|
||||||
"eslint": "^9.23.0",
|
"eslint": "^9.29.0",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.2.0",
|
||||||
"typescript": "~5.8.2",
|
"typescript": "~5.8.3",
|
||||||
"typescript-eslint": "^8.27.0",
|
"typescript-eslint": "^8.35.0",
|
||||||
"vite": "^6.2.2"
|
"vite": "^6.3.5"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"react-is": "^19.0.0-rc-69d4b800-20241021"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
225
frontend/src/components/admin/prodUser/ProdUserCard.tsx
Normal file
225
frontend/src/components/admin/prodUser/ProdUserCard.tsx
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { CardHeader } from "@/components/ui/card";
|
||||||
|
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 { useSessionStore } from "@/lib/store/sessionStore";
|
||||||
|
import { getProdPerms } from "@/utils/querys/prodUser/getProdPerms";
|
||||||
|
|
||||||
|
import { useForm } from "@tanstack/react-form";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export default function ProdUserCard() {
|
||||||
|
const { token } = useSessionStore();
|
||||||
|
const { data, isError, isLoading } = useQuery(getProdPerms(token ?? ""));
|
||||||
|
const [creating, setCreating] = useState(false);
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
defaultValues: {
|
||||||
|
username: "",
|
||||||
|
remark: "",
|
||||||
|
pcname: "",
|
||||||
|
role: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmit: async ({ value }) => {
|
||||||
|
setCreating(true);
|
||||||
|
//console.log(value);
|
||||||
|
|
||||||
|
if (value.role === "") {
|
||||||
|
toast.error(
|
||||||
|
"Role is missing please select a role and try again."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/api/produser/produser", value, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log(res.data);
|
||||||
|
|
||||||
|
if (!res.data.success) {
|
||||||
|
const errMSG: string = res.data.data.errors
|
||||||
|
? res.data.data?.errors[0].message
|
||||||
|
: res.data.data;
|
||||||
|
|
||||||
|
toast.error(`${errMSG}`);
|
||||||
|
setCreating(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
form.reset();
|
||||||
|
setCreating(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
setCreating(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isError)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>There was an error loading the prod Perms</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>Loading.....</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="m-4">
|
||||||
|
<LstCard>
|
||||||
|
<CardHeader>
|
||||||
|
<p>Alpla Prod user create/update</p>
|
||||||
|
</CardHeader>
|
||||||
|
<div className="m-2">
|
||||||
|
<p>
|
||||||
|
Please enter the windows username. <br /> To check the
|
||||||
|
user head here{" "}
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
href="https://alplaservicedesk.service-now.com/sp?id=sc_cat_item&sys_id=0c266831c32f41107cba16c4e40131c0&sysparm_category=564428bdc3eb41107cba16c4e40131f2"
|
||||||
|
>
|
||||||
|
<u>Active Directory</u>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Windows username */}
|
||||||
|
<form.Field
|
||||||
|
name="username"
|
||||||
|
validators={{
|
||||||
|
// We can choose between form-wide and field-specific validators
|
||||||
|
onChange: ({ value }) =>
|
||||||
|
value.length > 3
|
||||||
|
? undefined
|
||||||
|
: "Username must be longer than 3 letters",
|
||||||
|
}}
|
||||||
|
children={(field) => {
|
||||||
|
return (
|
||||||
|
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||||
|
<Label htmlFor="username">Username</Label>
|
||||||
|
<Input
|
||||||
|
name={field.name}
|
||||||
|
value={field.state.value}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
//type="number"
|
||||||
|
onChange={(e) =>
|
||||||
|
field.handleChange(e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{field.state.meta.errors.length ? (
|
||||||
|
<em>
|
||||||
|
{field.state.meta.errors.join(",")}
|
||||||
|
</em>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Remark for the user */}
|
||||||
|
<form.Field
|
||||||
|
name="remark"
|
||||||
|
validators={{
|
||||||
|
// We can choose between form-wide and field-specific validators
|
||||||
|
onChange: ({ value }) =>
|
||||||
|
value.length > 3
|
||||||
|
? undefined
|
||||||
|
: "The remark should be longer than 3 letters",
|
||||||
|
}}
|
||||||
|
children={(field) => {
|
||||||
|
return (
|
||||||
|
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||||
|
<Label htmlFor="remark">Remark</Label>
|
||||||
|
<Input
|
||||||
|
name={field.name}
|
||||||
|
value={field.state.value}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
//type="number"
|
||||||
|
onChange={(e) =>
|
||||||
|
field.handleChange(e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{field.state.meta.errors.length ? (
|
||||||
|
<em>
|
||||||
|
{field.state.meta.errors.join(",")}
|
||||||
|
</em>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Select the type of role we will be granting/updating */}
|
||||||
|
<form.Field
|
||||||
|
name="role"
|
||||||
|
//listeners={{onChange: ({value})=>{}}}
|
||||||
|
children={(field) => {
|
||||||
|
return (
|
||||||
|
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||||
|
<Label htmlFor={field.name}>
|
||||||
|
Select role
|
||||||
|
</Label>
|
||||||
|
<Select
|
||||||
|
value={field.state.value}
|
||||||
|
onValueChange={field.handleChange}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue
|
||||||
|
id={field.name}
|
||||||
|
placeholder="Select Role"
|
||||||
|
/>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>Roles</SelectLabel>
|
||||||
|
|
||||||
|
{data.map((i: any) => {
|
||||||
|
return (
|
||||||
|
<SelectItem
|
||||||
|
key={i.prodPerm_id}
|
||||||
|
value={i.name}
|
||||||
|
>
|
||||||
|
{i.name}
|
||||||
|
</SelectItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="flex justify-end mr-3">
|
||||||
|
<Button onClick={form.handleSubmit} disabled={creating}>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { getSettings } from "@/utils/querys/settings";
|
import { getSettings } from "@/utils/querys/settings";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { useEffect } from "react";
|
||||||
//import { useState } from "react";
|
//import { useState } from "react";
|
||||||
|
|
||||||
export type Servers = {
|
export type Servers = {
|
||||||
@@ -46,14 +47,35 @@ export default function ServerPage() {
|
|||||||
getServers(token ?? "")
|
getServers(token ?? "")
|
||||||
);
|
);
|
||||||
|
|
||||||
const adminModule = modules.filter((n) => n.name === "admin");
|
// const adminModule = modules.filter((n) => n.name === "admin");
|
||||||
const userLevel =
|
// const userLevel =
|
||||||
user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) ||
|
// user?.roles?.filter((r) => r.module_id === adminModule[0].module_id) ||
|
||||||
[];
|
// [];
|
||||||
|
|
||||||
if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
|
// if (!adminModule[0]?.roles?.includes(userLevel[0]?.role)) {
|
||||||
router.navigate({ to: "/" });
|
// console.log("Something failed");
|
||||||
}
|
// //router.navigate({ to: "/" });
|
||||||
|
// }
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!user || modules.length === 0) return;
|
||||||
|
|
||||||
|
const adminModule = modules.find((n) => n.name === "admin");
|
||||||
|
if (!adminModule) {
|
||||||
|
console.log("no module loaded");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userLevel =
|
||||||
|
user?.roles?.filter((r) => r.module_id === adminModule.module_id) ||
|
||||||
|
[];
|
||||||
|
|
||||||
|
if (!adminModule.roles?.includes(userLevel[0]?.role)) {
|
||||||
|
console.log("Something failed");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
|
}
|
||||||
|
}, [modules, user, router]);
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return <div>{JSON.stringify(error)}</div>;
|
return <div>{JSON.stringify(error)}</div>;
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
import {
|
||||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
Table,
|
||||||
import {useModuleStore} from "@/lib/store/useModuleStore";
|
TableBody,
|
||||||
import {useQuery} from "@tanstack/react-query";
|
TableCell,
|
||||||
import {useRouter} from "@tanstack/react-router";
|
TableHead,
|
||||||
import {ChangeSetting} from "./SettingForm";
|
TableHeader,
|
||||||
import {getSettings} from "@/utils/querys/settings";
|
TableRow,
|
||||||
import {Skeleton} from "@/components/ui/skeleton";
|
} from "@/components/ui/table";
|
||||||
|
import { useSessionStore } from "@/lib/store/sessionStore";
|
||||||
|
import { useModuleStore } from "@/lib/store/useModuleStore";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useRouter } from "@tanstack/react-router";
|
||||||
|
import { ChangeSetting } from "./SettingForm";
|
||||||
|
import { getSettings } from "@/utils/querys/settings";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export type Settings = {
|
export type Settings = {
|
||||||
settings_id?: string;
|
settings_id?: string;
|
||||||
@@ -16,18 +24,33 @@ export type Settings = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const {user, token} = useSessionStore();
|
const { user, token } = useSessionStore();
|
||||||
const {modules} = useModuleStore();
|
const { modules } = useModuleStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const adminModule = modules.filter((n) => n.name === "admin");
|
useEffect(() => {
|
||||||
const userLevel = user?.roles.filter((r) => r.module_id === adminModule[0].module_id) || [];
|
if (!user || modules.length === 0) return;
|
||||||
|
|
||||||
if (!adminModule[0].roles.includes(userLevel[0]?.role)) {
|
const adminModule = modules.find((n) => n.name === "admin");
|
||||||
router.navigate({to: "/"});
|
if (!adminModule) {
|
||||||
}
|
console.log("no module loaded");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const {data, isError, error, isLoading} = useQuery(getSettings(token ?? ""));
|
const userLevel =
|
||||||
|
user?.roles?.filter((r) => r.module_id === adminModule.module_id) ||
|
||||||
|
[];
|
||||||
|
|
||||||
|
if (!adminModule.roles?.includes(userLevel[0]?.role)) {
|
||||||
|
console.log("Something failed");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
|
}
|
||||||
|
}, [modules, user, router]);
|
||||||
|
|
||||||
|
const { data, isError, error, isLoading } = useQuery(
|
||||||
|
getSettings(token ?? "")
|
||||||
|
);
|
||||||
|
|
||||||
// if (isLoading) {
|
// if (isLoading) {
|
||||||
// return <div>Loading.....</div>;
|
// return <div>Loading.....</div>;
|
||||||
@@ -51,32 +74,38 @@ export default function SettingsPage() {
|
|||||||
<>
|
<>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{Array(10)
|
{Array(10)
|
||||||
.fill(0)
|
.fill(0)
|
||||||
.map((_, i) => (
|
.map((_, i) => (
|
||||||
<TableRow key={i}>
|
<TableRow key={i}>
|
||||||
<TableCell className="font-medium">
|
<TableCell className="font-medium">
|
||||||
<Skeleton className="h-4" />
|
<Skeleton className="h-4" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Skeleton className="h-4" />
|
<Skeleton className="h-4" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Skeleton className="h-4" />
|
<Skeleton className="h-4" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Skeleton className="h-4" />
|
<Skeleton className="h-4" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{data?.map((setting: Settings) => (
|
{data?.map((setting: Settings) => (
|
||||||
<TableRow key={setting.settings_id}>
|
<TableRow key={setting.settings_id}>
|
||||||
<TableCell className="font-medium">{setting.name}</TableCell>
|
<TableCell className="font-medium">
|
||||||
<TableCell className="font-medium">{setting.value}</TableCell>
|
{setting.name}
|
||||||
<TableCell className="font-medium">{setting.description}</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{setting.value}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">
|
||||||
|
{setting.description}
|
||||||
|
</TableCell>
|
||||||
<TableCell className="font-medium">
|
<TableCell className="font-medium">
|
||||||
<ChangeSetting setting={setting} />
|
<ChangeSetting setting={setting} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { ChangeSubModule } from "./SubModuleForm";
|
|||||||
|
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { getSubModules } from "@/utils/querys/admin/subModules";
|
import { getSubModules } from "@/utils/querys/admin/subModules";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export type Settings = {
|
export type Settings = {
|
||||||
settings_id?: string;
|
settings_id?: string;
|
||||||
@@ -28,14 +29,34 @@ export default function SubModulePage() {
|
|||||||
const { modules } = useModuleStore();
|
const { modules } = useModuleStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const adminModule = modules.filter((n) => n.name === "admin");
|
// const adminModule = modules.filter((n) => n.name === "admin");
|
||||||
const userLevel =
|
// const userLevel =
|
||||||
user?.roles.filter((r) => r.module_id === adminModule[0].module_id) ||
|
// user?.roles.filter((r) => r.module_id === adminModule[0].module_id) ||
|
||||||
[];
|
// [];
|
||||||
|
|
||||||
if (!adminModule[0].roles.includes(userLevel[0]?.role)) {
|
// if (!adminModule[0]?.roles.includes(userLevel[0]?.role)) {
|
||||||
router.navigate({ to: "/" });
|
// //router.navigate({ to: "/" });
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!user || modules.length === 0) return;
|
||||||
|
|
||||||
|
const adminModule = modules.find((n) => n.name === "admin");
|
||||||
|
if (!adminModule) {
|
||||||
|
console.log("no module loaded");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userLevel =
|
||||||
|
user?.roles?.filter((r) => r.module_id === adminModule.module_id) ||
|
||||||
|
[];
|
||||||
|
|
||||||
|
if (!adminModule.roles?.includes(userLevel[0]?.role)) {
|
||||||
|
console.log("Something failed");
|
||||||
|
//router.navigate({ to: "/" });
|
||||||
|
}
|
||||||
|
}, [modules, user, router]);
|
||||||
|
|
||||||
const { data, isError, error, isLoading } = useQuery(
|
const { data, isError, error, isLoading } = useQuery(
|
||||||
getSubModules(token ?? "")
|
getSubModules(token ?? "")
|
||||||
|
|||||||
@@ -1,25 +1,15 @@
|
|||||||
import { useCardStore } from "@/lib/store/useCardStore";
|
import { useCardStore } from "@/lib/store/useCardStore";
|
||||||
import { useForm } from "@tanstack/react-form";
|
|
||||||
import { Label } from "../ui/label";
|
import { Label } from "../ui/label";
|
||||||
import { Checkbox } from "../ui/checkbox";
|
import { Checkbox } from "../ui/checkbox";
|
||||||
import { Input } from "../ui/input";
|
|
||||||
// import {
|
|
||||||
// Select,
|
|
||||||
// SelectContent,
|
|
||||||
// SelectGroup,
|
|
||||||
// SelectItem,
|
|
||||||
// SelectLabel,
|
|
||||||
// SelectTrigger,
|
|
||||||
// SelectValue,
|
|
||||||
// } from "../ui/select";
|
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
import { useAppForm } from "@/utils/formStuff";
|
||||||
|
|
||||||
export default function Cards(card: any) {
|
export default function Cards(card: any) {
|
||||||
const { addCard, removeCard, cards } = useCardStore();
|
const { addCard, removeCard, cards } = useCardStore();
|
||||||
let existing: any = cards.filter((n: any) => n.name === card.name);
|
let existing: any = cards.filter((n: any) => n.name === card.name);
|
||||||
|
|
||||||
//console.log(existing);
|
//console.log(existing);
|
||||||
const form = useForm({
|
const form = useAppForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: existing[0]?.name || card.name,
|
name: existing[0]?.name || card.name,
|
||||||
rowType: existing[0]?.type ?? card.rowType,
|
rowType: existing[0]?.type ?? card.rowType,
|
||||||
@@ -62,7 +52,7 @@ export default function Cards(card: any) {
|
|||||||
}}
|
}}
|
||||||
className="flex flex-row"
|
className="flex flex-row"
|
||||||
>
|
>
|
||||||
<form.Field
|
<form.AppField
|
||||||
name="active"
|
name="active"
|
||||||
// validators={{
|
// validators={{
|
||||||
// // We can choose between form-wide and field-specific validators
|
// // We can choose between form-wide and field-specific validators
|
||||||
@@ -95,83 +85,16 @@ export default function Cards(card: any) {
|
|||||||
/>
|
/>
|
||||||
{!card.inventory && (
|
{!card.inventory && (
|
||||||
<>
|
<>
|
||||||
<form.Field
|
<form.AppField
|
||||||
name="age"
|
name="age"
|
||||||
// validators={{
|
children={(field) => (
|
||||||
// // We can choose between form-wide and field-specific validators
|
<field.InputField
|
||||||
// onChange: ({ value }) =>
|
label="Age"
|
||||||
// value.length > 3
|
inputType="number"
|
||||||
// ? undefined
|
required={true}
|
||||||
// : "Username must be longer than 3 letters",
|
/>
|
||||||
// }}
|
)}
|
||||||
children={(field) => {
|
|
||||||
return (
|
|
||||||
<div className="m-2 min-w-48 p-2">
|
|
||||||
<Label htmlFor="active" className="">
|
|
||||||
Age
|
|
||||||
</Label>
|
|
||||||
<Input
|
|
||||||
name={field.name}
|
|
||||||
onBlur={field.handleBlur}
|
|
||||||
value={field.state.value}
|
|
||||||
type="number"
|
|
||||||
onChange={(e) =>
|
|
||||||
field.handleChange(
|
|
||||||
e.target.value
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* <form.Field
|
|
||||||
name="rowType"
|
|
||||||
//listeners={{onChange: ({value})=>{}}}
|
|
||||||
children={(field) => {
|
|
||||||
return (
|
|
||||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
|
||||||
<Label htmlFor={field.name}>
|
|
||||||
Row Type
|
|
||||||
</Label>
|
|
||||||
<Select
|
|
||||||
value={field.state.value}
|
|
||||||
onValueChange={field.handleChange}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
|
||||||
<SelectValue
|
|
||||||
id={field.name}
|
|
||||||
placeholder="Select Role"
|
|
||||||
/>
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectGroup>
|
|
||||||
<SelectLabel>
|
|
||||||
Row Type
|
|
||||||
</SelectLabel>
|
|
||||||
<SelectItem value="empty">
|
|
||||||
Empty
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="fg">
|
|
||||||
Finished Goods
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="materials">
|
|
||||||
Materials
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="waste">
|
|
||||||
Waste
|
|
||||||
</SelectItem>
|
|
||||||
<SelectItem value="packaging">
|
|
||||||
Packaging
|
|
||||||
</SelectItem>
|
|
||||||
</SelectGroup>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/> */}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="mt-7">
|
<div className="mt-7">
|
||||||
|
|||||||
@@ -27,9 +27,10 @@ export default function DashBoard() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
//console.log(name.split("-")[0], a);
|
||||||
return (
|
return (
|
||||||
<div key={a.name} className="col-span-3">
|
<div key={a.name} className="col-span-3">
|
||||||
<Component age={a.age} type={a.rowType} />
|
<Component data={a} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +1,9 @@
|
|||||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
import MaterialCheck from "./materialCheck/MaterialCheck";
|
||||||
import {LstCard} from "../extendedUI/LstCard";
|
|
||||||
import {Tabs, TabsContent, TabsList, TabsTrigger} from "../ui/tabs";
|
|
||||||
import {useModuleStore} from "@/lib/store/useModuleStore";
|
|
||||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "../ui/table";
|
|
||||||
import {Skeleton} from "../ui/skeleton";
|
|
||||||
|
|
||||||
import {Link, useRouter} from "@tanstack/react-router";
|
|
||||||
import {Popover, PopoverContent, PopoverTrigger} from "../ui/popover";
|
|
||||||
import {Button} from "../ui/button";
|
|
||||||
import {cn} from "@/lib/utils";
|
|
||||||
import {CalendarIcon} from "lucide-react";
|
|
||||||
import {format, startOfMonth} from "date-fns";
|
|
||||||
import {Calendar} from "../ui/calendar";
|
|
||||||
import {useState} from "react";
|
|
||||||
import {toast} from "sonner";
|
|
||||||
import KFP from "./KFP";
|
|
||||||
|
|
||||||
export default function EomPage() {
|
export default function EomPage() {
|
||||||
const {modules} = useModuleStore();
|
|
||||||
const {user} = useSessionStore();
|
|
||||||
const router = useRouter();
|
|
||||||
const [date, setDate] = useState<Date>();
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
router.navigate({to: "/"});
|
|
||||||
}
|
|
||||||
const eomMod = modules.filter((m) => m.name === "eom");
|
|
||||||
// the users current role for eom is?
|
|
||||||
const role: any = user?.roles.filter((r) => r.module_id === eomMod[0].module_id) || "";
|
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{key: "kfp", label: "Key Figures", roles: ["admin", "systemAdmin"], content: <KFP />},
|
|
||||||
{key: "fg", label: "Finished Goods", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
|
||||||
{key: "mm", label: "Main Material", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
|
||||||
{key: "mb", label: "Master Batch", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
|
||||||
{key: "ab", label: "Additive", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
|
||||||
{key: "pp", label: "Purchased Preforms", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
|
||||||
{key: "pre", label: "Preforms", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
|
||||||
{key: "pkg", label: "Packaging", roles: ["admin", "systemAdmin"], content: <DummyContent />},
|
|
||||||
{key: "ui", label: "Undefined Items", roles: ["admin"], content: <DummyContent />},
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
<div className="m-2 w-screen">
|
<div className="m-2 w-screen">
|
||||||
<div className="mb-2 flex flex-row">
|
<MaterialCheck />
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant={"outline"}
|
|
||||||
className={cn(
|
|
||||||
"w-[280px] justify-start text-left font-normal",
|
|
||||||
!date && "text-muted-foreground"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
|
||||||
{date ? format(date, "PPP") : <span>Pick a date</span>}
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className="w-auto p-0">
|
|
||||||
<Calendar mode="single" selected={date} onSelect={setDate} initialFocus />
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
<div className="ml-2">
|
|
||||||
<Button onClick={() => toast.success(`Getting data for ${startOfMonth(date!)}-${date}`)}>
|
|
||||||
<span className="text-sm">Update Data</span>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Tabs defaultValue="mm">
|
|
||||||
<TabsList>
|
|
||||||
{tabs.map((tab) => {
|
|
||||||
if (tab.roles.includes(role[0].role))
|
|
||||||
return <TabsTrigger value={tab.key}>{tab.label}</TabsTrigger>;
|
|
||||||
})}
|
|
||||||
</TabsList>
|
|
||||||
{tabs.map((tab) => {
|
|
||||||
if (tab.roles.includes(role[0].role))
|
|
||||||
return <TabsContent value={tab.key}>{tab.content}</TabsContent>;
|
|
||||||
})}
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DummyContent() {
|
|
||||||
return (
|
|
||||||
<LstCard className="w-5/6">
|
|
||||||
<Table>
|
|
||||||
<TableHeader>
|
|
||||||
<TableRow>
|
|
||||||
<TableHead>Av</TableHead>
|
|
||||||
<TableHead>Description</TableHead>
|
|
||||||
<TableHead>Material Type</TableHead>
|
|
||||||
<TableHead>Waste</TableHead>
|
|
||||||
<TableHead>Loss / Gain $$</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
|
|
||||||
<TableBody>
|
|
||||||
{Array(10)
|
|
||||||
.fill(0)
|
|
||||||
.map((_, i) => (
|
|
||||||
<TableRow key={i}>
|
|
||||||
<TableCell className="font-medium m-2">
|
|
||||||
<Link to="/article/$av" params={{av: `${i}`}}>
|
|
||||||
{i}
|
|
||||||
</Link>
|
|
||||||
</TableCell>
|
|
||||||
<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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export default function MaterialCheck() {
|
||||||
|
return <div>MaterialCheck</div>;
|
||||||
|
}
|
||||||
211
frontend/src/components/eom/materialsData/MaterialData.tsx
Normal file
211
frontend/src/components/eom/materialsData/MaterialData.tsx
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Calendar } from "@/components/ui/calendar";
|
||||||
|
import { Popover, PopoverTrigger } from "@/components/ui/popover";
|
||||||
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import { useSessionStore } from "@/lib/store/sessionStore";
|
||||||
|
import { useModuleStore } from "@/lib/store/useModuleStore";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { PopoverContent } from "@radix-ui/react-popover";
|
||||||
|
import { Link, useRouter } from "@tanstack/react-router";
|
||||||
|
import { startOfMonth } from "date-fns";
|
||||||
|
import { format } from "date-fns-tz";
|
||||||
|
import { CalendarIcon } from "lucide-react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import KFP from "../KFP";
|
||||||
|
|
||||||
|
export default function MaterialData() {
|
||||||
|
const { modules } = useModuleStore();
|
||||||
|
const { user } = useSessionStore();
|
||||||
|
const router = useRouter();
|
||||||
|
const [date, setDate] = useState<Date>();
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
router.navigate({ to: "/" });
|
||||||
|
}
|
||||||
|
const eomMod = modules.filter((m) => m.name === "eom");
|
||||||
|
// the users current role for eom is?
|
||||||
|
const role: any =
|
||||||
|
user?.roles.filter((r) => r.module_id === eomMod[0].module_id) || "";
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
key: "kfp",
|
||||||
|
label: "Key Figures",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <KFP />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "fg",
|
||||||
|
label: "Finished Goods",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "mm",
|
||||||
|
label: "Main Material",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "mb",
|
||||||
|
label: "Master Batch",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ab",
|
||||||
|
label: "Additive",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "pp",
|
||||||
|
label: "Purchased Preforms",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "pre",
|
||||||
|
label: "Preforms",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "pkg",
|
||||||
|
label: "Packaging",
|
||||||
|
roles: ["admin", "systemAdmin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ui",
|
||||||
|
label: "Undefined Items",
|
||||||
|
roles: ["admin"],
|
||||||
|
content: <DummyContent />,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<div className="m-2 w-screen">
|
||||||
|
<div className="mb-2 flex flex-row">
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant={"outline"}
|
||||||
|
className={cn(
|
||||||
|
"w-[280px] justify-start text-left font-normal",
|
||||||
|
!date && "text-muted-foreground"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||||
|
{date ? (
|
||||||
|
format(date, "PPP")
|
||||||
|
) : (
|
||||||
|
<span>Pick a date</span>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-auto p-0">
|
||||||
|
<Calendar
|
||||||
|
mode="single"
|
||||||
|
selected={date}
|
||||||
|
onSelect={setDate}
|
||||||
|
initialFocus
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
<div className="ml-2">
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
toast.success(
|
||||||
|
`Getting data for ${startOfMonth(date!)}-${date}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="text-sm">Update Data</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tabs defaultValue="mm">
|
||||||
|
<TabsList>
|
||||||
|
{tabs.map((tab) => {
|
||||||
|
if (tab.roles.includes(role[0].role))
|
||||||
|
return (
|
||||||
|
<TabsTrigger value={tab.key}>
|
||||||
|
{tab.label}
|
||||||
|
</TabsTrigger>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TabsList>
|
||||||
|
{tabs.map((tab) => {
|
||||||
|
if (tab.roles.includes(role[0].role))
|
||||||
|
return (
|
||||||
|
<TabsContent value={tab.key}>
|
||||||
|
{tab.content}
|
||||||
|
</TabsContent>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DummyContent() {
|
||||||
|
return (
|
||||||
|
<LstCard className="w-5/6">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead>Av</TableHead>
|
||||||
|
<TableHead>Description</TableHead>
|
||||||
|
<TableHead>Material Type</TableHead>
|
||||||
|
<TableHead>Waste</TableHead>
|
||||||
|
<TableHead>Loss / Gain $$</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
|
||||||
|
<TableBody>
|
||||||
|
{Array(10)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => (
|
||||||
|
<TableRow key={i}>
|
||||||
|
<TableCell className="font-medium m-2">
|
||||||
|
<Link
|
||||||
|
to="/article/$av"
|
||||||
|
params={{ av: `${i}` }}
|
||||||
|
>
|
||||||
|
{i}
|
||||||
|
</Link>
|
||||||
|
</TableCell>
|
||||||
|
<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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
import {Link} from "@tanstack/react-router";
|
import { Link } from "@tanstack/react-router";
|
||||||
import {SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem} from "../../ui/sidebar";
|
import {
|
||||||
|
SidebarHeader,
|
||||||
|
SidebarMenu,
|
||||||
|
SidebarMenuButton,
|
||||||
|
SidebarMenuItem,
|
||||||
|
} from "../../ui/sidebar";
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
return (
|
return (
|
||||||
@@ -9,10 +14,16 @@ export function Header() {
|
|||||||
<Link to="/">
|
<Link to="/">
|
||||||
<SidebarMenuButton size="lg" asChild>
|
<SidebarMenuButton size="lg" asChild>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<img src="/imgs/dkLst.png" alt="Description" className="size-8" />
|
<img
|
||||||
|
src={"imgs/dkLst.png"}
|
||||||
|
alt="Description"
|
||||||
|
className="size-8"
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="flex flex-col gap-0.5 leading-none">
|
<div className="flex flex-col gap-0.5 leading-none">
|
||||||
<span className="font-semibold">Logistics Support Tool</span>
|
<span className="font-semibold">
|
||||||
|
Logistics Support Tool
|
||||||
|
</span>
|
||||||
<span className="">v2.0.0</span>
|
<span className="">v2.0.0</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Barcode, Cylinder, Package, Truck } from "lucide-react";
|
import { Barcode, Cylinder, Package, Truck, Command } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
SidebarGroup,
|
SidebarGroup,
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
@@ -16,6 +16,7 @@ const iconMap: any = {
|
|||||||
Truck: Truck,
|
Truck: Truck,
|
||||||
Cylinder: Cylinder,
|
Cylinder: Cylinder,
|
||||||
Barcode: Barcode,
|
Barcode: Barcode,
|
||||||
|
Command: Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function LogisticsSideBar({
|
export function LogisticsSideBar({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Printer} from "lucide-react";
|
import { Printer, Tag } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
SidebarGroup,
|
SidebarGroup,
|
||||||
SidebarGroupContent,
|
SidebarGroupContent,
|
||||||
@@ -7,21 +7,36 @@ import {
|
|||||||
SidebarMenuButton,
|
SidebarMenuButton,
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
} from "../../ui/sidebar";
|
} from "../../ui/sidebar";
|
||||||
import {hasPageAccess} from "@/utils/userAccess";
|
import { hasPageAccess } from "@/utils/userAccess";
|
||||||
import {User} from "@/types/users";
|
import { User } from "@/types/users";
|
||||||
|
|
||||||
const items = [
|
export function ProductionSideBar({
|
||||||
{
|
user,
|
||||||
title: "One Click Print",
|
moduleID,
|
||||||
url: "/ocp",
|
}: {
|
||||||
icon: Printer,
|
user: User | null;
|
||||||
role: ["viewer"],
|
moduleID: string;
|
||||||
module: "ocp",
|
}) {
|
||||||
active: true,
|
const url: string = window.location.host.split(":")[0];
|
||||||
},
|
const items = [
|
||||||
];
|
{
|
||||||
|
title: "One Click Print",
|
||||||
export function ProductionSideBar({user, moduleID}: {user: User | null; moduleID: string}) {
|
url: "/ocp",
|
||||||
|
icon: Printer,
|
||||||
|
role: ["viewer"],
|
||||||
|
module: "ocp",
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Rfid Readers",
|
||||||
|
url: "/rfid",
|
||||||
|
icon: Tag,
|
||||||
|
role: ["viewer"],
|
||||||
|
module: "production",
|
||||||
|
active:
|
||||||
|
url === "usday1vms006" || url === "localhost" ? true : false,
|
||||||
|
},
|
||||||
|
];
|
||||||
return (
|
return (
|
||||||
<SidebarGroup>
|
<SidebarGroup>
|
||||||
<SidebarGroupLabel>Production</SidebarGroupLabel>
|
<SidebarGroupLabel>Production</SidebarGroupLabel>
|
||||||
@@ -30,14 +45,15 @@ export function ProductionSideBar({user, moduleID}: {user: User | null; moduleID
|
|||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<SidebarMenuItem key={item.title}>
|
<SidebarMenuItem key={item.title}>
|
||||||
<>
|
<>
|
||||||
{hasPageAccess(user, item.role, moduleID) && item.active && (
|
{hasPageAccess(user, item.role, moduleID) &&
|
||||||
<SidebarMenuButton asChild>
|
item.active && (
|
||||||
<a href={item.url}>
|
<SidebarMenuButton asChild>
|
||||||
<item.icon />
|
<a href={item.url}>
|
||||||
<span>{item.title}</span>
|
<item.icon />
|
||||||
</a>
|
<span>{item.title}</span>
|
||||||
</SidebarMenuButton>
|
</a>
|
||||||
)}
|
</SidebarMenuButton>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import Barcode from "react-barcode";
|
|||||||
import { BarcodePDFExport } from "./BarcodeExport";
|
import { BarcodePDFExport } from "./BarcodeExport";
|
||||||
import { BulkBarcodePDFExport } from "./BulkExport";
|
import { BulkBarcodePDFExport } from "./BulkExport";
|
||||||
|
|
||||||
const commoncmd = [{ name: "Relocate", commandId: 33 }];
|
const commoncmd = [
|
||||||
|
{ name: "Relocate", commandId: 33 },
|
||||||
|
//-{ name: "Stock in", commandId: 22 },
|
||||||
|
];
|
||||||
export default function CommonCommands() {
|
export default function CommonCommands() {
|
||||||
const [checked, setChecked] = useState([]);
|
const [checked, setChecked] = useState([]);
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export default function DmPage() {
|
|||||||
<ul className="list-disc mr-2">
|
<ul className="list-disc mr-2">
|
||||||
<li>
|
<li>
|
||||||
Download the standard template if you have not yet done
|
Download the standard template if you have not yet done
|
||||||
so, top right click standard, then template.
|
so, Above click Standard Order Template.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Add in the orders like you see in the example below.
|
Add in the orders like you see in the example below.
|
||||||
@@ -37,8 +37,8 @@ export default function DmPage() {
|
|||||||
customerReleaseNumber. Quatity and dates can change.
|
customerReleaseNumber. Quatity and dates can change.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Once you have all the orders enters click the upload
|
Once you have all the orders entered, click Standard
|
||||||
button on the top right
|
Order Import
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { CardContent, CardHeader } from "@/components/ui/card";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { useForm } from "@tanstack/react-form";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export default function Relocate() {
|
||||||
|
const [bookingIn, setBookingIn] = useState(false);
|
||||||
|
const form = useForm({
|
||||||
|
defaultValues: { runningNr: " ", lane: "" },
|
||||||
|
onSubmit: async ({ value }) => {
|
||||||
|
// Do something with form data
|
||||||
|
setBookingIn(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/api/ocp/bookin", {
|
||||||
|
runningNr: parseInt(value.runningNr),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
form.reset();
|
||||||
|
setBookingIn(false);
|
||||||
|
} else {
|
||||||
|
console.log(res.data.data.errors);
|
||||||
|
toast.error(res.data.data.errors[0]?.message);
|
||||||
|
form.reset();
|
||||||
|
setBookingIn(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error(
|
||||||
|
"There was an error booking in pallet please validate you entered the correct info and try again."
|
||||||
|
);
|
||||||
|
setBookingIn(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<LstCard>
|
||||||
|
<CardHeader>
|
||||||
|
<p>Relocate a pallet to another lane</p>
|
||||||
|
</CardHeader>
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent>
|
||||||
|
<form.Field
|
||||||
|
name="runningNr"
|
||||||
|
validators={{
|
||||||
|
// We can choose between form-wide and field-specific validators
|
||||||
|
onChange: ({ value }) =>
|
||||||
|
value.length > 2
|
||||||
|
? undefined
|
||||||
|
: "Please enter a valid running number",
|
||||||
|
}}
|
||||||
|
children={(field) => {
|
||||||
|
return (
|
||||||
|
<div className="">
|
||||||
|
<Label htmlFor="runningNr" className="mb-2">
|
||||||
|
Runnning Number
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
name={field.name}
|
||||||
|
value={field.state.value}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
type="number"
|
||||||
|
onChange={(e) =>
|
||||||
|
field.handleChange(e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{field.state.meta.errors.length ? (
|
||||||
|
<em>
|
||||||
|
{field.state.meta.errors.join(",")}
|
||||||
|
</em>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<form.Field
|
||||||
|
name="lane"
|
||||||
|
validators={{
|
||||||
|
// We can choose between form-wide and field-specific validators
|
||||||
|
onChange: ({ value }) =>
|
||||||
|
value.length > 2
|
||||||
|
? undefined
|
||||||
|
: "Please enter a valid running number",
|
||||||
|
}}
|
||||||
|
children={(field) => {
|
||||||
|
return (
|
||||||
|
<div className="">
|
||||||
|
<Label htmlFor="runningNr" className="mb-2">
|
||||||
|
Enter lane
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
name={field.name}
|
||||||
|
value={field.state.value}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
//type="number"
|
||||||
|
onChange={(e) =>
|
||||||
|
field.handleChange(e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{field.state.meta.errors.length ? (
|
||||||
|
<em>
|
||||||
|
{field.state.meta.errors.join(",")}
|
||||||
|
</em>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="flex mt-2 justify-end">
|
||||||
|
<Button
|
||||||
|
onClick={form.handleSubmit}
|
||||||
|
disabled={bookingIn}
|
||||||
|
>
|
||||||
|
Relocate
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</form>
|
||||||
|
</LstCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import Bookin from "./commands/Bookin";
|
import Bookin from "./commands/Bookin";
|
||||||
|
import Relocate from "./commands/Relocate";
|
||||||
import RemoveAsNonReusable from "./commands/RemoveAsNonReusable";
|
import RemoveAsNonReusable from "./commands/RemoveAsNonReusable";
|
||||||
|
|
||||||
export default function HelperPage() {
|
export default function HelperPage() {
|
||||||
|
const url: string = window.location.host.split(":")[0];
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap m-2 justify-center">
|
<div className="flex flex-wrap m-2 justify-center">
|
||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
@@ -11,6 +13,7 @@ export default function HelperPage() {
|
|||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
<RemoveAsNonReusable />
|
<RemoveAsNonReusable />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="m-1">{url === "localhost" && <Relocate />}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
import {Button} from "@/components/ui/button";
|
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 {useState} from "react";
|
|
||||||
|
|
||||||
import {useForm} from "react-hook-form";
|
import axios from "axios";
|
||||||
import {toast} from "sonner";
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
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} = useSessionStore();
|
|
||||||
|
|
||||||
const handleConsume = async (data: any) => {
|
const handleConsume = async (data: any) => {
|
||||||
setSubmitting(true);
|
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}`},
|
||||||
});
|
// });
|
||||||
|
const result = await axios.post(`/api/logistics/consume`, data);
|
||||||
if (result.data.success) {
|
if (result.data.success) {
|
||||||
toast.success(result.data.message);
|
toast.success(result.data.message);
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
@@ -33,12 +37,14 @@ export default function ConsumeMaterial() {
|
|||||||
toast.error(result.data.message);
|
toast.error(result.data.message);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
//console.log(error);
|
console.log(error);
|
||||||
setSubmitting(false);
|
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 {
|
||||||
toast.error("Unexpected error if this continues please constact an admin.");
|
toast.error(
|
||||||
|
"Unexpected error if this continues please constact an admin."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -53,7 +59,9 @@ export default function ConsumeMaterial() {
|
|||||||
<LstCard>
|
<LstCard>
|
||||||
<form onSubmit={handleSubmit1(handleConsume)}>
|
<form onSubmit={handleSubmit1(handleConsume)}>
|
||||||
<div className="m-2">
|
<div className="m-2">
|
||||||
<Label htmlFor="runningNr">Enter unit running number</Label>
|
<Label htmlFor="runningNr">
|
||||||
|
Enter unit running number
|
||||||
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
//defaultValue="634"
|
//defaultValue="634"
|
||||||
@@ -62,7 +70,9 @@ export default function ConsumeMaterial() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="m-2">
|
<div className="m-2">
|
||||||
<Label htmlFor="lotNum">Enter lot number</Label>
|
<Label htmlFor="lotNum">
|
||||||
|
Enter lot number
|
||||||
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
//defaultValue="634"
|
//defaultValue="634"
|
||||||
@@ -71,7 +81,12 @@ export default function ConsumeMaterial() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button className="m-2" color="primary" type="submit" disabled={submitting}>
|
<Button
|
||||||
|
className="m-2"
|
||||||
|
color="primary"
|
||||||
|
type="submit"
|
||||||
|
disabled={submitting}
|
||||||
|
>
|
||||||
Consume materal
|
Consume materal
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
@@ -81,12 +96,19 @@ export default function ConsumeMaterial() {
|
|||||||
<LstCard>
|
<LstCard>
|
||||||
<div className="w-96 p-1">
|
<div className="w-96 p-1">
|
||||||
<ol>
|
<ol>
|
||||||
<li>1. Enter the running number of the material you would like to consume</li>
|
<li>
|
||||||
<li>2. Enter the lot number you will be consuming to</li>
|
1. Enter the running number of the
|
||||||
|
material you would like to consume
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2. Enter the lot number you will be
|
||||||
|
consuming to
|
||||||
|
</li>
|
||||||
<li>3. Press consume material</li>
|
<li>3. Press consume material</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p className="text-pretty w-96">
|
<p className="text-pretty w-96">
|
||||||
*This process is only for barcoded material, if it is set to auto consume you will
|
*This process is only for barcoded material,
|
||||||
|
if it is set to auto consume you will
|
||||||
encounter and error.
|
encounter and error.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { CardHeader } from "@/components/ui/card";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { useSessionStore } from "@/lib/store/sessionStore";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export default function PreformReturn() {
|
||||||
|
const {
|
||||||
|
register: register1,
|
||||||
|
handleSubmit: handleSubmit1,
|
||||||
|
reset,
|
||||||
|
} = useForm();
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
const { token } = useSessionStore();
|
||||||
|
|
||||||
|
const handleConsume = async (data: any) => {
|
||||||
|
setSubmitting(true);
|
||||||
|
try {
|
||||||
|
const result = await axios.post(`/api/logistics/consume`, data, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
if (result.data.success) {
|
||||||
|
toast.success(result.data.message);
|
||||||
|
setSubmitting(false);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
if (!result.data.success) {
|
||||||
|
//console.log(result.data);
|
||||||
|
setSubmitting(false);
|
||||||
|
|
||||||
|
toast.error(result.data.message);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
//console.log(error);
|
||||||
|
setSubmitting(false);
|
||||||
|
if (error.status === 401) {
|
||||||
|
toast.error("Unauthorized to do this task.");
|
||||||
|
} else {
|
||||||
|
toast.error(
|
||||||
|
"Unexpected error if this continues please constact an admin."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="m-2">
|
||||||
|
<LstCard>
|
||||||
|
<CardHeader>
|
||||||
|
<p className="text-center text-lg">Preform Return.</p>
|
||||||
|
</CardHeader>
|
||||||
|
<div className="flex m-1">
|
||||||
|
<div className="w-96 m-1">
|
||||||
|
<LstCard>
|
||||||
|
<form onSubmit={handleSubmit1(handleConsume)}>
|
||||||
|
<div className="m-2">
|
||||||
|
<Label htmlFor="runningNr">
|
||||||
|
Enter unit running number
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className="mt-2"
|
||||||
|
//defaultValue="634"
|
||||||
|
type="number"
|
||||||
|
{...register1("runningNr")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="m-2">
|
||||||
|
<Label htmlFor="lotNum">
|
||||||
|
Enter the new wight of the gaylord of
|
||||||
|
preforms
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className="mt-2"
|
||||||
|
//defaultValue="634"
|
||||||
|
type="number"
|
||||||
|
{...register1("lotNum")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="m-2">
|
||||||
|
<Label htmlFor="lotNum">
|
||||||
|
Select the printer you would like to
|
||||||
|
print to
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className="mt-2"
|
||||||
|
//defaultValue="634"
|
||||||
|
type="number"
|
||||||
|
{...register1("lotNum")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="m-2">
|
||||||
|
<Label htmlFor="lotNum">
|
||||||
|
Select the staging location to be
|
||||||
|
returned to.
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className="mt-2"
|
||||||
|
//defaultValue="634"
|
||||||
|
type="number"
|
||||||
|
{...register1("lotNum")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="m-2">
|
||||||
|
<Label htmlFor="lotNum">
|
||||||
|
Select type of material coming back.
|
||||||
|
</Label>
|
||||||
|
<Input
|
||||||
|
className="mt-2"
|
||||||
|
//defaultValue="634"
|
||||||
|
type="number"
|
||||||
|
{...register1("lotNum")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
className="m-2"
|
||||||
|
color="primary"
|
||||||
|
type="submit"
|
||||||
|
disabled={submitting}
|
||||||
|
>
|
||||||
|
Preform return
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
<div className="m-1 p-1">
|
||||||
|
<LstCard>
|
||||||
|
<div className="w-96 p-1">
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
1. Enter the running number of the
|
||||||
|
preform cage you would like to return
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2. Enter the new weight of the gaylord
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
3. Select the printer you would like to
|
||||||
|
print to
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<p className="text-pretty w-96">
|
||||||
|
*As soon as you press preform return it will
|
||||||
|
print a new label and return to the staging
|
||||||
|
location.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,478 @@
|
|||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { CardContent, CardHeader } from "@/components/ui/card";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import { useAppForm } from "@/utils/formStuff";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { Info } from "lucide-react";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
|
import { useSettingStore } from "@/lib/store/useSettings";
|
||||||
|
|
||||||
|
export default function TransferToNextLot() {
|
||||||
|
const [gaylordFilled, setGaylordFilled] = useState([0]);
|
||||||
|
const [actualAmount, setActualAmount] = useState(0);
|
||||||
|
const [tab, setTab] = useState("esitmate");
|
||||||
|
const [typeSwitch, setTypeSwitch] = useState(false);
|
||||||
|
const { settings } = useSettingStore();
|
||||||
|
|
||||||
|
const server = settings.filter((n: any) => n.name === "dbServer");
|
||||||
|
const form = useAppForm({
|
||||||
|
defaultValues: {
|
||||||
|
runningNumber: "",
|
||||||
|
lotNumber: "",
|
||||||
|
originalAmount: "",
|
||||||
|
amount: "",
|
||||||
|
},
|
||||||
|
onSubmit: async ({ value }) => {
|
||||||
|
//console.log(transferData);
|
||||||
|
//toast.success("603468: qty: 361, was transfered to lot:24897");
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/api/ocp/materiallottransfer", {
|
||||||
|
runningNumber: Number(value.runningNumber),
|
||||||
|
lotNumber: Number(value.lotNumber),
|
||||||
|
originalAmount: Number(value.originalAmount),
|
||||||
|
level: Number(
|
||||||
|
gaylordFilled.length === 1
|
||||||
|
? 0.25
|
||||||
|
: gaylordFilled.length === 2
|
||||||
|
? 0.5
|
||||||
|
: gaylordFilled.length === 3
|
||||||
|
? 0.75
|
||||||
|
: gaylordFilled.length === 4 && 0.95
|
||||||
|
),
|
||||||
|
amount: actualAmount,
|
||||||
|
type: typeSwitch ? "eom" : "lot",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(`${res.data.message}`);
|
||||||
|
form.reset();
|
||||||
|
setGaylordFilled([0]);
|
||||||
|
setActualAmount(0);
|
||||||
|
}
|
||||||
|
//console.log(res.data);
|
||||||
|
|
||||||
|
if (!res.data.success) {
|
||||||
|
toast.error(res.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error) {
|
||||||
|
console.log(error);
|
||||||
|
//toast.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<LstCard>
|
||||||
|
<CardHeader>
|
||||||
|
<p className="text-center text-lg">
|
||||||
|
Material Transfer to Next lot
|
||||||
|
</p>
|
||||||
|
</CardHeader>
|
||||||
|
<div>
|
||||||
|
<div className="flex flex-wrap m-2 gap-2">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<div>
|
||||||
|
<LstCard className="">
|
||||||
|
<Tabs
|
||||||
|
defaultValue={tab}
|
||||||
|
onValueChange={setTab}
|
||||||
|
>
|
||||||
|
<TabsList>
|
||||||
|
<TabsTrigger value="esitmate">
|
||||||
|
Estimate Amount
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="actual">
|
||||||
|
Actual Amount
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
<TabsContent value="esitmate">
|
||||||
|
<div className="grid columns-1">
|
||||||
|
<button
|
||||||
|
className={`box-border h-16 w-96 border-3 ${
|
||||||
|
gaylordFilled.includes(
|
||||||
|
4
|
||||||
|
)
|
||||||
|
? " bg-green-500"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
onClick={() =>
|
||||||
|
setGaylordFilled([
|
||||||
|
1, 2, 3, 4,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p className="text-center">
|
||||||
|
Almost full - 95%
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`box-border h-16 w-96 border-3 ${
|
||||||
|
gaylordFilled.includes(
|
||||||
|
3
|
||||||
|
)
|
||||||
|
? " bg-green-500"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
onClick={() =>
|
||||||
|
setGaylordFilled([
|
||||||
|
1, 2, 3,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p className="text-center">
|
||||||
|
About full - 75%
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`box-border h-16 w-96 border-3 ${
|
||||||
|
gaylordFilled.includes(
|
||||||
|
2
|
||||||
|
)
|
||||||
|
? " bg-green-500"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
onClick={() =>
|
||||||
|
setGaylordFilled([1, 2])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p className="text-center">
|
||||||
|
Half full - 50%
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`box-border h-16 w-96 border-3 ${
|
||||||
|
gaylordFilled.includes(
|
||||||
|
1
|
||||||
|
)
|
||||||
|
? " bg-green-500"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
onClick={() =>
|
||||||
|
setGaylordFilled(() => [
|
||||||
|
1,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<p className="text-center">
|
||||||
|
Almost empty - 25%
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end pr-1">
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
setGaylordFilled([0])
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Reset Gaylord
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
<TabsContent
|
||||||
|
value="actual"
|
||||||
|
className="w-96"
|
||||||
|
>
|
||||||
|
<CardHeader>
|
||||||
|
<p>
|
||||||
|
Enter the total amount of
|
||||||
|
the cage/gaylord
|
||||||
|
</p>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
//placeholder="35"
|
||||||
|
onChange={(e) =>
|
||||||
|
setActualAmount(
|
||||||
|
Number(
|
||||||
|
e.target.value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="w-96">
|
||||||
|
<LstCard>
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
form.handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="mt-3 p-2">
|
||||||
|
<form.AppField
|
||||||
|
name="runningNumber"
|
||||||
|
children={(field) => (
|
||||||
|
<field.InputField
|
||||||
|
label="Running Number"
|
||||||
|
inputType="number"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3 p-2">
|
||||||
|
<form.AppField
|
||||||
|
name="lotNumber"
|
||||||
|
children={(field) => (
|
||||||
|
<field.InputField
|
||||||
|
label="Lot Number"
|
||||||
|
inputType="number"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{tab !== "actual" && (
|
||||||
|
<div className="mt-3 p-2">
|
||||||
|
<form.AppField
|
||||||
|
name="originalAmount"
|
||||||
|
children={(
|
||||||
|
field
|
||||||
|
) => (
|
||||||
|
<field.InputField
|
||||||
|
label="Orignal Quantity"
|
||||||
|
inputType="number"
|
||||||
|
required={
|
||||||
|
true
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between p-2">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Switch
|
||||||
|
checked={typeSwitch}
|
||||||
|
onCheckedChange={
|
||||||
|
setTypeSwitch
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{typeSwitch ? (
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<span>
|
||||||
|
"EOM
|
||||||
|
Transfer"
|
||||||
|
</span>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<Info className="h-[16px] w-[16px]" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>
|
||||||
|
Click
|
||||||
|
the
|
||||||
|
toggle
|
||||||
|
if
|
||||||
|
you
|
||||||
|
will
|
||||||
|
be
|
||||||
|
transfering
|
||||||
|
at
|
||||||
|
EOM,
|
||||||
|
NOTE:
|
||||||
|
This
|
||||||
|
will
|
||||||
|
trigger
|
||||||
|
the
|
||||||
|
delayed
|
||||||
|
transfer.
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<span>
|
||||||
|
"Lot
|
||||||
|
Transfer"
|
||||||
|
</span>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<Info className="h-[16px] w-[16px]" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>
|
||||||
|
Click
|
||||||
|
the
|
||||||
|
toggle
|
||||||
|
if
|
||||||
|
you
|
||||||
|
will
|
||||||
|
be
|
||||||
|
transfering
|
||||||
|
at
|
||||||
|
EOM,
|
||||||
|
NOTE:
|
||||||
|
This
|
||||||
|
will
|
||||||
|
trigger
|
||||||
|
the
|
||||||
|
delayed
|
||||||
|
transfer.
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form.AppForm>
|
||||||
|
<form.SubmitButton>
|
||||||
|
Transfer To Lot
|
||||||
|
</form.SubmitButton>
|
||||||
|
</form.AppForm>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<LstCard className="p-2">
|
||||||
|
<CardHeader>
|
||||||
|
<p className="text-center text-lg">
|
||||||
|
Moving material to the next lot.
|
||||||
|
</p>
|
||||||
|
</CardHeader>
|
||||||
|
{tab !== "actual" ? (
|
||||||
|
<div>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
1. Grab the gaylord running
|
||||||
|
number from the gaylord at the
|
||||||
|
line/next to the tschritter
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2. Grab the next lot number you
|
||||||
|
are going to be running (or the
|
||||||
|
one that state no Main material
|
||||||
|
prepared)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
3. Enter the total gaylord
|
||||||
|
weight (this is how much the
|
||||||
|
gaylord weighed when it came in
|
||||||
|
from the supplier.)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
4. *Click the level of the
|
||||||
|
gaylord (this is just an
|
||||||
|
estimate to move to the next
|
||||||
|
lot.)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
5. type in running number on the
|
||||||
|
gaylord.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
6. Type in the new lot number.
|
||||||
|
</li>
|
||||||
|
<li>7. Press "Transfer To Lot"</li>
|
||||||
|
</ol>
|
||||||
|
<br></br>
|
||||||
|
<p>
|
||||||
|
* to reduce the time needed to get
|
||||||
|
the lot going we will use an
|
||||||
|
estimate of how full the gaylord is.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
NOTE: This is not the return
|
||||||
|
process, this process will just get
|
||||||
|
the gaylord to the next lot.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
{settings.length > 0 && (
|
||||||
|
<p>
|
||||||
|
For more in depth instructions
|
||||||
|
please{" "}
|
||||||
|
<a
|
||||||
|
href={`https://${server[0].value}.alpla.net/lst/d/docs/ocp/ocp#tranfer-partial-estimated-quantity-to-the-next-lot`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<em>CLICK HERE</em>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
1. Grab the gaylord running
|
||||||
|
number from the gaylord at the
|
||||||
|
line/next to the tschritter
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2. Grab the next lot number you
|
||||||
|
are going to be running (or the
|
||||||
|
one that state no Main material
|
||||||
|
prepared)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
3. Take the gaylord to the scale
|
||||||
|
and weight it
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
4. Enter the weight of the
|
||||||
|
gaylord minus the tar weight.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
5. type in running number on the
|
||||||
|
gaylord.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
6. Type in the new lot number.
|
||||||
|
</li>
|
||||||
|
<li>7. Press "Transfer To Lot"</li>
|
||||||
|
</ol>
|
||||||
|
<br></br>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
NOTE: This is not the return
|
||||||
|
process, this process will just get
|
||||||
|
the gaylord to the next lot.
|
||||||
|
</p>
|
||||||
|
<br />
|
||||||
|
{settings.length > 0 && (
|
||||||
|
<p>
|
||||||
|
For more in depth instructions
|
||||||
|
please{" "}
|
||||||
|
<a
|
||||||
|
href={`https://${server[0].value}.alpla.net/lst/d/docs/ocp/ocp#tranfer-partial-estimated-quantity-to-the-next-lot`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<em>CLICK HERE</em>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LstCard>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
frontend/src/components/logistics/rfid/ManualTrigger.tsx
Normal file
31
frontend/src/components/logistics/rfid/ManualTrigger.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export default function ManualTrigger() {
|
||||||
|
const rfidReaderTrigger = async () => {
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/api/rfid/manualtrigger/wrapper1");
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!res.data.success) {
|
||||||
|
toast.error(res.data.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
//stoast.success(error.data.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button onClick={rfidReaderTrigger}>Wrapper 1 RFID</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
163
frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx
Normal file
163
frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogClose,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
|
||||||
|
import { useAppForm } from "@/utils/formStuff";
|
||||||
|
import { getMachineConnected } from "@/utils/querys/logistics/machineConnected";
|
||||||
|
import { getMachineNotConnected } from "@/utils/querys/logistics/notConnected";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export function AttachSilo(props: any) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const { data, isError, isLoading, refetch } = useQuery(
|
||||||
|
getMachineNotConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "detached",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const { refetch: attached } = useQuery(
|
||||||
|
getMachineConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "connected",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const form = useAppForm({
|
||||||
|
defaultValues: {
|
||||||
|
laneId: props.silo.LocationID,
|
||||||
|
productionLotId: "",
|
||||||
|
machineId: "",
|
||||||
|
},
|
||||||
|
onSubmit: async ({ value }) => {
|
||||||
|
try {
|
||||||
|
const res = await axios.post(
|
||||||
|
"/api/logistics/attachsilo",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.data.success) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
refetch();
|
||||||
|
attached();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
} else {
|
||||||
|
console.log(res.data);
|
||||||
|
toast.error(res.data.message);
|
||||||
|
refetch();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error(
|
||||||
|
"There was an error attaching the silo please try again, if persist please enter a helpdesk ticket."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isError)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>There was an error loading data</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Loading....</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// convert the array that comes over to label and value
|
||||||
|
const tranMachine = data.map((i: any) => ({
|
||||||
|
value: i.machineId.toString(),
|
||||||
|
label: i.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant="outline" onClick={() => setOpen(!open)}>
|
||||||
|
Attach Silo
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
|
||||||
|
<DialogContent className="sm:max-w-[425px]">
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
form.handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>
|
||||||
|
Attach silo for: {props.silo.Description}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Enter the new lotnumber, select the machine you
|
||||||
|
would like to attach.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm">
|
||||||
|
NOTE: If the machine you are trying to attach is not
|
||||||
|
showing in the drop down this means it is already
|
||||||
|
attached to this silo.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3">
|
||||||
|
<form.AppField
|
||||||
|
name="productionLotId"
|
||||||
|
children={(field) => (
|
||||||
|
<field.InputField
|
||||||
|
label="Lot Number"
|
||||||
|
inputType="number"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2">
|
||||||
|
<form.AppField
|
||||||
|
name="machineId"
|
||||||
|
children={(field) => (
|
||||||
|
<field.SelectField
|
||||||
|
label="Select Machine"
|
||||||
|
options={tranMachine}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DialogFooter className="mt-2">
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setOpen(!open)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<form.AppForm>
|
||||||
|
<form.SubmitButton>Attach</form.SubmitButton>
|
||||||
|
</form.AppForm>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
151
frontend/src/components/logistics/siloAdjustments/DetachSilo.tsx
Normal file
151
frontend/src/components/logistics/siloAdjustments/DetachSilo.tsx
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogClose,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
|
||||||
|
import { useAppForm } from "@/utils/formStuff";
|
||||||
|
import { getMachineConnected } from "@/utils/querys/logistics/machineConnected";
|
||||||
|
import { getMachineNotConnected } from "@/utils/querys/logistics/notConnected";
|
||||||
|
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
export function DetachSilo(props: any) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const { data, isError, isLoading, refetch } = useQuery(
|
||||||
|
getMachineConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "connected",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const { refetch: notConnected } = useQuery(
|
||||||
|
getMachineNotConnected({
|
||||||
|
siloID: props.silo.LocationID,
|
||||||
|
connectionType: "detached",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const form = useAppForm({
|
||||||
|
defaultValues: {
|
||||||
|
laneId: props.silo.LocationID,
|
||||||
|
machineId: 0,
|
||||||
|
},
|
||||||
|
onSubmit: async ({ value }) => {
|
||||||
|
try {
|
||||||
|
const res = await axios.post(
|
||||||
|
"/api/logistics/detachsilo",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
console.log(res.data.data);
|
||||||
|
toast.success(res.data.message);
|
||||||
|
|
||||||
|
refetch();
|
||||||
|
notConnected();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
} else {
|
||||||
|
console.log(res.data);
|
||||||
|
toast.error(res.data.message);
|
||||||
|
refetch();
|
||||||
|
form.reset();
|
||||||
|
setOpen(!open);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
toast.error(
|
||||||
|
"There was an error detaching the silo please try again, if persist please enter a helpdesk ticket."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isError)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>There was an error loading data</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Loading....</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// convert the array that comes over to label and value
|
||||||
|
const tranMachine = data.map((i: any) => ({
|
||||||
|
value: i.machineId.toString(),
|
||||||
|
label: i.name,
|
||||||
|
}));
|
||||||
|
return (
|
||||||
|
<Dialog open={open}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setOpen(!open)}
|
||||||
|
disabled={data.length === 0}
|
||||||
|
>
|
||||||
|
Detach Silo
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-[425px]">
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
form.handleSubmit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>
|
||||||
|
Attach silo for: {props.silo.Description}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Select the machine you would like to detach.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="grid gap-4">
|
||||||
|
<div className="grid gap-3">
|
||||||
|
<div className="mt-2">
|
||||||
|
<form.AppField
|
||||||
|
name="machineId"
|
||||||
|
children={(field) => (
|
||||||
|
<field.SelectField
|
||||||
|
label="Select Machine"
|
||||||
|
options={tranMachine}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DialogFooter>
|
||||||
|
<DialogClose asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setOpen(!open)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</DialogClose>
|
||||||
|
<form.AppForm>
|
||||||
|
<form.SubmitButton>Detach</form.SubmitButton>
|
||||||
|
</form.AppForm>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -19,13 +19,30 @@ import { CircleAlert } from "lucide-react";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import ChartData from "./ChartData";
|
import ChartData from "./ChartData";
|
||||||
|
import { AttachSilo } from "./AttachSilo";
|
||||||
|
import { DetachSilo } from "./DetachSilo";
|
||||||
|
import { useSessionStore } from "@/lib/store/sessionStore";
|
||||||
|
import { useModuleStore } from "@/lib/store/useModuleStore";
|
||||||
|
import { useGetUserRoles } from "@/lib/store/useGetRoles";
|
||||||
|
|
||||||
export default function SiloCard(data: any) {
|
export default function SiloCard(data: any) {
|
||||||
const token = localStorage.getItem("auth_token");
|
const token = localStorage.getItem("auth_token");
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const { refetch } = useQuery(getStockSilo());
|
const { refetch } = useQuery(getStockSilo());
|
||||||
|
const { user } = useSessionStore();
|
||||||
|
const { userRoles } = useGetUserRoles();
|
||||||
|
const { modules } = useModuleStore();
|
||||||
const silo = data.silo;
|
const silo = data.silo;
|
||||||
|
|
||||||
|
// roles that can do the silo adjustments
|
||||||
|
const roles = ["systemAdmin", "technician", "admin", "manager"];
|
||||||
|
|
||||||
|
const module = modules.filter((n) => n.name === "logistics");
|
||||||
|
|
||||||
|
const accessRoles = userRoles.filter(
|
||||||
|
(n) => n.module_id === module[0]?.module_id
|
||||||
|
) as any;
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
newLevel: "",
|
newLevel: "",
|
||||||
@@ -44,7 +61,7 @@ export default function SiloCard(data: any) {
|
|||||||
dataToSubmit,
|
dataToSubmit,
|
||||||
{ headers: { Authorization: `Bearer ${token}` } }
|
{ headers: { Authorization: `Bearer ${token}` } }
|
||||||
);
|
);
|
||||||
console.log(res.data);
|
//console.log(res.data);
|
||||||
|
|
||||||
if (res.data.success) {
|
if (res.data.success) {
|
||||||
toast.success(res.data.message);
|
toast.success(res.data.message);
|
||||||
@@ -68,6 +85,8 @@ export default function SiloCard(data: any) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(accessRoles);
|
||||||
return (
|
return (
|
||||||
<LstCard>
|
<LstCard>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
@@ -107,94 +126,115 @@ export default function SiloCard(data: any) {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form
|
<>
|
||||||
onSubmit={(e) => {
|
{user &&
|
||||||
e.preventDefault();
|
roles.includes(accessRoles[0]?.role) && (
|
||||||
e.stopPropagation();
|
<form
|
||||||
}}
|
onSubmit={(e) => {
|
||||||
>
|
e.preventDefault();
|
||||||
<form.Field
|
e.stopPropagation();
|
||||||
name="newLevel"
|
}}
|
||||||
validators={{
|
>
|
||||||
// We can choose between form-wide and field-specific validators
|
<form.Field
|
||||||
onChange: ({ value }) =>
|
name="newLevel"
|
||||||
value.length > 1
|
validators={{
|
||||||
? undefined
|
// We can choose between form-wide and field-specific validators
|
||||||
: "You must enter a value greate than 1",
|
onChange: ({ value }) =>
|
||||||
}}
|
value.length > 1
|
||||||
children={(field) => {
|
? undefined
|
||||||
return (
|
: "You must enter a value greate than 1",
|
||||||
<div className="m-2 min-w-48 max-w-96 p-2">
|
}}
|
||||||
<div className="flex flex-row">
|
children={(field) => {
|
||||||
<Label htmlFor="newLevel">
|
return (
|
||||||
New level
|
<div className="m-2 min-w-48 max-w-96 p-2">
|
||||||
</Label>
|
<div className="flex flex-row">
|
||||||
<div>
|
<Label htmlFor="newLevel">
|
||||||
<Disclaimer />
|
New level
|
||||||
</div>
|
</Label>
|
||||||
</div>
|
<div>
|
||||||
<div className="flex flex-row">
|
<Disclaimer />
|
||||||
<Input
|
</div>
|
||||||
name={field.name}
|
</div>
|
||||||
value={
|
<div className="flex flex-row">
|
||||||
field.state.value
|
<Input
|
||||||
}
|
name={
|
||||||
onBlur={
|
field.name
|
||||||
field.handleBlur
|
}
|
||||||
}
|
value={
|
||||||
type="decimal"
|
field
|
||||||
onChange={(e) =>
|
.state
|
||||||
field.handleChange(
|
.value
|
||||||
e.target.value
|
}
|
||||||
)
|
onBlur={
|
||||||
}
|
field.handleBlur
|
||||||
/>
|
}
|
||||||
<Button
|
type="decimal"
|
||||||
className="ml-1"
|
onChange={(
|
||||||
type="submit"
|
e
|
||||||
onClick={
|
) =>
|
||||||
form.handleSubmit
|
field.handleChange(
|
||||||
}
|
e
|
||||||
disabled={submitting}
|
.target
|
||||||
>
|
.value
|
||||||
{submitting ? (
|
)
|
||||||
<span className="w-24">
|
}
|
||||||
Submitting...
|
/>
|
||||||
</span>
|
<Button
|
||||||
) : (
|
className="ml-1"
|
||||||
<span className="w-24">
|
variant="outline"
|
||||||
Submit
|
type="submit"
|
||||||
</span>
|
onClick={
|
||||||
)}
|
form.handleSubmit
|
||||||
</Button>
|
}
|
||||||
</div>
|
disabled={
|
||||||
|
submitting
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{submitting ? (
|
||||||
|
<span className="w-24">
|
||||||
|
Submitting...
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="w-24">
|
||||||
|
Submit
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{field.state.meta.errors
|
{field.state.meta
|
||||||
.length ? (
|
.errors
|
||||||
<em>
|
.length ? (
|
||||||
{field.state.meta.errors.join(
|
<em>
|
||||||
","
|
{field.state.meta.errors.join(
|
||||||
)}
|
","
|
||||||
</em>
|
)}
|
||||||
) : null}
|
</em>
|
||||||
</div>
|
) : null}
|
||||||
);
|
</div>
|
||||||
}}
|
);
|
||||||
/>
|
}}
|
||||||
</form>
|
/>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</LstCard>
|
</LstCard>
|
||||||
<div className="grow max-w-[600px]">
|
<div className="grow max-w-[600px]">
|
||||||
<ChartData laneId={silo.LocationID} />
|
<ChartData laneId={silo.LocationID} />
|
||||||
|
|
||||||
<div className="flex justify-end m-1">
|
<div className="flex justify-end m-1 gap-3">
|
||||||
<Link
|
<AttachSilo silo={silo} />
|
||||||
to={"/siloAdjustments/$hist"}
|
<DetachSilo silo={silo} />
|
||||||
params={{ hist: silo.LocationID }}
|
<Button variant="outline">
|
||||||
>
|
<Link
|
||||||
Historical Data
|
to={"/siloAdjustments/$hist"}
|
||||||
</Link>
|
params={{ hist: silo.LocationID }}
|
||||||
|
>
|
||||||
|
Historical Data
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
//import { toast } from "sonner";
|
//import { toast } from "sonner";
|
||||||
|
|
||||||
export default function INVCheckCard(props: any) {
|
export default function INVCheckCard(props: any) {
|
||||||
//{ style = {} }
|
const { age, rowType } = props.data;
|
||||||
const { data, isError, isLoading } = useQuery(getinventoryCheck(props));
|
|
||||||
|
//console.log(props.data);
|
||||||
|
const { data, isError, isLoading } = useQuery(
|
||||||
|
getinventoryCheck({ age: age })
|
||||||
|
);
|
||||||
|
|
||||||
if (isLoading) return <div>Loading inventory data...</div>;
|
if (isLoading) return <div>Loading inventory data...</div>;
|
||||||
if (isError) {
|
if (isError) {
|
||||||
@@ -23,11 +27,11 @@ export default function INVCheckCard(props: any) {
|
|||||||
let laneData: any = data;
|
let laneData: any = data;
|
||||||
if (props.type != "") {
|
if (props.type != "") {
|
||||||
laneData = laneData.filter(
|
laneData = laneData.filter(
|
||||||
(l: any) => l.rowType === props.type.toUpperCase()
|
(l: any) => l.rowType === rowType.toUpperCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
// age
|
// age
|
||||||
laneData = laneData.filter((l: any) => l.DaysSinceLast >= props.age);
|
laneData = laneData.filter((l: any) => l.DaysSinceLast >= age);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const handleCloseCard = () => {
|
// const handleCloseCard = () => {
|
||||||
@@ -36,5 +40,5 @@ export default function INVCheckCard(props: any) {
|
|||||||
// toast.success("card removed");
|
// toast.success("card removed");
|
||||||
// };
|
// };
|
||||||
|
|
||||||
return <InvTable columns={invColumns} data={laneData} info={props} />;
|
return <InvTable columns={invColumns} data={laneData} info={props.data} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ import { getOcmeInfo } from "@/utils/querys/production/getOcmeInfo";
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Trash } from "lucide-react";
|
import { Trash } from "lucide-react";
|
||||||
import ManuallyEnterRn from "./ManuallyEnterRn";
|
import ManualTrigger from "../logistics/rfid/ManualTrigger";
|
||||||
import { Separator } from "../ui/separator";
|
|
||||||
|
|
||||||
const currentPallets = [
|
const currentPallets = [
|
||||||
{ key: "line", label: "Line" },
|
{ key: "line", label: "Line" },
|
||||||
@@ -160,11 +159,12 @@ export default function WrapperManualTrigger() {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<hr />
|
<hr />
|
||||||
<p className="text-center mb-3">Manual Trigger</p>
|
{/* <p className="text-center mb-3">Manual Trigger</p>
|
||||||
<ManuallyEnterRn />
|
<ManuallyEnterRn />
|
||||||
<Separator className="m-1" />
|
<Separator className="m-1" /> */}
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between m-2">
|
||||||
<Button onClick={cameraTrigger}>Camera</Button>
|
<Button onClick={cameraTrigger}>Camera</Button>
|
||||||
|
<ManualTrigger />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</LstCard>
|
</LstCard>
|
||||||
|
|||||||
27
frontend/src/components/production/ocp/LabelRatio.tsx
Normal file
27
frontend/src/components/production/ocp/LabelRatio.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { getlabelRatio } from "@/utils/querys/production/labelRatio";
|
||||||
|
import { labelRatioColumns } from "@/utils/tableData/production/labelRatio/labelRatioColumns";
|
||||||
|
import { LabelRatioTable } from "@/utils/tableData/production/labelRatio/labelRatioData";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
export default function LabelRatio() {
|
||||||
|
const { data, isError, isLoading } = useQuery(getlabelRatio());
|
||||||
|
|
||||||
|
const ratioData = data ? data : [];
|
||||||
|
if (isError) {
|
||||||
|
return <div>Error</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <div>Loading</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="m-2">
|
||||||
|
<LabelRatioTable
|
||||||
|
columns={labelRatioColumns}
|
||||||
|
data={ratioData}
|
||||||
|
//style={style}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -242,7 +242,9 @@ export default function Lots() {
|
|||||||
{lot.overPrinting}
|
{lot.overPrinting}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
{user &&
|
{user &&
|
||||||
roles.includes(accessRoles[0].role) && (
|
roles.includes(
|
||||||
|
accessRoles[0]?.role
|
||||||
|
) && (
|
||||||
<>
|
<>
|
||||||
{server === "usday1vms006" ||
|
{server === "usday1vms006" ||
|
||||||
server === "localhost" ? (
|
server === "localhost" ? (
|
||||||
|
|||||||
@@ -243,7 +243,8 @@ export default function ManualPrintForm() {
|
|||||||
<Textarea
|
<Textarea
|
||||||
//label="Comments"
|
//label="Comments"
|
||||||
placeholder="add more info as needed."
|
placeholder="add more info as needed."
|
||||||
{...register("additionalComments")}
|
{...(register("additionalComments"),
|
||||||
|
{ required: true, minLength: 10 })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ import {
|
|||||||
ResizablePanel,
|
ResizablePanel,
|
||||||
ResizablePanelGroup,
|
ResizablePanelGroup,
|
||||||
} from "@/components/ui/resizable-panels";
|
} from "@/components/ui/resizable-panels";
|
||||||
|
import LabelRatio from "./LabelRatio";
|
||||||
|
|
||||||
export default function OCPPage() {
|
export default function OCPPage() {
|
||||||
const { settings } = useSettingStore();
|
const { settings } = useSettingStore();
|
||||||
|
|
||||||
|
if (settings.length === 0) return;
|
||||||
let server = settings.filter((n) => n.name === "server");
|
let server = settings.filter((n) => n.name === "server");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -63,18 +65,32 @@ export default function OCPPage() {
|
|||||||
</ResizablePanelGroup>
|
</ResizablePanelGroup>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
<ResizableHandle />
|
<ResizableHandle />
|
||||||
<ResizablePanel defaultSize={25}>
|
<ResizablePanel className="min-h-[200px] min-w-[200px] max-w-[450px]">
|
||||||
<ResizablePanelGroup
|
<ResizablePanelGroup
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
autoSaveId="ocpPage"
|
autoSaveId="ocpPage_vert"
|
||||||
>
|
>
|
||||||
{server[0].value === "usday1vms006" && (
|
{server[0].value === "usday1vms006" && (
|
||||||
<ResizablePanel className="max-h-[300px]">
|
<ResizablePanel
|
||||||
|
style={{
|
||||||
|
overflow: "auto",
|
||||||
|
scrollbarWidth: "none",
|
||||||
|
}}
|
||||||
|
defaultSize={50}
|
||||||
|
className="min-h-[200px]"
|
||||||
|
>
|
||||||
<WrapperManualTrigger />
|
<WrapperManualTrigger />
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
)}
|
)}
|
||||||
{server[0].value === "localhost" && (
|
{server[0]?.value === "localhost" && (
|
||||||
<ResizablePanel className="max-h-[300px]">
|
<ResizablePanel
|
||||||
|
className="min-h-[200px]"
|
||||||
|
style={{
|
||||||
|
overflow: "auto",
|
||||||
|
scrollbarWidth: "none",
|
||||||
|
}}
|
||||||
|
defaultSize={50}
|
||||||
|
>
|
||||||
<WrapperManualTrigger />
|
<WrapperManualTrigger />
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
)}
|
)}
|
||||||
@@ -82,6 +98,7 @@ export default function OCPPage() {
|
|||||||
<ResizableHandle />
|
<ResizableHandle />
|
||||||
<ResizablePanel>
|
<ResizablePanel>
|
||||||
<PrinterStatus />
|
<PrinterStatus />
|
||||||
|
<LabelRatio />
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
</ResizablePanelGroup>
|
</ResizablePanelGroup>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export const SessionProvider = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchModules();
|
fetchModules();
|
||||||
fetchSettings();
|
fetchSettings();
|
||||||
|
console.log("settings grab ran");
|
||||||
fetchUserRoles();
|
fetchUserRoles();
|
||||||
fetchSubModules();
|
fetchSubModules();
|
||||||
}, []);
|
}, []);
|
||||||
|
|||||||
28
frontend/src/components/rfid/RfidPage.tsx
Normal file
28
frontend/src/components/rfid/RfidPage.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { getReaders } from "@/utils/querys/rfid/getReaders";
|
||||||
|
import { readerColumns } from "@/utils/tableData/rfid/readers/readerColumns";
|
||||||
|
import { ReaderTable } from "@/utils/tableData/rfid/readers/readerData";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
export default function RfidPage() {
|
||||||
|
const { data, isError, isLoading } = useQuery(getReaders());
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
return <div>Error</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <div>Loading</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="m-2">
|
||||||
|
<ReaderTable
|
||||||
|
columns={readerColumns}
|
||||||
|
data={data.data.sort((a: any, b: any) =>
|
||||||
|
a.reader.localeCompare(b.reader)
|
||||||
|
)}
|
||||||
|
//style={style}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,73 +1,208 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { ChevronLeft, ChevronRight } from "lucide-react"
|
import {
|
||||||
import { DayPicker } from "react-day-picker"
|
ChevronDownIcon,
|
||||||
|
ChevronLeftIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
} from "lucide-react"
|
||||||
|
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { buttonVariants } from "@/components/ui/button"
|
import { Button, buttonVariants } from "@/components/ui/button"
|
||||||
|
|
||||||
function Calendar({
|
function Calendar({
|
||||||
className,
|
className,
|
||||||
classNames,
|
classNames,
|
||||||
showOutsideDays = true,
|
showOutsideDays = true,
|
||||||
|
captionLayout = "label",
|
||||||
|
buttonVariant = "ghost",
|
||||||
|
formatters,
|
||||||
|
components,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DayPicker>) {
|
}: React.ComponentProps<typeof DayPicker> & {
|
||||||
|
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
|
||||||
|
}) {
|
||||||
|
const defaultClassNames = getDefaultClassNames()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DayPicker
|
<DayPicker
|
||||||
showOutsideDays={showOutsideDays}
|
showOutsideDays={showOutsideDays}
|
||||||
className={cn("p-3", className)}
|
className={cn(
|
||||||
|
"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
||||||
|
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
||||||
|
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
captionLayout={captionLayout}
|
||||||
|
formatters={{
|
||||||
|
formatMonthDropdown: (date) =>
|
||||||
|
date.toLocaleString("default", { month: "short" }),
|
||||||
|
...formatters,
|
||||||
|
}}
|
||||||
classNames={{
|
classNames={{
|
||||||
months: "flex flex-col sm:flex-row gap-2",
|
root: cn("w-fit", defaultClassNames.root),
|
||||||
month: "flex flex-col gap-4",
|
months: cn(
|
||||||
caption: "flex justify-center pt-1 relative items-center w-full",
|
"flex gap-4 flex-col md:flex-row relative",
|
||||||
caption_label: "text-sm font-medium",
|
defaultClassNames.months
|
||||||
nav: "flex items-center gap-1",
|
|
||||||
nav_button: cn(
|
|
||||||
buttonVariants({ variant: "outline" }),
|
|
||||||
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
|
||||||
),
|
),
|
||||||
nav_button_previous: "absolute left-1",
|
month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
|
||||||
nav_button_next: "absolute right-1",
|
nav: cn(
|
||||||
table: "w-full border-collapse space-x-1",
|
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
|
||||||
head_row: "flex",
|
defaultClassNames.nav
|
||||||
head_cell:
|
),
|
||||||
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
button_previous: cn(
|
||||||
row: "flex w-full mt-2",
|
buttonVariants({ variant: buttonVariant }),
|
||||||
cell: cn(
|
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
|
||||||
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md",
|
defaultClassNames.button_previous
|
||||||
props.mode === "range"
|
),
|
||||||
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
|
button_next: cn(
|
||||||
: "[&:has([aria-selected])]:rounded-md"
|
buttonVariants({ variant: buttonVariant }),
|
||||||
|
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
|
||||||
|
defaultClassNames.button_next
|
||||||
|
),
|
||||||
|
month_caption: cn(
|
||||||
|
"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
|
||||||
|
defaultClassNames.month_caption
|
||||||
|
),
|
||||||
|
dropdowns: cn(
|
||||||
|
"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
|
||||||
|
defaultClassNames.dropdowns
|
||||||
|
),
|
||||||
|
dropdown_root: cn(
|
||||||
|
"relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
|
||||||
|
defaultClassNames.dropdown_root
|
||||||
|
),
|
||||||
|
dropdown: cn("absolute inset-0 opacity-0", defaultClassNames.dropdown),
|
||||||
|
caption_label: cn(
|
||||||
|
"select-none font-medium",
|
||||||
|
captionLayout === "label"
|
||||||
|
? "text-sm"
|
||||||
|
: "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5",
|
||||||
|
defaultClassNames.caption_label
|
||||||
|
),
|
||||||
|
table: "w-full border-collapse",
|
||||||
|
weekdays: cn("flex", defaultClassNames.weekdays),
|
||||||
|
weekday: cn(
|
||||||
|
"text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none",
|
||||||
|
defaultClassNames.weekday
|
||||||
|
),
|
||||||
|
week: cn("flex w-full mt-2", defaultClassNames.week),
|
||||||
|
week_number_header: cn(
|
||||||
|
"select-none w-(--cell-size)",
|
||||||
|
defaultClassNames.week_number_header
|
||||||
|
),
|
||||||
|
week_number: cn(
|
||||||
|
"text-[0.8rem] select-none text-muted-foreground",
|
||||||
|
defaultClassNames.week_number
|
||||||
),
|
),
|
||||||
day: cn(
|
day: cn(
|
||||||
buttonVariants({ variant: "ghost" }),
|
"relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none",
|
||||||
"size-8 p-0 font-normal aria-selected:opacity-100"
|
defaultClassNames.day
|
||||||
),
|
),
|
||||||
day_range_start:
|
range_start: cn(
|
||||||
"day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
|
"rounded-l-md bg-accent",
|
||||||
day_range_end:
|
defaultClassNames.range_start
|
||||||
"day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
|
),
|
||||||
day_selected:
|
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
||||||
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
|
||||||
day_today: "bg-accent text-accent-foreground",
|
today: cn(
|
||||||
day_outside:
|
"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none",
|
||||||
"day-outside text-muted-foreground aria-selected:text-muted-foreground",
|
defaultClassNames.today
|
||||||
day_disabled: "text-muted-foreground opacity-50",
|
),
|
||||||
day_range_middle:
|
outside: cn(
|
||||||
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
"text-muted-foreground aria-selected:text-muted-foreground",
|
||||||
day_hidden: "invisible",
|
defaultClassNames.outside
|
||||||
|
),
|
||||||
|
disabled: cn(
|
||||||
|
"text-muted-foreground opacity-50",
|
||||||
|
defaultClassNames.disabled
|
||||||
|
),
|
||||||
|
hidden: cn("invisible", defaultClassNames.hidden),
|
||||||
...classNames,
|
...classNames,
|
||||||
}}
|
}}
|
||||||
components={{
|
components={{
|
||||||
IconLeft: ({ className, ...props }) => (
|
Root: ({ className, rootRef, ...props }) => {
|
||||||
<ChevronLeft className={cn("size-4", className)} {...props} />
|
return (
|
||||||
),
|
<div
|
||||||
IconRight: ({ className, ...props }) => (
|
data-slot="calendar"
|
||||||
<ChevronRight className={cn("size-4", className)} {...props} />
|
ref={rootRef}
|
||||||
),
|
className={cn(className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Chevron: ({ className, orientation, ...props }) => {
|
||||||
|
if (orientation === "left") {
|
||||||
|
return (
|
||||||
|
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation === "right") {
|
||||||
|
return (
|
||||||
|
<ChevronRightIcon
|
||||||
|
className={cn("size-4", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChevronDownIcon className={cn("size-4", className)} {...props} />
|
||||||
|
)
|
||||||
|
},
|
||||||
|
DayButton: CalendarDayButton,
|
||||||
|
WeekNumber: ({ children, ...props }) => {
|
||||||
|
return (
|
||||||
|
<td {...props}>
|
||||||
|
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
...components,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Calendar }
|
function CalendarDayButton({
|
||||||
|
className,
|
||||||
|
day,
|
||||||
|
modifiers,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof DayButton>) {
|
||||||
|
const defaultClassNames = getDefaultClassNames()
|
||||||
|
|
||||||
|
const ref = React.useRef<HTMLButtonElement>(null)
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (modifiers.focused) ref.current?.focus()
|
||||||
|
}, [modifiers.focused])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
ref={ref}
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
data-day={day.date.toLocaleDateString()}
|
||||||
|
data-selected-single={
|
||||||
|
modifiers.selected &&
|
||||||
|
!modifiers.range_start &&
|
||||||
|
!modifiers.range_end &&
|
||||||
|
!modifiers.range_middle
|
||||||
|
}
|
||||||
|
data-range-start={modifiers.range_start}
|
||||||
|
data-range-end={modifiers.range_end}
|
||||||
|
data-range-middle={modifiers.range_middle}
|
||||||
|
className={cn(
|
||||||
|
"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
|
||||||
|
defaultClassNames.day,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Calendar, CalendarDayButton }
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-header"
|
data-slot="card-header"
|
||||||
className={cn("flex flex-col gap-1.5 px-6", className)}
|
className={cn(
|
||||||
|
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||||
|
className
|
||||||
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -45,6 +48,19 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-action"
|
||||||
|
className={cn(
|
||||||
|
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -59,10 +75,18 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-slot="card-footer"
|
data-slot="card-footer"
|
||||||
className={cn("flex items-center px-6", className)}
|
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardAction,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function PopoverContent({
|
|||||||
align={align}
|
align={align}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
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 z-50 w-72 rounded-md border p-4 shadow-md outline-hidden",
|
"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 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
29
frontend/src/components/ui/switch.tsx
Normal file
29
frontend/src/components/ui/switch.tsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import * as SwitchPrimitive from "@radix-ui/react-switch"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Switch({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
|
||||||
|
return (
|
||||||
|
<SwitchPrimitive.Root
|
||||||
|
data-slot="switch"
|
||||||
|
className={cn(
|
||||||
|
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SwitchPrimitive.Thumb
|
||||||
|
data-slot="switch-thumb"
|
||||||
|
className={cn(
|
||||||
|
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SwitchPrimitive.Root>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Switch }
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {create} from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
interface SettingState {
|
interface SettingState {
|
||||||
settings: any[];
|
settings: any[];
|
||||||
|
|
||||||
fetchSettings: () => Promise<void>;
|
fetchSettings: () => Promise<void>;
|
||||||
setSettings: (settings: any[]) => void;
|
setSettings: (settings: any[]) => void;
|
||||||
}
|
}
|
||||||
@@ -13,17 +12,17 @@ interface FetchModulesResponse {
|
|||||||
|
|
||||||
export const useSettingStore = create<SettingState>()((set) => ({
|
export const useSettingStore = create<SettingState>()((set) => ({
|
||||||
settings: [],
|
settings: [],
|
||||||
setSettings: (settings) => set({settings}),
|
setSettings: (settings) => set({ settings }),
|
||||||
fetchSettings: async () => {
|
fetchSettings: 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 axios.get(`/api/server/settings`, {});
|
const response = await axios.get(`/api/server/settings`, {});
|
||||||
const data: FetchModulesResponse = response.data; //await response.json();
|
const data: FetchModulesResponse = response.data; //await response.json();
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
set({settings: data.data});
|
set({ settings: data.data });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to fetch settings:", error);
|
console.error("Failed to fetch settings:", error);
|
||||||
set({settings: []});
|
set({ settings: [] });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
import {RouterProvider, createRouter} from "@tanstack/react-router";
|
import { RouterProvider, createRouter } from "@tanstack/react-router";
|
||||||
|
|
||||||
// Import the generated route tree
|
// Import the generated route tree
|
||||||
import {routeTree} from "./routeTree.gen";
|
import { routeTree } from "./routeTree.gen";
|
||||||
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
|
||||||
// Create a client
|
// Create a client
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
// Create a new router instance
|
// Create a new router instance
|
||||||
const router = createRouter({routeTree});
|
const router = createRouter({
|
||||||
|
routeTree,
|
||||||
|
//basepath: import.meta.env.BASE_URL, // This is the key part!
|
||||||
|
});
|
||||||
|
|
||||||
// Register the router instance for type safety
|
// Register the router instance for type safety
|
||||||
declare module "@tanstack/react-router" {
|
declare module "@tanstack/react-router" {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,11 @@
|
|||||||
import ConsumeMaterial from "@/components/logistics/materialHelper/consumption/ConsumeMaterial";
|
import ConsumeMaterial from "@/components/logistics/materialHelper/consumption/ConsumeMaterial";
|
||||||
import {createFileRoute} from "@tanstack/react-router";
|
import PreformReturn from "@/components/logistics/materialHelper/consumption/MaterialReturn";
|
||||||
|
import TransferToNextLot from "@/components/logistics/materialHelper/consumption/TransferToNextLot";
|
||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
export const Route = createFileRoute("/(logistics)/materialHelper/consumption/")({
|
export const Route = createFileRoute(
|
||||||
|
"/(logistics)/materialHelper/consumption/"
|
||||||
|
)({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
head: () => ({
|
head: () => ({
|
||||||
meta: [
|
meta: [
|
||||||
@@ -17,9 +21,22 @@ export const Route = createFileRoute("/(logistics)/materialHelper/consumption/")
|
|||||||
});
|
});
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
|
const url: string = window.location.host.split(":")[0];
|
||||||
|
const auth = localStorage.getItem("auth_token");
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="flex flex-wrap">
|
||||||
<ConsumeMaterial />
|
{auth ? (
|
||||||
|
<>
|
||||||
|
<ConsumeMaterial />
|
||||||
|
{url === "localhost" && <PreformReturn />}
|
||||||
|
<TransferToNextLot />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ConsumeMaterial />
|
||||||
|
<TransferToNextLot />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import MaterialHelperPage from "@/components/logistics/materialHelper/materialHelperPage";
|
import MaterialHelperPage from "@/components/logistics/materialHelper/materialHelperPage";
|
||||||
import {createFileRoute} from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
export const Route = createFileRoute("/(logistics)/materialHelper/")({
|
export const Route = createFileRoute("/(logistics)/materialHelper/")({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { useLogout } from "@/hooks/useLogout";
|
|||||||
import ExportInventoryData from "@/components/logistics/warehouse/ExportInventoryData";
|
import ExportInventoryData from "@/components/logistics/warehouse/ExportInventoryData";
|
||||||
import { AddCards } from "@/components/dashboard/AddCards";
|
import { AddCards } from "@/components/dashboard/AddCards";
|
||||||
import DMButtons from "@/components/logistics/dm/DMButtons";
|
import DMButtons from "@/components/logistics/dm/DMButtons";
|
||||||
|
import { useSettingStore } from "@/lib/store/useSettings";
|
||||||
//import { AddCards } from "@/components/dashboard/AddCards";
|
//import { AddCards } from "@/components/dashboard/AddCards";
|
||||||
|
|
||||||
// same as the layout
|
// same as the layout
|
||||||
@@ -38,6 +39,9 @@ export const Route = createRootRoute({
|
|||||||
const { user } = useSessionStore();
|
const { user } = useSessionStore();
|
||||||
const logout = useLogout();
|
const logout = useLogout();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const { settings } = useSettingStore();
|
||||||
|
|
||||||
|
const server = settings.filter((n: any) => n.name === "dbServer");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="overflow-hidden">
|
<div className="overflow-hidden">
|
||||||
@@ -61,6 +65,17 @@ export const Route = createRootRoute({
|
|||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
<ModeToggle />
|
<ModeToggle />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mr-1 ml-1">
|
||||||
|
{settings.length > 0 && (
|
||||||
|
<a
|
||||||
|
href={`https://${server[0].value}.alpla.net/lst/d`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
LST - Docs
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{session ? (
|
{session ? (
|
||||||
<div className="m-1">
|
<div className="m-1">
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
|
|||||||
14
frontend/src/routes/_admin/prodUsers.tsx
Normal file
14
frontend/src/routes/_admin/prodUsers.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import ProdUserCard from "@/components/admin/prodUser/ProdUserCard";
|
||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/_admin/prodUsers")({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ProdUserCard />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -33,13 +33,12 @@ function RouteComponent() {
|
|||||||
<span className="font-bold">
|
<span className="font-bold">
|
||||||
Authentication Notice:
|
Authentication Notice:
|
||||||
</span>
|
</span>
|
||||||
To interact with the Alpla prod through this
|
<span>
|
||||||
application, you must use your{" "}
|
The username, email, and password are
|
||||||
<span className="font-semibold">
|
only for LST you <em>DO NOT</em>Need to
|
||||||
Windows login credentials
|
use Windows username if you do not wish
|
||||||
|
to.
|
||||||
</span>
|
</span>
|
||||||
. These credentials are used solely for
|
|
||||||
authentication purposes.
|
|
||||||
</li>
|
</li>
|
||||||
{/* <li>
|
{/* <li>
|
||||||
<span className="font-bold">
|
<span className="font-bold">
|
||||||
|
|||||||
14
frontend/src/routes/rfid/index.tsx
Normal file
14
frontend/src/routes/rfid/index.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import RfidPage from "@/components/rfid/RfidPage";
|
||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/rfid/")({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<RfidPage />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
15
frontend/src/utils/formStuff/index.tsx
Normal file
15
frontend/src/utils/formStuff/index.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { createFormHook, createFormHookContexts } from "@tanstack/react-form";
|
||||||
|
import { InputField } from "./options/InputField";
|
||||||
|
import { SubmitButton } from "./options/submitButton";
|
||||||
|
import { SelectField } from "./options/selectorField";
|
||||||
|
import { CheckboxField } from "./options/checkbox";
|
||||||
|
|
||||||
|
export const { fieldContext, useFieldContext, formContext, useFormContext } =
|
||||||
|
createFormHookContexts();
|
||||||
|
|
||||||
|
export const { useAppForm } = createFormHook({
|
||||||
|
fieldComponents: { InputField, SelectField, CheckboxField },
|
||||||
|
formComponents: { SubmitButton },
|
||||||
|
fieldContext,
|
||||||
|
formContext,
|
||||||
|
});
|
||||||
16
frontend/src/utils/formStuff/options/FieldErrors.tsx
Normal file
16
frontend/src/utils/formStuff/options/FieldErrors.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { AnyFieldMeta } from "@tanstack/react-form";
|
||||||
|
import { ZodError } from "zod";
|
||||||
|
|
||||||
|
type FieldErrorsProps = {
|
||||||
|
meta: AnyFieldMeta;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FieldErrors = ({ meta }: FieldErrorsProps) => {
|
||||||
|
if (!meta.isTouched) return null;
|
||||||
|
|
||||||
|
return meta.errors.map(({ message }: ZodError, index) => (
|
||||||
|
<p key={index} className="text-sm font-medium text-destructive">
|
||||||
|
{message}
|
||||||
|
</p>
|
||||||
|
));
|
||||||
|
};
|
||||||
@@ -1,32 +1,28 @@
|
|||||||
//import { Input } from "@/components/ui/input";
|
import { Label } from "@/components/ui/label";
|
||||||
//import { Label } from "@radix-ui/react-dropdown-menu";
|
import { useFieldContext } from "..";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { FieldErrors } from "./FieldErrors";
|
||||||
|
|
||||||
// export const FormInput = (form: any, label: string) => {
|
type InputFieldProps = {
|
||||||
// // <form.Field
|
label: string;
|
||||||
// // name="username"
|
inputType: string;
|
||||||
// // validators={{
|
required: boolean;
|
||||||
// // // We can choose between form-wide and field-specific validators
|
};
|
||||||
// // onChange: ({ value }) =>
|
export const InputField = ({ label, inputType, required }: InputFieldProps) => {
|
||||||
// // value.length > 3
|
const field = useFieldContext<any>();
|
||||||
// // ? undefined
|
|
||||||
// // : "Username must be longer than 3 letters",
|
return (
|
||||||
// // }}
|
<div className="grid gap-3">
|
||||||
// // children={(field) => {
|
<Label htmlFor={field.name}>{label}</Label>
|
||||||
// // return (
|
<Input
|
||||||
// // <div className="m-2 min-w-48 max-w-96 p-2">
|
id={field.name}
|
||||||
// // <Label htmlFor="username">{label}</Label>
|
value={field.state.value}
|
||||||
// // <Input
|
onChange={(e) => field.handleChange(e.target.value)}
|
||||||
// // name={field.name}
|
onBlur={field.handleBlur}
|
||||||
// // value={field.state.value}
|
type={inputType}
|
||||||
// // onBlur={field.handleBlur}
|
required={required}
|
||||||
// // //type="number"
|
/>
|
||||||
// // onChange={(e) => field.handleChange(e.target.value)}
|
<FieldErrors meta={field.state.meta} />
|
||||||
// // />
|
</div>
|
||||||
// // {field.state.meta.errors.length ? (
|
);
|
||||||
// // <em>{field.state.meta.errors.join(",")}</em>
|
};
|
||||||
// // ) : null}
|
|
||||||
// // </div>
|
|
||||||
// // );
|
|
||||||
// // }}
|
|
||||||
// // />;
|
|
||||||
// };
|
|
||||||
|
|||||||
34
frontend/src/utils/formStuff/options/checkbox.tsx
Normal file
34
frontend/src/utils/formStuff/options/checkbox.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { Checkbox } from "@radix-ui/react-checkbox";
|
||||||
|
import { useFieldContext } from "..";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { FieldErrors } from "./FieldErrors";
|
||||||
|
|
||||||
|
type CheckboxFieldProps = {
|
||||||
|
label: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CheckboxField = ({ label }: CheckboxFieldProps) => {
|
||||||
|
const field = useFieldContext<boolean>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="m-2 p-2 flex flex-row">
|
||||||
|
<div>
|
||||||
|
<Label htmlFor="active">
|
||||||
|
<span>{label}</span>
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
<Checkbox
|
||||||
|
id={field.name}
|
||||||
|
checked={field.state.value}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
field.handleChange(checked === true);
|
||||||
|
}}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<FieldErrors meta={field.state.meta} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
57
frontend/src/utils/formStuff/options/selectorField.tsx
Normal file
57
frontend/src/utils/formStuff/options/selectorField.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { useFieldContext } from "..";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { FieldErrors } from "./FieldErrors";
|
||||||
|
|
||||||
|
type SelectOption = {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectFieldProps = {
|
||||||
|
label: string;
|
||||||
|
options: SelectOption[];
|
||||||
|
placeholder?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SelectField = ({
|
||||||
|
label,
|
||||||
|
options,
|
||||||
|
placeholder,
|
||||||
|
}: SelectFieldProps) => {
|
||||||
|
const field = useFieldContext<string>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid gap-3">
|
||||||
|
<div className="grid gap-3">
|
||||||
|
<Label htmlFor={field.name}>{label}</Label>
|
||||||
|
<Select
|
||||||
|
value={field.state.value}
|
||||||
|
onValueChange={(value) => field.handleChange(value)}
|
||||||
|
>
|
||||||
|
<SelectTrigger
|
||||||
|
id={field.name}
|
||||||
|
onBlur={field.handleBlur}
|
||||||
|
className="w-[380px]"
|
||||||
|
>
|
||||||
|
<SelectValue placeholder={placeholder} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{options.map((option) => (
|
||||||
|
<SelectItem key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<FieldErrors meta={field.state.meta} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
24
frontend/src/utils/formStuff/options/submitButton.tsx
Normal file
24
frontend/src/utils/formStuff/options/submitButton.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { useStore } from "@tanstack/react-form";
|
||||||
|
import { useFormContext } from "..";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
type SubmitButtonProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SubmitButton = ({ children }: SubmitButtonProps) => {
|
||||||
|
const form = useFormContext();
|
||||||
|
|
||||||
|
const [isSubmitting] = useStore(form.store, (state) => [
|
||||||
|
state.isSubmitting,
|
||||||
|
state.canSubmit,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="">
|
||||||
|
<Button type="submit" disabled={isSubmitting}>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -13,7 +13,7 @@ export function getinventoryCheck(data: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fetchStockSilo = async (info: any) => {
|
const fetchStockSilo = async (info: any) => {
|
||||||
console.log(info);
|
//console.log("What tpye of info:", info);
|
||||||
const { data } = await axios.post(`/api/logistics/cyclecountcheck`, {
|
const { data } = await axios.post(`/api/logistics/cyclecountcheck`, {
|
||||||
age: info.age ? parseInt(info.age) : null,
|
age: info.age ? parseInt(info.age) : null,
|
||||||
type: "",
|
type: "",
|
||||||
|
|||||||
23
frontend/src/utils/querys/logistics/machineConnected.tsx
Normal file
23
frontend/src/utils/querys/logistics/machineConnected.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getMachineConnected(siloCon: any) {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: [`siloConnectionAttached-${siloCon.siloID}`],
|
||||||
|
queryFn: () => fetchStockSilo(siloCon),
|
||||||
|
//enabled:
|
||||||
|
//staleTime: 1000,
|
||||||
|
//refetchInterval: 60 * 1000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchStockSilo = async (siloCon: any) => {
|
||||||
|
const { data } = await axios.post(`/api/logistics/siloconnection`, {
|
||||||
|
siloID: siloCon.siloID,
|
||||||
|
connectionType: siloCon.connectionType,
|
||||||
|
});
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
23
frontend/src/utils/querys/logistics/notConnected.tsx
Normal file
23
frontend/src/utils/querys/logistics/notConnected.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getMachineNotConnected(siloCon: any) {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: [`siloConnectionNotConnected-${siloCon.siloID}`],
|
||||||
|
queryFn: () => fetchStockSilo(siloCon),
|
||||||
|
//enabled:
|
||||||
|
//staleTime: 1000,
|
||||||
|
//refetchInterval: 60 * 1000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchStockSilo = async (siloCon: any) => {
|
||||||
|
const { data } = await axios.post(`/api/logistics/siloconnection`, {
|
||||||
|
siloID: siloCon.siloID,
|
||||||
|
connectionType: siloCon.connectionType,
|
||||||
|
});
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
25
frontend/src/utils/querys/prodUser/getProdPerms.tsx
Normal file
25
frontend/src/utils/querys/prodUser/getProdPerms.tsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getProdPerms(token: string) {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["prodPerms"],
|
||||||
|
queryFn: () => fetch(token),
|
||||||
|
enabled: !!token,
|
||||||
|
staleTime: 1000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetch = async (token: string) => {
|
||||||
|
const { data } = await axios.get("/api/produser/prodrole", {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
// const url: string = window.location.host.split(":")[0];
|
||||||
|
// let settingsData = data.data;
|
||||||
|
// if (url != "localhost") {
|
||||||
|
// settingsData.filter((n: any) => n.name === "devDir");
|
||||||
|
// }
|
||||||
|
return data.data;
|
||||||
|
};
|
||||||
20
frontend/src/utils/querys/production/labelRatio.tsx
Normal file
20
frontend/src/utils/querys/production/labelRatio.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getlabelRatio() {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["labelRatio"],
|
||||||
|
queryFn: () => fetchSettings(),
|
||||||
|
|
||||||
|
//staleTime: 1000,
|
||||||
|
refetchInterval: 2 * 2000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettings = async () => {
|
||||||
|
const { data } = await axios.get(`/api/ocp/labelratio`);
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
20
frontend/src/utils/querys/rfid/getReaders.tsx
Normal file
20
frontend/src/utils/querys/rfid/getReaders.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export function getReaders() {
|
||||||
|
return queryOptions({
|
||||||
|
queryKey: ["getReaders"],
|
||||||
|
queryFn: () => fetchReaders(),
|
||||||
|
//enabled:
|
||||||
|
staleTime: 1000,
|
||||||
|
refetchInterval: 60 * 1000,
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchReaders = async () => {
|
||||||
|
const { data } = await axios.get(`/api/rfid/getreaders`);
|
||||||
|
// if we are not localhost ignore the devDir setting.
|
||||||
|
//const url: string = window.location.host.split(":")[0];
|
||||||
|
return data.data ?? [];
|
||||||
|
};
|
||||||
@@ -1,23 +1,25 @@
|
|||||||
import {queryOptions} from "@tanstack/react-query";
|
import { queryOptions } from "@tanstack/react-query";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
export function getSettings(token: string) {
|
export function getSettings(token: string) {
|
||||||
return queryOptions({
|
return queryOptions({
|
||||||
queryKey: ["settings"],
|
queryKey: ["settings"],
|
||||||
queryFn: () => fetchSettings(token),
|
queryFn: () => fetch(token),
|
||||||
enabled: !!token,
|
enabled: !!token,
|
||||||
staleTime: 1000,
|
staleTime: 1000,
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchSettings = async (token: string) => {
|
const fetch = 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.
|
// if we are not localhost ignore the devDir setting.
|
||||||
const url: string = window.location.host.split(":")[0];
|
// const url: string = window.location.host.split(":")[0];
|
||||||
let settingsData = data.data;
|
// let settingsData = data.data;
|
||||||
if (url != "localhost") {
|
// if (url != "localhost") {
|
||||||
settingsData.filter((n: any) => n.name === "devDir");
|
// settingsData.filter((n: any) => n.name === "devDir");
|
||||||
}
|
// }
|
||||||
return settingsData;
|
return data.data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export function InvTable<TData, TValue>({
|
|||||||
});
|
});
|
||||||
//console.log(table.getState().sorting);
|
//console.log(table.getState().sorting);
|
||||||
//console.log(parseInt(style.height.replace("px", "")) - 50);
|
//console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||||
|
console.log(info);
|
||||||
return (
|
return (
|
||||||
<LstCard
|
<LstCard
|
||||||
className="p-3"
|
className="p-3"
|
||||||
@@ -79,8 +80,9 @@ export function InvTable<TData, TValue>({
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
<p className="text-center text-pretty">
|
<p className="text-center text-pretty">
|
||||||
{info.type} {data.length > 0 ? "lanes" : "lane"} older
|
{info.rowType} {data.length > 0 ? "lanes" : "lane"}{" "}
|
||||||
than: {info.age}, needing to be completed
|
older than: {info.age}, {data.length} needing to be
|
||||||
|
completed
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ScrollArea className="h-72 rounded-md border m-2">
|
<ScrollArea className="h-72 rounded-md border m-2">
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
//import { fixTime } from "@/utils/fixTime";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { getReaders } from "@/utils/querys/rfid/getReaders";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
// This type is used to define the shape of our data.
|
||||||
|
// You can use a Zod schema here if you want.
|
||||||
|
export type Adjustmnets = {
|
||||||
|
ratio_id: string;
|
||||||
|
name: string;
|
||||||
|
autoLabel: number;
|
||||||
|
manualLabel: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const labelRatioColumns: ColumnDef<Adjustmnets>[] = [
|
||||||
|
// {
|
||||||
|
// accessorKey: "line",
|
||||||
|
// header: () => <div className="text-left">Line</div>,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
accessorKey: "autoLabel",
|
||||||
|
header: "Auto Labels",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "manualLabel",
|
||||||
|
header: "Manual Labels",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "goodRatio",
|
||||||
|
header: "Ratio",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const goodRatio =
|
||||||
|
(parseInt(row.getValue("autoLabel")) /
|
||||||
|
(parseInt(row.getValue("autoLabel")) +
|
||||||
|
parseInt(row.getValue("manualLabel")))) *
|
||||||
|
100;
|
||||||
|
return (
|
||||||
|
<div className="text-center font-medium">
|
||||||
|
{isNaN(goodRatio) ? 0 : goodRatio.toFixed(2)}%
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "reset",
|
||||||
|
header: "Reset Reads",
|
||||||
|
cell: () => {
|
||||||
|
const { refetch } = useQuery(getReaders());
|
||||||
|
const [readerReset, setReaderReset] = useState(false);
|
||||||
|
const resetReads = async () => {
|
||||||
|
setReaderReset(true);
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/api/ocp/resetlabelratio", {
|
||||||
|
reader: name,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
setReaderReset(false);
|
||||||
|
} else {
|
||||||
|
toast.error(res.data.message);
|
||||||
|
setReaderReset(false);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error.data.message);
|
||||||
|
setReaderReset(false);
|
||||||
|
}
|
||||||
|
refetch();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="text-left font-medium">
|
||||||
|
<Button
|
||||||
|
className="h-4"
|
||||||
|
onClick={resetReads}
|
||||||
|
disabled={readerReset}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import {
|
||||||
|
ColumnDef,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
useReactTable,
|
||||||
|
getPaginationRowModel,
|
||||||
|
} from "@tanstack/react-table";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
|
||||||
|
interface DataTableProps<TData, TValue> {
|
||||||
|
columns: ColumnDef<TData, TValue>[];
|
||||||
|
data: TData[];
|
||||||
|
//style: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LabelRatioTable<TData, TValue>({
|
||||||
|
columns,
|
||||||
|
data,
|
||||||
|
//style,
|
||||||
|
}: DataTableProps<TData, TValue>) {
|
||||||
|
const [pagination, setPagination] = useState({
|
||||||
|
pageIndex: 0, //initial page index
|
||||||
|
pageSize: 5, //default page size
|
||||||
|
});
|
||||||
|
const table = useReactTable({
|
||||||
|
data,
|
||||||
|
columns,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
onPaginationChange: setPagination,
|
||||||
|
state: {
|
||||||
|
//...
|
||||||
|
pagination,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||||
|
return (
|
||||||
|
<LstCard>
|
||||||
|
<div>
|
||||||
|
<div className="flex flex-row justify-between">
|
||||||
|
{data.length === 0 ? (
|
||||||
|
<span className="text-center">
|
||||||
|
No labels printed since last reset.
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span>Label Ratio</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<ScrollArea className="max-h-32 rounded-md border m-2">
|
||||||
|
<Table
|
||||||
|
// style={{
|
||||||
|
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||||
|
// height: `${parseInt(style.height.replace("px", "")) - 200}px`,
|
||||||
|
// cursor: "move",
|
||||||
|
// }}
|
||||||
|
>
|
||||||
|
<TableHeader>
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<TableRow key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header) => {
|
||||||
|
return (
|
||||||
|
<TableHead key={header.id}>
|
||||||
|
{header.isPlaceholder
|
||||||
|
? null
|
||||||
|
: flexRender(
|
||||||
|
header.column
|
||||||
|
.columnDef.header,
|
||||||
|
header.getContext()
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{table.getRowModel().rows?.length ? (
|
||||||
|
table.getRowModel().rows.map((row) => (
|
||||||
|
<TableRow
|
||||||
|
key={row.id}
|
||||||
|
data-state={
|
||||||
|
row.getIsSelected() && "selected"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<TableCell key={cell.id}>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={columns.length}
|
||||||
|
className="h-24 text-center"
|
||||||
|
>
|
||||||
|
No labels.
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
</LstCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { fixTime } from "@/utils/fixTime";
|
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
|
import { format } from "date-fns-tz";
|
||||||
import { Trash } from "lucide-react";
|
import { Trash } from "lucide-react";
|
||||||
|
|
||||||
// This type is used to define the shape of our data.
|
// This type is used to define the shape of our data.
|
||||||
@@ -38,9 +38,11 @@ export const ocpColumns = (
|
|||||||
header: "Error Date",
|
header: "Error Date",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
if (row.getValue("created_at")) {
|
if (row.getValue("created_at")) {
|
||||||
const correctDate = fixTime(row.getValue("created_at"));
|
const correctDate: any = row.getValue("created_at");
|
||||||
|
const strippedDate = correctDate.replace("Z", ""); // Remove Z
|
||||||
|
const formattedDate = format(strippedDate, "MM/dd/yyyy HH:mm");
|
||||||
return (
|
return (
|
||||||
<div className="text-left font-medium">{correctDate}</div>
|
<div className="text-left font-medium">{formattedDate}</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
148
frontend/src/utils/tableData/rfid/readers/readerColumns.tsx
Normal file
148
frontend/src/utils/tableData/rfid/readers/readerColumns.tsx
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
//import { fixTime } from "@/utils/fixTime";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { getReaders } from "@/utils/querys/rfid/getReaders";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
|
import axios from "axios";
|
||||||
|
import { format } from "date-fns-tz";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
// This type is used to define the shape of our data.
|
||||||
|
// You can use a Zod schema here if you want.
|
||||||
|
export type Readers = {
|
||||||
|
rfidReader_id: string;
|
||||||
|
reader: string;
|
||||||
|
readerIP: string;
|
||||||
|
lastHeartBeat: string;
|
||||||
|
lastTrigger: string;
|
||||||
|
lastTriggerGood: boolean;
|
||||||
|
active: boolean;
|
||||||
|
lastTagScanned: string;
|
||||||
|
goodReads: number;
|
||||||
|
badReads: number;
|
||||||
|
totalReads: number;
|
||||||
|
goodRatio: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const readerColumns: ColumnDef<Readers>[] = [
|
||||||
|
{
|
||||||
|
accessorKey: "reader",
|
||||||
|
header: () => <div className="text-left">Name</div>,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "lastHeartBeat",
|
||||||
|
header: "Last HeartBeat",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
if (row.getValue("lastHeartBeat")) {
|
||||||
|
const correctDate: any = row.getValue("lastHeartBeat");
|
||||||
|
const strippedDate = correctDate.replace("Z", ""); // Remove Z
|
||||||
|
const formattedDate = format(strippedDate, "MM/dd/yyyy HH:mm");
|
||||||
|
return (
|
||||||
|
<div className="text-left font-medium">{formattedDate}</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "lastTrigger",
|
||||||
|
header: "Last Trigger",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
if (row.getValue("lastTrigger")) {
|
||||||
|
const correctDate: any = row.getValue("lastTrigger");
|
||||||
|
const strippedDate = correctDate.replace("Z", ""); // Remove Z
|
||||||
|
const formattedDate = format(strippedDate, "MM/dd/yyyy HH:mm");
|
||||||
|
return (
|
||||||
|
<div className="text-left font-medium">{formattedDate}</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "lastTriggerGood",
|
||||||
|
header: "Last Trigger Status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "lastTagScanned",
|
||||||
|
header: "Last Scanned Tag",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "goodReads",
|
||||||
|
header: "Total Good Reads",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "badReads",
|
||||||
|
header: "Total Bad Reads",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "totalReads",
|
||||||
|
header: "Total Reads",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const total =
|
||||||
|
parseInt(row.getValue("goodReads")) +
|
||||||
|
parseInt(row.getValue("badReads"));
|
||||||
|
return <div className="text-left font-medium">{total}</div>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "goodRatio",
|
||||||
|
header: "Good Ratio",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const goodRatio =
|
||||||
|
(parseInt(row.getValue("goodReads")) /
|
||||||
|
(parseInt(row.getValue("goodReads")) +
|
||||||
|
parseInt(row.getValue("badReads")))) *
|
||||||
|
100;
|
||||||
|
return (
|
||||||
|
<div className="text-left font-medium">
|
||||||
|
{isNaN(goodRatio) ? 0 : goodRatio.toFixed(2)}%
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "reset",
|
||||||
|
header: "Reset Reads",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const { refetch } = useQuery(getReaders());
|
||||||
|
const [readerReset, setReaderReset] = useState(false);
|
||||||
|
// const goodRatio =
|
||||||
|
// (parseInt(row.getValue("goodReads")) /
|
||||||
|
// (parseInt(row.getValue("goodReads")) +
|
||||||
|
// parseInt(row.getValue("badReads")))) *
|
||||||
|
// 100;
|
||||||
|
const name = row.getValue("reader");
|
||||||
|
const resetReads = async () => {
|
||||||
|
setReaderReset(true);
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/api/rfid/resetRatio", {
|
||||||
|
reader: name,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
toast.success(res.data.message);
|
||||||
|
setReaderReset(false);
|
||||||
|
} else {
|
||||||
|
toast.error(res.data.message);
|
||||||
|
setReaderReset(false);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error.data.message);
|
||||||
|
setReaderReset(false);
|
||||||
|
}
|
||||||
|
refetch();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="text-left font-medium">
|
||||||
|
<Button
|
||||||
|
className="h-4"
|
||||||
|
onClick={resetReads}
|
||||||
|
disabled={readerReset}
|
||||||
|
>
|
||||||
|
Reset Reads
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
174
frontend/src/utils/tableData/rfid/readers/readerData.tsx
Normal file
174
frontend/src/utils/tableData/rfid/readers/readerData.tsx
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
import {
|
||||||
|
ColumnDef,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
useReactTable,
|
||||||
|
getPaginationRowModel,
|
||||||
|
} from "@tanstack/react-table";
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from "@/components/ui/table";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { useState } from "react";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectLabel,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
|
import { LstCard } from "@/components/extendedUI/LstCard";
|
||||||
|
|
||||||
|
interface DataTableProps<TData, TValue> {
|
||||||
|
columns: ColumnDef<TData, TValue>[];
|
||||||
|
data: TData[];
|
||||||
|
//style: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ReaderTable<TData, TValue>({
|
||||||
|
columns,
|
||||||
|
data,
|
||||||
|
//style,
|
||||||
|
}: DataTableProps<TData, TValue>) {
|
||||||
|
const [pagination, setPagination] = useState({
|
||||||
|
pageIndex: 0, //initial page index
|
||||||
|
pageSize: 10, //default page size
|
||||||
|
});
|
||||||
|
const table = useReactTable({
|
||||||
|
data,
|
||||||
|
columns,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
onPaginationChange: setPagination,
|
||||||
|
state: {
|
||||||
|
//...
|
||||||
|
pagination,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log(parseInt(style.height.replace("px", "")) - 50);
|
||||||
|
return (
|
||||||
|
<LstCard>
|
||||||
|
<div>
|
||||||
|
<div className="flex flex-row justify-between">
|
||||||
|
{data.length === 0 ? (
|
||||||
|
<span>No readers</span>
|
||||||
|
) : (
|
||||||
|
<span>Current reader Info</span>
|
||||||
|
)}
|
||||||
|
<Select
|
||||||
|
value={pagination.pageSize.toString()}
|
||||||
|
onValueChange={(e) =>
|
||||||
|
setPagination({
|
||||||
|
...pagination,
|
||||||
|
pageSize: parseInt(e),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue
|
||||||
|
//id={field.name}
|
||||||
|
placeholder="Select Page"
|
||||||
|
defaultValue={10}
|
||||||
|
/>
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>Page Size</SelectLabel>
|
||||||
|
<SelectItem value="5">5</SelectItem>
|
||||||
|
<SelectItem value="10">10</SelectItem>
|
||||||
|
<SelectItem value="50">50</SelectItem>
|
||||||
|
<SelectItem value="100">100</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<ScrollArea className="h-96 rounded-md border m-2">
|
||||||
|
<Table
|
||||||
|
// style={{
|
||||||
|
// width: `${parseInt(style.width.replace("px", "")) - 50}px`,
|
||||||
|
// height: `${parseInt(style.height.replace("px", "")) - 200}px`,
|
||||||
|
// cursor: "move",
|
||||||
|
// }}
|
||||||
|
>
|
||||||
|
<TableHeader>
|
||||||
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
|
<TableRow key={headerGroup.id}>
|
||||||
|
{headerGroup.headers.map((header) => {
|
||||||
|
return (
|
||||||
|
<TableHead key={header.id}>
|
||||||
|
{header.isPlaceholder
|
||||||
|
? null
|
||||||
|
: flexRender(
|
||||||
|
header.column
|
||||||
|
.columnDef.header,
|
||||||
|
header.getContext()
|
||||||
|
)}
|
||||||
|
</TableHead>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{table.getRowModel().rows?.length ? (
|
||||||
|
table.getRowModel().rows.map((row) => (
|
||||||
|
<TableRow
|
||||||
|
key={row.id}
|
||||||
|
data-state={
|
||||||
|
row.getIsSelected() && "selected"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
<TableCell key={cell.id}>
|
||||||
|
{flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={columns.length}
|
||||||
|
className="h-24 text-center"
|
||||||
|
>
|
||||||
|
No labels.
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-end space-x-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => table.previousPage()}
|
||||||
|
disabled={!table.getCanPreviousPage()}
|
||||||
|
>
|
||||||
|
Previous
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => table.nextPage()}
|
||||||
|
disabled={!table.getCanNextPage()}
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</LstCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ export default defineConfig({
|
|||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
TanStackRouterVite({ target: "react", autoCodeSplitting: true }),
|
TanStackRouterVite({ target: "react", autoCodeSplitting: true }),
|
||||||
],
|
],
|
||||||
|
// base: "/lst", // this is whats showing in the ssl version and we need this to work on both versions that also have a port on them.
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": path.resolve(__dirname, "./src"),
|
"@": path.resolve(__dirname, "./src"),
|
||||||
|
|||||||
1773
package-lock.json
generated
1773
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user