🚧 wip: user devices endpoint

This commit is contained in:
Fred KISSIE
2026-02-06 05:37:44 +01:00
parent 67b63d3084
commit 9f2fd34e99
10 changed files with 374 additions and 74 deletions

View File

@@ -1,11 +1,12 @@
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/UserDevicesTable";
import UserDevicesTable from "@app/components/UserDevicesTable";
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import { type ListUserDevicesResponse } from "@server/routers/client";
import type { Pagination } from "@server/types/Pagination";
import { AxiosResponse } from "axios";
import { getTranslations } from "next-intl/server";
type ClientsPageProps = {
params: Promise<{ orgId: string }>;
@@ -18,14 +19,21 @@ export default async function ClientsPage(props: ClientsPageProps) {
const params = await props.params;
let userClients: ListClientsResponse["clients"] = [];
let userClients: ListUserDevicesResponse["devices"] = [];
let pagination: Pagination = {
page: 1,
total: 0,
pageSize: 20
};
try {
const userRes = await internal.get<AxiosResponse<ListClientsResponse>>(
`/org/${params.orgId}/clients?filter=user`,
await authCookieHeader()
);
userClients = userRes.data.data.clients;
const userRes = await internal.get<
AxiosResponse<ListUserDevicesResponse>
>(`/org/${params.orgId}/user-devices`, await authCookieHeader());
const responseData = userRes.data.data;
userClients = responseData.devices;
pagination = responseData.pagination;
} catch (e) {}
function formatSize(mb: number): string {
@@ -39,31 +47,29 @@ export default async function ClientsPage(props: ClientsPageProps) {
}
const mapClientToRow = (
client: ListClientsResponse["clients"][0]
client: ListUserDevicesResponse["devices"][number]
): ClientRow => {
// Build fingerprint object if any fingerprint data exists
const hasFingerprintData =
(client as any).fingerprintPlatform ||
(client as any).fingerprintOsVersion ||
(client as any).fingerprintKernelVersion ||
(client as any).fingerprintArch ||
(client as any).fingerprintSerialNumber ||
(client as any).fingerprintUsername ||
(client as any).fingerprintHostname ||
(client as any).deviceModel;
client.fingerprintPlatform ||
client.fingerprintOsVersion ||
client.fingerprintKernelVersion ||
client.fingerprintArch ||
client.fingerprintSerialNumber ||
client.fingerprintUsername ||
client.fingerprintHostname ||
client.deviceModel;
const fingerprint = hasFingerprintData
? {
platform: (client as any).fingerprintPlatform || null,
osVersion: (client as any).fingerprintOsVersion || null,
kernelVersion:
(client as any).fingerprintKernelVersion || null,
arch: (client as any).fingerprintArch || null,
deviceModel: (client as any).deviceModel || null,
serialNumber:
(client as any).fingerprintSerialNumber || null,
username: (client as any).fingerprintUsername || null,
hostname: (client as any).fingerprintHostname || null
platform: client.fingerprintPlatform,
osVersion: client.fingerprintOsVersion,
kernelVersion: client.fingerprintKernelVersion,
arch: client.fingerprintArch,
deviceModel: client.deviceModel,
serialNumber: client.fingerprintSerialNumber,
username: client.fingerprintUsername,
hostname: client.fingerprintHostname
}
: null;
@@ -71,19 +77,19 @@ export default async function ClientsPage(props: ClientsPageProps) {
name: client.name,
id: client.clientId,
subnet: client.subnet.split("/")[0],
mbIn: formatSize(client.megabytesIn || 0),
mbOut: formatSize(client.megabytesOut || 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,
olmUpdateAvailable: Boolean(client.olmUpdateAvailable),
userId: client.userId,
username: client.username,
userEmail: client.userEmail,
niceId: client.niceId,
agent: client.agent,
archived: client.archived || false,
blocked: client.blocked || false,
archived: Boolean(client.archived),
blocked: Boolean(client.blocked),
approvalState: client.approvalState,
fingerprint
};
@@ -91,6 +97,11 @@ export default async function ClientsPage(props: ClientsPageProps) {
const userClientRows: ClientRow[] = userClients.map(mapClientToRow);
console.log({
userClientRows,
pagination
});
return (
<>
<SettingsSectionTitle

View File

@@ -255,10 +255,7 @@ export default function CreateInternalResourceDialog({
const { data: usersResponse = [] } = useQuery(orgQueries.users({ orgId }));
const { data: clientsResponse = [] } = useQuery(
orgQueries.clients({
orgId,
filters: {
filter: "machine"
}
orgId
})
);

View File

@@ -277,10 +277,7 @@ export default function EditInternalResourceDialog({
orgQueries.roles({ orgId }),
orgQueries.users({ orgId }),
orgQueries.clients({
orgId,
filters: {
filter: "machine"
}
orgId
}),
resourceQueries.siteResourceUsers({ siteResourceId: resource.id }),
resourceQueries.siteResourceRoles({ siteResourceId: resource.id }),

View File

@@ -86,8 +86,7 @@ export const productUpdatesQueries = {
};
export const clientFilterSchema = z.object({
filter: z.enum(["machine", "user"]),
limit: z.int().prefault(1000).optional()
pageSize: z.int().prefault(1000).optional()
});
export const orgQueries = {
@@ -96,14 +95,13 @@ export const orgQueries = {
filters
}: {
orgId: string;
filters: z.infer<typeof clientFilterSchema>;
filters?: z.infer<typeof clientFilterSchema>;
}) =>
queryOptions({
queryKey: ["ORG", orgId, "CLIENTS", filters] as const,
queryFn: async ({ signal, meta }) => {
const sp = new URLSearchParams({
...filters,
limit: (filters.limit ?? 1000).toString()
pageSize: (filters?.pageSize ?? 1000).toString()
});
const res = await meta!.api.get<