import { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { Plus, Pencil, Trash2, RefreshCw, AlertCircle, Store } from 'lucide-react';
import { connectivityAPI } from '../../services/api';
import { useConnectivityData } from './useConnectivityData';
import {
Toast, useToasts, toastEvent, apiError, typeMeta,
GROUP_TYPES, GROUP_LABELS, LifecycleBadge, HealthDot, TypeIcon,
lifecycleOf, buildRefCounts,
} from './shared';
function DeleteDialog({ conn, onConfirm, onCancel, deleting }) {
return (
Delete "{conn.name}"?
This removes the connection. Peers or services assigned to it must be
re-pointed first โ the API blocks deletion while it is in use.
);
}
export default function ConnectionListPage({ group }) {
const toasts = useToasts();
const navigate = useNavigate();
const {
connections, peerExits, serviceEgress, installed, loading, error, reload,
} = useConnectivityData();
const [delTarget, setDelTarget] = useState(null);
const [deleting, setDeleting] = useState(false);
const types = GROUP_TYPES[group] || [];
const rows = connections.filter((c) => types.includes(c.type));
const refs = buildRefCounts(peerExits, serviceEgress);
// The backing store service for this group is considered installed if any of
// its types' service ids is present in the installed map.
const anyServiceInstalled = types.some((t) => {
const svc = typeMeta(t).service;
return svc && installed[svc];
});
const handleDelete = async () => {
setDeleting(true);
try {
await connectivityAPI.deleteConnection(delTarget.id);
toastEvent(`Deleted ${delTarget.name}`);
setDelTarget(null);
await reload();
} catch (err) {
// 409 โ in use; surface the API's specific message.
toastEvent(apiError(err, `Failed to delete ${delTarget.name}`), 'error');
} finally {
setDeleting(false);
}
};
const title = GROUP_LABELS[group] || group;
// For single-type groups the "Add" button targets that type; multi-type
// groups default to the first type (the form lets the user switch).
const addType = types[0];
return (
{title}
{group === 'tor'
? 'A single Tor exit for anonymised peer traffic'
: `Manage ${title.toLowerCase()} exit connections`}
{/* Tor is a singleton โ hide Add once one exists */}
{!(group === 'tor' && rows.length > 0) && (
Add {typeMeta(addType).short}
)}
{loading && (
)}
{!loading && error && (
Failed to load connections
{error}
)}
{!loading && !error && rows.length === 0 && (
No {title.toLowerCase()} configured yet
{anyServiceInstalled
? `Add your first ${typeMeta(addType).short} connection to route peer traffic through it.`
: 'The backing service is not installed yet.'}
Add {typeMeta(addType).short}
{!anyServiceInstalled && (
Open Store
)}