mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-23 13:59:09 +02:00
update exit node tab
This commit is contained in:
@@ -22,17 +22,32 @@ export const ExitNodes = () => {
|
|||||||
searchRef.current?.focus();
|
searchRef.current?.focus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Initial order: active-first, then by id. After that, positions are sticky
|
||||||
|
// — toggling a row doesn't move it. Mirrors the networks-list behavior so
|
||||||
|
// the optimistic radio flip paints in place instead of the row jumping to
|
||||||
|
// the top.
|
||||||
|
const orderRef = useRef<string[]>([]);
|
||||||
|
const ordered = useMemo(() => {
|
||||||
|
const byId = new Map(exitNodes.map((n) => [n.id, n]));
|
||||||
|
const kept = orderRef.current.filter((id) => byId.has(id));
|
||||||
|
const known = new Set(kept);
|
||||||
|
const fresh = exitNodes
|
||||||
|
.filter((n) => !known.has(n.id))
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.selected !== b.selected) return a.selected ? -1 : 1;
|
||||||
|
return a.id.localeCompare(b.id);
|
||||||
|
})
|
||||||
|
.map((n) => n.id);
|
||||||
|
const next = [...kept, ...fresh];
|
||||||
|
orderRef.current = next;
|
||||||
|
return next.map((id) => byId.get(id)!);
|
||||||
|
}, [exitNodes]);
|
||||||
|
|
||||||
const filtered = useMemo(() => {
|
const filtered = useMemo(() => {
|
||||||
const q = search.trim().toLowerCase();
|
const q = search.trim().toLowerCase();
|
||||||
const matches = exitNodes.filter((r) => {
|
if (!q) return ordered;
|
||||||
if (!q) return true;
|
return ordered.filter((r) => r.id.toLowerCase().includes(q));
|
||||||
return r.id.toLowerCase().includes(q);
|
}, [ordered, search]);
|
||||||
});
|
|
||||||
return matches.sort((a, b) => {
|
|
||||||
if (a.selected !== b.selected) return a.selected ? -1 : 1;
|
|
||||||
return a.id.localeCompare(b.id);
|
|
||||||
});
|
|
||||||
}, [exitNodes, search]);
|
|
||||||
|
|
||||||
if (isConnected && exitNodes.length === 0) {
|
if (isConnected && exitNodes.length === 0) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const ExitNodesList = ({ data, onToggle }: Props) => {
|
|||||||
onValueChange={handleChange}
|
onValueChange={handleChange}
|
||||||
className={"flex flex-col"}
|
className={"flex flex-col"}
|
||||||
>
|
>
|
||||||
<Row value={NONE_VALUE} label={t("exitNodes.none")} />
|
<Row value={NONE_VALUE} label={t("exitNodes.none")} first />
|
||||||
{data.map((n) => (
|
{data.map((n) => (
|
||||||
<Row key={n.id} value={n.id} label={n.id} />
|
<Row key={n.id} value={n.id} label={n.id} />
|
||||||
))}
|
))}
|
||||||
@@ -41,17 +41,26 @@ export const ExitNodesList = ({ data, onToggle }: Props) => {
|
|||||||
type RowProps = {
|
type RowProps = {
|
||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
first?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Row = ({ value, label }: RowProps) => (
|
const Row = ({ value, label, first }: RowProps) => (
|
||||||
<RadioGroup.Item
|
<RadioGroup.Item
|
||||||
value={value}
|
value={value}
|
||||||
className={cn(
|
className={cn(
|
||||||
"group flex items-center gap-3 px-7 py-3 min-w-0 text-left outline-none",
|
"group flex items-center gap-2.5 pl-6 pr-8 py-3 min-w-0 w-full",
|
||||||
"cursor-pointer wails-no-draggable",
|
first && "mt-2",
|
||||||
"hover:bg-nb-gray-900/40",
|
"hover:bg-nb-gray-900/40 transition-colors",
|
||||||
|
"wails-no-draggable cursor-pointer outline-none text-left",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
<span
|
||||||
|
className={
|
||||||
|
"min-w-0 flex-1 text-[0.81rem] font-medium text-nb-gray-100 truncate"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-4 w-4 shrink-0 rounded-full border",
|
"h-4 w-4 shrink-0 rounded-full border",
|
||||||
@@ -64,12 +73,5 @@ const Row = ({ value, label }: RowProps) => (
|
|||||||
className={"h-2 w-2 rounded-full bg-white"}
|
className={"h-2 w-2 rounded-full bg-white"}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span
|
|
||||||
className={
|
|
||||||
"text-[0.81rem] font-medium text-nb-gray-100 truncate min-w-0 flex-1"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</span>
|
|
||||||
</RadioGroup.Item>
|
</RadioGroup.Item>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user