[] = [
+ {
+ accessorKey: "startedAt",
+ header: ({ column }) => {
+ return t("timestamp");
+ },
+ cell: ({ row }) => {
+ return (
+
+ {new Date(
+ row.original.startedAt * 1000
+ ).toLocaleString()}
+
+ );
+ }
+ },
+ {
+ accessorKey: "protocol",
+ header: ({ column }) => {
+ return (
+
+ {t("protocol")}
+ ({
+ label: protocol.toUpperCase(),
+ value: protocol
+ })
+ )}
+ selectedValue={filters.protocol}
+ onValueChange={(value) =>
+ handleFilterChange("protocol", value)
+ }
+ searchPlaceholder="Search..."
+ emptyMessage="None found"
+ />
+
+ );
+ },
+ cell: ({ row }) => {
+ return (
+
+ {row.original.protocol?.toUpperCase()}
+
+ );
+ }
+ },
+ {
+ accessorKey: "resourceName",
+ header: ({ column }) => {
+ return (
+
+ {t("resource")}
+ ({
+ value: res.id.toString(),
+ label: res.name || "Unnamed Resource"
+ }))}
+ selectedValue={filters.siteResourceId}
+ onValueChange={(value) =>
+ handleFilterChange("siteResourceId", value)
+ }
+ searchPlaceholder="Search..."
+ emptyMessage="None found"
+ />
+
+ );
+ },
+ cell: ({ row }) => {
+ if (row.original.resourceName && row.original.resourceNiceId) {
+ return (
+
+
+
+ );
+ }
+ return (
+
+ {row.original.resourceName ?? "—"}
+
+ );
+ }
+ },
+ {
+ accessorKey: "clientName",
+ header: ({ column }) => {
+ return (
+
+ {t("client")}
+ ({
+ value: c.id.toString(),
+ label: c.name
+ }))}
+ selectedValue={filters.clientId}
+ onValueChange={(value) =>
+ handleFilterChange("clientId", value)
+ }
+ searchPlaceholder="Search..."
+ emptyMessage="None found"
+ />
+
+ );
+ },
+ cell: ({ row }) => {
+ const clientType = row.original.clientType === "olm" ? "machine" : "user";
+ if (row.original.clientName && row.original.clientNiceId) {
+ return (
+
+
+
+ );
+ }
+ return (
+
+ {row.original.clientName ?? "—"}
+
+ );
+ }
+ },
+ {
+ accessorKey: "userEmail",
+ header: ({ column }) => {
+ return (
+
+ {t("user")}
+ ({
+ value: u.id,
+ label: u.email || u.id
+ }))}
+ selectedValue={filters.userId}
+ onValueChange={(value) =>
+ handleFilterChange("userId", value)
+ }
+ searchPlaceholder="Search..."
+ emptyMessage="None found"
+ />
+
+ );
+ },
+ cell: ({ row }) => {
+ if (row.original.userEmail || row.original.userId) {
+ return (
+
+
+ {row.original.userEmail ?? row.original.userId}
+
+ );
+ }
+ return —;
+ }
+ },
+ {
+ accessorKey: "sourceAddr",
+ header: ({ column }) => {
+ return t("sourceAddress");
+ },
+ cell: ({ row }) => {
+ return (
+
+ {row.original.sourceAddr}
+
+ );
+ }
+ },
+ {
+ accessorKey: "destAddr",
+ header: ({ column }) => {
+ return (
+
+ {t("destinationAddress")}
+ ({
+ value: addr,
+ label: addr
+ }))}
+ selectedValue={filters.destAddr}
+ onValueChange={(value) =>
+ handleFilterChange("destAddr", value)
+ }
+ searchPlaceholder="Search..."
+ emptyMessage="None found"
+ />
+
+ );
+ },
+ cell: ({ row }) => {
+ return (
+
+ {row.original.destAddr}
+
+ );
+ }
+ },
+ {
+ accessorKey: "duration",
+ header: ({ column }) => {
+ return t("duration");
+ },
+ cell: ({ row }) => {
+ return (
+
+ {formatDuration(
+ row.original.startedAt,
+ row.original.endedAt
+ )}
+
+ );
+ }
+ }
+ ];
+
+ const renderExpandedRow = (row: any) => {
+ return (
+
+
+
+ {/*
+ Connection Details
+
*/}
+
+ Session ID:{" "}
+
+ {row.sessionId ?? "—"}
+
+
+
+ Protocol:{" "}
+ {row.protocol?.toUpperCase() ?? "—"}
+
+
+ Source:{" "}
+
+ {row.sourceAddr ?? "—"}
+
+
+
+ Destination:{" "}
+
+ {row.destAddr ?? "—"}
+
+
+
+
+ {/*
+ Resource & Site
+
*/}
+ {/*
+ Resource:{" "}
+ {row.resourceName ?? "—"}
+ {row.resourceNiceId && (
+
+ ({row.resourceNiceId})
+
+ )}
+
*/}
+
+ Site: {row.siteName ?? "—"}
+ {row.siteNiceId && (
+
+ ({row.siteNiceId})
+
+ )}
+
+
+ Site ID: {row.siteId ?? "—"}
+
+
+ Started At:{" "}
+ {row.startedAt
+ ? new Date(
+ row.startedAt * 1000
+ ).toLocaleString()
+ : "—"}
+
+
+ Ended At:{" "}
+ {row.endedAt
+ ? new Date(
+ row.endedAt * 1000
+ ).toLocaleString()
+ : "Active"}
+
+
+ Duration:{" "}
+ {formatDuration(row.startedAt, row.endedAt)}
+
+ {/*
+ Resource ID:{" "}
+ {row.siteResourceId ?? "—"}
+
*/}
+
+
+ {/*
+ Client & Transfer
+
*/}
+ {/*
+ Bytes Sent (TX):{" "}
+ {formatBytes(row.bytesTx)}
+
*/}
+ {/*
+ Bytes Received (RX):{" "}
+ {formatBytes(row.bytesRx)}
+
*/}
+ {/*
+ Total Transfer:{" "}
+ {formatBytes(
+ (row.bytesTx ?? 0) + (row.bytesRx ?? 0)
+ )}
+
*/}
+
+
+
+ );
+ };
+
+ return (
+ <>
+
+
+
+
+ startTransition(exportData)}
+ isExporting={isExporting}
+ onDateRangeChange={handleDateRangeChange}
+ dateRange={{
+ start: dateRange.startDate,
+ end: dateRange.endDate
+ }}
+ defaultSort={{
+ id: "startedAt",
+ desc: true
+ }}
+ // Server-side pagination props
+ totalCount={totalCount}
+ currentPage={currentPage}
+ pageSize={pageSize}
+ onPageChange={handlePageChange}
+ onPageSizeChange={handlePageSizeChange}
+ isLoading={isLoading}
+ // Row expansion props
+ expandable={true}
+ renderExpandedRow={renderExpandedRow}
+ disabled={
+ !isPaidUser(tierMatrix.connectionLogs) || build === "oss"
+ }
+ />
+ >
+ );
+}
diff --git a/src/app/navigation.tsx b/src/app/navigation.tsx
index c90b211a3..66e6cdad0 100644
--- a/src/app/navigation.tsx
+++ b/src/app/navigation.tsx
@@ -4,6 +4,7 @@ import { build } from "@server/build";
import {
Boxes,
Building2,
+ Cable,
ChartLine,
Combine,
CreditCard,
@@ -190,6 +191,11 @@ export const orgNavSections = (
title: "sidebarLogsAction",
href: "/{orgId}/settings/logs/action",
icon:
+ },
+ {
+ title: "sidebarLogsConnection",
+ href: "/{orgId}/settings/logs/connection",
+ icon:
}
]
: [])