From beae6eb6486ca749632433dc46641e36068266d0 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Fri, 3 Apr 2026 09:51:52 -0500 Subject: [PATCH] lots of changes with docker --- .dockerignore | 5 +- .gitignore | 1 + Dockerfile | 10 +- backend/db/schema/printerLogs.schema.ts | 6 + .../notification/notificationSub.get.route.ts | 6 +- backend/ocp/ocp.printer.listener.ts | 36 + backend/ocp/ocp.printer.manage.ts | 19 + backend/ocp/ocp.routes.ts | 22 + backend/routeHandler.routes.ts | 2 + backend/system/settingsBase.controller.ts | 12 +- backend/utils/cors.utils.ts | 1 + backend/utils/returnHelper.utils.ts | 3 +- .../Subscribe to notification.bru | 2 +- brunoApi/ocp/Printer Listenter.bru | 22 + brunoApi/ocp/folder.bru | 8 + docker-compose.yml | 14 +- frontend/src/components/Sidebar/AdminBar.tsx | 18 +- frontend/src/components/ui/select.tsx | 190 +++ .../src/lib/formSutff/DynamicInput.Field.tsx | 87 ++ frontend/src/lib/formSutff/Select.Field.tsx | 57 + frontend/src/lib/formSutff/index.tsx | 5 +- frontend/src/lib/queries/notificationSubs.ts | 24 + frontend/src/lib/queries/notifications.ts | 22 + .../src/lib/tableStuff/SearchableHeader.tsx | 2 +- .../-components/NotificationsSubCard.tsx | 87 ++ frontend/src/routes/(auth)/user.profile.tsx | 23 + frontend/src/routes/__root.tsx | 2 +- .../routes/admin/-components/FeatureCard.tsx | 5 +- frontend/src/routes/index.tsx | 4 +- migrations/0019_large_thunderbird.sql | 4 + migrations/meta/0019_snapshot.json | 1327 +++++++++++++++++ migrations/meta/_journal.json | 7 + package-lock.json | 271 ++++ package.json | 5 +- scripts/agentController.ps1 | 5 + scripts/dockerscripts.md | 6 + 36 files changed, 2284 insertions(+), 36 deletions(-) create mode 100644 backend/db/schema/printerLogs.schema.ts create mode 100644 backend/ocp/ocp.printer.listener.ts create mode 100644 backend/ocp/ocp.printer.manage.ts create mode 100644 backend/ocp/ocp.routes.ts create mode 100644 brunoApi/ocp/Printer Listenter.bru create mode 100644 brunoApi/ocp/folder.bru create mode 100644 frontend/src/components/ui/select.tsx create mode 100644 frontend/src/lib/formSutff/DynamicInput.Field.tsx create mode 100644 frontend/src/lib/formSutff/Select.Field.tsx create mode 100644 frontend/src/lib/queries/notificationSubs.ts create mode 100644 frontend/src/lib/queries/notifications.ts create mode 100644 frontend/src/routes/(auth)/-components/NotificationsSubCard.tsx create mode 100644 migrations/0019_large_thunderbird.sql create mode 100644 migrations/meta/0019_snapshot.json create mode 100644 scripts/dockerscripts.md diff --git a/.dockerignore b/.dockerignore index 8865e38..7c46942 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,4 +6,7 @@ Dockerfile docker-compose.yml npm-debug.log builds -testFiles \ No newline at end of file +testFiles +nssm.exe +postgresql-17.9-2-windows-x64.exe +VSCodeUserSetup-x64-1.112.0.msi \ No newline at end of file diff --git a/.gitignore b/.gitignore index aa77468..04961bb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ temp node-v24.14.0-x64.msi postgresql-17.9-2-windows-x64.exe VSCodeUserSetup-x64-1.112.0.exe +nssm.exe # Logs logs diff --git a/Dockerfile b/Dockerfile index ca4565e..63bdc89 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,10 +9,13 @@ WORKDIR /app # Copy package files COPY . . -# Install production dependencies only +# build backend RUN npm ci +RUN npm run build:docker -RUN npm run build +# build frontend +RUN npm --prefix frontend ci +RUN npm --prefix frontend run build ########### # Stage 2 # @@ -33,6 +36,9 @@ RUN npm ci --omit=dev COPY --from=build /app/dist ./dist +COPY --from=build /app/frontend/dist ./frontend/dist + +# TODO add in drizzle migrates ENV RUNNING_IN_DOCKER=true EXPOSE 3000 diff --git a/backend/db/schema/printerLogs.schema.ts b/backend/db/schema/printerLogs.schema.ts new file mode 100644 index 0000000..ee3d84e --- /dev/null +++ b/backend/db/schema/printerLogs.schema.ts @@ -0,0 +1,6 @@ +import { integer, pgTable, text } from "drizzle-orm/pg-core"; + +export const opendockApt = pgTable("printer_log", { + id: integer().primaryKey().generatedAlwaysAsIdentity(), + name: text("name").notNull(), +}); diff --git a/backend/notification/notificationSub.get.route.ts b/backend/notification/notificationSub.get.route.ts index e2c65cd..e15b025 100644 --- a/backend/notification/notificationSub.get.route.ts +++ b/backend/notification/notificationSub.get.route.ts @@ -9,6 +9,8 @@ import { tryCatch } from "../utils/trycatch.utils.js"; const r = Router(); r.get("/", async (req, res: Response) => { + const { userId } = req.query; + const hasPermissions = await auth.api.userHasPermission({ body: { //userId: req?.user?.id, @@ -24,7 +26,7 @@ r.get("/", async (req, res: Response) => { .select() .from(notificationSub) .where( - !hasPermissions.success + userId || !hasPermissions.success ? eq(notificationSub.userId, `${req?.user?.id ?? ""}`) : undefined, ), @@ -47,7 +49,7 @@ r.get("/", async (req, res: Response) => { level: "info", module: "notification", subModule: "post", - message: `Subscription deleted`, + message: `Subscriptions`, data: data ?? [], status: 200, }); diff --git a/backend/ocp/ocp.printer.listener.ts b/backend/ocp/ocp.printer.listener.ts new file mode 100644 index 0000000..c4bb150 --- /dev/null +++ b/backend/ocp/ocp.printer.listener.ts @@ -0,0 +1,36 @@ +/** + * the route that listens for the printers post. + * + * and http-post alert should be setup on each printer pointing to at min you will want to make the alert for + * pause printer, you can have all on here as it will also monitor and do things on all messages + * + * http://{serverIP}:2222/lst/api/ocp/printer/listener/{printerName} + * + * the messages will be sent over to the db for logging as well as specific ones will do something + * + * pause will validate if can print + * close head will repause the printer so it wont print a label + * power up will just repause the printer so it wont print a label + */ + +import { Router } from "express"; +import { apiReturn } from "../utils/returnHelper.utils.js"; + +const r = Router(); + +r.post("/printer/listener/:printer", async (req, res) => { + const { printer: printerName } = req.params; + console.log(req.body); + + return apiReturn(res, { + success: true, + level: "info", + module: "ocp", + subModule: "printing", + message: `${printerName} just passed over a message`, + data: req.body ?? [], + status: 200, + }); +}); + +export default r; diff --git a/backend/ocp/ocp.printer.manage.ts b/backend/ocp/ocp.printer.manage.ts new file mode 100644 index 0000000..dd3cfb6 --- /dev/null +++ b/backend/ocp/ocp.printer.manage.ts @@ -0,0 +1,19 @@ +/** + * this will do a prod sync, update or add alerts to the printer, validate the next pm intervale as well as head replacement. + * + * if a printer is upcoming on a pm or head replacement send to the plant to address. + * + * a trigger on the printer table will have the ability to run this as well + * + * heat beats on all assigned printers + * + * printer status will live here this will be how we manage all the levels of status like 3 paused, 1 printing, 8 error, 10 power up, etc... + */ + +export const printerManager = async () => {}; + +export const printerHeartBeat = async () => { + // heat heats will be defaulted to 60 seconds no reason to allow anything else +}; + +//export const printerStatus = async (statusNr: number, printerId: number) => {}; diff --git a/backend/ocp/ocp.routes.ts b/backend/ocp/ocp.routes.ts new file mode 100644 index 0000000..530fb46 --- /dev/null +++ b/backend/ocp/ocp.routes.ts @@ -0,0 +1,22 @@ +import { type Express, Router } from "express"; +import { requireAuth } from "../middleware/auth.middleware.js"; +import { featureCheck } from "../middleware/featureActive.middleware.js"; +import listener from "./ocp.printer.listener.js"; + +export const setupOCPRoutes = (baseUrl: string, app: Express) => { + //setup all the routes + const router = Router(); + + // is the feature even on? + router.use(featureCheck("ocp")); + + // non auth routes up here + router.use(listener); + + // auth routes below here + router.use(requireAuth); + + //router.use(""); + + app.use(`${baseUrl}/api/ocp`, router); +}; diff --git a/backend/routeHandler.routes.ts b/backend/routeHandler.routes.ts index 047830f..ba8fae2 100644 --- a/backend/routeHandler.routes.ts +++ b/backend/routeHandler.routes.ts @@ -5,6 +5,7 @@ import { setupAuthRoutes } from "./auth/auth.routes.js"; import { setupApiDocsRoutes } from "./configs/scaler.config.js"; import { setupDatamartRoutes } from "./datamart/datamart.routes.js"; import { setupNotificationRoutes } from "./notification/notification.routes.js"; +import { setupOCPRoutes } from "./ocp/ocp.routes.js"; import { setupOpendockRoutes } from "./opendock/opendock.routes.js"; import { setupProdSqlRoutes } from "./prodSql/prodSql.routes.js"; import { setupSystemRoutes } from "./system/system.routes.js"; @@ -20,4 +21,5 @@ export const setupRoutes = (baseUrl: string, app: Express) => { setupUtilsRoutes(baseUrl, app); setupOpendockRoutes(baseUrl, app); setupNotificationRoutes(baseUrl, app); + setupOCPRoutes(baseUrl, app); }; diff --git a/backend/system/settingsBase.controller.ts b/backend/system/settingsBase.controller.ts index bde460e..d3369e0 100644 --- a/backend/system/settingsBase.controller.ts +++ b/backend/system/settingsBase.controller.ts @@ -9,7 +9,7 @@ const newSettings: NewSetting[] = [ { name: "opendock_sync", value: "0", - active: true, + active: false, description: "Dock Scheduling system", moduleName: "opendock", settingType: "feature", @@ -19,7 +19,7 @@ const newSettings: NewSetting[] = [ { name: "ocp", value: "1", - active: true, + active: false, description: "One click print", moduleName: "ocp", settingType: "feature", @@ -29,7 +29,7 @@ const newSettings: NewSetting[] = [ { name: "ocme", value: "0", - active: true, + active: false, description: "Dayton Agv system", moduleName: "ocme", settingType: "feature", @@ -39,7 +39,7 @@ const newSettings: NewSetting[] = [ { name: "demandManagement", value: "1", - active: true, + active: false, description: "Fake EDI System", moduleName: "demandManagement", settingType: "feature", @@ -49,7 +49,7 @@ const newSettings: NewSetting[] = [ { name: "qualityRequest", value: "0", - active: true, + active: false, description: "Quality System", moduleName: "qualityRequest", settingType: "feature", @@ -59,7 +59,7 @@ const newSettings: NewSetting[] = [ { name: "tms", value: "0", - active: true, + active: false, description: "Transport system integration", moduleName: "tms", settingType: "feature", diff --git a/backend/utils/cors.utils.ts b/backend/utils/cors.utils.ts index 5895f2f..efc834d 100644 --- a/backend/utils/cors.utils.ts +++ b/backend/utils/cors.utils.ts @@ -15,6 +15,7 @@ export const allowedOrigins = [ `http://${process.env.PROD_SERVER}:3000`, `http://${process.env.PROD_SERVER}:3100`, // temp `http://usmcd1olp082:3000`, + `http://localhost:3600`, // internal docker ]; export const lstCors = () => { return cors({ diff --git a/backend/utils/returnHelper.utils.ts b/backend/utils/returnHelper.utils.ts index 0f82462..51a80fd 100644 --- a/backend/utils/returnHelper.utils.ts +++ b/backend/utils/returnHelper.utils.ts @@ -28,7 +28,8 @@ interface Data { | "delete" | "post" | "notification" - | "delete"; + | "delete" + | "printing"; level: "info" | "error" | "debug" | "fatal"; message: string; room?: string; diff --git a/brunoApi/notifications/Subscribe to notification.bru b/brunoApi/notifications/Subscribe to notification.bru index e98cffc..a357482 100644 --- a/brunoApi/notifications/Subscribe to notification.bru +++ b/brunoApi/notifications/Subscribe to notification.bru @@ -14,7 +14,7 @@ body:json { { "userId":"m6AbQXFwOXoX3YKLfwWgq2LIdDqS5jqv", "notificationId": "0399eb2a-39df-48b7-9f1c-d233cec94d2e", - "emails": ["blake.mattes@alpla.com"] + "emails": ["blake.mattes@alpla.com","cowchmonkey@gmail.com"] } } diff --git a/brunoApi/ocp/Printer Listenter.bru b/brunoApi/ocp/Printer Listenter.bru new file mode 100644 index 0000000..0d0bc16 --- /dev/null +++ b/brunoApi/ocp/Printer Listenter.bru @@ -0,0 +1,22 @@ +meta { + name: Printer Listenter + type: http + seq: 1 +} + +post { + url: {{url}}/api/ocp/printer/listener/line_1 + body: json + auth: inherit +} + +body:json { + { + "message":"xnvjdhhgsdfr" + } +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/brunoApi/ocp/folder.bru b/brunoApi/ocp/folder.bru new file mode 100644 index 0000000..4842046 --- /dev/null +++ b/brunoApi/ocp/folder.bru @@ -0,0 +1,8 @@ +meta { + name: ocp + seq: 9 +} + +auth { + mode: inherit +} diff --git a/docker-compose.yml b/docker-compose.yml index 570e44c..1ccbaaf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,20 @@ services: - app: - build: - context: . - dockerfile: Dockerfile + lst: + image: git.tuffraid.net/cowch/lst_v3:latest container_name: lst_app + restart: unless-stopped + # app: + # build: + # context: . + # dockerfile: Dockerfile + # container_name: lst_app ports: #- "${VITE_PORT:-4200}:4200" - "3600:3000" environment: - NODE_ENV=production - LOG_LEVEL=info - - DATABASE_HOST=host.docker.internal + - DATABASE_HOST=host.docker.internal # if running on the same docker then do this - DATABASE_PORT=5433 - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} diff --git a/frontend/src/components/Sidebar/AdminBar.tsx b/frontend/src/components/Sidebar/AdminBar.tsx index 9959e20..d50b210 100644 --- a/frontend/src/components/Sidebar/AdminBar.tsx +++ b/frontend/src/components/Sidebar/AdminBar.tsx @@ -11,15 +11,15 @@ import { useSidebar, } from "../ui/sidebar"; -type AdminSidebarProps = { - session: { - user: { - name?: string | null; - email?: string | null; - role?: string | string[]; - }; - } | null; -}; +// type AdminSidebarProps = { +// session: { +// user: { +// name?: string | null; +// email?: string | null; +// role?: string | string[]; +// }; +// } | null; +//}; export default function AdminSidebar({ session }: any) { const { setOpen } = useSidebar(); diff --git a/frontend/src/components/ui/select.tsx b/frontend/src/components/ui/select.tsx new file mode 100644 index 0000000..8333850 --- /dev/null +++ b/frontend/src/components/ui/select.tsx @@ -0,0 +1,190 @@ +import * as React from "react" +import { Select as SelectPrimitive } from "radix-ui" + +import { cn } from "@/lib/utils" +import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react" + +function Select({ + ...props +}: React.ComponentProps) { + return +} + +function SelectGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectValue({ + ...props +}: React.ComponentProps) { + return +} + +function SelectTrigger({ + className, + size = "default", + children, + ...props +}: React.ComponentProps & { + size?: "sm" | "default" +}) { + return ( + + {children} + + + + + ) +} + +function SelectContent({ + className, + children, + position = "item-aligned", + align = "center", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ) +} + +function SelectLabel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +} diff --git a/frontend/src/lib/formSutff/DynamicInput.Field.tsx b/frontend/src/lib/formSutff/DynamicInput.Field.tsx new file mode 100644 index 0000000..2031a7a --- /dev/null +++ b/frontend/src/lib/formSutff/DynamicInput.Field.tsx @@ -0,0 +1,87 @@ +import { Trash2 } from "lucide-react"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Button } from "../../components/ui/button"; +import { useFieldContext } from "."; +import { FieldErrors } from "./Errors.Field"; + +type DynamicInputField = { + name?: string; + label: string; + inputType: "text" | "email" | "password" | "number" | "username"; + required?: boolean; + description?: string; + addLabel?: string; + placeholder?: string; + disabled?: boolean; +}; + +const autoCompleteMap: Record = { + email: "email", + password: "current-password", + text: "off", + username: "username", +}; + +export const DynamicInputField = ({ + label, + inputType = "text", + required = false, + description, + addLabel, +}: DynamicInputField) => { + const field = useFieldContext(); + const values = Array.isArray(field.state.value) ? field.state.value : []; + + return ( +
+
+
+ + {description ? ( +

{description}

+ ) : null} +
+ + +
+
+ {values.map((_: string, index: number) => ( +
+
+ + field.replaceValue(index, e.target.value)} + onBlur={field.handleBlur} + type={inputType} + required={required} + /> + {values.length > 1 ? ( + + ) : null} + +
+
+ ))} +
+
+ ); +}; diff --git a/frontend/src/lib/formSutff/Select.Field.tsx b/frontend/src/lib/formSutff/Select.Field.tsx new file mode 100644 index 0000000..dfac24f --- /dev/null +++ b/frontend/src/lib/formSutff/Select.Field.tsx @@ -0,0 +1,57 @@ +import { Label } from "../../components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "../../components/ui/select"; +import { useFieldContext } from "."; +import { FieldErrors } from "./Errors.Field"; + +type SelectOption = { + value: string; + label: string; +}; + +type SelectFieldProps = { + label: string; + options: SelectOption[]; + placeholder?: string; +}; + +export const SelectField = ({ + label, + options, + placeholder, +}: SelectFieldProps) => { + const field = useFieldContext(); + + return ( +
+
+ + +
+ +
+ ); +}; diff --git a/frontend/src/lib/formSutff/index.tsx b/frontend/src/lib/formSutff/index.tsx index a4d8163..e5e2f41 100644 --- a/frontend/src/lib/formSutff/index.tsx +++ b/frontend/src/lib/formSutff/index.tsx @@ -1,7 +1,9 @@ import { createFormHook, createFormHookContexts } from "@tanstack/react-form"; import { CheckboxField } from "./CheckBox.Field"; +import { DynamicInputField } from "./DynamicInput.Field"; import { InputField } from "./Input.Field"; import { InputPasswordField } from "./InputPassword.Field"; +import { SelectField } from "./Select.Field"; import { SubmitButton } from "./SubmitButton"; import { SwitchField } from "./Switch.Field"; @@ -12,12 +14,13 @@ export const { useAppForm } = createFormHook({ fieldComponents: { InputField, InputPasswordField, - //SelectField, + SelectField, CheckboxField, //DateField, //TextArea, //Searchable, SwitchField, + DynamicInputField, }, formComponents: { SubmitButton }, fieldContext, diff --git a/frontend/src/lib/queries/notificationSubs.ts b/frontend/src/lib/queries/notificationSubs.ts new file mode 100644 index 0000000..c05be55 --- /dev/null +++ b/frontend/src/lib/queries/notificationSubs.ts @@ -0,0 +1,24 @@ +import { keepPreviousData, queryOptions } from "@tanstack/react-query"; +import axios from "axios"; + +export function notificationSubs(userId?: string) { + return queryOptions({ + queryKey: ["notificationSubs"], + queryFn: () => fetch(userId), + staleTime: 5000, + refetchOnWindowFocus: true, + placeholderData: keepPreviousData, + }); +} + +const fetch = async (userId?: string) => { + if (window.location.hostname === "localhost") { + await new Promise((res) => setTimeout(res, 5000)); + } + + const { data } = await axios.get( + `/lst/api/notification/sub${userId ? `?userId=${userId}` : ""}`, + ); + + return data.data; +}; diff --git a/frontend/src/lib/queries/notifications.ts b/frontend/src/lib/queries/notifications.ts new file mode 100644 index 0000000..c1e90f5 --- /dev/null +++ b/frontend/src/lib/queries/notifications.ts @@ -0,0 +1,22 @@ +import { keepPreviousData, queryOptions } from "@tanstack/react-query"; +import axios from "axios"; + +export function notifications() { + return queryOptions({ + queryKey: ["notifications"], + queryFn: () => fetch(), + staleTime: 5000, + refetchOnWindowFocus: true, + placeholderData: keepPreviousData, + }); +} + +const fetch = async () => { + if (window.location.hostname === "localhost") { + await new Promise((res) => setTimeout(res, 5000)); + } + + const { data } = await axios.get("/lst/api/notification"); + + return data.data; +}; diff --git a/frontend/src/lib/tableStuff/SearchableHeader.tsx b/frontend/src/lib/tableStuff/SearchableHeader.tsx index 77224ff..258631e 100644 --- a/frontend/src/lib/tableStuff/SearchableHeader.tsx +++ b/frontend/src/lib/tableStuff/SearchableHeader.tsx @@ -1,6 +1,6 @@ import type { Column } from "@tanstack/react-table"; import { ArrowDown, ArrowUp, Search } from "lucide-react"; -import React, { useState } from "react"; +import { useState } from "react"; import { Button } from "../../components/ui/button"; import { DropdownMenu, diff --git a/frontend/src/routes/(auth)/-components/NotificationsSubCard.tsx b/frontend/src/routes/(auth)/-components/NotificationsSubCard.tsx new file mode 100644 index 0000000..d4f116e --- /dev/null +++ b/frontend/src/routes/(auth)/-components/NotificationsSubCard.tsx @@ -0,0 +1,87 @@ +import { useSuspenseQuery } from "@tanstack/react-query"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "../../../components/ui/card"; +import { useAppForm } from "../../../lib/formSutff"; +import { notificationSubs } from "../../../lib/queries/notificationSubs"; +import { notifications } from "../../../lib/queries/notifications"; + +export default function NotificationsSubCard({ user }: any) { + const { data } = useSuspenseQuery(notifications()); + const { data: ns } = useSuspenseQuery(notificationSubs(user.id)); + const form = useAppForm({ + defaultValues: { + notificationId: "", + emails: [user.email], + }, + onSubmit: async ({ value }) => { + const postD = { ...value, userId: user.id }; + console.log(postD); + }, + }); + + let n: any = []; + if (data) { + n = data.map((i: any) => ({ + label: i.name, + value: i.id, + })); + } + + console.log(ns); + + return ( +
+ + + Notifications + + All currently active notifications you can subscribe to. selecting a + notification will give you a brief description on how it works + + + +
{ + e.preventDefault(); + form.handleSubmit(); + }} + > +
+ + {(field) => ( + + )} + +
+ + + {(field) => ( + + )} + +
+ + Subscribe + +
+
+
+
+
+ ); +} diff --git a/frontend/src/routes/(auth)/user.profile.tsx b/frontend/src/routes/(auth)/user.profile.tsx index d69313c..701f83c 100644 --- a/frontend/src/routes/(auth)/user.profile.tsx +++ b/frontend/src/routes/(auth)/user.profile.tsx @@ -1,4 +1,5 @@ import { createFileRoute, redirect } from "@tanstack/react-router"; +import { Suspense } from "react"; import { toast } from "sonner"; import { Card, @@ -9,7 +10,9 @@ import { } from "@/components/ui/card"; import { authClient, useSession } from "@/lib/auth-client"; import { useAppForm } from "@/lib/formSutff"; +import { Spinner } from "../../components/ui/spinner"; import ChangePassword from "./-components/ChangePassword"; +import NotificationsSubCard from "./-components/NotificationsSubCard"; export const Route = createFileRoute("/(auth)/user/profile")({ beforeLoad: async () => { @@ -93,6 +96,26 @@ function RouteComponent() {
+
+ + + Notifications + + +
+
+ +
+
+
+ + } + > + {session && } +
+
); } diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx index 32cc087..62d8367 100644 --- a/frontend/src/routes/__root.tsx +++ b/frontend/src/routes/__root.tsx @@ -3,7 +3,7 @@ import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import { Toaster } from "sonner"; import Header from "@/components/Header"; import { AppSidebar } from "@/components/Sidebar/sidebar"; -import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"; +import { SidebarProvider } from "@/components/ui/sidebar"; import { ThemeProvider } from "@/lib/theme-provider"; const RootLayout = () => ( diff --git a/frontend/src/routes/admin/-components/FeatureCard.tsx b/frontend/src/routes/admin/-components/FeatureCard.tsx index 17a00dc..626242a 100644 --- a/frontend/src/routes/admin/-components/FeatureCard.tsx +++ b/frontend/src/routes/admin/-components/FeatureCard.tsx @@ -1,6 +1,5 @@ import { useSuspenseQuery } from "@tanstack/react-query"; import axios from "axios"; -import React from "react"; import { toast } from "sonner"; import { Card, CardDescription, CardHeader } from "../../../components/ui/card"; import { useAppForm } from "../../../lib/formSutff"; @@ -33,7 +32,9 @@ export default function FeatureCard({ item }: { item: Setting }) { const { data } = await axios.patch(`/lst/api/settings/${item.name}`, { value: value.value, active: value.active ? "true" : "false", - }); + }, { + withCredentials: true, + }); refetch(); toast.success( diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index d6fec2e..9a3d6e5 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -34,7 +34,7 @@ function Index() {

This is active in your plant today due to having warehousing activated and new functions needed to be introduced, you should be still using LST - as you were before + as you were before.



@@ -50,7 +50,7 @@ function Index() { rel="noopener" > - Here + Here.

diff --git a/migrations/0019_large_thunderbird.sql b/migrations/0019_large_thunderbird.sql new file mode 100644 index 0000000..e6888ee --- /dev/null +++ b/migrations/0019_large_thunderbird.sql @@ -0,0 +1,4 @@ +CREATE TABLE "printer_log" ( + "id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "printer_log_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1), + "name" text NOT NULL +); diff --git a/migrations/meta/0019_snapshot.json b/migrations/meta/0019_snapshot.json new file mode 100644 index 0000000..7a88da4 --- /dev/null +++ b/migrations/meta/0019_snapshot.json @@ -0,0 +1,1327 @@ +{ + "id": "5628fac7-7958-4306-9c5d-5f00b843624d", + "prevId": "5e84c914-35fe-4583-afd4-de064de17317", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.job_audit_log": { + "name": "job_audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "job_name": { + "name": "job_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "finished_at": { + "name": "finished_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_stack": { + "name": "error_stack", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meta_data": { + "name": "meta_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_job_audit_logs_cleanup": { + "name": "idx_job_audit_logs_cleanup", + "columns": [ + { + "expression": "start_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apikey": { + "name": "apikey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 86400000 + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 10 + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_request": { + "name": "last_request", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "apikey_key_idx": { + "name": "apikey_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "apikey_userId_idx": { + "name": "apikey_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "apikey_user_id_user_id_fk": { + "name": "apikey_user_id_user_id_fk", + "tableFrom": "apikey", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.jwks": { + "name": "jwks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.datamart": { + "name": "datamart", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "query": { + "name": "query", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "options": { + "name": "options", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "public_access": { + "name": "public_access", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "add_date": { + "name": "add_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "add_user": { + "name": "add_user", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'lst-system'" + }, + "upd_date": { + "name": "upd_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "upd_user": { + "name": "upd_user", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'lst-system'" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "datamart_name_unique": { + "name": "datamart_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.logs": { + "name": "logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "module": { + "name": "module", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subModule": { + "name": "subModule", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stack": { + "name": "stack", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "checked": { + "name": "checked", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "hostname": { + "name": "hostname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notifications": { + "name": "notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "interval": { + "name": "interval", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'5'" + }, + "options": { + "name": "options", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + } + }, + "indexes": { + "notify_name": { + "name": "notify_name", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification_sub": { + "name": "notification_sub", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "notification_id": { + "name": "notification_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "emails": { + "name": "emails", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + } + }, + "indexes": {}, + "foreignKeys": { + "notification_sub_user_id_user_id_fk": { + "name": "notification_sub_user_id_user_id_fk", + "tableFrom": "notification_sub", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_sub_notification_id_notifications_id_fk": { + "name": "notification_sub_notification_id_notifications_id_fk", + "tableFrom": "notification_sub", + "tableTo": "notifications", + "columnsFrom": [ + "notification_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "notification_sub_user_notification_unique": { + "name": "notification_sub_user_notification_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "notification_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.opendock_apt": { + "name": "opendock_apt", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "release": { + "name": "release", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "open_dock_apt_id": { + "name": "open_dock_apt_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "appointment": { + "name": "appointment", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "upd_date": { + "name": "upd_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "opendock_apt_release_unique": { + "name": "opendock_apt_release_unique", + "nullsNotDistinct": false, + "columns": [ + "release" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.printer_log": { + "name": "printer_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "always", + "name": "printer_log_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "settings_id": { + "name": "settings_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "moduleName": { + "name": "moduleName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "roles": { + "name": "roles", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[\"systemAdmin\"]'::jsonb" + }, + "settingType": { + "name": "settingType", + "type": "setting_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "seed_version": { + "name": "seed_version", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 1 + }, + "add_User": { + "name": "add_User", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'LST_System'" + }, + "add_Date": { + "name": "add_Date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "upd_User": { + "name": "upd_User", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'LST_System'" + }, + "upd_date": { + "name": "upd_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "name": { + "name": "name", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.stats": { + "name": "stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "'serverStats'" + }, + "build": { + "name": "build", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "last_update": { + "name": "last_update", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.setting_type": { + "name": "setting_type", + "schema": "public", + "values": [ + "feature", + "system", + "standard" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index e21f18e..951806e 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -134,6 +134,13 @@ "when": 1774032587305, "tag": "0018_lowly_wallow", "breakpoints": true + }, + { + "idx": 19, + "version": "7", + "when": 1775159956510, + "tag": "0019_large_thunderbird", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c1b9019..6924ab4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,6 +63,7 @@ "@types/swagger-jsdoc": "^6.0.4", "@types/swagger-ui-express": "^4.1.8", "commitizen": "^4.3.1", + "cpy-cli": "^7.0.0", "cz-conventional-changelog": "^3.3.0", "npm-check-updates": "^19.6.5", "openapi-types": "^12.1.3", @@ -2388,6 +2389,19 @@ "url": "https://ko-fi.com/dangreen" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@socket.io/admin-ui": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/@socket.io/admin-ui/-/admin-ui-0.5.1.tgz", @@ -3838,6 +3852,23 @@ "node": ">=6.6.0" } }, + "node_modules/copy-file": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/copy-file/-/copy-file-11.1.0.tgz", + "integrity": "sha512-X8XDzyvYaA6msMyAM575CUoygY5b44QzLcGRKsK3MFmXcOvQa518dNPLsKYwkYsn72g3EiW+LE0ytd/FlqWmyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.11", + "p-event": "^6.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cors": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", @@ -3900,6 +3931,178 @@ "typescript": ">=5" } }, + "node_modules/cpy": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-13.2.1.tgz", + "integrity": "sha512-/H2B3WW9gccZJKjKoDZsIrDU3MkkHlxgheT82hUbInC5fEdi4+54zyYpFueZT9pLfr5ObrtgN4MsYYrmTmHzeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-file": "^11.1.0", + "globby": "^16.1.0", + "junk": "^4.0.1", + "micromatch": "^4.0.8", + "p-filter": "^4.1.0", + "p-map": "^7.0.4" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy-cli": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-7.0.0.tgz", + "integrity": "sha512-uGCdhIxGfZcPXidCuT8w1jBknVXFx0un7NLjzqBZcdnkIWtLUnWMPk5TC37ceoVjwASLSNsRtTXXNTuFIyE2ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "cpy": "^13.2.0", + "globby": "^16.1.0", + "meow": "^14.0.0" + }, + "bin": { + "cpy": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy-cli/node_modules/globby": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz", + "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy-cli/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/cpy-cli/node_modules/meow": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", + "integrity": "sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy-cli/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy/node_modules/globby": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz", + "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/cpy/node_modules/p-filter": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-4.1.0.tgz", + "integrity": "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^7.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy/node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cpy/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -6427,6 +6630,19 @@ "node": ">=8" } }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -6637,6 +6853,19 @@ "npm": ">=6" } }, + "node_modules/junk": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.1.tgz", + "integrity": "sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jwa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", @@ -7467,6 +7696,22 @@ "dev": true, "license": "MIT" }, + "node_modules/p-event": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", + "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-filter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", @@ -7519,6 +7764,19 @@ "node": ">=6" } }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -9256,6 +9514,19 @@ "dev": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index af04209..7ed37c4 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,8 @@ "build": "rimraf dist && npm run dev:db:generate && npm run dev:db:migrate && npm run build:app && npm run build:copySql && cd frontend && npm run build", "build:app": "tsc", "agent": "powershell -ExecutionPolicy Bypass -File scripts/agentController.ps1", - "build:docker": "docker compose up --force-recreate --build -d", - "build:copySql": "xcopy backend\\prodSql\\queries dist\\prodSql\\queries\\ /E /I /Y ", + "build:docker": "rimraf dist && npm run build:app && npm run build:copySql", + "build:copySql": "cpy \"backend/prodSql/queries/**/*\" dist/prodSql/queries --parents", "lint": "tsc && biome lint", "start": "npm run start:server", "start:server": "dotenvx run -f .env -- node dist/server.js", @@ -57,6 +57,7 @@ "@types/swagger-jsdoc": "^6.0.4", "@types/swagger-ui-express": "^4.1.8", "commitizen": "^4.3.1", + "cpy-cli": "^7.0.0", "cz-conventional-changelog": "^3.3.0", "npm-check-updates": "^19.6.5", "openapi-types": "^12.1.3", diff --git a/scripts/agentController.ps1 b/scripts/agentController.ps1 index 7535b69..4568430 100644 --- a/scripts/agentController.ps1 +++ b/scripts/agentController.ps1 @@ -17,6 +17,11 @@ $Servers = @( token = "uslim1" loc = "D$\LST_V3" }, + [PSCustomObject]@{ + server = "ushou1vms006" + token = "ushou1" + loc = "D$\LST_V3" + }, [PSCustomObject]@{ server = "usday1vms006" token = "usday1" diff --git a/scripts/dockerscripts.md b/scripts/dockerscripts.md new file mode 100644 index 0000000..759e6da --- /dev/null +++ b/scripts/dockerscripts.md @@ -0,0 +1,6 @@ + + +docker build -t git.tuffraid.net/cowch/lst_v3:latest . +docker push git.tuffraid.net/cowch/lst_v3:latest + +docker compose pull && docker compose up -d --force-recreate \ No newline at end of file