mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-26 18:52:41 +00:00
💄 show loading animation on http request logs table
This commit is contained in:
@@ -1620,6 +1620,7 @@
|
|||||||
"certificateStatus": "Certificate",
|
"certificateStatus": "Certificate",
|
||||||
"certificateStatusAutoRefreshHint": "Status refreshes automatically.",
|
"certificateStatusAutoRefreshHint": "Status refreshes automatically.",
|
||||||
"loading": "Loading",
|
"loading": "Loading",
|
||||||
|
"loadingEllipsis": "Loading...",
|
||||||
"loadingAnalytics": "Loading Analytics",
|
"loadingAnalytics": "Loading Analytics",
|
||||||
"restart": "Restart",
|
"restart": "Restart",
|
||||||
"domains": "Domains",
|
"domains": "Domains",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { useParams, useRouter, useSearchParams } from "next/navigation";
|
|||||||
import { useMemo, useState, useTransition } from "react";
|
import { useMemo, useState, useTransition } from "react";
|
||||||
import { useStoredPageSize } from "@app/hooks/useStoredPageSize";
|
import { useStoredPageSize } from "@app/hooks/useStoredPageSize";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
|
import type { QueryRequestAuditLogResponse } from "@server/routers/auditLogs/types";
|
||||||
|
|
||||||
export default function GeneralPage() {
|
export default function GeneralPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -79,7 +80,9 @@ export default function GeneralPage() {
|
|||||||
if (dateRange.startDate?.date) {
|
if (dateRange.startDate?.date) {
|
||||||
const dt = new Date(dateRange.startDate.date);
|
const dt = new Date(dateRange.startDate.date);
|
||||||
if (dateRange.startDate.time) {
|
if (dateRange.startDate.time) {
|
||||||
const [h, m, s] = dateRange.startDate.time.split(":").map(Number);
|
const [h, m, s] = dateRange.startDate.time
|
||||||
|
.split(":")
|
||||||
|
.map(Number);
|
||||||
dt.setHours(h, m, s || 0);
|
dt.setHours(h, m, s || 0);
|
||||||
}
|
}
|
||||||
timeStart = dt.toISOString();
|
timeStart = dt.toISOString();
|
||||||
@@ -114,7 +117,7 @@ export default function GeneralPage() {
|
|||||||
};
|
};
|
||||||
}, [dateRange, currentPage, pageSize, filters]);
|
}, [dateRange, currentPage, pageSize, filters]);
|
||||||
|
|
||||||
const { data, isFetching, refetch } = useQuery({
|
const { data, isFetching, isLoading, refetch } = useQuery({
|
||||||
...logQueries.requests({
|
...logQueries.requests({
|
||||||
orgId: orgId as string,
|
orgId: orgId as string,
|
||||||
filters: queryFilters
|
filters: queryFilters
|
||||||
@@ -122,7 +125,7 @@ export default function GeneralPage() {
|
|||||||
enabled: build !== "oss"
|
enabled: build !== "oss"
|
||||||
});
|
});
|
||||||
|
|
||||||
const rows = data?.log ?? [];
|
const rows = isLoading ? generateSampleRequestLogs() : (data?.log ?? []);
|
||||||
const totalCount = data?.pagination?.total ?? 0;
|
const totalCount = data?.pagination?.total ?? 0;
|
||||||
const filterAttributes = data?.filterAttributes ?? {
|
const filterAttributes = data?.filterAttributes ?? {
|
||||||
actors: [],
|
actors: [],
|
||||||
@@ -681,7 +684,7 @@ export default function GeneralPage() {
|
|||||||
currentPage={currentPage}
|
currentPage={currentPage}
|
||||||
onPageChange={handlePageChange}
|
onPageChange={handlePageChange}
|
||||||
onPageSizeChange={handlePageSizeChange}
|
onPageSizeChange={handlePageSizeChange}
|
||||||
isLoading={isFetching}
|
isLoading={isLoading}
|
||||||
pageSize={pageSize}
|
pageSize={pageSize}
|
||||||
// Row expansion props
|
// Row expansion props
|
||||||
expandable={true}
|
expandable={true}
|
||||||
@@ -690,3 +693,63 @@ export default function GeneralPage() {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateSampleRequestLogs(): QueryRequestAuditLogResponse["log"] {
|
||||||
|
const methods = ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
||||||
|
const paths = [
|
||||||
|
"/api/v1/users",
|
||||||
|
"/dashboard",
|
||||||
|
"/settings",
|
||||||
|
"/health",
|
||||||
|
"/metrics"
|
||||||
|
];
|
||||||
|
const hosts = ["app.example.com", "api.example.com", "admin.example.com"];
|
||||||
|
const locations = ["US", "DE", "GB", "FR", "JP", "CA", "AU"];
|
||||||
|
const allowedReasons = [100, 101, 102, 103, 104, 105, 106, 107, 108];
|
||||||
|
const deniedReasons = [201, 202, 203, 204, 205, 299];
|
||||||
|
const actors = [
|
||||||
|
"alice@example.com",
|
||||||
|
"bob@example.com",
|
||||||
|
"carol@example.com",
|
||||||
|
null
|
||||||
|
];
|
||||||
|
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
const sevenDaysAgo = now - 7 * 24 * 60 * 60;
|
||||||
|
|
||||||
|
return Array.from({ length: 10 }, (_, i) => {
|
||||||
|
const action = Math.random() > 0.3;
|
||||||
|
const reason = action
|
||||||
|
? allowedReasons[Math.floor(Math.random() * allowedReasons.length)]
|
||||||
|
: deniedReasons[Math.floor(Math.random() * deniedReasons.length)];
|
||||||
|
const actor = actors[Math.floor(Math.random() * actors.length)];
|
||||||
|
|
||||||
|
return {
|
||||||
|
timestamp: Math.floor(
|
||||||
|
sevenDaysAgo + Math.random() * (now - sevenDaysAgo)
|
||||||
|
),
|
||||||
|
action,
|
||||||
|
reason,
|
||||||
|
orgId: "sample-org",
|
||||||
|
actorType: actor ? "user" : null,
|
||||||
|
actor,
|
||||||
|
actorId: actor ? `user-${i}` : null,
|
||||||
|
resourceId: Math.floor(Math.random() * 5) + 1,
|
||||||
|
siteResourceId: null,
|
||||||
|
resourceNiceId: `resource-${(i % 3) + 1}`,
|
||||||
|
resourceName: `Resource ${(i % 3) + 1}`,
|
||||||
|
ip: `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`,
|
||||||
|
location: locations[Math.floor(Math.random() * locations.length)],
|
||||||
|
userAgent: "Mozilla/5.0",
|
||||||
|
metadata: null,
|
||||||
|
headers: null,
|
||||||
|
query: null,
|
||||||
|
originalRequestURL: null,
|
||||||
|
scheme: "https",
|
||||||
|
host: hosts[Math.floor(Math.random() * hosts.length)],
|
||||||
|
path: paths[Math.floor(Math.random() * paths.length)],
|
||||||
|
method: methods[Math.floor(Math.random() * methods.length)],
|
||||||
|
tls: true
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
ChevronRight,
|
ChevronRight,
|
||||||
Download,
|
Download,
|
||||||
Loader,
|
Loader,
|
||||||
|
LoaderIcon,
|
||||||
RefreshCw
|
RefreshCw
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -427,7 +428,7 @@ export function LogDataTable<TData, TValue>({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent className="relative">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
{table.getHeaderGroups().map((headerGroup) => (
|
{table.getHeaderGroups().map((headerGroup) => (
|
||||||
@@ -535,6 +536,19 @@ export function LogDataTable<TData, TValue>({
|
|||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
|
{isLoading && (
|
||||||
|
<>
|
||||||
|
<div className="backdrop-blur-[2px] z-10 absolute inset-0 top-10"></div>
|
||||||
|
<div className="absolute z-20 left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 border border-border rounded-md bg-muted">
|
||||||
|
<div className="flex items-center gap-2 p-6">
|
||||||
|
<LoaderIcon className="size-4 animate-spin" />
|
||||||
|
{t("loadingEllipsis")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<DataTablePagination
|
<DataTablePagination
|
||||||
table={table}
|
table={table}
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
|
import { StatusHistoryResponse } from "@server/lib/statusHistory";
|
||||||
|
import type { ListAlertRulesResponse } from "@server/routers/alertRule/types";
|
||||||
import type { QueryRequestAnalyticsResponse } from "@server/routers/auditLogs";
|
import type { QueryRequestAnalyticsResponse } from "@server/routers/auditLogs";
|
||||||
import type { QueryRequestAuditLogResponse } from "@server/routers/auditLogs/types";
|
import type { QueryRequestAuditLogResponse } from "@server/routers/auditLogs/types";
|
||||||
import type { ListClientsResponse } from "@server/routers/client";
|
import type { ListClientsResponse } from "@server/routers/client";
|
||||||
import type {
|
import type {
|
||||||
ListDomainsResponse,
|
GetDNSRecordsResponse,
|
||||||
GetDNSRecordsResponse
|
ListDomainsResponse
|
||||||
} from "@server/routers/domain";
|
} from "@server/routers/domain";
|
||||||
import type { GetDomainResponse } from "@server/routers/domain/getDomain";
|
import type { GetDomainResponse } from "@server/routers/domain/getDomain";
|
||||||
|
import { ListHealthChecksResponse } from "@server/routers/healthChecks/types";
|
||||||
import type {
|
import type {
|
||||||
GetResourceWhitelistResponse,
|
GetResourceWhitelistResponse,
|
||||||
ListResourceNamesResponse,
|
ListResourceNamesResponse,
|
||||||
ListResourcesResponse
|
ListResourcesResponse
|
||||||
} from "@server/routers/resource";
|
} from "@server/routers/resource";
|
||||||
import type { ListAlertRulesResponse } from "@server/routers/alertRule/types";
|
|
||||||
import type { ListRolesResponse } from "@server/routers/role";
|
import type { ListRolesResponse } from "@server/routers/role";
|
||||||
import type { ListSitesResponse } from "@server/routers/site";
|
import type { ListSitesResponse } from "@server/routers/site";
|
||||||
import type {
|
import type {
|
||||||
@@ -32,8 +34,6 @@ import type { AxiosResponse } from "axios";
|
|||||||
import z from "zod";
|
import z from "zod";
|
||||||
import { remote } from "./api";
|
import { remote } from "./api";
|
||||||
import { durationToMs } from "./durationToMs";
|
import { durationToMs } from "./durationToMs";
|
||||||
import { ListHealthChecksResponse } from "@server/routers/healthChecks/types";
|
|
||||||
import { StatusHistoryResponse } from "@server/lib/statusHistory";
|
|
||||||
|
|
||||||
export type ProductUpdate = {
|
export type ProductUpdate = {
|
||||||
link: string | null;
|
link: string | null;
|
||||||
|
|||||||
Reference in New Issue
Block a user