feat: upgrade codemirror to 6.39.13 and enhance host switching

This commit is contained in:
Bohdan Triapitsyn
2026-02-10 01:16:13 +02:00
parent 29eb71a7d5
commit b727f16b80
6 changed files with 68 additions and 16 deletions
+5 -6
View File
@@ -23,7 +23,7 @@
"@codemirror/lint": "^6.9.2",
"@codemirror/search": "^6.6.0",
"@codemirror/state": "^6.5.4",
"@codemirror/view": "^6.39.11",
"@codemirror/view": "^6.39.13",
"@fontsource/ibm-plex-mono": "^5.2.7",
"@fontsource/ibm-plex-sans": "^5.1.1",
"@heroui/scroll-shadow": "^2.3.18",
@@ -128,7 +128,7 @@
"@codemirror/lint": "^6.9.2",
"@codemirror/search": "^6.6.0",
"@codemirror/state": "^6.5.4",
"@codemirror/view": "^6.39.11",
"@codemirror/view": "^6.39.13",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
@@ -301,6 +301,9 @@
},
},
},
"overrides": {
"@codemirror/view": "6.39.13",
},
"packages": {
"7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="],
@@ -3230,14 +3233,10 @@
"@codemirror/highlight/@codemirror/state": ["@codemirror/state@0.19.9", "", { "dependencies": { "@codemirror/text": "^0.19.0" } }, "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw=="],
"@codemirror/highlight/@codemirror/view": ["@codemirror/view@0.19.48", "", { "dependencies": { "@codemirror/rangeset": "^0.19.5", "@codemirror/state": "^0.19.3", "@codemirror/text": "^0.19.0", "style-mod": "^4.0.0", "w3c-keyname": "^2.2.4" } }, "sha512-0eg7D2Nz4S8/caetCTz61rK0tkHI17V/d15Jy0kLOT8dTLGGNJUponDnW28h2B6bERmPlVHKh8MJIr5OCp1nGw=="],
"@codemirror/highlight/@lezer/common": ["@lezer/common@0.15.12", "", {}, "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig=="],
"@codemirror/history/@codemirror/state": ["@codemirror/state@0.19.9", "", { "dependencies": { "@codemirror/text": "^0.19.0" } }, "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw=="],
"@codemirror/history/@codemirror/view": ["@codemirror/view@0.19.48", "", { "dependencies": { "@codemirror/rangeset": "^0.19.5", "@codemirror/state": "^0.19.3", "@codemirror/text": "^0.19.0", "style-mod": "^4.0.0", "w3c-keyname": "^2.2.4" } }, "sha512-0eg7D2Nz4S8/caetCTz61rK0tkHI17V/d15Jy0kLOT8dTLGGNJUponDnW28h2B6bERmPlVHKh8MJIr5OCp1nGw=="],
"@codemirror/rangeset/@codemirror/state": ["@codemirror/state@0.19.9", "", { "dependencies": { "@codemirror/text": "^0.19.0" } }, "sha512-psOzDolKTZkx4CgUqhBQ8T8gBc0xN5z4gzed109aF6x7D7umpDRoimacI/O6d9UGuyl4eYuDCZmDFr2Rq7aGOw=="],
"@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
+4 -1
View File
@@ -76,7 +76,7 @@
"@codemirror/lint": "^6.9.2",
"@codemirror/search": "^6.6.0",
"@codemirror/state": "^6.5.4",
"@codemirror/view": "^6.39.11",
"@codemirror/view": "^6.39.13",
"@fontsource/ibm-plex-mono": "^5.2.7",
"@fontsource/ibm-plex-sans": "^5.1.1",
"@heroui/scroll-shadow": "^2.3.18",
@@ -120,6 +120,9 @@
"zod": "^4.3.6",
"zustand": "^5.0.8"
},
"overrides": {
"@codemirror/view": "6.39.13"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
"@tailwindcss/postcss": "^4.0.0",
+24
View File
@@ -1121,6 +1121,7 @@ async fn desktop_host_probe(url: String) -> Result<HostProbeResult, String> {
.build()
.map_err(|err| err.to_string())?;
let started = std::time::Instant::now();
match client.get(&health).send().await {
Ok(resp) => {
let status = resp.status();
@@ -2086,6 +2087,29 @@ fn main() {
}
}
if initial_url != local_ui_url {
match desktop_host_probe(initial_url.clone()).await {
Ok(probe) if probe.status != "unreachable" => {}
Ok(_) => {
log::warn!(
"[desktop] startup host unreachable ({}), falling back to local ({})",
initial_url,
local_ui_url
);
initial_url = local_ui_url.clone();
}
Err(err) => {
log::warn!(
"[desktop] startup host probe failed ({}): {}, falling back to local ({})",
initial_url,
err,
local_ui_url
);
initial_url = local_ui_url.clone();
}
}
}
if let Err(err) = create_main_window(&handle, &initial_url, &local_origin) {
log::error!("[desktop] failed to create window: {err}");
}
+2 -2
View File
@@ -31,7 +31,7 @@
"@codemirror/lint": "^6.9.2",
"@codemirror/search": "^6.6.0",
"@codemirror/state": "^6.5.4",
"@codemirror/view": "^6.39.11",
"@codemirror/view": "^6.39.13",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
@@ -102,4 +102,4 @@
"typescript-eslint": "^8.39.1",
"vite": "^7.1.2"
}
}
}
@@ -31,6 +31,7 @@ import {
RiDeleteBinLine,
} from '@remixicon/react';
import { cn } from '@/lib/utils';
import { toast } from '@/components/ui';
import { isTauriShell, isDesktopShell } from '@/lib/desktop';
import {
desktopHostProbe,
@@ -160,6 +161,7 @@ export function DesktopHostSwitcherDialog({
const [isLoading, setIsLoading] = React.useState(false);
const [isProbing, setIsProbing] = React.useState(false);
const [isSaving, setIsSaving] = React.useState(false);
const [switchingHostId, setSwitchingHostId] = React.useState<string | null>(null);
const [error, setError] = React.useState<string>('');
const [editingId, setEditingId] = React.useState<string | null>(null);
@@ -262,9 +264,25 @@ export function DesktopHostSwitcherDialog({
void probeAll(allHosts);
}, [open, allHosts, probeAll]);
const handleSwitch = React.useCallback((host: DesktopHost) => {
const handleSwitch = React.useCallback(async (host: DesktopHost) => {
const origin = host.id === LOCAL_HOST_ID ? getLocalOrigin() : (normalizeHostUrl(host.url) || '');
if (!origin) return;
if (host.id !== LOCAL_HOST_ID && isTauriShell()) {
setSwitchingHostId(host.id);
const probe = await desktopHostProbe(origin).catch((): HostProbeResult => ({ status: 'unreachable', latencyMs: 0 }));
setStatusById((prev) => ({
...prev,
[host.id]: { status: probe.status, latencyMs: probe.latencyMs },
}));
if (probe.status === 'unreachable') {
toast.error(`Instance "${host.label}" is unreachable`);
setSwitchingHostId(null);
return;
}
}
const target = toNavigationUrl(origin);
onHostSwitched?.();
@@ -440,7 +458,8 @@ export function DesktopHostSwitcherDialog({
'flex items-center gap-2 flex-1 min-w-0 text-left',
isEditing && 'pointer-events-none opacity-70'
)}
onClick={() => handleSwitch(host)}
onClick={() => void handleSwitch(host)}
disabled={switchingHostId === host.id}
aria-label={`Switch to ${host.label}`}
>
<span className={cn('h-2 w-2 rounded-full flex-shrink-0', statusDotClass(status?.status ?? null))} />
@@ -2,7 +2,7 @@ import React from 'react';
import type { Extension } from '@codemirror/state';
import { Compartment, EditorState, RangeSetBuilder, StateField } from '@codemirror/state';
import { Decoration, type DecorationSet, EditorView, ViewPlugin, WidgetType, gutters, keymap, lineNumbers } from '@codemirror/view';
import { Decoration, type DecorationSet, EditorView, type KeyBinding, ViewPlugin, WidgetType, gutters, keymap, lineNumbers } from '@codemirror/view';
import { defaultKeymap, indentWithTab, history, historyKeymap } from '@codemirror/commands';
import { indentUnit } from '@codemirror/language';
import { search, searchKeymap, openSearchPanel, closeSearchPanel } from '@codemirror/search';
@@ -39,6 +39,13 @@ const highlightLinesCompartment = new Compartment();
const blockWidgetsCompartment = new Compartment();
const searchCompartment = new Compartment();
const toViewKeyBindings = (bindings: readonly unknown[]): readonly KeyBinding[] => {
return bindings as readonly KeyBinding[];
};
const openSearchPanelCompat = openSearchPanel as unknown as (view: EditorView) => void;
const closeSearchPanelCompat = closeSearchPanel as unknown as (view: EditorView) => void;
// BlockWidget class definition moved inside helper or adapted to take map
class BlockWidget extends WidgetType {
constructor(readonly id: string, readonly containerMap: Map<string, HTMLElement>) {
@@ -198,7 +205,7 @@ export function CodeMirrorEditor({
externalExtensionsCompartment.of(extensions ?? []),
highlightLinesCompartment.of(createHighlightLinesExtension(highlightLines)),
blockWidgetsCompartment.of(createBlockWidgetsExtension(blockWidgets, widgetContainersRef.current)),
searchCompartment.of(enableSearch ? [search({ top: true }), keymap.of(searchKeymap)] : []),
searchCompartment.of(enableSearch ? [search({ top: true }), keymap.of(toViewKeyBindings(searchKeymap))] : []),
],
});
@@ -232,7 +239,7 @@ export function CodeMirrorEditor({
externalExtensionsCompartment.reconfigure(extensions ?? []),
highlightLinesCompartment.reconfigure(createHighlightLinesExtension(highlightLines)),
blockWidgetsCompartment.reconfigure(createBlockWidgetsExtension(blockWidgets, widgetContainersRef.current)),
searchCompartment.reconfigure(enableSearch ? [search({ top: true }), keymap.of(searchKeymap)] : []),
searchCompartment.reconfigure(enableSearch ? [search({ top: true }), keymap.of(toViewKeyBindings(searchKeymap))] : []),
],
});
@@ -247,9 +254,9 @@ export function CodeMirrorEditor({
return;
}
if (searchOpen) {
openSearchPanel(view);
openSearchPanelCompat(view);
} else {
closeSearchPanel(view);
closeSearchPanelCompat(view);
}
}, [searchOpen, enableSearch]);