Compare commits
5 Commits
2ebf695526
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ff10dfcb2 | |||
| 9a0bb18c5b | |||
| 1838c6f1e9 | |||
| 3a24d62957 | |||
| 6a14bab30c |
94
README.md
94
README.md
@@ -7,7 +7,7 @@
|
||||
Quick summary of current rewrite/migration goal.
|
||||
|
||||
- **Phase:** Backend rewrite
|
||||
- **Last updated:** 2026-05-27
|
||||
- **Last updated:** 2026-06-17
|
||||
|
||||
---
|
||||
|
||||
@@ -39,21 +39,91 @@ _Status legend:_
|
||||
|
||||
---
|
||||
|
||||
## Setup / Installation
|
||||
# Install
|
||||
|
||||
How to run the current version of the app.
|
||||
## Files needed to be downloaded before install.
|
||||
|
||||
### To run the server
|
||||
|
||||
- [PostgresSQL](https://www.postgresql.org/download/windows/) - current version using is 17
|
||||
- [NodeJS](https://nodejs.org)
|
||||
- [NSSM](https://nssm.cc/)
|
||||
|
||||
### To manage the server
|
||||
|
||||
- [VSCODE](https://code.visualstudio.com/)
|
||||
|
||||
## Creating directories needed
|
||||
|
||||
- Create a new folder where we will host the server files.
|
||||
- Copy the nssm.exe into this folder
|
||||
- Copy the get the build from the releases and extract.
|
||||
- This will house all the compiles and minified files needed to start the server up, this includes the frontend.
|
||||
- Save the nssm.exe into this folder as well, this will be used to control the service.
|
||||
|
||||
## Do the initial install
|
||||
|
||||
### DB instal setup
|
||||
|
||||
1. Install postgres
|
||||
2. Open pgAdmin
|
||||
3. create a new Database named lst_db_v3. this can also be to your liking
|
||||
|
||||
### Initial server setup
|
||||
|
||||
1. Open VSCode and navigate to the folder where you extracted the files.
|
||||
2. Click trusted when it pops up.
|
||||
3. Open a terminal window inside vscode.
|
||||
4. Run the install script this will install all dependence's needed as well as do all the database migrations
|
||||
|
||||
|
||||
### Create the .env file
|
||||
|
||||
In the root of the folder create a new .env file by renaming .env-example to .env
|
||||
|
||||
change all the parameters to your desired server
|
||||
|
||||
```bash
|
||||
git clone https://git.tuffraid.net/cowch/lst_v3.git
|
||||
cd lst_v3
|
||||
npm install
|
||||
npm run install --omit=dev
|
||||
```
|
||||
|
||||
Rename the .env-example to .env
|
||||
Next we want to do an initial db
|
||||
|
||||
Update all the fields
|
||||
|
||||
```bash
|
||||
```bash
|
||||
npm run dev:db:migrate
|
||||
npm run dev
|
||||
```
|
||||
```
|
||||
|
||||
### Run the start command to get all the basic settings and modules installed
|
||||
|
||||
1. Run the below
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
### Creating first user.
|
||||
|
||||
Open http://[SERVER]:[PORT]/api/docs or postman and create a user.
|
||||
- Please do not try to manually enter a new user this is due to how the password is hashed, as well as setting systemAdmin for the first user.
|
||||
- Change the server and port to what you changed in the DB.
|
||||
|
||||
### Running as a serivice.
|
||||
|
||||
You want to CD into the scripts folder.
|
||||
|
||||
```bash
|
||||
cd .\scripts\
|
||||
```
|
||||
|
||||
Next use the example command below to get the service up and running.
|
||||
|
||||
- Options legend
|
||||
- serviceName = not recommended to change to reduce issues with the update process
|
||||
- option = use install for the install, but you can use this script later to stop, start, restart the service.
|
||||
- appPath = where did you extract the server files
|
||||
- description = no need to change this unless you want it to be something else
|
||||
- command = do not change this unless you know what your doing and really need to change this.
|
||||
|
||||
```powershell
|
||||
.\services.ps1 -serviceName "LSTV3_app" -option "install" -appPath "D:\LS_V3T" -description "Logistics Support Tool V3" -command "run start"
|
||||
```
|
||||
|
||||
@@ -9,8 +9,6 @@ import os from "node:os";
|
||||
import { apiReference } from "@scalar/express-api-reference";
|
||||
// const port = 3000;
|
||||
import type { OpenAPIV3_1 } from "openapi-types";
|
||||
import { cronerActiveJobs } from "../scaler/cronerActiveJobs.spec.js";
|
||||
import { cronerStatusChange } from "../scaler/cronerStatusChange.spec.js";
|
||||
import { prodLoginSpec } from "../scaler/login.spec.js";
|
||||
import { openDockApt } from "../scaler/opendockGetRelease.spec.js";
|
||||
import { prodRestartSpec } from "../scaler/prodSqlRestart.spec.js";
|
||||
@@ -125,8 +123,6 @@ export const setupApiDocsRoutes = (baseUrl: string, app: Express) => {
|
||||
...prodLoginSpec,
|
||||
...prodRegisterSpec,
|
||||
//...mergedDatamart,
|
||||
...cronerActiveJobs,
|
||||
...cronerStatusChange,
|
||||
...openDockApt,
|
||||
|
||||
// Add more specs here as you build features
|
||||
|
||||
@@ -275,10 +275,10 @@ export const runDatamartQuery = async (data: Data) => {
|
||||
.replace("[startDate]", `${data.options.startDate}`)
|
||||
.replace("[endDate]", `${data.options.endDate}`)
|
||||
.replace(
|
||||
"and p.IdArtikelvarianten in ([articles])",
|
||||
"and pl.ArticleHumanReadableId IN ([articles]) ",
|
||||
data.options.articles
|
||||
? `and p.IdArtikelvarianten in (${data.options.articles})`
|
||||
: "--and p.IdArtikelvarianten in ([articles])",
|
||||
? `and pl.ArticleHumanReadableId IN (${data.options.articles})`
|
||||
: "--and pl.ArticleHumanReadableId IN ([articles])",
|
||||
);
|
||||
break;
|
||||
default:
|
||||
|
||||
57
backend/logistics/logistics.dm.repost.route.ts
Normal file
57
backend/logistics/logistics.dm.repost.route.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Router } from "express";
|
||||
import { requireAuth } from "../middleware/auth.middleware.js";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { postData } from "./logistics.dm.postData.js";
|
||||
|
||||
const r = Router();
|
||||
|
||||
r.post("/", requireAuth, async (req, res) => {
|
||||
let posting: any;
|
||||
|
||||
|
||||
if (req.body.type !== "forecast" || req.body.type !== "orders") {
|
||||
return apiReturn(res, {
|
||||
success: false,
|
||||
level: "error",
|
||||
module: "dm",
|
||||
subModule: "repost",
|
||||
message: "You must pass over a proper type.",
|
||||
data: [],
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
||||
if (req.body.type === "forecast") {
|
||||
posting = await postData(
|
||||
{
|
||||
type: "forecast",
|
||||
endpoint: "/public/v1.0/DemandManagement/DELFOR",
|
||||
data: req.body.data as any,
|
||||
},
|
||||
req.user,
|
||||
);
|
||||
}
|
||||
|
||||
if (req.body.type === "orders") {
|
||||
posting = await postData(
|
||||
{
|
||||
type: "orders",
|
||||
endpoint: "/public/v1.0/DemandManagement/ORDERS",
|
||||
data: req.body.data as any,
|
||||
},
|
||||
req.user,
|
||||
);
|
||||
}
|
||||
|
||||
return apiReturn(res, {
|
||||
success: posting.success,
|
||||
level: posting.success ? "info" : "error",
|
||||
module: "dm",
|
||||
subModule: "repost",
|
||||
message: posting.message,
|
||||
data: [],
|
||||
status: 200,
|
||||
});
|
||||
});
|
||||
|
||||
export default r;
|
||||
@@ -1,74 +1,73 @@
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
|
||||
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
|
||||
SELECT
|
||||
r.[ArticleHumanReadableId]
|
||||
,[ReleaseNumber]
|
||||
,h.CustomerOrderNumber
|
||||
,x.CustomerLineItemNumber
|
||||
,[CustomerReleaseNumber]
|
||||
,[ReleaseState]
|
||||
,[DeliveryState]
|
||||
,ea.JournalNummer as BOL_Number
|
||||
,[ReleaseConfirmationState]
|
||||
,[PlanningState]
|
||||
DECLARE @StartDate DATE = '[startDate]'
|
||||
DECLARE @EndDate DATE = '[endDate]'
|
||||
|
||||
;WITH bol_20 AS ( -- 2.0 BOL, one per release (newest doc wins)
|
||||
SELECT pos.ReleaseId,
|
||||
dd.JournalNumber,
|
||||
ROW_NUMBER() OVER (PARTITION BY pos.ReleaseId
|
||||
ORDER BY dd.ShippingDate DESC) AS rn
|
||||
FROM [outboundDelivery].[DeliveryDocumentPosition] (nolock) pos
|
||||
JOIN [outboundDelivery].[DeliveryDocument] (nolock) dd
|
||||
ON dd.Id = pos.DeliveryDocumentId
|
||||
-- WHERE dd.DocumentType = <BOL value> -- see note below
|
||||
)
|
||||
SELECT
|
||||
r.[ArticleHumanReadableId]
|
||||
,[ReleaseNumber]
|
||||
,h.CustomerOrderNumber
|
||||
,x.CustomerLineItemNumber
|
||||
,[CustomerReleaseNumber]
|
||||
,[ReleaseState]
|
||||
,[DeliveryState]
|
||||
,COALESCE(ea.JournalNummer, bol_20.JournalNumber) AS BOL_Number -- 1.0 or 2.0
|
||||
,[ReleaseConfirmationState]
|
||||
,[PlanningState]
|
||||
,format(r.[OrderDate], 'yyyy-MM-dd HH:mm') as OrderDate
|
||||
--,r.[OrderDate]
|
||||
,FORMAT(r.[DeliveryDate], 'yyyy-MM-dd HH:mm') as DeliveryDate
|
||||
--,r.[DeliveryDate]
|
||||
,FORMAT(r.[LoadingDate], 'yyyy-MM-dd HH:mm') as LoadingDate
|
||||
--,r.[LoadingDate]
|
||||
,[Quantity]
|
||||
,[DeliveredQuantity]
|
||||
,r.[AdditionalInformation1]
|
||||
,r.[AdditionalInformation2]
|
||||
,[TradeUnits]
|
||||
,[LoadingUnits]
|
||||
,[Trucks]
|
||||
,[LoadingToleranceType]
|
||||
,[SalesPrice]
|
||||
,[Currency]
|
||||
,[QuantityUnit]
|
||||
,[SalesPriceRemark]
|
||||
,r.[Remark]
|
||||
,[Irradiated]
|
||||
,r.[CreatedByEdi]
|
||||
,[DeliveryAddressHumanReadableId]
|
||||
,DeliveryAddressDescription
|
||||
,[CustomerArtNo]
|
||||
,[TotalPrice]
|
||||
,r.[ArticleAlias]
|
||||
,[Quantity]
|
||||
,[DeliveredQuantity]
|
||||
,r.[AdditionalInformation1]
|
||||
,r.[AdditionalInformation2]
|
||||
,[TradeUnits]
|
||||
,[LoadingUnits]
|
||||
,[Trucks]
|
||||
,[LoadingToleranceType]
|
||||
,[SalesPrice]
|
||||
,[Currency]
|
||||
,[QuantityUnit]
|
||||
,[SalesPriceRemark]
|
||||
,r.[Remark]
|
||||
,[Irradiated]
|
||||
,r.[CreatedByEdi]
|
||||
,[DeliveryAddressHumanReadableId]
|
||||
,DeliveryAddressDescription
|
||||
,[CustomerArtNo]
|
||||
,[TotalPrice]
|
||||
,r.[ArticleAlias]
|
||||
FROM [order].[Release] (nolock) AS r
|
||||
LEFT JOIN [order].LineItem AS x ON r.LineItemId = x.id
|
||||
LEFT JOIN [order].Header AS h ON x.HeaderId = h.id
|
||||
|
||||
FROM [order].[Release] (nolock) as r
|
||||
-- 1.0 BOL (legacy) — unchanged
|
||||
LEFT JOIN AlplaPROD_test1.dbo.V_LadePlanungenLadeAuftragAbruf (nolock) AS zz
|
||||
ON zz.AbrufIdAuftragsAbruf = r.ReleaseNumber
|
||||
LEFT JOIN (
|
||||
SELECT * FROM (
|
||||
SELECT ROW_NUMBER() OVER (PARTITION BY IdJournal ORDER BY add_date DESC) AS RowNum, *
|
||||
FROM [AlplaPROD_test1].[dbo].[T_Lieferungen] (nolock)
|
||||
) t WHERE RowNum = 1
|
||||
) AS ea ON zz.IdLieferschein = ea.IdJournal
|
||||
|
||||
left join
|
||||
[order].LineItem as x on
|
||||
-- 2.0 BOL (new)
|
||||
LEFT JOIN bol_20 ON bol_20.ReleaseId = r.Id AND bol_20.rn = 1
|
||||
|
||||
r.LineItemId = x.id
|
||||
|
||||
left join
|
||||
[order].Header as h on
|
||||
x.HeaderId = h.id
|
||||
|
||||
--bol stuff
|
||||
left join
|
||||
AlplaPROD_test1.dbo.V_LadePlanungenLadeAuftragAbruf (nolock) as zz
|
||||
on zz.AbrufIdAuftragsAbruf = r.ReleaseNumber
|
||||
|
||||
left join
|
||||
(select * from (SELECT
|
||||
ROW_NUMBER() OVER (PARTITION BY IdJournal ORDER BY add_date DESC) AS RowNum
|
||||
,*
|
||||
FROM [AlplaPROD_test1].[dbo].[T_Lieferungen] (nolock)) x
|
||||
|
||||
where RowNum = 1) as ea on
|
||||
zz.IdLieferschein = ea.IdJournal
|
||||
|
||||
where
|
||||
--r.ReleaseNumber = 1452
|
||||
|
||||
r.DeliveryDate between @StartDate AND @EndDate
|
||||
WHERE r.DeliveryDate BETWEEN @StartDate AND @EndDate
|
||||
and DeliveredQuantity > 0
|
||||
--and r.ArticleHumanReadableId in ([articles])
|
||||
--and Journalnummer = 169386
|
||||
@@ -1,79 +0,0 @@
|
||||
use AlplaPROD_test1
|
||||
/**
|
||||
|
||||
move this over to the delivery date range query once we have the shift data mapped over correctly.
|
||||
|
||||
update the psi stuff on this as well.
|
||||
**/
|
||||
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
|
||||
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
|
||||
SELECT
|
||||
r.[ArticleHumanReadableId]
|
||||
,[ReleaseNumber]
|
||||
,h.CustomerOrderNumber
|
||||
,x.CustomerLineItemNumber
|
||||
,[CustomerReleaseNumber]
|
||||
,[ReleaseState]
|
||||
,[DeliveryState]
|
||||
,ea.JournalNummer as BOL_Number
|
||||
,[ReleaseConfirmationState]
|
||||
,[PlanningState]
|
||||
--,format(r.[OrderDate], 'yyyy-MM-dd HH:mm') as OrderDate
|
||||
,r.[OrderDate]
|
||||
--,FORMAT(r.[DeliveryDate], 'yyyy-MM-dd HH:mm') as DeliveryDate
|
||||
,r.[DeliveryDate]
|
||||
--,FORMAT(r.[LoadingDate], 'yyyy-MM-dd HH:mm') as LoadingDate
|
||||
,r.[LoadingDate]
|
||||
,[Quantity]
|
||||
,[DeliveredQuantity]
|
||||
,r.[AdditionalInformation1]
|
||||
,r.[AdditionalInformation2]
|
||||
,[TradeUnits]
|
||||
,[LoadingUnits]
|
||||
,[Trucks]
|
||||
,[LoadingToleranceType]
|
||||
,[SalesPrice]
|
||||
,[Currency]
|
||||
,[QuantityUnit]
|
||||
,[SalesPriceRemark]
|
||||
,r.[Remark]
|
||||
,[Irradiated]
|
||||
,r.[CreatedByEdi]
|
||||
,[DeliveryAddressHumanReadableId]
|
||||
,DeliveryAddressDescription
|
||||
,[CustomerArtNo]
|
||||
,[TotalPrice]
|
||||
,r.[ArticleAlias]
|
||||
|
||||
FROM [order].[Release] (nolock) as r
|
||||
|
||||
left join
|
||||
[order].LineItem as x on
|
||||
|
||||
r.LineItemId = x.id
|
||||
|
||||
left join
|
||||
[order].Header as h on
|
||||
x.HeaderId = h.id
|
||||
|
||||
--bol stuff
|
||||
left join
|
||||
AlplaPROD_test1.dbo.V_LadePlanungenLadeAuftragAbruf (nolock) as zz
|
||||
on zz.AbrufIdAuftragsAbruf = r.ReleaseNumber
|
||||
|
||||
left join
|
||||
(select * from (SELECT
|
||||
ROW_NUMBER() OVER (PARTITION BY IdJournal ORDER BY add_date DESC) AS RowNum
|
||||
,*
|
||||
FROM [AlplaPROD_test1].[dbo].[T_Lieferungen] (nolock)) x
|
||||
|
||||
where RowNum = 1) as ea on
|
||||
zz.IdLieferschein = ea.IdJournal
|
||||
|
||||
where
|
||||
r.ArticleHumanReadableId in ([articles])
|
||||
--r.ReleaseNumber = 1452
|
||||
|
||||
and r.DeliveryDate between @StartDate AND @EndDate
|
||||
--and DeliveredQuantity > 0
|
||||
--and Journalnummer = 169386
|
||||
@@ -1,32 +1,72 @@
|
||||
use AlplaPROD_test1
|
||||
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
|
||||
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
|
||||
/*
|
||||
articles will need to be passed over as well as the date structure we want to see
|
||||
*/
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
select x.IdArtikelvarianten As Article,
|
||||
ProduktionAlias as Description,
|
||||
standort as MachineId,
|
||||
MaschinenBezeichnung as MachineName,
|
||||
--MaschZyklus as PlanningCycleTime,
|
||||
x.IdProdPlanung as LotNumber,
|
||||
FORMAT(ProdTag, 'MM/dd/yyyy') as ProductionDay,
|
||||
x.planMenge as TotalPlanned,
|
||||
ProduktionMenge as QTYPerDay,
|
||||
round(ProduktionMengeVPK, 2) PalDay,
|
||||
Status as finished
|
||||
--MaschStdAuslastung as nee
|
||||
|
||||
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock) as x
|
||||
|
||||
left join
|
||||
dbo.V_ProdPlanung (nolock) as p on
|
||||
x.IdProdPlanung = p.IdProdPlanung
|
||||
|
||||
where ProdTag between @start_date and @end_date
|
||||
and p.IdArtikelvarianten in ([articles])
|
||||
--and V_ProdLosProduktionJeProdTag_PLANNING.IdKunde = 10
|
||||
--and IdProdPlanung = 18442
|
||||
|
||||
order by ProdTag desc
|
||||
DECLARE @start_date date = '[startDate]'; --'2025-01-01'
|
||||
DECLARE @end_date date = '[endDate]'; --'2025-08-09'
|
||||
DECLARE @tz sysname = 'Eastern Standard Time'; -- usday1; use 'Central Standard Time' for usksc1
|
||||
DECLARE @shiftSeconds int = 7*3600; -- 07:00 production-day anchor
|
||||
--TODO: add in the proper time zone based on the env, get correcr shift time as well
|
||||
;WITH src AS (
|
||||
SELECT
|
||||
pl.RunningNumber, pl.ArticleHumanReadableId, pl.ArticleAlias, pl.ArticleDescription,
|
||||
pl.MachineLocation, pl.MachineDescription, pl.ProductionLotState, pl.ProductionInterrupt,
|
||||
pl.PlanQuantityPieces, pl.PlanQuantityLoadingUnit,
|
||||
CAST(pl.ProdStart AT TIME ZONE @tz AS datetime2(0)) AS StartLocal,
|
||||
CAST(pl.PlanEnd AT TIME ZONE @tz AS datetime2(0)) AS EndLocal
|
||||
FROM productionScheduling.ProductionLot AS pl
|
||||
WHERE pl.PlanEnd > pl.ProdStart
|
||||
and pl.publishState = 1
|
||||
and pl.ArticleHumanReadableId IN ([articles]) -- <-- article filter (was IdArtikelvarianten)
|
||||
--AND pl.RunningNumber = 28094 -- <-- lot filter (was IdProdPlanung); comment out for all
|
||||
),
|
||||
calc AS (
|
||||
SELECT *,
|
||||
DATEADD(SECOND, @shiftSeconds,
|
||||
CAST(CASE WHEN DATEDIFF(SECOND, CAST(StartLocal AS date), StartLocal) >= @shiftSeconds
|
||||
THEN CAST(StartLocal AS date)
|
||||
ELSE DATEADD(DAY,-1, CAST(StartLocal AS date)) END AS datetime2(0))) AS FirstBoundary
|
||||
FROM src
|
||||
),
|
||||
days AS ( -- one row per production day the lot touches
|
||||
SELECT RunningNumber, ArticleHumanReadableId, ArticleAlias, ArticleDescription, MachineLocation,
|
||||
MachineDescription, ProductionLotState, PlanQuantityPieces, PlanQuantityLoadingUnit,
|
||||
StartLocal, EndLocal, FirstBoundary AS DayStart
|
||||
FROM calc
|
||||
UNION ALL
|
||||
SELECT RunningNumber, ArticleHumanReadableId, ArticleAlias, ArticleDescription, MachineLocation,
|
||||
MachineDescription, ProductionLotState, PlanQuantityPieces, PlanQuantityLoadingUnit,
|
||||
StartLocal, EndLocal, DATEADD(DAY,1,DayStart)
|
||||
FROM days
|
||||
WHERE DATEADD(DAY,1,DayStart) < EndLocal
|
||||
),
|
||||
seg AS ( -- working seconds inside each production day
|
||||
SELECT *,
|
||||
DATEDIFF(SECOND,
|
||||
CASE WHEN StartLocal > DayStart THEN StartLocal ELSE DayStart END,
|
||||
CASE WHEN EndLocal < DATEADD(DAY,1,DayStart) THEN EndLocal ELSE DATEADD(DAY,1,DayStart) END
|
||||
) AS SegSec
|
||||
FROM days
|
||||
),
|
||||
cum AS ( -- cumulative seconds for telescoping round
|
||||
SELECT *,
|
||||
SUM(SegSec) OVER (PARTITION BY RunningNumber ORDER BY DayStart ROWS UNBOUNDED PRECEDING) AS CumEnd,
|
||||
SUM(SegSec) OVER (PARTITION BY RunningNumber ORDER BY DayStart ROWS UNBOUNDED PRECEDING) - SegSec AS CumStart,
|
||||
SUM(SegSec) OVER (PARTITION BY RunningNumber) AS DenomSec
|
||||
FROM seg
|
||||
)
|
||||
SELECT
|
||||
ArticleHumanReadableId AS Article,
|
||||
ArticleAlias AS Description,
|
||||
MachineLocation AS MachineId,
|
||||
MachineDescription AS MachineName,
|
||||
RunningNumber AS LotNumber,
|
||||
FORMAT(DayStart, 'MM/dd/yyyy') AS ProductionDay,
|
||||
PlanQuantityPieces AS TotalPlanned,
|
||||
ROUND(PlanQuantityPieces * 1.0 * CumEnd / DenomSec, 0)
|
||||
- ROUND(PlanQuantityPieces * 1.0 * CumStart / DenomSec, 0) AS QTYPerDay,
|
||||
ROUND(PlanQuantityLoadingUnit * CumEnd / DenomSec, 2)
|
||||
- ROUND(PlanQuantityLoadingUnit * CumStart / DenomSec, 2) AS PalDay,
|
||||
ProductionLotState AS finished
|
||||
FROM cum
|
||||
WHERE CAST(DayStart AS date) BETWEEN @start_date AND @end_date -- filter AFTER cumulative calc
|
||||
ORDER BY RunningNumber, DayStart DESC
|
||||
OPTION (MAXRECURSION 366);
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import type { OpenAPIV3_1 } from "openapi-types";
|
||||
|
||||
export const cronerActiveJobs: OpenAPIV3_1.PathsObject = {
|
||||
"/api/utils/croner": {
|
||||
get: {
|
||||
summary: "Cron jobs",
|
||||
description: "Returns all jobs on the server.",
|
||||
tags: ["Utils"],
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Jobs returned",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
status: {
|
||||
type: "boolean",
|
||||
format: "boolean",
|
||||
example: true,
|
||||
},
|
||||
uptime: {
|
||||
type: "number",
|
||||
format: "3454.34",
|
||||
example: 3454.34,
|
||||
},
|
||||
memoryUsage: {
|
||||
type: "string",
|
||||
format: "Heap: 11.62 MB / RSS: 86.31 MB",
|
||||
},
|
||||
sqlServerStats: {
|
||||
type: "number",
|
||||
format: "442127",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,94 +0,0 @@
|
||||
import type { OpenAPIV3_1 } from "openapi-types";
|
||||
|
||||
export const cronerStatusChange: OpenAPIV3_1.PathsObject = {
|
||||
"/api/utils/croner/{status}": {
|
||||
patch: {
|
||||
summary: "Pauses or Resume the Job",
|
||||
description:
|
||||
"When sending start or stop with job name it will resume or stop the job",
|
||||
tags: ["Utils"],
|
||||
|
||||
parameters: [
|
||||
{
|
||||
name: "status",
|
||||
in: "path",
|
||||
required: true,
|
||||
description: "Status change",
|
||||
schema: {
|
||||
type: "string",
|
||||
},
|
||||
example: "start",
|
||||
},
|
||||
{
|
||||
name: "limit",
|
||||
in: "query",
|
||||
required: false, // 👈 optional
|
||||
description: "Maximum number of records to return",
|
||||
schema: {
|
||||
type: "integer",
|
||||
minimum: 1,
|
||||
maximum: 100,
|
||||
},
|
||||
example: 10,
|
||||
},
|
||||
],
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
required: ["name"],
|
||||
properties: {
|
||||
name: {
|
||||
type: "string",
|
||||
example: "start",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
responses: {
|
||||
"200": {
|
||||
description: "Successful response",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
success: { type: "boolean", example: true },
|
||||
data: {
|
||||
type: "object",
|
||||
example: {
|
||||
name: "exampleName",
|
||||
value: "some value",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"400": {
|
||||
description: "Bad request",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
success: { type: "boolean", example: false },
|
||||
message: {
|
||||
type: "string",
|
||||
example: "Invalid name parameter",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,10 +1,14 @@
|
||||
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { LaptopMinimal } from "lucide-react";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarHeader,
|
||||
SidebarFooter,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { useSession } from "@/lib/auth-client";
|
||||
import { getSettings } from "../../lib/queries/getSettings";
|
||||
@@ -23,6 +27,7 @@ export function AppSidebar() {
|
||||
openDock: ["read"],
|
||||
}),
|
||||
);
|
||||
const { setOpen } = useSidebar();
|
||||
|
||||
// const { data: canReadWarehouse = false } = useQuery(
|
||||
// permissionQuery({
|
||||
@@ -36,7 +41,7 @@ export function AppSidebar() {
|
||||
collapsible="offcanvas"
|
||||
className="top-(--header-height) h-[calc(100svh-var(--header-height))]!"
|
||||
>
|
||||
<SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarContent>
|
||||
@@ -64,7 +69,24 @@ export function AppSidebar() {
|
||||
</SidebarContent>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
</SidebarContent>
|
||||
{session &&
|
||||
(session.user.role === "admin" ||
|
||||
session.user.role === "systemAdmin" ||
|
||||
session.user.role === "manager") && (
|
||||
<SidebarFooter>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton asChild>
|
||||
<Link to={"/apidocs"} onClick={() => setOpen(false)}>
|
||||
<LaptopMinimal />
|
||||
<span>Api docs</span>
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarFooter>
|
||||
)}
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as ForbiddenRouteImport } from './routes/forbidden'
|
||||
import { Route as AppDownRouteImport } from './routes/app-down'
|
||||
import { Route as ApidocsRouteImport } from './routes/apidocs'
|
||||
import { Route as AboutRouteImport } from './routes/about'
|
||||
import { Route as IndexRouteImport } from './routes/index'
|
||||
import { Route as DocsIndexRouteImport } from './routes/docs/index'
|
||||
import { Route as DocsDatamartRouteImport } from './routes/docs/datamart'
|
||||
import { Route as DocsSplatRouteImport } from './routes/docs/$'
|
||||
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
||||
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
||||
@@ -41,6 +43,11 @@ const AppDownRoute = AppDownRouteImport.update({
|
||||
path: '/app-down',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const ApidocsRoute = ApidocsRouteImport.update({
|
||||
id: '/apidocs',
|
||||
path: '/apidocs',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const AboutRoute = AboutRouteImport.update({
|
||||
id: '/about',
|
||||
path: '/about',
|
||||
@@ -56,6 +63,11 @@ const DocsIndexRoute = DocsIndexRouteImport.update({
|
||||
path: '/docs/',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const DocsDatamartRoute = DocsDatamartRouteImport.update({
|
||||
id: '/docs/datamart',
|
||||
path: '/docs/datamart',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const DocsSplatRoute = DocsSplatRouteImport.update({
|
||||
id: '/docs/$',
|
||||
path: '/docs/$',
|
||||
@@ -145,6 +157,7 @@ const WarehouseDockdoorscanningScansDockScansRoute =
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/about': typeof AboutRoute
|
||||
'/apidocs': typeof ApidocsRoute
|
||||
'/app-down': typeof AppDownRoute
|
||||
'/forbidden': typeof ForbiddenRoute
|
||||
'/login': typeof authLoginRoute
|
||||
@@ -155,6 +168,7 @@ export interface FileRoutesByFullPath {
|
||||
'/admin/settings': typeof AdminSettingsRoute
|
||||
'/admin/users': typeof AdminUsersRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
'/docs/datamart': typeof DocsDatamartRoute
|
||||
'/docs/': typeof DocsIndexRoute
|
||||
'/user/profile': typeof authUserProfileRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
@@ -168,6 +182,7 @@ export interface FileRoutesByFullPath {
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/about': typeof AboutRoute
|
||||
'/apidocs': typeof ApidocsRoute
|
||||
'/app-down': typeof AppDownRoute
|
||||
'/forbidden': typeof ForbiddenRoute
|
||||
'/login': typeof authLoginRoute
|
||||
@@ -178,6 +193,7 @@ export interface FileRoutesByTo {
|
||||
'/admin/settings': typeof AdminSettingsRoute
|
||||
'/admin/users': typeof AdminUsersRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
'/docs/datamart': typeof DocsDatamartRoute
|
||||
'/docs': typeof DocsIndexRoute
|
||||
'/user/profile': typeof authUserProfileRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
@@ -192,6 +208,7 @@ export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
'/': typeof IndexRoute
|
||||
'/about': typeof AboutRoute
|
||||
'/apidocs': typeof ApidocsRoute
|
||||
'/app-down': typeof AppDownRoute
|
||||
'/forbidden': typeof ForbiddenRoute
|
||||
'/(auth)/login': typeof authLoginRoute
|
||||
@@ -202,6 +219,7 @@ export interface FileRoutesById {
|
||||
'/admin/settings': typeof AdminSettingsRoute
|
||||
'/admin/users': typeof AdminUsersRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
'/docs/datamart': typeof DocsDatamartRoute
|
||||
'/docs/': typeof DocsIndexRoute
|
||||
'/(auth)/user/profile': typeof authUserProfileRoute
|
||||
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
@@ -217,6 +235,7 @@ export interface FileRouteTypes {
|
||||
fullPaths:
|
||||
| '/'
|
||||
| '/about'
|
||||
| '/apidocs'
|
||||
| '/app-down'
|
||||
| '/forbidden'
|
||||
| '/login'
|
||||
@@ -227,6 +246,7 @@ export interface FileRouteTypes {
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
| '/docs/$'
|
||||
| '/docs/datamart'
|
||||
| '/docs/'
|
||||
| '/user/profile'
|
||||
| '/user/resetpassword'
|
||||
@@ -240,6 +260,7 @@ export interface FileRouteTypes {
|
||||
to:
|
||||
| '/'
|
||||
| '/about'
|
||||
| '/apidocs'
|
||||
| '/app-down'
|
||||
| '/forbidden'
|
||||
| '/login'
|
||||
@@ -250,6 +271,7 @@ export interface FileRouteTypes {
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
| '/docs/$'
|
||||
| '/docs/datamart'
|
||||
| '/docs'
|
||||
| '/user/profile'
|
||||
| '/user/resetpassword'
|
||||
@@ -263,6 +285,7 @@ export interface FileRouteTypes {
|
||||
| '__root__'
|
||||
| '/'
|
||||
| '/about'
|
||||
| '/apidocs'
|
||||
| '/app-down'
|
||||
| '/forbidden'
|
||||
| '/(auth)/login'
|
||||
@@ -273,6 +296,7 @@ export interface FileRouteTypes {
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
| '/docs/$'
|
||||
| '/docs/datamart'
|
||||
| '/docs/'
|
||||
| '/(auth)/user/profile'
|
||||
| '/(auth)/user/resetpassword'
|
||||
@@ -287,6 +311,7 @@ export interface FileRouteTypes {
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
AboutRoute: typeof AboutRoute
|
||||
ApidocsRoute: typeof ApidocsRoute
|
||||
AppDownRoute: typeof AppDownRoute
|
||||
ForbiddenRoute: typeof ForbiddenRoute
|
||||
authLoginRoute: typeof authLoginRoute
|
||||
@@ -297,6 +322,7 @@ export interface RootRouteChildren {
|
||||
AdminSettingsRoute: typeof AdminSettingsRoute
|
||||
AdminUsersRoute: typeof AdminUsersRoute
|
||||
DocsSplatRoute: typeof DocsSplatRoute
|
||||
DocsDatamartRoute: typeof DocsDatamartRoute
|
||||
DocsIndexRoute: typeof DocsIndexRoute
|
||||
authUserProfileRoute: typeof authUserProfileRoute
|
||||
authUserResetpasswordRoute: typeof authUserResetpasswordRoute
|
||||
@@ -324,6 +350,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AppDownRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/apidocs': {
|
||||
id: '/apidocs'
|
||||
path: '/apidocs'
|
||||
fullPath: '/apidocs'
|
||||
preLoaderRoute: typeof ApidocsRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/about': {
|
||||
id: '/about'
|
||||
path: '/about'
|
||||
@@ -345,6 +378,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof DocsIndexRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/docs/datamart': {
|
||||
id: '/docs/datamart'
|
||||
path: '/docs/datamart'
|
||||
fullPath: '/docs/datamart'
|
||||
preLoaderRoute: typeof DocsDatamartRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/docs/$': {
|
||||
id: '/docs/$'
|
||||
path: '/docs/$'
|
||||
@@ -463,6 +503,7 @@ declare module '@tanstack/react-router' {
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
AboutRoute: AboutRoute,
|
||||
ApidocsRoute: ApidocsRoute,
|
||||
AppDownRoute: AppDownRoute,
|
||||
ForbiddenRoute: ForbiddenRoute,
|
||||
authLoginRoute: authLoginRoute,
|
||||
@@ -473,6 +514,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
AdminSettingsRoute: AdminSettingsRoute,
|
||||
AdminUsersRoute: AdminUsersRoute,
|
||||
DocsSplatRoute: DocsSplatRoute,
|
||||
DocsDatamartRoute: DocsDatamartRoute,
|
||||
DocsIndexRoute: DocsIndexRoute,
|
||||
authUserProfileRoute: authUserProfileRoute,
|
||||
authUserResetpasswordRoute: authUserResetpasswordRoute,
|
||||
|
||||
@@ -19,8 +19,10 @@ const RootLayout = () => {
|
||||
<div className="relative min-h-[calc(100svh-var(--header-height))]">
|
||||
<AppSidebar />
|
||||
|
||||
<main className="w-full p-4">
|
||||
<div className="mx-auto w-full max-w-7xl">
|
||||
<main className="w-full">
|
||||
<div className="mx-auto w-full flex justify-center">
|
||||
{" "}
|
||||
{/* className="mx-auto w-full max-w-7xl" use this for dashboards and stuff*/}
|
||||
<Outlet />
|
||||
</div>
|
||||
</main>
|
||||
@@ -31,7 +33,7 @@ const RootLayout = () => {
|
||||
</SidebarProvider>
|
||||
</ThemeProvider>
|
||||
{session && session.user.role === "systemAdmin" && (
|
||||
<TanStackRouterDevtools />
|
||||
<TanStackRouterDevtools position="bottom-right" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -248,7 +248,7 @@ function RouteComponent() {
|
||||
};
|
||||
//console.log(logs);
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col gap-1 max-w-7xl">
|
||||
<div className="flex gap-1 justify-end">
|
||||
<Button onClick={triggerBuild}>Trigger Build</Button>
|
||||
<Button onClick={() => clearRoom()}>Clear Logs</Button>
|
||||
|
||||
15
frontend/src/routes/apidocs.tsx
Normal file
15
frontend/src/routes/apidocs.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/apidocs")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<iframe
|
||||
src="/lst/api/docs"
|
||||
className="h-[calc(100vh-64px)] w-full border-0"
|
||||
title="LST API Docs"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import { Trash } from "lucide-react";
|
||||
import { Suspense, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "../../../components/ui/button";
|
||||
import { Spinner } from "../../../components/ui/spinner";
|
||||
import { api } from "../../../lib/apiHelper";
|
||||
import { authClient } from "../../../lib/auth-client";
|
||||
import { getArticleLinks } from "../../../lib/queries/getArticleLinks";
|
||||
import LstTable from "../../../lib/tableStuff/LstTable";
|
||||
import SearchableHeader from "../../../lib/tableStuff/SearchableHeader";
|
||||
import SkellyTable from "../../../lib/tableStuff/SkellyTable";
|
||||
import NewArticleLink from "./-components/NewArticleLink";
|
||||
import { api } from "../../../lib/apiHelper";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "../../../components/ui/button";
|
||||
import { Spinner } from "../../../components/ui/spinner";
|
||||
import { Trash } from "lucide-react";
|
||||
|
||||
export const Route = createFileRoute("/transportation/opendock/")({
|
||||
beforeLoad: async ({ location }) => {
|
||||
@@ -97,77 +97,77 @@ const ArticleLinkTable = () => {
|
||||
cell: (i) => i.getValue(),
|
||||
}),
|
||||
columnHelper.accessor("deleteUser", {
|
||||
header: ({ column }) => (
|
||||
<SearchableHeader
|
||||
column={column}
|
||||
title="Delete Link"
|
||||
searchable={false}
|
||||
/>
|
||||
),
|
||||
filterFn: "includesString",
|
||||
cell: (i) => {
|
||||
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
|
||||
const [activeToggle, setActiveToggle] = useState(false);
|
||||
|
||||
const onTrigger = async () => {
|
||||
setActiveToggle(true);
|
||||
|
||||
try {
|
||||
const res = await api.delete(
|
||||
`/opendock/articleCheck/${i.row.original.id}`,
|
||||
|
||||
{
|
||||
withCredentials: true,
|
||||
timeout: 5000,
|
||||
validateStatus: () => true,
|
||||
},
|
||||
);
|
||||
|
||||
if (res.data.success) {
|
||||
toast.success(`AV: ${i.row.original.av} was deleted.`);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
|
||||
if (!res.data.success) {
|
||||
toast.error(
|
||||
`AV: ${i.row.original.av} encountered an error when trying to delete: ${res.data.message}`,
|
||||
);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setActiveToggle(false);
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="destructive"
|
||||
disabled={activeToggle}
|
||||
onClick={onTrigger}
|
||||
>
|
||||
{activeToggle ? (
|
||||
<span>
|
||||
<Spinner />
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
<Trash />
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
header: ({ column }) => (
|
||||
<SearchableHeader
|
||||
column={column}
|
||||
title="Delete Link"
|
||||
searchable={false}
|
||||
/>
|
||||
),
|
||||
filterFn: "includesString",
|
||||
cell: (i) => {
|
||||
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
|
||||
const [activeToggle, setActiveToggle] = useState(false);
|
||||
|
||||
const onTrigger = async () => {
|
||||
setActiveToggle(true);
|
||||
|
||||
try {
|
||||
const res = await api.delete(
|
||||
`/opendock/articleCheck/${i.row.original.id}`,
|
||||
|
||||
{
|
||||
withCredentials: true,
|
||||
timeout: 5000,
|
||||
validateStatus: () => true,
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
|
||||
if (res.data.success) {
|
||||
toast.success(`AV: ${i.row.original.av} was deleted.`);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
|
||||
if (!res.data.success) {
|
||||
toast.error(
|
||||
`AV: ${i.row.original.av} encountered an error when trying to delete: ${res.data.message}`,
|
||||
);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setActiveToggle(false);
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="destructive"
|
||||
disabled={activeToggle}
|
||||
onClick={onTrigger}
|
||||
>
|
||||
{activeToggle ? (
|
||||
<span>
|
||||
<Spinner />
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
<Trash />
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
}),
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<div className="">
|
||||
<div>
|
||||
<div className="flex justify-end m-2">
|
||||
<Suspense
|
||||
|
||||
90
package-lock.json
generated
90
package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.57.0",
|
||||
"@scalar/express-api-reference": "^0.9.4",
|
||||
"@scalar/express-api-reference": "^0.9.20",
|
||||
"@socket.io/admin-ui": "^0.5.1",
|
||||
"archiver": "^7.0.1",
|
||||
"axios": "^1.13.6",
|
||||
@@ -44,7 +44,8 @@
|
||||
"socket.io": "^4.8.3",
|
||||
"socket.io-client": "^4.8.3",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^4.3.6"
|
||||
"zod": "^4.3.6",
|
||||
"zod-openapi": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.4.8",
|
||||
@@ -2424,46 +2425,61 @@
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@scalar/core": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/core/-/core-0.4.4.tgz",
|
||||
"integrity": "sha512-eXIG0opyQn45FzpTp0dAWFP1Vjcx+helgUAsa0uN36tyUR7DSmz2kRwHqqedzvPWryeRCKPz7/vwzKpETZp5lg==",
|
||||
"node_modules/@scalar/client-side-rendering": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/client-side-rendering/-/client-side-rendering-0.1.13.tgz",
|
||||
"integrity": "sha512-p8V4HgEWjaCpqsnhclg1pTfjE9JA0AWRr0ocBQHexoHo+pqnSs1d83Mv9rjH7R0FZJrlCSandZZeY3DMX2gYXQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/types": "0.7.4"
|
||||
"@scalar/schemas": "0.3.3",
|
||||
"@scalar/types": "0.12.3",
|
||||
"@scalar/validation": "0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/express-api-reference": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/express-api-reference/-/express-api-reference-0.9.4.tgz",
|
||||
"integrity": "sha512-KXG+VaMArCGcWhzDV2rfkHd+UF1HYevIFbO6cqFpd+az7QHvVT99BU8Yh60T1dmtCp504s0Pl/vcTyJ91fK1Ug==",
|
||||
"version": "0.9.20",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/express-api-reference/-/express-api-reference-0.9.20.tgz",
|
||||
"integrity": "sha512-J0P6qpYoL0kXvs/A/vuAwCqQFCYnErbXSB5/3lEGTbARuK0oGyMvl55dQyW5Ucq3CX1npuRejlTX6bxEprSvJA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/core": "0.4.4"
|
||||
"@scalar/client-side-rendering": "0.1.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/helpers": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.4.2.tgz",
|
||||
"integrity": "sha512-IrgrGVSahCfYDNWITazz4Q1BOndp5eEzlimRkfxiYn++KqeWyLfALyym1omqcdKGYtiSx1KIbKaUJL9vkjaN7w==",
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.8.1.tgz",
|
||||
"integrity": "sha512-yuiuBCadP5bjAnIv23QvifVN/NaMi9xBF6b8Wdk4QOzwzLPJmp699MAdf33J0A5i2qKcvnu32iz/VkEJmQRe5g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/types": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.7.4.tgz",
|
||||
"integrity": "sha512-1o9uf42lZ9YD0XP/HMWrwXN0unx6vFTTgtduA1F28Yloea9Pfv9N2R/t0wO91iSIzw4+NubEFolunbdb2QcgHA==",
|
||||
"node_modules/@scalar/schemas": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/schemas/-/schemas-0.3.3.tgz",
|
||||
"integrity": "sha512-qDcgFu6ta5Z90L9D2P6DFKzYesU+FW5+m55SGmdI4iRMRCwj5umHpec2Y2W/SJcCF6bbUZawMxuOH2Ja6rUNpQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/helpers": "0.4.2",
|
||||
"@scalar/helpers": "0.8.1",
|
||||
"@scalar/validation": "0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/types": {
|
||||
"version": "0.12.3",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.12.3.tgz",
|
||||
"integrity": "sha512-7zaXafbgTFmsJ/9AwYeExUWzXoZNyKOL0SEVAUWRaOndcjxpFCtwzuPrc1elMEWdHopWbY1Qe5pWKbE2aqG2HA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/helpers": "0.8.1",
|
||||
"nanoid": "^5.1.6",
|
||||
"type-fest": "^5.3.1",
|
||||
"zod": "^4.3.5"
|
||||
@@ -2472,6 +2488,15 @@
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/validation": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/validation/-/validation-0.6.0.tgz",
|
||||
"integrity": "sha512-tpmmG+/xRE2Kn9RpflU3AIyZv08v10+E1ZrJCx7z6+/91zHVxy0M73kC1LT4/8PbYNt85ywyC8+n+D99JdMcGA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@serialport/binding-mock": {
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-10.2.2.tgz",
|
||||
@@ -10566,9 +10591,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "5.1.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.7.tgz",
|
||||
"integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==",
|
||||
"version": "5.1.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz",
|
||||
"integrity": "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -13252,9 +13277,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.5.0.tgz",
|
||||
"integrity": "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==",
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz",
|
||||
"integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"dependencies": {
|
||||
"tagged-tag": "^1.0.0"
|
||||
@@ -13937,6 +13962,21 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/zod-openapi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/zod-openapi/-/zod-openapi-6.0.0.tgz",
|
||||
"integrity": "sha512-mS4eRJ4DGCPrg6elRbJqc/3nLe4EPVi8KiHRKZ7dcTR5m5orPy8EfoWmceAyGZAq71MAWuyrTTOag7W5N61ZPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22.14.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/samchungy/zod-openapi?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.57.0",
|
||||
"@scalar/express-api-reference": "^0.9.4",
|
||||
"@scalar/express-api-reference": "^0.9.20",
|
||||
"@socket.io/admin-ui": "^0.5.1",
|
||||
"archiver": "^7.0.1",
|
||||
"axios": "^1.13.6",
|
||||
@@ -102,7 +102,8 @@
|
||||
"socket.io": "^4.8.3",
|
||||
"socket.io-client": "^4.8.3",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^4.3.6"
|
||||
"zod": "^4.3.6",
|
||||
"zod-openapi": "^6.0.0"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
|
||||
Reference in New Issue
Block a user