mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
🚧WIP: Separate user & machine clients
This commit is contained in:
@@ -1166,6 +1166,8 @@
|
||||
"sidebarIdentityProviders": "Identity Providers",
|
||||
"sidebarLicense": "License",
|
||||
"sidebarClients": "Clients",
|
||||
"sidebarUserDevices": "User devices",
|
||||
"sidebarMachineClients": "Machine Clients",
|
||||
"sidebarDomains": "Domains",
|
||||
"sidebarBluePrints": "Blueprints",
|
||||
"blueprints": "Blueprints",
|
||||
|
||||
92
src/app/[orgId]/settings/clients/machine/page.tsx
Normal file
92
src/app/[orgId]/settings/clients/machine/page.tsx
Normal file
@@ -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<AxiosResponse<ListClientsResponse>>(
|
||||
`/org/${params.orgId}/clients?filter=user`,
|
||||
await authCookieHeader()
|
||||
),
|
||||
internal.get<AxiosResponse<ListClientsResponse>>(
|
||||
`/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 (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title={t("manageClients")}
|
||||
description={t("manageClientsDescription")}
|
||||
/>
|
||||
|
||||
<ClientsTable
|
||||
userClients={userClientRows}
|
||||
machineClients={machineClientRows}
|
||||
orgId={params.orgId}
|
||||
defaultView={defaultView}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -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<AxiosResponse<ListClientsResponse>>(
|
||||
`/org/${params.orgId}/clients?filter=user`,
|
||||
await authCookieHeader()
|
||||
),
|
||||
internal.get<AxiosResponse<ListClientsResponse>>(
|
||||
`/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 (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title={t("manageClients")}
|
||||
description={t("manageClientsDescription")}
|
||||
/>
|
||||
|
||||
<ClientsTable
|
||||
userClients={userClientRows}
|
||||
machineClients={machineClientRows}
|
||||
orgId={params.orgId}
|
||||
defaultView={defaultView}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
redirect(`/${params.orgId}/settings/clients/user`);
|
||||
}
|
||||
|
||||
92
src/app/[orgId]/settings/clients/user/page.tsx
Normal file
92
src/app/[orgId]/settings/clients/user/page.tsx
Normal file
@@ -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<AxiosResponse<ListClientsResponse>>(
|
||||
`/org/${params.orgId}/clients?filter=user`,
|
||||
await authCookieHeader()
|
||||
),
|
||||
internal.get<AxiosResponse<ListClientsResponse>>(
|
||||
`/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 (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title={t("manageClients")}
|
||||
description={t("manageClientsDescription")}
|
||||
/>
|
||||
|
||||
<ClientsTable
|
||||
userClients={userClientRows}
|
||||
machineClients={machineClientRows}
|
||||
orgId={params.orgId}
|
||||
defaultView={defaultView}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -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: <MonitorUp className="size-4 flex-none" />,
|
||||
isBeta: true
|
||||
isBeta: true,
|
||||
items: [
|
||||
{
|
||||
href: "/{orgId}/settings/clients/user",
|
||||
title: "sidebarUserDevices",
|
||||
icon: (
|
||||
<Smartphone className="size-4 flex-none" />
|
||||
)
|
||||
},
|
||||
{
|
||||
href: "/{orgId}/settings/clients/machine",
|
||||
title: "sidebarMachineClients",
|
||||
icon: <Server className="size-4 flex-none" />
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
: []),
|
||||
|
||||
Reference in New Issue
Block a user