mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 07:36:38 +08:00
30e1473f06
Replace read-then-subtract pattern in collectAndReport with atomic swap-to-zero to eliminate race where AddTraffic increments counters between snapshot and clearReportedTraffic, causing residual traffic to accumulate indefinitely and inflate user flow counters. Also add defensive check in processFlowItem to skip AddFlow when forward no longer exists, and send DeleteService to clean up orphaned agent services.
253 lines
7.3 KiB
TypeScript
253 lines
7.3 KiB
TypeScript
import * as React from "react";
|
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
function DropdownMenu({
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
|
}
|
|
|
|
function DropdownMenuTrigger({
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
return (
|
|
<DropdownMenuPrimitive.Trigger
|
|
data-slot="dropdown-menu-trigger"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuGroup({
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
return (
|
|
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
);
|
|
}
|
|
|
|
function DropdownMenuPortal({
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
return (
|
|
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
);
|
|
}
|
|
|
|
function DropdownMenuSub({
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
|
}
|
|
|
|
function DropdownMenuRadioGroup({
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
return (
|
|
<DropdownMenuPrimitive.RadioGroup
|
|
data-slot="dropdown-menu-radio-group"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuSubTrigger({
|
|
className,
|
|
inset,
|
|
children,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
|
inset?: boolean;
|
|
}) {
|
|
return (
|
|
<DropdownMenuPrimitive.SubTrigger
|
|
className={cn(
|
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-default-100 data-[state=open]:bg-default-100",
|
|
inset && "pl-8",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-sub-trigger"
|
|
{...props}
|
|
>
|
|
{children}
|
|
<ChevronRightIcon className="ml-auto h-4 w-4" />
|
|
</DropdownMenuPrimitive.SubTrigger>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuSubContent({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
return (
|
|
<DropdownMenuPrimitive.SubContent
|
|
className={cn(
|
|
"z-50 min-w-32 overflow-y-auto rounded-md border border-default-200 bg-white p-1.5 text-foreground shadow-lg max-h-[--radix-dropdown-menu-content-available-height] [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=top]:slide-in-from-bottom-2 data-[side=bottom]:slide-in-from-top-2 dark:bg-default-50",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-sub-content"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuContent({
|
|
className,
|
|
sideOffset = 6,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
return (
|
|
<DropdownMenuPrimitive.Portal>
|
|
<DropdownMenuPrimitive.Content
|
|
className={cn(
|
|
"z-50 min-w-32 overflow-y-auto rounded-md border border-default-200 bg-white p-1.5 text-foreground shadow-md max-h-[--radix-dropdown-menu-content-available-height] [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none] data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=top]:slide-in-from-bottom-2 data-[side=bottom]:slide-in-from-top-2 dark:bg-default-50",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-content"
|
|
sideOffset={sideOffset}
|
|
{...props}
|
|
/>
|
|
</DropdownMenuPrimitive.Portal>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuItem({
|
|
className,
|
|
inset,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
inset?: boolean;
|
|
}) {
|
|
return (
|
|
<DropdownMenuPrimitive.Item
|
|
className={cn(
|
|
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-default-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
inset && "pl-8",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-item"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuCheckboxItem({
|
|
className,
|
|
children,
|
|
checked,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
return (
|
|
<DropdownMenuPrimitive.CheckboxItem
|
|
checked={checked}
|
|
className={cn(
|
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-default-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-checkbox-item"
|
|
{...props}
|
|
>
|
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
<DropdownMenuPrimitive.ItemIndicator>
|
|
<CheckIcon className="h-4 w-4" />
|
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
</span>
|
|
{children}
|
|
</DropdownMenuPrimitive.CheckboxItem>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuRadioItem({
|
|
className,
|
|
children,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
return (
|
|
<DropdownMenuPrimitive.RadioItem
|
|
className={cn(
|
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-default-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-radio-item"
|
|
{...props}
|
|
>
|
|
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
|
<DropdownMenuPrimitive.ItemIndicator>
|
|
<CircleIcon className="h-2 w-2 fill-current" />
|
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
</span>
|
|
{children}
|
|
</DropdownMenuPrimitive.RadioItem>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuLabel({
|
|
className,
|
|
inset,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
|
inset?: boolean;
|
|
}) {
|
|
return (
|
|
<DropdownMenuPrimitive.Label
|
|
className={cn(
|
|
"px-2 py-1.5 text-sm font-semibold",
|
|
inset && "pl-8",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-label"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuSeparator({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
return (
|
|
<DropdownMenuPrimitive.Separator
|
|
className={cn("-mx-1 my-1 h-px bg-divider", className)}
|
|
data-slot="dropdown-menu-separator"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DropdownMenuShortcut({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<"span">) {
|
|
return (
|
|
<span
|
|
className={cn(
|
|
"ml-auto text-xs tracking-widest text-default-500",
|
|
className,
|
|
)}
|
|
data-slot="dropdown-menu-shortcut"
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export {
|
|
DropdownMenu,
|
|
DropdownMenuCheckboxItem,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuPortal,
|
|
DropdownMenuRadioGroup,
|
|
DropdownMenuRadioItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuShortcut,
|
|
DropdownMenuSub,
|
|
DropdownMenuSubContent,
|
|
DropdownMenuSubTrigger,
|
|
DropdownMenuTrigger,
|
|
};
|