diff --git a/src/shared/versions.js b/src/shared/versions.js index d6f3072..39f5443 100644 --- a/src/shared/versions.js +++ b/src/shared/versions.js @@ -1,6 +1,6 @@ export const HARBOR_VERSIONS = Object.freeze({ - macClient: '0.17.2', - gatewayClient: '0.18.2', + macClient: '0.17.3', + gatewayClient: '0.18.3', gatewayBackend: '0.18.0', }); diff --git a/src/web/components/DevicesPanel.jsx b/src/web/components/DevicesPanel.jsx index 84e64ca..5ced2cc 100644 --- a/src/web/components/DevicesPanel.jsx +++ b/src/web/components/DevicesPanel.jsx @@ -200,6 +200,8 @@ export function DevicesPanel({ open, panelRef, closeRef, onClose }) { const previousScrollTop = useRef(0); const movementAnimations = useRef(new Map()); const previousTraffic = useRef(new Map()); + const aliasBaseline = useRef({ id: '', value: '' }); + const aliasWidth = useRef('1px'); const copyTimer = useRef(null); const trafficDeltaTimer = useRef(null); const trafficOrder = useRef({ direction: sortDirection, ids: [] }); @@ -346,10 +348,14 @@ export function DevicesPanel({ open, panelRef, closeRef, onClose }) { } } - async function saveAlias(event, device) { - event.preventDefault(); - if (!await updateDevice(device, { alias })) return; - setEditingId(''); + async function saveAlias(device) { + const nextAlias = alias.trim(); + if (aliasBaseline.current.id === device.id && nextAlias === aliasBaseline.current.value.trim()) { + setEditingId((current) => current === device.id ? '' : current); + return; + } + if (!await updateDevice(device, { alias: nextAlias })) return; + setEditingId((current) => current === device.id ? '' : current); } async function updatePolicy(device, mode) { @@ -395,9 +401,12 @@ export function DevicesPanel({ open, panelRef, closeRef, onClose }) { copyTimer.current = setTimeout(() => setCopyFeedback(null), COPY_FEEDBACK_MS); } - function startEditing(device) { + function startEditing(device, width = 1) { + const value = device.alias || device.hostname || ''; + aliasBaseline.current = { id: device.id, value }; + aliasWidth.current = `${width}px`; setEditingId(device.id); - setAlias(device.alias || device.hostname || ''); + setAlias(value); } return ( @@ -560,56 +569,56 @@ export function DevicesPanel({ open, panelRef, closeRef, onClose }) {
- {editing ? ( -
saveAlias(event, device)}> +

+ {editing ? ( setAlias(event.target.value)} + onBlur={() => saveAlias(device)} + onKeyDown={(event) => { + if (event.key === 'Enter') event.currentTarget.blur(); + }} /> - - - - ) : ( - <> -

- {hasName && } - {hasName && device.ip && } - {device.ip ? : !hasName && Неизвестное устройство} -

- {!hasName && - - Изменить название - } - - )} + ) : hasName && } + {(hasName || (editing && Boolean(alias))) && device.ip && } + {device.ip ? : !hasName && !editing && Неизвестное устройство} + + {!hasName && !editing && + + Изменить название + }