mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-07 21:07:23 +00:00
Add resource
This commit is contained in:
@@ -41,6 +41,7 @@ type AlertRuleRow = {
|
||||
updatedAt: number;
|
||||
siteIds: number[];
|
||||
healthCheckIds: number[];
|
||||
resourceIds: number[];
|
||||
};
|
||||
|
||||
function ruleHref(orgId: string, ruleId: number) {
|
||||
@@ -53,10 +54,14 @@ function sourceSummary(
|
||||
) {
|
||||
if (
|
||||
rule.eventType === "site_online" ||
|
||||
rule.eventType === "site_offline"
|
||||
rule.eventType === "site_offline" ||
|
||||
rule.eventType === "site_toggle"
|
||||
) {
|
||||
return t("alertingSummarySites", { count: rule.siteIds.length });
|
||||
}
|
||||
if (rule.eventType.startsWith("resource_")) {
|
||||
return t("alertingSummaryResources", { count: rule.resourceIds.length });
|
||||
}
|
||||
return t("alertingSummaryHealthChecks", {
|
||||
count: rule.healthCheckIds.length
|
||||
});
|
||||
@@ -79,6 +84,12 @@ function triggerLabel(
|
||||
return t("alertingTriggerHcUnhealthy");
|
||||
case "health_check_toggle":
|
||||
return t("alertingTriggerHcToggle");
|
||||
case "resource_healthy":
|
||||
return t("alertingTriggerResourceHealthy");
|
||||
case "resource_unhealthy":
|
||||
return t("alertingTriggerResourceUnhealthy");
|
||||
case "resource_toggle":
|
||||
return t("alertingTriggerResourceToggle");
|
||||
default:
|
||||
return rule.eventType;
|
||||
}
|
||||
|
||||
@@ -275,6 +275,93 @@ function HealthCheckMultiSelect({
|
||||
);
|
||||
}
|
||||
|
||||
function ResourceMultiSelect({
|
||||
orgId,
|
||||
value,
|
||||
onChange
|
||||
}: {
|
||||
orgId: string;
|
||||
value: number[];
|
||||
onChange: (v: number[]) => void;
|
||||
}) {
|
||||
const t = useTranslations();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [q, setQ] = useState("");
|
||||
const [debounced] = useDebounce(q, 150);
|
||||
|
||||
const { data: resources = [] } = useQuery(
|
||||
orgQueries.resources({ orgId, query: debounced, perPage: 10 })
|
||||
);
|
||||
|
||||
const shown = useMemo(() => {
|
||||
return resources;
|
||||
}, [resources]);
|
||||
|
||||
const toggle = (id: number) => {
|
||||
if (value.includes(id)) {
|
||||
onChange(value.filter((x) => x !== id));
|
||||
} else {
|
||||
onChange([...value, id]);
|
||||
}
|
||||
};
|
||||
|
||||
const summary =
|
||||
value.length === 0
|
||||
? t("alertingSelectResources")
|
||||
: t("alertingResourcesSelected", { count: value.length });
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
className="w-full justify-between font-normal"
|
||||
>
|
||||
<span className="truncate">{summary}</span>
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
className="w-[var(--radix-popover-trigger-width)] p-0"
|
||||
align="start"
|
||||
>
|
||||
<Command shouldFilter={false}>
|
||||
<CommandInput
|
||||
placeholder={t("alertingSelectResources")}
|
||||
value={q}
|
||||
onValueChange={setQ}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty>
|
||||
{t("alertingResourcesEmpty")}
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{shown.map((r) => (
|
||||
<CommandItem
|
||||
key={r.resourceId}
|
||||
value={`${r.resourceId}:${r.name}`}
|
||||
onSelect={() => toggle(r.resourceId)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<Checkbox
|
||||
checked={value.includes(r.resourceId)}
|
||||
className="mr-2 pointer-events-none shrink-0"
|
||||
aria-hidden
|
||||
tabIndex={-1}
|
||||
/>
|
||||
<span className="truncate">{r.name}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
export function ActionBlock({
|
||||
orgId,
|
||||
index,
|
||||
@@ -895,6 +982,18 @@ export function AlertRuleSourceFields({
|
||||
shouldValidate: true
|
||||
});
|
||||
}
|
||||
} else if (next === "resource") {
|
||||
if (
|
||||
curTrigger !== "resource_healthy" &&
|
||||
curTrigger !== "resource_unhealthy" &&
|
||||
curTrigger !== "resource_toggle"
|
||||
) {
|
||||
setValue(
|
||||
"trigger",
|
||||
"resource_unhealthy",
|
||||
{ shouldValidate: true }
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
curTrigger !== "health_check_healthy" &&
|
||||
curTrigger !== "health_check_unhealthy" &&
|
||||
@@ -920,6 +1019,9 @@ export function AlertRuleSourceFields({
|
||||
<SelectItem value="health_check">
|
||||
{t("alertingSourceHealthCheck")}
|
||||
</SelectItem>
|
||||
<SelectItem value="resource">
|
||||
{t("alertingSourceResource")}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
@@ -942,6 +1044,22 @@ export function AlertRuleSourceFields({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
) : sourceType === "resource" ? (
|
||||
<FormField
|
||||
control={control}
|
||||
name="resourceIds"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("alertingPickResources")}</FormLabel>
|
||||
<ResourceMultiSelect
|
||||
orgId={orgId}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
/>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<FormField
|
||||
control={control}
|
||||
@@ -1002,6 +1120,18 @@ export function AlertRuleTriggerFields({
|
||||
{t("alertingTriggerSiteToggle")}
|
||||
</SelectItem>
|
||||
</>
|
||||
) : sourceType === "resource" ? (
|
||||
<>
|
||||
<SelectItem value="resource_healthy">
|
||||
{t("alertingTriggerResourceHealthy")}
|
||||
</SelectItem>
|
||||
<SelectItem value="resource_unhealthy">
|
||||
{t("alertingTriggerResourceUnhealthy")}
|
||||
</SelectItem>
|
||||
<SelectItem value="resource_toggle">
|
||||
{t("alertingTriggerResourceToggle")}
|
||||
</SelectItem>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<SelectItem value="health_check_healthy">
|
||||
|
||||
@@ -82,6 +82,12 @@ function summarizeSource(v: AlertRuleFormValues, t: AlertRuleT) {
|
||||
}
|
||||
return t("alertingSummarySites", { count: v.siteIds.length });
|
||||
}
|
||||
if (v.sourceType === "resource") {
|
||||
if (v.resourceIds.length === 0) {
|
||||
return t("alertingNodeNotConfigured");
|
||||
}
|
||||
return t("alertingSummaryResources", { count: v.resourceIds.length });
|
||||
}
|
||||
if (v.healthCheckIds.length === 0) {
|
||||
return t("alertingNodeNotConfigured");
|
||||
}
|
||||
@@ -102,6 +108,12 @@ function summarizeTrigger(v: AlertRuleFormValues, t: AlertRuleT) {
|
||||
return t("alertingTriggerHcUnhealthy");
|
||||
case "health_check_toggle":
|
||||
return t("alertingTriggerHcToggle");
|
||||
case "resource_healthy":
|
||||
return t("alertingTriggerResourceHealthy");
|
||||
case "resource_unhealthy":
|
||||
return t("alertingTriggerResourceUnhealthy");
|
||||
case "resource_toggle":
|
||||
return t("alertingTriggerResourceToggle");
|
||||
default:
|
||||
return v.trigger;
|
||||
}
|
||||
@@ -338,6 +350,8 @@ export default function AlertRuleGraphEditor({
|
||||
useWatch({ control: form.control, name: "siteIds" }) ?? [];
|
||||
const wHealthCheckIds =
|
||||
useWatch({ control: form.control, name: "healthCheckIds" }) ?? [];
|
||||
const wResourceIds =
|
||||
useWatch({ control: form.control, name: "resourceIds" }) ?? [];
|
||||
const wTrigger =
|
||||
useWatch({ control: form.control, name: "trigger" }) ??
|
||||
"site_offline";
|
||||
@@ -351,6 +365,7 @@ export default function AlertRuleGraphEditor({
|
||||
sourceType: wSourceType,
|
||||
siteIds: wSiteIds,
|
||||
healthCheckIds: wHealthCheckIds,
|
||||
resourceIds: wResourceIds,
|
||||
trigger: wTrigger,
|
||||
actions: wActions
|
||||
}),
|
||||
@@ -360,6 +375,7 @@ export default function AlertRuleGraphEditor({
|
||||
wSourceType,
|
||||
wSiteIds,
|
||||
wHealthCheckIds,
|
||||
wResourceIds,
|
||||
wTrigger,
|
||||
wActions
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user