refactor: Replace 'reach' field with 'public' boolean in service registration and related components

This commit is contained in:
2026-07-10 02:13:37 +00:00
parent fffc84e14c
commit 4feaa63da0
12 changed files with 112 additions and 220 deletions

View File

@@ -143,22 +143,8 @@ export function CrowdSecComponent() {
deleteDecision,
deleteBouncer,
deleteMachine,
provision,
isProvisioning,
} = useCrowdSec();
// Derive instance names from CrowdSec machines/bouncers with "wc-" prefix convention
const instances = [...new Set([
...(status?.machines ?? [])
.filter(m => m.machineId.startsWith('wc-'))
.map(m => m.machineId.replace(/^wc-/, '')),
...(status?.bouncers ?? [])
.filter(b => b.name.startsWith('wc-bouncer-'))
.map(b => b.name.replace(/^wc-bouncer-/, '').split('@')[0]),
])].sort();
const [provisionResults, setProvisionResults] = useState<Record<string, { ok: boolean; message: string }>>({});
const [provisioningInstance, setProvisioningInstance] = useState<string | null>(null);
const [blockSuccess, setBlockSuccess] = useState<string | null>(null);
const [timescale, setTimescale] = useState<Timescale>('24h');
@@ -167,20 +153,6 @@ export function CrowdSecComponent() {
});
const selectedType = watch('type');
function handleProvision(instanceName: string) {
setProvisioningInstance(instanceName);
provision(instanceName, {
onSuccess: (data) => {
setProvisionResults((prev) => ({ ...prev, [instanceName]: { ok: true, message: data.message } }));
setProvisioningInstance(null);
},
onError: (err) => {
setProvisionResults((prev) => ({ ...prev, [instanceName]: { ok: false, message: (err as Error).message } }));
setProvisioningInstance(null);
},
});
}
function onBlockSubmit(values: BlockFormValues) {
setBlockSuccess(null);
const req: AddDecisionRequest = { ip: values.ip, type: values.type, reason: values.reason, duration: values.duration };
@@ -707,88 +679,6 @@ export function CrowdSecComponent() {
</CardContent>
</Card>
{/* Provision Instances */}
<Card>
<CardHeader>
<div className="flex items-center gap-2">
<Zap className="h-4 w-4 text-muted-foreground" />
<CardTitle>Provision Instances</CardTitle>
</div>
</CardHeader>
<CardContent className="space-y-3">
<p className="text-sm text-muted-foreground">
<strong>Provisioning</strong> connects a Wild Cloud instance's CrowdSec agent to this LAPI —
generating credentials, registering agent and bouncer, and writing the LAPI URL into the
instance's app config. After provisioning, redeploy the CrowdSec app on the instance.
Safe to re-run.
</p>
<div className="space-y-2">
{instances.length === 0 ? (
<p className="text-sm text-muted-foreground">No instances found.</p>
) : (
instances.map((instanceName) => {
const agentName = `wc-${instanceName}`;
const bouncerName = `wc-bouncer-${instanceName}`;
const agent = status.machines.find((m) => m.machineId === agentName);
const bouncer = status.bouncers.find((b) => b.name === bouncerName);
const isActive = provisioningInstance === instanceName;
const result = provisionResults[instanceName];
return (
<div key={instanceName} className="rounded border p-3 space-y-2">
<div className="flex items-center justify-between">
<span className="font-mono text-sm font-medium">{instanceName}</span>
<Button
size="sm"
variant={agent ? 'outline' : 'default'}
onClick={() => handleProvision(instanceName)}
disabled={isProvisioning || isActive}
className="gap-2 h-7"
>
{isActive
? <><Loader2 className="h-3 w-3 animate-spin" />Provisioning</>
: agent
? <><Zap className="h-3 w-3" />Re-provision</>
: <><Zap className="h-3 w-3" />Provision</>
}
</Button>
</div>
<div className="flex items-center gap-4 text-xs">
<div className="flex items-center gap-1.5">
<span className="text-muted-foreground">Agent:</span>
{agent ? (
<Badge variant={agent.isValidated ? 'default' : 'secondary'} className="text-xs h-4">
{agent.isValidated ? 'validated' : 'pending'}
{agent.last_heartbeat && ` · ${formatRelativeTime(agent.last_heartbeat)}`}
</Badge>
) : (
<span className="text-muted-foreground italic">not provisioned</span>
)}
</div>
<div className="flex items-center gap-1.5">
<span className="text-muted-foreground">Bouncer:</span>
{bouncer ? (
<Badge variant={bouncer.revoked ? 'secondary' : 'default'} className="text-xs h-4">
{bouncer.revoked ? 'revoked' : 'active'}
</Badge>
) : (
<span className="text-muted-foreground italic">not provisioned</span>
)}
</div>
</div>
{result && (
<Alert variant={result.ok ? 'default' : 'error'} className="py-2">
{result.ok ? <CheckCircle className="h-3 w-3" /> : <AlertCircle className="h-3 w-3" />}
<AlertDescription className="text-xs">{result.message}</AlertDescription>
</Alert>
)}
</div>
);
})
)}
</div>
</CardContent>
</Card>
</>
)}
</div>