Compare commits
10 Commits
7dbc31c046
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e8417dcff | |||
| 1b1918dcd0 | |||
| 4ff10dfcb2 | |||
| 9a0bb18c5b | |||
| 1838c6f1e9 | |||
| 3a24d62957 | |||
| 6a14bab30c | |||
| 2ebf695526 | |||
| 24af3ca403 | |||
| 6fbe3a9eed |
94
README.md
94
README.md
@@ -7,7 +7,7 @@
|
|||||||
Quick summary of current rewrite/migration goal.
|
Quick summary of current rewrite/migration goal.
|
||||||
|
|
||||||
- **Phase:** Backend rewrite
|
- **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
|
```bash
|
||||||
git clone https://git.tuffraid.net/cowch/lst_v3.git
|
npm run install --omit=dev
|
||||||
cd lst_v3
|
|
||||||
npm install
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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: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,6 +9,7 @@ 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";
|
||||||
|
import { getAppVersion } from "./utils/version.utils.js";
|
||||||
|
|
||||||
const createApp = async () => {
|
const createApp = async () => {
|
||||||
const log = createLogger({ module: "system", subModule: "main start" });
|
const log = createLogger({ module: "system", subModule: "main start" });
|
||||||
@@ -35,6 +36,7 @@ const createApp = async () => {
|
|||||||
app.all(`${baseUrl}/api/auth/*splat`, toNodeHandler(auth));
|
app.all(`${baseUrl}/api/auth/*splat`, toNodeHandler(auth));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
const version = await getAppVersion();
|
||||||
app.get(`${baseUrl}/api/lst-config.js`, (_, res) => {
|
app.get(`${baseUrl}/api/lst-config.js`, (_, res) => {
|
||||||
res.type("application/javascript");
|
res.type("application/javascript");
|
||||||
res.setHeader("Cache-Control", "no-store");
|
res.setHeader("Cache-Control", "no-store");
|
||||||
@@ -47,7 +49,9 @@ const createApp = async () => {
|
|||||||
appVersion: ${JSON.stringify(umamiConfig.appVersion ?? "dev")},
|
appVersion: ${JSON.stringify(umamiConfig.appVersion ?? "dev")},
|
||||||
umamiHost: ${JSON.stringify(umamiConfig.umamiHost ?? "")},
|
umamiHost: ${JSON.stringify(umamiConfig.umamiHost ?? "")},
|
||||||
umamiWebsiteId: ${JSON.stringify(umamiConfig.umamiWebsiteId ?? "")},
|
umamiWebsiteId: ${JSON.stringify(umamiConfig.umamiWebsiteId ?? "")},
|
||||||
timezone: ${JSON.stringify(process.env.TIMEZONE ?? "America/Chicago")}
|
timezone: ${JSON.stringify(process.env.TIMEZONE ?? "America/Chicago")},
|
||||||
|
version: ${JSON.stringify(version.version)},
|
||||||
|
lastBuildTIme: ${JSON.stringify(version.lastBuildTime)}
|
||||||
};
|
};
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import os from "node:os";
|
|||||||
import { apiReference } from "@scalar/express-api-reference";
|
import { apiReference } from "@scalar/express-api-reference";
|
||||||
// const port = 3000;
|
// const port = 3000;
|
||||||
import type { OpenAPIV3_1 } from "openapi-types";
|
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 { prodLoginSpec } from "../scaler/login.spec.js";
|
||||||
import { openDockApt } from "../scaler/opendockGetRelease.spec.js";
|
import { openDockApt } from "../scaler/opendockGetRelease.spec.js";
|
||||||
import { prodRestartSpec } from "../scaler/prodSqlRestart.spec.js";
|
import { prodRestartSpec } from "../scaler/prodSqlRestart.spec.js";
|
||||||
@@ -19,12 +17,13 @@ import { prodStopSpec } from "../scaler/prodSqlStop.spec.js";
|
|||||||
import { prodRegisterSpec } from "../scaler/register.spec.js";
|
import { prodRegisterSpec } from "../scaler/register.spec.js";
|
||||||
// all the specs
|
// all the specs
|
||||||
import { statusSpec } from "../scaler/stats.spec.js";
|
import { statusSpec } from "../scaler/stats.spec.js";
|
||||||
|
import { getAppVersion } from "../utils/version.utils.js";
|
||||||
|
|
||||||
export const openApiBase: OpenAPIV3_1.Document = {
|
export const openApiBase: OpenAPIV3_1.Document = {
|
||||||
openapi: "3.1.0",
|
openapi: "3.1.0",
|
||||||
info: {
|
info: {
|
||||||
title: "LST API",
|
title: "LST API",
|
||||||
version: "3.0.0",
|
version: (await getAppVersion()).version ?? "",
|
||||||
description: "Label System Tracking API",
|
description: "Label System Tracking API",
|
||||||
},
|
},
|
||||||
servers: [
|
servers: [
|
||||||
@@ -125,8 +124,6 @@ export const setupApiDocsRoutes = (baseUrl: string, app: Express) => {
|
|||||||
...prodLoginSpec,
|
...prodLoginSpec,
|
||||||
...prodRegisterSpec,
|
...prodRegisterSpec,
|
||||||
//...mergedDatamart,
|
//...mergedDatamart,
|
||||||
...cronerActiveJobs,
|
|
||||||
...cronerStatusChange,
|
|
||||||
...openDockApt,
|
...openDockApt,
|
||||||
|
|
||||||
// Add more specs here as you build features
|
// Add more specs here as you build features
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ const lstDbRun = async (data: Data) => {
|
|||||||
if (data.options) {
|
if (data.options) {
|
||||||
if (data.name === "psiInventory") {
|
if (data.name === "psiInventory") {
|
||||||
const ids = data.options.articles.split(",").map((id: any) => id.trim());
|
const ids = data.options.articles.split(",").map((id: any) => id.trim());
|
||||||
|
|
||||||
const whse = data.options.whseToInclude
|
const whse = data.options.whseToInclude
|
||||||
? data.options.whseToInclude
|
? data.options.whseToInclude
|
||||||
.split(",")
|
.split(",")
|
||||||
@@ -274,10 +275,10 @@ export const runDatamartQuery = async (data: Data) => {
|
|||||||
.replace("[startDate]", `${data.options.startDate}`)
|
.replace("[startDate]", `${data.options.startDate}`)
|
||||||
.replace("[endDate]", `${data.options.endDate}`)
|
.replace("[endDate]", `${data.options.endDate}`)
|
||||||
.replace(
|
.replace(
|
||||||
"and p.IdArtikelvarianten in ([articles])",
|
"and pl.ArticleHumanReadableId IN ([articles]) ",
|
||||||
data.options.articles
|
data.options.articles
|
||||||
? `and p.IdArtikelvarianten in (${data.options.articles})`
|
? `and pl.ArticleHumanReadableId IN (${data.options.articles})`
|
||||||
: "--and p.IdArtikelvarianten in ([articles])",
|
: "--and pl.ArticleHumanReadableId IN ([articles])",
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
|
import * as XLSX from "xlsx";
|
||||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
import { runDatamartQuery } from "./datamart.controller.js";
|
import { runDatamartQuery } from "./datamart.controller.js";
|
||||||
|
|
||||||
@@ -7,13 +8,73 @@ const r = Router();
|
|||||||
type Options = {
|
type Options = {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
format: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
r.get("/:name", async (req, res) => {
|
r.get("/:name", async (req, res) => {
|
||||||
const { name } = req.params;
|
const { name } = req.params;
|
||||||
const options = req.query as Options;
|
const options = { ...req.query } as Options;
|
||||||
|
|
||||||
const dataRan = await runDatamartQuery({ name, options });
|
const dataRan = await runDatamartQuery({ name, options });
|
||||||
|
|
||||||
|
if (!dataRan.success) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "datamart",
|
||||||
|
subModule: "query",
|
||||||
|
message: dataRan.message,
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// XLSX Export
|
||||||
|
if (options.format?.toLowerCase() === "xlsx") {
|
||||||
|
const wb = XLSX.utils.book_new();
|
||||||
|
|
||||||
|
const ws = XLSX.utils.json_to_sheet(dataRan.data);
|
||||||
|
|
||||||
|
XLSX.utils.book_append_sheet(wb, ws, name);
|
||||||
|
|
||||||
|
const buffer = XLSX.write(wb, {
|
||||||
|
type: "buffer",
|
||||||
|
bookType: "xlsx",
|
||||||
|
});
|
||||||
|
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Type",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
);
|
||||||
|
|
||||||
|
res.setHeader("Content-Disposition", `attachment; filename="${name}.xlsx"`);
|
||||||
|
|
||||||
|
return res.send(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSV Export
|
||||||
|
if (options.format?.toLowerCase() === "csv") {
|
||||||
|
const rows = dataRan.data as any;
|
||||||
|
|
||||||
|
if (!rows.length) {
|
||||||
|
return res.status(200).send("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = Object.keys(rows[0]);
|
||||||
|
|
||||||
|
const csv = [
|
||||||
|
headers.join(","),
|
||||||
|
...rows.map((row: any) =>
|
||||||
|
headers
|
||||||
|
.map((h) => `"${String(row[h] ?? "").replace(/"/g, '""')}"`)
|
||||||
|
.join(","),
|
||||||
|
),
|
||||||
|
].join("\r\n");
|
||||||
|
|
||||||
|
res.setHeader("Content-Type", "text/csv");
|
||||||
|
res.setHeader("Content-Disposition", `attachment; filename="${name}.csv"`);
|
||||||
|
|
||||||
|
return res.send(csv);
|
||||||
|
}
|
||||||
|
|
||||||
return apiReturn(res, {
|
return apiReturn(res, {
|
||||||
success: dataRan.success,
|
success: dataRan.success,
|
||||||
level: "info",
|
level: "info",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
sqlQuerySelector,
|
sqlQuerySelector,
|
||||||
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||||
import { returnFunc } from "../utils/returnHelper.utils.js";
|
import { returnFunc } from "../utils/returnHelper.utils.js";
|
||||||
import { sendEmail } from "../utils/sendEmail.utils.js";
|
//import { sendEmail } from "../utils/sendEmail.utils.js";
|
||||||
import { tryCatch } from "../utils/trycatch.utils.js";
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
import { postData } from "./logistics.dm.postData.js";
|
import { postData } from "./logistics.dm.postData.js";
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ export const lorealForecast = async (data: any, user: any) => {
|
|||||||
|
|
||||||
const article: any = a?.data;
|
const article: any = a?.data;
|
||||||
|
|
||||||
console.log(article);
|
//console.log(article);
|
||||||
|
|
||||||
// process the ebm forcast
|
// process the ebm forcast
|
||||||
for (let i = 0; i < ebmForeCastData.length; i++) {
|
for (let i = 0; i < ebmForeCastData.length; i++) {
|
||||||
@@ -127,31 +127,6 @@ export const lorealForecast = async (data: any, user: any) => {
|
|||||||
//console.log(ebmForeCastData.length);
|
//console.log(ebmForeCastData.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// petForeCastData.forEach((item: any, index: any) => {
|
|
||||||
// //console.log(`Processing item ${index + 1} of ${forecastData.length}`);
|
|
||||||
|
|
||||||
// // Extract the customer code
|
|
||||||
// const customerCode = item["SOUTH PET BOTTLES"];
|
|
||||||
|
|
||||||
// // Process each date in the current object
|
|
||||||
// for (const [date, qty] of Object.entries(item)) {
|
|
||||||
// // Skip metadata fields
|
|
||||||
// if (petMetadataFields.includes(date)) continue;
|
|
||||||
|
|
||||||
// if (qty === 0) continue;
|
|
||||||
|
|
||||||
// // Create your transformed record
|
|
||||||
// const record = {
|
|
||||||
// customerArticleNo: customerCode,
|
|
||||||
// requirementDate: excelDateStuff(parseInt(date)),
|
|
||||||
// quantity: qty,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Do something with this record
|
|
||||||
// petForecastData.push(record);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// pet forecast
|
// pet forecast
|
||||||
for (let i = 0; i < petForeCastData.length; i++) {
|
for (let i = 0; i < petForeCastData.length; i++) {
|
||||||
// bottle code
|
// bottle code
|
||||||
@@ -200,25 +175,25 @@ export const lorealForecast = async (data: any, user: any) => {
|
|||||||
//console.log(comForecast);
|
//console.log(comForecast);
|
||||||
|
|
||||||
// email the for the missing ones
|
// email the for the missing ones
|
||||||
const missedGrouped = Object.values(
|
// const missedGrouped = Object.values(
|
||||||
missingSku.reduce((acc: any, item: any) => {
|
// missingSku.reduce((acc: any, item: any) => {
|
||||||
const key = item.customerArticleNo;
|
// const key = item.customerArticleNo;
|
||||||
|
|
||||||
if (!acc[key]) {
|
// if (!acc[key]) {
|
||||||
// first time we see this customer
|
// // first time we see this customer
|
||||||
acc[key] = item;
|
// acc[key] = item;
|
||||||
} else {
|
// } else {
|
||||||
// compare dates and keep the earliest
|
// // compare dates and keep the earliest
|
||||||
if (
|
// if (
|
||||||
new Date(item.requirementDate) < new Date(acc[key].requirementDate)
|
// new Date(item.requirementDate) < new Date(acc[key].requirementDate)
|
||||||
) {
|
// ) {
|
||||||
acc[key] = item;
|
// acc[key] = item;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return acc;
|
// return acc;
|
||||||
}, {}),
|
// }, {}),
|
||||||
);
|
// );
|
||||||
|
|
||||||
// TODO: change this to a flagged notification so that he users can subscribe or leave it. this removes the hardcody shit.
|
// TODO: change this to a flagged notification so that he users can subscribe or leave it. this removes the hardcody shit.
|
||||||
// const emailSetup = {
|
// const emailSetup = {
|
||||||
@@ -248,19 +223,7 @@ export const lorealForecast = async (data: any, user: any) => {
|
|||||||
|
|
||||||
const updatedPredefinedObject = {
|
const updatedPredefinedObject = {
|
||||||
...predefinedObject,
|
...predefinedObject,
|
||||||
positions: [
|
positions: [...predefinedObject.positions, ...ebmForecastData],
|
||||||
...predefinedObject.positions,
|
|
||||||
...ebmForecastData,
|
|
||||||
|
|
||||||
// ...ebmForecastData.filter(
|
|
||||||
// (q: any) =>
|
|
||||||
// q.customerArticleNo != "" && q.customerArticleNo != "Total"
|
|
||||||
// ),
|
|
||||||
// ...petForecastData.filter(
|
|
||||||
// (q: any) =>
|
|
||||||
// q.customerArticleNo != "" && q.customerArticleNo != "Total"
|
|
||||||
// ),
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
// console.log(updatedPredefinedObject);
|
// console.log(updatedPredefinedObject);
|
||||||
|
|
||||||
|
|||||||
@@ -113,8 +113,8 @@ export const pNgForecast = async (data: any, user: any) => {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
customerArticleNo: parseInt(o["Customer Item No."]),
|
customerArticleNo: parseInt(o["Customer Item No."] ?? "0", 10),
|
||||||
requirementDate: excelDateStuff(parseInt(o["Request Date"])),
|
requirementDate: excelDateStuff(parseInt(o["Request Date"] ?? "0", 10)),
|
||||||
quantity: o["Remaining Qty to be Shipped"],
|
quantity: o["Remaining Qty to be Shipped"],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
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]
|
use [test1_AlplaPROD2.0_Read]
|
||||||
|
|
||||||
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
|
DECLARE @StartDate DATE = '[startDate]'
|
||||||
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
|
DECLARE @EndDate DATE = '[endDate]'
|
||||||
SELECT
|
|
||||||
r.[ArticleHumanReadableId]
|
;WITH bol_20 AS ( -- 2.0 BOL, one per release (newest doc wins)
|
||||||
,[ReleaseNumber]
|
SELECT pos.ReleaseId,
|
||||||
,h.CustomerOrderNumber
|
dd.JournalNumber,
|
||||||
,x.CustomerLineItemNumber
|
ROW_NUMBER() OVER (PARTITION BY pos.ReleaseId
|
||||||
,[CustomerReleaseNumber]
|
ORDER BY dd.ShippingDate DESC) AS rn
|
||||||
,[ReleaseState]
|
FROM [outboundDelivery].[DeliveryDocumentPosition] (nolock) pos
|
||||||
,[DeliveryState]
|
JOIN [outboundDelivery].[DeliveryDocument] (nolock) dd
|
||||||
,ea.JournalNummer as BOL_Number
|
ON dd.Id = pos.DeliveryDocumentId
|
||||||
,[ReleaseConfirmationState]
|
-- WHERE dd.DocumentType = <BOL value> -- see note below
|
||||||
,[PlanningState]
|
)
|
||||||
|
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
|
,format(r.[OrderDate], 'yyyy-MM-dd HH:mm') as OrderDate
|
||||||
--,r.[OrderDate]
|
--,r.[OrderDate]
|
||||||
,FORMAT(r.[DeliveryDate], 'yyyy-MM-dd HH:mm') as DeliveryDate
|
,FORMAT(r.[DeliveryDate], 'yyyy-MM-dd HH:mm') as DeliveryDate
|
||||||
--,r.[DeliveryDate]
|
--,r.[DeliveryDate]
|
||||||
,FORMAT(r.[LoadingDate], 'yyyy-MM-dd HH:mm') as LoadingDate
|
,FORMAT(r.[LoadingDate], 'yyyy-MM-dd HH:mm') as LoadingDate
|
||||||
--,r.[LoadingDate]
|
--,r.[LoadingDate]
|
||||||
,[Quantity]
|
,[Quantity]
|
||||||
,[DeliveredQuantity]
|
,[DeliveredQuantity]
|
||||||
,r.[AdditionalInformation1]
|
,r.[AdditionalInformation1]
|
||||||
,r.[AdditionalInformation2]
|
,r.[AdditionalInformation2]
|
||||||
,[TradeUnits]
|
,[TradeUnits]
|
||||||
,[LoadingUnits]
|
,[LoadingUnits]
|
||||||
,[Trucks]
|
,[Trucks]
|
||||||
,[LoadingToleranceType]
|
,[LoadingToleranceType]
|
||||||
,[SalesPrice]
|
,[SalesPrice]
|
||||||
,[Currency]
|
,[Currency]
|
||||||
,[QuantityUnit]
|
,[QuantityUnit]
|
||||||
,[SalesPriceRemark]
|
,[SalesPriceRemark]
|
||||||
,r.[Remark]
|
,r.[Remark]
|
||||||
,[Irradiated]
|
,[Irradiated]
|
||||||
,r.[CreatedByEdi]
|
,r.[CreatedByEdi]
|
||||||
,[DeliveryAddressHumanReadableId]
|
,[DeliveryAddressHumanReadableId]
|
||||||
,DeliveryAddressDescription
|
,DeliveryAddressDescription
|
||||||
,[CustomerArtNo]
|
,[CustomerArtNo]
|
||||||
,[TotalPrice]
|
,[TotalPrice]
|
||||||
,r.[ArticleAlias]
|
,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
|
-- 2.0 BOL (new)
|
||||||
[order].LineItem as x on
|
LEFT JOIN bol_20 ON bol_20.ReleaseId = r.Id AND bol_20.rn = 1
|
||||||
|
|
||||||
r.LineItemId = x.id
|
WHERE r.DeliveryDate BETWEEN @StartDate AND @EndDate
|
||||||
|
|
||||||
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
|
|
||||||
and DeliveredQuantity > 0
|
and DeliveredQuantity > 0
|
||||||
--and r.ArticleHumanReadableId in ([articles])
|
--and r.ArticleHumanReadableId in ([articles])
|
||||||
--and Journalnummer = 169386
|
--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
|
use [test1_AlplaPROD2.0_Read]
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
select x.IdArtikelvarianten As Article,
|
DECLARE @start_date date = '[startDate]'; --'2025-01-01'
|
||||||
ProduktionAlias as Description,
|
DECLARE @end_date date = '[endDate]'; --'2025-08-09'
|
||||||
standort as MachineId,
|
DECLARE @tz sysname = 'Eastern Standard Time'; -- usday1; use 'Central Standard Time' for usksc1
|
||||||
MaschinenBezeichnung as MachineName,
|
DECLARE @shiftSeconds int = 7*3600; -- 07:00 production-day anchor
|
||||||
--MaschZyklus as PlanningCycleTime,
|
--TODO: add in the proper time zone based on the env, get correcr shift time as well
|
||||||
x.IdProdPlanung as LotNumber,
|
;WITH src AS (
|
||||||
FORMAT(ProdTag, 'MM/dd/yyyy') as ProductionDay,
|
SELECT
|
||||||
x.planMenge as TotalPlanned,
|
pl.RunningNumber, pl.ArticleHumanReadableId, pl.ArticleAlias, pl.ArticleDescription,
|
||||||
ProduktionMenge as QTYPerDay,
|
pl.MachineLocation, pl.MachineDescription, pl.ProductionLotState, pl.ProductionInterrupt,
|
||||||
round(ProduktionMengeVPK, 2) PalDay,
|
pl.PlanQuantityPieces, pl.PlanQuantityLoadingUnit,
|
||||||
Status as finished
|
CAST(pl.ProdStart AT TIME ZONE @tz AS datetime2(0)) AS StartLocal,
|
||||||
--MaschStdAuslastung as nee
|
CAST(pl.PlanEnd AT TIME ZONE @tz AS datetime2(0)) AS EndLocal
|
||||||
|
FROM productionScheduling.ProductionLot AS pl
|
||||||
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock) as x
|
WHERE pl.PlanEnd > pl.ProdStart
|
||||||
|
and pl.publishState = 1
|
||||||
left join
|
and pl.ArticleHumanReadableId IN ([articles]) -- <-- article filter (was IdArtikelvarianten)
|
||||||
dbo.V_ProdPlanung (nolock) as p on
|
--AND pl.RunningNumber = 28094 -- <-- lot filter (was IdProdPlanung); comment out for all
|
||||||
x.IdProdPlanung = p.IdProdPlanung
|
),
|
||||||
|
calc AS (
|
||||||
where ProdTag between @start_date and @end_date
|
SELECT *,
|
||||||
and p.IdArtikelvarianten in ([articles])
|
DATEADD(SECOND, @shiftSeconds,
|
||||||
--and V_ProdLosProduktionJeProdTag_PLANNING.IdKunde = 10
|
CAST(CASE WHEN DATEDIFF(SECOND, CAST(StartLocal AS date), StartLocal) >= @shiftSeconds
|
||||||
--and IdProdPlanung = 18442
|
THEN CAST(StartLocal AS date)
|
||||||
|
ELSE DATEADD(DAY,-1, CAST(StartLocal AS date)) END AS datetime2(0))) AS FirstBoundary
|
||||||
order by ProdTag desc
|
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);
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ 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
|
||||||
|
setupDatamartRoutes(baseUrl, app);
|
||||||
setupMobileRoutes(baseUrl, app);
|
setupMobileRoutes(baseUrl, app);
|
||||||
setupSystemRoutes(baseUrl, app);
|
setupSystemRoutes(baseUrl, app);
|
||||||
setupAdminRoutes(baseUrl, app);
|
setupAdminRoutes(baseUrl, app);
|
||||||
setupApiDocsRoutes(baseUrl, app);
|
setupApiDocsRoutes(baseUrl, app);
|
||||||
setupProdSqlRoutes(baseUrl, app);
|
setupProdSqlRoutes(baseUrl, app);
|
||||||
setupGPSqlRoutes(baseUrl, app);
|
setupGPSqlRoutes(baseUrl, app);
|
||||||
setupDatamartRoutes(baseUrl, app);
|
|
||||||
setupAuthRoutes(baseUrl, app);
|
setupAuthRoutes(baseUrl, app);
|
||||||
setupUtilsRoutes(baseUrl, app);
|
setupUtilsRoutes(baseUrl, app);
|
||||||
setupOpendockRoutes(baseUrl, app);
|
setupOpendockRoutes(baseUrl, app);
|
||||||
|
|||||||
@@ -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,5 +1,6 @@
|
|||||||
import { createServer } from "node:http";
|
import { createServer } from "node:http";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
|
|
||||||
import createApp from "./app.js";
|
import createApp from "./app.js";
|
||||||
import { db } from "./db/db.controller.js";
|
import { db } from "./db/db.controller.js";
|
||||||
import { startDbNotificationListener } from "./db/db.listener.js";
|
import { startDbNotificationListener } from "./db/db.listener.js";
|
||||||
@@ -32,6 +33,7 @@ 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[] = [];
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
const { app, baseUrl } = await createApp();
|
const { app, baseUrl } = await createApp();
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,15 @@ import {
|
|||||||
type SqlQuery,
|
type SqlQuery,
|
||||||
sqlQuerySelector,
|
sqlQuerySelector,
|
||||||
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
||||||
|
|
||||||
import { isServerRunning } from "../tcpServer/tcp.server.js";
|
import { isServerRunning } from "../tcpServer/tcp.server.js";
|
||||||
|
import { getAppVersion } from "../utils/version.utils.js";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get("/", async (_, res) => {
|
router.get("/", async (_, res) => {
|
||||||
const used = process.memoryUsage();
|
const used = process.memoryUsage();
|
||||||
|
const version = await getAppVersion();
|
||||||
|
|
||||||
const query = sqlQuerySelector("prodSqlStats") as SqlQuery;
|
const query = sqlQuerySelector("prodSqlStats") as SqlQuery;
|
||||||
|
|
||||||
@@ -20,6 +23,8 @@ router.get("/", async (_, res) => {
|
|||||||
status: "ok",
|
status: "ok",
|
||||||
uptime: process.uptime(),
|
uptime: process.uptime(),
|
||||||
nodeVersion: process.version,
|
nodeVersion: process.version,
|
||||||
|
appVersion: version.version ?? "",
|
||||||
|
lastBuildDate: version.lastBuildTime ?? "",
|
||||||
memoryUsage: `Heap: ${(used.heapUsed / 1024 / 1024).toFixed(2)} MB / RSS: ${(
|
memoryUsage: `Heap: ${(used.heapUsed / 1024 / 1024).toFixed(2)} MB / RSS: ${(
|
||||||
used.rss / 1024 / 1024
|
used.rss / 1024 / 1024
|
||||||
).toFixed(2)} MB`,
|
).toFixed(2)} MB`,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { spawn } from "node:child_process";
|
|||||||
import { createLogger } from "../logger/logger.controller.js";
|
import { createLogger } from "../logger/logger.controller.js";
|
||||||
import { emitToRoom } from "../socket.io/roomEmitter.socket.js";
|
import { emitToRoom } from "../socket.io/roomEmitter.socket.js";
|
||||||
import { updateAppStats } from "./updateAppStats.utils.js";
|
import { updateAppStats } from "./updateAppStats.utils.js";
|
||||||
|
import { getAppVersion } from "./version.utils.js";
|
||||||
import { zipBuild } from "./zipper.utils.js";
|
import { zipBuild } from "./zipper.utils.js";
|
||||||
|
|
||||||
export const emitBuildLog = (message: string, level = "info") => {
|
export const emitBuildLog = (message: string, level = "info") => {
|
||||||
@@ -28,6 +29,8 @@ export let building = false;
|
|||||||
const log = createLogger({ module: "utils", subModule: "builds" });
|
const log = createLogger({ module: "utils", subModule: "builds" });
|
||||||
export const build = async () => {
|
export const build = async () => {
|
||||||
const appDir = process.env.DEV_DIR ?? "";
|
const appDir = process.env.DEV_DIR ?? "";
|
||||||
|
const build = await getAppVersion();
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
building = true;
|
building = true;
|
||||||
|
|
||||||
@@ -72,6 +75,7 @@ export const build = async () => {
|
|||||||
updateAppStats({
|
updateAppStats({
|
||||||
lastUpdated: new Date(),
|
lastUpdated: new Date(),
|
||||||
building: false,
|
building: false,
|
||||||
|
currentBuild: build.build,
|
||||||
});
|
});
|
||||||
emitBuildLog(`Build failed with code ${code}`, "error");
|
emitBuildLog(`Build failed with code ${code}`, "error");
|
||||||
//reject(new Error(`Build failed with code ${code}`));
|
//reject(new Error(`Build failed with code ${code}`));
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { appStats } from "../db/schema/stats.schema.js";
|
|||||||
export const updateAppStats = async (
|
export const updateAppStats = async (
|
||||||
data: Partial<typeof appStats.$inferInsert>,
|
data: Partial<typeof appStats.$inferInsert>,
|
||||||
) => {
|
) => {
|
||||||
|
console.log(data);
|
||||||
await db
|
await db
|
||||||
.insert(appStats)
|
.insert(appStats)
|
||||||
.values({
|
.values({
|
||||||
|
|||||||
17
backend/utils/version.utils.ts
Normal file
17
backend/utils/version.utils.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import fsp from "node:fs/promises";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
export const getAppVersion = async () => {
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const version = path.join(__dirname, "../../package.json");
|
||||||
|
const raw = await fsp.readFile(`${version}`, "utf8");
|
||||||
|
const config = JSON.parse(raw);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: `${config.version}.${parseInt((config.build as string) ?? "1", 0) - 1}`,
|
||||||
|
build: parseInt((config.build as string) ?? "1", 0),
|
||||||
|
lastBuildTime: config.lastBuildDate,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|||||||
import fsp from "node:fs/promises";
|
import fsp from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import archiver from "archiver";
|
import archiver from "archiver";
|
||||||
|
import { format } from "date-fns";
|
||||||
import { createLogger } from "../logger/logger.controller.js";
|
import { createLogger } from "../logger/logger.controller.js";
|
||||||
import { emitBuildLog } from "./build.utils.js";
|
import { emitBuildLog } from "./build.utils.js";
|
||||||
import { updateAppStats } from "./updateAppStats.utils.js";
|
import { updateAppStats } from "./updateAppStats.utils.js";
|
||||||
@@ -17,33 +18,31 @@ const exists = async (target: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNextBuildNumber = async (buildNumberFile: string) => {
|
const getNextBuildNumber = async (versionPath: string) => {
|
||||||
if (!(await exists(buildNumberFile))) {
|
const raw = await fsp.readFile(versionPath, "utf8");
|
||||||
await fsp.writeFile(buildNumberFile, "1", "utf8");
|
const config = JSON.parse(raw);
|
||||||
return 1;
|
const current = Number.parseInt(config.build.trim(), 10);
|
||||||
}
|
|
||||||
|
|
||||||
const raw = await fsp.readFile(buildNumberFile, "utf8");
|
|
||||||
const current = Number.parseInt(raw.trim(), 10);
|
|
||||||
|
|
||||||
|
let nextBuild: string;
|
||||||
if (Number.isNaN(current) || current < 1) {
|
if (Number.isNaN(current) || current < 1) {
|
||||||
await fsp.writeFile(buildNumberFile, "1", "utf8");
|
nextBuild = "1";
|
||||||
return 1;
|
} else {
|
||||||
|
nextBuild = String(current + 1); // Incrementing the build number
|
||||||
}
|
}
|
||||||
|
|
||||||
const next = current + 1;
|
const updatedConfig = {
|
||||||
|
...config,
|
||||||
|
build: nextBuild,
|
||||||
|
lastBuildDate: format(new Date(Date.now()), "M/d/yyyy HH:mm"),
|
||||||
|
};
|
||||||
|
|
||||||
await fsp.writeFile(buildNumberFile, String(next), "utf8");
|
await fsp.writeFile(
|
||||||
|
versionPath,
|
||||||
|
JSON.stringify(updatedConfig, null, 4) + "\n",
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
|
||||||
// update the server with the next build number
|
return { version: config.version, build: config.build };
|
||||||
|
|
||||||
await updateAppStats({
|
|
||||||
currentBuild: next,
|
|
||||||
lastBuildAt: new Date(),
|
|
||||||
building: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const cleanupOldBuilds = async (buildFolder: string, maxBuilds: number) => {
|
const cleanupOldBuilds = async (buildFolder: string, maxBuilds: number) => {
|
||||||
@@ -53,7 +52,8 @@ const cleanupOldBuilds = async (buildFolder: string, maxBuilds: number) => {
|
|||||||
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (!entry.isFile()) continue;
|
if (!entry.isFile()) continue;
|
||||||
if (!/^LSTV3-\d+\.zip$/i.test(entry.name)) continue;
|
//if (!/^LSTV3-\d+\.zip$/i.test(entry.name)) continue;
|
||||||
|
if (!entry.name.includes("LSTV3")) continue;
|
||||||
|
|
||||||
const fullPath = path.join(buildFolder, entry.name);
|
const fullPath = path.join(buildFolder, entry.name);
|
||||||
const stat = await fsp.stat(fullPath);
|
const stat = await fsp.stat(fullPath);
|
||||||
@@ -85,7 +85,7 @@ export const zipBuild = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const includesFile = path.join(appDir, ".includes");
|
const includesFile = path.join(appDir, ".includes");
|
||||||
const buildNumberFile = path.join(appDir, ".buildNumber");
|
const version = path.join(appDir, "package.json");
|
||||||
const buildFolder = path.join(appDir, "builds");
|
const buildFolder = path.join(appDir, "builds");
|
||||||
const tempFolder = path.join(appDir, "temp", "zip-temp");
|
const tempFolder = path.join(appDir, "temp", "zip-temp");
|
||||||
if (!(await exists(includesFile))) {
|
if (!(await exists(includesFile))) {
|
||||||
@@ -95,11 +95,13 @@ export const zipBuild = async () => {
|
|||||||
|
|
||||||
await fsp.mkdir(buildFolder, { recursive: true });
|
await fsp.mkdir(buildFolder, { recursive: true });
|
||||||
|
|
||||||
const buildNumber = await getNextBuildNumber(buildNumberFile);
|
const lstVersion = await getNextBuildNumber(version);
|
||||||
const zipFileName = `LSTV3-${buildNumber}.zip`;
|
const zipFileName = `LSTV3-${lstVersion.version}.${lstVersion.build}.zip`;
|
||||||
const zipFile = path.join(buildFolder, zipFileName);
|
const zipFile = path.join(buildFolder, zipFileName);
|
||||||
// make the folders in case they are not created already
|
// make the folders in case they are not created already
|
||||||
emitBuildLog(`Using build number: ${buildNumber}`);
|
emitBuildLog(
|
||||||
|
`Using version, build number: ${lstVersion.version}.${lstVersion.build}`,
|
||||||
|
);
|
||||||
|
|
||||||
if (await exists(tempFolder)) {
|
if (await exists(tempFolder)) {
|
||||||
await fsp.rm(tempFolder, { recursive: true, force: true });
|
await fsp.rm(tempFolder, { recursive: true, force: true });
|
||||||
@@ -166,11 +168,12 @@ export const zipBuild = async () => {
|
|||||||
await updateAppStats({
|
await updateAppStats({
|
||||||
lastUpdated: new Date(),
|
lastUpdated: new Date(),
|
||||||
building: false,
|
building: false,
|
||||||
|
currentBuild: lstVersion.build,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
buildNumber,
|
build: lstVersion.build,
|
||||||
zipFile,
|
zipFile,
|
||||||
zipFileName,
|
zipFileName,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
|
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
|
||||||
|
import { Link } from "@tanstack/react-router";
|
||||||
|
import { LaptopMinimal } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
SidebarContent,
|
SidebarContent,
|
||||||
SidebarHeader,
|
SidebarFooter,
|
||||||
SidebarMenu,
|
SidebarMenu,
|
||||||
|
SidebarMenuButton,
|
||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
|
useSidebar,
|
||||||
} from "@/components/ui/sidebar";
|
} from "@/components/ui/sidebar";
|
||||||
import { useSession } from "@/lib/auth-client";
|
import { useSession } from "@/lib/auth-client";
|
||||||
import { getSettings } from "../../lib/queries/getSettings";
|
import { getSettings } from "../../lib/queries/getSettings";
|
||||||
@@ -23,6 +27,7 @@ export function AppSidebar() {
|
|||||||
openDock: ["read"],
|
openDock: ["read"],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const { setOpen } = useSidebar();
|
||||||
|
|
||||||
// const { data: canReadWarehouse = false } = useQuery(
|
// const { data: canReadWarehouse = false } = useQuery(
|
||||||
// permissionQuery({
|
// permissionQuery({
|
||||||
@@ -36,7 +41,7 @@ export function AppSidebar() {
|
|||||||
collapsible="offcanvas"
|
collapsible="offcanvas"
|
||||||
className="top-(--header-height) h-[calc(100svh-var(--header-height))]!"
|
className="top-(--header-height) h-[calc(100svh-var(--header-height))]!"
|
||||||
>
|
>
|
||||||
<SidebarHeader>
|
<SidebarContent>
|
||||||
<SidebarMenu>
|
<SidebarMenu>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarContent>
|
<SidebarContent>
|
||||||
@@ -64,7 +69,24 @@ export function AppSidebar() {
|
|||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
</SidebarMenu>
|
</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>
|
</Sidebar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,11 @@
|
|||||||
import { Route as rootRouteImport } from './routes/__root'
|
import { Route as rootRouteImport } from './routes/__root'
|
||||||
import { Route as ForbiddenRouteImport } from './routes/forbidden'
|
import { Route as ForbiddenRouteImport } from './routes/forbidden'
|
||||||
import { Route as AppDownRouteImport } from './routes/app-down'
|
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 AboutRouteImport } from './routes/about'
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as DocsIndexRouteImport } from './routes/docs/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 DocsSplatRouteImport } from './routes/docs/$'
|
||||||
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
||||||
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
||||||
@@ -41,6 +43,11 @@ const AppDownRoute = AppDownRouteImport.update({
|
|||||||
path: '/app-down',
|
path: '/app-down',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const ApidocsRoute = ApidocsRouteImport.update({
|
||||||
|
id: '/apidocs',
|
||||||
|
path: '/apidocs',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
const AboutRoute = AboutRouteImport.update({
|
const AboutRoute = AboutRouteImport.update({
|
||||||
id: '/about',
|
id: '/about',
|
||||||
path: '/about',
|
path: '/about',
|
||||||
@@ -56,6 +63,11 @@ const DocsIndexRoute = DocsIndexRouteImport.update({
|
|||||||
path: '/docs/',
|
path: '/docs/',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const DocsDatamartRoute = DocsDatamartRouteImport.update({
|
||||||
|
id: '/docs/datamart',
|
||||||
|
path: '/docs/datamart',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
const DocsSplatRoute = DocsSplatRouteImport.update({
|
const DocsSplatRoute = DocsSplatRouteImport.update({
|
||||||
id: '/docs/$',
|
id: '/docs/$',
|
||||||
path: '/docs/$',
|
path: '/docs/$',
|
||||||
@@ -145,6 +157,7 @@ const WarehouseDockdoorscanningScansDockScansRoute =
|
|||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/about': typeof AboutRoute
|
'/about': typeof AboutRoute
|
||||||
|
'/apidocs': typeof ApidocsRoute
|
||||||
'/app-down': typeof AppDownRoute
|
'/app-down': typeof AppDownRoute
|
||||||
'/forbidden': typeof ForbiddenRoute
|
'/forbidden': typeof ForbiddenRoute
|
||||||
'/login': typeof authLoginRoute
|
'/login': typeof authLoginRoute
|
||||||
@@ -155,6 +168,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
'/docs/$': typeof DocsSplatRoute
|
'/docs/$': typeof DocsSplatRoute
|
||||||
|
'/docs/datamart': typeof DocsDatamartRoute
|
||||||
'/docs/': typeof DocsIndexRoute
|
'/docs/': typeof DocsIndexRoute
|
||||||
'/user/profile': typeof authUserProfileRoute
|
'/user/profile': typeof authUserProfileRoute
|
||||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||||
@@ -168,6 +182,7 @@ export interface FileRoutesByFullPath {
|
|||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/about': typeof AboutRoute
|
'/about': typeof AboutRoute
|
||||||
|
'/apidocs': typeof ApidocsRoute
|
||||||
'/app-down': typeof AppDownRoute
|
'/app-down': typeof AppDownRoute
|
||||||
'/forbidden': typeof ForbiddenRoute
|
'/forbidden': typeof ForbiddenRoute
|
||||||
'/login': typeof authLoginRoute
|
'/login': typeof authLoginRoute
|
||||||
@@ -178,6 +193,7 @@ export interface FileRoutesByTo {
|
|||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
'/docs/$': typeof DocsSplatRoute
|
'/docs/$': typeof DocsSplatRoute
|
||||||
|
'/docs/datamart': typeof DocsDatamartRoute
|
||||||
'/docs': typeof DocsIndexRoute
|
'/docs': typeof DocsIndexRoute
|
||||||
'/user/profile': typeof authUserProfileRoute
|
'/user/profile': typeof authUserProfileRoute
|
||||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||||
@@ -192,6 +208,7 @@ export interface FileRoutesById {
|
|||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/about': typeof AboutRoute
|
'/about': typeof AboutRoute
|
||||||
|
'/apidocs': typeof ApidocsRoute
|
||||||
'/app-down': typeof AppDownRoute
|
'/app-down': typeof AppDownRoute
|
||||||
'/forbidden': typeof ForbiddenRoute
|
'/forbidden': typeof ForbiddenRoute
|
||||||
'/(auth)/login': typeof authLoginRoute
|
'/(auth)/login': typeof authLoginRoute
|
||||||
@@ -202,6 +219,7 @@ export interface FileRoutesById {
|
|||||||
'/admin/settings': typeof AdminSettingsRoute
|
'/admin/settings': typeof AdminSettingsRoute
|
||||||
'/admin/users': typeof AdminUsersRoute
|
'/admin/users': typeof AdminUsersRoute
|
||||||
'/docs/$': typeof DocsSplatRoute
|
'/docs/$': typeof DocsSplatRoute
|
||||||
|
'/docs/datamart': typeof DocsDatamartRoute
|
||||||
'/docs/': typeof DocsIndexRoute
|
'/docs/': typeof DocsIndexRoute
|
||||||
'/(auth)/user/profile': typeof authUserProfileRoute
|
'/(auth)/user/profile': typeof authUserProfileRoute
|
||||||
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
|
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
|
||||||
@@ -217,6 +235,7 @@ export interface FileRouteTypes {
|
|||||||
fullPaths:
|
fullPaths:
|
||||||
| '/'
|
| '/'
|
||||||
| '/about'
|
| '/about'
|
||||||
|
| '/apidocs'
|
||||||
| '/app-down'
|
| '/app-down'
|
||||||
| '/forbidden'
|
| '/forbidden'
|
||||||
| '/login'
|
| '/login'
|
||||||
@@ -227,6 +246,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
| '/docs/$'
|
| '/docs/$'
|
||||||
|
| '/docs/datamart'
|
||||||
| '/docs/'
|
| '/docs/'
|
||||||
| '/user/profile'
|
| '/user/profile'
|
||||||
| '/user/resetpassword'
|
| '/user/resetpassword'
|
||||||
@@ -240,6 +260,7 @@ export interface FileRouteTypes {
|
|||||||
to:
|
to:
|
||||||
| '/'
|
| '/'
|
||||||
| '/about'
|
| '/about'
|
||||||
|
| '/apidocs'
|
||||||
| '/app-down'
|
| '/app-down'
|
||||||
| '/forbidden'
|
| '/forbidden'
|
||||||
| '/login'
|
| '/login'
|
||||||
@@ -250,6 +271,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
| '/docs/$'
|
| '/docs/$'
|
||||||
|
| '/docs/datamart'
|
||||||
| '/docs'
|
| '/docs'
|
||||||
| '/user/profile'
|
| '/user/profile'
|
||||||
| '/user/resetpassword'
|
| '/user/resetpassword'
|
||||||
@@ -263,6 +285,7 @@ export interface FileRouteTypes {
|
|||||||
| '__root__'
|
| '__root__'
|
||||||
| '/'
|
| '/'
|
||||||
| '/about'
|
| '/about'
|
||||||
|
| '/apidocs'
|
||||||
| '/app-down'
|
| '/app-down'
|
||||||
| '/forbidden'
|
| '/forbidden'
|
||||||
| '/(auth)/login'
|
| '/(auth)/login'
|
||||||
@@ -273,6 +296,7 @@ export interface FileRouteTypes {
|
|||||||
| '/admin/settings'
|
| '/admin/settings'
|
||||||
| '/admin/users'
|
| '/admin/users'
|
||||||
| '/docs/$'
|
| '/docs/$'
|
||||||
|
| '/docs/datamart'
|
||||||
| '/docs/'
|
| '/docs/'
|
||||||
| '/(auth)/user/profile'
|
| '/(auth)/user/profile'
|
||||||
| '/(auth)/user/resetpassword'
|
| '/(auth)/user/resetpassword'
|
||||||
@@ -287,6 +311,7 @@ export interface FileRouteTypes {
|
|||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
AboutRoute: typeof AboutRoute
|
AboutRoute: typeof AboutRoute
|
||||||
|
ApidocsRoute: typeof ApidocsRoute
|
||||||
AppDownRoute: typeof AppDownRoute
|
AppDownRoute: typeof AppDownRoute
|
||||||
ForbiddenRoute: typeof ForbiddenRoute
|
ForbiddenRoute: typeof ForbiddenRoute
|
||||||
authLoginRoute: typeof authLoginRoute
|
authLoginRoute: typeof authLoginRoute
|
||||||
@@ -297,6 +322,7 @@ export interface RootRouteChildren {
|
|||||||
AdminSettingsRoute: typeof AdminSettingsRoute
|
AdminSettingsRoute: typeof AdminSettingsRoute
|
||||||
AdminUsersRoute: typeof AdminUsersRoute
|
AdminUsersRoute: typeof AdminUsersRoute
|
||||||
DocsSplatRoute: typeof DocsSplatRoute
|
DocsSplatRoute: typeof DocsSplatRoute
|
||||||
|
DocsDatamartRoute: typeof DocsDatamartRoute
|
||||||
DocsIndexRoute: typeof DocsIndexRoute
|
DocsIndexRoute: typeof DocsIndexRoute
|
||||||
authUserProfileRoute: typeof authUserProfileRoute
|
authUserProfileRoute: typeof authUserProfileRoute
|
||||||
authUserResetpasswordRoute: typeof authUserResetpasswordRoute
|
authUserResetpasswordRoute: typeof authUserResetpasswordRoute
|
||||||
@@ -324,6 +350,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof AppDownRouteImport
|
preLoaderRoute: typeof AppDownRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/apidocs': {
|
||||||
|
id: '/apidocs'
|
||||||
|
path: '/apidocs'
|
||||||
|
fullPath: '/apidocs'
|
||||||
|
preLoaderRoute: typeof ApidocsRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
'/about': {
|
'/about': {
|
||||||
id: '/about'
|
id: '/about'
|
||||||
path: '/about'
|
path: '/about'
|
||||||
@@ -345,6 +378,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof DocsIndexRouteImport
|
preLoaderRoute: typeof DocsIndexRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/docs/datamart': {
|
||||||
|
id: '/docs/datamart'
|
||||||
|
path: '/docs/datamart'
|
||||||
|
fullPath: '/docs/datamart'
|
||||||
|
preLoaderRoute: typeof DocsDatamartRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
'/docs/$': {
|
'/docs/$': {
|
||||||
id: '/docs/$'
|
id: '/docs/$'
|
||||||
path: '/docs/$'
|
path: '/docs/$'
|
||||||
@@ -463,6 +503,7 @@ declare module '@tanstack/react-router' {
|
|||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
AboutRoute: AboutRoute,
|
AboutRoute: AboutRoute,
|
||||||
|
ApidocsRoute: ApidocsRoute,
|
||||||
AppDownRoute: AppDownRoute,
|
AppDownRoute: AppDownRoute,
|
||||||
ForbiddenRoute: ForbiddenRoute,
|
ForbiddenRoute: ForbiddenRoute,
|
||||||
authLoginRoute: authLoginRoute,
|
authLoginRoute: authLoginRoute,
|
||||||
@@ -473,6 +514,7 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
AdminSettingsRoute: AdminSettingsRoute,
|
AdminSettingsRoute: AdminSettingsRoute,
|
||||||
AdminUsersRoute: AdminUsersRoute,
|
AdminUsersRoute: AdminUsersRoute,
|
||||||
DocsSplatRoute: DocsSplatRoute,
|
DocsSplatRoute: DocsSplatRoute,
|
||||||
|
DocsDatamartRoute: DocsDatamartRoute,
|
||||||
DocsIndexRoute: DocsIndexRoute,
|
DocsIndexRoute: DocsIndexRoute,
|
||||||
authUserProfileRoute: authUserProfileRoute,
|
authUserProfileRoute: authUserProfileRoute,
|
||||||
authUserResetpasswordRoute: authUserResetpasswordRoute,
|
authUserResetpasswordRoute: authUserResetpasswordRoute,
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ const RootLayout = () => {
|
|||||||
<div className="relative min-h-[calc(100svh-var(--header-height))]">
|
<div className="relative min-h-[calc(100svh-var(--header-height))]">
|
||||||
<AppSidebar />
|
<AppSidebar />
|
||||||
|
|
||||||
<main className="w-full p-4">
|
<main className="w-full">
|
||||||
<div className="mx-auto w-full max-w-7xl">
|
<div className="mx-auto w-full flex justify-center">
|
||||||
|
{" "}
|
||||||
|
{/* className="mx-auto w-full max-w-7xl" use this for dashboards and stuff*/}
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -31,7 +33,7 @@ const RootLayout = () => {
|
|||||||
</SidebarProvider>
|
</SidebarProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
{session && session.user.role === "systemAdmin" && (
|
{session && session.user.role === "systemAdmin" && (
|
||||||
<TanStackRouterDevtools />
|
<TanStackRouterDevtools position="bottom-right" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ function RouteComponent() {
|
|||||||
};
|
};
|
||||||
//console.log(logs);
|
//console.log(logs);
|
||||||
return (
|
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">
|
<div className="flex gap-1 justify-end">
|
||||||
<Button onClick={triggerBuild}>Trigger Build</Button>
|
<Button onClick={triggerBuild}>Trigger Build</Button>
|
||||||
<Button onClick={() => clearRoom()}>Clear Logs</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"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
frontend/src/routes/docs/datamart.tsx
Normal file
17
frontend/src/routes/docs/datamart.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/docs/datamart")({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
return (
|
||||||
|
<div className="w-full h-[calc(100vh-48px)] overflow-hidden mr-2 ml-2">
|
||||||
|
<iframe
|
||||||
|
className="w-full h-full border-0"
|
||||||
|
title="datamart"
|
||||||
|
src="https://docs.tuffraid.net/share/40lshswjqq/p/logistics-support-tool-docs-g3nuKAZ7Pw"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||||
import { createColumnHelper } from "@tanstack/react-table";
|
import { createColumnHelper } from "@tanstack/react-table";
|
||||||
|
import { Trash } from "lucide-react";
|
||||||
import { Suspense, useState } from "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 { authClient } from "../../../lib/auth-client";
|
||||||
import { getArticleLinks } from "../../../lib/queries/getArticleLinks";
|
import { getArticleLinks } from "../../../lib/queries/getArticleLinks";
|
||||||
import LstTable from "../../../lib/tableStuff/LstTable";
|
import LstTable from "../../../lib/tableStuff/LstTable";
|
||||||
import SearchableHeader from "../../../lib/tableStuff/SearchableHeader";
|
import SearchableHeader from "../../../lib/tableStuff/SearchableHeader";
|
||||||
import SkellyTable from "../../../lib/tableStuff/SkellyTable";
|
import SkellyTable from "../../../lib/tableStuff/SkellyTable";
|
||||||
import NewArticleLink from "./-components/NewArticleLink";
|
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/")({
|
export const Route = createFileRoute("/transportation/opendock/")({
|
||||||
beforeLoad: async ({ location }) => {
|
beforeLoad: async ({ location }) => {
|
||||||
@@ -97,77 +97,77 @@ const ArticleLinkTable = () => {
|
|||||||
cell: (i) => i.getValue(),
|
cell: (i) => i.getValue(),
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor("deleteUser", {
|
columnHelper.accessor("deleteUser", {
|
||||||
header: ({ column }) => (
|
header: ({ column }) => (
|
||||||
<SearchableHeader
|
<SearchableHeader
|
||||||
column={column}
|
column={column}
|
||||||
title="Delete Link"
|
title="Delete Link"
|
||||||
searchable={false}
|
searchable={false}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
filterFn: "includesString",
|
filterFn: "includesString",
|
||||||
cell: (i) => {
|
cell: (i) => {
|
||||||
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
|
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
|
||||||
const [activeToggle, setActiveToggle] = useState(false);
|
const [activeToggle, setActiveToggle] = useState(false);
|
||||||
|
|
||||||
const onTrigger = async () => {
|
const onTrigger = async () => {
|
||||||
setActiveToggle(true);
|
setActiveToggle(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await api.delete(
|
const res = await api.delete(
|
||||||
`/opendock/articleCheck/${i.row.original.id}`,
|
`/opendock/articleCheck/${i.row.original.id}`,
|
||||||
|
|
||||||
{
|
{
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
timeout: 5000,
|
timeout: 5000,
|
||||||
validateStatus: () => true,
|
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>
|
|
||||||
);
|
);
|
||||||
},
|
|
||||||
}),
|
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 (
|
return (
|
||||||
<div>
|
<div className="">
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-end m-2">
|
<div className="flex justify-end m-2">
|
||||||
<Suspense
|
<Suspense
|
||||||
|
|||||||
@@ -4,4 +4,10 @@
|
|||||||
{ "path": "./tsconfig.app.json" },
|
{ "path": "./tsconfig.app.json" },
|
||||||
{ "path": "./tsconfig.node.json" }
|
{ "path": "./tsconfig.node.json" }
|
||||||
],
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
90
package-lock.json
generated
90
package-lock.json
generated
@@ -10,7 +10,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dotenvx/dotenvx": "^1.57.0",
|
"@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",
|
"@socket.io/admin-ui": "^0.5.1",
|
||||||
"archiver": "^7.0.1",
|
"archiver": "^7.0.1",
|
||||||
"axios": "^1.13.6",
|
"axios": "^1.13.6",
|
||||||
@@ -44,7 +44,8 @@
|
|||||||
"socket.io": "^4.8.3",
|
"socket.io": "^4.8.3",
|
||||||
"socket.io-client": "^4.8.3",
|
"socket.io-client": "^4.8.3",
|
||||||
"xlsx": "^0.18.5",
|
"xlsx": "^0.18.5",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6",
|
||||||
|
"zod-openapi": "^6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.4.8",
|
"@biomejs/biome": "2.4.8",
|
||||||
@@ -2424,46 +2425,61 @@
|
|||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@scalar/core": {
|
"node_modules/@scalar/client-side-rendering": {
|
||||||
"version": "0.4.4",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/@scalar/core/-/core-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@scalar/client-side-rendering/-/client-side-rendering-0.1.13.tgz",
|
||||||
"integrity": "sha512-eXIG0opyQn45FzpTp0dAWFP1Vjcx+helgUAsa0uN36tyUR7DSmz2kRwHqqedzvPWryeRCKPz7/vwzKpETZp5lg==",
|
"integrity": "sha512-p8V4HgEWjaCpqsnhclg1pTfjE9JA0AWRr0ocBQHexoHo+pqnSs1d83Mv9rjH7R0FZJrlCSandZZeY3DMX2gYXQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@scalar/types": "0.7.4"
|
"@scalar/schemas": "0.3.3",
|
||||||
|
"@scalar/types": "0.12.3",
|
||||||
|
"@scalar/validation": "0.6.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@scalar/express-api-reference": {
|
"node_modules/@scalar/express-api-reference": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.20",
|
||||||
"resolved": "https://registry.npmjs.org/@scalar/express-api-reference/-/express-api-reference-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/@scalar/express-api-reference/-/express-api-reference-0.9.20.tgz",
|
||||||
"integrity": "sha512-KXG+VaMArCGcWhzDV2rfkHd+UF1HYevIFbO6cqFpd+az7QHvVT99BU8Yh60T1dmtCp504s0Pl/vcTyJ91fK1Ug==",
|
"integrity": "sha512-J0P6qpYoL0kXvs/A/vuAwCqQFCYnErbXSB5/3lEGTbARuK0oGyMvl55dQyW5Ucq3CX1npuRejlTX6bxEprSvJA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@scalar/core": "0.4.4"
|
"@scalar/client-side-rendering": "0.1.13"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@scalar/helpers": {
|
"node_modules/@scalar/helpers": {
|
||||||
"version": "0.4.2",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.8.1.tgz",
|
||||||
"integrity": "sha512-IrgrGVSahCfYDNWITazz4Q1BOndp5eEzlimRkfxiYn++KqeWyLfALyym1omqcdKGYtiSx1KIbKaUJL9vkjaN7w==",
|
"integrity": "sha512-yuiuBCadP5bjAnIv23QvifVN/NaMi9xBF6b8Wdk4QOzwzLPJmp699MAdf33J0A5i2qKcvnu32iz/VkEJmQRe5g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@scalar/types": {
|
"node_modules/@scalar/schemas": {
|
||||||
"version": "0.7.4",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@scalar/schemas/-/schemas-0.3.3.tgz",
|
||||||
"integrity": "sha512-1o9uf42lZ9YD0XP/HMWrwXN0unx6vFTTgtduA1F28Yloea9Pfv9N2R/t0wO91iSIzw4+NubEFolunbdb2QcgHA==",
|
"integrity": "sha512-qDcgFu6ta5Z90L9D2P6DFKzYesU+FW5+m55SGmdI4iRMRCwj5umHpec2Y2W/SJcCF6bbUZawMxuOH2Ja6rUNpQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"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",
|
"nanoid": "^5.1.6",
|
||||||
"type-fest": "^5.3.1",
|
"type-fest": "^5.3.1",
|
||||||
"zod": "^4.3.5"
|
"zod": "^4.3.5"
|
||||||
@@ -2472,6 +2488,15 @@
|
|||||||
"node": ">=22"
|
"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": {
|
"node_modules/@serialport/binding-mock": {
|
||||||
"version": "10.2.2",
|
"version": "10.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-10.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-10.2.2.tgz",
|
||||||
@@ -10566,9 +10591,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "5.1.7",
|
"version": "5.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz",
|
||||||
"integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==",
|
"integrity": "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -13252,9 +13277,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/type-fest": {
|
"node_modules/type-fest": {
|
||||||
"version": "5.5.0",
|
"version": "5.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz",
|
||||||
"integrity": "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==",
|
"integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==",
|
||||||
"license": "(MIT OR CC0-1.0)",
|
"license": "(MIT OR CC0-1.0)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tagged-tag": "^1.0.0"
|
"tagged-tag": "^1.0.0"
|
||||||
@@ -13937,6 +13962,21 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
223
package.json
223
package.json
@@ -1,112 +1,115 @@
|
|||||||
{
|
{
|
||||||
"name": "lst_v3",
|
"name": "lst_v3",
|
||||||
"version": "0.1.0-alpha.3",
|
"version": "0.1.0-alpha.3",
|
||||||
"description": "The tool that supports us in our everyday alplaprod",
|
"build": "179",
|
||||||
"main": "index.js",
|
"lastBuildDate": "6/17/2026 11:03",
|
||||||
"scripts": {
|
"description": "The tool that supports us in our everyday alplaprod",
|
||||||
"test": "dotenvx run -f .env -- vitest",
|
"main": "index.js",
|
||||||
"test:run": "dotenvx run -f .env -- vitest run",
|
"scripts": {
|
||||||
"dev": "concurrently -n \"server,frontend\" -c \"#007755, #1F73D1\" \"npm run dev:app\" \"npm run dev:frontend\"",
|
"test": "dotenvx run -f .env -- vitest",
|
||||||
"dev:app": "dotenvx run -f .env -- tsx watch backend/server.ts",
|
"test:run": "dotenvx run -f .env -- vitest run",
|
||||||
"dev:frontend": "cd frontend && npm run dev",
|
"dev": "concurrently -n \"server,frontend\" -c \"#007755, #1F73D1\" \"npm run dev:app\" \"npm run dev:frontend\"",
|
||||||
"dev:db:migrate": "npx drizzle-kit push",
|
"dev:app": "dotenvx run -f .env -- tsx watch backend/server.ts",
|
||||||
"dev:db:generate": "tsc && npx drizzle-kit generate --config=drizzle.config.ts",
|
"dev:frontend": "cd frontend && npm run dev",
|
||||||
"build": "rimraf dist && npm run dev:db:generate && npm run dev:db:migrate && npm run build:app && npm run build:copySql && npm run build:copyGpSql && npm run build:emailTemplate && cd frontend && npm run build",
|
"dev:db:migrate": "npx drizzle-kit push",
|
||||||
"build:app": "tsc",
|
"dev:db:generate": "tsc && npx drizzle-kit generate --config=drizzle.config.ts",
|
||||||
"agent": "powershell -ExecutionPolicy Bypass -File scripts/agentController.ps1",
|
"build": "rimraf dist && npm run dev:db:generate && npm run dev:db:migrate && npm run build:app && npm run build:copySql && npm run build:copyGpSql && npm run build:emailTemplate && cd frontend && npm run build",
|
||||||
"build:docker": "rimraf dist && npm run build:app && npm run build:copySql && npm run build:copyGpSql && npm run build:emailTemplate",
|
"build:app": "tsc",
|
||||||
"build:emailTemplate": "cpy \"backend/utils/mailViews/**/*\" dist/utils/mailViews --parents",
|
"agent": "powershell -ExecutionPolicy Bypass -File scripts/agentController.ps1",
|
||||||
"build:copyGpSql": "cpy \"backend/gpSql/queries/**/*\" dist/gpSql/queries --parents",
|
"build:docker": "rimraf dist && npm run build:app && npm run build:copySql && npm run build:copyGpSql && npm run build:emailTemplate",
|
||||||
"build:copySql": "cpy \"backend/prodSql/queries/**/*\" dist/prodSql/queries --parents",
|
"build:emailTemplate": "cpy \"backend/utils/mailViews/**/*\" dist/utils/mailViews --parents",
|
||||||
"lint": "tsc && biome lint",
|
"build:copyGpSql": "cpy \"backend/gpSql/queries/**/*\" dist/gpSql/queries --parents",
|
||||||
"start": "npm run start:server",
|
"build:copySql": "cpy \"backend/prodSql/queries/**/*\" dist/prodSql/queries --parents",
|
||||||
"start:server": "dotenvx run -f .env -- node dist/server.js",
|
"lint": "tsc && biome lint",
|
||||||
"start:docker": "node dist/server.js",
|
"start": "npm run start:server",
|
||||||
"version": "changeset version",
|
"start:server": "dotenvx run -f .env -- node dist/server.js",
|
||||||
"specCheck": "node scripts/check-route-specs.mjs",
|
"start:docker": "node dist/server.js",
|
||||||
"commit": "cz",
|
"version": "changeset version",
|
||||||
"release": "npm run build && commit-and-tag-version",
|
"specCheck": "node scripts/check-route-specs.mjs",
|
||||||
"build:apk": "cd lstMobile && expo prebuild --clean && cd android && gradlew.bat assembleRelease "
|
"commit": "cz",
|
||||||
},
|
"release": "npm run build && commit-and-tag-version",
|
||||||
"repository": {
|
"build:apk": "cd lstMobile && expo prebuild --clean && cd android && gradlew.bat assembleRelease "
|
||||||
"type": "git",
|
},
|
||||||
"url": "https://git.tuffraid.net/cowch/lst_v3.git"
|
"repository": {
|
||||||
},
|
"type": "git",
|
||||||
"keywords": [],
|
"url": "https://git.tuffraid.net/cowch/lst_v3.git"
|
||||||
"author": "",
|
},
|
||||||
"license": "ISC",
|
"keywords": [],
|
||||||
"type": "module",
|
"author": "",
|
||||||
"devDependencies": {
|
"license": "ISC",
|
||||||
"@biomejs/biome": "2.4.8",
|
"type": "module",
|
||||||
"@commitlint/cli": "^20.5.0",
|
"devDependencies": {
|
||||||
"@commitlint/config-conventional": "^20.5.0",
|
"@biomejs/biome": "2.4.8",
|
||||||
"@types/archiver": "^7.0.0",
|
"@commitlint/cli": "^20.5.0",
|
||||||
"@types/cors": "^2.8.19",
|
"@commitlint/config-conventional": "^20.5.0",
|
||||||
"@types/express": "^5.0.6",
|
"@types/archiver": "^7.0.0",
|
||||||
"@types/morgan": "^1.9.10",
|
"@types/cors": "^2.8.19",
|
||||||
"@types/mssql": "^9.1.9",
|
"@types/express": "^5.0.6",
|
||||||
"@types/multer": "^2.1.0",
|
"@types/morgan": "^1.9.10",
|
||||||
"@types/net-snmp": "^3.23.0",
|
"@types/mssql": "^9.1.9",
|
||||||
"@types/node": "^25.5.0",
|
"@types/multer": "^2.1.0",
|
||||||
"@types/nodemailer": "^7.0.11",
|
"@types/net-snmp": "^3.23.0",
|
||||||
"@types/nodemailer-express-handlebars": "^4.0.6",
|
"@types/node": "^25.5.0",
|
||||||
"@types/pg": "^8.18.0",
|
"@types/nodemailer": "^7.0.11",
|
||||||
"@types/supertest": "^7.2.0",
|
"@types/nodemailer-express-handlebars": "^4.0.6",
|
||||||
"@types/swagger-jsdoc": "^6.0.4",
|
"@types/pg": "^8.18.0",
|
||||||
"@types/swagger-ui-express": "^4.1.8",
|
"@types/supertest": "^7.2.0",
|
||||||
"commit-and-tag-version": "^12.7.1",
|
"@types/swagger-jsdoc": "^6.0.4",
|
||||||
"commitizen": "^4.3.1",
|
"@types/swagger-ui-express": "^4.1.8",
|
||||||
"cpy-cli": "^7.0.0",
|
"commit-and-tag-version": "^12.7.1",
|
||||||
"cz-conventional-changelog": "^3.3.0",
|
"commitizen": "^4.3.1",
|
||||||
"npm-check-updates": "^19.6.5",
|
"cpy-cli": "^7.0.0",
|
||||||
"openapi-types": "^12.1.3",
|
"cz-conventional-changelog": "^3.3.0",
|
||||||
"supertest": "^7.2.2",
|
"npm-check-updates": "^19.6.5",
|
||||||
"ts-node-dev": "^2.0.0",
|
"openapi-types": "^12.1.3",
|
||||||
"tsx": "^4.21.0",
|
"supertest": "^7.2.2",
|
||||||
"typescript": "^5.9.3",
|
"ts-node-dev": "^2.0.0",
|
||||||
"vitest": "^4.1.8"
|
"tsx": "^4.21.0",
|
||||||
},
|
"typescript": "^5.9.3",
|
||||||
"dependencies": {
|
"vitest": "^4.1.8"
|
||||||
"@dotenvx/dotenvx": "^1.57.0",
|
},
|
||||||
"@scalar/express-api-reference": "^0.9.4",
|
"dependencies": {
|
||||||
"@socket.io/admin-ui": "^0.5.1",
|
"@dotenvx/dotenvx": "^1.57.0",
|
||||||
"archiver": "^7.0.1",
|
"@scalar/express-api-reference": "^0.9.20",
|
||||||
"axios": "^1.13.6",
|
"@socket.io/admin-ui": "^0.5.1",
|
||||||
"bcryptjs": "^3.0.3",
|
"archiver": "^7.0.1",
|
||||||
"better-auth": "^1.5.5",
|
"axios": "^1.13.6",
|
||||||
"chokidar": "^5.0.0",
|
"bcryptjs": "^3.0.3",
|
||||||
"concurrently": "^9.2.1",
|
"better-auth": "^1.5.5",
|
||||||
"cors": "^2.8.6",
|
"chokidar": "^5.0.0",
|
||||||
"croner": "^10.0.1",
|
"concurrently": "^9.2.1",
|
||||||
"date-fns": "^4.1.0",
|
"cors": "^2.8.6",
|
||||||
"date-fns-tz": "^3.2.0",
|
"croner": "^10.0.1",
|
||||||
"drizzle-kit": "^0.31.10",
|
"date-fns": "^4.1.0",
|
||||||
"drizzle-orm": "^0.45.1",
|
"date-fns-tz": "^3.2.0",
|
||||||
"drizzle-zod": "^0.8.3",
|
"drizzle-kit": "^0.31.10",
|
||||||
"excel-date-to-js": "^1.1.5",
|
"drizzle-orm": "^0.45.1",
|
||||||
"express": "^5.2.1",
|
"drizzle-zod": "^0.8.3",
|
||||||
"husky": "^9.1.7",
|
"excel-date-to-js": "^1.1.5",
|
||||||
"ldapts": "^8.1.7",
|
"express": "^5.2.1",
|
||||||
"modbus-serial": "^8.0.25",
|
"husky": "^9.1.7",
|
||||||
"morgan": "^1.10.1",
|
"ldapts": "^8.1.7",
|
||||||
"mssql": "^12.2.1",
|
"modbus-serial": "^8.0.25",
|
||||||
"multer": "^2.1.1",
|
"morgan": "^1.10.1",
|
||||||
"net-snmp": "^3.26.1",
|
"mssql": "^12.2.1",
|
||||||
"nodemailer": "^8.0.3",
|
"multer": "^2.1.1",
|
||||||
"nodemailer-express-handlebars": "^7.0.0",
|
"net-snmp": "^3.26.1",
|
||||||
"pg": "^8.20.0",
|
"nodemailer": "^8.0.3",
|
||||||
"pino": "^10.3.1",
|
"nodemailer-express-handlebars": "^7.0.0",
|
||||||
"pino-pretty": "^13.1.3",
|
"pg": "^8.20.0",
|
||||||
"postgres": "^3.4.8",
|
"pino": "^10.3.1",
|
||||||
"powershell": "^2.3.3",
|
"pino-pretty": "^13.1.3",
|
||||||
"socket.io": "^4.8.3",
|
"postgres": "^3.4.8",
|
||||||
"socket.io-client": "^4.8.3",
|
"powershell": "^2.3.3",
|
||||||
"xlsx": "^0.18.5",
|
"socket.io": "^4.8.3",
|
||||||
"zod": "^4.3.6"
|
"socket.io-client": "^4.8.3",
|
||||||
},
|
"xlsx": "^0.18.5",
|
||||||
"config": {
|
"zod": "^4.3.6",
|
||||||
"commitizen": {
|
"zod-openapi": "^6.0.0"
|
||||||
"path": "cz-conventional-changelog"
|
},
|
||||||
}
|
"config": {
|
||||||
}
|
"commitizen": {
|
||||||
|
"path": "cz-conventional-changelog"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,24 +31,32 @@ function Update-Server {
|
|||||||
[string]$Server,
|
[string]$Server,
|
||||||
[string]$Token
|
[string]$Token
|
||||||
)
|
)
|
||||||
$buildFile = Join-Path $AppDir ".buildNumber"
|
|
||||||
|
$buildFile = Join-Path $AppDir "package.json"
|
||||||
$BuildNumber = 1
|
$BuildNumber = 1
|
||||||
$BuildFolder = Join-Path $AppDir "builds"
|
$BuildFolder = Join-Path $AppDir "builds"
|
||||||
|
|
||||||
if (Test-Path $BuildFile) {
|
$packageJson = Get-Content $buildFile -Raw | ConvertFrom-Json
|
||||||
$content = Get-Content $BuildFile | Select-Object -First 1
|
|
||||||
$num = $content.Trim() -as [int] # safe cast
|
# Extract the .build property and cast it safely to an integer
|
||||||
|
$num = "$($packageJson.version).$(([int]$packageJson.build) -1)"
|
||||||
|
# if (Test-Path $BuildFile) {
|
||||||
|
# # Parse the entire JSON file into a PowerShell object
|
||||||
|
# $packageJson = Get-Content $buildFile -Raw | ConvertFrom-Json
|
||||||
|
|
||||||
|
# # Extract the .build property and cast it safely to an integer
|
||||||
|
# $num = "($packageJson.version).($packageJson.build)"
|
||||||
|
|
||||||
if ($num) {
|
# if ($null -ne $num) {
|
||||||
$BuildNumber = $num + 1
|
# $BuildNumber = $num + 1
|
||||||
}
|
# }
|
||||||
else {
|
# else {
|
||||||
$BuildNumber = 1
|
# $BuildNumber = 1
|
||||||
}
|
# }
|
||||||
}
|
# }
|
||||||
|
|
||||||
# Get The current Build we have zipped up
|
# Get The current Build we have zipped up
|
||||||
$BuildNumber = ([int]$BuildNumber - 1).ToString()
|
$BuildNumber = $num
|
||||||
|
|
||||||
|
|
||||||
# copy the latest build over
|
# copy the latest build over
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ESNext",
|
|
||||||
"module": "NodeNext",
|
|
||||||
"moduleResolution": "nodenext",
|
|
||||||
"strict": true,
|
|
||||||
"verbatimModuleSyntax": true,
|
|
||||||
"types": ["node", "better-auth"],
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"outDir": "./dist",
|
|
||||||
"removeComments": true,
|
|
||||||
"allowJs": false,
|
|
||||||
"rootDir": "./backend",
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noUnusedParameters": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
"noUncheckedIndexedAccess": true,
|
|
||||||
"exactOptionalPropertyTypes": true,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["backend/*"],
|
|
||||||
"@features/*": ["backend/features/*"],
|
|
||||||
"@shared/*": ["backend/shared/*"],
|
|
||||||
"@config/*": ["backend/config/*"]
|
|
||||||
},
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
//"allowImportingTsExtensions": true,
|
|
||||||
"noEmit": false
|
|
||||||
},
|
|
||||||
"include": ["backend/**/*"],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"frontend",
|
|
||||||
"dist",
|
|
||||||
"lstDocs",
|
|
||||||
"database/testFiles",
|
|
||||||
"scripts"
|
|
||||||
]}
|
|
||||||
Reference in New Issue
Block a user