refactor(opendock): added some new goodies to the app to help manage releases
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 1m24s

This commit is contained in:
2026-06-09 21:09:03 -05:00
parent 8fcb2c66ed
commit c0a7d4a125
15 changed files with 3286 additions and 72 deletions

View File

@@ -16,6 +16,7 @@ export const opendockApt = pgTable(
id: uuid("id").defaultRandom().primaryKey(), id: uuid("id").defaultRandom().primaryKey(),
release: integer("release").notNull().unique("opendock_apt_release_unique"), release: integer("release").notNull().unique("opendock_apt_release_unique"),
openDockAptId: text("open_dock_apt_id").notNull(), openDockAptId: text("open_dock_apt_id").notNull(),
status: text("status").default("active"),
appointment: jsonb("appointment").notNull().default([]), appointment: jsonb("appointment").notNull().default([]),
upd_date: timestamp("upd_date", { withTimezone: true }) upd_date: timestamp("upd_date", { withTimezone: true })
.notNull() .notNull()

View File

@@ -21,6 +21,7 @@ type Releases = {
ReleaseNumber: number; ReleaseNumber: number;
DeliveryState: number; DeliveryState: number;
DeliveryDate: Date; DeliveryDate: Date;
ReleaseState: number;
LineItemHumanReadableId: number; LineItemHumanReadableId: number;
ArticleAlias: string; ArticleAlias: string;
LoadingUnits: string; LoadingUnits: string;
@@ -38,6 +39,8 @@ const actaulDocks = [
{ name: "matrix", dockId: "3e32cbfc-49f4-4138-b491-9d5df9c94754" }, { name: "matrix", dockId: "3e32cbfc-49f4-4138-b491-9d5df9c94754" },
{ name: "gerber", dockId: "9109e789-6c15-4cd9-87cb-de1b18627b6d" }, { name: "gerber", dockId: "9109e789-6c15-4cd9-87cb-de1b18627b6d" },
{ name: "rb", dockId: "6be02526-6183-4789-a73f-e0aa155e6d1e" }, { name: "rb", dockId: "6be02526-6183-4789-a73f-e0aa155e6d1e" },
//test server dock
{ name: "second", dockId: "e87c92bd-13b4-4f7e-bf5e-b0182884c47a" },
]; ];
const timeZone = process.env.TIMEZONE as string; const timeZone = process.env.TIMEZONE as string;
const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000; const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;
@@ -273,11 +276,65 @@ const postRelease = async (release: Releases) => {
if (existing) { if (existing) {
const id = existing.openDockAptId; const id = existing.openDockAptId;
// deal with canceled stuff as we want this gone off od
if (release.ReleaseState === 2 || release.ReleaseState === 4) {
// delete the order in od and change the state to canceled in lst
try {
const response = await axios.delete(
`${process.env.OPENDOCK_URL}/appointment/${id}`,
{
headers: {
"content-type": "application/json; charset=utf-8",
Authorization: `Bearer ${odToken.odToken}`,
},
},
// {
// hardDelete: true,
// },
);
if (response.status === 400) {
log.error({}, response.data.data.message);
return;
}
// update the release in the db leaving as insert just incase something weird happened
try {
await db
.update(opendockApt)
.set({
status: "canceled",
upd_date: sql`Now()`,
})
.where(eq(opendockApt.release, release.ReleaseNumber))
.returning();
log.info({}, `${release.ReleaseNumber} was canceled`);
} catch (e) {
log.error(
{ stack: e },
`Error canceling the release: ${release.ReleaseNumber}`,
);
}
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
} catch (e: any) {
//console.info(newDockApt);
log.error(
{ stack: e.response.data },
`An error has occurred during canceling of the release: ${release.ReleaseNumber}`,
);
return;
}
return;
}
if ( if (
(releaseLoadtypeCheck || (releaseLoadtypeCheck ||
opendDockArticleCheck?.loadType === "drop" || opendDockArticleCheck?.loadType === "drop" ||
defaultDock?.value === "drop") && defaultDock?.value === "drop") &&
(release.DeliveryState === 0 || release.DeliveryState === 2) release.DeliveryState === 2
) { ) {
const setArrival = { ...newDockApt, status: "Arrived" }; const setArrival = { ...newDockApt, status: "Arrived" };
@@ -392,7 +449,11 @@ const postRelease = async (release: Releases) => {
return; return;
} }
// changing to only trigger the change if the state is 2 meaning it has a scan to it and already in progress of being loaded. // changing to only trigger the change if the state is 2 meaning it has a scan to it and already in progress of being loaded.
} else if (release.DeliveryState === 0 || release.DeliveryState === 2) { } else if (
release.DeliveryState === 0 ||
release.DeliveryState === 1 ||
release.DeliveryState === 2
) {
try { try {
const response = await axios.patch( const response = await axios.patch(
`${process.env.OPENDOCK_URL}/appointment/${id}`, `${process.env.OPENDOCK_URL}/appointment/${id}`,
@@ -479,6 +540,7 @@ const postRelease = async (release: Releases) => {
set: { set: {
openDockAptId: response.data.data.id, openDockAptId: response.data.data.id,
appointment: response.data.data, appointment: response.data.data,
status: "completed",
upd_date: sql`NOW()`, upd_date: sql`NOW()`,
}, },
}) })

View File

@@ -0,0 +1,73 @@
import axios from "axios";
import { eq, sql } from "drizzle-orm";
import { Router } from "express";
import { db } from "../db/db.controller.js";
import { opendockApt } from "../db/schema/opendock_apt.schema.js";
import { apiReturn } from "../utils/returnHelper.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
import { odToken } from "./opendock.utils.js";
const r = Router();
r.patch("/:id", async (req, res) => {
//const limit
const { id } = req.params;
try {
const response = await axios.patch(
`${process.env.OPENDOCK_URL}/appointment/${id}/undo-latest-status`,
{
headers: {
"content-type": "application/json; charset=utf-8",
Authorization: `Bearer ${odToken.odToken}`,
},
},
);
if (response.status === 400) {
return apiReturn(res, {
success: false,
level: "error",
module: "opendock",
subModule: "apt",
message: response.data.data.message,
data: [],
status: 400,
});
}
// update the release in the db
const { data } = await tryCatch(
db
.update(opendockApt)
.set({
appointment: response.data.data,
upd_date: sql`NOW()`,
})
.where(eq(opendockApt.openDockAptId, id)),
);
return apiReturn(res, {
success: true,
level: "info",
module: "opendock",
subModule: "apt",
message: `The release was reverted to the last state.`,
data: data as any,
status: 200,
});
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
} catch (e: any) {
return apiReturn(res, {
success: false,
level: "error",
module: "opendock",
subModule: "apt",
message: `An error updating the release in opendock`,
data: e.response.data,
status: 400,
});
}
});
export default r;

View File

@@ -1,9 +1,9 @@
import type { Express } from "express"; import type { Express } from "express";
import { requireAuth } from "../middleware/auth.middleware.js"; import { requireAuth } from "../middleware/auth.middleware.js";
import { featureCheck } from "../middleware/featureActive.middleware.js"; import { featureCheck } from "../middleware/featureActive.middleware.js";
import undo from "./openDockUndoLastStatus.js";
import articleCheck from "./opendock.articleCheck.route.js"; import articleCheck from "./opendock.articleCheck.route.js";
import getApt from "./opendockRelease.route.js";
import getApt from "./opendockGetRelease.route.js";
export const setupOpendockRoutes = (baseUrl: string, app: Express) => { export const setupOpendockRoutes = (baseUrl: string, app: Express) => {
//setup all the routes //setup all the routes
@@ -21,4 +21,11 @@ export const setupOpendockRoutes = (baseUrl: string, app: Express) => {
requireAuth, requireAuth,
articleCheck, articleCheck,
); );
app.use(
`${baseUrl}/api/opendock/undo-latest-status`,
featureCheck("opendock_sync"),
requireAuth,
undo,
);
}; };

View File

@@ -1,40 +0,0 @@
import { desc, gte, sql } from "drizzle-orm";
import { Router } from "express";
import { db } from "../db/db.controller.js";
import { opendockApt } from "../db/schema/opendock_apt.schema.js";
import { apiReturn } from "../utils/returnHelper.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
const r = Router();
r.get("/", async (_, res) => {
//const limit
const daysCreated = 30;
const { data } = await tryCatch(
db
.select()
.from(opendockApt)
.where(
gte(
opendockApt.createdAt,
sql.raw(`NOW() - INTERVAL '${daysCreated} days'`),
),
)
.orderBy(desc(opendockApt.createdAt))
.limit(500),
);
apiReturn(res, {
success: true,
level: "info",
module: "opendock",
subModule: "apt",
message: `The first ${data?.length} Apt(s) that were created in the last ${daysCreated} `,
data: data ?? [],
status: 200,
});
});
export default r;

View File

@@ -0,0 +1,124 @@
import axios from "axios";
import { and, desc, eq, gte, sql } from "drizzle-orm";
import { Router } from "express";
import { db } from "../db/db.controller.js";
import { opendockApt } from "../db/schema/opendock_apt.schema.js";
import { apiReturn } from "../utils/returnHelper.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
import { odToken } from "./opendock.utils.js";
const r = Router();
r.get("/", async (req, res) => {
//const limit
const daysCreated = req.query.daysCreated ?? 30;
const { data } = await tryCatch(
db
.select()
.from(opendockApt)
.where(
and(
gte(
opendockApt.upd_date,
sql.raw(`NOW() - INTERVAL '${daysCreated} days'`),
),
eq(opendockApt.status, "active"),
),
)
.orderBy(desc(opendockApt.upd_date))
.limit(500),
);
apiReturn(res, {
success: true,
level: "info",
module: "opendock",
subModule: "apt",
message: `The first ${data?.length} Apt(s) that were created in the last ${daysCreated} `,
data: data ?? [],
status: 200,
});
});
r.delete("/:id", async (req, res) => {
const { id } = req.params;
const { data: releaseInfo } = (await tryCatch(
db
.select()
.from(opendockApt)
.where(eq(opendockApt.id, id as string)),
)) as any;
if (releaseInfo.length === 0) {
return apiReturn(res, {
success: false,
level: "error",
module: "opendock",
subModule: "apt",
message: "Invalid release id passed over please try again",
data: [],
status: 400,
});
}
try {
const response = await axios.delete(
`${process.env.OPENDOCK_URL}/appointment/${releaseInfo[0].appointment.id}`,
{
headers: {
"content-type": "application/json; charset=utf-8",
Authorization: `Bearer ${odToken.odToken}`,
},
},
// {
// hardDelete: true,
// },
);
if (response.status === 400) {
return apiReturn(res, {
success: false,
level: "error",
module: "opendock",
subModule: "apt",
message: response.data.data.message,
data: [],
status: 400,
});
}
// update the release in the db leaving as insert just in-case something weird happened
const { data } = await tryCatch(
db
.delete(opendockApt)
.where(eq(opendockApt.id, id as string))
.returning(),
);
return apiReturn(res, {
success: true,
level: "info",
module: "opendock",
subModule: "apt",
message: `The release was deleted, this is un unrecoverable`,
data: data as any,
status: 200,
});
// biome-ignore lint/suspicious/noExplicitAny: to many possibilities
} catch (e: any) {
return apiReturn(res, {
success: false,
level: "error",
module: "opendock",
subModule: "apt",
message: `An error deleting the release in opendock`,
data: e.response.data,
status: 400,
});
}
});
export default r;

View File

@@ -40,6 +40,11 @@ export default function TransportationBar() {
icon: link, icon: link,
url: "/transportation/opendock", url: "/transportation/opendock",
}, },
{
title: "Active releases",
icon: link,
url: "/transportation/opendock/releases",
},
], ],
}, },
]; ];

