feat(submodules and login redirect): submodules added and login redirect
This commit is contained in:
@@ -23,16 +23,17 @@ export const subModules = pgTable(
|
||||
link: text("link").notNull(),
|
||||
active: boolean("active").default(false),
|
||||
roles: jsonb("roles").notNull().default(["systemAdmin"]), // ["view", "technician", "supervisor","manager", "admin","systemAdmin"]
|
||||
icon: text("icon"),
|
||||
subSubModule: jsonb("subSubModule").default([]),
|
||||
add_User: text("add_User").default("LST_System").notNull(),
|
||||
add_Date: timestamp("add_Date").defaultNow(),
|
||||
upd_user: text("upd_User").default("LST_System").notNull(),
|
||||
upd_date: timestamp("upd_date").defaultNow(),
|
||||
}
|
||||
// (table) => [
|
||||
// // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||
// uniqueIndex("subModule_name").on(table.name),
|
||||
// ]
|
||||
},
|
||||
(table) => [
|
||||
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||
uniqueIndex("subModule_name").on(table.name),
|
||||
]
|
||||
);
|
||||
|
||||
// Schema for inserting a user - can be used to validate API requests
|
||||
|
||||
@@ -3,7 +3,7 @@ import { LstCard } from "../extendedUI/LstCard";
|
||||
import { CardHeader } from "../ui/card";
|
||||
import { toast } from "sonner";
|
||||
import { z } from "zod";
|
||||
import { useRouter } from "@tanstack/react-router";
|
||||
import { useRouter, useSearch } from "@tanstack/react-router";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Label } from "../ui/label";
|
||||
@@ -12,153 +12,160 @@ import { Checkbox } from "../ui/checkbox";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
const FormSchema = z.object({
|
||||
username: z.string().min(1, "You must enter a valid username"),
|
||||
password: z.string().min(4, "You must enter a valid password"),
|
||||
rememberMe: z.boolean(),
|
||||
username: z.string().min(1, "You must enter a valid username"),
|
||||
password: z.string().min(4, "You must enter a valid password"),
|
||||
rememberMe: z.boolean(),
|
||||
});
|
||||
|
||||
const LoginForm = () => {
|
||||
const { setSession } = useSessionStore();
|
||||
const rememeberMe = localStorage.getItem("rememberMe") === "true";
|
||||
const username = localStorage.getItem("username") || "";
|
||||
const router = useRouter();
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
control,
|
||||
formState: { errors },
|
||||
} = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
username: username || "",
|
||||
password: "",
|
||||
rememberMe: rememeberMe,
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => {
|
||||
// Do something with form data
|
||||
|
||||
// first update the rememberMe incase it was selected
|
||||
if (value.rememberMe) {
|
||||
localStorage.setItem("rememberMe", value.rememberMe.toString());
|
||||
localStorage.setItem("username", value.username);
|
||||
} else {
|
||||
localStorage.removeItem("rememberMe");
|
||||
localStorage.removeItem("username");
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/auth/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
const { setSession } = useSessionStore();
|
||||
const rememeberMe = localStorage.getItem("rememberMe") === "true";
|
||||
const username = localStorage.getItem("username") || "";
|
||||
const router = useRouter();
|
||||
const search = useSearch({ from: "/login" });
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
control,
|
||||
formState: { errors },
|
||||
} = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
username: username || "",
|
||||
password: "",
|
||||
rememberMe: rememeberMe,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: value.username,
|
||||
password: value.password,
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
const onSubmitLogin = async (value: z.infer<typeof FormSchema>) => {
|
||||
// Do something with form data
|
||||
|
||||
// Store token in localStorage
|
||||
// localStorage.setItem("auth_token", data.data.token);
|
||||
if (data.success) {
|
||||
const prod = btoa(`${value.username.toLowerCase()}:${value.password}`);
|
||||
const prodUser = { ...data.user, prod: prod };
|
||||
// first update the rememberMe incase it was selected
|
||||
if (value.rememberMe) {
|
||||
localStorage.setItem("rememberMe", value.rememberMe.toString());
|
||||
localStorage.setItem("username", value.username);
|
||||
} else {
|
||||
localStorage.removeItem("rememberMe");
|
||||
localStorage.removeItem("username");
|
||||
}
|
||||
|
||||
setSession(prodUser, data.token);
|
||||
toast.success(`You are logged in as ${data.user.username}`);
|
||||
router.navigate({ to: "/" });
|
||||
}
|
||||
try {
|
||||
const response = await fetch("/api/auth/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: value.username,
|
||||
password: value.password,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!data.success) {
|
||||
toast.error(`${data.message}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
|
||||
//console.log(data);
|
||||
} catch (err) {
|
||||
toast.error("Invalid credentials");
|
||||
}
|
||||
};
|
||||
// Store token in localStorage
|
||||
// localStorage.setItem("auth_token", data.data.token);
|
||||
if (data.success) {
|
||||
const prod = btoa(
|
||||
`${value.username.toLowerCase()}:${value.password}`
|
||||
);
|
||||
const prodUser = { ...data.user, prod: prod };
|
||||
|
||||
return (
|
||||
<div className="ml-[25%]">
|
||||
<LstCard className="p-3 w-96">
|
||||
<CardHeader>
|
||||
<div>
|
||||
<p className="text-2xl">Login to LST</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<hr className="rounded"></hr>
|
||||
<form onSubmit={handleSubmit(onSubmitLogin)}>
|
||||
<div>
|
||||
<Label htmlFor="username" className="m-1">
|
||||
Username
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="smith001"
|
||||
{...register("username")}
|
||||
className={errors.username ? "border-red-500" : ""}
|
||||
aria-invalid={!!errors.username}
|
||||
/>
|
||||
{errors.username && (
|
||||
<p className="text-red-500 text-sm mt-1">
|
||||
{errors.username.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<>
|
||||
<Label htmlFor={"password"} className="m-1">
|
||||
Password
|
||||
</Label>
|
||||
<Input
|
||||
type="password"
|
||||
{...register("password")}
|
||||
className={errors.password ? "border-red-500" : ""}
|
||||
aria-invalid={!!errors.password}
|
||||
/>
|
||||
{errors.password && (
|
||||
<p className="text-red-500 text-sm mt-1">
|
||||
{errors.password.message}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
<div className="flex justify-between pt-2">
|
||||
<div className="flex">
|
||||
<Controller
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<Checkbox
|
||||
id="remember"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<label
|
||||
htmlFor="remember"
|
||||
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
remember me
|
||||
</label>
|
||||
</>
|
||||
)}
|
||||
control={control}
|
||||
name="rememberMe"
|
||||
defaultValue={rememeberMe}
|
||||
/>
|
||||
</div>
|
||||
setSession(prodUser, data.token);
|
||||
toast.success(`You are logged in as ${data.user.username}`);
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">Submit</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
console.log(search.redirect ? search.redirect : "oops");
|
||||
router.history.push(search.redirect ? search.redirect : "/");
|
||||
}
|
||||
|
||||
if (!data.success) {
|
||||
toast.error(`${data.message}`);
|
||||
}
|
||||
|
||||
//console.log(data);
|
||||
} catch (err) {
|
||||
toast.error("Invalid credentials");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="ml-[25%]">
|
||||
<LstCard className="p-3 w-96">
|
||||
<CardHeader>
|
||||
<div>
|
||||
<p className="text-2xl">Login to LST</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<hr className="rounded"></hr>
|
||||
<form onSubmit={handleSubmit(onSubmitLogin)}>
|
||||
<div>
|
||||
<Label htmlFor="username" className="m-1">
|
||||
Username
|
||||
</Label>
|
||||
<Input
|
||||
placeholder="smith001"
|
||||
{...register("username")}
|
||||
className={errors.username ? "border-red-500" : ""}
|
||||
aria-invalid={!!errors.username}
|
||||
/>
|
||||
{errors.username && (
|
||||
<p className="text-red-500 text-sm mt-1">
|
||||
{errors.username.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<>
|
||||
<Label htmlFor={"password"} className="m-1">
|
||||
Password
|
||||
</Label>
|
||||
<Input
|
||||
type="password"
|
||||
{...register("password")}
|
||||
className={
|
||||
errors.password ? "border-red-500" : ""
|
||||
}
|
||||
aria-invalid={!!errors.password}
|
||||
/>
|
||||
{errors.password && (
|
||||
<p className="text-red-500 text-sm mt-1">
|
||||
{errors.password.message}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
<div className="flex justify-between pt-2">
|
||||
<div className="flex">
|
||||
<Controller
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<Checkbox
|
||||
id="remember"
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<label
|
||||
htmlFor="remember"
|
||||
className="pl-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
remember me
|
||||
</label>
|
||||
</>
|
||||
)}
|
||||
control={control}
|
||||
name="rememberMe"
|
||||
defaultValue={rememeberMe}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button type="submit">Submit</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</LstCard>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginForm;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Cylinder, Package, Truck } from "lucide-react";
|
||||
//import { Cylinder, Package, Truck } from "lucide-react";
|
||||
import {
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
@@ -9,67 +9,68 @@ import {
|
||||
} from "../../ui/sidebar";
|
||||
import { hasPageAccess } from "@/utils/userAccess";
|
||||
import { User } from "@/types/users";
|
||||
import { useSubModuleStore } from "@/lib/store/useSubModuleStore";
|
||||
// this will need to be moved to a links section the db to make it more easy to remove and add
|
||||
const items = [
|
||||
{
|
||||
title: "Silo Adjustments",
|
||||
url: "#",
|
||||
icon: Cylinder,
|
||||
role: ["admin", "systemAdmin"],
|
||||
module: "logistics",
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
name: "Bulk orders",
|
||||
moduleName: "logistics",
|
||||
description: "",
|
||||
link: "#",
|
||||
icon: Truck,
|
||||
role: ["systemAdmin"],
|
||||
active: true,
|
||||
subSubModule: [],
|
||||
},
|
||||
{
|
||||
name: "Forecast",
|
||||
moduleName: "logistics",
|
||||
description: "",
|
||||
link: "#",
|
||||
icon: Truck,
|
||||
role: ["systemAdmin"],
|
||||
active: true,
|
||||
subSubModule: [],
|
||||
},
|
||||
{
|
||||
name: "Ocme cycle counts",
|
||||
moduleName: "logistics",
|
||||
description: "",
|
||||
link: "#",
|
||||
icon: Package,
|
||||
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||
active: false,
|
||||
subSubModule: [],
|
||||
},
|
||||
{
|
||||
name: "Material Helper",
|
||||
moduleName: "logistics",
|
||||
description: "",
|
||||
link: "/materialHelper/consumption",
|
||||
icon: Package,
|
||||
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||
active: true,
|
||||
subSubModule: [],
|
||||
},
|
||||
{
|
||||
name: "Ocme Cyclecount",
|
||||
moduleName: "logistics",
|
||||
description: "",
|
||||
link: "/cyclecount",
|
||||
icon: Package,
|
||||
role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||
active: true,
|
||||
subSubModule: [],
|
||||
},
|
||||
];
|
||||
// const items = [
|
||||
// {
|
||||
// title: "Silo Adjustments",
|
||||
// url: "#",
|
||||
// icon: Cylinder,
|
||||
// role: ["admin", "systemAdmin"],
|
||||
// module: "logistics",
|
||||
// active: true,
|
||||
// },
|
||||
// {
|
||||
// name: "Bulk orders",
|
||||
// moduleName: "logistics",
|
||||
// description: "",
|
||||
// link: "#",
|
||||
// icon: Truck,
|
||||
// role: ["systemAdmin"],
|
||||
// active: true,
|
||||
// subSubModule: [],
|
||||
// },
|
||||
// {
|
||||
// name: "Forecast",
|
||||
// moduleName: "logistics",
|
||||
// description: "",
|
||||
// link: "#",
|
||||
// icon: Truck,
|
||||
// role: ["systemAdmin"],
|
||||
// active: true,
|
||||
// subSubModule: [],
|
||||
// },
|
||||
// {
|
||||
// name: "Ocme cycle counts",
|
||||
// moduleName: "logistics",
|
||||
// description: "",
|
||||
// link: "#",
|
||||
// icon: Package,
|
||||
// role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||
// active: false,
|
||||
// subSubModule: [],
|
||||
// },
|
||||
// {
|
||||
// name: "Material Helper",
|
||||
// moduleName: "logistics",
|
||||
// description: "",
|
||||
// link: "/materialHelper/consumption",
|
||||
// icon: Package,
|
||||
// role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||
// active: true,
|
||||
// subSubModule: [],
|
||||
// },
|
||||
// {
|
||||
// name: "Ocme Cyclecount",
|
||||
// moduleName: "logistics",
|
||||
// description: "",
|
||||
// link: "/cyclecount",
|
||||
// icon: Package,
|
||||
// role: ["technician", "supervisor", "manager", "admin", "systemAdmin"],
|
||||
// active: true,
|
||||
// subSubModule: [],
|
||||
// },
|
||||
// ];
|
||||
|
||||
export function LogisticsSideBar({
|
||||
user,
|
||||
@@ -78,26 +79,35 @@ export function LogisticsSideBar({
|
||||
user: User | null;
|
||||
moduleID: string;
|
||||
}) {
|
||||
const { subModules } = useSubModuleStore();
|
||||
|
||||
const items = subModules.filter((m) => m.moduleName === "logistics");
|
||||
console.log(items);
|
||||
return (
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Logistics</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{items.map((item) => (
|
||||
<SidebarMenuItem key={item.title}>
|
||||
<>
|
||||
{hasPageAccess(user, item.role, moduleID) &&
|
||||
item.active && (
|
||||
<SidebarMenuButton asChild>
|
||||
<a href={item.url}>
|
||||
<item.icon />
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
)}
|
||||
</>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
{items.map((item) => {
|
||||
return (
|
||||
<SidebarMenuItem key={item.submodule_id}>
|
||||
<>
|
||||
{hasPageAccess(
|
||||
user,
|
||||
item.roles,
|
||||
moduleID
|
||||
) &&
|
||||
item.active && (
|
||||
<SidebarMenuButton asChild>
|
||||
<a href={item.link}>
|
||||
<span>{item.name}</span>
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
)}
|
||||
</>
|
||||
</SidebarMenuItem>
|
||||
);
|
||||
})}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useModuleStore } from "../../lib/store/useModuleStore";
|
||||
import { useEffect } from "react";
|
||||
import { useSettingStore } from "@/lib/store/useSettings";
|
||||
import { useGetUserRoles } from "@/lib/store/useGetRoles";
|
||||
import { useSubModuleStore } from "@/lib/store/useSubModuleStore";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@@ -14,11 +15,13 @@ export const SessionProvider = ({
|
||||
const { fetchModules } = useModuleStore();
|
||||
const { fetchSettings } = useSettingStore();
|
||||
const { fetchUserRoles } = useGetUserRoles();
|
||||
const { fetchSubModules } = useSubModuleStore();
|
||||
|
||||
useEffect(() => {
|
||||
fetchModules();
|
||||
fetchSettings();
|
||||
fetchUserRoles();
|
||||
fetchSubModules();
|
||||
}, []);
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
|
||||
30
frontend/src/lib/store/useSubModuleStore.ts
Normal file
30
frontend/src/lib/store/useSubModuleStore.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { SubModules } from "@/types/modules";
|
||||
import axios from "axios";
|
||||
import { create } from "zustand";
|
||||
|
||||
interface SettingState {
|
||||
subModules: SubModules[];
|
||||
|
||||
fetchSubModules: () => Promise<void>;
|
||||
setSubModules: (modules: SubModules[]) => void;
|
||||
}
|
||||
interface FetchModulesResponse {
|
||||
data: SubModules[];
|
||||
}
|
||||
|
||||
export const useSubModuleStore = create<SettingState>()((set) => ({
|
||||
subModules: [],
|
||||
setSubModules: (subModules) => set({ subModules }),
|
||||
fetchSubModules: async () => {
|
||||
try {
|
||||
//const response = await axios.get<{data: Setting[]}>(`${process.env.NEXT_PUBLIC_URL}/api/settings/client`);
|
||||
const response = await axios.get(`/api/server/submodules`, {});
|
||||
const data: FetchModulesResponse = response.data; //await response.json();
|
||||
//console.log(data);
|
||||
set({ subModules: data.data });
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch settings:", error);
|
||||
set({ subModules: [] });
|
||||
}
|
||||
},
|
||||
}));
|
||||
@@ -25,10 +25,12 @@ import { Route as AdminSettingsImport } from './routes/_admin/settings'
|
||||
import { Route as AdminServersImport } from './routes/_admin/servers'
|
||||
import { Route as AdminModulesImport } from './routes/_admin/modules'
|
||||
import { Route as ocmeCyclecountIndexImport } from './routes/(ocme)/cyclecount/index'
|
||||
import { Route as logisticsSiloAdjustmentsIndexImport } from './routes/(logistics)/siloAdjustments/index'
|
||||
import { Route as logisticsMaterialHelperIndexImport } from './routes/(logistics)/materialHelper/index'
|
||||
import { Route as EomArticleAvImport } from './routes/_eom/article/$av'
|
||||
import { Route as logisticsMaterialHelperSiloLinkIndexImport } from './routes/(logistics)/materialHelper/siloLink/index'
|
||||
import { Route as logisticsMaterialHelperConsumptionIndexImport } from './routes/(logistics)/materialHelper/consumption/index'
|
||||
import { Route as logisticsSiloAdjustmentsCommentCommentImport } from './routes/(logistics)/siloAdjustments/comment/$comment'
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
@@ -113,6 +115,13 @@ const ocmeCyclecountIndexRoute = ocmeCyclecountIndexImport.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const logisticsSiloAdjustmentsIndexRoute =
|
||||
logisticsSiloAdjustmentsIndexImport.update({
|
||||
id: '/(logistics)/siloAdjustments/',
|
||||
path: '/siloAdjustments/',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const logisticsMaterialHelperIndexRoute =
|
||||
logisticsMaterialHelperIndexImport.update({
|
||||
id: '/(logistics)/materialHelper/',
|
||||
@@ -140,6 +149,13 @@ const logisticsMaterialHelperConsumptionIndexRoute =
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const logisticsSiloAdjustmentsCommentCommentRoute =
|
||||
logisticsSiloAdjustmentsCommentCommentImport.update({
|
||||
id: '/(logistics)/siloAdjustments/comment/$comment',
|
||||
path: '/siloAdjustments/comment/$comment',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
// Populate the FileRoutesByPath interface
|
||||
|
||||
declare module '@tanstack/react-router' {
|
||||
@@ -249,6 +265,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof logisticsMaterialHelperIndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/(logistics)/siloAdjustments/': {
|
||||
id: '/(logistics)/siloAdjustments/'
|
||||
path: '/siloAdjustments'
|
||||
fullPath: '/siloAdjustments'
|
||||
preLoaderRoute: typeof logisticsSiloAdjustmentsIndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/(ocme)/cyclecount/': {
|
||||
id: '/(ocme)/cyclecount/'
|
||||
path: '/cyclecount'
|
||||
@@ -256,6 +279,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof ocmeCyclecountIndexImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/(logistics)/siloAdjustments/comment/$comment': {
|
||||
id: '/(logistics)/siloAdjustments/comment/$comment'
|
||||
path: '/siloAdjustments/comment/$comment'
|
||||
fullPath: '/siloAdjustments/comment/$comment'
|
||||
preLoaderRoute: typeof logisticsSiloAdjustmentsCommentCommentImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/(logistics)/materialHelper/consumption/': {
|
||||
id: '/(logistics)/materialHelper/consumption/'
|
||||
path: '/materialHelper/consumption'
|
||||
@@ -327,7 +357,9 @@ export interface FileRoutesByFullPath {
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||
'/siloAdjustments': typeof logisticsSiloAdjustmentsIndexRoute
|
||||
'/cyclecount': typeof ocmeCyclecountIndexRoute
|
||||
'/siloAdjustments/comment/$comment': typeof logisticsSiloAdjustmentsCommentCommentRoute
|
||||
'/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||
'/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||
}
|
||||
@@ -346,7 +378,9 @@ export interface FileRoutesByTo {
|
||||
'/ocp': typeof OcpIndexRoute
|
||||
'/article/$av': typeof EomArticleAvRoute
|
||||
'/materialHelper': typeof logisticsMaterialHelperIndexRoute
|
||||
'/siloAdjustments': typeof logisticsSiloAdjustmentsIndexRoute
|
||||
'/cyclecount': typeof ocmeCyclecountIndexRoute
|
||||
'/siloAdjustments/comment/$comment': typeof logisticsSiloAdjustmentsCommentCommentRoute
|
||||
'/materialHelper/consumption': typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||
'/materialHelper/siloLink': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||
}
|
||||
@@ -368,7 +402,9 @@ export interface FileRoutesById {
|
||||
'/ocp/': typeof OcpIndexRoute
|
||||
'/_eom/article/$av': typeof EomArticleAvRoute
|
||||
'/(logistics)/materialHelper/': typeof logisticsMaterialHelperIndexRoute
|
||||
'/(logistics)/siloAdjustments/': typeof logisticsSiloAdjustmentsIndexRoute
|
||||
'/(ocme)/cyclecount/': typeof ocmeCyclecountIndexRoute
|
||||
'/(logistics)/siloAdjustments/comment/$comment': typeof logisticsSiloAdjustmentsCommentCommentRoute
|
||||
'/(logistics)/materialHelper/consumption/': typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||
'/(logistics)/materialHelper/siloLink/': typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||
}
|
||||
@@ -389,7 +425,9 @@ export interface FileRouteTypes {
|
||||
| '/ocp'
|
||||
| '/article/$av'
|
||||
| '/materialHelper'
|
||||
| '/siloAdjustments'
|
||||
| '/cyclecount'
|
||||
| '/siloAdjustments/comment/$comment'
|
||||
| '/materialHelper/consumption'
|
||||
| '/materialHelper/siloLink'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
@@ -407,7 +445,9 @@ export interface FileRouteTypes {
|
||||
| '/ocp'
|
||||
| '/article/$av'
|
||||
| '/materialHelper'
|
||||
| '/siloAdjustments'
|
||||
| '/cyclecount'
|
||||
| '/siloAdjustments/comment/$comment'
|
||||
| '/materialHelper/consumption'
|
||||
| '/materialHelper/siloLink'
|
||||
id:
|
||||
@@ -427,7 +467,9 @@ export interface FileRouteTypes {
|
||||
| '/ocp/'
|
||||
| '/_eom/article/$av'
|
||||
| '/(logistics)/materialHelper/'
|
||||
| '/(logistics)/siloAdjustments/'
|
||||
| '/(ocme)/cyclecount/'
|
||||
| '/(logistics)/siloAdjustments/comment/$comment'
|
||||
| '/(logistics)/materialHelper/consumption/'
|
||||
| '/(logistics)/materialHelper/siloLink/'
|
||||
fileRoutesById: FileRoutesById
|
||||
@@ -442,7 +484,9 @@ export interface RootRouteChildren {
|
||||
LoginRoute: typeof LoginRoute
|
||||
OcpIndexRoute: typeof OcpIndexRoute
|
||||
logisticsMaterialHelperIndexRoute: typeof logisticsMaterialHelperIndexRoute
|
||||
logisticsSiloAdjustmentsIndexRoute: typeof logisticsSiloAdjustmentsIndexRoute
|
||||
ocmeCyclecountIndexRoute: typeof ocmeCyclecountIndexRoute
|
||||
logisticsSiloAdjustmentsCommentCommentRoute: typeof logisticsSiloAdjustmentsCommentCommentRoute
|
||||
logisticsMaterialHelperConsumptionIndexRoute: typeof logisticsMaterialHelperConsumptionIndexRoute
|
||||
logisticsMaterialHelperSiloLinkIndexRoute: typeof logisticsMaterialHelperSiloLinkIndexRoute
|
||||
}
|
||||
@@ -456,7 +500,10 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
LoginRoute: LoginRoute,
|
||||
OcpIndexRoute: OcpIndexRoute,
|
||||
logisticsMaterialHelperIndexRoute: logisticsMaterialHelperIndexRoute,
|
||||
logisticsSiloAdjustmentsIndexRoute: logisticsSiloAdjustmentsIndexRoute,
|
||||
ocmeCyclecountIndexRoute: ocmeCyclecountIndexRoute,
|
||||
logisticsSiloAdjustmentsCommentCommentRoute:
|
||||
logisticsSiloAdjustmentsCommentCommentRoute,
|
||||
logisticsMaterialHelperConsumptionIndexRoute:
|
||||
logisticsMaterialHelperConsumptionIndexRoute,
|
||||
logisticsMaterialHelperSiloLinkIndexRoute:
|
||||
@@ -481,7 +528,9 @@ export const routeTree = rootRoute
|
||||
"/login",
|
||||
"/ocp/",
|
||||
"/(logistics)/materialHelper/",
|
||||
"/(logistics)/siloAdjustments/",
|
||||
"/(ocme)/cyclecount/",
|
||||
"/(logistics)/siloAdjustments/comment/$comment",
|
||||
"/(logistics)/materialHelper/consumption/",
|
||||
"/(logistics)/materialHelper/siloLink/"
|
||||
]
|
||||
@@ -551,9 +600,15 @@ export const routeTree = rootRoute
|
||||
"/(logistics)/materialHelper/": {
|
||||
"filePath": "(logistics)/materialHelper/index.tsx"
|
||||
},
|
||||
"/(logistics)/siloAdjustments/": {
|
||||
"filePath": "(logistics)/siloAdjustments/index.tsx"
|
||||
},
|
||||
"/(ocme)/cyclecount/": {
|
||||
"filePath": "(ocme)/cyclecount/index.tsx"
|
||||
},
|
||||
"/(logistics)/siloAdjustments/comment/$comment": {
|
||||
"filePath": "(logistics)/siloAdjustments/comment/$comment.tsx"
|
||||
},
|
||||
"/(logistics)/materialHelper/consumption/": {
|
||||
"filePath": "(logistics)/materialHelper/consumption/index.tsx"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/(logistics)/siloAdjustments/')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/(logistics)/siloAdjustments/"!</div>
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import {createFileRoute, redirect} from "@tanstack/react-router";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
|
||||
// src/routes/_authenticated.tsx
|
||||
export const Route = createFileRoute("/_admin")({
|
||||
@@ -7,6 +7,12 @@ export const Route = createFileRoute("/_admin")({
|
||||
if (!auth) {
|
||||
throw redirect({
|
||||
to: "/login",
|
||||
search: {
|
||||
// Use the current location to power a redirect after login
|
||||
// (Do not use `router.state.resolvedLocation` as it can
|
||||
// potentially lag behind the actual current location)
|
||||
redirect: location.pathname + location.search,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {createFileRoute, redirect} from "@tanstack/react-router";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
|
||||
// src/routes/_authenticated.tsx
|
||||
export const Route = createFileRoute("/_auth")({
|
||||
@@ -7,6 +7,12 @@ export const Route = createFileRoute("/_auth")({
|
||||
if (!auth) {
|
||||
throw redirect({
|
||||
to: "/login",
|
||||
search: {
|
||||
// Use the current location to power a redirect after login
|
||||
// (Do not use `router.state.resolvedLocation` as it can
|
||||
// potentially lag behind the actual current location)
|
||||
redirect: location.href,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {createFileRoute, redirect} from "@tanstack/react-router";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
|
||||
import LoginForm from "@/components/auth/LoginForm";
|
||||
import { z } from "zod";
|
||||
|
||||
export const Route = createFileRoute("/login")({
|
||||
component: RouteComponent,
|
||||
@@ -12,6 +13,9 @@ export const Route = createFileRoute("/login")({
|
||||
});
|
||||
}
|
||||
},
|
||||
validateSearch: z.object({
|
||||
redirect: z.string().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
|
||||
@@ -8,3 +8,13 @@ export interface Modules {
|
||||
upd_user: string;
|
||||
upd_date: Date;
|
||||
}
|
||||
|
||||
export interface SubModules {
|
||||
submodule_id: string;
|
||||
name: string;
|
||||
link: string;
|
||||
icon: string;
|
||||
moduleName: string;
|
||||
active: boolean;
|
||||
roles: string[];
|
||||
}
|
||||
|
||||
@@ -2,9 +2,18 @@ import { OpenAPIHono } from "@hono/zod-openapi";
|
||||
|
||||
import comsumeMaterial from "./route/consumeMaterial.js";
|
||||
import returnMat from "./route/returnMaterial.js";
|
||||
import createSiloAdjustment from "./route/siloAdjustments/createSiloAdjustment.js";
|
||||
import postComment from "./route/siloAdjustments/postComment.js";
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const routes = [comsumeMaterial, returnMat] as const;
|
||||
const routes = [
|
||||
comsumeMaterial,
|
||||
returnMat,
|
||||
|
||||
// silo
|
||||
createSiloAdjustment,
|
||||
postComment,
|
||||
] as const;
|
||||
|
||||
// app.route("/server", modules);
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
|
||||
73
server/services/server/route/modules/getSubModules.ts
Normal file
73
server/services/server/route/modules/getSubModules.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
|
||||
import { modules } from "../../../../../database/schema/modules.js";
|
||||
import { db } from "../../../../../database/dbclient.js";
|
||||
import { subModules } from "../../../../../database/schema/subModules.js";
|
||||
|
||||
// Define the request body schema
|
||||
const requestSchema = z.object({
|
||||
ip: z.string().optional(),
|
||||
endpoint: z.string().optional(),
|
||||
action: z.string().optional(),
|
||||
stats: z.string().optional(),
|
||||
});
|
||||
|
||||
// Define the response schema
|
||||
const responseSchema = z.object({
|
||||
message: z.string().optional(),
|
||||
module_id: z
|
||||
.string()
|
||||
.openapi({ example: "6c922c6c-7de3-4ec4-acb0-f068abdc" })
|
||||
.optional(),
|
||||
name: z.string().openapi({ example: "Production" }).optional(),
|
||||
active: z.boolean().openapi({ example: true }).optional(),
|
||||
roles: z
|
||||
.string()
|
||||
.openapi({ example: `["viewer","technician"]` })
|
||||
.optional(),
|
||||
});
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["server"],
|
||||
summary: "Returns all submodules in the server",
|
||||
method: "get",
|
||||
path: "/submodules",
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": { schema: responseSchema },
|
||||
},
|
||||
description: "Response message",
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
//console.log("system modules");
|
||||
let module: any = [];
|
||||
try {
|
||||
module = await db.select().from(subModules); // .where(eq(modules.active, true));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
module = [];
|
||||
}
|
||||
|
||||
// parse the roles
|
||||
const updateModules = module.map((m: any) => {
|
||||
if (m.roles) {
|
||||
return { ...m, roles: m?.roles };
|
||||
}
|
||||
return m;
|
||||
}); //JSON.parse(module[0]?.roles);
|
||||
|
||||
// Return response with the received data
|
||||
|
||||
return c.json({
|
||||
message: `All active submodules`,
|
||||
data: module,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export default app;
|
||||
@@ -15,6 +15,7 @@ import updateServer from "./route/updates/updateServer.js";
|
||||
import { setPerms } from "./utils/testServerPerms.js";
|
||||
import serviceControl from "./route/servers/serverContorl.js";
|
||||
import { areSubModulesIn } from "./utils/subModuleCheck.js";
|
||||
import getSubmodules from "./route/modules/getSubModules.js";
|
||||
|
||||
// making sure all modules are in properly
|
||||
setTimeout(async () => {
|
||||
@@ -31,6 +32,7 @@ const routes = [
|
||||
getModules,
|
||||
updateModule,
|
||||
addModule,
|
||||
getSubmodules,
|
||||
// settings
|
||||
addSetting,
|
||||
getSettings,
|
||||
|
||||
@@ -12,7 +12,7 @@ const newSubModules = [
|
||||
name: "Silo Adjustmnet",
|
||||
moduleName: "logistics",
|
||||
description: "Do a silo adjustmnet",
|
||||
link: "/sa",
|
||||
link: "/siloAdjustments",
|
||||
icon: "Cylinder",
|
||||
active: false,
|
||||
roles: ["tester", "systemAdmin"],
|
||||
@@ -156,6 +156,7 @@ export const areSubModulesIn = async () => {
|
||||
roles: newSubModules[i].roles,
|
||||
link: newSubModules[i].link,
|
||||
subSubModule: newSubModules[i].subSubModule,
|
||||
icon: newSubModules[i].icon,
|
||||
},
|
||||
}) // this will only update the ones that are new :D
|
||||
.returning({ name: subModules.name });
|
||||
@@ -167,6 +168,7 @@ export const areSubModulesIn = async () => {
|
||||
"SubModules were just added due to missing them on server startup"
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
createLog(
|
||||
"error",
|
||||
"lst",
|
||||
|
||||
Reference in New Issue
Block a user