mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-07 11:16:37 +00:00
💄handle empty data
This commit is contained in:
@@ -2154,5 +2154,6 @@
|
|||||||
"niceIdUpdateErrorDescription": "An error occurred while updating the Nice ID.",
|
"niceIdUpdateErrorDescription": "An error occurred while updating the Nice ID.",
|
||||||
"niceIdCannotBeEmpty": "Nice ID cannot be empty",
|
"niceIdCannotBeEmpty": "Nice ID cannot be empty",
|
||||||
"enterIdentifier": "Enter identifier",
|
"enterIdentifier": "Enter identifier",
|
||||||
"identifier": "Identifier"
|
"identifier": "Identifier",
|
||||||
|
"noData": "No Data"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Card, CardContent, CardHeader } from "./ui/card";
|
import { Card, CardContent, CardHeader } from "./ui/card";
|
||||||
import { RefreshCw, XIcon } from "lucide-react";
|
import { LoaderIcon, RefreshCw, XIcon } from "lucide-react";
|
||||||
import { DateRangePicker, type DateTimeValue } from "./DateTimePicker";
|
import { DateRangePicker, type DateTimeValue } from "./DateTimePicker";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
@@ -74,7 +74,8 @@ export function LogAnalyticsData(props: AnalyticsContentProps) {
|
|||||||
const {
|
const {
|
||||||
data: stats,
|
data: stats,
|
||||||
isFetching: isFetchingAnalytics,
|
isFetching: isFetchingAnalytics,
|
||||||
refetch: refreshAnalytics
|
refetch: refreshAnalytics,
|
||||||
|
isLoading: isLoadingAnalytics // only `true` when there is no data yet
|
||||||
} = useQuery(
|
} = useQuery(
|
||||||
logQueries.requestAnalytics({
|
logQueries.requestAnalytics({
|
||||||
orgId: props.orgId,
|
orgId: props.orgId,
|
||||||
@@ -296,6 +297,7 @@ export function LogAnalyticsData(props: AnalyticsContentProps) {
|
|||||||
<TopCountriesList
|
<TopCountriesList
|
||||||
countries={stats?.requestsPerCountry ?? []}
|
countries={stats?.requestsPerCountry ?? []}
|
||||||
total={stats?.totalRequests ?? 0}
|
total={stats?.totalRequests ?? 0}
|
||||||
|
isLoading={isLoadingAnalytics}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -310,6 +312,7 @@ type TopCountriesListProps = {
|
|||||||
count: number;
|
count: number;
|
||||||
}[];
|
}[];
|
||||||
total: number;
|
total: number;
|
||||||
|
isLoading: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function TopCountriesList(props: TopCountriesListProps) {
|
function TopCountriesList(props: TopCountriesListProps) {
|
||||||
@@ -331,13 +334,27 @@ function TopCountriesList(props: TopCountriesListProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col gap-2">
|
<div className="h-full flex flex-col gap-2">
|
||||||
<div className="grid grid-cols-7 text-sm text-muted-foreground font-medium h-4">
|
{props.countries.length > 0 && (
|
||||||
<div className="col-span-5">{t("countries")}</div>
|
<div className="grid grid-cols-7 text-sm text-muted-foreground font-medium h-4">
|
||||||
<div className="text-end">{t("total")}</div>
|
<div className="col-span-5">{t("countries")}</div>
|
||||||
<div className="text-end">%</div>
|
<div className="text-end">{t("total")}</div>
|
||||||
</div>
|
<div className="text-end">%</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{/* `aspect-475/335` is the same aspect ratio as the world map component */}
|
{/* `aspect-475/335` is the same aspect ratio as the world map component */}
|
||||||
<ol className="w-full overflow-auto grid gap-1 aspect-475/335">
|
<ol className="w-full overflow-auto grid gap-1 aspect-475/335">
|
||||||
|
{props.countries.length === 0 && (
|
||||||
|
<div className="flex items-center justify-center size-full text-muted-foreground font-mono gap-1">
|
||||||
|
{props.isLoading ? (
|
||||||
|
<>
|
||||||
|
<LoaderIcon className="size-4 animate-spin" />{" "}
|
||||||
|
{t("loading")}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
t("noData")
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{props.countries.map((country) => {
|
{props.countries.map((country) => {
|
||||||
const percent = country.count / props.total;
|
const percent = country.count / props.total;
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user