View File

@@ -0,0 +1,23 @@
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
import { api } from "../apiHelper";
export function opendockApt() {
return queryOptions({
queryKey: ["opendockApt"],
queryFn: () => fetch(),
staleTime: 5000,
refetchOnWindowFocus: true,
placeholderData: keepPreviousData,
});
}
const fetch = async () => {
if (window.location.hostname === "localhost") {
await new Promise((res) => setTimeout(res, 1500));
}
const { data } = await api.get("/opendock?daysCreated=90");
return data.data;
};

View File

@@ -25,6 +25,7 @@ import { Route as authLoginRouteImport } from './routes/(auth)/login'
import { Route as WarehouseDockdoorscanningIndexRouteImport } from './routes/warehouse/dockdoorscanning/index' import { Route as WarehouseDockdoorscanningIndexRouteImport } from './routes/warehouse/dockdoorscanning/index'
import { Route as TransportationOpendockIndexRouteImport } from './routes/transportation/opendock/index' import { Route as TransportationOpendockIndexRouteImport } from './routes/transportation/opendock/index'
import { Route as WarehouseDockdoorscanningDockRouteImport } from './routes/warehouse/dockdoorscanning/$dock' import { Route as WarehouseDockdoorscanningDockRouteImport } from './routes/warehouse/dockdoorscanning/$dock'
import { Route as TransportationOpendockReleasesRouteImport } from './routes/transportation/opendock/releases'
import { Route as authUserSignupRouteImport } from './routes/(auth)/user.signup' import { Route as authUserSignupRouteImport } from './routes/(auth)/user.signup'
import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user.resetpassword' import { Route as authUserResetpasswordRouteImport } from './routes/(auth)/user.resetpassword'
import { Route as authUserProfileRouteImport } from './routes/(auth)/user.profile' import { Route as authUserProfileRouteImport } from './routes/(auth)/user.profile'
@@ -113,6 +114,12 @@ const WarehouseDockdoorscanningDockRoute =
path: '/warehouse/dockdoorscanning/$dock', path: '/warehouse/dockdoorscanning/$dock',
getParentRoute: () => rootRouteImport, getParentRoute: () => rootRouteImport,
} as any) } as any)
const TransportationOpendockReleasesRoute =
TransportationOpendockReleasesRouteImport.update({
id: '/transportation/opendock/releases',
path: '/transportation/opendock/releases',
getParentRoute: () => rootRouteImport,
} as any)
const authUserSignupRoute = authUserSignupRouteImport.update({ const authUserSignupRoute = authUserSignupRouteImport.update({
id: '/(auth)/user/signup', id: '/(auth)/user/signup',
path: '/user/signup', path: '/user/signup',
@@ -152,6 +159,7 @@ export interface FileRoutesByFullPath {
'/user/profile': typeof authUserProfileRoute '/user/profile': typeof authUserProfileRoute
'/user/resetpassword': typeof authUserResetpasswordRoute '/user/resetpassword': typeof authUserResetpasswordRoute
'/user/signup': typeof authUserSignupRoute '/user/signup': typeof authUserSignupRoute
'/transportation/opendock/releases': typeof TransportationOpendockReleasesRoute
'/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute '/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute
'/transportation/opendock/': typeof TransportationOpendockIndexRoute '/transportation/opendock/': typeof TransportationOpendockIndexRoute
'/warehouse/dockdoorscanning/': typeof WarehouseDockdoorscanningIndexRoute '/warehouse/dockdoorscanning/': typeof WarehouseDockdoorscanningIndexRoute
@@ -174,6 +182,7 @@ export interface FileRoutesByTo {
'/user/profile': typeof authUserProfileRoute '/user/profile': typeof authUserProfileRoute
'/user/resetpassword': typeof authUserResetpasswordRoute '/user/resetpassword': typeof authUserResetpasswordRoute
'/user/signup': typeof authUserSignupRoute '/user/signup': typeof authUserSignupRoute
'/transportation/opendock/releases': typeof TransportationOpendockReleasesRoute
'/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute '/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute
'/transportation/opendock': typeof TransportationOpendockIndexRoute '/transportation/opendock': typeof TransportationOpendockIndexRoute
'/warehouse/dockdoorscanning': typeof WarehouseDockdoorscanningIndexRoute '/warehouse/dockdoorscanning': typeof WarehouseDockdoorscanningIndexRoute
@@ -197,6 +206,7 @@ export interface FileRoutesById {
'/(auth)/user/profile': typeof authUserProfileRoute '/(auth)/user/profile': typeof authUserProfileRoute
'/(auth)/user/resetpassword': typeof authUserResetpasswordRoute '/(auth)/user/resetpassword': typeof authUserResetpasswordRoute
'/(auth)/user/signup': typeof authUserSignupRoute '/(auth)/user/signup': typeof authUserSignupRoute
'/transportation/opendock/releases': typeof TransportationOpendockReleasesRoute
'/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute '/warehouse/dockdoorscanning/$dock': typeof WarehouseDockdoorscanningDockRoute
'/transportation/opendock/': typeof TransportationOpendockIndexRoute '/transportation/opendock/': typeof TransportationOpendockIndexRoute
'/warehouse/dockdoorscanning/': typeof WarehouseDockdoorscanningIndexRoute '/warehouse/dockdoorscanning/': typeof WarehouseDockdoorscanningIndexRoute
@@ -221,6 +231,7 @@ export interface FileRouteTypes {
| '/user/profile' | '/user/profile'
| '/user/resetpassword' | '/user/resetpassword'
| '/user/signup' | '/user/signup'
| '/transportation/opendock/releases'
| '/warehouse/dockdoorscanning/$dock' | '/warehouse/dockdoorscanning/$dock'
| '/transportation/opendock/' | '/transportation/opendock/'
| '/warehouse/dockdoorscanning/' | '/warehouse/dockdoorscanning/'
@@ -243,6 +254,7 @@ export interface FileRouteTypes {
| '/user/profile' | '/user/profile'
| '/user/resetpassword' | '/user/resetpassword'
| '/user/signup' | '/user/signup'
| '/transportation/opendock/releases'
| '/warehouse/dockdoorscanning/$dock' | '/warehouse/dockdoorscanning/$dock'
| '/transportation/opendock' | '/transportation/opendock'
| '/warehouse/dockdoorscanning' | '/warehouse/dockdoorscanning'
@@ -265,6 +277,7 @@ export interface FileRouteTypes {
| '/(auth)/user/profile' | '/(auth)/user/profile'
| '/(auth)/user/resetpassword' | '/(auth)/user/resetpassword'
| '/(auth)/user/signup' | '/(auth)/user/signup'
| '/transportation/opendock/releases'
| '/warehouse/dockdoorscanning/$dock' | '/warehouse/dockdoorscanning/$dock'
| '/transportation/opendock/' | '/transportation/opendock/'
| '/warehouse/dockdoorscanning/' | '/warehouse/dockdoorscanning/'
@@ -288,6 +301,7 @@ export interface RootRouteChildren {
authUserProfileRoute: typeof authUserProfileRoute authUserProfileRoute: typeof authUserProfileRoute
authUserResetpasswordRoute: typeof authUserResetpasswordRoute authUserResetpasswordRoute: typeof authUserResetpasswordRoute
authUserSignupRoute: typeof authUserSignupRoute authUserSignupRoute: typeof authUserSignupRoute
TransportationOpendockReleasesRoute: typeof TransportationOpendockReleasesRoute
WarehouseDockdoorscanningDockRoute: typeof WarehouseDockdoorscanningDockRoute WarehouseDockdoorscanningDockRoute: typeof WarehouseDockdoorscanningDockRoute
TransportationOpendockIndexRoute: typeof TransportationOpendockIndexRoute TransportationOpendockIndexRoute: typeof TransportationOpendockIndexRoute
WarehouseDockdoorscanningIndexRoute: typeof WarehouseDockdoorscanningIndexRoute WarehouseDockdoorscanningIndexRoute: typeof WarehouseDockdoorscanningIndexRoute
@@ -408,6 +422,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof WarehouseDockdoorscanningDockRouteImport preLoaderRoute: typeof WarehouseDockdoorscanningDockRouteImport
parentRoute: typeof rootRouteImport parentRoute: typeof rootRouteImport
} }
'/transportation/opendock/releases': {
id: '/transportation/opendock/releases'
path: '/transportation/opendock/releases'
fullPath: '/transportation/opendock/releases'
preLoaderRoute: typeof TransportationOpendockReleasesRouteImport
parentRoute: typeof rootRouteImport
}
'/(auth)/user/signup': { '/(auth)/user/signup': {
id: '/(auth)/user/signup' id: '/(auth)/user/signup'
path: '/user/signup' path: '/user/signup'
@@ -456,6 +477,7 @@ const rootRouteChildren: RootRouteChildren = {
authUserProfileRoute: authUserProfileRoute, authUserProfileRoute: authUserProfileRoute,
authUserResetpasswordRoute: authUserResetpasswordRoute, authUserResetpasswordRoute: authUserResetpasswordRoute,
authUserSignupRoute: authUserSignupRoute, authUserSignupRoute: authUserSignupRoute,
TransportationOpendockReleasesRoute: TransportationOpendockReleasesRoute,
WarehouseDockdoorscanningDockRoute: WarehouseDockdoorscanningDockRoute, WarehouseDockdoorscanningDockRoute: WarehouseDockdoorscanningDockRoute,
TransportationOpendockIndexRoute: TransportationOpendockIndexRoute, TransportationOpendockIndexRoute: TransportationOpendockIndexRoute,
WarehouseDockdoorscanningIndexRoute: WarehouseDockdoorscanningIndexRoute, WarehouseDockdoorscanningIndexRoute: WarehouseDockdoorscanningIndexRoute,

View File

@@ -0,0 +1,221 @@
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute, redirect } from "@tanstack/react-router";
import { createColumnHelper } from "@tanstack/react-table";
import { formatInTimeZone } from "date-fns-tz";
import { Trash } from "lucide-react";
import { Suspense, useState } from "react";
import { toast } from "sonner";
import { Button } from "../../../components/ui/button";
import { Spinner } from "../../../components/ui/spinner";
import { api } from "../../../lib/apiHelper";
import { authClient } from "../../../lib/auth-client";
import { opendockApt } from "../../../lib/queries/openDockApt";
import { permissionQuery } from "../../../lib/queries/permsCheck";
import LstTable from "../../../lib/tableStuff/LstTable";
import SearchableHeader from "../../../lib/tableStuff/SearchableHeader";
import SkellyTable from "../../../lib/tableStuff/SkellyTable";
export const Route = createFileRoute("/transportation/opendock/releases")({
beforeLoad: async ({ location }) => {
const { data: session } = await authClient.getSession();
//const allowedRole = ["systemAdmin", "admin", "manager"];
const canAccess = await authClient.admin.hasPermission({
permissions: {
openDock: ["create"],
},
});
if (!session?.user) {
throw redirect({
to: "/",
search: {
redirect: location.href,
},
});
}
//if (!allowedRole.includes(session.user.role as string)) {
if (!canAccess) {
throw redirect({
to: "/",
});
}
return { user: session.user };
},
component: RouteComponent,
});
const OpendockApts = () => {
const { data, refetch } = useSuspenseQuery(opendockApt());
const { data: canReadOpenDock = false } = useQuery(
permissionQuery({
openDock: ["update"],
}),
);
const columnHelper = createColumnHelper<any>();
const columns = [
columnHelper.accessor("release", {
header: ({ column }) => (
<SearchableHeader column={column} title="Release" searchable={true} />
),
filterFn: "includesString",
cell: (i) => i.getValue(),
}),
columnHelper.accessor(
(row) =>
row.appointment.customFields.find((x: any) => x.name === "strArticle")
?.value ?? "",
{
id: "article",
header: ({ column }) => (
<SearchableHeader column={column} title="Article" searchable={true} />
),
filterFn: "includesString",
cell: (i) => i.getValue(),
},
),
columnHelper.accessor("appointment.status", {
header: ({ column }) => (
<SearchableHeader
column={column}
title="Current Opendock status"
searchable={true}
/>
),
filterFn: "includesString",
cell: (i) => i.getValue(),
}),
columnHelper.accessor("upd_date", {
header: ({ column }) => (
<SearchableHeader column={column} title="Last Updated" />
),
filterFn: "includesString",
cell: (i) => {
function isDateValid(date: any) {
return date instanceof Date && !isNaN(date.getTime());
}
const trueDate = isDateValid(new Date(i.getValue()))
? formatInTimeZone(
i.getValue(),
`${window.LST_CONFIG?.timezone}`,
"MM/dd/yyyy HH:mm:ss",
)
: "invalid time";
return <span>{trueDate}</span>;
},
}),
];
if (canReadOpenDock) {
columns.push(
columnHelper.accessor("deleteRelease", {
header: ({ column }) => (
<SearchableHeader
column={column}
title="Delete Link"
searchable={false}
/>
),
filterFn: "includesString",
cell: (i) => {
// biome-ignore lint: just removing the lint for now to get this going will maybe fix later
const [activeToggle, setActiveToggle] = useState(false);
const onTrigger = async () => {
setActiveToggle(true);
try {
const res = await api.delete(
`/opendock/${i.row.original.id}`,
{
withCredentials: true,
timeout: 5000,
validateStatus: () => true,
},
);
if (res.data.success) {
toast.success(
`Release: ${i.row.original.release} was deleted.`,
);
refetch();
setActiveToggle(false);
}
if (!res.data.success) {
toast.error(
`Release: ${i.row.original.release} encountered an error when trying to delete: ${res.data.message}`,
);
refetch();
setActiveToggle(false);
}
} catch (error) {
setActiveToggle(false);
console.error(error);
}
};
return (
<div>
<div className="flex items-center space-x-2">
<Button
variant="destructive"
disabled={
activeToggle ||
i.row.original.appointment.status !== "Scheduled"
}
onClick={onTrigger}
>
{activeToggle ? (
<span>
<Spinner />
</span>
) : (
<span>
<Trash />
</span>
)}
</Button>
</div>
</div>
);
},
}),
);
}
return (
<div>
<div>
<div className="flex justify-end m-2">
{/* <Suspense
fallback={
<div>
<p>Loading...</p>
</div>
}
>
<NewArticleLink refetch={refetch} />
</Suspense> */}
</div>
<div>
<LstTable data={data} columns={columns} pageSize={50} />
</div>
</div>
</div>
);
};
function RouteComponent() {
return (
<Suspense fallback={<SkellyTable />}>
<OpendockApts />
</Suspense>
);
}

View File

@@ -68,9 +68,9 @@ function RouteComponent() {
<div className="flex justify-center"> <div className="flex justify-center">
<p>Please select an active loading order for {dockData[0].name}</p> <p>Please select an active loading order for {dockData[0].name}</p>
</div> </div>
<div className="flex justify-center mt-5 gap-2"> <div className="flex flex-row justify-center mt-5 gap-2">
{loadingPlans && loadingPlans.length > 0 ? ( {loadingPlans && loadingPlans.length > 0 ? (
<div> <div className="flex flex-row gap-3">
{loadingPlans.map((i: any) => { {loadingPlans.map((i: any) => {
return ( return (
<Card key={i.id} className="max-w-96"> <Card key={i.id} className="max-w-96">
@@ -140,7 +140,8 @@ function RouteComponent() {
) )
} }
disabled={ disabled={
dockData[0].currentLoadingOrder === "" ? true : false dockData[0].currentLoadingOrder === "" ||
dockData[0].currentLoadingOrder !== i.id.toString()
} }
> >
Finish Loading Finish Loading

View File

@@ -1,4 +1,4 @@
import { useSuspenseQuery } from "@tanstack/react-query"; import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router";
import { createColumnHelper } from "@tanstack/react-table"; import { createColumnHelper } from "@tanstack/react-table";
import { formatInTimeZone } from "date-fns-tz"; import { formatInTimeZone } from "date-fns-tz";
@@ -9,6 +9,7 @@ import { api } from "../../../../lib/apiHelper";
import { useAppForm } from "../../../../lib/formSutff"; import { useAppForm } from "../../../../lib/formSutff";
import { getActiveLoadingOrders } from "../../../../lib/queries/getActiveDockScanners"; import { getActiveLoadingOrders } from "../../../../lib/queries/getActiveDockScanners";
import { getActiveDockScanners } from "../../../../lib/queries/getActiveLoadingOrders"; import { getActiveDockScanners } from "../../../../lib/queries/getActiveLoadingOrders";
import { permissionQuery } from "../../../../lib/queries/permsCheck";
import LstTable from "../../../../lib/tableStuff/LstTable"; import LstTable from "../../../../lib/tableStuff/LstTable";
import SearchableHeader from "../../../../lib/tableStuff/SearchableHeader"; import SearchableHeader from "../../../../lib/tableStuff/SearchableHeader";
import { finishLoadingOrder } from ".."; import { finishLoadingOrder } from "..";
@@ -27,6 +28,12 @@ function RouteComponent() {
const { data, refetch } = useSuspenseQuery(getActiveDockScanners()); const { data, refetch } = useSuspenseQuery(getActiveDockScanners());
const { data: loadingPlanItems, refetch: refetchActiveLoading } = const { data: loadingPlanItems, refetch: refetchActiveLoading } =
useSuspenseQuery(getActiveLoadingOrders()); useSuspenseQuery(getActiveLoadingOrders());
const { data: canReadWarehouse = false } = useQuery(
permissionQuery({
warehouse: ["delete"],
}),
);
const columnHelper = createColumnHelper<any>(); const columnHelper = createColumnHelper<any>();
const column = [ const column = [
@@ -119,6 +126,7 @@ function RouteComponent() {
(x: any) => x.id === Number(data[0].currentLoadingOrder), (x: any) => x.id === Number(data[0].currentLoadingOrder),
) )
: []; : [];
return ( return (
<div> <div>
<div> <div>
@@ -138,7 +146,7 @@ function RouteComponent() {
)} )}
</p> </p>
</div> </div>
<div className="max-w-1/2 flex flex-col"> <div className="flex flex-col">
<div> <div>
<form <form
onSubmit={(e) => { onSubmit={(e) => {
@@ -166,29 +174,32 @@ function RouteComponent() {
</div> </div>
</form> </form>
</div> </div>
{loadingPlan && loadingPlan.length > 0 && (
<div className="flex justify-end mr-3 "> <div className="flex mb-2 gap-2">
<Button <Button
type="button" type="button"
onClick={() => { onClick={() => {
finishLoadingOrder( finishLoadingOrder(
String(data[0].currentLoadingOrder), String(data[0].currentLoadingOrder),
dockScans, dockScans,
refetch, refetch,
refetchActiveLoading, refetchActiveLoading,
); );
clearRoom(); clearRoom();
}} }}
disabled={ disabled={
loadingPlan || (loadingPlan && loadingPlan.length < 0) ||
loadingPlan[0].loadingPlanItems[0].loadedQuantityLUs !== loadingPlan[0].loadingPlanItems[0].loadedQuantityLUs !==
loadingPlan[0].loadingPlanItems[0].plannedQuantityLUs loadingPlan[0].loadingPlanItems[0].plannedQuantityLUs
} }
> >
Finish Loading order Finish Loading order
</Button> </Button>
<Button onClick={() => clearRoom()}>Clear Table</Button> {canReadWarehouse && (
</div> <Button onClick={() => clearRoom()}>Clear Table</Button>
)}
</div>
)}
</div> </div>
<div> <div>
<LstTable data={logs} columns={column} pageSize={50} /> <LstTable data={logs} columns={column} pageSize={50} />

View File

@@ -0,0 +1 @@
ALTER TABLE "opendock_apt" ADD COLUMN "status" text DEFAULT 'active';

File diff suppressed because it is too large Load Diff

View File

@@ -442,6 +442,13 @@
"when": 1781009330205, "when": 1781009330205,
"tag": "0062_square_harrier", "tag": "0062_square_harrier",
"breakpoints": true "breakpoints": true
},
{
"idx": 63,
"version": "7",
"when": 1781045714275,
"tag": "0063_illegal_mauler",
"breakpoints": true
} }
] ]
} }