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
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 1m24s
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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()`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
73
backend/opendock/openDockUndoLastStatus.ts
Normal file
73
backend/opendock/openDockUndoLastStatus.ts
Normal 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;
|
||||||
@@ -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,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
|
||||||
124
backend/opendock/opendockRelease.route.ts
Normal file
124
backend/opendock/opendockRelease.route.ts
Normal 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;
|
||||||
@@ -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",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
23
frontend/src/lib/queries/openDockApt.ts
Normal file
23
frontend/src/lib/queries/openDockApt.ts
Normal 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;
|
||||||
|
};
|
||||||
@@ -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,
|
||||||
|
|||||||
221
frontend/src/routes/transportation/opendock/releases.tsx
Normal file
221
frontend/src/routes/transportation/opendock/releases.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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} />
|
||||||
|
|||||||
1
migrations/0063_illegal_mauler.sql
Normal file
1
migrations/0063_illegal_mauler.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "opendock_apt" ADD COLUMN "status" text DEFAULT 'active';
|
||||||
2696
migrations/meta/0063_snapshot.json
Normal file
2696
migrations/meta/0063_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user