feat: Allow multiple selections for regional agents.

- Allow multiple regional agents to be selected in the service dialog form, similar to the notification channels.
This commit is contained in:
Tola Leng
2025-07-10 23:06:10 +07:00
parent 7fd6d07c10
commit de79eb963d
6 changed files with 135 additions and 85 deletions
@@ -6,7 +6,9 @@ import { UseFormReturn } from "react-hook-form";
import { ServiceFormData } from "./types";
import { useQuery } from "@tanstack/react-query";
import { regionalService } from "@/services/regionalService";
import { MapPin, Loader2, X } from "lucide-react";
import { MapPin, Loader2, X, Plus } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
interface ServiceRegionalFieldsProps {
form: UseFormReturn<ServiceFormData>;
@@ -14,7 +16,7 @@ interface ServiceRegionalFieldsProps {
export function ServiceRegionalFields({ form }: ServiceRegionalFieldsProps) {
const regionalMonitoringEnabled = form.watch("regionalMonitoringEnabled");
const currentRegionalAgent = form.watch("regionalAgent");
const currentRegionalAgents = form.watch("regionalAgents") || [];
const { data: regionalAgents = [], isLoading } = useQuery({
queryKey: ['regional-services'],
@@ -27,15 +29,16 @@ export function ServiceRegionalFields({ form }: ServiceRegionalFieldsProps) {
agent.connection === 'online' && agent.agent_id !== "1"
);
// Find the current agent name for display
const getCurrentAgentDisplay = () => {
if (!currentRegionalAgent || currentRegionalAgent === "unassign") {
return "Select a regional agent or unassign";
}
const [regionName, agentId] = currentRegionalAgent.split("|");
// Get available agents (not already selected)
const availableAgents = onlineAgents.filter(agent =>
!currentRegionalAgents.includes(`${agent.region_name}|${agent.agent_id}`)
);
// Get agent display name
const getAgentDisplayName = (agentValue: string) => {
const [regionName, agentId] = agentValue.split("|");
const agent = onlineAgents.find(agent =>
`${agent.region_name}|${agent.agent_id}` === currentRegionalAgent
`${agent.region_name}|${agent.agent_id}` === agentValue
);
if (agent) {
@@ -43,25 +46,27 @@ export function ServiceRegionalFields({ form }: ServiceRegionalFieldsProps) {
}
// If agent is not found in online agents, it might be offline but still assigned
// Show the region name from the stored value
if (regionName && agentId) {
return `${regionName} (Agent ${agentId}) - Offline`;
}
return "Select a regional agent or unassign";
return agentValue;
};
// Get the proper select value - handle both assigned and unassigned cases
const getSelectValue = () => {
if (!regionalMonitoringEnabled) {
return "unassign";
// Add regional agent
const addRegionalAgent = (agentValue: string) => {
if (agentValue && agentValue !== "select") {
const currentAgents = form.getValues("regionalAgents") || [];
if (!currentAgents.includes(agentValue)) {
form.setValue("regionalAgents", [...currentAgents, agentValue]);
}
}
if (!currentRegionalAgent || currentRegionalAgent === "") {
return "unassign";
}
return currentRegionalAgent;
};
// Remove regional agent
const removeRegionalAgent = (agentValue: string) => {
const currentAgents = form.getValues("regionalAgents") || [];
form.setValue("regionalAgents", currentAgents.filter(agent => agent !== agentValue));
};
return (
@@ -77,13 +82,19 @@ export function ServiceRegionalFields({ form }: ServiceRegionalFieldsProps) {
Regional Monitoring
</FormLabel>
<div className="text-sm text-muted-foreground">
Assign this service to a regional monitoring agent for distributed monitoring
Assign this service to regional monitoring agents for distributed monitoring
</div>
</div>
<FormControl>
<Switch
checked={field.value || false}
onCheckedChange={field.onChange}
onCheckedChange={(checked) => {
field.onChange(checked);
// Clear agents when disabling regional monitoring
if (!checked) {
form.setValue("regionalAgents", []);
}
}}
/>
</FormControl>
</FormItem>
@@ -93,16 +104,36 @@ export function ServiceRegionalFields({ form }: ServiceRegionalFieldsProps) {
{regionalMonitoringEnabled && (
<FormField
control={form.control}
name="regionalAgent"
name="regionalAgents"
render={({ field }) => (
<FormItem>
<FormLabel>Regional Agent</FormLabel>
<FormLabel>Regional Agents</FormLabel>
{/* Display selected agents */}
{currentRegionalAgents.length > 0 && (
<div className="flex flex-wrap gap-2 mb-3">
{currentRegionalAgents.map((agentValue) => (
<Badge key={agentValue} variant="secondary" className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="text-sm">{getAgentDisplayName(agentValue)}</span>
<Button
type="button"
variant="ghost"
size="sm"
className="h-4 w-4 p-0 ml-1"
onClick={() => removeRegionalAgent(agentValue)}
>
<X className="h-3 w-3" />
</Button>
</Badge>
))}
</div>
)}
{/* Add new agent selector */}
<Select
onValueChange={(value) => {
// Handle the unassign case by setting to empty string
field.onChange(value === "unassign" ? "" : value);
}}
value={getSelectValue()}
onValueChange={addRegionalAgent}
value="select"
disabled={isLoading}
>
<FormControl>
@@ -110,7 +141,11 @@ export function ServiceRegionalFields({ form }: ServiceRegionalFieldsProps) {
<SelectValue placeholder={
isLoading
? "Loading agents..."
: getCurrentAgentDisplay()
: availableAgents.length > 0
? "Select additional regional agents..."
: currentRegionalAgents.length > 0
? "All available agents selected"
: "No regional agents available"
} />
</SelectTrigger>
</FormControl>
@@ -122,47 +157,52 @@ export function ServiceRegionalFields({ form }: ServiceRegionalFieldsProps) {
Loading agents...
</div>
</SelectItem>
) : availableAgents.length === 0 ? (
<SelectItem value="no-agents" disabled>
{currentRegionalAgents.length > 0
? "All available agents selected"
: "No online regional agents available"
}
</SelectItem>
) : (
<>
<SelectItem value="unassign">
<SelectItem value="select" disabled>
<div className="flex items-center gap-2">
<X className="h-4 w-4 text-red-500" />
<span className="text-red-600">Unassign (No Regional Agent)</span>
<Plus className="h-4 w-4 text-muted-foreground" />
<span className="text-muted-foreground">Select an agent to add...</span>
</div>
</SelectItem>
{onlineAgents.length === 0 ? (
<SelectItem value="no-agents" disabled>
No online regional agents available
{availableAgents.map((agent) => (
<SelectItem key={agent.id} value={`${agent.region_name}|${agent.agent_id}`}>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">{agent.region_name}</span>
<span className="text-muted-foreground">({agent.agent_ip_address})</span>
</div>
</SelectItem>
) : (
onlineAgents.map((agent) => (
<SelectItem key={agent.id} value={`${agent.region_name}|${agent.agent_id}`}>
<div className="flex items-center gap-2">
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="font-medium">{agent.region_name}</span>
<span className="text-muted-foreground">({agent.agent_ip_address})</span>
</div>
</SelectItem>
))
)}
))}
</>
)}
</SelectContent>
</Select>
<FormMessage />
{regionalMonitoringEnabled && onlineAgents.length === 0 && !isLoading && (
<p className="text-sm text-amber-600">
No online regional agents found. Services will use default monitoring.
</p>
)}
{currentRegionalAgent && currentRegionalAgent !== "" && (
<p className="text-sm text-green-600">
Currently assigned to: {getCurrentAgentDisplay()}
{currentRegionalAgents.length === 0 && regionalMonitoringEnabled && (
<p className="text-sm text-orange-600">
No regional agents selected. Service will use default monitoring.
</p>
)}
{(!currentRegionalAgent || currentRegionalAgent === "") && regionalMonitoringEnabled && (
<p className="text-sm text-orange-600">
Service is unassigned and will use default monitoring.
{currentRegionalAgents.length > 0 && (
<p className="text-sm text-green-600">
Service assigned to {currentRegionalAgents.length} regional agent{currentRegionalAgents.length > 1 ? 's' : ''}.
</p>
)}
</FormItem>