From 46cdcbaf5c0459d0d6c8c08f3b2b2a1af42dfd3e Mon Sep 17 00:00:00 2001 From: Icedsoda <29167146+1cedsoda@users.noreply.github.com> Date: Wed, 12 Mar 2025 23:18:04 +0100 Subject: [PATCH] add Winder tab - use generic icons in bars - add useMachines hooks --- electron/src/components/Page.tsx | 5 ++- electron/src/components/SidebarLayout.tsx | 29 ++++++------ electron/src/components/Topbar.tsx | 16 ++----- electron/src/hooks/useMachines.tsx | 44 +++++++++++++++++++ electron/src/machines/types.ts | 31 ++++++++++--- .../machines/winder1/Winder1ControlPage.tsx | 8 ++++ electron/src/machines/winder1/Winder1Page.tsx | 17 ++++--- electron/src/routes/router.tsx | 2 +- electron/src/routes/routes.tsx | 30 ++++++------- electron/src/setup/DeviceEepromDialog.tsx | 2 +- electron/src/setup/EthercatPage.tsx | 5 ++- electron/src/setup/MachinesPage.tsx | 9 ++-- electron/src/setup/SetupPage.tsx | 5 +-- 13 files changed, 139 insertions(+), 64 deletions(-) create mode 100644 electron/src/hooks/useMachines.tsx create mode 100644 electron/src/machines/winder1/Winder1ControlPage.tsx diff --git a/electron/src/components/Page.tsx b/electron/src/components/Page.tsx index d0b04d54..b89fcaa2 100644 --- a/electron/src/components/Page.tsx +++ b/electron/src/components/Page.tsx @@ -1,8 +1,9 @@ +import React from "react"; + type Props = { children: React.ReactNode; - title?: string; }; export function Page({ children }: Props) { - return
{children}
; + return
{children}
; } diff --git a/electron/src/components/SidebarLayout.tsx b/electron/src/components/SidebarLayout.tsx index b0f9dab2..55c8fb70 100644 --- a/electron/src/components/SidebarLayout.tsx +++ b/electron/src/components/SidebarLayout.tsx @@ -1,14 +1,15 @@ import { OutsideCorner } from "@/components/OutsideCorner"; +import { useMachines } from "@/hooks/useMachines"; import { useOnSubpath } from "@/hooks/useOnSubpath"; import { Link, Outlet } from "@tanstack/react-router"; -import { Wrench } from "lucide-react"; import { Fragment } from "react"; import React from "react"; +import { Icon, IconName } from "./Icon"; type SidebarItemContent = { link: string; activeLink: string; - icon?: React.ReactNode; + icon?: IconName; title: string; }; @@ -31,10 +32,10 @@ export function SidebarItem({ >
- {icon} + {icon && } {title}
{isActive && } @@ -43,26 +44,28 @@ export function SidebarItem({ } export function SidebarLayout() { + const machines = useMachines(); const items: SidebarItemContent[] = [ - { - link: "/_sidebar/machines/123", - activeLink: "/_sidebar/machines/123", - title: "Winder 123", - }, + ...machines.map((machine) => ({ + link: `/_sidebar/machines/${machine.slug}/${machine.machine_identification.serial}/control`, + activeLink: `/_sidebar/machines/${machine.slug}/${machine.machine_identification.serial}`, + title: machine.name, + icon: machine.icon, + })), { link: "/_sidebar/setup/ethercat", activeLink: "/_sidebar/setup", title: "Setup", - icon: , + icon: "lu:Settings2", }, ]; return (
-
-
+
+
-
QiTech
+
QITECH
{items.map((item, index) => ( diff --git a/electron/src/components/Topbar.tsx b/electron/src/components/Topbar.tsx index 2f6d098d..231b2e78 100644 --- a/electron/src/components/Topbar.tsx +++ b/electron/src/components/Topbar.tsx @@ -4,21 +4,11 @@ import { OutsideCorner } from "./OutsideCorner"; import { BackButton } from "./BackButton"; import { Link, Outlet } from "@tanstack/react-router"; import { useOnSubpath } from "@/hooks/useOnSubpath"; - -// type TopbarItemProps = { -// icon?: React.ReactNode; -// title: string; -// } & SidebarButtonBuilderProps; - -// export type SidebarButtonBuilderProps = { -// isActive: boolean; -// isFirst: boolean; -// onClick: () => void; -// }; +import { Icon, IconName } from "./Icon"; type TopbarItemContent = { link: string; - icon?: React.ReactNode; + icon?: IconName; title: string; }; @@ -32,7 +22,7 @@ export function TopbarItem({ icon, title, link }: TopbarItemProps) { isActive ? "rounded-t-lg bg-white pb-2" : "rounded-lg bg-neutral-100" }`} > - {icon} + {icon && } {title}
diff --git a/electron/src/hooks/useMachines.tsx b/electron/src/hooks/useMachines.tsx new file mode 100644 index 00000000..8d937768 --- /dev/null +++ b/electron/src/hooks/useMachines.tsx @@ -0,0 +1,44 @@ +import { + getVendorPreset, + getMachinePreset, + MachinePreset, + VendorPreset, +} from "@/machines/types"; +import { + EthercatSetupEventMachineInfo, + useSocketioEthercatSetupEvent, +} from "./useSocketio"; + +type UseMachine = { + machine_identification: EthercatSetupEventMachineInfo["machine_identification"]; + name: MachinePreset["name"]; + version: MachinePreset["version"]; + slug: MachinePreset["slug"]; + vendor: VendorPreset["name"]; + icon: MachinePreset["icon"]; +}; + +// returns only valid mahcines +export function useMachines(): UseMachine[] { + const event = useSocketioEthercatSetupEvent(); + return ( + event.data?.machine_infos + .filter((machine) => machine.error === null) + .map((machine) => { + const machinePreset = getMachinePreset(machine.machine_identification); + const vendorPreset = getVendorPreset(machinePreset!.vendor_id); + if (!machinePreset || !vendorPreset) { + return undefined; + } + return { + machine_identification: machine.machine_identification, + name: machinePreset.name, + version: machinePreset.version, + slug: machinePreset.slug, + vendor: vendorPreset.name, + icon: machinePreset.icon, + }; + }) + .filter((machine) => machine !== undefined) || [] + ); +} diff --git a/electron/src/machines/types.ts b/electron/src/machines/types.ts index 1178b9c7..207a4d08 100644 --- a/electron/src/machines/types.ts +++ b/electron/src/machines/types.ts @@ -1,9 +1,18 @@ +// every device has multiple roles to indentify the function of a subdevice +// each role can only be given once + +import { IconName } from "@/components/Icon"; + +// EK1100 should have role 0 export type DeviceRole = { role: number; + // UI purpose role_label: string; + // what kind of subdevices can be assigned to this role allowed_devices: EthercatDevice[]; }; +// data to identify subdevices type EthercatDevice = { product_id: number; revision: number; @@ -16,33 +25,45 @@ export type MachineIdentification = { }; export type MachinePreset = { + // displayable name name: string; + // displayable version + version: string; + // path for IO routes + slug: string; + icon: IconName; + // needs to be same as in the backend vendor_id: 0x0001; + // needs to be same as in the backend machine_id: number; + // roles and thair allowed devices device_roles: DeviceRole[]; }; export const VENDOR_QITECH = 0x0001; -export type Vendor = { +export type VendorPreset = { id: number; name: string; }; -export const vendors: Vendor[] = [ +export const vendorPresets: VendorPreset[] = [ { id: VENDOR_QITECH, name: "QiTech Industries GmbH", }, ]; -export function get_vendor_name(vendor_id: number): Vendor | undefined { - return vendors.find((v) => v.id === vendor_id); +export function getVendorPreset(vendor_id: number): VendorPreset | undefined { + return vendorPresets.find((v) => v.id === vendor_id); } export const machinePresets: MachinePreset[] = [ { - name: "Winder V1", + name: "Winder", + version: "V1", + slug: "winder1", + icon: "lu:Shell", vendor_id: VENDOR_QITECH, machine_id: 0x0001, device_roles: [ diff --git a/electron/src/machines/winder1/Winder1ControlPage.tsx b/electron/src/machines/winder1/Winder1ControlPage.tsx new file mode 100644 index 00000000..3406be1b --- /dev/null +++ b/electron/src/machines/winder1/Winder1ControlPage.tsx @@ -0,0 +1,8 @@ +import { Page } from "@/components/Page"; +import { winder1SerialRoute } from "@/routes/routes"; +import React from "react"; + +export function Winder1ControlPage() { + const { serial } = winder1SerialRoute.useParams(); + return Winder 1 Control; +} diff --git a/electron/src/machines/winder1/Winder1Page.tsx b/electron/src/machines/winder1/Winder1Page.tsx index 4808c705..d2097bbf 100644 --- a/electron/src/machines/winder1/Winder1Page.tsx +++ b/electron/src/machines/winder1/Winder1Page.tsx @@ -1,11 +1,18 @@ -import { Outlet } from "@tanstack/react-router"; +import { Topbar } from "@/components/Topbar"; +import { winder1SerialRoute } from "@/routes/routes"; import React from "react"; export function Winder1Page() { + const { serial } = winder1SerialRoute.useParams(); return ( - <> -

Winder1Page

- - + ); } diff --git a/electron/src/routes/router.tsx b/electron/src/routes/router.tsx index fe78268a..8ed0ee9e 100644 --- a/electron/src/routes/router.tsx +++ b/electron/src/routes/router.tsx @@ -8,6 +8,6 @@ declare module "@tanstack/react-router" { } const history = createMemoryHistory({ - initialEntries: ["/_sidebar/machines/123/winder1/general"], + initialEntries: ["/_sidebar/setup/ethercat"], }); export const router = createRouter({ routeTree: rootTree, history: history }); diff --git a/electron/src/routes/routes.tsx b/electron/src/routes/routes.tsx index 306c7ed0..b24976a2 100644 --- a/electron/src/routes/routes.tsx +++ b/electron/src/routes/routes.tsx @@ -2,16 +2,14 @@ import { createRoute } from "@tanstack/react-router"; import { RootRoute } from "./__root"; import React from "react"; import { SidebarLayout } from "@/components/SidebarLayout"; -import { Winder1Page } from "@/machines/winder1/Winder1Page"; import { SetupPage } from "@/setup/SetupPage"; import { EthercatPage } from "@/setup/EthercatPage"; import { MachinesPage } from "@/setup/MachinesPage"; +import { Winder1Page } from "@/machines/winder1/Winder1Page"; +import { Winder1ControlPage } from "@/machines/winder1/Winder1ControlPage"; // make a route tree like this -// _mainNavigation/machines/$machineSerial/winder1/general -// _mainNavigation/machines/$machineSerial/winder1/handbook -// _mainNavigation/machines/$machineSerial/winder2/general -// _mainNavigation/machines/$machineSerial/winder2/handbook +// _mainNavigation/machines/winder1/$serial/control // _mainNavigation/configuration/a // _mainNavigation/configuration/b // the mainNavigation has a custom layout @@ -24,21 +22,21 @@ export const sidebarRoute = createRoute({ component: () => , }); -export const machineRoute = createRoute({ +export const machinesRoute = createRoute({ getParentRoute: () => sidebarRoute, - path: "machines/$machineSerial", + path: "machines", }); -export const winder1Route = createRoute({ +export const winder1SerialRoute = createRoute({ getParentRoute: () => machinesRoute, - path: "winder1", + path: "winder1/$serial", component: () => , }); export const winder1GeneralRoute = createRoute({ - getParentRoute: () => winder1Route, - path: "general", - component: () =>
winder1 general
, + getParentRoute: () => winder1SerialRoute, + path: "control", + component: () => , }); export const setupRoute = createRoute({ @@ -53,7 +51,7 @@ export const ethercatRoute = createRoute({ component: () => , }); -export const machinesRoute = createRoute({ +export const setupMachinesRoute = createRoute({ getParentRoute: () => setupRoute, path: "machines", component: () => , @@ -61,7 +59,9 @@ export const machinesRoute = createRoute({ export const rootTree = RootRoute.addChildren([ sidebarRoute.addChildren([ - machineRoute.addChildren([winder1Route.addChildren([winder1GeneralRoute])]), - setupRoute.addChildren([ethercatRoute, machinesRoute]), + setupRoute.addChildren([ethercatRoute, setupMachinesRoute]), + machinesRoute.addChildren([ + winder1SerialRoute.addChildren([winder1GeneralRoute]), + ]), ]), ]); diff --git a/electron/src/setup/DeviceEepromDialog.tsx b/electron/src/setup/DeviceEepromDialog.tsx index f7563f2d..2ec0c32b 100644 --- a/electron/src/setup/DeviceEepromDialog.tsx +++ b/electron/src/setup/DeviceEepromDialog.tsx @@ -190,7 +190,7 @@ export function DeviceEeepromDialogContent({ device, setOpen }: ContentProps) { key={machine.machine_id} value={machine.machine_id.toString()} > - {machine.name} + {machine.name} {machine.version} ))} diff --git a/electron/src/setup/EthercatPage.tsx b/electron/src/setup/EthercatPage.tsx index fdc2970e..0aa2252a 100644 --- a/electron/src/setup/EthercatPage.tsx +++ b/electron/src/setup/EthercatPage.tsx @@ -52,7 +52,8 @@ export const columns: ColumnDef[] = [ if (!machine_identification) { return "—"; } - return getMachinePreset(machine_identification)?.name ?? "UNKNOWN"; + const machinePreset = getMachinePreset(machine_identification); + return machinePreset?.name + " " + machinePreset?.version; }, }, { @@ -114,7 +115,7 @@ export function EthercatPage() { }); return ( - +

Maschine, Maschinen Seriennummer, Rolle sind QiTech spezifische Werte die in den EEPROM geschrieben werden um Maschinen als Einheit zu diff --git a/electron/src/setup/MachinesPage.tsx b/electron/src/setup/MachinesPage.tsx index 6a025d51..c2c199fa 100644 --- a/electron/src/setup/MachinesPage.tsx +++ b/electron/src/setup/MachinesPage.tsx @@ -13,7 +13,7 @@ import { useReactTable, } from "@tanstack/react-table"; import React, { useMemo } from "react"; -import { get_vendor_name, getMachinePreset } from "@/machines/types"; +import { getVendorPreset, getMachinePreset } from "@/machines/types"; import { IconText } from "@/components/IconText"; export const columns: ColumnDef[] = [ @@ -25,7 +25,8 @@ export const columns: ColumnDef[] = [ if (!machine_identification) { return "—"; } - return getMachinePreset(machine_identification)?.name ?? "UNKNOWN"; + const machinePreset = getMachinePreset(machine_identification); + return machinePreset?.name + " " + machinePreset?.version; }, }, { @@ -36,7 +37,7 @@ export const columns: ColumnDef[] = [ if (!machine_identification) { return "—"; } - return get_vendor_name(machine_identification.vendor)?.name ?? "UNKNOWN"; + return getVendorPreset(machine_identification.vendor)?.name ?? "UNKNOWN"; }, }, { @@ -81,7 +82,7 @@ export function MachinesPage() { }); return ( - + diff --git a/electron/src/setup/SetupPage.tsx b/electron/src/setup/SetupPage.tsx index 019bc283..23248977 100644 --- a/electron/src/setup/SetupPage.tsx +++ b/electron/src/setup/SetupPage.tsx @@ -1,5 +1,4 @@ import { Topbar } from "@/components/Topbar"; -import { EthernetPort, Factory } from "lucide-react"; import React from "react"; export function SetupPage() { @@ -10,12 +9,12 @@ export function SetupPage() { { link: "ethercat", title: "Ethercat", - icon: , + icon: "lu:EthernetPort", }, { link: "machines", title: "Maschinen", - icon: , + icon: "lu:Factory", }, ]} />