Compare commits
5 Commits
7dbc31c046
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a24d62957 | |||
| 6a14bab30c | |||
| 2ebf695526 | |||
| 24af3ca403 | |||
| 6fbe3a9eed |
@@ -9,8 +9,6 @@ import os from "node:os";
|
||||
import { apiReference } from "@scalar/express-api-reference";
|
||||
// const port = 3000;
|
||||
import type { OpenAPIV3_1 } from "openapi-types";
|
||||
import { cronerActiveJobs } from "../scaler/cronerActiveJobs.spec.js";
|
||||
import { cronerStatusChange } from "../scaler/cronerStatusChange.spec.js";
|
||||
import { prodLoginSpec } from "../scaler/login.spec.js";
|
||||
import { openDockApt } from "../scaler/opendockGetRelease.spec.js";
|
||||
import { prodRestartSpec } from "../scaler/prodSqlRestart.spec.js";
|
||||
@@ -125,8 +123,6 @@ export const setupApiDocsRoutes = (baseUrl: string, app: Express) => {
|
||||
...prodLoginSpec,
|
||||
...prodRegisterSpec,
|
||||
//...mergedDatamart,
|
||||
...cronerActiveJobs,
|
||||
...cronerStatusChange,
|
||||
...openDockApt,
|
||||
|
||||
// Add more specs here as you build features
|
||||
|
||||
@@ -37,6 +37,7 @@ const lstDbRun = async (data: Data) => {
|
||||
if (data.options) {
|
||||
if (data.name === "psiInventory") {
|
||||
const ids = data.options.articles.split(",").map((id: any) => id.trim());
|
||||
|
||||
const whse = data.options.whseToInclude
|
||||
? data.options.whseToInclude
|
||||
.split(",")
|
||||
@@ -274,10 +275,10 @@ export const runDatamartQuery = async (data: Data) => {
|
||||
.replace("[startDate]", `${data.options.startDate}`)
|
||||
.replace("[endDate]", `${data.options.endDate}`)
|
||||
.replace(
|
||||
"and p.IdArtikelvarianten in ([articles])",
|
||||
"and pl.ArticleHumanReadableId IN ([articles]) ",
|
||||
data.options.articles
|
||||
? `and p.IdArtikelvarianten in (${data.options.articles})`
|
||||
: "--and p.IdArtikelvarianten in ([articles])",
|
||||
? `and pl.ArticleHumanReadableId IN (${data.options.articles})`
|
||||
: "--and pl.ArticleHumanReadableId IN ([articles])",
|
||||
);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Router } from "express";
|
||||
import * as XLSX from "xlsx";
|
||||
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||
import { runDatamartQuery } from "./datamart.controller.js";
|
||||
|
||||
@@ -7,13 +8,73 @@ const r = Router();
|
||||
type Options = {
|
||||
name: string;
|
||||
value: string;
|
||||
format: string;
|
||||
};
|
||||
|
||||
r.get("/:name", async (req, res) => {
|
||||
const { name } = req.params;
|
||||
const options = req.query as Options;
|
||||
|
||||
const options = { ...req.query } as 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, {
|
||||
success: dataRan.success,
|
||||
level: "info",
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
sqlQuerySelector,
|
||||
} from "../prodSql/prodSqlQuerySelector.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 { postData } from "./logistics.dm.postData.js";
|
||||
|
||||
@@ -83,7 +83,7 @@ export const lorealForecast = async (data: any, user: any) => {
|
||||
|
||||
const article: any = a?.data;
|
||||
|
||||
console.log(article);
|
||||
//console.log(article);
|
||||
|
||||
// process the ebm forcast
|
||||
for (let i = 0; i < ebmForeCastData.length; i++) {
|
||||
@@ -127,31 +127,6 @@ export const lorealForecast = async (data: any, user: any) => {
|
||||
//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
|
||||
for (let i = 0; i < petForeCastData.length; i++) {
|
||||
// bottle code
|
||||
@@ -200,25 +175,25 @@ export const lorealForecast = async (data: any, user: any) => {
|
||||
//console.log(comForecast);
|
||||
|
||||
// email the for the missing ones
|
||||
const missedGrouped = Object.values(
|
||||
missingSku.reduce((acc: any, item: any) => {
|
||||
const key = item.customerArticleNo;
|
||||
// const missedGrouped = Object.values(
|
||||
// missingSku.reduce((acc: any, item: any) => {
|
||||
// const key = item.customerArticleNo;
|
||||
|
||||
if (!acc[key]) {
|
||||
// first time we see this customer
|
||||
acc[key] = item;
|
||||
} else {
|
||||
// compare dates and keep the earliest
|
||||
if (
|
||||
new Date(item.requirementDate) < new Date(acc[key].requirementDate)
|
||||
) {
|
||||
acc[key] = item;
|
||||
}
|
||||
}
|
||||
// if (!acc[key]) {
|
||||
// // first time we see this customer
|
||||
// acc[key] = item;
|
||||
// } else {
|
||||
// // compare dates and keep the earliest
|
||||
// if (
|
||||
// new Date(item.requirementDate) < new Date(acc[key].requirementDate)
|
||||
// ) {
|
||||
// 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.
|
||||
// const emailSetup = {
|
||||
@@ -248,19 +223,7 @@ export const lorealForecast = async (data: any, user: any) => {
|
||||
|
||||
const updatedPredefinedObject = {
|
||||
...predefinedObject,
|
||||
positions: [
|
||||
...predefinedObject.positions,
|
||||
...ebmForecastData,
|
||||
|
||||
// ...ebmForecastData.filter(
|
||||
// (q: any) =>
|
||||
// q.customerArticleNo != "" && q.customerArticleNo != "Total"
|
||||
// ),
|
||||
// ...petForecastData.filter(
|
||||
// (q: any) =>
|
||||
// q.customerArticleNo != "" && q.customerArticleNo != "Total"
|
||||
// ),
|
||||
],
|
||||
positions: [...predefinedObject.positions, ...ebmForecastData],
|
||||
};
|
||||
// console.log(updatedPredefinedObject);
|
||||
|
||||
|
||||
@@ -113,8 +113,8 @@ export const pNgForecast = async (data: any, user: any) => {
|
||||
// }
|
||||
|
||||
return {
|
||||
customerArticleNo: parseInt(o["Customer Item No."]),
|
||||
requirementDate: excelDateStuff(parseInt(o["Request Date"])),
|
||||
customerArticleNo: parseInt(o["Customer Item No."] ?? "0", 10),
|
||||
requirementDate: excelDateStuff(parseInt(o["Request Date"] ?? "0", 10)),
|
||||
quantity: o["Remaining Qty to be Shipped"],
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,74 +1,73 @@
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
|
||||
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
|
||||
SELECT
|
||||
r.[ArticleHumanReadableId]
|
||||
,[ReleaseNumber]
|
||||
,h.CustomerOrderNumber
|
||||
,x.CustomerLineItemNumber
|
||||
,[CustomerReleaseNumber]
|
||||
,[ReleaseState]
|
||||
,[DeliveryState]
|
||||
,ea.JournalNummer as BOL_Number
|
||||
,[ReleaseConfirmationState]
|
||||
,[PlanningState]
|
||||
DECLARE @StartDate DATE = '[startDate]'
|
||||
DECLARE @EndDate DATE = '[endDate]'
|
||||
|
||||
;WITH bol_20 AS ( -- 2.0 BOL, one per release (newest doc wins)
|
||||
SELECT pos.ReleaseId,
|
||||
dd.JournalNumber,
|
||||
ROW_NUMBER() OVER (PARTITION BY pos.ReleaseId
|
||||
ORDER BY dd.ShippingDate DESC) AS rn
|
||||
FROM [outboundDelivery].[DeliveryDocumentPosition] (nolock) pos
|
||||
JOIN [outboundDelivery].[DeliveryDocument] (nolock) dd
|
||||
ON dd.Id = pos.DeliveryDocumentId
|
||||
-- WHERE dd.DocumentType = <BOL value> -- see note below
|
||||
)
|
||||
SELECT
|
||||
r.[ArticleHumanReadableId]
|
||||
,[ReleaseNumber]
|
||||
,h.CustomerOrderNumber
|
||||
,x.CustomerLineItemNumber
|
||||
,[CustomerReleaseNumber]
|
||||
,[ReleaseState]
|
||||
,[DeliveryState]
|
||||
,COALESCE(ea.JournalNummer, bol_20.JournalNumber) AS BOL_Number -- 1.0 or 2.0
|
||||
,[ReleaseConfirmationState]
|
||||
,[PlanningState]
|
||||
,format(r.[OrderDate], 'yyyy-MM-dd HH:mm') as OrderDate
|
||||
--,r.[OrderDate]
|
||||
,FORMAT(r.[DeliveryDate], 'yyyy-MM-dd HH:mm') as DeliveryDate
|
||||
--,r.[DeliveryDate]
|
||||
,FORMAT(r.[LoadingDate], 'yyyy-MM-dd HH:mm') as LoadingDate
|
||||
--,r.[LoadingDate]
|
||||
,[Quantity]
|
||||
,[DeliveredQuantity]
|
||||
,r.[AdditionalInformation1]
|
||||
,r.[AdditionalInformation2]
|
||||
,[TradeUnits]
|
||||
,[LoadingUnits]
|
||||
,[Trucks]
|
||||
,[LoadingToleranceType]
|
||||
,[SalesPrice]
|
||||
,[Currency]
|
||||
,[QuantityUnit]
|
||||
,[SalesPriceRemark]
|
||||
,r.[Remark]
|
||||
,[Irradiated]
|
||||
,r.[CreatedByEdi]
|
||||
,[DeliveryAddressHumanReadableId]
|
||||
,DeliveryAddressDescription
|
||||
,[CustomerArtNo]
|
||||
,[TotalPrice]
|
||||
,r.[ArticleAlias]
|
||||
,[Quantity]
|
||||
,[DeliveredQuantity]
|
||||
,r.[AdditionalInformation1]
|
||||
,r.[AdditionalInformation2]
|
||||
,[TradeUnits]
|
||||
,[LoadingUnits]
|
||||
,[Trucks]
|
||||
,[LoadingToleranceType]
|
||||
,[SalesPrice]
|
||||
,[Currency]
|
||||
,[QuantityUnit]
|
||||
,[SalesPriceRemark]
|
||||
,r.[Remark]
|
||||
,[Irradiated]
|
||||
,r.[CreatedByEdi]
|
||||
,[DeliveryAddressHumanReadableId]
|
||||
,DeliveryAddressDescription
|
||||
,[CustomerArtNo]
|
||||
,[TotalPrice]
|
||||
,r.[ArticleAlias]
|
||||
FROM [order].[Release] (nolock) AS r
|
||||
LEFT JOIN [order].LineItem AS x ON r.LineItemId = x.id
|
||||
LEFT JOIN [order].Header AS h ON x.HeaderId = h.id
|
||||
|
||||
FROM [order].[Release] (nolock) as r
|
||||
-- 1.0 BOL (legacy) — unchanged
|
||||
LEFT JOIN AlplaPROD_test1.dbo.V_LadePlanungenLadeAuftragAbruf (nolock) AS zz
|
||||
ON zz.AbrufIdAuftragsAbruf = r.ReleaseNumber
|
||||
LEFT JOIN (
|
||||
SELECT * FROM (
|
||||
SELECT ROW_NUMBER() OVER (PARTITION BY IdJournal ORDER BY add_date DESC) AS RowNum, *
|
||||
FROM [AlplaPROD_test1].[dbo].[T_Lieferungen] (nolock)
|
||||
) t WHERE RowNum = 1
|
||||
) AS ea ON zz.IdLieferschein = ea.IdJournal
|
||||
|
||||
left join
|
||||
[order].LineItem as x on
|
||||
-- 2.0 BOL (new)
|
||||
LEFT JOIN bol_20 ON bol_20.ReleaseId = r.Id AND bol_20.rn = 1
|
||||
|
||||
r.LineItemId = x.id
|
||||
|
||||
left join
|
||||
[order].Header as h on
|
||||
x.HeaderId = h.id
|
||||
|
||||
--bol stuff
|
||||
left join
|
||||
AlplaPROD_test1.dbo.V_LadePlanungenLadeAuftragAbruf (nolock) as zz
|
||||
on zz.AbrufIdAuftragsAbruf = r.ReleaseNumber
|
||||
|
||||
left join
|
||||
(select * from (SELECT
|
||||
ROW_NUMBER() OVER (PARTITION BY IdJournal ORDER BY add_date DESC) AS RowNum
|
||||
,*
|
||||
FROM [AlplaPROD_test1].[dbo].[T_Lieferungen] (nolock)) x
|
||||
|
||||
where RowNum = 1) as ea on
|
||||
zz.IdLieferschein = ea.IdJournal
|
||||
|
||||
where
|
||||
--r.ReleaseNumber = 1452
|
||||
|
||||
r.DeliveryDate between @StartDate AND @EndDate
|
||||
WHERE r.DeliveryDate BETWEEN @StartDate AND @EndDate
|
||||
and DeliveredQuantity > 0
|
||||
--and r.ArticleHumanReadableId in ([articles])
|
||||
--and Journalnummer = 169386
|
||||
@@ -1,79 +0,0 @@
|
||||
use AlplaPROD_test1
|
||||
/**
|
||||
|
||||
move this over to the delivery date range query once we have the shift data mapped over correctly.
|
||||
|
||||
update the psi stuff on this as well.
|
||||
**/
|
||||
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
|
||||
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
|
||||
SELECT
|
||||
r.[ArticleHumanReadableId]
|
||||
,[ReleaseNumber]
|
||||
,h.CustomerOrderNumber
|
||||
,x.CustomerLineItemNumber
|
||||
,[CustomerReleaseNumber]
|
||||
,[ReleaseState]
|
||||
,[DeliveryState]
|
||||
,ea.JournalNummer as BOL_Number
|
||||
,[ReleaseConfirmationState]
|
||||
,[PlanningState]
|
||||
--,format(r.[OrderDate], 'yyyy-MM-dd HH:mm') as OrderDate
|
||||
,r.[OrderDate]
|
||||
--,FORMAT(r.[DeliveryDate], 'yyyy-MM-dd HH:mm') as DeliveryDate
|
||||
,r.[DeliveryDate]
|
||||
--,FORMAT(r.[LoadingDate], 'yyyy-MM-dd HH:mm') as LoadingDate
|
||||
,r.[LoadingDate]
|
||||
,[Quantity]
|
||||
,[DeliveredQuantity]
|
||||
,r.[AdditionalInformation1]
|
||||
,r.[AdditionalInformation2]
|
||||
,[TradeUnits]
|
||||
,[LoadingUnits]
|
||||
,[Trucks]
|
||||
,[LoadingToleranceType]
|
||||
,[SalesPrice]
|
||||
,[Currency]
|
||||
,[QuantityUnit]
|
||||
,[SalesPriceRemark]
|
||||
,r.[Remark]
|
||||
,[Irradiated]
|
||||
,r.[CreatedByEdi]
|
||||
,[DeliveryAddressHumanReadableId]
|
||||
,DeliveryAddressDescription
|
||||
,[CustomerArtNo]
|
||||
,[TotalPrice]
|
||||
,r.[ArticleAlias]
|
||||
|
||||
FROM [order].[Release] (nolock) as r
|
||||
|
||||
left join
|
||||
[order].LineItem as x on
|
||||
|
||||
r.LineItemId = x.id
|
||||
|
||||
left join
|
||||
[order].Header as h on
|
||||
x.HeaderId = h.id
|
||||
|
||||
--bol stuff
|
||||
left join
|
||||
AlplaPROD_test1.dbo.V_LadePlanungenLadeAuftragAbruf (nolock) as zz
|
||||
on zz.AbrufIdAuftragsAbruf = r.ReleaseNumber
|
||||
|
||||
left join
|
||||
(select * from (SELECT
|
||||
ROW_NUMBER() OVER (PARTITION BY IdJournal ORDER BY add_date DESC) AS RowNum
|
||||
,*
|
||||
FROM [AlplaPROD_test1].[dbo].[T_Lieferungen] (nolock)) x
|
||||
|
||||
where RowNum = 1) as ea on
|
||||
zz.IdLieferschein = ea.IdJournal
|
||||
|
||||
where
|
||||
r.ArticleHumanReadableId in ([articles])
|
||||
--r.ReleaseNumber = 1452
|
||||
|
||||
and r.DeliveryDate between @StartDate AND @EndDate
|
||||
--and DeliveredQuantity > 0
|
||||
--and Journalnummer = 169386
|
||||
@@ -1,32 +1,72 @@
|
||||
use AlplaPROD_test1
|
||||
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
|
||||
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
|
||||
/*
|
||||
articles will need to be passed over as well as the date structure we want to see
|
||||
*/
|
||||
use [test1_AlplaPROD2.0_Read]
|
||||
|
||||
select x.IdArtikelvarianten As Article,
|
||||
ProduktionAlias as Description,
|
||||
standort as MachineId,
|
||||
MaschinenBezeichnung as MachineName,
|
||||
--MaschZyklus as PlanningCycleTime,
|
||||
x.IdProdPlanung as LotNumber,
|
||||
FORMAT(ProdTag, 'MM/dd/yyyy') as ProductionDay,
|
||||
x.planMenge as TotalPlanned,
|
||||
ProduktionMenge as QTYPerDay,
|
||||
round(ProduktionMengeVPK, 2) PalDay,
|
||||
Status as finished
|
||||
--MaschStdAuslastung as nee
|
||||
|
||||
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock) as x
|
||||
|
||||
left join
|
||||
dbo.V_ProdPlanung (nolock) as p on
|
||||
x.IdProdPlanung = p.IdProdPlanung
|
||||
|
||||
where ProdTag between @start_date and @end_date
|
||||
and p.IdArtikelvarianten in ([articles])
|
||||
--and V_ProdLosProduktionJeProdTag_PLANNING.IdKunde = 10
|
||||
--and IdProdPlanung = 18442
|
||||
|
||||
order by ProdTag desc
|
||||
DECLARE @start_date date = '[startDate]'; --'2025-01-01'
|
||||
DECLARE @end_date date = '[endDate]'; --'2025-08-09'
|
||||
DECLARE @tz sysname = 'Eastern Standard Time'; -- usday1; use 'Central Standard Time' for usksc1
|
||||
DECLARE @shiftSeconds int = 7*3600; -- 07:00 production-day anchor
|
||||
--TODO: add in the proper time zone based on the env, get correcr shift time as well
|
||||
;WITH src AS (
|
||||
SELECT
|
||||
pl.RunningNumber, pl.ArticleHumanReadableId, pl.ArticleAlias, pl.ArticleDescription,
|
||||
pl.MachineLocation, pl.MachineDescription, pl.ProductionLotState, pl.ProductionInterrupt,
|
||||
pl.PlanQuantityPieces, pl.PlanQuantityLoadingUnit,
|
||||
CAST(pl.ProdStart AT TIME ZONE @tz AS datetime2(0)) AS StartLocal,
|
||||
CAST(pl.PlanEnd AT TIME ZONE @tz AS datetime2(0)) AS EndLocal
|
||||
FROM productionScheduling.ProductionLot AS pl
|
||||
WHERE pl.PlanEnd > pl.ProdStart
|
||||
and pl.publishState = 1
|
||||
and pl.ArticleHumanReadableId IN ([articles]) -- <-- article filter (was IdArtikelvarianten)
|
||||
--AND pl.RunningNumber = 28094 -- <-- lot filter (was IdProdPlanung); comment out for all
|
||||
),
|
||||
calc AS (
|
||||
SELECT *,
|
||||
DATEADD(SECOND, @shiftSeconds,
|
||||
CAST(CASE WHEN DATEDIFF(SECOND, CAST(StartLocal AS date), StartLocal) >= @shiftSeconds
|
||||
THEN CAST(StartLocal AS date)
|
||||
ELSE DATEADD(DAY,-1, CAST(StartLocal AS date)) END AS datetime2(0))) AS FirstBoundary
|
||||
FROM src
|
||||
),
|
||||
days AS ( -- one row per production day the lot touches
|
||||
SELECT RunningNumber, ArticleHumanReadableId, ArticleAlias, ArticleDescription, MachineLocation,
|
||||
MachineDescription, ProductionLotState, PlanQuantityPieces, PlanQuantityLoadingUnit,
|
||||
StartLocal, EndLocal, FirstBoundary AS DayStart
|
||||
FROM calc
|
||||
UNION ALL
|
||||
SELECT RunningNumber, ArticleHumanReadableId, ArticleAlias, ArticleDescription, MachineLocation,
|
||||
MachineDescription, ProductionLotState, PlanQuantityPieces, PlanQuantityLoadingUnit,
|
||||
StartLocal, EndLocal, DATEADD(DAY,1,DayStart)
|
||||
FROM days
|
||||
WHERE DATEADD(DAY,1,DayStart) < EndLocal
|
||||
),
|
||||
seg AS ( -- working seconds inside each production day
|
||||
SELECT *,
|
||||
DATEDIFF(SECOND,
|
||||
CASE WHEN StartLocal > DayStart THEN StartLocal ELSE DayStart END,
|
||||
CASE WHEN EndLocal < DATEADD(DAY,1,DayStart) THEN EndLocal ELSE DATEADD(DAY,1,DayStart) END
|
||||
) AS SegSec
|
||||
FROM days
|
||||
),
|
||||
cum AS ( -- cumulative seconds for telescoping round
|
||||
SELECT *,
|
||||
SUM(SegSec) OVER (PARTITION BY RunningNumber ORDER BY DayStart ROWS UNBOUNDED PRECEDING) AS CumEnd,
|
||||
SUM(SegSec) OVER (PARTITION BY RunningNumber ORDER BY DayStart ROWS UNBOUNDED PRECEDING) - SegSec AS CumStart,
|
||||
SUM(SegSec) OVER (PARTITION BY RunningNumber) AS DenomSec
|
||||
FROM seg
|
||||
)
|
||||
SELECT
|
||||
ArticleHumanReadableId AS Article,
|
||||
ArticleAlias AS Description,
|
||||
MachineLocation AS MachineId,
|
||||
MachineDescription AS MachineName,
|
||||
RunningNumber AS LotNumber,
|
||||
FORMAT(DayStart, 'MM/dd/yyyy') AS ProductionDay,
|
||||
PlanQuantityPieces AS TotalPlanned,
|
||||
ROUND(PlanQuantityPieces * 1.0 * CumEnd / DenomSec, 0)
|
||||
- ROUND(PlanQuantityPieces * 1.0 * CumStart / DenomSec, 0) AS QTYPerDay,
|
||||
ROUND(PlanQuantityLoadingUnit * CumEnd / DenomSec, 2)
|
||||
- ROUND(PlanQuantityLoadingUnit * CumStart / DenomSec, 2) AS PalDay,
|
||||
ProductionLotState AS finished
|
||||
FROM cum
|
||||
WHERE CAST(DayStart AS date) BETWEEN @start_date AND @end_date -- filter AFTER cumulative calc
|
||||
ORDER BY RunningNumber, DayStart DESC
|
||||
OPTION (MAXRECURSION 366);
|
||||
|
||||
@@ -19,13 +19,13 @@ import { setupUtilsRoutes } from "./utils/utils.routes.js";
|
||||
|
||||
export const setupRoutes = (baseUrl: string, app: Express) => {
|
||||
//routes that are on by default
|
||||
setupDatamartRoutes(baseUrl, app);
|
||||
setupMobileRoutes(baseUrl, app);
|
||||
setupSystemRoutes(baseUrl, app);
|
||||
setupAdminRoutes(baseUrl, app);
|
||||
setupApiDocsRoutes(baseUrl, app);
|
||||
setupProdSqlRoutes(baseUrl, app);
|
||||
setupGPSqlRoutes(baseUrl, app);
|
||||
setupDatamartRoutes(baseUrl, app);
|
||||
setupAuthRoutes(baseUrl, app);
|
||||
setupUtilsRoutes(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,10 +1,14 @@
|
||||
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { LaptopMinimal } from "lucide-react";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarHeader,
|
||||
SidebarFooter,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { useSession } from "@/lib/auth-client";
|
||||
import { getSettings } from "../../lib/queries/getSettings";
|
||||
@@ -23,6 +27,7 @@ export function AppSidebar() {
|
||||
openDock: ["read"],
|
||||
}),
|
||||
);
|
||||
const { setOpen } = useSidebar();
|
||||
|
||||
// const { data: canReadWarehouse = false } = useQuery(
|
||||
// permissionQuery({
|
||||
@@ -36,7 +41,7 @@ export function AppSidebar() {
|
||||
collapsible="offcanvas"
|
||||
className="top-(--header-height) h-[calc(100svh-var(--header-height))]!"
|
||||
>
|
||||
<SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarContent>
|
||||
@@ -64,7 +69,24 @@ export function AppSidebar() {
|
||||
</SidebarContent>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
</SidebarContent>
|
||||
{session &&
|
||||
(session.user.role === "admin" ||
|
||||
session.user.role === "systemAdmin" ||
|
||||
session.user.role === "manager") && (
|
||||
<SidebarFooter>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton asChild>
|
||||
<Link to={"/apidocs"} onClick={() => setOpen(false)}>
|
||||
<LaptopMinimal />
|
||||
<span>Api docs</span>
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarFooter>
|
||||
)}
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as ForbiddenRouteImport } from './routes/forbidden'
|
||||
import { Route as AppDownRouteImport } from './routes/app-down'
|
||||
import { Route as ApidocsRouteImport } from './routes/apidocs'
|
||||
import { Route as AboutRouteImport } from './routes/about'
|
||||
import { Route as IndexRouteImport } from './routes/index'
|
||||
import { Route as DocsIndexRouteImport } from './routes/docs/index'
|
||||
import { Route as DocsDatamartRouteImport } from './routes/docs/datamart'
|
||||
import { Route as DocsSplatRouteImport } from './routes/docs/$'
|
||||
import { Route as AdminUsersRouteImport } from './routes/admin/users'
|
||||
import { Route as AdminSettingsRouteImport } from './routes/admin/settings'
|
||||
@@ -41,6 +43,11 @@ const AppDownRoute = AppDownRouteImport.update({
|
||||
path: '/app-down',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const ApidocsRoute = ApidocsRouteImport.update({
|
||||
id: '/apidocs',
|
||||
path: '/apidocs',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const AboutRoute = AboutRouteImport.update({
|
||||
id: '/about',
|
||||
path: '/about',
|
||||
@@ -56,6 +63,11 @@ const DocsIndexRoute = DocsIndexRouteImport.update({
|
||||
path: '/docs/',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const DocsDatamartRoute = DocsDatamartRouteImport.update({
|
||||
id: '/docs/datamart',
|
||||
path: '/docs/datamart',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const DocsSplatRoute = DocsSplatRouteImport.update({
|
||||
id: '/docs/$',
|
||||
path: '/docs/$',
|
||||
@@ -145,6 +157,7 @@ const WarehouseDockdoorscanningScansDockScansRoute =
|
||||
export interface FileRoutesByFullPath {
|
||||
'/': typeof IndexRoute
|
||||
'/about': typeof AboutRoute
|
||||
'/apidocs': typeof ApidocsRoute
|
||||
'/app-down': typeof AppDownRoute
|
||||
'/forbidden': typeof ForbiddenRoute
|
||||
'/login': typeof authLoginRoute
|
||||
@@ -155,6 +168,7 @@ export interface FileRoutesByFullPath {
|
||||
'/admin/settings': typeof AdminSettingsRoute
|
||||
'/admin/users': typeof AdminUsersRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
'/docs/datamart': typeof DocsDatamartRoute
|
||||
'/docs/': typeof DocsIndexRoute
|
||||
'/user/profile': typeof authUserProfileRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
@@ -168,6 +182,7 @@ export interface FileRoutesByFullPath {
|
||||
export interface FileRoutesByTo {
|
||||
'/': typeof IndexRoute
|
||||
'/about': typeof AboutRoute
|
||||
'/apidocs': typeof ApidocsRoute
|
||||
'/app-down': typeof AppDownRoute
|
||||
'/forbidden': typeof ForbiddenRoute
|
||||
'/login': typeof authLoginRoute
|
||||
@@ -178,6 +193,7 @@ export interface FileRoutesByTo {
|
||||
'/admin/settings': typeof AdminSettingsRoute
|
||||
'/admin/users': typeof AdminUsersRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
'/docs/datamart': typeof DocsDatamartRoute
|
||||
'/docs': typeof DocsIndexRoute
|
||||
'/user/profile': typeof authUserProfileRoute
|
||||
'/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
@@ -192,6 +208,7 @@ export interface FileRoutesById {
|
||||
__root__: typeof rootRouteImport
|
||||
'/': typeof IndexRoute
|
||||
'/about': typeof AboutRoute
|
||||
'/apidocs': typeof ApidocsRoute
|
||||
'/app-down': typeof AppDownRoute
|
||||
'/forbidden': typeof ForbiddenRoute
|
||||
'/(auth)/login': typeof authLoginRoute
|
||||
@@ -202,6 +219,7 @@ export interface FileRoutesById {
|
||||
'/admin/settings': typeof AdminSettingsRoute
|
||||
'/admin/users': typeof AdminUsersRoute
|
||||
'/docs/$': typeof DocsSplatRoute
|
||||
'/docs/datamart': typeof DocsDatamartRoute
|
||||
'/docs/': typeof DocsIndexRoute
|
||||
'/(auth)/user/profile': typeof authUserProfileRoute
|
||||
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
|
||||
@@ -217,6 +235,7 @@ export interface FileRouteTypes {
|
||||
fullPaths:
|
||||
| '/'
|
||||
| '/about'
|
||||
| '/apidocs'
|
||||
| '/app-down'
|
||||
| '/forbidden'
|
||||
| '/login'
|
||||
@@ -227,6 +246,7 @@ export interface FileRouteTypes {
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
| '/docs/$'
|
||||
| '/docs/datamart'
|
||||
| '/docs/'
|
||||
| '/user/profile'
|
||||
| '/user/resetpassword'
|
||||
@@ -240,6 +260,7 @@ export interface FileRouteTypes {
|
||||
to:
|
||||
| '/'
|
||||
| '/about'
|
||||
| '/apidocs'
|
||||
| '/app-down'
|
||||
| '/forbidden'
|
||||
| '/login'
|
||||
@@ -250,6 +271,7 @@ export interface FileRouteTypes {
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
| '/docs/$'
|
||||
| '/docs/datamart'
|
||||
| '/docs'
|
||||
| '/user/profile'
|
||||
| '/user/resetpassword'
|
||||
@@ -263,6 +285,7 @@ export interface FileRouteTypes {
|
||||
| '__root__'
|
||||
| '/'
|
||||
| '/about'
|
||||
| '/apidocs'
|
||||
| '/app-down'
|
||||
| '/forbidden'
|
||||
| '/(auth)/login'
|
||||
@@ -273,6 +296,7 @@ export interface FileRouteTypes {
|
||||
| '/admin/settings'
|
||||
| '/admin/users'
|
||||
| '/docs/$'
|
||||
| '/docs/datamart'
|
||||
| '/docs/'
|
||||
| '/(auth)/user/profile'
|
||||
| '/(auth)/user/resetpassword'
|
||||
@@ -287,6 +311,7 @@ export interface FileRouteTypes {
|
||||
export interface RootRouteChildren {
|
||||
IndexRoute: typeof IndexRoute
|
||||
AboutRoute: typeof AboutRoute
|
||||
ApidocsRoute: typeof ApidocsRoute
|
||||
AppDownRoute: typeof AppDownRoute
|
||||
ForbiddenRoute: typeof ForbiddenRoute
|
||||
authLoginRoute: typeof authLoginRoute
|
||||
@@ -297,6 +322,7 @@ export interface RootRouteChildren {
|
||||
AdminSettingsRoute: typeof AdminSettingsRoute
|
||||
AdminUsersRoute: typeof AdminUsersRoute
|
||||
DocsSplatRoute: typeof DocsSplatRoute
|
||||
DocsDatamartRoute: typeof DocsDatamartRoute
|
||||
DocsIndexRoute: typeof DocsIndexRoute
|
||||
authUserProfileRoute: typeof authUserProfileRoute
|
||||
authUserResetpasswordRoute: typeof authUserResetpasswordRoute
|
||||
@@ -324,6 +350,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AppDownRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/apidocs': {
|
||||
id: '/apidocs'
|
||||
path: '/apidocs'
|
||||
fullPath: '/apidocs'
|
||||
preLoaderRoute: typeof ApidocsRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/about': {
|
||||
id: '/about'
|
||||
path: '/about'
|
||||
@@ -345,6 +378,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof DocsIndexRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/docs/datamart': {
|
||||
id: '/docs/datamart'
|
||||
path: '/docs/datamart'
|
||||
fullPath: '/docs/datamart'
|
||||
preLoaderRoute: typeof DocsDatamartRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/docs/$': {
|
||||
id: '/docs/$'
|
||||
path: '/docs/$'
|
||||
@@ -463,6 +503,7 @@ declare module '@tanstack/react-router' {
|
||||
const rootRouteChildren: RootRouteChildren = {
|
||||
IndexRoute: IndexRoute,
|
||||
AboutRoute: AboutRoute,
|
||||
ApidocsRoute: ApidocsRoute,
|
||||
AppDownRoute: AppDownRoute,
|
||||
ForbiddenRoute: ForbiddenRoute,
|
||||
authLoginRoute: authLoginRoute,
|
||||
@@ -473,6 +514,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
AdminSettingsRoute: AdminSettingsRoute,
|
||||
AdminUsersRoute: AdminUsersRoute,
|
||||
DocsSplatRoute: DocsSplatRoute,
|
||||
DocsDatamartRoute: DocsDatamartRoute,
|
||||
DocsIndexRoute: DocsIndexRoute,
|
||||
authUserProfileRoute: authUserProfileRoute,
|
||||
authUserResetpasswordRoute: authUserResetpasswordRoute,
|
||||
|
||||
@@ -19,8 +19,10 @@ const RootLayout = () => {
|
||||
<div className="relative min-h-[calc(100svh-var(--header-height))]">
|
||||
<AppSidebar />
|
||||
|
||||
<main className="w-full p-4">
|
||||
<div className="mx-auto w-full max-w-7xl">
|
||||
<main className="w-full">
|
||||
<div className="mx-auto w-full flex justify-center">
|
||||
{" "}
|
||||
{/* className="mx-auto w-full max-w-7xl" use this for dashboards and stuff*/}
|
||||
<Outlet />
|
||||
</div>
|
||||
</main>
|
||||
@@ -31,7 +33,7 @@ const RootLayout = () => {
|
||||
</SidebarProvider>
|
||||
</ThemeProvider>
|
||||
{session && session.user.role === "systemAdmin" && (
|
||||
<TanStackRouterDevtools />
|
||||
<TanStackRouterDevtools position="bottom-right" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -248,7 +248,7 @@ function RouteComponent() {
|
||||
};
|
||||
//console.log(logs);
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col gap-1 max-w-7xl">
|
||||
<div className="flex gap-1 justify-end">
|
||||
<Button onClick={triggerBuild}>Trigger Build</Button>
|
||||
<Button onClick={() => clearRoom()}>Clear Logs</Button>
|
||||
|
||||
15
frontend/src/routes/apidocs.tsx
Normal file
15
frontend/src/routes/apidocs.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/apidocs")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return (
|
||||
<iframe
|
||||
src="/lst/api/docs"
|
||||
className="h-[calc(100vh-64px)] w-full border-0"
|
||||
title="LST API Docs"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import { Trash } from "lucide-react";
|
||||
import { Suspense, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "../../../components/ui/button";
|
||||
import { Spinner } from "../../../components/ui/spinner";
|
||||
import { api } from "../../../lib/apiHelper";
|
||||
import { authClient } from "../../../lib/auth-client";
|
||||
import { getArticleLinks } from "../../../lib/queries/getArticleLinks";
|
||||
import LstTable from "../../../lib/tableStuff/LstTable";
|
||||
import SearchableHeader from "../../../lib/tableStuff/SearchableHeader";
|
||||
import SkellyTable from "../../../lib/tableStuff/SkellyTable";
|
||||
import NewArticleLink from "./-components/NewArticleLink";
|
||||
import { api } from "../../../lib/apiHelper";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "../../../components/ui/button";
|
||||
import { Spinner } from "../../../components/ui/spinner";
|
||||
import { Trash } from "lucide-react";
|
||||
|
||||
export const Route = createFileRoute("/transportation/opendock/")({
|
||||
beforeLoad: async ({ location }) => {
|
||||
@@ -97,77 +97,77 @@ const ArticleLinkTable = () => {
|
||||
cell: (i) => i.getValue(),
|
||||
}),
|
||||
columnHelper.accessor("deleteUser", {
|
||||
header: ({ column }) => (
|
||||
<SearchableHeader
|
||||
column={column}
|
||||
title="Delete Link"
|
||||
searchable={false}
|
||||
/>
|
||||
),
|
||||
filterFn: "includesString",
|
||||
cell: (i) => {
|
||||
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
|
||||
const [activeToggle, setActiveToggle] = useState(false);
|
||||
|
||||
const onTrigger = async () => {
|
||||
setActiveToggle(true);
|
||||
|
||||
try {
|
||||
const res = await api.delete(
|
||||
`/opendock/articleCheck/${i.row.original.id}`,
|
||||
|
||||
{
|
||||
withCredentials: true,
|
||||
timeout: 5000,
|
||||
validateStatus: () => true,
|
||||
},
|
||||
);
|
||||
|
||||
if (res.data.success) {
|
||||
toast.success(`AV: ${i.row.original.av} was deleted.`);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
|
||||
if (!res.data.success) {
|
||||
toast.error(
|
||||
`AV: ${i.row.original.av} encountered an error when trying to delete: ${res.data.message}`,
|
||||
);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setActiveToggle(false);
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="destructive"
|
||||
disabled={activeToggle}
|
||||
onClick={onTrigger}
|
||||
>
|
||||
{activeToggle ? (
|
||||
<span>
|
||||
<Spinner />
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
<Trash />
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
header: ({ column }) => (
|
||||
<SearchableHeader
|
||||
column={column}
|
||||
title="Delete Link"
|
||||
searchable={false}
|
||||
/>
|
||||
),
|
||||
filterFn: "includesString",
|
||||
cell: (i) => {
|
||||
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
|
||||
const [activeToggle, setActiveToggle] = useState(false);
|
||||
|
||||
const onTrigger = async () => {
|
||||
setActiveToggle(true);
|
||||
|
||||
try {
|
||||
const res = await api.delete(
|
||||
`/opendock/articleCheck/${i.row.original.id}`,
|
||||
|
||||
{
|
||||
withCredentials: true,
|
||||
timeout: 5000,
|
||||
validateStatus: () => true,
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
|
||||
if (res.data.success) {
|
||||
toast.success(`AV: ${i.row.original.av} was deleted.`);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
|
||||
if (!res.data.success) {
|
||||
toast.error(
|
||||
`AV: ${i.row.original.av} encountered an error when trying to delete: ${res.data.message}`,
|
||||
);
|
||||
refetch();
|
||||
setActiveToggle(false);
|
||||
}
|
||||
} catch (error) {
|
||||
setActiveToggle(false);
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="destructive"
|
||||
disabled={activeToggle}
|
||||
onClick={onTrigger}
|
||||
>
|
||||
{activeToggle ? (
|
||||
<span>
|
||||
<Spinner />
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
<Trash />
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
}),
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<div className="">
|
||||
<div>
|
||||
<div className="flex justify-end m-2">
|
||||
<Suspense
|
||||
|
||||
90
package-lock.json
generated
90
package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.57.0",
|
||||
"@scalar/express-api-reference": "^0.9.4",
|
||||
"@scalar/express-api-reference": "^0.9.20",
|
||||
"@socket.io/admin-ui": "^0.5.1",
|
||||
"archiver": "^7.0.1",
|
||||
"axios": "^1.13.6",
|
||||
@@ -44,7 +44,8 @@
|
||||
"socket.io": "^4.8.3",
|
||||
"socket.io-client": "^4.8.3",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^4.3.6"
|
||||
"zod": "^4.3.6",
|
||||
"zod-openapi": "^6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.4.8",
|
||||
@@ -2424,46 +2425,61 @@
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@scalar/core": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/core/-/core-0.4.4.tgz",
|
||||
"integrity": "sha512-eXIG0opyQn45FzpTp0dAWFP1Vjcx+helgUAsa0uN36tyUR7DSmz2kRwHqqedzvPWryeRCKPz7/vwzKpETZp5lg==",
|
||||
"node_modules/@scalar/client-side-rendering": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/client-side-rendering/-/client-side-rendering-0.1.13.tgz",
|
||||
"integrity": "sha512-p8V4HgEWjaCpqsnhclg1pTfjE9JA0AWRr0ocBQHexoHo+pqnSs1d83Mv9rjH7R0FZJrlCSandZZeY3DMX2gYXQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/types": "0.7.4"
|
||||
"@scalar/schemas": "0.3.3",
|
||||
"@scalar/types": "0.12.3",
|
||||
"@scalar/validation": "0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/express-api-reference": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/express-api-reference/-/express-api-reference-0.9.4.tgz",
|
||||
"integrity": "sha512-KXG+VaMArCGcWhzDV2rfkHd+UF1HYevIFbO6cqFpd+az7QHvVT99BU8Yh60T1dmtCp504s0Pl/vcTyJ91fK1Ug==",
|
||||
"version": "0.9.20",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/express-api-reference/-/express-api-reference-0.9.20.tgz",
|
||||
"integrity": "sha512-J0P6qpYoL0kXvs/A/vuAwCqQFCYnErbXSB5/3lEGTbARuK0oGyMvl55dQyW5Ucq3CX1npuRejlTX6bxEprSvJA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/core": "0.4.4"
|
||||
"@scalar/client-side-rendering": "0.1.13"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/helpers": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.4.2.tgz",
|
||||
"integrity": "sha512-IrgrGVSahCfYDNWITazz4Q1BOndp5eEzlimRkfxiYn++KqeWyLfALyym1omqcdKGYtiSx1KIbKaUJL9vkjaN7w==",
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.8.1.tgz",
|
||||
"integrity": "sha512-yuiuBCadP5bjAnIv23QvifVN/NaMi9xBF6b8Wdk4QOzwzLPJmp699MAdf33J0A5i2qKcvnu32iz/VkEJmQRe5g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/types": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.7.4.tgz",
|
||||
"integrity": "sha512-1o9uf42lZ9YD0XP/HMWrwXN0unx6vFTTgtduA1F28Yloea9Pfv9N2R/t0wO91iSIzw4+NubEFolunbdb2QcgHA==",
|
||||
"node_modules/@scalar/schemas": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/schemas/-/schemas-0.3.3.tgz",
|
||||
"integrity": "sha512-qDcgFu6ta5Z90L9D2P6DFKzYesU+FW5+m55SGmdI4iRMRCwj5umHpec2Y2W/SJcCF6bbUZawMxuOH2Ja6rUNpQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/helpers": "0.4.2",
|
||||
"@scalar/helpers": "0.8.1",
|
||||
"@scalar/validation": "0.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/types": {
|
||||
"version": "0.12.3",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.12.3.tgz",
|
||||
"integrity": "sha512-7zaXafbgTFmsJ/9AwYeExUWzXoZNyKOL0SEVAUWRaOndcjxpFCtwzuPrc1elMEWdHopWbY1Qe5pWKbE2aqG2HA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@scalar/helpers": "0.8.1",
|
||||
"nanoid": "^5.1.6",
|
||||
"type-fest": "^5.3.1",
|
||||
"zod": "^4.3.5"
|
||||
@@ -2472,6 +2488,15 @@
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@scalar/validation": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@scalar/validation/-/validation-0.6.0.tgz",
|
||||
"integrity": "sha512-tpmmG+/xRE2Kn9RpflU3AIyZv08v10+E1ZrJCx7z6+/91zHVxy0M73kC1LT4/8PbYNt85ywyC8+n+D99JdMcGA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@serialport/binding-mock": {
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@serialport/binding-mock/-/binding-mock-10.2.2.tgz",
|
||||
@@ -10566,9 +10591,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "5.1.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.7.tgz",
|
||||
"integrity": "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==",
|
||||
"version": "5.1.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz",
|
||||
"integrity": "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -13252,9 +13277,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.5.0.tgz",
|
||||
"integrity": "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==",
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz",
|
||||
"integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"dependencies": {
|
||||
"tagged-tag": "^1.0.0"
|
||||
@@ -13937,6 +13962,21 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/zod-openapi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/zod-openapi/-/zod-openapi-6.0.0.tgz",
|
||||
"integrity": "sha512-mS4eRJ4DGCPrg6elRbJqc/3nLe4EPVi8KiHRKZ7dcTR5m5orPy8EfoWmceAyGZAq71MAWuyrTTOag7W5N61ZPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22.14.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/samchungy/zod-openapi?sponsor=1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.57.0",
|
||||
"@scalar/express-api-reference": "^0.9.4",
|
||||
"@scalar/express-api-reference": "^0.9.20",
|
||||
"@socket.io/admin-ui": "^0.5.1",
|
||||
"archiver": "^7.0.1",
|
||||
"axios": "^1.13.6",
|
||||
@@ -102,7 +102,8 @@
|
||||
"socket.io": "^4.8.3",
|
||||
"socket.io-client": "^4.8.3",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^4.3.6"
|
||||
"zod": "^4.3.6",
|
||||
"zod-openapi": "^6.0.0"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
|
||||
@@ -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