mirror of
https://github.com/Buriburizaem0n/nezha-dash-v1.git
synced 2026-09-19 17:50:13 +00:00
fix: support per-server max/from/to in cycle transfer stats (#64)
* Initial plan
* fix: support per-server max/from/to values in cycle transfer stats
When the Nezha backend has multiple transfer rules within one alert rule,
the API may return per-server max values (as a map) instead of a single
max value. Update the TypeScript interface and CycleTransferStats component
to handle both formats:
- Single value (number/string): used for all servers (current behavior)
- Per-server map ({[serverId]: value}): uses the correct value per server
Fixes #63
Agent-Logs-Url: https://github.com/hamster1963/nezha-dash-v2/sessions/88f98dad-c2eb-4728-ac98-e02a95d5144d
Co-authored-by: hamster1963 <71394853+hamster1963@users.noreply.github.com>
* fix: update schema version in biome.json and improve null checks in components
* chore: auto-fix linting and formatting issues
* fix: guard null/zero in CycleTransferStats per-server map lookups
Agent-Logs-Url: https://github.com/hamster1963/nezha-dash-v2/sessions/2fb2306b-8011-487d-b284-9768778db8c3
Co-authored-by: hamster1963 <71394853+hamster1963@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: hamster1963 <71394853+hamster1963@users.noreply.github.com>
Co-authored-by: hamster1963 <1410514192@qq.com>
This commit is contained in:
co-authored by
hamster1963
hamster1963
parent
f69f480d3b
commit
2d46fb6b86
@@ -40,13 +40,36 @@ export const CycleTransferStatsCard: React.FC<CycleTransferStatsProps> = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
// Support per-server max values (map) or single max value (number)
|
||||
const max =
|
||||
typeof cycleData.max === "object" && cycleData.max !== null
|
||||
? cycleData.max[serverId]
|
||||
: cycleData.max;
|
||||
|
||||
// Support per-server from values (map) or single from value (string)
|
||||
const from =
|
||||
typeof cycleData.from === "object" && cycleData.from !== null
|
||||
? cycleData.from[serverId]
|
||||
: cycleData.from;
|
||||
|
||||
// Support per-server to values (map) or single to value (string)
|
||||
const to =
|
||||
typeof cycleData.to === "object" && cycleData.to !== null
|
||||
? cycleData.to[serverId]
|
||||
: cycleData.to;
|
||||
|
||||
// Skip rendering when required fields are missing or would cause invalid display
|
||||
if (!max || !from || !to) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<CycleTransferStatsClient
|
||||
key={`${cycleId}-${serverId}`}
|
||||
name={cycleData.name}
|
||||
from={cycleData.from}
|
||||
to={cycleData.to}
|
||||
max={cycleData.max}
|
||||
from={from}
|
||||
to={to}
|
||||
max={max}
|
||||
serverStats={[
|
||||
{
|
||||
serverId,
|
||||
|
||||
@@ -5,7 +5,7 @@ export default function PlanInfo({
|
||||
}: {
|
||||
parsedData: PublicNoteData;
|
||||
}) {
|
||||
if (!parsedData || !parsedData.planDataMod) {
|
||||
if (!parsedData?.planDataMod) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function ServerFlag({
|
||||
};
|
||||
|
||||
checkEmojiSupport();
|
||||
}, [forceUseSvgFlag]);
|
||||
}, []);
|
||||
|
||||
if (!country_code) return null;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function BillingInfo({
|
||||
parsedData: PublicNoteData;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
if (!parsedData || !parsedData.billingDataMod) {
|
||||
if (!parsedData?.billingDataMod) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,4 +52,4 @@ const AccordionContent = React.forwardRef<
|
||||
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
||||
|
||||
@@ -77,9 +77,9 @@ CardFooter.displayName = "CardFooter";
|
||||
|
||||
export {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
};
|
||||
|
||||
@@ -389,9 +389,9 @@ function getPayloadConfigFromPayload(
|
||||
|
||||
export {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
ChartLegend,
|
||||
ChartLegendContent,
|
||||
ChartStyle,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
};
|
||||
|
||||
@@ -149,11 +149,11 @@ CommandShortcut.displayName = "CommandShortcut";
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
};
|
||||
|
||||
@@ -108,13 +108,13 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogClose,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogOverlay,
|
||||
DialogPortal,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
};
|
||||
|
||||
@@ -180,18 +180,18 @@ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuTrigger,
|
||||
};
|
||||
|
||||
@@ -25,4 +25,4 @@ const PopoverContent = React.forwardRef<
|
||||
));
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent };
|
||||
export { Popover, PopoverContent, PopoverTrigger };
|
||||
|
||||
@@ -145,13 +145,13 @@ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectScrollUpButton,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
};
|
||||
|
||||
@@ -106,11 +106,11 @@ TableCaption.displayName = "TableCaption";
|
||||
|
||||
export {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
};
|
||||
|
||||
@@ -24,4 +24,4 @@ const TooltipContent = React.forwardRef<
|
||||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
||||
|
||||
@@ -128,10 +128,10 @@ export interface CycleTransferStats {
|
||||
|
||||
export interface CycleTransferData {
|
||||
name: string;
|
||||
from: string;
|
||||
to: string;
|
||||
max: number;
|
||||
min: number;
|
||||
from: string | { [key: string]: string };
|
||||
to: string | { [key: string]: string };
|
||||
max: number | { [key: string]: number };
|
||||
min: number | { [key: string]: number };
|
||||
server_name: {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user