feat(agents, config, dashboard, i18n): add agent line provision wizard, site deletion, and site dashboard with multi-language support

Added agent line provision wizard page with permission gating, replacing redirect placeholder. Introduced site deletion API and UI with confirmation dialog in integration sites management. Added new site-scoped dashboard panel showing bet metrics, P/L trends, active players, and quick links. Enhanced chart tooltip to support custom formatters and fix indicator color
This commit is contained in:
2026-06-12 20:47:53 +08:00
parent 24fd7c10bd
commit 6ea0a6feec
48 changed files with 1573 additions and 629 deletions

View File

@@ -0,0 +1,26 @@
"use client";
import Link from "next/link";
import type { ReactElement } from "react";
import { useTranslation } from "react-i18next";
import { AdminNoResourceState } from "@/components/admin/admin-no-resource-state";
import { Button } from "@/components/ui/button";
export function AdminNoIntegrationSiteState({
canCreate = false,
}: {
canCreate?: boolean;
}): ReactElement {
const { t } = useTranslation("common");
return (
<AdminNoResourceState message={t("integrationSites.emptyPlatformHint")}>
{canCreate ? (
<Button nativeButton={false} size="sm" render={<Link href="/admin/config/integration-sites" />}>
{t("integrationSites.createSite")}
</Button>
) : null}
</AdminNoResourceState>
);
}

View File

@@ -202,7 +202,15 @@ function ChartTooltipContent({
.map((item, index) => {
const key = `${nameKey ?? item.name ?? item.dataKey ?? "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const indicatorColor = color ?? item.payload?.fill ?? item.color
const configColor =
itemConfig && "color" in itemConfig ? itemConfig.color : undefined
const indicatorColor =
color ?? item.color ?? item.payload?.fill ?? configColor
const formattedValue =
formatter && item?.value !== undefined && item.name
? formatter(item.value, item.name, item, index, item.payload)
: null
return (
<div
@@ -212,56 +220,50 @@ function ChartTooltipContent({
indicator === "dot" && "items-center"
)}
>
{formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
<>
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
!hideIndicator && (
<div
className={cn(
"shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
{
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
}
)}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)
)}
!hideIndicator && (
<div
className={cn(
"flex flex-1 justify-between leading-none",
nestLabel ? "items-end" : "items-center"
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label ?? item.name}
</span>
</div>
{item.value != null && (
<span className="font-mono font-medium text-foreground tabular-nums">
{typeof item.value === "number"
? item.value.toLocaleString()
: String(item.value)}
</span>
)}
</div>
</>
className={cn("shrink-0 rounded-[2px]", {
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
})}
style={
indicator === "dashed"
? { borderColor: indicatorColor }
: {
backgroundColor: indicatorColor,
borderColor: indicatorColor,
}
}
/>
)
)}
<div
className={cn(
"flex flex-1 justify-between leading-none",
nestLabel ? "items-end" : "items-center"
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label ?? item.name}
</span>
</div>
{item.value != null && (
<span className="font-mono font-medium text-foreground tabular-nums">
{formattedValue ??
(typeof item.value === "number"
? item.value.toLocaleString()
: String(item.value))}
</span>
)}
</div>
</div>
)
})}