From 27db77bca40b593850b420e4e05ef0cb76f3976f Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 12 Dec 2025 14:53:26 -0500 Subject: [PATCH 1/4] Format --- server/lib/ip.ts | 10 ++++++---- server/private/license/license.ts | 17 ++++++++--------- src/components/Credenza.tsx | 8 +++++++- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/server/lib/ip.ts b/server/lib/ip.ts index 36065df3..02683edc 100644 --- a/server/lib/ip.ts +++ b/server/lib/ip.ts @@ -120,11 +120,13 @@ function bigIntToIp(num: bigint, version: IPVersion): string { * Parses an endpoint string (ip:port) handling both IPv4 and IPv6 addresses. * IPv6 addresses may be bracketed like [::1]:8080 or unbracketed like ::1:8080. * For unbracketed IPv6, the last colon-separated segment is treated as the port. - * + * * @param endpoint The endpoint string to parse (e.g., "192.168.1.1:8080" or "[::1]:8080" or "2607:fea8::1:8080") * @returns An object with ip and port, or null if parsing fails */ -export function parseEndpoint(endpoint: string): { ip: string; port: number } | null { +export function parseEndpoint( + endpoint: string +): { ip: string; port: number } | null { if (!endpoint) return null; // Check for bracketed IPv6 format: [ip]:port @@ -138,7 +140,7 @@ export function parseEndpoint(endpoint: string): { ip: string; port: number } | // Check if this looks like IPv6 (contains multiple colons) const colonCount = (endpoint.match(/:/g) || []).length; - + if (colonCount > 1) { // This is IPv6 - the port is after the last colon const lastColonIndex = endpoint.lastIndexOf(":"); @@ -163,7 +165,7 @@ export function parseEndpoint(endpoint: string): { ip: string; port: number } | /** * Formats an IP and port into a consistent endpoint string. * IPv6 addresses are wrapped in brackets for proper parsing. - * + * * @param ip The IP address (IPv4 or IPv6) * @param port The port number * @returns Formatted endpoint string diff --git a/server/private/license/license.ts b/server/private/license/license.ts index db3db509..f8f774c6 100644 --- a/server/private/license/license.ts +++ b/server/private/license/license.ts @@ -84,14 +84,11 @@ LQIDAQAB -----END PUBLIC KEY-----`; constructor(private hostMeta: HostMeta) { - setInterval( - async () => { - this.doRecheck = true; - await this.check(); - this.doRecheck = false; - }, - 1000 * this.phoneHomeInterval - ); + setInterval(async () => { + this.doRecheck = true; + await this.check(); + this.doRecheck = false; + }, 1000 * this.phoneHomeInterval); } public listKeys(): LicenseKeyCache[] { @@ -242,7 +239,9 @@ LQIDAQAB // First failure: fail silently logger.error("Error communicating with license server:"); logger.error(e); - logger.error(`Allowing failure. Will retry one more time at next run interval.`); + logger.error( + `Allowing failure. Will retry one more time at next run interval.` + ); // return last known good status return this.statusCache.get( this.statusKey diff --git a/src/components/Credenza.tsx b/src/components/Credenza.tsx index 9d468e60..6a48fc54 100644 --- a/src/components/Credenza.tsx +++ b/src/components/Credenza.tsx @@ -177,7 +177,13 @@ const CredenzaFooter = ({ className, children, ...props }: CredenzaProps) => { const CredenzaFooter = isDesktop ? DialogFooter : SheetFooter; return ( - + {children} ); From a012369f83abb7681f117700dcac24c31da34c8f Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 12 Dec 2025 18:39:13 -0500 Subject: [PATCH 2/4] Make sure to always check retention first Fixes #2061 --- server/routers/badger/logRequestAudit.ts | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/server/routers/badger/logRequestAudit.ts b/server/routers/badger/logRequestAudit.ts index 1cf97f98..1343bdaa 100644 --- a/server/routers/badger/logRequestAudit.ts +++ b/server/routers/badger/logRequestAudit.ts @@ -148,7 +148,7 @@ export async function cleanUpOldLogs(orgId: string, retentionDays: number) { } } -export function logRequestAudit( +export async function logRequestAudit( data: { action: boolean; reason: number; @@ -174,14 +174,13 @@ export function logRequestAudit( } ) { try { - // Quick synchronous check - if org has 0 retention, skip immediately + // Check retention before buffering any logs if (data.orgId) { - const cached = cache.get(`org_${data.orgId}_retentionDays`); - if (cached === 0) { + const retentionDays = await getRetentionDays(data.orgId); + if (retentionDays === 0) { // do not log return; } - // If not cached or > 0, we'll log it (async retention check happens in background) } let actorType: string | undefined; @@ -261,16 +260,6 @@ export function logRequestAudit( } else { scheduleFlush(); } - - // Async retention check in background (don't await) - if ( - data.orgId && - cache.get(`org_${data.orgId}_retentionDays`) === undefined - ) { - getRetentionDays(data.orgId).catch((err) => - logger.error("Error checking retention days:", err) - ); - } } catch (error) { logger.error(error); } From 3d857c3b5218b15a05a2e1d07119ff0f709ba278 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Fri, 12 Dec 2025 22:41:04 -0500 Subject: [PATCH 3/4] fix client side pagination issue --- src/components/DataTablePagination.tsx | 55 +++++++++++++++++--------- src/components/LogDataTable.tsx | 2 + src/components/ui/data-table.tsx | 31 +++++++++------ 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/components/DataTablePagination.tsx b/src/components/DataTablePagination.tsx index be12ca47..ba40eff4 100644 --- a/src/components/DataTablePagination.tsx +++ b/src/components/DataTablePagination.tsx @@ -24,6 +24,8 @@ interface DataTablePaginationProps { isServerPagination?: boolean; isLoading?: boolean; disabled?: boolean; + pageSize?: number; + pageIndex?: number; } export function DataTablePagination({ @@ -33,10 +35,24 @@ export function DataTablePagination({ totalCount, isServerPagination = false, isLoading = false, - disabled = false + disabled = false, + pageSize: controlledPageSize, + pageIndex: controlledPageIndex }: DataTablePaginationProps) { const t = useTranslations(); + // Use controlled values if provided, otherwise fall back to table state + const pageSize = controlledPageSize ?? table.getState().pagination.pageSize; + const pageIndex = controlledPageIndex ?? table.getState().pagination.pageIndex; + + // Calculate page boundaries based on controlled state + // For server-side pagination, use totalCount if available for accurate page count + const pageCount = isServerPagination && totalCount !== undefined + ? Math.ceil(totalCount / pageSize) + : table.getPageCount(); + const canNextPage = pageIndex < pageCount - 1; + const canPreviousPage = pageIndex > 0; + const handlePageSizeChange = (value: string) => { const newPageSize = Number(value); table.setPageSize(newPageSize); @@ -51,7 +67,7 @@ export function DataTablePagination({ action: "first" | "previous" | "next" | "last" ) => { if (isServerPagination && onPageChange) { - const currentPage = table.getState().pagination.pageIndex; + const currentPage = pageIndex; const pageCount = table.getPageCount(); let newPage: number; @@ -77,18 +93,24 @@ export function DataTablePagination({ } } else { // Use table's built-in navigation for client-side pagination + // But add bounds checking to prevent going beyond page boundaries + const pageCount = table.getPageCount(); switch (action) { case "first": table.setPageIndex(0); break; case "previous": - table.previousPage(); + if (pageIndex > 0) { + table.previousPage(); + } break; case "next": - table.nextPage(); + if (pageIndex < pageCount - 1) { + table.nextPage(); + } break; case "last": - table.setPageIndex(table.getPageCount() - 1); + table.setPageIndex(Math.max(0, pageCount - 1)); break; } } @@ -98,13 +120,13 @@ export function DataTablePagination({