From 45a82f3ecc7407fbdf769ac53af3cdddca7133a3 Mon Sep 17 00:00:00 2001 From: Fred KISSIE Date: Tue, 2 Dec 2025 03:14:02 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7WIP:=20Separate=20user=20&=20machin?= =?UTF-8?q?e=20clients?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en-US.json | 2 + .../[orgId]/settings/clients/machine/page.tsx | 92 +++++++++++++++++++ src/app/[orgId]/settings/clients/page.tsx | 70 +------------- .../[orgId]/settings/clients/user/page.tsx | 92 +++++++++++++++++++ src/app/navigation.tsx | 20 +++- 5 files changed, 205 insertions(+), 71 deletions(-) create mode 100644 src/app/[orgId]/settings/clients/machine/page.tsx create mode 100644 src/app/[orgId]/settings/clients/user/page.tsx diff --git a/messages/en-US.json b/messages/en-US.json index 0aa56ac5..279da0e3 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1166,6 +1166,8 @@ "sidebarIdentityProviders": "Identity Providers", "sidebarLicense": "License", "sidebarClients": "Clients", + "sidebarUserDevices": "User devices", + "sidebarMachineClients": "Machine Clients", "sidebarDomains": "Domains", "sidebarBluePrints": "Blueprints", "blueprints": "Blueprints", diff --git a/src/app/[orgId]/settings/clients/machine/page.tsx b/src/app/[orgId]/settings/clients/machine/page.tsx new file mode 100644 index 00000000..e0b4ebf7 --- /dev/null +++ b/src/app/[orgId]/settings/clients/machine/page.tsx @@ -0,0 +1,92 @@ +import { internal } from "@app/lib/api"; +import { authCookieHeader } from "@app/lib/api/cookies"; +import { AxiosResponse } from "axios"; +import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; +import { ListClientsResponse } from "@server/routers/client"; +import { getTranslations } from "next-intl/server"; +import type { ClientRow } from "@app/components/ClientsTable"; +import ClientsTable from "@app/components/ClientsTable"; + +type ClientsPageProps = { + params: Promise<{ orgId: string }>; + searchParams: Promise<{ view?: string }>; +}; + +export const dynamic = "force-dynamic"; + +export default async function ClientsPage(props: ClientsPageProps) { + const t = await getTranslations(); + + const params = await props.params; + const searchParams = await props.searchParams; + + // Default to 'user' view, or use the query param if provided + let defaultView: "user" | "machine" = "user"; + defaultView = searchParams.view === "machine" ? "machine" : "user"; + + let userClients: ListClientsResponse["clients"] = []; + let machineClients: ListClientsResponse["clients"] = []; + + try { + const [userRes, machineRes] = await Promise.all([ + internal.get>( + `/org/${params.orgId}/clients?filter=user`, + await authCookieHeader() + ), + internal.get>( + `/org/${params.orgId}/clients?filter=machine`, + await authCookieHeader() + ) + ]); + userClients = userRes.data.data.clients; + machineClients = machineRes.data.data.clients; + } catch (e) {} + + function formatSize(mb: number): string { + if (mb >= 1024 * 1024) { + return `${(mb / (1024 * 1024)).toFixed(2)} TB`; + } else if (mb >= 1024) { + return `${(mb / 1024).toFixed(2)} GB`; + } else { + return `${mb.toFixed(2)} MB`; + } + } + + const mapClientToRow = ( + client: ListClientsResponse["clients"][0] + ): ClientRow => { + return { + name: client.name, + id: client.clientId, + subnet: client.subnet.split("/")[0], + mbIn: formatSize(client.megabytesIn || 0), + mbOut: formatSize(client.megabytesOut || 0), + orgId: params.orgId, + online: client.online, + olmVersion: client.olmVersion || undefined, + olmUpdateAvailable: client.olmUpdateAvailable || false, + userId: client.userId, + username: client.username, + userEmail: client.userEmail + }; + }; + + const userClientRows: ClientRow[] = userClients.map(mapClientToRow); + const machineClientRows: ClientRow[] = machineClients.map(mapClientToRow); + + return ( + <> + + + + + ); +} diff --git a/src/app/[orgId]/settings/clients/page.tsx b/src/app/[orgId]/settings/clients/page.tsx index 7049306e..40bcc569 100644 --- a/src/app/[orgId]/settings/clients/page.tsx +++ b/src/app/[orgId]/settings/clients/page.tsx @@ -6,6 +6,7 @@ import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; import { ListClientsResponse } from "@server/routers/client"; import ClientsTable from "../../../../components/ClientsTable"; import { getTranslations } from "next-intl/server"; +import { redirect } from "next/navigation"; type ClientsPageProps = { params: Promise<{ orgId: string }>; @@ -18,73 +19,6 @@ export default async function ClientsPage(props: ClientsPageProps) { const t = await getTranslations(); const params = await props.params; - const searchParams = await props.searchParams; - // Default to 'user' view, or use the query param if provided - let defaultView: "user" | "machine" = "user"; - defaultView = searchParams.view === "machine" ? "machine" : "user"; - - let userClients: ListClientsResponse["clients"] = []; - let machineClients: ListClientsResponse["clients"] = []; - - try { - const [userRes, machineRes] = await Promise.all([ - internal.get>( - `/org/${params.orgId}/clients?filter=user`, - await authCookieHeader() - ), - internal.get>( - `/org/${params.orgId}/clients?filter=machine`, - await authCookieHeader() - ) - ]); - userClients = userRes.data.data.clients; - machineClients = machineRes.data.data.clients; - } catch (e) {} - - function formatSize(mb: number): string { - if (mb >= 1024 * 1024) { - return `${(mb / (1024 * 1024)).toFixed(2)} TB`; - } else if (mb >= 1024) { - return `${(mb / 1024).toFixed(2)} GB`; - } else { - return `${mb.toFixed(2)} MB`; - } - } - - const mapClientToRow = (client: ListClientsResponse["clients"][0]): ClientRow => { - return { - name: client.name, - id: client.clientId, - subnet: client.subnet.split("/")[0], - mbIn: formatSize(client.megabytesIn || 0), - mbOut: formatSize(client.megabytesOut || 0), - orgId: params.orgId, - online: client.online, - olmVersion: client.olmVersion || undefined, - olmUpdateAvailable: client.olmUpdateAvailable || false, - userId: client.userId, - username: client.username, - userEmail: client.userEmail - }; - }; - - const userClientRows: ClientRow[] = userClients.map(mapClientToRow); - const machineClientRows: ClientRow[] = machineClients.map(mapClientToRow); - - return ( - <> - - - - - ); + redirect(`/${params.orgId}/settings/clients/user`); } diff --git a/src/app/[orgId]/settings/clients/user/page.tsx b/src/app/[orgId]/settings/clients/user/page.tsx new file mode 100644 index 00000000..e0b4ebf7 --- /dev/null +++ b/src/app/[orgId]/settings/clients/user/page.tsx @@ -0,0 +1,92 @@ +import { internal } from "@app/lib/api"; +import { authCookieHeader } from "@app/lib/api/cookies"; +import { AxiosResponse } from "axios"; +import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; +import { ListClientsResponse } from "@server/routers/client"; +import { getTranslations } from "next-intl/server"; +import type { ClientRow } from "@app/components/ClientsTable"; +import ClientsTable from "@app/components/ClientsTable"; + +type ClientsPageProps = { + params: Promise<{ orgId: string }>; + searchParams: Promise<{ view?: string }>; +}; + +export const dynamic = "force-dynamic"; + +export default async function ClientsPage(props: ClientsPageProps) { + const t = await getTranslations(); + + const params = await props.params; + const searchParams = await props.searchParams; + + // Default to 'user' view, or use the query param if provided + let defaultView: "user" | "machine" = "user"; + defaultView = searchParams.view === "machine" ? "machine" : "user"; + + let userClients: ListClientsResponse["clients"] = []; + let machineClients: ListClientsResponse["clients"] = []; + + try { + const [userRes, machineRes] = await Promise.all([ + internal.get>( + `/org/${params.orgId}/clients?filter=user`, + await authCookieHeader() + ), + internal.get>( + `/org/${params.orgId}/clients?filter=machine`, + await authCookieHeader() + ) + ]); + userClients = userRes.data.data.clients; + machineClients = machineRes.data.data.clients; + } catch (e) {} + + function formatSize(mb: number): string { + if (mb >= 1024 * 1024) { + return `${(mb / (1024 * 1024)).toFixed(2)} TB`; + } else if (mb >= 1024) { + return `${(mb / 1024).toFixed(2)} GB`; + } else { + return `${mb.toFixed(2)} MB`; + } + } + + const mapClientToRow = ( + client: ListClientsResponse["clients"][0] + ): ClientRow => { + return { + name: client.name, + id: client.clientId, + subnet: client.subnet.split("/")[0], + mbIn: formatSize(client.megabytesIn || 0), + mbOut: formatSize(client.megabytesOut || 0), + orgId: params.orgId, + online: client.online, + olmVersion: client.olmVersion || undefined, + olmUpdateAvailable: client.olmUpdateAvailable || false, + userId: client.userId, + username: client.username, + userEmail: client.userEmail + }; + }; + + const userClientRows: ClientRow[] = userClients.map(mapClientToRow); + const machineClientRows: ClientRow[] = machineClients.map(mapClientToRow); + + return ( + <> + + + + + ); +} diff --git a/src/app/navigation.tsx b/src/app/navigation.tsx index ceefa8f0..a61ff4af 100644 --- a/src/app/navigation.tsx +++ b/src/app/navigation.tsx @@ -18,7 +18,8 @@ import { Logs, SquareMousePointer, ScanEye, - GlobeLock + GlobeLock, + Smartphone } from "lucide-react"; export type SidebarNavSection = { @@ -73,9 +74,22 @@ export const orgNavSections = ( ? [ { title: "sidebarClients", - href: "/{orgId}/settings/clients", icon: , - isBeta: true + isBeta: true, + items: [ + { + href: "/{orgId}/settings/clients/user", + title: "sidebarUserDevices", + icon: ( + + ) + }, + { + href: "/{orgId}/settings/clients/machine", + title: "sidebarMachineClients", + icon: + } + ] } ] : []),