Compare commits
37 Commits
8fb06c71d3
...
e597968777
| Author | SHA1 | Date | |
|---|---|---|---|
| e597968777 | |||
| bbd7a17144 | |||
| 5945ace9f2 | |||
| 316b27e3e0 | |||
| 7165c959b9 | |||
| ae7e3fd54e | |||
| 7ec5c5beb0 | |||
| c9aa41ab00 | |||
| 4696835c65 | |||
| 2d3f308877 | |||
| 3d083986ae | |||
| 92b47f03d9 | |||
| 3b8f18093e | |||
| 1cd1d3a3e9 | |||
| 8324fffeb6 | |||
| 354f3260a5 | |||
| ab5af4deac | |||
| 7a15b160ac | |||
| ca0ba7fe59 | |||
| 0914b53341 | |||
| 34b80cf236 | |||
| 196ea00972 | |||
| 807a4ca699 | |||
| d98a659262 | |||
| 6dd5f4b61f | |||
| 751b9d5701 | |||
| b0634d9427 | |||
| 8a143fbb19 | |||
| 8b72a1b47e | |||
| f4c44fb02b | |||
| 03aa7e5aee | |||
| f035e6f14a | |||
| 227e2aa00c | |||
| 4a48dd2bb5 | |||
| 9796947db5 | |||
| 1e02d4fa4f | |||
| 26ea8d5e89 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -148,3 +148,4 @@ dist
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
backend-0.1.3.zip
|
||||
|
||||
2
database/migrations/0023_wealthy_marvel_boy.sql
Normal file
2
database/migrations/0023_wealthy_marvel_boy.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "logs" ADD COLUMN "checked" boolean DEFAULT false;--> statement-breakpoint
|
||||
ALTER TABLE "logs" ADD COLUMN "checkedAt" timestamp;
|
||||
9
database/migrations/0024_curved_venom.sql
Normal file
9
database/migrations/0024_curved_venom.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE "manualPrinting" (
|
||||
"print_id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"line" integer,
|
||||
"printReason" text NOT NULL,
|
||||
"initials" text NOT NULL,
|
||||
"additionalComments" text NOT NULL,
|
||||
"add_date" timestamp DEFAULT now(),
|
||||
"add_user" text
|
||||
);
|
||||
1087
database/migrations/meta/0023_snapshot.json
Normal file
1087
database/migrations/meta/0023_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1144
database/migrations/meta/0024_snapshot.json
Normal file
1144
database/migrations/meta/0024_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -162,6 +162,20 @@
|
||||
"when": 1742156466912,
|
||||
"tag": "0022_amused_true_believers",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 23,
|
||||
"version": "7",
|
||||
"when": 1742346003832,
|
||||
"tag": "0023_wealthy_marvel_boy",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 24,
|
||||
"version": "7",
|
||||
"when": 1742408812383,
|
||||
"tag": "0024_curved_venom",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,6 +10,8 @@ export const logs = pgTable(
|
||||
username: text("username").default("LST_Serivce"),
|
||||
service: text("service").notNull().default("system"),
|
||||
message: text("message").notNull(),
|
||||
checked: boolean("checked").default(false),
|
||||
checkedAt: timestamp("checkedAt"),
|
||||
created_at: timestamp("add_Date").defaultNow(),
|
||||
},
|
||||
(table) => [
|
||||
|
||||
20
database/schema/ocpManualPrint.ts
Normal file
20
database/schema/ocpManualPrint.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {text, pgTable, timestamp, uuid, integer} from "drizzle-orm/pg-core";
|
||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
||||
import {z} from "zod";
|
||||
|
||||
export const manualPrinting = pgTable("manualPrinting", {
|
||||
print_id: uuid("print_id").defaultRandom().primaryKey(),
|
||||
line: integer("line"),
|
||||
printReason: text("printReason").notNull(),
|
||||
initials: text("initials").notNull(),
|
||||
additionalComments: text("additionalComments").notNull(),
|
||||
add_date: timestamp("add_date").defaultNow(),
|
||||
add_user: text("add_user"),
|
||||
});
|
||||
|
||||
// Schema for inserting a user - can be used to validate API requests
|
||||
// export const insertRolesSchema = createInsertSchema(roles, {
|
||||
// name: z.string().min(3, {message: "Role name must be more than 3 letters"}),
|
||||
// });
|
||||
// Schema for selecting a Expenses - can be used to validate API responses
|
||||
export const selectRolesSchema = createSelectSchema(manualPrinting);
|
||||
50
frontend/package-lock.json
generated
50
frontend/package-lock.json
generated
@@ -16,6 +16,7 @@
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
@@ -1152,6 +1153,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/number": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz",
|
||||
"integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
|
||||
@@ -1722,6 +1729,49 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.6.tgz",
|
||||
"integrity": "sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/number": "1.1.0",
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-collection": "1.1.2",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-direction": "1.1.0",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.5",
|
||||
"@radix-ui/react-focus-guards": "1.1.1",
|
||||
"@radix-ui/react-focus-scope": "1.1.2",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-popper": "1.2.2",
|
||||
"@radix-ui/react-portal": "1.1.4",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-slot": "1.1.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0",
|
||||
"@radix-ui/react-use-previous": "1.1.0",
|
||||
"@radix-ui/react-visually-hidden": "1.1.2",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-separator": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.2.tgz",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
|
||||
@@ -9,6 +9,7 @@ import {useQuery} from "@tanstack/react-query";
|
||||
import {useRouter} from "@tanstack/react-router";
|
||||
import {format} from "date-fns";
|
||||
import UpdateServer from "./UpdateServer";
|
||||
import {adminUrlCheck} from "@/utils/adminUrlCheck";
|
||||
|
||||
export type Servers = {
|
||||
server_id?: string;
|
||||
@@ -85,9 +86,7 @@ export default function ServerPage() {
|
||||
{format(server.lastUpdated, "MM/dd/yyyy hh:mm")}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
{window.location.host.split(":")[0] === "localhost" && (
|
||||
<UpdateServer server={server} token={token as string} />
|
||||
)}
|
||||
{adminUrlCheck() && <UpdateServer server={server} token={token as string} />}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function SettingsPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<LstCard className="m-2 flex place-content-center w-dvh">
|
||||
<LstCard className="m-2 flex place-content-center w-fit">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
|
||||
@@ -61,8 +61,10 @@ const LoginForm = () => {
|
||||
|
||||
// Store token in localStorage
|
||||
// localStorage.setItem("auth_token", data.data.token);
|
||||
const prod = btoa(`${value.username.toLowerCase()}:${value.password}`);
|
||||
const prodUser = {...data.user, prod: prod};
|
||||
|
||||
setSession(data.user, data.token);
|
||||
setSession(prodUser, data.token);
|
||||
toast.success(`You are logged in as ${data.user.username}`);
|
||||
router.navigate({to: "/"});
|
||||
} catch (err) {
|
||||
|
||||
@@ -15,7 +15,7 @@ const items = [
|
||||
title: "One Click Print",
|
||||
url: "/ocp",
|
||||
icon: Printer,
|
||||
role: ["systemAdmin"],
|
||||
role: ["viwer"],
|
||||
module: "ocp",
|
||||
active: true,
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Button} from "@/components/ui/button";
|
||||
import {CardHeader} from "@/components/ui/card";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Label} from "@/components/ui/label";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
import axios from "axios";
|
||||
import {useState} from "react";
|
||||
|
||||
@@ -12,7 +13,7 @@ import {toast} from "sonner";
|
||||
export default function ConsumeMaterial() {
|
||||
const {register: register1, handleSubmit: handleSubmit1, reset} = useForm();
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const token = localStorage.getItem("auth_token");
|
||||
const {token} = useSessionStore();
|
||||
|
||||
const handleConsume = async (data: any) => {
|
||||
setSubmitting(!submitting);
|
||||
|
||||
@@ -1,5 +1,92 @@
|
||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||
import {CardHeader} from "@/components/ui/card";
|
||||
import {Skeleton} from "@/components/ui/skeleton";
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||
// import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
// import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {getlabels} from "@/utils/querys/production/labels";
|
||||
import {format} from "date-fns";
|
||||
|
||||
const labelLogs = [
|
||||
{key: "line", label: "Line"},
|
||||
{key: "printerName", label: "Printer"},
|
||||
{key: "runningNr", label: "Running #"},
|
||||
{key: "upd_date", label: "Label date"},
|
||||
{key: "status", label: "Label Status"},
|
||||
//{key: "reprint", label: "Reprint"}, // removing the reprint button for now until repritning is working as intended
|
||||
];
|
||||
export default function LabelLog() {
|
||||
return <LstCard className="m-2 p-2"> label logs here</LstCard>;
|
||||
const {data, isError, error, isLoading} = useQuery(getlabels("4"));
|
||||
//const {user} = useSessionStore();
|
||||
//const {settings} = useSettingStore();
|
||||
//const server = settings.filter((n) => n.name === "server")[0]?.value || "";
|
||||
|
||||
//const roles = ["admin", "manager", "operator"];
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div>
|
||||
<LstCard>
|
||||
<CardHeader>There was an error loading the lots</CardHeader>
|
||||
{JSON.stringify(error)}
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LstCard className="m-2 p-2 min-h-2/5">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{labelLogs.map((l) => (
|
||||
<TableHead key={l.key}>{l.label}</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<TableBody>
|
||||
{Array(7)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<TableRow key={i}>
|
||||
<TableCell className="font-medium">
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</>
|
||||
) : (
|
||||
<TableBody>
|
||||
{data?.map((label: any) => (
|
||||
<TableRow key={label.runningNr}>
|
||||
<TableCell className="font-medium">{label.line}</TableCell>
|
||||
<TableCell className="font-medium">{label.printerName}</TableCell>
|
||||
<TableCell className="font-medium">{label.runningNr}</TableCell>
|
||||
<TableCell className="font-medium">
|
||||
{format(label.upd_date, "M/d/yyyy hh:mm")}
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">{label.status}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</LstCard>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,177 @@
|
||||
import {LstCard} from "@/components/extendedUI/LstCard";
|
||||
import {CardHeader} from "@/components/ui/card";
|
||||
import {Skeleton} from "@/components/ui/skeleton";
|
||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@/components/ui/table";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {LotType} from "@/types/lots";
|
||||
import {getlots} from "@/utils/querys/production/lots";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import ManualPrint from "./ManualPrinting/ManualPrint";
|
||||
import ManualPrintForm from "./ManualPrinting/ManualPrintForm";
|
||||
|
||||
let lotColumns = [
|
||||
{
|
||||
key: "MachineDescription",
|
||||
label: "Machine",
|
||||
},
|
||||
{
|
||||
key: "AV",
|
||||
label: "AV",
|
||||
},
|
||||
{
|
||||
key: "Alias",
|
||||
label: "AvDescription",
|
||||
},
|
||||
{
|
||||
key: "LOT",
|
||||
label: "LotNumber",
|
||||
},
|
||||
{
|
||||
key: "ProlinkLot",
|
||||
label: "ProlinkLot",
|
||||
},
|
||||
{
|
||||
key: "PlannedQTY",
|
||||
label: "PlannedQTY",
|
||||
},
|
||||
{
|
||||
key: "Produced",
|
||||
label: "Produced",
|
||||
},
|
||||
{
|
||||
key: "Remaining",
|
||||
label: "Remaining",
|
||||
},
|
||||
{
|
||||
key: "overPrinting",
|
||||
label: "Overprinting",
|
||||
},
|
||||
// {
|
||||
// key: "lastProlinkUpdate",
|
||||
// label: "Last ProlinkCheck",
|
||||
// },
|
||||
// {
|
||||
// key: "printLabel",
|
||||
// label: "Print Label",
|
||||
// },
|
||||
];
|
||||
export default function Lots() {
|
||||
const {data, isError, error, isLoading} = useQuery(getlots());
|
||||
const {user} = useSessionStore();
|
||||
const {settings} = useSettingStore();
|
||||
const server = settings.filter((n) => n.name === "server")[0]?.value || "";
|
||||
|
||||
console.log(server);
|
||||
|
||||
const roles = ["admin", "manager", "operator"];
|
||||
|
||||
if (user && roles.includes(user.role)) {
|
||||
//width = 1280;
|
||||
const checkCol = lotColumns.some((l) => l.key === "printLabel");
|
||||
if (!checkCol) {
|
||||
lotColumns = [
|
||||
...lotColumns,
|
||||
{
|
||||
key: "printLabel",
|
||||
label: "Print Label",
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div>
|
||||
<LstCard>
|
||||
<CardHeader>There was an error loading the lots</CardHeader>
|
||||
{JSON.stringify(error)}
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LstCard className="m-2 p-2 min-h-2/5">
|
||||
<h1>Lots</h1>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{lotColumns.map((l) => (
|
||||
<TableHead key={l.key}>{l.label}</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<TableBody>
|
||||
{Array(10)
|
||||
.fill(0)
|
||||
.map((_, i) => (
|
||||
<TableRow key={i}>
|
||||
<TableCell className="font-medium">
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="h-4" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</>
|
||||
) : (
|
||||
<TableBody>
|
||||
{data?.map((lot: LotType) => (
|
||||
<TableRow key={lot.LabelOnlineID}>
|
||||
<TableCell className="font-medium">{lot.MachineLocation}</TableCell>
|
||||
<TableCell className="font-medium">{lot.AV}</TableCell>
|
||||
<TableCell className="font-medium">{lot.Alias}</TableCell>
|
||||
<TableCell className="font-medium">{lot.LOT}</TableCell>
|
||||
<TableCell className="font-medium">{lot.ProlinkLot}</TableCell>
|
||||
<TableCell className="font-medium">{lot.PlannedQTY}</TableCell>
|
||||
<TableCell className="font-medium">{lot.Produced}</TableCell>
|
||||
<TableCell className="font-medium">{lot.Remaining}</TableCell>
|
||||
<TableCell className="font-medium">{lot.overPrinting}</TableCell>
|
||||
{user && roles.includes(user.role) && (
|
||||
<>
|
||||
{server === "usday1vms006" || server === "localhost" ? (
|
||||
<>
|
||||
<TableCell className="flex justify-center">
|
||||
<ManualPrintForm lot={lot} />
|
||||
</TableCell>
|
||||
</>
|
||||
) : (
|
||||
<TableCell className="flex justify-center">
|
||||
<ManualPrint lot={lot} />
|
||||
</TableCell>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</LstCard>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
//import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {LotType} from "@/types/lots";
|
||||
import {Tag} from "lucide-react";
|
||||
import {toast} from "sonner";
|
||||
import {manualPrintLabels} from "./ManualPrintLabel";
|
||||
|
||||
export default function ManualPrint({lot}: {lot: LotType}) {
|
||||
const {user} = useSessionStore();
|
||||
//const {settings} = useSettingStore();
|
||||
//const server = settings.filter((n) => n.name === "server")[0]?.value;
|
||||
//const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
|
||||
//const serverUrl = `http://${server}:${serverPort}`;
|
||||
|
||||
const handlePrintLabel = async (lot: LotType) => {
|
||||
//console.log(lot);
|
||||
|
||||
const labels: any = await manualPrintLabels(lot, user);
|
||||
|
||||
if (labels.success) {
|
||||
toast.success(labels.message);
|
||||
} else {
|
||||
toast.error(labels.message);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Button variant="outline" size="icon" onClick={() => handlePrintLabel(lot)}>
|
||||
<Tag className="h-[16px] w-[16px]" />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
import {Button} from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import {Input} from "@/components/ui/input";
|
||||
import {Label} from "@/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {Textarea} from "@/components/ui/textarea";
|
||||
import {useSessionStore} from "@/lib/store/sessionStore";
|
||||
import {useSettingStore} from "@/lib/store/useSettings";
|
||||
import {LotType} from "@/types/lots";
|
||||
import axios from "axios";
|
||||
import {Tag} from "lucide-react";
|
||||
import {useState} from "react";
|
||||
import {Controller, useForm} from "react-hook-form";
|
||||
import {toast} from "sonner";
|
||||
import {manualPrintLabels} from "./ManualPrintLabel";
|
||||
|
||||
const printReason = [
|
||||
{key: "printerIssue", label: "Printer Related"},
|
||||
{key: "strapper", label: "Strapper Error"},
|
||||
{key: "manualCheck", label: "20th pallet check"},
|
||||
{key: "outOfSync", label: "Labeler Out of Sync"},
|
||||
];
|
||||
|
||||
export default function ManualPrintForm({lot}: {lot: LotType}) {
|
||||
const {user} = useSessionStore();
|
||||
const token = localStorage.getItem("auth_token");
|
||||
const {settings} = useSettingStore();
|
||||
const [open, setOpen] = useState(false);
|
||||
const server = settings.filter((n) => n.name === "server")[0]?.value;
|
||||
// const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
|
||||
// const serverUrl = `http://${server}:${serverPort}`;
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
//watch,
|
||||
formState: {errors},
|
||||
reset,
|
||||
control,
|
||||
} = useForm();
|
||||
|
||||
const handlePrintLabel = async (lot: LotType) => {
|
||||
//console.log(lot);
|
||||
const labels: any = await manualPrintLabels(lot, user);
|
||||
|
||||
if (labels.success) {
|
||||
toast.success(labels.message);
|
||||
} else {
|
||||
toast.error(labels.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleManualPrintLog = async (logData: any, lot: LotType) => {
|
||||
// toast.success(`A new label was sent to printer: ${lot.PrinterName} for line ${lot.MachineDescription} `);
|
||||
const logdataUrl = `/api/ocp/manualLabelLog`;
|
||||
axios
|
||||
.post(logdataUrl, logData, {headers: {Authorization: `Bearer ${token}`}})
|
||||
.then((d) => {
|
||||
//console.log(d);
|
||||
toast.success(d.data.message);
|
||||
handlePrintLabel(lot);
|
||||
reset();
|
||||
})
|
||||
.catch((e) => {
|
||||
if (e.response.status === 500) {
|
||||
toast.error(`Internal Server error please try again.`);
|
||||
return {sucess: false};
|
||||
}
|
||||
|
||||
if (e.response.status === 401) {
|
||||
//console.log(e.response);
|
||||
toast.error(`You are not authorized to do this.`);
|
||||
return {sucess: false};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
console.log(data);
|
||||
|
||||
handleManualPrintLog(data, lot);
|
||||
};
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onOpenChange={(isOpen) => {
|
||||
if (!open) {
|
||||
reset();
|
||||
}
|
||||
setOpen(isOpen);
|
||||
// toast.message("Model was something", {
|
||||
// description: isOpen ? "Modal is open" : "Modal is closed",
|
||||
// });
|
||||
}}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<Tag className="h-[16px] w-[16px]" />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit profile</DialogTitle>
|
||||
<DialogDescription>
|
||||
Make changes to your profile here. Click save when you're done.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<p>
|
||||
To manually print a label you must complete all the required fields below.
|
||||
<br />
|
||||
If you clicked this in error just click close
|
||||
</p>
|
||||
<hr className="mt-2 mb-2" />
|
||||
{server == "usday1vms006" ? (
|
||||
<Controller
|
||||
control={control}
|
||||
name="printReason"
|
||||
defaultValue={""}
|
||||
render={({
|
||||
field: {onChange},
|
||||
fieldState: {},
|
||||
//formState,
|
||||
}) => (
|
||||
<Select onValueChange={onChange}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Select Reason" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Print Reasons</SelectLabel>
|
||||
{printReason.map((printReason: any) => (
|
||||
<SelectItem value={printReason.key}>{printReason.label}</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<div>
|
||||
<Label htmlFor="printRason" className="m-1">
|
||||
Why are you manually printing?
|
||||
</Label>
|
||||
<Input
|
||||
type="text"
|
||||
className={errors.printReason ? "border-red-500" : ""}
|
||||
aria-invalid={!!errors.printReason}
|
||||
{...register("printReason", {
|
||||
required: true,
|
||||
minLength: {
|
||||
value: 5,
|
||||
message: "To short of a reason please try again!",
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Label htmlFor="line" className="m-1">
|
||||
"What is the line number you are printing?"
|
||||
</Label>
|
||||
<Input
|
||||
//variant="underlined"
|
||||
type="number"
|
||||
className={errors.line ? "border-red-500" : ""}
|
||||
aria-invalid={!!errors.line}
|
||||
{...register("line", {required: true})}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="initials" className="m-1">
|
||||
Enter intials
|
||||
</Label>
|
||||
<Input
|
||||
//variant="underlined"
|
||||
//label="Enter intials"
|
||||
|
||||
{...register("initials", {required: true})}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
//label="Comments"
|
||||
placeholder="add more info as needed."
|
||||
{...register("additionalComments")}
|
||||
/>
|
||||
|
||||
<DialogFooter>
|
||||
<Button color="danger" variant="default" onClick={() => setOpen(!open)}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" type="submit">
|
||||
Print
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import {LotType} from "@/types/lots";
|
||||
import axios from "axios";
|
||||
|
||||
export const manualPrintLabels = async (lot: LotType, user: any) => {
|
||||
//console.log(lot);
|
||||
const labelUrl = `/ocp/manualPrintAndFollow`;
|
||||
|
||||
try {
|
||||
const res = await axios.post(
|
||||
labelUrl,
|
||||
{line: lot.MachineLocation, printerName: lot.PrinterName},
|
||||
{headers: {Authorization: `Basic ${user?.prod}`}}
|
||||
);
|
||||
|
||||
if (res.data.success) {
|
||||
return {
|
||||
success: true,
|
||||
message: `A new label was printed for ${lot.MachineDescription} to printer: ${lot.PrinterName}`,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: true,
|
||||
message: `Line ${lot.MachineDescription} encountered an error printing labels: ${res.data.message}`,
|
||||
};
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.response.status === 500) {
|
||||
//toast.error(`Internal Server error please try again.`);
|
||||
return {
|
||||
success: false,
|
||||
message: `Internal Server error please try again.`,
|
||||
};
|
||||
}
|
||||
|
||||
if (error.response.status === 401) {
|
||||
//console.log(e.response);
|
||||
//toast.error(`You are not authorized to do this.`);
|
||||
return {
|
||||
success: false,
|
||||
message: `You are not authorized to do this.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,16 +1,19 @@
|
||||
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
|
||||
import {useModuleStore} from "../../lib/store/useModuleStore";
|
||||
import {useEffect} from "react";
|
||||
import {useSettingStore} from "@/lib/store/useSettings";
|
||||
//import {useGetUserRoles} from "@/lib/store/useGetRoles";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export const SessionProvider = ({children}: {children: React.ReactNode}) => {
|
||||
const {fetchModules} = useModuleStore();
|
||||
const {fetchSettings} = useSettingStore();
|
||||
//const {fetchUserRoles} = useGetUserRoles();
|
||||
|
||||
useEffect(() => {
|
||||
fetchModules();
|
||||
fetchSettings();
|
||||
//fetchUserRoles();
|
||||
}, []);
|
||||
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
||||
|
||||
183
frontend/src/components/ui/select.tsx
Normal file
183
frontend/src/components/ui/select.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import * as React from "react"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Select({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot="select" {...props} />
|
||||
}
|
||||
|
||||
function SelectGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
||||
}
|
||||
|
||||
function SelectValue({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
||||
}
|
||||
|
||||
function SelectTrigger({
|
||||
className,
|
||||
size = "default",
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: "sm" | "default"
|
||||
}) {
|
||||
return (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = "popper",
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
data-slot="select-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLabel({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||
return (
|
||||
<SelectPrimitive.Label
|
||||
data-slot="select-label"
|
||||
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||
return (
|
||||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||
return (
|
||||
<SelectPrimitive.Separator
|
||||
data-slot="select-separator"
|
||||
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollUpButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
data-slot="select-scroll-up-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUpIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollDownButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
data-slot="select-scroll-down-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
}
|
||||
18
frontend/src/components/ui/textarea.tsx
Normal file
18
frontend/src/components/ui/textarea.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import * as React from "react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
||||
return (
|
||||
<textarea
|
||||
data-slot="textarea"
|
||||
className={cn(
|
||||
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Textarea }
|
||||
@@ -1,4 +1,5 @@
|
||||
import {User} from "@/types/users";
|
||||
import axios from "axios";
|
||||
import {create} from "zustand";
|
||||
|
||||
export type SessionState = {
|
||||
@@ -16,9 +17,14 @@ export const useSessionStore = create<SessionState>((set) => {
|
||||
user: null, // User is NOT stored in localStorage
|
||||
token: storedToken || null,
|
||||
|
||||
setSession: (user, token) => {
|
||||
setSession: async (user: any, token) => {
|
||||
if (token) {
|
||||
localStorage.setItem("auth_token", token);
|
||||
const response = await axios.get("/api/auth/getuseraccess", {
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
});
|
||||
const data = response.data; //await response.json();
|
||||
user = {...user, roles: data.data};
|
||||
} else {
|
||||
localStorage.removeItem("auth_token");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {create} from "zustand";
|
||||
import {useSessionStore} from "./sessionStore";
|
||||
import {Modules} from "@/types/modules";
|
||||
import axios from "axios";
|
||||
|
||||
interface SettingState {
|
||||
userRoles: Modules[];
|
||||
@@ -19,15 +20,8 @@ export const useGetUserRoles = create<SettingState>()((set) => ({
|
||||
try {
|
||||
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||
const {token} = useSessionStore();
|
||||
const response = await fetch(`/api/auth/getuseraccess`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authentication: `Beaer ${token}`,
|
||||
// You can add other headers here if necessary
|
||||
},
|
||||
});
|
||||
const data: FetchModulesResponse = await response.json();
|
||||
const response = await axios.get("/api/auth/getuseraccess", {headers: {Authorization: `Bearer ${token}`}});
|
||||
const data: FetchModulesResponse = response.data; //await response.json();
|
||||
//console.log(data);
|
||||
set({userRoles: data.data});
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {Modules} from "@/types/modules";
|
||||
import axios from "axios";
|
||||
import {create} from "zustand";
|
||||
|
||||
interface SettingState {
|
||||
@@ -17,14 +18,8 @@ export const useModuleStore = create<SettingState>()((set) => ({
|
||||
fetchModules: async () => {
|
||||
try {
|
||||
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||
const response = await fetch(`/api/server/modules`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
// You can add other headers here if necessary
|
||||
},
|
||||
});
|
||||
const data: FetchModulesResponse = await response.json();
|
||||
const response = await axios.get(`/api/server/modules`, {});
|
||||
const data: FetchModulesResponse = response.data; //await response.json();
|
||||
//console.log(data);
|
||||
set({modules: data.data});
|
||||
} catch (error) {
|
||||
|
||||
29
frontend/src/lib/store/useSettings.ts
Normal file
29
frontend/src/lib/store/useSettings.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import axios from "axios";
|
||||
import {create} from "zustand";
|
||||
|
||||
interface SettingState {
|
||||
settings: any[];
|
||||
|
||||
fetchSettings: () => Promise<void>;
|
||||
setSettings: (settings: any[]) => void;
|
||||
}
|
||||
interface FetchModulesResponse {
|
||||
data: any[];
|
||||
}
|
||||
|
||||
export const useSettingStore = create<SettingState>()((set) => ({
|
||||
settings: [],
|
||||
setSettings: (settings) => set({settings}),
|
||||
fetchSettings: async () => {
|
||||
try {
|
||||
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||
const response = await axios.get(`/api/server/settings`, {});
|
||||
const data: FetchModulesResponse = response.data; //await response.json();
|
||||
//console.log(data);
|
||||
set({settings: data.data});
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch settings:", error);
|
||||
set({settings: []});
|
||||
}
|
||||
},
|
||||
}));
|
||||
@@ -18,7 +18,6 @@ import { Route as AuthImport } from './routes/_auth'
|
||||
import { Route as AdminImport } from './routes/_admin'
|
||||
import { Route as IndexImport } from './routes/index'
|
||||
import { Route as OcpIndexImport } from './routes/ocp/index'
|
||||
import { Route as OcpLotsImport } from './routes/ocp/lots'
|
||||
import { Route as EomEomImport } from './routes/_eom/eom'
|
||||
import { Route as AuthProfileImport } from './routes/_auth/profile'
|
||||
import { Route as AdminSettingsImport } from './routes/_admin/settings'
|
||||
@@ -70,12 +69,6 @@ const OcpIndexRoute = OcpIndexImport.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const OcpLotsRoute = OcpLotsImport.update({
|
||||
id: '/ocp/lots',
|
||||
path: '/ocp/lots',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const EomEomRoute = EomEomImport.update({
|
||||
id: '/eom',
|
||||
path: '/eom',
|
||||
@@ -214,13 +207,6 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof EomEomImport
|
||||
parentRoute: typeof EomImport
|
||||
}
|
||||
'/ocp/lots': {
|
||||
id: '/ocp/lots'
|
||||
path: '/ocp/lots'
|
||||
fullPath: '/ocp/lots'
|
||||
preLoaderRoute: typeof OcpLotsImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/ocp/': {
|
||||
id: '/ocp/'
|
||||
path: '/ocp'
|
||||
@@ -307,7 +293,6 @@ export interface FileRoutesByFullPath {
|
||||
'/settings': typeof AdminSettingsRoute
|
||||
'/profile': typeof AuthProfileRoute
|
||||
'/eom': typeof EomEomRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||
@@ -325,7 +310,6 @@ export interface FileRoutesByTo {
|
||||
'/settings': typeof AdminSettingsRoute
|
||||
'/profile': typeof AuthProfileRoute
|
||||
'/eom': typeof EomEomRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||
@@ -346,7 +330,6 @@ export interface FileRoutesById {
|
||||
'/_admin/settings': typeof AdminSettingsRoute
|
||||
'/_auth/profile': typeof AuthProfileRoute
|
||||
'/_eom/eom': typeof EomEomRoute
|
||||
'/ocp/lots': typeof OcpLotsRoute
|
||||
'/ocp/': typeof OcpIndexRoute
|
||||
'/_eom/article/$av': typeof EomArticleAvRoute
|
||||
'/(logistics)/materialHelper/': typeof logisticsMaterialHelperIndexRoute
|
||||
@@ -366,7 +349,6 @@ export interface FileRouteTypes {
|
||||
| '/settings'
|
||||
| '/profile'
|
||||
| '/eom'
|
||||
| '/ocp/lots'
|
||||
| '/ocp'
|
||||
| '/article/$av'
|
||||
| '/materialHelper'
|
||||
@@ -383,7 +365,6 @@ export interface FileRouteTypes {
|
||||
| '/settings'
|
||||
| '/profile'
|
||||
| '/eom'
|
||||
| '/ocp/lots'
|
||||
| '/ocp'
|
||||
| '/article/$av'
|
||||
| '/materialHelper'
|
||||
@@ -402,7 +383,6 @@ export interface FileRouteTypes {
|
||||
| '/_admin/settings'
|
||||
| '/_auth/profile'
|
||||
| '/_eom/eom'
|
||||
| '/ocp/lots'
|
||||
| '/ocp/'
|
||||
| '/_eom/article/$av'
|
||||
| '/(logistics)/materialHelper/'
|
||||
@@ -418,7 +398,6 @@ export interface RootRouteChildren {
|
||||
EomRoute: typeof EomRouteWithChildren
|
||||
AboutRoute: typeof AboutRoute
|
||||
LoginRoute: typeof LoginRoute
|
||||
OcpLotsRoute: typeof OcpLotsRoute
|
||||
OcpIndexRoute: typeof OcpIndexRoute
|
||||
logisticsMaterialHelperIndexRoute: typeof logisticsMaterialHelperIndexRoute
|
||||
logisticsMaterialHelperConsumptionIndexRoute: typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||
@@ -432,7 +411,6 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
EomRoute: EomRouteWithChildren,
|
||||
AboutRoute: AboutRoute,
|
||||
LoginRoute: LoginRoute,
|
||||
OcpLotsRoute: OcpLotsRoute,
|
||||
OcpIndexRoute: OcpIndexRoute,
|
||||
logisticsMaterialHelperIndexRoute: logisticsMaterialHelperIndexRoute,
|
||||
logisticsMaterialHelperConsumptionIndexRoute:
|
||||
@@ -457,7 +435,6 @@ export const routeTree = rootRoute
|
||||
"/_eom",
|
||||
"/about",
|
||||
"/login",
|
||||
"/ocp/lots",
|
||||
"/ocp/",
|
||||
"/(logistics)/materialHelper/",
|
||||
"/(logistics)/materialHelper/consumption/",
|
||||
@@ -514,9 +491,6 @@ export const routeTree = rootRoute
|
||||
"filePath": "_eom/eom.tsx",
|
||||
"parent": "/_eom"
|
||||
},
|
||||
"/ocp/lots": {
|
||||
"filePath": "ocp/lots.tsx"
|
||||
},
|
||||
"/ocp/": {
|
||||
"filePath": "ocp/index.tsx"
|
||||
},
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/ocp/lots')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/ocp/lots"!</div>
|
||||
}
|
||||
19
frontend/src/types/lots.ts
Normal file
19
frontend/src/types/lots.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export type LotType = {
|
||||
AV: number;
|
||||
Alias: string;
|
||||
LOT: number;
|
||||
LabelOnlineID: number;
|
||||
MachineDescription: string;
|
||||
MachineID: number;
|
||||
MachineLocation: number;
|
||||
PlannedQTY: number;
|
||||
PrinterName: string;
|
||||
Produced: number;
|
||||
ProlinkLot: number;
|
||||
Remaining: number;
|
||||
machineID: number;
|
||||
overPrinting: string;
|
||||
pallerCopies: number;
|
||||
palletLabel: string;
|
||||
printerID: number;
|
||||
};
|
||||
@@ -6,4 +6,5 @@ export type User = {
|
||||
username: string;
|
||||
roles: Roles[];
|
||||
role: string;
|
||||
prod?: string;
|
||||
};
|
||||
|
||||
8
frontend/src/utils/adminUrlCheck.ts
Normal file
8
frontend/src/utils/adminUrlCheck.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const adminUrlCheck = () => {
|
||||
const host = window.location.host.split(":")[0];
|
||||
const okHost = ["localhost", "usmcd1vms036"];
|
||||
if (okHost.includes(host)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
20
frontend/src/utils/querys/production/labels.tsx
Normal file
20
frontend/src/utils/querys/production/labels.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import {queryOptions} from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getlabels(hours: string) {
|
||||
return queryOptions({
|
||||
queryKey: ["labels"],
|
||||
queryFn: () => fetchSettings(hours),
|
||||
|
||||
staleTime: 1000,
|
||||
refetchInterval: 2500,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetchSettings = async (hours: string) => {
|
||||
const {data} = await axios.get(`/api/v1/ocp/labels?hours=${hours}`);
|
||||
// if we are not localhost ignore the devDir setting.
|
||||
//const url: string = window.location.host.split(":")[0];
|
||||
return data.data;
|
||||
};
|
||||
21
frontend/src/utils/querys/production/lots.tsx
Normal file
21
frontend/src/utils/querys/production/lots.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import {queryOptions} from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
export function getlots() {
|
||||
return queryOptions({
|
||||
queryKey: ["lots"],
|
||||
queryFn: () => fetchSettings(),
|
||||
|
||||
staleTime: 10 * 1000,
|
||||
refetchInterval: 10 * 1000,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
}
|
||||
|
||||
const fetchSettings = async () => {
|
||||
const {data} = await axios.get("/api/v1/ocp/lots");
|
||||
// if we are not localhost ignore the devDir setting.
|
||||
//const url: string = window.location.host.split(":")[0];
|
||||
let lotData = data.data;
|
||||
return lotData;
|
||||
};
|
||||
@@ -73,7 +73,7 @@
|
||||
}
|
||||
},
|
||||
"admConfig": {
|
||||
"build": 26,
|
||||
"oldBuild": "backend-0.1.2.zip"
|
||||
"build": 43,
|
||||
"oldBuild": "backend-0.1.3.zip"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||
import {serve} from "@hono/node-server";
|
||||
import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {proxy} from "hono/proxy";
|
||||
import {serveStatic} from "@hono/node-server/serve-static";
|
||||
import {logger} from "hono/logger";
|
||||
import {cors} from "hono/cors";
|
||||
import {createLog} from "./services/logger/logger.js";
|
||||
import {closePool} from "./services/sqlServer/prodSqlServer.js";
|
||||
|
||||
// custom routes
|
||||
import scalar from "./services/general/route/scalar.js";
|
||||
@@ -17,7 +17,8 @@ import sqlService from "./services/sqlServer/sqlService.js";
|
||||
import logistics from "./services/logistics/logisticsService.js";
|
||||
import rfid from "./services/rfid/rfidService.js";
|
||||
import printers from "./services/printers/printerService.js";
|
||||
|
||||
import loggerService from "./services/logger/loggerService.js";
|
||||
import ocpService from "./services/ocp/ocpService.js";
|
||||
import {db} from "../database/dbclient.js";
|
||||
import {settings} from "../database/schema/settings.js";
|
||||
import {count, eq} from "drizzle-orm";
|
||||
@@ -32,32 +33,26 @@ const serverIntialized = await db.select({count: count()}).from(settings);
|
||||
export const installed = serverIntialized[0].count === 0 && process.env.NODE_ENV !== "development" ? false : true;
|
||||
createLog("info", "LST", "server", `Server is installed: ${installed}`);
|
||||
|
||||
const allowedOrigins = [
|
||||
"http://localhost:3000",
|
||||
"http://localhost:4000",
|
||||
"http://localhost:5173",
|
||||
`http://usmcd1vms006:4000`,
|
||||
];
|
||||
const app = new OpenAPIHono();
|
||||
const app = new OpenAPIHono({strict: false});
|
||||
|
||||
// middle ware
|
||||
app.use("*", logger());
|
||||
app.use(
|
||||
"*",
|
||||
cors({
|
||||
origin: allowedOrigins,
|
||||
allowHeaders: ["X-Custom-Header", "Upgrade-Insecure-Requests"],
|
||||
allowMethods: ["POST", "GET", "OPTIONS"],
|
||||
origin: "*", // Allow all origins
|
||||
allowHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
|
||||
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
|
||||
exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
|
||||
credentials: true, // Allow credentials if needed
|
||||
maxAge: 600,
|
||||
credentials: true,
|
||||
})
|
||||
);
|
||||
|
||||
// Middleware to normalize route case
|
||||
app.use("*", async (c, next) => {
|
||||
const lowercasedUrl = c.req.url.toLowerCase();
|
||||
|
||||
//console.log("Incoming Request:", c.req.url, c.req.method);
|
||||
// If the URL is already lowercase, continue as usual
|
||||
if (c.req.url === lowercasedUrl) {
|
||||
return next();
|
||||
@@ -85,22 +80,46 @@ const routes = [
|
||||
logistics,
|
||||
rfid,
|
||||
printers,
|
||||
loggerService,
|
||||
ocpService,
|
||||
] as const;
|
||||
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
app.route("/api/", route);
|
||||
});
|
||||
|
||||
app.route("/ocme/*", ocme);
|
||||
|
||||
//--------------- lst v1 proxy ----------------------\\
|
||||
app.all("/api/v1/*", (c) => {
|
||||
const path = c.req.path.replace("/api/v1/", ""); // Extract the subpath
|
||||
const query = c.req.query() ? "?" + new URLSearchParams(c.req.query()).toString() : ""; // Get query params
|
||||
return proxy(`http://localhost:4900/${path}${query}`, {
|
||||
headers: {
|
||||
...c.req.header(),
|
||||
"X-Forwarded-For": "127.0.0.1",
|
||||
"X-Forwarded-Host": c.req.header("host"),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
app.all("/system/*", (c) => {
|
||||
const path = c.req.path.replace("/system/", ""); // Extract the subpath
|
||||
const query = c.req.query() ? "?" + new URLSearchParams(c.req.query()).toString() : ""; // Get query params
|
||||
return proxy(`http://localhost:4200/${path}${query}`, {
|
||||
headers: {
|
||||
...c.req.header(),
|
||||
"X-Forwarded-For": "127.0.0.1",
|
||||
"X-Forwarded-Host": c.req.header("host"),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
//---------------------------------------------------\\
|
||||
|
||||
// the catch all api route
|
||||
app.all("/api/*", (c) => c.json({error: "API route not found"}, 404));
|
||||
|
||||
app.route("/ocme/", ocme);
|
||||
|
||||
// async (c) => {
|
||||
// //return ocmeService(c);
|
||||
// c.json({error: "Ocme route not found"}, 404);
|
||||
// });
|
||||
|
||||
// front end static files
|
||||
app.use("/*", serveStatic({root: "./frontend/dist"}));
|
||||
app.use("*", serveStatic({path: "./frontend/dist/index.html"}));
|
||||
|
||||
@@ -172,21 +172,28 @@ $plantFunness = {
|
||||
Write-Host "Removing services that are no longer used."
|
||||
& $nssmPath remove "LogisticsSupportTool" confirm
|
||||
& $nssmPath remove $serviceAuth confirm
|
||||
# & $nssmPath remove $serviceGateway confirm
|
||||
# if($token -eq "usday1"){
|
||||
# & $nssmPath remove $serviceOcme confirm
|
||||
# }
|
||||
Start-Sleep -Seconds 5
|
||||
|
||||
## adding in lstAdm
|
||||
Write-Host "Adding $($serviceLstV2)... incase its missing."
|
||||
$commandToRun = "run start"
|
||||
$description = "logistics Support Tool"
|
||||
& $nssmPath install $serviceLstV2 $npmPath $commandToRun
|
||||
Write-Host "Setting the app directory"
|
||||
& $nssmPath set $serviceLstV2 AppDirectory $appPath
|
||||
Write-Host "Setting the description"
|
||||
& $nssmPath set $serviceLstV2 Description $description
|
||||
Write-Host "Setting recovery options"
|
||||
# Set recovery options
|
||||
sc.exe failure $serviceLstV2 reset= 0 actions= restart/5000/restart/5000/restart/5000
|
||||
$service = Get-Service -Name $serviceLstV2 -ErrorAction SilentlyContinue
|
||||
|
||||
if(-not $service){
|
||||
## adding in lstAdm
|
||||
Write-Host "Adding $($serviceLstV2)... incase its missing."
|
||||
$commandToRun = "run start"
|
||||
$description = "logistics Support Tool"
|
||||
& $nssmPath install $serviceLstV2 $npmPath $commandToRun
|
||||
Write-Host "Setting the app directory"
|
||||
& $nssmPath set $serviceLstV2 AppDirectory $appPath
|
||||
Write-Host "Setting the description"
|
||||
& $nssmPath set $serviceLstV2 Description $description
|
||||
Write-Host "Setting recovery options"
|
||||
# Set recovery options
|
||||
sc.exe failure $serviceLstV2 reset= 0 actions= restart/5000/restart/5000/restart/5000
|
||||
}
|
||||
# Doing an install
|
||||
Write-Host "Running the install to make sure everything is updated."
|
||||
Set-Location $serverPath
|
||||
@@ -235,10 +242,9 @@ $plantFunness = {
|
||||
Start-Service -DisplayName $serviceLstV2
|
||||
Start-Sleep -Seconds 1
|
||||
Write-Host "$($server) finished updating"
|
||||
|
||||
if($token -eq "usday1"){
|
||||
Write-Host "Starting $($serviceOcme)"
|
||||
Start-Service -DisplayName $serviceOcme
|
||||
Start-Service -DisplayName $serviceOcme
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export async function login(
|
||||
user_id: user[0].user_id,
|
||||
username: user[0].username,
|
||||
email: user[0].email,
|
||||
roles: roles || null,
|
||||
//roles: roles || null,
|
||||
role: user[0].role || null, // this should be removed onces full migration to v2 is completed
|
||||
prod: btoa(`${username.toLowerCase()}:${password}`),
|
||||
};
|
||||
|
||||
22
server/services/logger/controller/clearLog.ts
Normal file
22
server/services/logger/controller/clearLog.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import {eq, sql} from "drizzle-orm";
|
||||
import {db} from "../../../../database/dbclient.js";
|
||||
import {logs} from "../../../../database/schema/logs.js";
|
||||
import {createLog} from "../logger.js";
|
||||
|
||||
export const clearLog = async (id: string) => {
|
||||
/**
|
||||
* mark the log as cleared
|
||||
*/
|
||||
|
||||
try {
|
||||
const clear = await db
|
||||
.update(logs)
|
||||
.set({checked: true, checkedAt: sql`NOW()`})
|
||||
.where(eq(logs.log_id, id));
|
||||
createLog("info", "lst", "logger", "Log just cleared.");
|
||||
return {success: true, message: "Log was just cleared."};
|
||||
} catch (error) {
|
||||
createLog("error", "lst", "logger", "There was an error clearing the log.");
|
||||
return {success: false, message: "There was an error clearing the log."};
|
||||
}
|
||||
};
|
||||
28
server/services/logger/controller/getLogs.ts
Normal file
28
server/services/logger/controller/getLogs.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import {and, eq, inArray, lte, sql} from "drizzle-orm";
|
||||
import {db} from "../../../../database/dbclient.js";
|
||||
import {logs} from "../../../../database/schema/logs.js";
|
||||
import {createLog} from "../logger.js";
|
||||
|
||||
export const getLogs = async (data: any) => {
|
||||
try {
|
||||
// clear all remaining logs ne to info.
|
||||
const checked = data.checked && data.checked[0] === "true" ? true : false || false;
|
||||
const logData = await db
|
||||
.select()
|
||||
.from(logs)
|
||||
.where(
|
||||
and(
|
||||
lte(logs.created_at, sql.raw(`NOW() - INTERVAL '${data.hours} hours'`)),
|
||||
inArray(logs.service, data.service),
|
||||
inArray(logs.level, data.level),
|
||||
eq(logs.checked, checked)
|
||||
)
|
||||
);
|
||||
|
||||
return {success: true, message: "logs returned", data: logData};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
createLog("error", "lst", "logger", `There was an error deleteing server logs. ${error}`);
|
||||
return {success: false, message: "An error occured while trying to get the logs", error};
|
||||
}
|
||||
};
|
||||
55
server/services/logger/controller/logCleanup.ts
Normal file
55
server/services/logger/controller/logCleanup.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import {and, eq, inArray, lte, ne, sql} from "drizzle-orm";
|
||||
import {db} from "../../../../database/dbclient.js";
|
||||
import {logs} from "../../../../database/schema/logs.js";
|
||||
import {createLog} from "../logger.js";
|
||||
|
||||
export const logCleanup = async () => {
|
||||
/**
|
||||
* We will run the clean logger where we have aged logs that do not need to be here flooding the db
|
||||
*/
|
||||
|
||||
// clear the server logs older than 3 days
|
||||
try {
|
||||
// clear info logs older than 3 days
|
||||
const delLogs = await db
|
||||
.delete(logs)
|
||||
.where(
|
||||
and(
|
||||
lte(logs.created_at, sql`NOW() - INTERVAL '3 days'`),
|
||||
inArray(logs.service, ["server", "tcp", "sqlProd", "globalutils"]),
|
||||
eq(logs.level, "30")
|
||||
)
|
||||
)
|
||||
.returning({name: logs.message});
|
||||
createLog(
|
||||
"info",
|
||||
"lst",
|
||||
"logger",
|
||||
`${delLogs.length} Server logs were just deleted that were older than 3 days`
|
||||
);
|
||||
} catch (error) {
|
||||
createLog("error", "lst", "logger", `There was an error deleteing server logs. ${error}`);
|
||||
}
|
||||
|
||||
try {
|
||||
// clear all remaining logs ne to info.
|
||||
const delLogs = await db
|
||||
.delete(logs)
|
||||
.where(
|
||||
and(
|
||||
lte(logs.created_at, sql`NOW() - INTERVAL '7 days'`),
|
||||
inArray(logs.service, ["server", "tcp", "sqlProd", "globalutils"]),
|
||||
ne(logs.level, "30")
|
||||
)
|
||||
)
|
||||
.returning({name: logs.message});
|
||||
createLog(
|
||||
"info",
|
||||
"lst",
|
||||
"logger",
|
||||
`${delLogs.length} Server logs were just deleted that were older than 7 days`
|
||||
);
|
||||
} catch (error) {
|
||||
createLog("error", "lst", "logger", `There was an error deleteing server logs. ${error}`);
|
||||
}
|
||||
};
|
||||
30
server/services/logger/loggerService.ts
Normal file
30
server/services/logger/loggerService.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
// routes
|
||||
import clearLog from "./routes/clearLog.js";
|
||||
import {db} from "../../../database/dbclient.js";
|
||||
import {settings} from "../../../database/schema/settings.js";
|
||||
import {logCleanup} from "./controller/logCleanup.js";
|
||||
import createNewLog from "./routes/createLog.js";
|
||||
import getLogs from "./routes/getLogs.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const routes = [clearLog, createNewLog, getLogs] as const;
|
||||
const setting = await db.select().from(settings);
|
||||
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
app.route("/logger", route);
|
||||
});
|
||||
|
||||
app.all("/logger/*", (c) => {
|
||||
return c.json({success: false, message: "You have encounters a log route that dose not exist."});
|
||||
});
|
||||
|
||||
// run the clean up job ones on server restart/crash/update and then once a date
|
||||
logCleanup();
|
||||
setInterval(async () => {
|
||||
logCleanup();
|
||||
}, 60 * 1000 * 60 * 24);
|
||||
|
||||
export default app;
|
||||
44
server/services/logger/routes/clearLog.ts
Normal file
44
server/services/logger/routes/clearLog.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
|
||||
import {apiHit} from "../../../globalUtils/apiHits.js";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import {clearLog} from "../controller/clearLog.js";
|
||||
|
||||
const app = new OpenAPIHono({strict: false});
|
||||
const ParamsSchema = z.object({
|
||||
id: z
|
||||
.string()
|
||||
.min(3)
|
||||
.openapi({
|
||||
param: {
|
||||
name: "id",
|
||||
in: "path",
|
||||
},
|
||||
example: "1212121",
|
||||
}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["server:logger"],
|
||||
summary: "Marks the select log id as cleared out.",
|
||||
method: "patch",
|
||||
path: "/logs/{id}",
|
||||
request: {
|
||||
params: ParamsSchema,
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const {id} = c.req.valid("param");
|
||||
//const body = await c.req.json();
|
||||
// make sure we have a vaid user being accessed thats really logged in
|
||||
apiHit(c, {endpoint: `api/logger/logs/id`});
|
||||
try {
|
||||
const clear = await clearLog(id);
|
||||
return c.json({success: clear.success, message: clear.message, data: []}, 200);
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: "There was an error clearing the log.", data: error}, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
export default app;
|
||||
38
server/services/logger/routes/createLog.ts
Normal file
38
server/services/logger/routes/createLog.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
// an external way to creating logs
|
||||
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
|
||||
import {apiHit} from "../../../globalUtils/apiHits.js";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import {createLog} from "../logger.js";
|
||||
|
||||
const app = new OpenAPIHono({strict: false});
|
||||
const CreateLog = z.object({
|
||||
level: z.string().openapi({example: "info"}),
|
||||
service: z.string().openapi({example: "server"}),
|
||||
message: z.string().openapi({example: "This is a new log posted"}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["server:logger"],
|
||||
summary: "Post a log to the db.",
|
||||
method: "post",
|
||||
path: "/logs",
|
||||
description: "This might be a temp soltuin during the transtion between versions",
|
||||
request: {
|
||||
body: {content: {"application/json": {schema: CreateLog}}},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
|
||||
apiHit(c, {endpoint: `api/logger/logs/id`});
|
||||
try {
|
||||
createLog(body.level, "logger", body.service, body.message);
|
||||
return c.json({success: true, message: "A new log was created.", data: []}, 200);
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: "There was an error clearing the log.", data: error}, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
export default app;
|
||||
39
server/services/logger/routes/getLogs.ts
Normal file
39
server/services/logger/routes/getLogs.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
// an external way to creating logs
|
||||
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
|
||||
import {apiHit} from "../../../globalUtils/apiHits.js";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import {createLog} from "../logger.js";
|
||||
import {getLogs} from "../controller/getLogs.js";
|
||||
|
||||
const app = new OpenAPIHono({strict: false});
|
||||
const CreateLog = z.object({
|
||||
level: z.string().openapi({example: "info"}),
|
||||
service: z.string().openapi({example: "server"}),
|
||||
message: z.string().openapi({example: "This is a new log posted"}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["server:logger"],
|
||||
summary: "Gets logs.",
|
||||
method: "get",
|
||||
path: "/logs",
|
||||
description: "This might be a temp soltuin during the transtion between versions",
|
||||
request: {
|
||||
body: {content: {"application/json": {schema: CreateLog}}},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const query = await c.req.queries();
|
||||
|
||||
apiHit(c, {endpoint: `api/logger/logs`});
|
||||
try {
|
||||
const logData = await getLogs(query);
|
||||
return c.json({success: logData?.success, message: logData?.message, data: logData?.data}, 200);
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: "There was an error clearing the log.", data: error}, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
export default app;
|
||||
@@ -6,12 +6,17 @@ import postRunningNr from "./route/postRunningNumber.js";
|
||||
import pickedup from "./route/pickedUp.js";
|
||||
import postsscc from "./route/postSSCC.js";
|
||||
import getShipments from "./route/getShipmentPallets.js";
|
||||
import {serve} from "@hono/node-server";
|
||||
import {createLog} from "../logger/logger.js";
|
||||
import {db} from "../../../database/dbclient.js";
|
||||
import {settings} from "../../../database/schema/settings.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const port = process.env.OCME_PORT;
|
||||
const routes = [getInfo, postRunningNr, postsscc, pickedup, getShipments] as const;
|
||||
const setting = await db.select().from(settings);
|
||||
|
||||
// app.route("/server", modules);
|
||||
const isActive = setting.filter((n) => n.name === "ocmeService");
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
app.route("/api/v1", route);
|
||||
});
|
||||
@@ -19,5 +24,17 @@ const appRoutes = routes.forEach((route) => {
|
||||
app.all("/api/v1/*", (c) => {
|
||||
return c.json({success: false, message: "you have encounted an ocme route that dose not exist."});
|
||||
});
|
||||
if (port && isActive[0]?.value === "1") {
|
||||
serve(
|
||||
{
|
||||
fetch: app.fetch,
|
||||
port: Number(port),
|
||||
hostname: "0.0.0.0",
|
||||
},
|
||||
(info) => {
|
||||
createLog("info", "LST", "server", `Ocme section is listening on http://${info.address}:${info.port}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default app;
|
||||
|
||||
@@ -2,7 +2,7 @@ import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
|
||||
import {getInfo} from "../controller/getInfo.js";
|
||||
import {apiHit} from "../../../globalUtils/apiHits.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
const app = new OpenAPIHono({strict: false});
|
||||
|
||||
const AddSetting = z.object({
|
||||
name: z.string().openapi({example: "server"}),
|
||||
|
||||
20
server/services/ocp/controller/manualLabelLog.ts
Normal file
20
server/services/ocp/controller/manualLabelLog.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {db} from "../../../../database/dbclient.js";
|
||||
import {manualPrinting} from "../../../../database/schema/ocpManualPrint.js";
|
||||
|
||||
export const manualPrint = async (data: any) => {
|
||||
/**
|
||||
* add the reason we did a manual print.
|
||||
*/
|
||||
|
||||
const manualPrintData = {
|
||||
line: data.line,
|
||||
printReason: data.printReason,
|
||||
initials: data.initials,
|
||||
additionalComments: data?.additionalComments,
|
||||
add_user: "lst",
|
||||
};
|
||||
|
||||
try {
|
||||
const manualPrint = await db.insert(manualPrinting).values(manualPrintData);
|
||||
} catch (error) {}
|
||||
};
|
||||
22
server/services/ocp/ocpService.ts
Normal file
22
server/services/ocp/ocpService.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
// routes
|
||||
import manualLabelLog from "./routes/manualPrintLog.js";
|
||||
|
||||
import {db} from "../../../database/dbclient.js";
|
||||
import {settings} from "../../../database/schema/settings.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const routes = [manualLabelLog] as const;
|
||||
const setting = await db.select().from(settings);
|
||||
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
app.route("/ocp", route);
|
||||
});
|
||||
|
||||
app.all("/ocp/*", (c) => {
|
||||
return c.json({success: false, message: "You have encounters a ocp route that dose not exist."});
|
||||
});
|
||||
|
||||
export default app;
|
||||
56
server/services/ocp/routes/manualPrintLog.ts
Normal file
56
server/services/ocp/routes/manualPrintLog.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
// an external way to creating logs
|
||||
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
|
||||
import {apiHit} from "../../../globalUtils/apiHits.js";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import type {User} from "../../../types/users.js";
|
||||
import {verify} from "hono/jwt";
|
||||
import {manualPrint} from "../controller/manualLabelLog.js";
|
||||
import {authMiddleware} from "../../auth/middleware/authMiddleware.js";
|
||||
|
||||
const app = new OpenAPIHono({strict: false});
|
||||
const CreateLog = z.object({
|
||||
line: z.string().openapi({example: "info"}),
|
||||
initials: z.string().openapi({example: "server"}),
|
||||
printReason: z.string().openapi({example: "This is a new log posted"}),
|
||||
additionalComments: z.string().optional().openapi({example: "Some reason why we did this."}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["ocp"],
|
||||
summary: "Post the log for manaulprinting.",
|
||||
method: "post",
|
||||
path: "/manuallabellog",
|
||||
//middleware: authMiddleware,
|
||||
//description: "This might be a temp soltuin during the transtion between versions",
|
||||
request: {
|
||||
body: {content: {"application/json": {schema: CreateLog}}},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
apiHit(c, {endpoint: `api/logger/logs/id`});
|
||||
// const authHeader = c.req.header("Authorization");
|
||||
|
||||
// const token = authHeader?.split("Bearer ")[1] || "";
|
||||
// let user: User;
|
||||
|
||||
// try {
|
||||
// const payload = await verify(token, process.env.JWT_SECRET!);
|
||||
// user = payload.user as User;
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// return c.json({message: "Unauthorized"}, 401);
|
||||
// }
|
||||
|
||||
try {
|
||||
//const data = {...body, add_user: user.username};
|
||||
await manualPrint(body);
|
||||
return c.json({success: true, message: "Manual Print was added.", data: []}, 200);
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: "There was an error clearing the log.", data: error}, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
export default app;
|
||||
52
server/services/ocp/routes/printLabel.ts
Normal file
52
server/services/ocp/routes/printLabel.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
// an external way to creating logs
|
||||
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
|
||||
import {apiHit} from "../../../globalUtils/apiHits.js";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
|
||||
const app = new OpenAPIHono({strict: false});
|
||||
const CreateLog = z.object({
|
||||
line: z.string().openapi({example: "info"}),
|
||||
initials: z.string().openapi({example: "server"}),
|
||||
printReason: z.string().openapi({example: "This is a new log posted"}),
|
||||
additionalComments: z.string().optional().openapi({example: "Some reason why we did this."}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["ocp"],
|
||||
summary: "Prints a label.",
|
||||
method: "post",
|
||||
path: "/printlabel",
|
||||
//middleware: authMiddleware,
|
||||
//description: "This might be a temp soltuin during the transtion between versions",
|
||||
request: {
|
||||
body: {content: {"application/json": {schema: CreateLog}}},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
apiHit(c, {endpoint: `api/logger/logs/id`});
|
||||
// const authHeader = c.req.header("Authorization");
|
||||
|
||||
// const token = authHeader?.split("Bearer ")[1] || "";
|
||||
// let user: User;
|
||||
|
||||
// try {
|
||||
// const payload = await verify(token, process.env.JWT_SECRET!);
|
||||
// user = payload.user as User;
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// return c.json({message: "Unauthorized"}, 401);
|
||||
// }
|
||||
|
||||
try {
|
||||
//const data = {...body, add_user: user.username};
|
||||
|
||||
return c.json({success: true, message: "Label was printed.", data: []}, 200);
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: "There was an error printing a label.", data: error}, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
export default app;
|
||||
@@ -4,6 +4,7 @@ import {addSetting} from "../../controller/settings/addSetting.js";
|
||||
import {verify} from "hono/jwt";
|
||||
import type {User} from "../../../../types/users.js";
|
||||
import {authMiddleware} from "../../../auth/middleware/authMiddleware.js";
|
||||
import {responses} from "../../../../globalUtils/routeDefs/responses.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
@@ -29,43 +30,7 @@ app.openapi(
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
success: z.boolean().openapi({example: true}),
|
||||
message: z.string().openapi({example: "Starter"}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Response message",
|
||||
},
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
401: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
|
||||
},
|
||||
},
|
||||
description: "Unauthorized",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
// make sure we have a vaid user being accessed thats really logged in
|
||||
|
||||
@@ -52,25 +52,6 @@ app.openapi(
|
||||
}),
|
||||
async (c) => {
|
||||
// make sure we have a vaid user being accessed thats really logged in
|
||||
const authHeader = c.req.header("Authorization");
|
||||
|
||||
if (authHeader?.includes("Basic")) {
|
||||
return c.json({message: "You are a Basic user! Please login to get a token"}, 401);
|
||||
}
|
||||
|
||||
if (!authHeader) {
|
||||
return c.json({message: "Unauthorized"}, 401);
|
||||
}
|
||||
|
||||
const token = authHeader?.split("Bearer ")[1] || "";
|
||||
let user: User;
|
||||
|
||||
try {
|
||||
const payload = await verify(token, process.env.JWT_SECRET!);
|
||||
user = payload.user as User;
|
||||
} catch (error) {
|
||||
return c.json({message: "Unauthorized"}, 401);
|
||||
}
|
||||
|
||||
// now pass all the data over to update the user info
|
||||
try {
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
"contactPhone": "6366970253",
|
||||
"customerTiAcc": "ALPL01DAYTONINT",
|
||||
"lstServerPort": "4000",
|
||||
"active": false,
|
||||
"active": true,
|
||||
"serverLoc": "E:\\LST\\lstv2",
|
||||
"oldVersion": "E:\\LST\\lst_backend",
|
||||
"shippingHours": "[{\"early\": \"06:30\", \"late\": \"23:00\"}]",
|
||||
|
||||
@@ -56,6 +56,12 @@ const newSettings = [
|
||||
description: "Dose the plant have 2 machines that go to 1?",
|
||||
moduleName: "ocp",
|
||||
},
|
||||
{
|
||||
name: "ocmeService",
|
||||
value: "0",
|
||||
description: "Is the ocme service enabled. this is gernerally only for Dayton.",
|
||||
moduleName: "ocme",
|
||||
},
|
||||
{
|
||||
name: "fifoCheck",
|
||||
value: "45",
|
||||
@@ -80,12 +86,40 @@ const newSettings = [
|
||||
description: "What address is monitored to be limited to the amount of lots that can be added to a truck.",
|
||||
moduleName: "ocme",
|
||||
},
|
||||
{
|
||||
name: "ocmeCycleCount",
|
||||
value: "1",
|
||||
description: "Are we allowing ocme cycle counts?",
|
||||
roles: "admin",
|
||||
module: "ocme",
|
||||
},
|
||||
{
|
||||
name: "devDir",
|
||||
value: "C:\\Users\\matthes01\\Documents\\lstv2",
|
||||
description: "This is the dev dir and strictly only for updating the servers.",
|
||||
moduleName: "server",
|
||||
},
|
||||
{
|
||||
name: "demandMGTActivated",
|
||||
value: "0",
|
||||
description: "Do we allow for new fake edi?",
|
||||
roles: "admin",
|
||||
module: "logistics",
|
||||
},
|
||||
{
|
||||
name: "qualityRequest",
|
||||
value: "0",
|
||||
description: "quality request module?",
|
||||
roles: "admin",
|
||||
module: "logistics",
|
||||
},
|
||||
{
|
||||
name: "ocpLogsCheck",
|
||||
value: "4",
|
||||
description: "How long do we want to allow logs to show that have not been cleared?",
|
||||
roles: "admin",
|
||||
module: "ocp",
|
||||
},
|
||||
];
|
||||
export const areSettingsIn = async () => {
|
||||
// get the roles
|
||||
|
||||
Reference in New Issue
Block a user