Compare commits
55 Commits
v0.0.2-alp
...
2a648f6306
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a648f6306 | |||
| 69a9a81a88 | |||
| 188fdd0eb7 | |||
| db28635c8c | |||
| bcdf9566bc | |||
| c15ee070e7 | |||
| 347edb7078 | |||
| fe0b1573f3 | |||
| 9c0ef1f5df | |||
| 8b076949a7 | |||
| 6d0fb8aee4 | |||
| 3a0c729b9a | |||
| 057a570e43 | |||
| 52974aa0b4 | |||
| ecfbda9036 | |||
| 389211186f | |||
| 3a27fd8542 | |||
| 1f6637c512 | |||
| 1840ac5e58 | |||
| 636daaed0a | |||
| 71c83062cb | |||
| cd67c4de80 | |||
| 36ac1dccb4 | |||
| 514a44b6de | |||
| a7bb364a2f | |||
| 047cc7cdf0 | |||
| 8dc4d70e28 | |||
| c8931c7249 | |||
| 67f36c5499 | |||
| ebf1060475 | |||
| c64392f457 | |||
| e9e73c829c | |||
| bcb7773007 | |||
| eb950d2c29 | |||
| 2616acf106 | |||
| 30ff7b71d9 | |||
| e7af3d1182 | |||
| 3e66c3920d | |||
| eb9d77c3d4 | |||
| 342a97f6b1 | |||
| b0c7277a6c | |||
| dc95e50a84 | |||
| d2a9e1d110 | |||
| a9c69250bd | |||
| d61be61f44 | |||
| f5bae2c0c2 | |||
| 05758791be | |||
| 51026e3e2c | |||
| 9631736e26 | |||
| ce9d8eaaf5 | |||
| 1bbf5c2a49 | |||
| 13718fe702 | |||
| 0de2579942 | |||
| 7c31b43a4a | |||
| 85e96f5ed1 |
@@ -9,4 +9,4 @@ builds
|
|||||||
testFiles
|
testFiles
|
||||||
nssm.exe
|
nssm.exe
|
||||||
postgresql-17.9-2-windows-x64.exe
|
postgresql-17.9-2-windows-x64.exe
|
||||||
VSCodeUserSetup-x64-1.112.0.msi
|
VSCodeSetup-x64-1.120.0.msi
|
||||||
66
.gitea/ISSUE_TEMPLATE/bug_report_frontend.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report - Frontend
|
||||||
|
about: Report something that is broken or not working correctly
|
||||||
|
title: "[BUG - Frontend] "
|
||||||
|
ref: "main"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- bug
|
||||||
|
- frontend
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
Briefly explain the issue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Steps To Reproduce
|
||||||
|
|
||||||
|
1. Go to ...
|
||||||
|
2. Click ...
|
||||||
|
3. Scan ...
|
||||||
|
4. Error occurs ...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Expected Behavior
|
||||||
|
|
||||||
|
What should have happened?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Actual Behavior
|
||||||
|
|
||||||
|
What actually happened instead?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Severity
|
||||||
|
|
||||||
|
- [ ] Low
|
||||||
|
- [ ] Medium
|
||||||
|
- [ ] High
|
||||||
|
- [ ] Critical
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
- Production
|
||||||
|
- Development
|
||||||
|
- Zebra Scanner
|
||||||
|
- Mobile Device
|
||||||
|
- Windows Server
|
||||||
|
- Docker
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Logs / Screenshots
|
||||||
|
|
||||||
|
Paste logs or upload screenshots here.
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Paste logs here
|
||||||
66
.gitea/ISSUE_TEMPLATE/bug_report_mobile.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report - Mobile
|
||||||
|
about: Report something that is broken or not working correctly
|
||||||
|
title: "[BUG - Mobile] "
|
||||||
|
ref: "main"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- bug
|
||||||
|
- mobile
|
||||||
|
---
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
|
||||||
|
Briefly explain the issue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Steps To Reproduce
|
||||||
|
|
||||||
|
1. Go to ...
|
||||||
|
2. Click ...
|
||||||
|
3. Scan ...
|
||||||
|
4. Error occurs ...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Expected Behavior
|
||||||
|
|
||||||
|
What should have happened?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Actual Behavior
|
||||||
|
|
||||||
|
What actually happened instead?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Severity
|
||||||
|
|
||||||
|
- [ ] Low
|
||||||
|
- [ ] Medium
|
||||||
|
- [ ] High
|
||||||
|
- [ ] Critical
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
- Production
|
||||||
|
- Development
|
||||||
|
- Zebra Scanner
|
||||||
|
- Mobile Device
|
||||||
|
- Windows Server
|
||||||
|
- Docker
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Logs / Screenshots
|
||||||
|
|
||||||
|
Paste logs or upload screenshots here.
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Paste logs here
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report - Server
|
||||||
about: Report something that is broken or not working correctly
|
about: Report something that is broken or not working correctly
|
||||||
title: "[BUG] "
|
title: "[BUG - Server] "
|
||||||
ref: "main"
|
ref: "main"
|
||||||
labels:
|
labels:
|
||||||
|
|
||||||
- bug
|
- bug
|
||||||
|
- server
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
48
.gitea/ISSUE_TEMPLATE/enhancement_frontend.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
name: Enhancement - Frontend
|
||||||
|
about: Improve or refine an existing feature
|
||||||
|
title: "[ENHANCEMENT - Frontend] "
|
||||||
|
ref: "main"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- enhancement
|
||||||
|
- frontend
|
||||||
|
---
|
||||||
|
|
||||||
|
# Existing Feature
|
||||||
|
|
||||||
|
What current feature or workflow is being improved?
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
- Notifications
|
||||||
|
- Scanner Login
|
||||||
|
- Release Monitor
|
||||||
|
- Printing
|
||||||
|
- Auth
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Proposed Improvement
|
||||||
|
|
||||||
|
Describe the improvement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Expected Benefit
|
||||||
|
|
||||||
|
Why would this improvement help?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Impact
|
||||||
|
|
||||||
|
- [ ] Small
|
||||||
|
- [ ] Medium
|
||||||
|
- [ ] Large
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Additional Notes
|
||||||
|
|
||||||
|
Anything else worth mentioning.
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: Enhancement
|
name: Enhancement - Mobile
|
||||||
about: Improve or refine an existing feature
|
about: Improve or refine an existing feature
|
||||||
title: "[ENHANCEMENT] "
|
title: "[ENHANCEMENT - Mobile] "
|
||||||
ref: "main"
|
ref: "main"
|
||||||
labels:
|
labels:
|
||||||
|
|
||||||
- enhancement
|
- enhancement
|
||||||
|
- mobile
|
||||||
---
|
---
|
||||||
|
|
||||||
# Existing Feature
|
# Existing Feature
|
||||||
48
.gitea/ISSUE_TEMPLATE/enhancement_server.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
name: Enhancement - Server
|
||||||
|
about: Improve or refine an existing feature
|
||||||
|
title: "[ENHANCEMENT - Server] "
|
||||||
|
ref: "main"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- enhancement
|
||||||
|
- server
|
||||||
|
---
|
||||||
|
|
||||||
|
# Existing Feature
|
||||||
|
|
||||||
|
What current feature or workflow is being improved?
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
- Notifications
|
||||||
|
- Scanner Login
|
||||||
|
- Release Monitor
|
||||||
|
- Printing
|
||||||
|
- Auth
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Proposed Improvement
|
||||||
|
|
||||||
|
Describe the improvement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Expected Benefit
|
||||||
|
|
||||||
|
Why would this improvement help?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Impact
|
||||||
|
|
||||||
|
- [ ] Small
|
||||||
|
- [ ] Medium
|
||||||
|
- [ ] Large
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Additional Notes
|
||||||
|
|
||||||
|
Anything else worth mentioning.
|
||||||
41
.gitea/ISSUE_TEMPLATE/feature_request_frontend.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
name: Feature Request - Frontend
|
||||||
|
about: Suggest a brand new feature or module
|
||||||
|
title: "[FEATURE - Frontend] "
|
||||||
|
ref: "main"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- feature
|
||||||
|
- frontend
|
||||||
|
---
|
||||||
|
|
||||||
|
# Problem Statement
|
||||||
|
|
||||||
|
What problem are you trying to solve?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Proposed Solution
|
||||||
|
|
||||||
|
Describe the feature you would like added.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Alternatives Considered
|
||||||
|
|
||||||
|
Any other ideas, workarounds, or approaches?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Priority
|
||||||
|
|
||||||
|
- [ ] Nice to Have
|
||||||
|
- [ ] Medium Priority
|
||||||
|
- [ ] High Priority
|
||||||
|
- [ ] Critical
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Additional Context
|
||||||
|
|
||||||
|
Add mockups, screenshots, examples, or notes here.
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
---
|
---
|
||||||
name: Feature Request
|
name: Feature Request - Mobile
|
||||||
about: Suggest a brand new feature or module
|
about: Suggest a brand new feature or module
|
||||||
title: "[FEATURE] "
|
title: "[FEATURE - Mobile] "
|
||||||
ref: "main"
|
ref: "main"
|
||||||
labels:
|
labels:
|
||||||
|
|
||||||
- feature
|
- feature
|
||||||
|
- mobile
|
||||||
---
|
---
|
||||||
|
|
||||||
# Problem Statement
|
# Problem Statement
|
||||||
41
.gitea/ISSUE_TEMPLATE/feature_request_server.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
name: Feature Request - Server
|
||||||
|
about: Suggest a brand new feature or module
|
||||||
|
title: "[FEATURE - Server] "
|
||||||
|
ref: "main"
|
||||||
|
labels:
|
||||||
|
|
||||||
|
- feature
|
||||||
|
- server
|
||||||
|
---
|
||||||
|
|
||||||
|
# Problem Statement
|
||||||
|
|
||||||
|
What problem are you trying to solve?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Proposed Solution
|
||||||
|
|
||||||
|
Describe the feature you would like added.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Alternatives Considered
|
||||||
|
|
||||||
|
Any other ideas, workarounds, or approaches?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Priority
|
||||||
|
|
||||||
|
- [ ] Nice to Have
|
||||||
|
- [ ] Medium Priority
|
||||||
|
- [ ] High Priority
|
||||||
|
- [ ] Critical
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Additional Context
|
||||||
|
|
||||||
|
Add mockups, screenshots, examples, or notes here.
|
||||||
3
.gitignore
vendored
@@ -9,8 +9,9 @@ downloads
|
|||||||
.scriptCreds
|
.scriptCreds
|
||||||
node-v24.14.0-x64.msi
|
node-v24.14.0-x64.msi
|
||||||
postgresql-17.9-2-windows-x64.exe
|
postgresql-17.9-2-windows-x64.exe
|
||||||
VSCodeUserSetup-x64-1.112.0.exe
|
VSCodeSetup-x64-1.120.0.exe
|
||||||
nssm.exe
|
nssm.exe
|
||||||
|
frontend/.tanstack
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
|
|||||||
112
CHANGELOG.md
@@ -1,5 +1,117 @@
|
|||||||
# All Changes to LST can be found below.
|
# All Changes to LST can be found below.
|
||||||
|
|
||||||
|
## [0.1.0-alpha.2](https://git.tuffraid.net/cowch/lst_v3/compare/v0.1.0-alpha.1...v0.1.0-alpha.2) (2026-05-23)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
* **build:** gives a rabbit hole error
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **opendock:** added in new article link setup for fine tuning how od works ([3892111](https://git.tuffraid.net/cowch/lst_v3/commits/389211186f00cb8a6fdd5de092a944fa7e5898aa))
|
||||||
|
* **opendock:** scheduing updates ([1840ac5](https://git.tuffraid.net/cowch/lst_v3/commits/1840ac5e580c726c452216480b6e14e7c52a0f35)), closes [#23](https://git.tuffraid.net/cowch/lst_v3/issues/23)
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **build:** crashes when files changed :( ([1f6637c](https://git.tuffraid.net/cowch/lst_v3/commits/1f6637c512dcd465c5000f8d1baaa8e76766edc1)), closes [#24](https://git.tuffraid.net/cowch/lst_v3/issues/24)
|
||||||
|
* **docs:** wrong location for images ([057a570](https://git.tuffraid.net/cowch/lst_v3/commits/057a570e43a8e1763652d98244c90999c3fccd42))
|
||||||
|
* **mobile:** correction to axios helper ([ecfbda9](https://git.tuffraid.net/cowch/lst_v3/commits/ecfbda9036f3d68c93e9c1d81021efa8093f18e2))
|
||||||
|
* **sql queries:** disable job would error so now we will check if it exists before trying to kill it ([636daae](https://git.tuffraid.net/cowch/lst_v3/commits/636daaed0adeda908e7e850a4f5bb20d7bbef861))
|
||||||
|
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
* **mobile:** updated imgs to be a little smaller ([3a27fd8](https://git.tuffraid.net/cowch/lst_v3/commits/3a27fd8542c3fa4ad5520532c2f10c6e3eaa951c))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **mobile:** added missing error to the scanner ([52974aa](https://git.tuffraid.net/cowch/lst_v3/commits/52974aa0b4f21431777b773200a57f185b4babd2))
|
||||||
|
* **opendock:** changes to how we do the intergration scheduling ([cd67c4d](https://git.tuffraid.net/cowch/lst_v3/commits/cd67c4de80b6f0244afc639a7360e9dc2ba97a21)), closes [#23](https://git.tuffraid.net/cowch/lst_v3/issues/23)
|
||||||
|
|
||||||
|
|
||||||
|
### 📈 Project changes
|
||||||
|
|
||||||
|
* **docker:** changes to the ignore file ([71c8306](https://git.tuffraid.net/cowch/lst_v3/commits/71c83062cb644796ebbfd845084ac6c019206faa))
|
||||||
|
|
||||||
|
## [0.1.0-alpha.1](https://git.tuffraid.net/cowch/lst_v3/compare/v0.1.0-alpha.0...v0.1.0-alpha.1) (2026-05-19)
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **notifications:** reprinting ([c8931c7](https://git.tuffraid.net/cowch/lst_v3/commits/c8931c7249b8f532b5dd37df3271da98f14ee710)), closes [#20](https://git.tuffraid.net/cowch/lst_v3/issues/20)
|
||||||
|
* **settings:** failed build due it dormant import ([a7bb364](https://git.tuffraid.net/cowch/lst_v3/commits/a7bb364a2fd49d96b6195aca0cd58ba57c58f3a6))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **servers:** changed activeity around and trying to make use of it ([514a44b](https://git.tuffraid.net/cowch/lst_v3/commits/514a44b6de3efe8dd8b308d98bdbc82e31ed8427))
|
||||||
|
* **users:** lots of auth stuff added to make it more easy to manage users ([047cc7c](https://git.tuffraid.net/cowch/lst_v3/commits/047cc7cdf036c39a89a0b87ab59dda8328efe0c0))
|
||||||
|
|
||||||
|
|
||||||
|
### 📈 Project changes
|
||||||
|
|
||||||
|
* **app:** added in chokidar to monitor folders ([8dc4d70](https://git.tuffraid.net/cowch/lst_v3/commits/8dc4d70e2827f0a40d2f54886fd757c8a2dc5ac4))
|
||||||
|
|
||||||
|
## [0.1.0-alpha.0](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.2-alpha.10...v0.1.0-alpha.0) (2026-05-14)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
* **app:** moved teh middleware to call the api hits to the main app and removed from
|
||||||
|
everywhere else
|
||||||
|
|
||||||
|
### 🌟 Enhancements
|
||||||
|
|
||||||
|
* **notification:** migrated sql cleanup ([3e66c39](https://git.tuffraid.net/cowch/lst_v3/commits/3e66c3920d65cee7a0a788f3910c1ddf09a07805))
|
||||||
|
* **scan users:** added in the place to add the new scanner users in ([ce9d8ea](https://git.tuffraid.net/cowch/lst_v3/commits/ce9d8eaaf5bcb8f53ea4bdc191347df8d589fdfa))
|
||||||
|
|
||||||
|
|
||||||
|
### 🐛 Bug fixes
|
||||||
|
|
||||||
|
* **anaylistics:** changes to the daily section so it populates correctly now ([f5bae2c](https://git.tuffraid.net/cowch/lst_v3/commits/f5bae2c0c24b85423c5c421164d94d58159ff70a))
|
||||||
|
* **anaylitics:** unique values were missing causing a weird crash ([13718fe](https://git.tuffraid.net/cowch/lst_v3/commits/13718fe70293c039bd1d9bf8cf395852e6ea6c21))
|
||||||
|
* **app:** emit.maxlistener issue ([7c31b43](https://git.tuffraid.net/cowch/lst_v3/commits/7c31b43a4a313237fa63c0c9bbc3690b74f63a6f)), closes [#18](https://git.tuffraid.net/cowch/lst_v3/issues/18)
|
||||||
|
* **app:** required auth was in wrong spot caused entire app to want you logged in ([d2a9e1d](https://git.tuffraid.net/cowch/lst_v3/commits/d2a9e1d1107ea05f13725e9528bc6ab1566c8efb))
|
||||||
|
* **notification subs:** made it so only acitve show ([2616acf](https://git.tuffraid.net/cowch/lst_v3/commits/2616acf106530f5c5ee04d1b79033795cf06b42d)), closes [#14](https://git.tuffraid.net/cowch/lst_v3/issues/14)
|
||||||
|
* **scanner:** changed to not crash on logging ([0de2579](https://git.tuffraid.net/cowch/lst_v3/commits/0de25799420f38a293ee9acc70eb36e3287145c4)), closes [#19](https://git.tuffraid.net/cowch/lst_v3/issues/19)
|
||||||
|
* **scanner:** fixes to be more clear that you need to scan a command to start ([0575879](https://git.tuffraid.net/cowch/lst_v3/commits/05758791be7a50e90b5da05d4977e618c311f654)), closes [#16](https://git.tuffraid.net/cowch/lst_v3/issues/16)
|
||||||
|
* **scanner:** logut out corrections ([85e96f5](https://git.tuffraid.net/cowch/lst_v3/commits/85e96f5ed13a81fd466c6bbff31c539244750838)), closes [#17](https://git.tuffraid.net/cowch/lst_v3/issues/17)
|
||||||
|
* **table:** skelly table causing hydration error ([1bbf5c2](https://git.tuffraid.net/cowch/lst_v3/commits/1bbf5c2a4955107a36ace05595886d19cc8e64f4))
|
||||||
|
|
||||||
|
|
||||||
|
### 📝 Chore
|
||||||
|
|
||||||
|
* **mobile:** removed console log that shouldnt be there ([9631736](https://git.tuffraid.net/cowch/lst_v3/commits/9631736e263ed00189f8118f686690cab25f09d3))
|
||||||
|
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
* **scanner:** added in instructions on how to update the scanner ([b0c7277](https://git.tuffraid.net/cowch/lst_v3/commits/b0c7277a6cdb5becec3a994ea1d5cc2d7b0326aa))
|
||||||
|
* **scanner:** added in westbend and dayton commands to scan for updates ([eb9d77c](https://git.tuffraid.net/cowch/lst_v3/commits/eb9d77c3d4767fd961759662ef44c3e09e00946b))
|
||||||
|
|
||||||
|
|
||||||
|
### 🛠️ Code Refactor
|
||||||
|
|
||||||
|
* **api:** changes to call a helper api to quit and redirect if needed ([c64392f](https://git.tuffraid.net/cowch/lst_v3/commits/c64392f45769108aa4134c7fd865f3d4bc664179))
|
||||||
|
* **app:** changed ways we get data so we can have better reasons why app no worky ([30ff7b7](https://git.tuffraid.net/cowch/lst_v3/commits/30ff7b71d9d159ced263a5330d70d53b97393157))
|
||||||
|
* **mobile:** scanner response ([a9c6925](https://git.tuffraid.net/cowch/lst_v3/commits/a9c69250bd3272ad682751e41b671c119cb678f1)), closes [#16](https://git.tuffraid.net/cowch/lst_v3/issues/16)
|
||||||
|
* **scanner:** logging - version of app ([d61be61](https://git.tuffraid.net/cowch/lst_v3/commits/d61be61f4433a2be2678d724f4724301931614c9))
|
||||||
|
* **scanner:** more scanner admin stuff ([eb950d2](https://git.tuffraid.net/cowch/lst_v3/commits/eb950d2c29f692b806d5cc4ab7014bd59a726a8d))
|
||||||
|
* **scanner:** removed 69 as an option lol ([e7af3d1](https://git.tuffraid.net/cowch/lst_v3/commits/e7af3d11824b42915cf6789f9c508a727511d678))
|
||||||
|
* **servers:** server name now links to the actual server:port ([ebf1060](https://git.tuffraid.net/cowch/lst_v3/commits/ebf1060475d37627b371bc6c79507cdde411600b))
|
||||||
|
* **users:** some user refactoring and configuring ([342a97f](https://git.tuffraid.net/cowch/lst_v3/commits/342a97f6b1054443b9126186d2c7872fbd8586da))
|
||||||
|
|
||||||
|
|
||||||
|
### 📈 Project changes
|
||||||
|
|
||||||
|
* **mobile:** added in ehs config to make it more easy for users to update the scanner app on the fly ([dc95e50](https://git.tuffraid.net/cowch/lst_v3/commits/dc95e50a8412b4fbc629fd44fcb5c77295583ca8))
|
||||||
|
* **notification:** removal of more console logs that shouldnt be here ([51026e3](https://git.tuffraid.net/cowch/lst_v3/commits/51026e3e2cce4d7f696d26aae305b3fd221f5bb1))
|
||||||
|
* **servives:** helpers moved around ([e9e73c8](https://git.tuffraid.net/cowch/lst_v3/commits/e9e73c829c2e5726650c0ac7ffa6a9055dbc982b))
|
||||||
|
* **updateserver:** changes to actually add the new env stuff ([bcb7773](https://git.tuffraid.net/cowch/lst_v3/commits/bcb7773007894ac2f85fe2a0b47faf14c7b474ad))
|
||||||
|
|
||||||
## [0.0.2-alpha.10](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.2-alpha.9...v0.0.2-alpha.10) (2026-05-08)
|
## [0.0.2-alpha.10](https://git.tuffraid.net/cowch/lst_v3/compare/v0.0.2-alpha.9...v0.0.2-alpha.10) (2026-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import build from "./admin.build.js";
|
import build from "./admin.build.js";
|
||||||
import update from "./admin.updateServer.js";
|
import update from "./admin.updateServer.js";
|
||||||
|
import users from "./admin.users.js";
|
||||||
|
|
||||||
export const setupAdminRoutes = (baseUrl: string, app: Express) => {
|
export const setupAdminRoutes = (baseUrl: string, app: Express) => {
|
||||||
//stats will be like this as we dont need to change this
|
//stats will be like this as we dont need to change this
|
||||||
app.use(`${baseUrl}/api/admin/build`, requireAuth, routeHitMiddleware, build);
|
|
||||||
app.use(
|
app.use(`${baseUrl}/api/admin/build`, requireAuth, build);
|
||||||
`${baseUrl}/api/admin/build`,
|
app.use(`${baseUrl}/api/admin/build`, requireAuth, update);
|
||||||
requireAuth,
|
app.use(`${baseUrl}/api/admin/user`, requireAuth, users);
|
||||||
routeHitMiddleware,
|
|
||||||
update,
|
|
||||||
);
|
|
||||||
|
|
||||||
// all other system should be under /api/system/*
|
// all other system should be under /api/system/*
|
||||||
};
|
};
|
||||||
|
|||||||
46
backend/admin/admin.users.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* To be able to run this we need to set our dev pc in the .env.
|
||||||
|
* if its empty just ignore it. this will just be the double catch
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fromNodeHeaders } from "better-auth/node";
|
||||||
|
import { Router } from "express";
|
||||||
|
import { auth } from "../utils/auth.utils.js";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
r.get("/", async (req, res) => {
|
||||||
|
const { users } = await auth.api.listUsers({
|
||||||
|
query: {
|
||||||
|
limit: 50,
|
||||||
|
},
|
||||||
|
headers: fromNodeHeaders(req.headers),
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log(error);
|
||||||
|
|
||||||
|
// if (error) {
|
||||||
|
// return apiReturn(res, {
|
||||||
|
// success: false,
|
||||||
|
// level: "info",
|
||||||
|
// module: "admin",
|
||||||
|
// subModule: "user",
|
||||||
|
// message: `There was an error getting the users.`,
|
||||||
|
// data: users,
|
||||||
|
// status: 400,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "admin",
|
||||||
|
subModule: "users",
|
||||||
|
message: `Current active users.`,
|
||||||
|
data: users,
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
@@ -5,6 +5,7 @@ import express from "express";
|
|||||||
import morgan from "morgan";
|
import morgan from "morgan";
|
||||||
import { umamiConfig } from "./configs/umami.config.js";
|
import { umamiConfig } from "./configs/umami.config.js";
|
||||||
import { createLogger } from "./logger/logger.controller.js";
|
import { createLogger } from "./logger/logger.controller.js";
|
||||||
|
import { routeHitMiddleware } from "./middleware/routeHit.middleware.js";
|
||||||
import { setupRoutes } from "./routeHandler.routes.js";
|
import { setupRoutes } from "./routeHandler.routes.js";
|
||||||
import { auth } from "./utils/auth.utils.js";
|
import { auth } from "./utils/auth.utils.js";
|
||||||
import { lstCors } from "./utils/cors.utils.js";
|
import { lstCors } from "./utils/cors.utils.js";
|
||||||
@@ -30,9 +31,9 @@ const createApp = async () => {
|
|||||||
app.use(morgan("dev"));
|
app.use(morgan("dev"));
|
||||||
app.set("trust proxy", true);
|
app.set("trust proxy", true);
|
||||||
app.use(lstCors());
|
app.use(lstCors());
|
||||||
|
app.use(routeHitMiddleware);
|
||||||
app.all(`${baseUrl}/api/auth/*splat`, toNodeHandler(auth));
|
app.all(`${baseUrl}/api/auth/*splat`, toNodeHandler(auth));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
setupRoutes(baseUrl, app);
|
|
||||||
|
|
||||||
app.get(`${baseUrl}/api/lst-config.js`, (_, res) => {
|
app.get(`${baseUrl}/api/lst-config.js`, (_, res) => {
|
||||||
res.type("application/javascript");
|
res.type("application/javascript");
|
||||||
@@ -50,6 +51,8 @@ const createApp = async () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setupRoutes(baseUrl, app);
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/app`,
|
`${baseUrl}/app`,
|
||||||
express.static(join(__dirname, "../frontend/dist")),
|
express.static(join(__dirname, "../frontend/dist")),
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import login from "./login.route.js";
|
import login from "./login.route.js";
|
||||||
import register from "./register.route.js";
|
import register from "./register.route.js";
|
||||||
|
|
||||||
export const setupAuthRoutes = (baseUrl: string, app: Express) => {
|
export const setupAuthRoutes = (baseUrl: string, app: Express) => {
|
||||||
//setup all the routes
|
//setup all the routes
|
||||||
app.use(routeHitMiddleware);
|
|
||||||
app.use(`${baseUrl}/api/authentication/login`, login);
|
app.use(`${baseUrl}/api/authentication/login`, login);
|
||||||
app.use(`${baseUrl}/api/authentication/register`, register);
|
app.use(`${baseUrl}/api/authentication/register`, register);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
import { datamartData } from "./datamartData.utlis.js";
|
import { datamartData } from "./datamartData.utlis.js";
|
||||||
import runQuery from "./getDatamart.route.js";
|
import runQuery from "./getDatamart.route.js";
|
||||||
@@ -30,7 +30,7 @@ export const setupDatamartRoutes = (baseUrl: string, app: Express) => {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
//setup all the routes
|
//setup all the routes
|
||||||
app.use(routeHitMiddleware);
|
|
||||||
app.use(`${baseUrl}/api/datamart`, runQuery);
|
app.use(`${baseUrl}/api/datamart`, runQuery);
|
||||||
|
|
||||||
// just sending a get on datamart will return all the queries that we can call.
|
// just sending a get on datamart will return all the queries that we can call.
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { drizzle } from "drizzle-orm/postgres-js";
|
import { drizzle } from "drizzle-orm/postgres-js";
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
|
import * as opendockAVCheck from "./schema/opendock_articleSetup.js";
|
||||||
import * as scanUserSchema from "./schema/scanUsers.js";
|
import * as scanUserSchema from "./schema/scanUsers.js";
|
||||||
|
import * as settingsSchema from "./schema/settings.schema.js";
|
||||||
|
|
||||||
const dbURL = `postgres://${process.env.DATABASE_USER}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_DB}`;
|
const dbURL = `postgres://${process.env.DATABASE_USER}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}:${process.env.DATABASE_PORT}/${process.env.DATABASE_DB}`;
|
||||||
|
|
||||||
@@ -20,5 +21,7 @@ const queryClient = postgres(dbURL, {
|
|||||||
export const db = drizzle(queryClient, {
|
export const db = drizzle(queryClient, {
|
||||||
schema: {
|
schema: {
|
||||||
...scanUserSchema,
|
...scanUserSchema,
|
||||||
|
...settingsSchema,
|
||||||
|
...opendockAVCheck,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,30 +4,42 @@ import {
|
|||||||
pgTable,
|
pgTable,
|
||||||
text,
|
text,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
unique,
|
||||||
uuid,
|
uuid,
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
export const analyticsDaily = pgTable("analytics_daily", {
|
export const analyticsDaily = pgTable(
|
||||||
id: uuid("id").defaultRandom().primaryKey(),
|
"analytics_daily",
|
||||||
|
{
|
||||||
|
id: uuid("id").defaultRandom().primaryKey(),
|
||||||
|
|
||||||
businessDate: date("business_date").notNull(),
|
businessDate: date("business_date", { mode: "string" }).notNull(),
|
||||||
|
|
||||||
method: text("method").notNull(),
|
method: text("method").notNull(),
|
||||||
routePattern: text("route_pattern").notNull(),
|
routePattern: text("route_pattern").notNull(),
|
||||||
module: text("module").notNull(),
|
module: text("module").notNull(),
|
||||||
|
|
||||||
totalHits: integer("total_hits").notNull(),
|
totalHits: integer("total_hits").notNull(),
|
||||||
uniqueUsers: integer("unique_users").notNull(),
|
uniqueUsers: integer("unique_users").notNull(),
|
||||||
|
|
||||||
successCount: integer("success_count").notNull(),
|
successCount: integer("success_count").notNull(),
|
||||||
errorCount: integer("error_count").notNull(),
|
errorCount: integer("error_count").notNull(),
|
||||||
|
|
||||||
avgDurationMs: integer("avg_duration_ms").notNull(),
|
avgDurationMs: integer("avg_duration_ms").notNull(),
|
||||||
maxDurationMs: integer("max_duration_ms").notNull(),
|
maxDurationMs: integer("max_duration_ms").notNull(),
|
||||||
|
|
||||||
firstHitAt: timestamp("first_hit_at").notNull(),
|
firstHitAt: timestamp("first_hit_at").notNull(),
|
||||||
lastHitAt: timestamp("last_hit_at").notNull(),
|
lastHitAt: timestamp("last_hit_at").notNull(),
|
||||||
|
|
||||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||||
});
|
},
|
||||||
|
(table) => [
|
||||||
|
unique("analytics_daily_business_route_unique").on(
|
||||||
|
table.businessDate,
|
||||||
|
table.method,
|
||||||
|
table.routePattern,
|
||||||
|
table.module,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
22
backend/db/schema/dockdoor.schema.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { boolean, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import type { z } from "zod";
|
||||||
|
|
||||||
|
export const dockDoorScanners = pgTable("dock_door_scanners", {
|
||||||
|
id: uuid("id").defaultRandom().primaryKey(),
|
||||||
|
ip: text("ip").notNull(),
|
||||||
|
name: text("name").unique(),
|
||||||
|
dockId: text("dock_id"),
|
||||||
|
active: boolean("active").default(true),
|
||||||
|
currentLoadingOrder: text("current_loading_order").default(""),
|
||||||
|
add_date: timestamp("add_date").defaultNow(),
|
||||||
|
add_user: text("add_user").default("lst-system"),
|
||||||
|
upd_date: timestamp("upd_date").defaultNow(),
|
||||||
|
upd_user: text("upd_user").default("lst-system"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const dockDoorScannersSchema = createSelectSchema(dockDoorScanners);
|
||||||
|
export const newDockDoorScannersSchema = createInsertSchema(dockDoorScanners);
|
||||||
|
|
||||||
|
export type DockDoorScanners = z.infer<typeof dockDoorScannersSchema>;
|
||||||
|
export type NewDockDoorScanners = z.infer<typeof newDockDoorScannersSchema>;
|
||||||
@@ -14,14 +14,13 @@ export const opendockApt = pgTable(
|
|||||||
"opendock_apt",
|
"opendock_apt",
|
||||||
{
|
{
|
||||||
id: uuid("id").defaultRandom().primaryKey(),
|
id: uuid("id").defaultRandom().primaryKey(),
|
||||||
release: integer("release").notNull().unique(),
|
release: integer("release").notNull().unique("opendock_apt_release_unique"),
|
||||||
openDockAptId: text("open_dock_apt_id").notNull(),
|
openDockAptId: text("open_dock_apt_id").notNull(),
|
||||||
appointment: jsonb("appointment").notNull().default([]),
|
appointment: jsonb("appointment").notNull().default([]),
|
||||||
upd_date: timestamp("upd_date").notNull().defaultNow(),
|
upd_date: timestamp("upd_date").notNull().defaultNow(),
|
||||||
createdAt: timestamp("created_at").notNull().defaultNow(),
|
createdAt: timestamp("created_at").notNull().defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => ({
|
(table) => ({
|
||||||
releaseIdx: index("opendock_apt_release_idx").on(table.release),
|
|
||||||
openDockAptIdIdx: index("opendock_apt_opendock_id_idx").on(
|
openDockAptIdIdx: index("opendock_apt_opendock_id_idx").on(
|
||||||
table.openDockAptId,
|
table.openDockAptId,
|
||||||
),
|
),
|
||||||
46
backend/db/schema/opendock_articleSetup.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import {
|
||||||
|
integer,
|
||||||
|
pgEnum,
|
||||||
|
pgTable,
|
||||||
|
text,
|
||||||
|
timestamp,
|
||||||
|
unique,
|
||||||
|
uuid,
|
||||||
|
} from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import type { z } from "zod";
|
||||||
|
|
||||||
|
export const loadTypeEnum = pgEnum("load_type", ["drop", "live"]);
|
||||||
|
|
||||||
|
export const opendockArticleSetup = pgTable(
|
||||||
|
"opendock_article_setup",
|
||||||
|
{
|
||||||
|
id: uuid("id").defaultRandom().primaryKey(),
|
||||||
|
av: integer("av").notNull(),
|
||||||
|
description: text("description").notNull(),
|
||||||
|
customer: text("customer").notNull(), // customer should be a concat of the ID - Desc
|
||||||
|
customerDescription: text("customer_description").notNull(),
|
||||||
|
loadType: loadTypeEnum("load_type").notNull().default("drop"),
|
||||||
|
dock: text("dock").notNull(),
|
||||||
|
upd_date: timestamp("upd_date").notNull().defaultNow(),
|
||||||
|
upd_user: text("upd_user").notNull().default("lst-system"),
|
||||||
|
createdAt: timestamp("created_at").notNull().defaultNow(),
|
||||||
|
add_user: text("add_user").notNull().default("lst-system"),
|
||||||
|
},
|
||||||
|
(table) => ({
|
||||||
|
uniqueAvCustomer: unique("uq_opendock_article_setup_av_customer").on(
|
||||||
|
table.av,
|
||||||
|
table.customer,
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const opendockArticleSetupSchema =
|
||||||
|
createSelectSchema(opendockArticleSetup);
|
||||||
|
export const newOpendockArticleSetupSchema =
|
||||||
|
createInsertSchema(opendockArticleSetup);
|
||||||
|
|
||||||
|
export type OpendockArticleSetup = z.infer<typeof opendockArticleSetupSchema>;
|
||||||
|
export type NewOpendockArticleSetup = z.infer<
|
||||||
|
typeof newOpendockArticleSetupSchema
|
||||||
|
>;
|
||||||
21
backend/db/schema/opendock_docks.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
||||||
|
import type { z } from "zod";
|
||||||
|
|
||||||
|
export const opendockDockSetup = pgTable("opendock_dock_setup", {
|
||||||
|
id: uuid("id").defaultRandom().primaryKey(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
dockID: text("dock_id").notNull(),
|
||||||
|
upd_date: timestamp("upd_date").notNull().defaultNow(),
|
||||||
|
upd_user: text("upd_user").notNull().default("lst-system"),
|
||||||
|
createdAt: timestamp("created_at").notNull().defaultNow(),
|
||||||
|
add_user: text("add_user").notNull().default("lst-system"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const opendockDockSetupSchema = createSelectSchema(opendockDockSetup);
|
||||||
|
export const newOpendockDockSetupSchema = createInsertSchema(opendockDockSetup);
|
||||||
|
|
||||||
|
export type OpendockArticleSetup = z.infer<typeof opendockDockSetupSchema>;
|
||||||
|
export type NewOpendockArticleSetup = z.infer<
|
||||||
|
typeof newOpendockDockSetupSchema
|
||||||
|
>;
|
||||||
@@ -11,6 +11,7 @@ export const scanLog = pgTable("scan_log", {
|
|||||||
commandDescription: text("command_description"),
|
commandDescription: text("command_description"),
|
||||||
runningNumber: text("running_number").default("0"),
|
runningNumber: text("running_number").default("0"),
|
||||||
status: text("status"),
|
status: text("status"),
|
||||||
|
scannerVersion: text("scanner_version").default("0"),
|
||||||
lines: jsonb("lines").default([]),
|
lines: jsonb("lines").default([]),
|
||||||
add_Date: timestamp("add_date").defaultNow(),
|
add_Date: timestamp("add_date").defaultNow(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const settings = pgTable(
|
|||||||
},
|
},
|
||||||
(table) => [
|
(table) => [
|
||||||
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||||
uniqueIndex("name").on(table.name),
|
uniqueIndex("settings_name_unique").on(table.name),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { addDays, subDays } from "date-fns";
|
||||||
|
import { format } from "date-fns-tz";
|
||||||
|
import { Router } from "express";
|
||||||
|
import { runProdApi } from "../utils/prodEndpoint.utils.js";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
r.get("/", async (_, res) => {
|
||||||
|
const orders = await runProdApi({
|
||||||
|
method: "post",
|
||||||
|
endpoint: "/public/v1.0/OutboundDeliveries/LoadingOrders/Search",
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
loadingDateFrom: format(subDays(new Date(Date.now()), 3), "yyyy-MM-dd"),
|
||||||
|
loadingDateTo: format(addDays(new Date(Date.now()), 3), "yyyy-MM-dd"),
|
||||||
|
states: [
|
||||||
|
1, // planned
|
||||||
|
],
|
||||||
|
//isCommissioned: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "current Active loading orders",
|
||||||
|
message: `Current active loading loaders.`,
|
||||||
|
data: orders?.data ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
18
backend/dockdoorScanning/dockdoor.closeLoadingOrder.route.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
r.post("/", async (req, res) => {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "lane check",
|
||||||
|
message: `Release x is being closed now. the bol should come out at the default printer.`,
|
||||||
|
data: req.body ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
89
backend/dockdoorScanning/dockdoor.loadUnits.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// sends the units from the dock door scanner here.
|
||||||
|
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { db } from "../db/db.controller.js";
|
||||||
|
import { dockDoorScanners } from "../db/schema/dockdoor.schema.js";
|
||||||
|
import { runProdApi } from "../utils/prodEndpoint.utils.js";
|
||||||
|
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||||
|
|
||||||
|
// validate we are active
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
dockId?: string;
|
||||||
|
sscc?: string;
|
||||||
|
runningNr?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadUnit = async (data: Data) => {
|
||||||
|
// are we even active at this time?
|
||||||
|
const dockDoorActive = await db.query.settings.findFirst({
|
||||||
|
where: (u, { eq }) => eq(u.name, "dockDoorScanning"),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!dockDoorActive?.active) {
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "loadunit",
|
||||||
|
message: "Dock door scanning feature is not active.",
|
||||||
|
data: [],
|
||||||
|
notify: false,
|
||||||
|
room: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// check if its a valids an sscc
|
||||||
|
|
||||||
|
if (data.sscc === "noread") {
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "loadUnit",
|
||||||
|
message:
|
||||||
|
"Failed to load the unit to the truck, there was no pallet read.",
|
||||||
|
data: [],
|
||||||
|
notify: false,
|
||||||
|
room: `dockDoorLoading${data.dockId}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we currently have a loading order attached to the dock door.
|
||||||
|
const dock = await db
|
||||||
|
.select()
|
||||||
|
.from(dockDoorScanners)
|
||||||
|
.where(eq(dockDoorScanners.dockId, data.dockId as string));
|
||||||
|
|
||||||
|
if (dock[0]?.currentLoadingOrder === "") {
|
||||||
|
return returnFunc({
|
||||||
|
success: true,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "loadingOrders",
|
||||||
|
message:
|
||||||
|
"There are know current active loading orders please start one and try again.",
|
||||||
|
data: [],
|
||||||
|
notify: false,
|
||||||
|
room: `dockDoorLoading${data.dockId}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: pallet validation, check if we are on hold, then check if we have been in the staging warehouse for more than x time.
|
||||||
|
|
||||||
|
// if on hold stop the scan and send a bad read with the reason its on hold and what its on hold for, including coa.
|
||||||
|
|
||||||
|
// if precheck is active then check if we have a warehouse, then check if the pallet was in the warehouse for greater than the define min, all fails send a warning and still do the scan
|
||||||
|
|
||||||
|
// add the loading units
|
||||||
|
try {
|
||||||
|
const prod = await runProdApi({
|
||||||
|
method: "post",
|
||||||
|
endpoint: `/public/v1.0/OutboundDeliveries/LoadingOrders/${dock[0]?.currentLoadingOrder}/LoadUnit`,
|
||||||
|
data: [{ sscc: data.sscc?.slice(2) }],
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(prod?.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
43
backend/dockdoorScanning/dockdoor.routes.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import type { Express } from "express";
|
||||||
|
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
||||||
|
import activeLoadingOrders from "./dockdoor.activeLoadingOrders.route.js";
|
||||||
|
import closeLoadingOrder from "./dockdoor.closeLoadingOrder.route.js";
|
||||||
|
import startLoad from "./dockdoor.startLoad.route.js";
|
||||||
|
import prodDocks from "./dockdoors.docks.route.js";
|
||||||
|
import docks from "./dockdoors.route.js";
|
||||||
|
|
||||||
|
export const setupDockDoorRoutes = (baseUrl: string, app: Express) => {
|
||||||
|
//stats will be like this as we dont need to change this
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
`${baseUrl}/api/dockDoor/scanners`,
|
||||||
|
featureCheck("dockDoorScanning"),
|
||||||
|
|
||||||
|
docks,
|
||||||
|
);
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
`${baseUrl}/api/dockDoor/closeLoadingOrder`,
|
||||||
|
featureCheck("dockDoorScanning"),
|
||||||
|
closeLoadingOrder,
|
||||||
|
);
|
||||||
|
app.use(
|
||||||
|
`${baseUrl}/api/dockDoor/activeLoadingOrders`,
|
||||||
|
featureCheck("dockDoorScanning"),
|
||||||
|
activeLoadingOrders,
|
||||||
|
);
|
||||||
|
app.use(
|
||||||
|
`${baseUrl}/api/dockDoor/startLoad`,
|
||||||
|
featureCheck("dockDoorScanning"),
|
||||||
|
startLoad,
|
||||||
|
);
|
||||||
|
app.use(
|
||||||
|
`${baseUrl}/api/dockDoor/docks`,
|
||||||
|
featureCheck("dockDoorScanning"),
|
||||||
|
prodDocks,
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO : add manual way to add pallets
|
||||||
|
|
||||||
|
// all other system should be under /api/system/*
|
||||||
|
};
|
||||||
65
backend/dockdoorScanning/dockdoor.startLoad.route.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { sql } from "drizzle-orm";
|
||||||
|
import { Router } from "express";
|
||||||
|
import z from "zod";
|
||||||
|
import { db } from "../db/db.controller.js";
|
||||||
|
import { dockDoorScanners } from "../db/schema/dockdoor.schema.js";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
const startLoading = z.object({
|
||||||
|
loadingOrder: z.string(),
|
||||||
|
dockId: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
r.post("/", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const validated = startLoading.parse(req.body);
|
||||||
|
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
db
|
||||||
|
.update(dockDoorScanners)
|
||||||
|
.set({
|
||||||
|
currentLoadingOrder: validated.loadingOrder,
|
||||||
|
upd_date: sql`NOW()`,
|
||||||
|
upd_user: req.user?.username,
|
||||||
|
})
|
||||||
|
.returning(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "loadingOrder",
|
||||||
|
message: `Failed to updating the dock.`,
|
||||||
|
data: (error as any) ?? [],
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "loadingOrder",
|
||||||
|
message: `Loading order ${validated.loadingOrder} was just added to dockId ${validated.dockId}.`,
|
||||||
|
data: data ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "loadingOrder",
|
||||||
|
message: `Failed to start loading order.`,
|
||||||
|
data: (error as any) ?? [],
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
54
backend/dockdoorScanning/dockdoors.docks.route.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||||
|
import {
|
||||||
|
type SqlQuery,
|
||||||
|
sqlQuerySelector,
|
||||||
|
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
r.get("/", async (_, res) => {
|
||||||
|
const activeDocks = sqlQuerySelector(`outbound.docks`) as SqlQuery;
|
||||||
|
|
||||||
|
if (!activeDocks.success) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "docks",
|
||||||
|
message: `There was an error getting the docks query.`,
|
||||||
|
data: [],
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, error } = await tryCatch(
|
||||||
|
prodQuery(activeDocks.query, "Current Active Docks"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "newDock",
|
||||||
|
message: `There was an error getting the docks.`,
|
||||||
|
data: (error as any) ?? ([] as any),
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "docks",
|
||||||
|
message: `Current active docks.`,
|
||||||
|
data: (data.data as any) ?? ([] as any),
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
76
backend/dockdoorScanning/dockdoors.route.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import z from "zod";
|
||||||
|
import { db } from "../db/db.controller.js";
|
||||||
|
import { dockDoorScanners } from "../db/schema/dockdoor.schema.js";
|
||||||
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
const newDockScanner = z.object({
|
||||||
|
ip: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
dockId: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
r.get("/", async (_, res) => {
|
||||||
|
try {
|
||||||
|
const docks = await db
|
||||||
|
.select()
|
||||||
|
.from(dockDoorScanners)
|
||||||
|
.orderBy(dockDoorScanners.name);
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "lane check",
|
||||||
|
message: `All dock Doors.`,
|
||||||
|
data: docks ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "newDock",
|
||||||
|
message: `There was an error adding in the new dock.`,
|
||||||
|
data: error ?? ([] as any),
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
r.post("/", requireAuth, async (req, res) => {
|
||||||
|
try {
|
||||||
|
const validated = newDockScanner.parse(req.body);
|
||||||
|
|
||||||
|
const newDock = await db
|
||||||
|
.insert(dockDoorScanners)
|
||||||
|
.values(validated)
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "lane check",
|
||||||
|
message: `${validated.name} was just added.`,
|
||||||
|
data: newDock ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "dockdoor",
|
||||||
|
subModule: "newDock",
|
||||||
|
message: `There was an error adding in the new dock.`,
|
||||||
|
data: error ?? ([] as any),
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type Express, Router } from "express";
|
import { type Express, Router } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import restart from "./gpSqlRestart.route.js";
|
import restart from "./gpSqlRestart.route.js";
|
||||||
import start from "./gpSqlStart.route.js";
|
import start from "./gpSqlStart.route.js";
|
||||||
import stop from "./gpSqlStop.route.js";
|
import stop from "./gpSqlStop.route.js";
|
||||||
@@ -8,12 +8,10 @@ export const setupGPSqlRoutes = (baseUrl: string, app: Express) => {
|
|||||||
//setup all the routes
|
//setup all the routes
|
||||||
// Apply auth to entire router
|
// Apply auth to entire router
|
||||||
const router = Router();
|
const router = Router();
|
||||||
router.use(requireAuth);
|
|
||||||
app.use(routeHitMiddleware);
|
|
||||||
|
|
||||||
router.use(start);
|
router.use(start);
|
||||||
router.use(stop);
|
router.use(stop);
|
||||||
router.use(restart);
|
router.use(restart);
|
||||||
|
|
||||||
app.use(`${baseUrl}/api/system/gpSql`, router);
|
app.use(`${baseUrl}/api/system/gpSql`, requireAuth, router);
|
||||||
};
|
};
|
||||||
|
|||||||
54
backend/mobile/availableScanIds.route.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import { Router } from "express";
|
||||||
|
import { db } from "../db/db.controller.js";
|
||||||
|
import { scanUser } from "../db/schema/scanUsers.js";
|
||||||
|
import { settings } from "../db/schema/settings.schema.js";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
// scanners that are dedicated to specific users.
|
||||||
|
const SPECIAL_SCANNERS = [98];
|
||||||
|
|
||||||
|
const buildAllowedScannerIds = (scannerCount: number) => {
|
||||||
|
const generatedIds = Array.from({ length: scannerCount }, (_, i) => i + 1);
|
||||||
|
|
||||||
|
return Array.from(new Set([...generatedIds, ...SPECIAL_SCANNERS])).sort(
|
||||||
|
(a, b) => a - b,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
r.get("/", async (_, res) => {
|
||||||
|
// get the scan users and setting
|
||||||
|
const scanusers = await db.select().from(scanUser);
|
||||||
|
const scannerIdSetting = await db
|
||||||
|
.select()
|
||||||
|
.from(settings)
|
||||||
|
.where(eq(settings.name, "scannerIds"));
|
||||||
|
|
||||||
|
const usedScannerIds = scanusers.map((x) => Number(x.scannerId));
|
||||||
|
const allowedScannerIds = buildAllowedScannerIds(
|
||||||
|
Number(scannerIdSetting[0]?.value ?? 0),
|
||||||
|
);
|
||||||
|
|
||||||
|
const availableScannerIds = allowedScannerIds.filter(
|
||||||
|
(id) => !usedScannerIds.includes(id),
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = availableScannerIds.map((id) => ({
|
||||||
|
label: `${id}`,
|
||||||
|
value: id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "mobile",
|
||||||
|
subModule: "scanner",
|
||||||
|
message: `There are ${availableScannerIds.length} scanner id's`,
|
||||||
|
data,
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
@@ -38,7 +38,86 @@ router.get("/ehs", (_, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.setHeader("Content-Type", "application/vnd.android.package-archive");
|
res.setHeader("Content-Type", "application/vnd.android.package-archive");
|
||||||
res.setHeader("Content-Disposition", `attachment; filename="EHS.apk}"`);
|
res.setHeader("Content-Disposition", `attachment; filename="EHS.apk"`);
|
||||||
|
|
||||||
|
return res.sendFile(apkPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/ehs/xml", (_, res) => {
|
||||||
|
const xmlPath = path.join(downloadDir, "enterprisehomescreen.xml");
|
||||||
|
|
||||||
|
if (!fs.existsSync(xmlPath)) {
|
||||||
|
return res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: "EHS XML not found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setHeader("Content-Type", "application/xml");
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Disposition",
|
||||||
|
`attachment; filename="enterprisehomescreen.xml"`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.sendFile(xmlPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/android/upgrade/11", (_, res) => {
|
||||||
|
const apkPath = path.join(
|
||||||
|
downloadDir,
|
||||||
|
"HE_FULL_UPDATE_11-70-20.00-RG-U00-STD-HEL-04.zip",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!fs.existsSync(apkPath)) {
|
||||||
|
return res.status(404).json({ success: false, message: "APK not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
//res.setHeader("Content-Type", "application/vnd.android.package-archive");
|
||||||
|
res.setHeader("Content-Type", "application/zip");
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Disposition",
|
||||||
|
`attachment; filename="HE_FULL_UPDATE_11.zip"`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.sendFile(apkPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/android/upgrade/13", (_, res) => {
|
||||||
|
const apkPath = path.join(
|
||||||
|
downloadDir,
|
||||||
|
"HE_FULL_UPDATE_13-51-16.00-TG-U00-STD-HEL-04.zip",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!fs.existsSync(apkPath)) {
|
||||||
|
return res.status(404).json({ success: false, message: "APK not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
//res.setHeader("Content-Type", "application/vnd.android.package-archive");
|
||||||
|
res.setHeader("Content-Type", "application/zip");
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Disposition",
|
||||||
|
`attachment; filename="HE_FULL_UPDATE_13.zip"`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.sendFile(apkPath);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/android/upgrade/14", (_, res) => {
|
||||||
|
const apkPath = path.join(
|
||||||
|
downloadDir,
|
||||||
|
"HE_FULL_UPDATE_14-38-04.00-UG-U15-STD-HEL-04.zip",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!fs.existsSync(apkPath)) {
|
||||||
|
return res.status(404).json({ success: false, message: "APK not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
//res.setHeader("Content-Type", "application/vnd.android.package-archive");
|
||||||
|
res.setHeader("Content-Type", "application/zip");
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Disposition",
|
||||||
|
`attachment; filename="HE_FULL_UPDATE_14.zip"`,
|
||||||
|
);
|
||||||
|
|
||||||
return res.sendFile(apkPath);
|
return res.sendFile(apkPath);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||||
|
import {
|
||||||
|
type SqlQuery,
|
||||||
|
sqlQuerySelector,
|
||||||
|
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||||
import { runProdApi } from "../utils/prodEndpoint.utils.js";
|
import { runProdApi } from "../utils/prodEndpoint.utils.js";
|
||||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
import { apiReturn, returnFunc } from "../utils/returnHelper.utils.js";
|
||||||
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
@@ -9,7 +15,27 @@ router.post("/", async (req, res) => {
|
|||||||
|
|
||||||
const lane = body.lane.split("#");
|
const lane = body.lane.split("#");
|
||||||
|
|
||||||
console.log(lane[2]);
|
// check if the plant has warehousing activated
|
||||||
|
const featureQ = sqlQuerySelector(`featureCheck`) as SqlQuery;
|
||||||
|
|
||||||
|
const { data: fd, error: fe } = await tryCatch(
|
||||||
|
prodQuery(featureQ.query, `Running feature check`),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fe) {
|
||||||
|
return returnFunc({
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "datamart",
|
||||||
|
subModule: "query",
|
||||||
|
message: `feature check failed`,
|
||||||
|
data: fe as any,
|
||||||
|
notify: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(fd);
|
||||||
|
|
||||||
const laneData = await runProdApi({
|
const laneData = await runProdApi({
|
||||||
method: "post",
|
method: "post",
|
||||||
endpoint: "/public/v1.1/Warehousing/GetWarehouseUnits",
|
endpoint: "/public/v1.1/Warehousing/GetWarehouseUnits",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
||||||
|
import available from "./availableScanIds.route.js";
|
||||||
import downloads from "./downloadApps.route.js";
|
import downloads from "./downloadApps.route.js";
|
||||||
import lanes from "./laneCheck.js";
|
import lanes from "./laneCheck.js";
|
||||||
import authPin from "./mobileAuth.route.js";
|
import authPin from "./mobileAuth.route.js";
|
||||||
@@ -10,14 +11,13 @@ import version from "./version.route.js";
|
|||||||
export const setupMobileRoutes = (baseUrl: string, app: Express) => {
|
export const setupMobileRoutes = (baseUrl: string, app: Express) => {
|
||||||
//stats will be like this as we dont need to change this
|
//stats will be like this as we dont need to change this
|
||||||
|
|
||||||
app.use(routeHitMiddleware);
|
app.use(`${baseUrl}/api/mobile/version`, featureCheck("mobile"), version);
|
||||||
|
app.use(`${baseUrl}/api/mobile/apk`, featureCheck("mobile"), downloads);
|
||||||
app.use(`${baseUrl}/api/mobile/version`, version);
|
app.use(`${baseUrl}/api/mobile/logs`, featureCheck("mobile"), logs);
|
||||||
app.use(`${baseUrl}/api/mobile/apk`, downloads);
|
app.use(`${baseUrl}/api/mobile/auth`, featureCheck("mobile"), authPin);
|
||||||
app.use(`${baseUrl}/api/mobile/logs`, logs);
|
app.use(`${baseUrl}/api/mobile/pin`, featureCheck("mobile"), newPin);
|
||||||
app.use(`${baseUrl}/api/mobile/auth`, authPin);
|
app.use(`${baseUrl}/api/mobile/laneCheck`, featureCheck("mobile"), lanes);
|
||||||
app.use(`${baseUrl}/api/mobile/pin`, newPin);
|
app.use(`${baseUrl}/api/mobile/available`, featureCheck("mobile"), available);
|
||||||
app.use(`${baseUrl}/api/mobile/laneCheck`, lanes);
|
|
||||||
|
|
||||||
// all other system should be under /api/system/*
|
// all other system should be under /api/system/*
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +1,34 @@
|
|||||||
|
import { eq, sql } from "drizzle-orm";
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
|
||||||
import { db } from "../db/db.controller.js";
|
import { db } from "../db/db.controller.js";
|
||||||
import { scanLog } from "../db/schema/scanlog.schema.js";
|
import { scanLog } from "../db/schema/scanlog.schema.js";
|
||||||
|
import { scanUser } from "../db/schema/scanUsers.js";
|
||||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.post("/", async (req, res) => {
|
router.post("/", async (req, res) => {
|
||||||
const body = req.body;
|
const body = req.body;
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.update(scanUser)
|
||||||
|
.set({ lastScan: sql`NOW()` })
|
||||||
|
.where(eq(scanUser.name, body.user));
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
const newLog = await db
|
const newLog = await db
|
||||||
.insert(scanLog)
|
.insert(scanLog)
|
||||||
.values({
|
.values({
|
||||||
scannerId: body.scannerId,
|
scannerId: body.scannerId ?? "",
|
||||||
message: body.message,
|
message: body.message ?? "",
|
||||||
prompt: body.prompt,
|
prompt: body.prompt ?? "",
|
||||||
commandDescription: body.commandDescription,
|
commandDescription: body.commandDescription ?? "",
|
||||||
status: body.status,
|
status: body.status ?? "",
|
||||||
lines: body.lines,
|
lines: body.lines ?? "",
|
||||||
user: body.user,
|
user: body.user ?? "",
|
||||||
runningNumber: body.runningNumber,
|
runningNumber: body.runningNumber ?? "",
|
||||||
|
scannerVersion: body.scannerVersion ?? "0",
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
|
|||||||
80
backend/notification/notification.SqlJobCleanUp.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||||
|
import {
|
||||||
|
type SqlQuery,
|
||||||
|
sqlQuerySelector,
|
||||||
|
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||||
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
|
// disable the jobs
|
||||||
|
const jobNames: string[] = [
|
||||||
|
"monitor_$_lots",
|
||||||
|
"monitor_$_lots_2",
|
||||||
|
"monitor$lots",
|
||||||
|
"Monitor_APO", //listen for people to cry this is no longer a thing
|
||||||
|
"Monitor_APO2",
|
||||||
|
"Monitor_AutoConsumeMaterials", // TODO: migrate to lst
|
||||||
|
"Monitor_AutoConsumeMaterials_iow1",
|
||||||
|
"Monitor_AutoConsumeMaterials_iow2",
|
||||||
|
"Monitor_BlockedINV_Loc",
|
||||||
|
"monitor_inv_cycle",
|
||||||
|
"monitor_inv_cycle_1",
|
||||||
|
"monitor_inv_cycle_2",
|
||||||
|
"monitor_edi_import", // TODO: migrate to lst -- for the query select count(*) from AlplaPROD_test3.dbo.T_EDIDokumente (nolock) where /* IdLieferant > 1 and */ add_date > DATEADD(MINUTE, -30, getdate())
|
||||||
|
"Monitor_Lot_Progression",
|
||||||
|
"Monitor_Lots", // TODO: migrate to lst -- this should be the one where we monitor the when a lot is assigned if its missing some data.
|
||||||
|
"Monitor_MinMax", // TODO:Migrate to lst
|
||||||
|
"Monitor_MinMax_iow2",
|
||||||
|
"Monitor_PM",
|
||||||
|
"Monitor_Purity",
|
||||||
|
"monitor_wastebookings", // TODO: Migrate
|
||||||
|
"LastPriceUpdate", // not even sure what this is
|
||||||
|
"GETLabelsCount", // seems like an old jc job
|
||||||
|
"jobforpuritycount", // was not even working correctly
|
||||||
|
"Monitor_EmptyAutoConsumLocations", // not sure who uses this one
|
||||||
|
"monitor_labelreprint", // Migrated but need to find out who really wants this
|
||||||
|
"test", // not even sure why this is active
|
||||||
|
"UpdateLastMoldUsed", // old jc inserts data into a table but not sure what its used for not linked to any other alert
|
||||||
|
"UpdateWhsePositions3", // old jc inserts data into a table but not sure what its used for not linked to any other alert
|
||||||
|
"UpdateWhsePositions4",
|
||||||
|
"delete_print", // i think this was in here for when we was having lag prints in iowa1
|
||||||
|
"INV_WHSE_1", // something random i wrote long time ago looks like an inv thing to see aged stuff
|
||||||
|
"INV_WHSE_2",
|
||||||
|
"laneAgeCheck", // another strange one thats been since moved to lst
|
||||||
|
"monitor_blocking_2",
|
||||||
|
"monitor_blocking", // already in lst
|
||||||
|
"monitor_min_inv", // do we still want this one? it has a description of: this checks m-f the min inventory of materials based on the min level set in stock
|
||||||
|
"Monitor_MixedLocations",
|
||||||
|
"Monitor_PM",
|
||||||
|
"Monitor_PM2",
|
||||||
|
"wrong_lots_1",
|
||||||
|
"wrong_lots_2",
|
||||||
|
"invenotry check", // spelling error one of my stupids
|
||||||
|
"monitor_hold_monitor",
|
||||||
|
"Monitor_Silo_adjustments",
|
||||||
|
"monitor_qualityLocMonitor", // validating with lima this is still needed
|
||||||
|
"Monitor_Stock_Change",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const sqlJobCleanUp = async () => {
|
||||||
|
// running a query to disable jobs that are moved to lst to be better maintained
|
||||||
|
const sqlQuery = sqlQuerySelector("disableJob") as SqlQuery;
|
||||||
|
|
||||||
|
if (!sqlQuery.success) {
|
||||||
|
console.error("Failed to load the query: ", sqlQuery.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const job of jobNames) {
|
||||||
|
const { error } = await tryCatch(
|
||||||
|
prodQuery(
|
||||||
|
sqlQuery.query.replace("[jobName]", `${job}`),
|
||||||
|
`Disabling job: ${job}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import manual from "./notification.manualTrigger.js";
|
import manual from "./notification.manualTrigger.js";
|
||||||
import getNotifications from "./notification.route.js";
|
import getNotifications from "./notification.route.js";
|
||||||
import updateNote from "./notification.update.route.js";
|
import updateNote from "./notification.update.route.js";
|
||||||
@@ -14,43 +14,43 @@ export const setupNotificationRoutes = (baseUrl: string, app: Express) => {
|
|||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/notification`,
|
`${baseUrl}/api/notification`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
getNotifications,
|
getNotifications,
|
||||||
);
|
);
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/notification`,
|
`${baseUrl}/api/notification`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
updateNote,
|
updateNote,
|
||||||
);
|
);
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/notification/manual`,
|
`${baseUrl}/api/notification/manual`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
manual,
|
manual,
|
||||||
);
|
);
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/notification/sub`,
|
`${baseUrl}/api/notification/sub`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
subs,
|
subs,
|
||||||
);
|
);
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/notification/sub`,
|
`${baseUrl}/api/notification/sub`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
newSub,
|
newSub,
|
||||||
);
|
);
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/notification/sub`,
|
`${baseUrl}/api/notification/sub`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
updateSub,
|
updateSub,
|
||||||
);
|
);
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/notification/sub`,
|
`${baseUrl}/api/notification/sub`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
deleteSub,
|
deleteSub,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const parseZebraAlert = (body: any): PrinterEvent => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
r.post("/printer/listener/:printer", upload.any(), async (req, res) => {
|
r.post("/:printer", upload.any(), async (req, res) => {
|
||||||
const { printer: printerName } = req.params;
|
const { printer: printerName } = req.params;
|
||||||
const event: PrinterEvent = parseZebraAlert(req.body);
|
const event: PrinterEvent = parseZebraAlert(req.body);
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { printerSync } from "./ocp.printer.manage.js";
|
|||||||
|
|
||||||
const r = Router();
|
const r = Router();
|
||||||
|
|
||||||
r.post("/printer/update", async (_, res) => {
|
r.post("/update", async (_, res) => {
|
||||||
printerSync();
|
printerSync();
|
||||||
return apiReturn(res, {
|
return apiReturn(res, {
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -1,27 +1,16 @@
|
|||||||
import { type Express, Router } from "express";
|
import type { Express } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import listener from "./ocp.printer.listener.js";
|
import listener from "./ocp.printer.listener.js";
|
||||||
import update from "./ocp.printer.update.js";
|
import update from "./ocp.printer.update.js";
|
||||||
|
|
||||||
export const setupOCPRoutes = (baseUrl: string, app: Express) => {
|
export const setupOCPRoutes = (baseUrl: string, app: Express) => {
|
||||||
//setup all the routes
|
app.use(`${baseUrl}/api/ocp/printer/listener`, featureCheck("ocp"), listener);
|
||||||
const router = Router();
|
app.use(
|
||||||
|
`${baseUrl}/api/ocp/printer`,
|
||||||
// is the feature even on?
|
featureCheck("ocp"),
|
||||||
router.use(featureCheck("ocp"));
|
requireAuth,
|
||||||
|
update,
|
||||||
// non auth routes up here
|
);
|
||||||
router.use(listener);
|
|
||||||
|
|
||||||
// auth routes below here
|
|
||||||
router.use(requireAuth);
|
|
||||||
|
|
||||||
app.use(routeHitMiddleware);
|
|
||||||
|
|
||||||
router.use(update);
|
|
||||||
//router.use("");
|
|
||||||
|
|
||||||
app.use(`${baseUrl}/api/ocp`, router);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { addHours } from "date-fns";
|
|||||||
import { formatInTimeZone } from "date-fns-tz";
|
import { formatInTimeZone } from "date-fns-tz";
|
||||||
import { eq, sql } from "drizzle-orm";
|
import { eq, sql } from "drizzle-orm";
|
||||||
import { db } from "../db/db.controller.js";
|
import { db } from "../db/db.controller.js";
|
||||||
import { opendockApt } from "../db/schema/opendock.schema.js";
|
import { opendockApt } from "../db/schema/opendock_apt.schema.js";
|
||||||
import { settings } from "../db/schema/settings.schema.js";
|
import { settings } from "../db/schema/settings.schema.js";
|
||||||
import { createLogger } from "../logger/logger.controller.js";
|
import { createLogger } from "../logger/logger.controller.js";
|
||||||
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||||
@@ -27,6 +27,9 @@ type Releases = {
|
|||||||
Quantity: number;
|
Quantity: number;
|
||||||
LineItemArticleWeight: number;
|
LineItemArticleWeight: number;
|
||||||
CustomerReleaseNumber: string;
|
CustomerReleaseNumber: string;
|
||||||
|
DeliveryAddressDescription: string;
|
||||||
|
DeliveryAddressHumanReadableId: string;
|
||||||
|
AdditionalInformation1: string;
|
||||||
};
|
};
|
||||||
const timeZone = process.env.TIMEZONE as string;
|
const timeZone = process.env.TIMEZONE as string;
|
||||||
const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;
|
const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;
|
||||||
@@ -73,6 +76,28 @@ const postRelease = async (release: Releases) => {
|
|||||||
log.info({}, "Refreshing Auth Token");
|
log.info({}, "Refreshing Auth Token");
|
||||||
await getToken();
|
await getToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load validation checks
|
||||||
|
const defaultDock = await db.query.settings.findFirst({
|
||||||
|
where: (u, { eq }) => eq(u.name, "defaultLoadType"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// check if the release has the data in it
|
||||||
|
const releaseLoadtypeCheck = (release.AdditionalInformation1 ?? "")
|
||||||
|
.toLowerCase()
|
||||||
|
.split(",")
|
||||||
|
.map((x) => x.trim())
|
||||||
|
.includes("drop");
|
||||||
|
|
||||||
|
const opendDockArticleCheck = await db.query.opendockArticleSetup.findFirst({
|
||||||
|
where: (table, { and, eq }) =>
|
||||||
|
and(
|
||||||
|
eq(table.av, release.LineItemArticleWeight),
|
||||||
|
eq(table.customer, release.DeliveryAddressHumanReadableId),
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: add in docks from lst db here to make it more universal for the team
|
||||||
/**
|
/**
|
||||||
* ReleaseState
|
* ReleaseState
|
||||||
* 0 = open
|
* 0 = open
|
||||||
@@ -101,6 +126,7 @@ const postRelease = async (release: Releases) => {
|
|||||||
: release.DeliveryState === 4 && "Completed",
|
: release.DeliveryState === 4 && "Completed",
|
||||||
userId: process.env.DEFAULT_CARRIER, // this should be the carrierid
|
userId: process.env.DEFAULT_CARRIER, // this should be the carrierid
|
||||||
loadTypeId: process.env.DEFAULT_LOAD_TYPE, // well get this and make it a default one
|
loadTypeId: process.env.DEFAULT_LOAD_TYPE, // well get this and make it a default one
|
||||||
|
// TODO: look in the remarks in the release and if its says
|
||||||
dockId: process.env.DEFAULT_DOCK, // this the warehouse we want it in to start out
|
dockId: process.env.DEFAULT_DOCK, // this the warehouse we want it in to start out
|
||||||
refNumbers: [release.ReleaseNumber],
|
refNumbers: [release.ReleaseNumber],
|
||||||
//refNumber: release.ReleaseNumber,
|
//refNumber: release.ReleaseNumber,
|
||||||
@@ -115,6 +141,19 @@ const postRelease = async (release: Releases) => {
|
|||||||
},
|
},
|
||||||
units: null,
|
units: null,
|
||||||
customFields: [
|
customFields: [
|
||||||
|
{
|
||||||
|
name: "strCustomer",
|
||||||
|
type: "str",
|
||||||
|
label: "Customer",
|
||||||
|
value: `${release.DeliveryAddressDescription}`,
|
||||||
|
description: "Who is the customer ",
|
||||||
|
placeholder: "",
|
||||||
|
dropDownValues: [],
|
||||||
|
minLengthOrValue: 1,
|
||||||
|
hiddenFromCarrier: false,
|
||||||
|
requiredForCarrier: false,
|
||||||
|
requiredForWarehouse: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "strArticle",
|
name: "strArticle",
|
||||||
type: "str",
|
type: "str",
|
||||||
@@ -190,58 +229,179 @@ const postRelease = async (release: Releases) => {
|
|||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
const id = existing.openDockAptId;
|
const id = existing.openDockAptId;
|
||||||
try {
|
|
||||||
const response = await axios.patch(
|
|
||||||
`${process.env.OPENDOCK_URL}/appointment/${id}`,
|
|
||||||
newDockApt,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"content-type": "application/json; charset=utf-8",
|
|
||||||
Authorization: `Bearer ${odToken.odToken}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.status === 400) {
|
if (
|
||||||
log.error({}, response.data.data.message);
|
(releaseLoadtypeCheck ||
|
||||||
|
opendDockArticleCheck?.loadType === "drop" ||
|
||||||
|
defaultDock?.value === "drop") &&
|
||||||
|
(release.DeliveryState === 0 || release.DeliveryState === 1)
|
||||||
|
) {
|
||||||
|
const setArrival = { ...newDockApt, status: "Arrived" };
|
||||||
|
|
||||||
|
// set to arrived
|
||||||
|
try {
|
||||||
|
const response = await axios.patch(
|
||||||
|
`${process.env.OPENDOCK_URL}/appointment/${id}`,
|
||||||
|
setArrival,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/json; charset=utf-8",
|
||||||
|
Authorization: `Bearer ${odToken.odToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.status === 400) {
|
||||||
|
log.error({}, response.data.data.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the release in the db leaving as insert just incase something weird happened
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.insert(opendockApt)
|
||||||
|
.values({
|
||||||
|
release: release.ReleaseNumber,
|
||||||
|
openDockAptId: response.data.data.id,
|
||||||
|
appointment: response.data.data,
|
||||||
|
})
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: opendockApt.release,
|
||||||
|
set: {
|
||||||
|
openDockAptId: response.data.data.id,
|
||||||
|
appointment: response.data.data,
|
||||||
|
upd_date: sql`NOW()`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
log.info({}, `${release.ReleaseNumber} was updated`);
|
||||||
|
} catch (e) {
|
||||||
|
log.error(
|
||||||
|
{ stack: e },
|
||||||
|
`Error updating the release: ${release.ReleaseNumber}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
|
||||||
|
} catch (e: any) {
|
||||||
|
//console.info(newDockApt);
|
||||||
|
log.error(
|
||||||
|
{ stack: e.response.data },
|
||||||
|
`An error has occurred during patching of the release: ${release.ReleaseNumber}`,
|
||||||
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the release in the db leaving as insert just incase something weird happened
|
// set to inprogress
|
||||||
|
await delay(1500);
|
||||||
try {
|
try {
|
||||||
await db
|
const response = await axios.patch(
|
||||||
.insert(opendockApt)
|
`${process.env.OPENDOCK_URL}/appointment/${id}`,
|
||||||
.values({
|
newDockApt,
|
||||||
release: release.ReleaseNumber,
|
{
|
||||||
openDockAptId: response.data.data.id,
|
headers: {
|
||||||
appointment: response.data.data,
|
"content-type": "application/json; charset=utf-8",
|
||||||
})
|
Authorization: `Bearer ${odToken.odToken}`,
|
||||||
.onConflictDoUpdate({
|
},
|
||||||
target: opendockApt.release,
|
},
|
||||||
set: {
|
);
|
||||||
|
|
||||||
|
if (response.status === 400) {
|
||||||
|
log.error({}, response.data.data.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the release in the db leaving as insert just incase something weird happened
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.insert(opendockApt)
|
||||||
|
.values({
|
||||||
|
release: release.ReleaseNumber,
|
||||||
openDockAptId: response.data.data.id,
|
openDockAptId: response.data.data.id,
|
||||||
appointment: response.data.data,
|
appointment: response.data.data,
|
||||||
upd_date: sql`NOW()`,
|
})
|
||||||
},
|
.onConflictDoUpdate({
|
||||||
})
|
target: opendockApt.release,
|
||||||
.returning();
|
set: {
|
||||||
|
openDockAptId: response.data.data.id,
|
||||||
|
appointment: response.data.data,
|
||||||
|
upd_date: sql`NOW()`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
log.info({}, `${release.ReleaseNumber} was updated`);
|
log.info({}, `${release.ReleaseNumber} was updated`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
log.error(
|
||||||
|
{ stack: e },
|
||||||
|
`Error updating the release: ${release.ReleaseNumber}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
|
||||||
|
} catch (e: any) {
|
||||||
|
//console.info(newDockApt);
|
||||||
log.error(
|
log.error(
|
||||||
{ error: e },
|
{ stack: e.response.data },
|
||||||
`Error updating the release: ${release.ReleaseNumber}`,
|
`An error has occurred during patching of the release: ${release.ReleaseNumber}`,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
|
|
||||||
} catch (e: any) {
|
|
||||||
//console.info(newDockApt);
|
|
||||||
log.error(
|
|
||||||
{ error: e.response.data },
|
|
||||||
`An error has occurred during patching of the release: ${release.ReleaseNumber}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const response = await axios.patch(
|
||||||
|
`${process.env.OPENDOCK_URL}/appointment/${id}`,
|
||||||
|
newDockApt,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/json; charset=utf-8",
|
||||||
|
Authorization: `Bearer ${odToken.odToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.status === 400) {
|
||||||
|
log.error({}, response.data.data.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the release in the db leaving as insert just incase something weird happened
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.insert(opendockApt)
|
||||||
|
.values({
|
||||||
|
release: release.ReleaseNumber,
|
||||||
|
openDockAptId: response.data.data.id,
|
||||||
|
appointment: response.data.data,
|
||||||
|
})
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: opendockApt.release,
|
||||||
|
set: {
|
||||||
|
openDockAptId: response.data.data.id,
|
||||||
|
appointment: response.data.data,
|
||||||
|
upd_date: sql`NOW()`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
log.info({}, `${release.ReleaseNumber} was updated`);
|
||||||
|
} catch (e) {
|
||||||
|
log.error(
|
||||||
|
{ stack: e },
|
||||||
|
`Error updating the release: ${release.ReleaseNumber}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
|
||||||
|
} catch (e: any) {
|
||||||
|
//console.info(newDockApt);
|
||||||
|
log.error(
|
||||||
|
{ stack: e.response.data },
|
||||||
|
`An error has occurred during patching of the release: ${release.ReleaseNumber}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
@@ -287,13 +447,13 @@ const postRelease = async (release: Releases) => {
|
|||||||
|
|
||||||
log.info({}, `${release.ReleaseNumber} was created`);
|
log.info({}, `${release.ReleaseNumber} was created`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error({ error: e }, "Error creating new release");
|
log.error({ stack: e }, "Error creating new release");
|
||||||
}
|
}
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
|
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
log.error(
|
log.error(
|
||||||
{ error: e?.response?.data },
|
{ stack: e?.response?.data },
|
||||||
"Error posting new release to opendock",
|
`Error posting new release to opendock, ${release.ReleaseNumber}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
277
backend/opendock/opendock.articleCheck.route.ts
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
import { desc, eq, sql } from "drizzle-orm";
|
||||||
|
import { Router } from "express";
|
||||||
|
import z from "zod";
|
||||||
|
import { db } from "../db/db.controller.js";
|
||||||
|
import {
|
||||||
|
type NewOpendockArticleSetup,
|
||||||
|
opendockArticleSetup,
|
||||||
|
} from "../db/schema/opendock_articleSetup.js";
|
||||||
|
import { opendockDockSetup } from "../db/schema/opendock_docks.js";
|
||||||
|
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
|
||||||
|
import {
|
||||||
|
type SqlQuery,
|
||||||
|
sqlQuerySelector,
|
||||||
|
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
const newArticleLink = z.object({
|
||||||
|
av: z.number().int(),
|
||||||
|
description: z.string(),
|
||||||
|
customer: z.string().min(1).max(32),
|
||||||
|
customerDescription: z.string().min(2).max(100),
|
||||||
|
loadType: z
|
||||||
|
.enum(["drop", "live"])
|
||||||
|
.optional()
|
||||||
|
.describe("What roles are available to use."),
|
||||||
|
dock: z
|
||||||
|
//.record(z.string(), z.unknown())
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"This allows us to add extra fields to the data to parse against",
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const newDockLink = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
dockID: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
r.post("/", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const validated = newArticleLink.parse(req.body) as NewOpendockArticleSetup;
|
||||||
|
|
||||||
|
const newLink = await db
|
||||||
|
.insert(opendockArticleSetup)
|
||||||
|
.values({
|
||||||
|
av: validated.av,
|
||||||
|
description: validated.description,
|
||||||
|
customer: validated.customer,
|
||||||
|
customerDescription: validated.customerDescription,
|
||||||
|
loadType: validated.loadType,
|
||||||
|
dock: validated.dock,
|
||||||
|
add_user: req.user?.username ?? "lst_user",
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: `${validated.av} was just added `,
|
||||||
|
data: newLink as any,
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof z.ZodError) {
|
||||||
|
const flattened = z.flattenError(err);
|
||||||
|
// return res.status(400).json({
|
||||||
|
// error: "Validation failed",
|
||||||
|
// details: flattened,
|
||||||
|
// });
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error", //connect.success ? "info" : "error",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: "Validation failed",
|
||||||
|
data: [flattened.fieldErrors],
|
||||||
|
status: 400, //connect.success ? 200 : 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error", //connect.success ? "info" : "error",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: "Internal Server Error adding article link",
|
||||||
|
data: [err],
|
||||||
|
status: 400, //connect.success ? 200 : 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
r.patch("/:id", async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
const updates: Record<string, unknown | null> = {};
|
||||||
|
|
||||||
|
if (req.body?.loadType !== undefined) {
|
||||||
|
updates.loadType = req.body.loadType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.body?.dock !== undefined) {
|
||||||
|
updates.dock = req.body.dock;
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.upd_user = req.user?.username || "lst_user";
|
||||||
|
updates.upd_date = sql`NOW()`;
|
||||||
|
|
||||||
|
const updatedSetting = await db
|
||||||
|
.update(opendockArticleSetup)
|
||||||
|
.set(updates)
|
||||||
|
.where(eq(opendockArticleSetup.id, id))
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: `${updatedSetting[0]?.av} was just updated. `,
|
||||||
|
data: updatedSetting,
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
r.delete("/:id", async (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
|
||||||
|
const removeLink = await db
|
||||||
|
.delete(opendockArticleSetup)
|
||||||
|
.where(eq(opendockArticleSetup.id, id))
|
||||||
|
.returning();
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "info", //connect.success ? "info" : "error",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: "Article link was deleted",
|
||||||
|
data: removeLink,
|
||||||
|
status: 200, //connect.success ? 200 : 400,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
r.get("/", async (_, res) => {
|
||||||
|
const { data } = await tryCatch(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(opendockArticleSetup)
|
||||||
|
.orderBy(desc(opendockArticleSetup.customer))
|
||||||
|
.limit(1500),
|
||||||
|
);
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: `All links`,
|
||||||
|
data: data ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
r.get("/customers/:av", async (req, res) => {
|
||||||
|
const { av } = req.params;
|
||||||
|
|
||||||
|
const avSQLQuery = sqlQuerySelector(`opendock.addressLink`) as SqlQuery;
|
||||||
|
|
||||||
|
if (!avSQLQuery.success) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "error",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: avSQLQuery.message,
|
||||||
|
data: [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const { data } = await tryCatch(
|
||||||
|
prodQuery(
|
||||||
|
avSQLQuery.query.replace("[articleCheck]", av),
|
||||||
|
"openDock addressLink",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: `All customers linked to av: ${av}`,
|
||||||
|
data: data?.data ?? ([] as any),
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
r.post("/dock", async (req, res) => {
|
||||||
|
try {
|
||||||
|
const validated = newDockLink.parse(req.body) as any;
|
||||||
|
|
||||||
|
const newLink = await db
|
||||||
|
.insert(opendockDockSetup)
|
||||||
|
.values({
|
||||||
|
name: validated.name,
|
||||||
|
dockID: validated.dockID,
|
||||||
|
add_user: req.user?.username ?? "lst_user",
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: `${validated.name} was just added `,
|
||||||
|
data: newLink as any,
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof z.ZodError) {
|
||||||
|
const flattened = z.flattenError(err);
|
||||||
|
// return res.status(400).json({
|
||||||
|
// error: "Validation failed",
|
||||||
|
// details: flattened,
|
||||||
|
// });
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error", //connect.success ? "info" : "error",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: "Validation failed",
|
||||||
|
data: [flattened.fieldErrors],
|
||||||
|
status: 400, //connect.success ? 200 : 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error", //connect.success ? "info" : "error",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: "Internal Server Error adding dock link",
|
||||||
|
data: [err],
|
||||||
|
status: 400, //connect.success ? 200 : 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
r.get("/dock", async (_, res) => {
|
||||||
|
const { data } = await tryCatch(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(opendockDockSetup)
|
||||||
|
.orderBy(desc(opendockDockSetup.name))
|
||||||
|
.limit(1500),
|
||||||
|
);
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "opendock",
|
||||||
|
subModule: "articleCheck",
|
||||||
|
message: `All dock links`,
|
||||||
|
data: data ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
@@ -1,21 +1,24 @@
|
|||||||
import { type Express, Router } from "express";
|
import type { Express } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
import { featureCheck } from "../middleware/featureActive.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
import articleCheck from "./opendock.articleCheck.route.js";
|
||||||
|
|
||||||
import getApt from "./opendockGetRelease.route.js";
|
import getApt from "./opendockGetRelease.route.js";
|
||||||
|
|
||||||
export const setupOpendockRoutes = (baseUrl: string, app: Express) => {
|
export const setupOpendockRoutes = (baseUrl: string, app: Express) => {
|
||||||
//setup all the routes
|
//setup all the routes
|
||||||
// Apply auth to entire router
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
// is the feature even on?
|
app.use(
|
||||||
router.use(featureCheck("opendock_sync"));
|
`${baseUrl}/api/opendock`,
|
||||||
|
featureCheck("opendock_sync"),
|
||||||
|
requireAuth,
|
||||||
|
getApt,
|
||||||
|
);
|
||||||
|
|
||||||
// we need to make sure we are authenticated to see the releases
|
app.use(
|
||||||
router.use(requireAuth);
|
`${baseUrl}/api/opendock/articleCheck`,
|
||||||
app.use(routeHitMiddleware);
|
featureCheck("opendock_sync"),
|
||||||
|
requireAuth,
|
||||||
router.use(getApt);
|
articleCheck,
|
||||||
app.use(`${baseUrl}/api/opendock`, router);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { desc, gte, sql } from "drizzle-orm";
|
import { desc, gte, sql } from "drizzle-orm";
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { db } from "../db/db.controller.js";
|
import { db } from "../db/db.controller.js";
|
||||||
import { opendockApt } from "../db/schema/opendock.schema.js";
|
import { opendockApt } from "../db/schema/opendock_apt.schema.js";
|
||||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type Express, Router } from "express";
|
import { type Express, Router } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import restart from "./prodSqlRestart.route.js";
|
import restart from "./prodSqlRestart.route.js";
|
||||||
import start from "./prodSqlStart.route.js";
|
import start from "./prodSqlStart.route.js";
|
||||||
import stop from "./prodSqlStop.route.js";
|
import stop from "./prodSqlStop.route.js";
|
||||||
@@ -9,11 +9,8 @@ export const setupProdSqlRoutes = (baseUrl: string, app: Express) => {
|
|||||||
// Apply auth to entire router
|
// Apply auth to entire router
|
||||||
const router = Router();
|
const router = Router();
|
||||||
router.use(requireAuth);
|
router.use(requireAuth);
|
||||||
app.use(routeHitMiddleware);
|
|
||||||
|
|
||||||
router.use(start);
|
app.use(`${baseUrl}/api/system/prodSql/start`, requireAuth, start);
|
||||||
router.use(stop);
|
app.use(`${baseUrl}/api/system/prodSql/stop`, requireAuth, stop);
|
||||||
router.use(restart);
|
app.use(`${baseUrl}/api/system/prodSql/restart`, requireAuth, restart);
|
||||||
|
|
||||||
app.use(`${baseUrl}/api/system/prodSql`, router);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { closePool, connectProdSql } from "./prodSqlConnection.controller.js";
|
|||||||
|
|
||||||
const r = Router();
|
const r = Router();
|
||||||
|
|
||||||
r.post("/restart", async (_, res) => {
|
r.post("/", async (_, res) => {
|
||||||
await closePool();
|
await closePool();
|
||||||
|
|
||||||
await new Promise((r) => setTimeout(r, 2000));
|
await new Promise((r) => setTimeout(r, 2000));
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { connectProdSql } from "./prodSqlConnection.controller.js";
|
|||||||
|
|
||||||
const r = Router();
|
const r = Router();
|
||||||
|
|
||||||
r.post("/start", async (_, res) => {
|
r.post("/", async (_, res) => {
|
||||||
const connect = await connectProdSql();
|
const connect = await connectProdSql();
|
||||||
apiReturn(res, {
|
apiReturn(res, {
|
||||||
success: connect.success,
|
success: connect.success,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { closePool } from "./prodSqlConnection.controller.js";
|
|||||||
|
|
||||||
const r = Router();
|
const r = Router();
|
||||||
|
|
||||||
r.post("/stop", async (_, res) => {
|
r.post("/", async (_, res) => {
|
||||||
const connect = await closePool();
|
const connect = await closePool();
|
||||||
apiReturn(res, {
|
apiReturn(res, {
|
||||||
success: connect.success,
|
success: connect.success,
|
||||||
|
|||||||
21
backend/prodSql/queries/disableJob.sql
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
disables sql jobs.
|
||||||
|
*/
|
||||||
|
--EXEC msdb.dbo.sp_update_job @job_name = N'[jobName]', @enabled = 0;
|
||||||
|
-- DECLARE @JobName varchar(max) = '[jobName]'
|
||||||
|
-- UPDATE msdb.dbo.sysjobs
|
||||||
|
-- SET enabled = 0
|
||||||
|
-- WHERE name = @JobName;
|
||||||
|
|
||||||
|
DECLARE @JobName NVARCHAR(128) = N'[jobName]';
|
||||||
|
|
||||||
|
IF EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM msdb.dbo.sysjobs
|
||||||
|
WHERE name = @JobName
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
EXEC msdb.dbo.sp_update_job
|
||||||
|
@job_name = @JobName,
|
||||||
|
@enabled = 0;
|
||||||
|
END
|
||||||
34
backend/prodSql/queries/opendock.addressLink.sql
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
This will return all address with a sales price.
|
||||||
|
*/
|
||||||
|
WITH ranked AS (
|
||||||
|
SELECT
|
||||||
|
av.id,
|
||||||
|
av.humanReadableId as av,
|
||||||
|
av.Alias as description,
|
||||||
|
-- CONCAT(ad.HumanReadableId, ' - ',ad.Name) as customer ,
|
||||||
|
ad.HumanReadableId as customer,
|
||||||
|
ad.Name as customerDescription,
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY AddressId, sp.articleId
|
||||||
|
ORDER BY ValidAfter DESC
|
||||||
|
) AS rn
|
||||||
|
FROM [test1_AlplaPROD2.0_Read].[masterData].[SalesPrice] as sp (nolock)
|
||||||
|
|
||||||
|
/* av */
|
||||||
|
left join
|
||||||
|
[test1_AlplaPROD2.0_Read].[masterData].[Article] as av (nolock) on
|
||||||
|
av.id = sp.articleId
|
||||||
|
|
||||||
|
/* address */
|
||||||
|
left join
|
||||||
|
[test1_AlplaPROD2.0_Read].[masterData].[Address] as ad (nolock) on
|
||||||
|
ad.id = AddressId
|
||||||
|
|
||||||
|
)
|
||||||
|
SELECT *
|
||||||
|
FROM ranked
|
||||||
|
WHERE rn = 1
|
||||||
|
and ranked.av = '[articleCheck]'
|
||||||
|
|
||||||
|
order by customerDescription
|
||||||
6
backend/prodSql/queries/outbound.docks.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
USE [test1_AlplaPROD2.0_Read]
|
||||||
|
|
||||||
|
SELECT *
|
||||||
|
FROM [masterData].[Dock] (nolock)
|
||||||
|
where active = 1
|
||||||
|
order by Description desc
|
||||||
@@ -21,7 +21,7 @@ SELECT
|
|||||||
,[MainMaterialId]
|
,[MainMaterialId]
|
||||||
,[MainMaterialHumanReadableId]
|
,[MainMaterialHumanReadableId]
|
||||||
,[MainMaterialDescription]
|
,[MainMaterialDescription]
|
||||||
,[AdditionalInformation1]
|
,[AdditionalInformation1] -- we will use this to reference as the first check
|
||||||
,[AdditionalInformation2]
|
,[AdditionalInformation2]
|
||||||
,[D365SupplierLot]
|
,[D365SupplierLot]
|
||||||
,[TradeUnits]
|
,[TradeUnits]
|
||||||
@@ -47,9 +47,9 @@ SELECT
|
|||||||
,[PaymentTermsId]
|
,[PaymentTermsId]
|
||||||
,[PaymentTermsHumanReadableId]
|
,[PaymentTermsHumanReadableId]
|
||||||
,[PaymentTermsDescription]
|
,[PaymentTermsDescription]
|
||||||
,[Remark]
|
,[Remark]
|
||||||
,[DeliveryAddressId]
|
,[DeliveryAddressId]
|
||||||
,[DeliveryAddressHumanReadableId]
|
,[DeliveryAddressHumanReadableId] --use this to validate with the new drop or live check
|
||||||
,[DeliveryAddressDescription]
|
,[DeliveryAddressDescription]
|
||||||
,[DeliveryStreetName]
|
,[DeliveryStreetName]
|
||||||
,[DeliveryAddressZip]
|
,[DeliveryAddressZip]
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
use [test1_AlplaPROD2.0_Read]
|
use [test1_AlplaPROD2.0_Read]
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
--JSON_VALUE(content, '$.EntityId') as labelId
|
JSON_VALUE(content, '$.EntityId') as labelId,
|
||||||
a.id
|
a.id
|
||||||
,ActorName
|
,ActorName
|
||||||
,FORMAT(PrintDate, 'yyyy-MM-dd HH:mm') as printDate
|
--,FORMAT(l.PrintDate, 'yyyy-MM-dd HH:mm') as printDate
|
||||||
|
,Format(COALESCE(l.PrintDate, e.ProductionDate), 'yyyy-MM-dd HH:mm') as printDate
|
||||||
,FORMAT(CreatedDateTime, 'yyyy-MM-dd HH:mm') createdDateTime
|
,FORMAT(CreatedDateTime, 'yyyy-MM-dd HH:mm') createdDateTime
|
||||||
,l.ArticleHumanReadableId as av
|
,COALESCE(l.ArticleHumanReadableId,e.ArticleHumanReadableId) as av
|
||||||
,l.ArticleDescription as alias
|
,COALESCE(l.ArticleDescription, av.Name) as alias
|
||||||
,PrintedCopies
|
,COALESCE(l.PrintedCopies, 0) as PrintedCopies
|
||||||
,p.name as printerName
|
,COALESCE(p.name,'External Label not tracked') as printerName
|
||||||
,RunningNumber
|
,COALESCE(l.RunningNumber, e.RunningNumber) as runningNumber
|
||||||
--,*
|
--,*
|
||||||
FROM [support].[AuditLog] (nolock) as a
|
FROM [support].[AuditLog] (nolock) as a
|
||||||
|
|
||||||
@@ -18,10 +19,20 @@ left join
|
|||||||
[labelling].[InternalLabel] (nolock) as l on
|
[labelling].[InternalLabel] (nolock) as l on
|
||||||
l.id = JSON_VALUE(content, '$.EntityId')
|
l.id = JSON_VALUE(content, '$.EntityId')
|
||||||
|
|
||||||
|
OUTER APPLY (
|
||||||
|
SELECT TOP 1 *
|
||||||
|
FROM labelling.ExternalLabel e
|
||||||
|
WHERE e.id = JSON_VALUE(a.content, '$.EntityId')
|
||||||
|
ORDER BY e.Id DESC
|
||||||
|
) e
|
||||||
|
|
||||||
left join
|
left join
|
||||||
[masterData].[printer] (nolock) as p on
|
[masterData].[printer] (nolock) as p on
|
||||||
p.id = l.PrinterId
|
p.id = l.PrinterId
|
||||||
|
|
||||||
|
left join
|
||||||
|
[masterData].[article] (nolock) as av on
|
||||||
|
av.HumanReadableId = e.ArticleHumanReadableId
|
||||||
where message like '%reprint%'
|
where message like '%reprint%'
|
||||||
and CreatedDateTime > DATEADD(minute, -[intervalCheck], SYSDATETIMEOFFSET())
|
and CreatedDateTime > DATEADD(minute, -[intervalCheck], SYSDATETIMEOFFSET())
|
||||||
and a.id > [ignoreList]
|
and a.id > [ignoreList]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { setupAuthRoutes } from "./auth/auth.routes.js";
|
|||||||
// import the routes and route setups
|
// import the routes and route setups
|
||||||
import { setupApiDocsRoutes } from "./configs/scaler.config.js";
|
import { setupApiDocsRoutes } from "./configs/scaler.config.js";
|
||||||
import { setupDatamartRoutes } from "./datamart/datamart.routes.js";
|
import { setupDatamartRoutes } from "./datamart/datamart.routes.js";
|
||||||
|
import { setupDockDoorRoutes } from "./dockdoorScanning/dockdoor.routes.js";
|
||||||
import { setupGPSqlRoutes } from "./gpSql/gpSql.routes.js";
|
import { setupGPSqlRoutes } from "./gpSql/gpSql.routes.js";
|
||||||
import { setupMobileRoutes } from "./mobile/mobile.routes.js";
|
import { setupMobileRoutes } from "./mobile/mobile.routes.js";
|
||||||
import { setupNotificationRoutes } from "./notification/notification.routes.js";
|
import { setupNotificationRoutes } from "./notification/notification.routes.js";
|
||||||
@@ -16,6 +17,7 @@ import { setupUtilsRoutes } from "./utils/utils.routes.js";
|
|||||||
|
|
||||||
export const setupRoutes = (baseUrl: string, app: Express) => {
|
export const setupRoutes = (baseUrl: string, app: Express) => {
|
||||||
//routes that are on by default
|
//routes that are on by default
|
||||||
|
setupMobileRoutes(baseUrl, app);
|
||||||
setupSystemRoutes(baseUrl, app);
|
setupSystemRoutes(baseUrl, app);
|
||||||
setupAdminRoutes(baseUrl, app);
|
setupAdminRoutes(baseUrl, app);
|
||||||
setupApiDocsRoutes(baseUrl, app);
|
setupApiDocsRoutes(baseUrl, app);
|
||||||
@@ -28,5 +30,5 @@ export const setupRoutes = (baseUrl: string, app: Express) => {
|
|||||||
setupNotificationRoutes(baseUrl, app);
|
setupNotificationRoutes(baseUrl, app);
|
||||||
setupOCPRoutes(baseUrl, app);
|
setupOCPRoutes(baseUrl, app);
|
||||||
setupTCPRoutes(baseUrl, app);
|
setupTCPRoutes(baseUrl, app);
|
||||||
setupMobileRoutes(baseUrl, app);
|
setupDockDoorRoutes(baseUrl, app);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { connectGPSql } from "./gpSql/gpSqlConnection.controller.js";
|
|||||||
import { createLogger } from "./logger/logger.controller.js";
|
import { createLogger } from "./logger/logger.controller.js";
|
||||||
import { historicalSchedule } from "./logistics/logistics.historicalInv.js";
|
import { historicalSchedule } from "./logistics/logistics.historicalInv.js";
|
||||||
import { startNotifications } from "./notification/notification.controller.js";
|
import { startNotifications } from "./notification/notification.controller.js";
|
||||||
|
import { sqlJobCleanUp } from "./notification/notification.SqlJobCleanUp.js";
|
||||||
import { createNotifications } from "./notification/notifications.master.js";
|
import { createNotifications } from "./notification/notifications.master.js";
|
||||||
import { printerSync } from "./ocp/ocp.printer.manage.js";
|
import { printerSync } from "./ocp/ocp.printer.manage.js";
|
||||||
import { monitorReleaseChanges } from "./opendock/openDockRreleaseMonitor.utils.js";
|
import { monitorReleaseChanges } from "./opendock/openDockRreleaseMonitor.utils.js";
|
||||||
@@ -25,6 +26,7 @@ import {
|
|||||||
} from "./utils/analyticRouteHits.utils.js";
|
} from "./utils/analyticRouteHits.utils.js";
|
||||||
import { createCronJob } from "./utils/croner.utils.js";
|
import { createCronJob } from "./utils/croner.utils.js";
|
||||||
import { sendEmail } from "./utils/sendEmail.utils.js";
|
import { sendEmail } from "./utils/sendEmail.utils.js";
|
||||||
|
import { ppooMonitoring } from "./warehousing/warehousing.ppooMonitor.js";
|
||||||
|
|
||||||
const port = Number(process.env.PORT) || 3000;
|
const port = Number(process.env.PORT) || 3000;
|
||||||
export let systemSettings: Setting[] = [];
|
export let systemSettings: Setting[] = [];
|
||||||
@@ -77,12 +79,19 @@ const start = async () => {
|
|||||||
runRouteHitAnalyticsCron(),
|
runRouteHitAnalyticsCron(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
createCronJob("ppooMonitor", "*/45 * * * * *", async () =>
|
||||||
|
ppooMonitoring(),
|
||||||
|
);
|
||||||
|
|
||||||
createCronJob("cleanHitsUp", "0 0 7 * * *", () => cleanupOldRouteHits());
|
createCronJob("cleanHitsUp", "0 0 7 * * *", () => cleanupOldRouteHits());
|
||||||
// one shots only needed to run on server startups
|
// one shots only needed to run on server startups
|
||||||
createNotifications();
|
createNotifications();
|
||||||
startNotifications();
|
startNotifications();
|
||||||
serversChecks();
|
serversChecks();
|
||||||
aggregateRouteHitsForBusinessDay();
|
aggregateRouteHitsForBusinessDay();
|
||||||
|
|
||||||
|
// can be removed at a later date
|
||||||
|
sqlJobCleanUp();
|
||||||
}, 5 * 1000);
|
}, 5 * 1000);
|
||||||
|
|
||||||
process.on("uncaughtException", async (err) => {
|
process.on("uncaughtException", async (err) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { RoomId } from "./types.socket.js";
|
import type { RoomId } from "./roomDefinitions.socket.js";
|
||||||
|
|
||||||
export const MAX_HISTORY = 50;
|
export const MAX_HISTORY = 50;
|
||||||
export const FLUSH_INTERVAL = 100; // 50ms change higher if needed
|
export const FLUSH_INTERVAL = 100; // 50ms change higher if needed
|
||||||
|
|||||||
@@ -1,17 +1,50 @@
|
|||||||
import { desc } from "drizzle-orm";
|
import { desc } from "drizzle-orm";
|
||||||
import { db } from "../db/db.controller.js";
|
import { db } from "../db/db.controller.js";
|
||||||
import { logs } from "../db/schema/logs.schema.js";
|
import { logs } from "../db/schema/logs.schema.js";
|
||||||
import type { RoomId } from "./types.socket.js";
|
import { ppoRun } from "../warehousing/warehousing.ppooMonitor.js";
|
||||||
|
|
||||||
type RoomDefinition<T = unknown> = {
|
type RoomDefinition<T = unknown> = {
|
||||||
seed: (limit: number) => Promise<T[]>;
|
seed: (limit: number) => Promise<T[]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const protectedRooms: any = {
|
export type StaticRoomId = "logs" | "labels" | "admin" | "admin:build" | "ppoo";
|
||||||
|
export type DynamicRoomId = `dockDoorLoading:${string}`;
|
||||||
|
export type RoomId = StaticRoomId | DynamicRoomId;
|
||||||
|
|
||||||
|
export type RoomConfig = {
|
||||||
|
requiresAuth?: boolean;
|
||||||
|
role?: string[];
|
||||||
|
seed?: (limit: number, roomId: RoomId) => Promise<unknown[]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const protectedRooms: Record<StaticRoomId, RoomConfig> = {
|
||||||
logs: { requiresAuth: true, role: ["admin", "systemAdmin"] },
|
logs: { requiresAuth: true, role: ["admin", "systemAdmin"] },
|
||||||
//admin: { requiresAuth: false, role: ["admin", "systemAdmin"] },
|
//admin: { requiresAuth: false, role: ["admin", "systemAdmin"] },
|
||||||
|
labels: {},
|
||||||
|
admin: {},
|
||||||
|
"admin:build": {},
|
||||||
|
ppoo: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getRoomConfig(roomId: string): RoomConfig | null {
|
||||||
|
if (roomId in protectedRooms) {
|
||||||
|
return protectedRooms[roomId as StaticRoomId];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roomId.startsWith("dockDoorLoading:")) {
|
||||||
|
const dockId = roomId.split(":")[1];
|
||||||
|
|
||||||
|
if (!dockId) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
requiresAuth: true,
|
||||||
|
role: ["admin", "systemAdmin", "dockDoor"],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export const roomDefinition: Record<RoomId, RoomDefinition> = {
|
export const roomDefinition: Record<RoomId, RoomDefinition> = {
|
||||||
logs: {
|
logs: {
|
||||||
seed: async (limit) => {
|
seed: async (limit) => {
|
||||||
@@ -48,4 +81,14 @@ export const roomDefinition: Record<RoomId, RoomDefinition> = {
|
|||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ppoo: {
|
||||||
|
seed: async (limit) => {
|
||||||
|
console.log(limit);
|
||||||
|
return {
|
||||||
|
type: "snapshot",
|
||||||
|
items: await ppoRun(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
} as any;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// the emitter setup
|
// the emitter setup
|
||||||
|
|
||||||
import type { RoomId } from "./types.socket.js";
|
import type { RoomId } from "./roomDefinitions.socket.js";
|
||||||
|
|
||||||
let addDataToRoom: ((roomId: RoomId, payload: unknown[]) => void) | null = null;
|
let addDataToRoom: ((roomId: RoomId, payload: unknown[]) => void) | null = null;
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,33 @@ import {
|
|||||||
roomFlushTimers,
|
roomFlushTimers,
|
||||||
roomHistory,
|
roomHistory,
|
||||||
} from "./roomCache.socket.js";
|
} from "./roomCache.socket.js";
|
||||||
import { roomDefinition } from "./roomDefinitions.socket.js";
|
import { type RoomId, roomDefinition } from "./roomDefinitions.socket.js";
|
||||||
import type { RoomId } from "./types.socket.js";
|
|
||||||
|
|
||||||
// get the db data if not exiting already
|
// get the db data if not exiting already
|
||||||
const log = createLogger({ module: "socket.io", subModule: "roomService" });
|
const log = createLogger({ module: "socket.io", subModule: "roomService" });
|
||||||
|
let ioRef: Server | null = null;
|
||||||
|
|
||||||
|
export const registerRoomService = (io: Server) => {
|
||||||
|
ioRef = io;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const hasRoomMembers = (roomId: string): boolean => {
|
||||||
|
if (!ioRef) return false;
|
||||||
|
|
||||||
|
return (ioRef.sockets.adapter.rooms.get(roomId)?.size ?? 0) > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRoomMemberCount = (roomId: string): number => {
|
||||||
|
if (!ioRef) return 0;
|
||||||
|
|
||||||
|
return ioRef.sockets.adapter.rooms.get(roomId)?.size ?? 0;
|
||||||
|
};
|
||||||
export const preseedRoom = async (roomId: RoomId) => {
|
export const preseedRoom = async (roomId: RoomId) => {
|
||||||
if (roomHistory.has(roomId)) {
|
if (roomHistory.has(roomId)) {
|
||||||
return roomHistory.get(roomId);
|
return roomHistory.get(roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const roomDef = roomDefinition[roomId];
|
const roomDef = roomDefinition[roomId] as any;
|
||||||
|
|
||||||
if (!roomDef) {
|
if (!roomDef) {
|
||||||
log.error({}, `Room ${roomId} is not defined`);
|
log.error({}, `Room ${roomId} is not defined`);
|
||||||
@@ -32,7 +47,7 @@ export const preseedRoom = async (roomId: RoomId) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const createRoomEmitter = (io: Server) => {
|
export const createRoomEmitter = (io: Server) => {
|
||||||
const addDataToRoom = <T>(roomId: RoomId, payload: T) => {
|
const addDataToRoom = <T>(roomId: RoomId, payload: T[]) => {
|
||||||
if (!roomHistory.has(roomId)) {
|
if (!roomHistory.has(roomId)) {
|
||||||
roomHistory.set(roomId, []);
|
roomHistory.set(roomId, []);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ import { Server } from "socket.io";
|
|||||||
import { createLogger } from "../logger/logger.controller.js";
|
import { createLogger } from "../logger/logger.controller.js";
|
||||||
import { allowedOrigins } from "../utils/cors.utils.js";
|
import { allowedOrigins } from "../utils/cors.utils.js";
|
||||||
import { registerEmitter } from "./roomEmitter.socket.js";
|
import { registerEmitter } from "./roomEmitter.socket.js";
|
||||||
import { createRoomEmitter, preseedRoom } from "./roomService.socket.js";
|
import {
|
||||||
|
createRoomEmitter,
|
||||||
|
preseedRoom,
|
||||||
|
registerRoomService,
|
||||||
|
} from "./roomService.socket.js";
|
||||||
|
|
||||||
//const __filename = fileURLToPath(import.meta.url);
|
//const __filename = fileURLToPath(import.meta.url);
|
||||||
//const __dirname = dirname(__filename);
|
//const __dirname = dirname(__filename);
|
||||||
@@ -15,7 +19,7 @@ const log = createLogger({ module: "socket.io", subModule: "setup" });
|
|||||||
|
|
||||||
import { auth } from "../utils/auth.utils.js";
|
import { auth } from "../utils/auth.utils.js";
|
||||||
//import type { Session, User } from "better-auth"; // adjust if needed
|
//import type { Session, User } from "better-auth"; // adjust if needed
|
||||||
import { protectedRooms } from "./roomDefinitions.socket.js";
|
import { getRoomConfig } from "./roomDefinitions.socket.js";
|
||||||
|
|
||||||
// declare module "socket.io" {
|
// declare module "socket.io" {
|
||||||
// interface Socket {
|
// interface Socket {
|
||||||
@@ -33,6 +37,9 @@ export const setupSocketIORoutes = (baseUrl: string, server: HttpServer) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// manage members of the rooms.
|
||||||
|
registerRoomService(io);
|
||||||
|
|
||||||
// ✅ Create emitter instance
|
// ✅ Create emitter instance
|
||||||
const { addDataToRoom } = createRoomEmitter(io);
|
const { addDataToRoom } = createRoomEmitter(io);
|
||||||
registerEmitter(addDataToRoom);
|
registerEmitter(addDataToRoom);
|
||||||
@@ -78,38 +85,76 @@ export const setupSocketIORoutes = (baseUrl: string, server: HttpServer) => {
|
|||||||
version: "1.0.0",
|
version: "1.0.0",
|
||||||
});
|
});
|
||||||
|
|
||||||
s.on("join-room", async (rn) => {
|
// s.on("join-room", async (rn) => {
|
||||||
const config = protectedRooms[rn];
|
// const config = protectedRooms[rn];
|
||||||
|
|
||||||
if (config?.requiresAuth && !s.user) {
|
// if (config?.requiresAuth && !s.user) {
|
||||||
|
// return s.emit("room-error", {
|
||||||
|
// room: rn,
|
||||||
|
// message: "Authentication required",
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const roles = Array.isArray(config?.role) ? config?.role : [config?.role];
|
||||||
|
|
||||||
|
// //if (config?.role && s.user?.role !== config.role) {
|
||||||
|
// if (config?.role && !roles.includes(s.user?.role)) {
|
||||||
|
// return s.emit("room-error", {
|
||||||
|
// roomId: rn,
|
||||||
|
// message: `Not authorized to be in room: ${rn}`,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// s.join(rn);
|
||||||
|
|
||||||
|
// // get room seeded
|
||||||
|
// const history = await preseedRoom(rn);
|
||||||
|
// log.info({}, `User joined ${rn}: ${s.id}`);
|
||||||
|
// // send the intial data
|
||||||
|
// s.emit("room-update", {
|
||||||
|
// roomId: rn,
|
||||||
|
// payloads: history,
|
||||||
|
// initial: true,
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
s.on("join-room", async (rn: string) => {
|
||||||
|
const config = getRoomConfig(rn);
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
return s.emit("room-error", {
|
return s.emit("room-error", {
|
||||||
room: rn,
|
roomId: rn,
|
||||||
|
message: `Unknown room: ${rn}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.requiresAuth && !s.user) {
|
||||||
|
return s.emit("room-error", {
|
||||||
|
roomId: rn,
|
||||||
message: "Authentication required",
|
message: "Authentication required",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const roles = Array.isArray(config?.role) ? config?.role : [config?.role];
|
const roles = Array.isArray(config.role) ? config.role : [];
|
||||||
|
|
||||||
//if (config?.role && s.user?.role !== config.role) {
|
if (roles.length > 0 && !roles.includes(s.user?.role)) {
|
||||||
if (config?.role && !roles.includes(s.user?.role)) {
|
|
||||||
return s.emit("room-error", {
|
return s.emit("room-error", {
|
||||||
roomId: rn,
|
roomId: rn,
|
||||||
message: `Not authorized to be in room: ${rn}`,
|
message: `Not authorized to be in room: ${rn}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
s.join(rn);
|
s.join(rn);
|
||||||
|
|
||||||
// get room seeded
|
const history = await preseedRoom(rn as any);
|
||||||
const history = await preseedRoom(rn);
|
|
||||||
log.info({}, `User joined ${rn}: ${s.id}`);
|
log.info({}, `User joined ${rn}: ${s.id}`);
|
||||||
// send the intial data
|
|
||||||
s.emit("room-update", {
|
s.emit("room-update", {
|
||||||
roomId: rn,
|
roomId: rn,
|
||||||
payloads: history,
|
payloads: history,
|
||||||
initial: true,
|
initial: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
s.on("leave-room", (room) => {
|
s.on("leave-room", (room) => {
|
||||||
s.leave(room);
|
s.leave(room);
|
||||||
log.info({}, `${s.id} left room: ${room}`);
|
log.info({}, `${s.id} left room: ${room}`);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export type RoomId = "logs" | "labels" | "admin" | "admin:build"; //| "alerts" | "metrics";
|
|
||||||
@@ -162,6 +162,17 @@ const servers: NewServerData[] = [
|
|||||||
serverLoc: "D$\\LST_V3",
|
serverLoc: "D$\\LST_V3",
|
||||||
buildNumber: 1,
|
buildNumber: 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Salt Lake City",
|
||||||
|
server: "USSLC1VMS006",
|
||||||
|
plantToken: "usslc1",
|
||||||
|
idAddress: "10.202.0.26",
|
||||||
|
greatPlainsPlantCode: "70",
|
||||||
|
contactEmail: "",
|
||||||
|
contactPhone: "",
|
||||||
|
serverLoc: "D$\\LST_V3",
|
||||||
|
buildNumber: 1,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// notes here for when it comes time to pull in all the server address info [test1_AlplaPROD2.0_Read].[masterData].[Plant] has everything from every server :D
|
// notes here for when it comes time to pull in all the server address info [test1_AlplaPROD2.0_Read].[masterData].[Plant] has everything from every server :D
|
||||||
|
|||||||
@@ -86,8 +86,40 @@ const newSettings: NewSetting[] = [
|
|||||||
roles: ["admin"],
|
roles: ["admin"],
|
||||||
seedVersion: 1,
|
seedVersion: 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "dockDoorScanning",
|
||||||
|
value: "0",
|
||||||
|
active: false,
|
||||||
|
description: "dock door scanning",
|
||||||
|
moduleName: "dockDoorScanning",
|
||||||
|
settingType: "feature",
|
||||||
|
roles: ["admin"],
|
||||||
|
seedVersion: 1,
|
||||||
|
},
|
||||||
|
|
||||||
// standard settings
|
// standard settings
|
||||||
|
{
|
||||||
|
name: "stagingWarehouse",
|
||||||
|
value: "30218",
|
||||||
|
active: true,
|
||||||
|
description:
|
||||||
|
"The warehouse we will use for staging, validation that we did our prechecks if required",
|
||||||
|
moduleName: "dockDoorScanning",
|
||||||
|
settingType: "standard",
|
||||||
|
roles: ["admin"],
|
||||||
|
seedVersion: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "precheck",
|
||||||
|
value: "5",
|
||||||
|
active: false,
|
||||||
|
description:
|
||||||
|
"Precheck is required, the value is in minute, 5 min should be 5",
|
||||||
|
moduleName: "dockDoorScanning",
|
||||||
|
settingType: "standard",
|
||||||
|
roles: ["admin"],
|
||||||
|
seedVersion: 1,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "prolinkCheck",
|
name: "prolinkCheck",
|
||||||
value: "1",
|
value: "1",
|
||||||
@@ -346,6 +378,28 @@ const newSettings: NewSetting[] = [
|
|||||||
roles: ["admin"],
|
roles: ["admin"],
|
||||||
seedVersion: 1,
|
seedVersion: 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "scannerIds",
|
||||||
|
value: "10",
|
||||||
|
active: false,
|
||||||
|
description:
|
||||||
|
"How many scanners ids are setup for this, there should be a lst_scanner instance created.",
|
||||||
|
moduleName: "mobile",
|
||||||
|
settingType: "standard",
|
||||||
|
roles: ["admin"],
|
||||||
|
seedVersion: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "defaultLoadType",
|
||||||
|
value: "drop",
|
||||||
|
active: false,
|
||||||
|
description:
|
||||||
|
"What is the default load type we will use for creating new apt: drop or live are the current options.",
|
||||||
|
moduleName: "opendock",
|
||||||
|
settingType: "standard",
|
||||||
|
roles: ["admin"],
|
||||||
|
seedVersion: 1,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const baseSettingValidationCheck = async () => {
|
export const baseSettingValidationCheck = async () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import getServers from "./serverData.route.js";
|
import getServers from "./serverData.route.js";
|
||||||
import getSettings from "./settings.route.js";
|
import getSettings from "./settings.route.js";
|
||||||
import updSetting from "./settingsUpdate.route.js";
|
import updSetting from "./settingsUpdate.route.js";
|
||||||
@@ -8,7 +8,6 @@ import stats from "./stats.route.js";
|
|||||||
|
|
||||||
export const setupSystemRoutes = (baseUrl: string, app: Express) => {
|
export const setupSystemRoutes = (baseUrl: string, app: Express) => {
|
||||||
//stats will be like this as we dont need to change this
|
//stats will be like this as we dont need to change this
|
||||||
app.use(routeHitMiddleware);
|
|
||||||
app.use(`${baseUrl}/api/stats`, stats);
|
app.use(`${baseUrl}/api/stats`, stats);
|
||||||
app.use(`${baseUrl}/api/settings`, getSettings);
|
app.use(`${baseUrl}/api/settings`, getSettings);
|
||||||
app.use(`${baseUrl}/api/servers`, getServers);
|
app.use(`${baseUrl}/api/servers`, getServers);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import restart from "./tcpRestart.route.js";
|
import restart from "./tcpRestart.route.js";
|
||||||
import start from "./tcpStart.route.js";
|
import start from "./tcpStart.route.js";
|
||||||
import stop from "./tcpStop.route.js";
|
import stop from "./tcpStop.route.js";
|
||||||
@@ -8,12 +8,12 @@ import stop from "./tcpStop.route.js";
|
|||||||
export const setupTCPRoutes = (baseUrl: string, app: Express) => {
|
export const setupTCPRoutes = (baseUrl: string, app: Express) => {
|
||||||
//stats will be like this as we dont need to change this
|
//stats will be like this as we dont need to change this
|
||||||
|
|
||||||
app.use(`${baseUrl}/api/tcp/start`, requireAuth, routeHitMiddleware, start);
|
app.use(`${baseUrl}/api/tcp/start`, requireAuth, start);
|
||||||
app.use(`${baseUrl}/api/tcp/stop`, requireAuth, routeHitMiddleware, stop);
|
app.use(`${baseUrl}/api/tcp/stop`, requireAuth, stop);
|
||||||
app.use(
|
app.use(
|
||||||
`${baseUrl}/api/tcp/restart`,
|
`${baseUrl}/api/tcp/restart`,
|
||||||
requireAuth,
|
requireAuth,
|
||||||
routeHitMiddleware,
|
|
||||||
restart,
|
restart,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import net from "node:net";
|
import net from "node:net";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "../db/db.controller.js";
|
import { db } from "../db/db.controller.js";
|
||||||
|
import { dockDoorScanners } from "../db/schema/dockdoor.schema.js";
|
||||||
import { printerData } from "../db/schema/printers.schema.js";
|
import { printerData } from "../db/schema/printers.schema.js";
|
||||||
|
import { loadUnit } from "../dockdoorScanning/dockdoor.loadUnits.js";
|
||||||
import { createLogger } from "../logger/logger.controller.js";
|
import { createLogger } from "../logger/logger.controller.js";
|
||||||
import { delay } from "../utils/delay.utils.js";
|
import { delay } from "../utils/delay.utils.js";
|
||||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||||
@@ -14,6 +16,7 @@ export let isServerRunning = false;
|
|||||||
|
|
||||||
const port = parseInt(process.env.TCP_PORT ?? "2222", 10);
|
const port = parseInt(process.env.TCP_PORT ?? "2222", 10);
|
||||||
|
|
||||||
|
// This is the parser for zebra scanners
|
||||||
const parseTcpAlert = (input: string) => {
|
const parseTcpAlert = (input: string) => {
|
||||||
// guard
|
// guard
|
||||||
const colonIndex = input.indexOf(":");
|
const colonIndex = input.indexOf(":");
|
||||||
@@ -74,6 +77,24 @@ export const startTCPServer = async () => {
|
|||||||
|
|
||||||
printerListen(printerData as PrinterData);
|
printerListen(printerData as PrinterData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if its a dock door scanner
|
||||||
|
// TODO: move to the db and get real info lol
|
||||||
|
const dockdoorScanners = await db.select().from(dockDoorScanners);
|
||||||
|
|
||||||
|
if (dockdoorScanners.some((s) => s.ip === ip.replace("::ffff:", ""))) {
|
||||||
|
console.log("dock door logic");
|
||||||
|
|
||||||
|
const currentDock = dockdoorScanners.filter(
|
||||||
|
(s) => s.ip === ip.replace("::ffff:", ""),
|
||||||
|
);
|
||||||
|
|
||||||
|
// send the data + dock scan over
|
||||||
|
loadUnit({
|
||||||
|
dockId: currentDock[0]?.dockId ?? "0",
|
||||||
|
sscc: data.toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("end", () => {
|
socket.on("end", () => {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export async function aggregateRouteHitsForBusinessDay() {
|
|||||||
|
|
||||||
const rows = await db
|
const rows = await db
|
||||||
.select({
|
.select({
|
||||||
businessDate: sql<string>`${businessDate}`,
|
businessDate: sql<string>`CAST(${businessDate} AS date)`,
|
||||||
method: analytics.method,
|
method: analytics.method,
|
||||||
routePattern: analytics.routePattern,
|
routePattern: analytics.routePattern,
|
||||||
module: sql<string>`COALESCE(${analytics.module}, 'unknown')`,
|
module: sql<string>`COALESCE(${analytics.module}, 'unknown')`,
|
||||||
@@ -105,9 +105,16 @@ export async function aggregateRouteHitsForBusinessDay() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const values = rows.map((row) => ({
|
||||||
|
...row,
|
||||||
|
businessDate: row.businessDate,
|
||||||
|
firstHitAt: new Date(row.firstHitAt),
|
||||||
|
lastHitAt: new Date(row.lastHitAt),
|
||||||
|
}));
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.insert(analyticsDaily)
|
.insert(analyticsDaily)
|
||||||
.values(rows)
|
.values(values)
|
||||||
.onConflictDoUpdate({
|
.onConflictDoUpdate({
|
||||||
target: [
|
target: [
|
||||||
analyticsDaily.businessDate,
|
analyticsDaily.businessDate,
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import { createAccessControl } from "better-auth/plugins/access";
|
import { createAccessControl } from "better-auth/plugins/access";
|
||||||
|
import { adminAc, defaultStatements } from "better-auth/plugins/admin/access";
|
||||||
|
|
||||||
export const statement = {
|
export const statement = {
|
||||||
app: ["read", "create", "share", "update", "delete", "readAll"],
|
...defaultStatements,
|
||||||
user: ["ban"],
|
app: ["read", "create", "update", "delete", "readAll"],
|
||||||
quality: ["read", "create", "share", "update", "delete", "readAll"],
|
quality: ["read", "create", "update", "delete", "readAll"],
|
||||||
notifications: ["read", "create", "share", "update", "delete", "readAll"],
|
logistics: ["read", "create", "update", "delete", "readAll"],
|
||||||
|
mobile: ["read", "create", "update", "delete", "readAll"],
|
||||||
|
openDock: ["read", "create", "update", "delete"],
|
||||||
|
notifications: ["read", "create", "update", "delete", "readAll"],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const ac = createAccessControl(statement);
|
export const ac = createAccessControl(statement);
|
||||||
@@ -12,15 +16,50 @@ export const ac = createAccessControl(statement);
|
|||||||
export const user = ac.newRole({
|
export const user = ac.newRole({
|
||||||
app: ["read", "create"],
|
app: ["read", "create"],
|
||||||
notifications: ["read", "create"],
|
notifications: ["read", "create"],
|
||||||
|
openDock: ["read"],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const manager = ac.newRole({
|
||||||
|
app: ["read", "create", "update"],
|
||||||
|
mobile: ["read", "create", "update"],
|
||||||
|
openDock: ["read", "create", "update"],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const transport = ac.newRole({
|
||||||
|
app: ["read", "create", "update"],
|
||||||
|
openDock: ["read", "create", "update"],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const admin = ac.newRole({
|
export const admin = ac.newRole({
|
||||||
app: ["read", "create", "update"],
|
app: ["read", "create", "update"],
|
||||||
|
mobile: ["read", "create", "update"],
|
||||||
|
user: ["create", "update", "ban"],
|
||||||
|
openDock: ["read", "create", "update"],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const systemAdmin = ac.newRole({
|
export const systemAdmin = ac.newRole({
|
||||||
app: ["read", "create", "share", "update", "delete", "readAll"],
|
...adminAc.statements,
|
||||||
user: ["ban"],
|
app: ["read", "create", "update", "delete", "readAll"],
|
||||||
quality: ["read", "create", "share", "update", "delete", "readAll"],
|
quality: ["read", "create", "update", "delete", "readAll"],
|
||||||
notifications: ["read", "create", "share", "update", "delete", "readAll"],
|
mobile: ["read", "create", "update", "delete", "readAll"],
|
||||||
|
logistics: ["read", "create", "update", "delete", "readAll"],
|
||||||
|
notifications: ["read", "create", "update", "delete", "readAll"],
|
||||||
|
openDock: ["read", "create", "update", "delete"],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* example usage
|
||||||
|
const canCreateProject = await authClient.admin.hasPermission({
|
||||||
|
permissions: {
|
||||||
|
project: ["create"],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// You can also check multiple resource permissions at the same time
|
||||||
|
const canCreateProjectAndCreateSale = await authClient.admin.hasPermission({
|
||||||
|
permissions: {
|
||||||
|
project: ["create"],
|
||||||
|
sale: ["create"]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
//import { eq } from "drizzle-orm";
|
//import { eq } from "drizzle-orm";
|
||||||
import { db } from "../db/db.controller.js";
|
import { db } from "../db/db.controller.js";
|
||||||
import * as rawSchema from "../db/schema/auth.schema.js";
|
import * as rawSchema from "../db/schema/auth.schema.js";
|
||||||
import { ac, admin, systemAdmin, user } from "./auth.permissions.js";
|
import { ac, admin, manager, systemAdmin, user } from "./auth.permissions.js";
|
||||||
import { allowedOrigins } from "./cors.utils.js";
|
import { allowedOrigins } from "./cors.utils.js";
|
||||||
import { sendEmail } from "./sendEmail.utils.js";
|
import { sendEmail } from "./sendEmail.utils.js";
|
||||||
|
|
||||||
@@ -163,6 +163,7 @@ export const auth = betterAuth({
|
|||||||
roles: {
|
roles: {
|
||||||
admin,
|
admin,
|
||||||
user,
|
user,
|
||||||
|
manager,
|
||||||
systemAdmin,
|
systemAdmin,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const allowedOrigins = [
|
|||||||
`http://${process.env.PROD_SERVER}:3100`, // temp
|
`http://${process.env.PROD_SERVER}:3100`, // temp
|
||||||
`http://usmcd1olp082:3000`,
|
`http://usmcd1olp082:3000`,
|
||||||
`${process.env.EXTERNAL_URL}`, // internal docker
|
`${process.env.EXTERNAL_URL}`, // internal docker
|
||||||
|
"chrome-extension://mddoackclclnbkmofficmmepfnadolfa",
|
||||||
];
|
];
|
||||||
export const lstCors = () => {
|
export const lstCors = () => {
|
||||||
return cors({
|
return cors({
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export async function generateUniquePin() {
|
|||||||
const pin = generateSixDigitPin();
|
const pin = generateSixDigitPin();
|
||||||
|
|
||||||
const existing = await db.query.scanUser.findFirst({
|
const existing = await db.query.scanUser.findFirst({
|
||||||
where: (u, { eq }) => eq(u.pinHash, pin), // ⚠️ we'll fix this below
|
where: (u, { eq }) => eq(u.pinHash, pin),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!existing)
|
if (!existing)
|
||||||
@@ -37,3 +37,13 @@ export async function generateUniquePin() {
|
|||||||
room: "",
|
room: "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// export const pinExists = async (pin: string | number) => {
|
||||||
|
// const existing = await db.query.scanUser.findFirst({
|
||||||
|
// where: (u, { eq }) => eq(u.pinHash, pin),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (!existing) return true;
|
||||||
|
|
||||||
|
// return false;
|
||||||
|
// };
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ export interface ReturnHelper<T = unknown[]> {
|
|||||||
| "tcp"
|
| "tcp"
|
||||||
| "logistics"
|
| "logistics"
|
||||||
| "admin"
|
| "admin"
|
||||||
| "mobile";
|
| "mobile"
|
||||||
|
| "dockdoor";
|
||||||
subModule: string;
|
subModule: string;
|
||||||
|
|
||||||
level: "info" | "error" | "debug" | "fatal" | "warn";
|
level: "info" | "error" | "debug" | "fatal" | "warn";
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
import { routeHitMiddleware } from "../middleware/routeHit.middleware.js";
|
|
||||||
import getActiveJobs from "./cronerActiveJobs.route.js";
|
import getActiveJobs from "./cronerActiveJobs.route.js";
|
||||||
import jobStatusChange from "./cronerStatusChange.route.js";
|
import jobStatusChange from "./cronerStatusChange.route.js";
|
||||||
export const setupUtilsRoutes = (baseUrl: string, app: Express) => {
|
export const setupUtilsRoutes = (baseUrl: string, app: Express) => {
|
||||||
app.use(routeHitMiddleware);
|
|
||||||
app.use(`${baseUrl}/api/utils/croner`, getActiveJobs);
|
app.use(`${baseUrl}/api/utils/croner`, getActiveJobs);
|
||||||
app.use(`${baseUrl}/api/utils/croner`, jobStatusChange);
|
app.use(`${baseUrl}/api/utils/croner`, jobStatusChange);
|
||||||
};
|
};
|
||||||
|
|||||||
29
backend/warehousing/warehousing.ppooMonitor.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { emitToRoom } from "../socket.io/roomEmitter.socket.js";
|
||||||
|
import { hasRoomMembers } from "../socket.io/roomService.socket.js";
|
||||||
|
import { runProdApi } from "../utils/prodEndpoint.utils.js";
|
||||||
|
|
||||||
|
export const ppoRun = async () => {
|
||||||
|
const laneData = await runProdApi({
|
||||||
|
method: "post",
|
||||||
|
endpoint: "/public/v1.1/Warehousing/GetWarehouseUnits",
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
laneIds: ["0"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
return laneData?.data ?? [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ppooMonitoring = async () => {
|
||||||
|
if (!hasRoomMembers(`ppoo`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitToRoom("ppoo", {
|
||||||
|
type: "snapshot",
|
||||||
|
items: await ppoRun(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
} as any);
|
||||||
|
};
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
<title>Logistics Support Tool</title>
|
<title>Logistics Support Tool</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const configScript = document.createElement("script");
|
const configScript = document.createElement("script");
|
||||||
configScript.src = `${window.location.origin}/lst/api/lst-config.js`;
|
configScript.src = `${window.location.origin}/lst/api/lst-config.js`;
|
||||||
|
|||||||
699
frontend/package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@base-ui/react": "^1.5.0",
|
||||||
"@fontsource-variable/inter": "^5.2.8",
|
"@fontsource-variable/inter": "^5.2.8",
|
||||||
"@tailwindcss/vite": "^4.2.1",
|
"@tailwindcss/vite": "^4.2.1",
|
||||||
"@tanstack/react-form": "^1.28.5",
|
"@tanstack/react-form": "^1.28.5",
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
"tailwind-merge": "^3.5.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
"tailwindcss": "^4.2.1",
|
"tailwindcss": "^4.2.1",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
|
"vite-imagetools": "^10.0.0",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -439,6 +441,15 @@
|
|||||||
"@babel/core": "^7.0.0-0"
|
"@babel/core": "^7.0.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@babel/runtime": {
|
||||||
|
"version": "7.29.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
|
||||||
|
"integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.28.6",
|
"version": "7.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
||||||
@@ -484,6 +495,66 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@base-ui/react": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.29.2",
|
||||||
|
"@base-ui/utils": "0.2.9",
|
||||||
|
"@floating-ui/react-dom": "^2.1.8",
|
||||||
|
"@floating-ui/utils": "^0.2.11",
|
||||||
|
"use-sync-external-store": "^1.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@date-fns/tz": "^1.2.0",
|
||||||
|
"@types/react": "^17 || ^18 || ^19",
|
||||||
|
"date-fns": "^4.0.0",
|
||||||
|
"react": "^17 || ^18 || ^19",
|
||||||
|
"react-dom": "^17 || ^18 || ^19"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@date-fns/tz": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"date-fns": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@base-ui/utils": {
|
||||||
|
"version": "0.2.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.2.9.tgz",
|
||||||
|
"integrity": "sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.29.2",
|
||||||
|
"@floating-ui/utils": "^0.2.11",
|
||||||
|
"reselect": "^5.1.1",
|
||||||
|
"use-sync-external-store": "^1.6.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^17 || ^18 || ^19",
|
||||||
|
"react": "^17 || ^18 || ^19",
|
||||||
|
"react-dom": "^17 || ^18 || ^19"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@better-auth/utils": {
|
"node_modules/@better-auth/utils": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.1.tgz",
|
||||||
@@ -649,6 +720,16 @@
|
|||||||
"node": "^16.13.0 || >=18.0.0"
|
"node": "^16.13.0 || >=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@emnapi/runtime": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.27.4",
|
"version": "0.27.4",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz",
|
||||||
@@ -1333,6 +1414,519 @@
|
|||||||
"url": "https://github.com/sponsors/nzakas"
|
"url": "https://github.com/sponsors/nzakas"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@img/colour": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-darwin-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-darwin-arm64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-darwin-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-darwin-x64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-ppc64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-riscv64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-arm": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-arm": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-arm64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-ppc64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-ppc64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-riscv64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-riscv64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-s390x": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-s390x": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-x64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-wasm32": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
|
||||||
|
"cpu": [
|
||||||
|
"wasm32"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/runtime": "^1.7.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-win32-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-win32-ia32": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-win32-x64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@inquirer/ansi": {
|
"node_modules/@inquirer/ansi": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
|
||||||
@@ -3163,6 +3757,28 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/pluginutils": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "^1.0.0",
|
||||||
|
"estree-walker": "^2.0.2",
|
||||||
|
"picomatch": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.59.0",
|
"version": "4.59.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
||||||
@@ -6672,6 +7288,12 @@
|
|||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/estree-walker": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/esutils": {
|
"node_modules/esutils": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||||
@@ -7511,6 +8133,15 @@
|
|||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/imagetools-core": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/imagetools-core/-/imagetools-core-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-xQjs+2vrxLnAjCq+omuNkd5UQTld9/bP8+YT0LyYTlKfuSQtgUBvqhUwGugzSAh6sCdN+LnROMuLswn5hZ9Fhg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/import-fresh": {
|
"node_modules/import-fresh": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||||
@@ -10460,6 +11091,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/reselect": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/resolve-from": {
|
"node_modules/resolve-from": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||||
@@ -10638,7 +11275,6 @@
|
|||||||
"version": "7.7.4",
|
"version": "7.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||||
"dev": true,
|
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@@ -10804,6 +11440,50 @@
|
|||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sharp": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@img/colour": "^1.0.0",
|
||||||
|
"detect-libc": "^2.1.2",
|
||||||
|
"semver": "^7.7.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-darwin-arm64": "0.34.5",
|
||||||
|
"@img/sharp-darwin-x64": "0.34.5",
|
||||||
|
"@img/sharp-libvips-darwin-arm64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-darwin-x64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-arm": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-arm64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-ppc64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-riscv64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-s390x": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linux-x64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
|
||||||
|
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
|
||||||
|
"@img/sharp-linux-arm": "0.34.5",
|
||||||
|
"@img/sharp-linux-arm64": "0.34.5",
|
||||||
|
"@img/sharp-linux-ppc64": "0.34.5",
|
||||||
|
"@img/sharp-linux-riscv64": "0.34.5",
|
||||||
|
"@img/sharp-linux-s390x": "0.34.5",
|
||||||
|
"@img/sharp-linux-x64": "0.34.5",
|
||||||
|
"@img/sharp-linuxmusl-arm64": "0.34.5",
|
||||||
|
"@img/sharp-linuxmusl-x64": "0.34.5",
|
||||||
|
"@img/sharp-wasm32": "0.34.5",
|
||||||
|
"@img/sharp-win32-arm64": "0.34.5",
|
||||||
|
"@img/sharp-win32-ia32": "0.34.5",
|
||||||
|
"@img/sharp-win32-x64": "0.34.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
@@ -11837,6 +12517,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vite-imagetools": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite-imagetools/-/vite-imagetools-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-+83L32YPU/2BOHWhudO2+9T5HBvb3+0qHoUNN7fb0+XcAoXilx7aE25cDPWU5kBi5Yc750zYCvHxgfyR+tAuMA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@rollup/pluginutils": "^5.0.5",
|
||||||
|
"imagetools-core": "^9.1.0",
|
||||||
|
"sharp": "^0.34.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=22.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vite": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/web-streams-polyfill": {
|
"node_modules/web-streams-polyfill": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@base-ui/react": "^1.5.0",
|
||||||
"@fontsource-variable/inter": "^5.2.8",
|
"@fontsource-variable/inter": "^5.2.8",
|
||||||
"@tailwindcss/vite": "^4.2.1",
|
"@tailwindcss/vite": "^4.2.1",
|
||||||
"@tanstack/react-form": "^1.28.5",
|
"@tanstack/react-form": "^1.28.5",
|
||||||
@@ -21,6 +22,8 @@
|
|||||||
"better-auth": "^1.5.5",
|
"better-auth": "^1.5.5",
|
||||||
"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-tz": "^3.2.0",
|
||||||
"lucide-react": "^0.577.0",
|
"lucide-react": "^0.577.0",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"radix-ui": "^1.4.3",
|
"radix-ui": "^1.4.3",
|
||||||
@@ -34,9 +37,8 @@
|
|||||||
"tailwind-merge": "^3.5.0",
|
"tailwind-merge": "^3.5.0",
|
||||||
"tailwindcss": "^4.2.1",
|
"tailwindcss": "^4.2.1",
|
||||||
"tw-animate-css": "^1.4.0",
|
"tw-animate-css": "^1.4.0",
|
||||||
"zod": "^4.3.6",
|
"vite-imagetools": "^10.0.0",
|
||||||
"date-fns": "^4.1.0",
|
"zod": "^4.3.6"
|
||||||
"date-fns-tz": "^3.2.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.36.0",
|
"@eslint/js": "^9.36.0",
|
||||||
|
|||||||
BIN
frontend/public/imgs/docs/mobile/critical_update.png
Normal file
|
After Width: | Height: | Size: 483 KiB |
BIN
frontend/public/imgs/docs/mobile/ehs_homeScreen.png
Normal file
|
After Width: | Height: | Size: 613 KiB |
BIN
frontend/public/imgs/docs/mobile/ehs_menu.png
Normal file
|
After Width: | Height: | Size: 403 KiB |
BIN
frontend/public/imgs/docs/mobile/stagenow.png
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
frontend/public/imgs/docs/mobile/test2-1.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/tools.png
Normal file
|
After Width: | Height: | Size: 268 KiB |
BIN
frontend/public/imgs/docs/mobile/update.png
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
frontend/public/imgs/docs/mobile/usbow1-1.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/usbow1-2.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/usbow1-3.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
frontend/public/imgs/docs/mobile/usday1-1.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/usday1-2.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/usday1-3.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
frontend/public/imgs/docs/mobile/usmar1-1.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
frontend/public/imgs/docs/mobile/usmar1-2.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/usmar1-3.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
frontend/public/imgs/docs/mobile/usstp1-1.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/usstp1-2.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
frontend/public/imgs/docs/mobile/usstp1-3.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
frontend/public/imgs/docs/mobile/usweb1-1.png
Normal file
|
After Width: | Height: | Size: 28 KiB |