Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
f7423cf
feat(remote-desktop): 双击已打开的 RDP/VNC 连接改为切换标签页(#288)
feigeCode Sep 24, 2026
4de3fea
feat(db): SQL 导出的 INSERT 支持每条合并多行数据
feigeCode Sep 24, 2026
3402ab9
fix(one_ui): 编辑态下拖动不再把相邻单元格拖进选区(#302)
feigeCode Sep 24, 2026
869d258
feat(db_view): 数据库结果新增纵向「列:值」显示方式(#300)
feigeCode Sep 24, 2026
2f86683
feat(db_view): 表数据页 SQL 可复制 + 注释快捷键纳入可配置(#290)
feigeCode Sep 24, 2026
31be6dd
fix(ssh): 认证阶段断开可诊断,设备掐断 keyboard-interactive 时自动降级
feigeCode Sep 24, 2026
6dc3c05
fix(home): 迁移/导入的连接不再默认开启「双因素认证」
feigeCode Sep 24, 2026
fb98640
fix(db_view): 注释快捷键改键不生效、默认键被 notes 抢走,并支持空白行注释(#290)
feigeCode Sep 24, 2026
4ba6f78
fix(db_view): 纵向「列:值」补上横向滚动与单元格编辑(#300)
feigeCode Sep 24, 2026
f42d2d7
fix(db_view): 字段过滤改为可搜索的滚动面板,字段多时不再顶穿窗口(#255)
feigeCode Sep 24, 2026
65e88f2
feat(one-core): 弹窗支持关闭即隐藏与复用,规避 macOS 销毁窗口闪退
feigeCode Sep 24, 2026
a6bbad7
fix(app): 代理等 12 处弹窗改走复用关闭,修 macOS 关闭窗口闪退
feigeCode Sep 24, 2026
cfddb73
chore(release): 准备 v0.19.2(CHANGELOG 双语条目 + 版本号)
feigeCode Sep 24, 2026
65dfe11
style(db_view): 过滤编辑器补一次 rustfmt 换行\n\n.child(...) 里嵌套的 Editor 构造链按 r…
feigeCode Sep 24, 2026
e8c6b75
fix(one-core): 弹窗关闭即结束业务会话,复用窗口不再扣着上一轮的业务内容
feigeCode Sep 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,13 @@
- **验证方式**:四条结构 contract(`include_str!` 断言源码里存在对应的 `configure_background_child` / `creation_flags`,沿用 `workspace_explorer/src/git/tests.rs` 风格)——`cargo test -p terminal --lib wsl_distributions`、`cargo test -p html-preview`、`cargo test -p workspace_explorer --lib backend`、`cargo test -p main --bin navop mcp_skill`;再跑受影响 crate 的 `cargo check --tests` 与 `cargo clippy --all-targets`(只比对改动文件是否有新增告警)。**macOS 上 `cfg(windows)` 分支根本不参与编译,本机无法验证「不闪窗」**,最终必须 Windows 实机启动一次确认。
- **适用范围**:`crates/terminal/src/wsl_distributions.rs`(启动期 WSL 识别,commit 57e31731b 引入的遗漏)、`crates/html-preview/src/browser.rs`(Windows 走 `cmd /C start`)、`crates/workspace_explorer/src/backend.rs`(容器后端 `docker exec`)、`main/src/settings/mcp_skill_install.rs`(`npx`/`node` 启动器),以及所有新增后台外部命令调用点;`workspace_explorer/src/git.rs`、`core/cloud_sync/personal/git_store.rs`、`extension-host/src/process.rs`、`remote_desktop/src/backends/rdp/transport.rs`、`remote_file_editor/src/external_launcher.rs`、`main/src/file_association.rs` 是已按此约定收口的正确样例。

- **标题**:macOS 弹窗「关闭即复用」必须同时结束业务会话,并用计数把受控保留和泄漏分开
- **触发信号**:把弹窗关闭从 `remove_window()` 改成隐藏复用(`orderOut`)后,内存采样里 `GPUIView`/`CAMetalLayer` 只增不减;或反过来为了「彻底释放」把复用窗口改回销毁,于是 Touch Bar 机型又出现关闭闪退(issue #262)。
- **根因 / 约束**:隐藏的窗口仍然活在 GPUI 内容树里,而内容树**强引用** `PopupWindowContent.view`;复用注册表只存 `WeakEntity`,管不到这份强引用。所以「只隐藏不卸载」=上一次的业务 view(含数据、任务句柄)被一直扣着,用户不再打开那类窗口时就是纯泄漏;而销毁原生窗口又会触发 AppKit Touch Bar 观察者向已 dealloc 的对象注销并抛 ObjC 异常。两件事必须拆开:**原生窗口**隐藏复用(受控保留,上限=复用键数量),**业务会话**关闭即结束。
- **正确做法**:`PopupWindowContent.view: Option<AnyView>`;`close_window_for_reuse(window, cx)` 在 `hide_for_reuse` 成功后**同步**调 `end_reusable_popup_session`(`window.blur` + `clear_notifications` + `end_session` 置 `None`),并靠 `Drop` 归还计数(非 macOS、隐藏失败回落、窗口真销毁)。清理不能交给 `defer`:延后清理存在「上一轮清理删掉刚打开的新会话」的窗口期,同步卸载没有这个窗口。未登记复用键的窗口照旧 `remove_window()`。计数看 `popup_lifecycle`(`live_windows`/`live_sessions` 存量,`opened_*` 累计),日志 target `one_core::popup_lifecycle`;**不要**给复用注册表加 LRU 淘汰(淘汰即销毁,把崩溃挪到淘汰路径上)。
- **验证方式**:`cargo test -p one-core --lib`(`popup_window::reuse_contract_tests`、`popup_lifecycle::tests`)、`cargo check -p main -p db_view -p extension_view --all-targets`、`cargo test -p main --bin navop setting_tab`。计数判据:每类弹窗首次打开 `live_windows` +1 后不再增长、关闭后 `live_sessions` 回落;`opened_windows` 随开关次数上涨说明复用没命中。**本机无 Touch Bar,崩溃无法本地复现**,行为层面必须真机验证,自动化只能靠 `include_str!` 源码契约守住「关闭路径必须走会话卸载」。注意这类契约对格式敏感:`popup_window_tests.rs` 用 `find("struct PopupWindowContent")` 切片,改结构体可见性或字段会让它的 `expect` 直接 panic,锚点要跟着改。
- **适用范围**:`crates/core/src/{window_close,popup_window,popup_lifecycle}.rs`、`crates/core/src/popup_window_tests.rs`,以及所有 `open_reusable_popup_window` 调用点(更新对话框、代理设置、表导入/导出、SQL 运行/转储、比较窗口、离线扩展包对话框)。

### 执行原则

1. 先澄清,再实现;先缩小边界,再扩展范围。
Expand Down
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,48 @@ Navop user-facing release notes. Generate and review each bilingual version entr

<!-- NAVOP_RELEASES -->

## [v0.19.2] - 2026-09-24

#### 更新内容

- 数据库结果新增纵向「列:值」显示方式:宽表横向铺满几十列后没法读,现在可以按「列名:值」逐字段竖排(表数据页与 SQL 结果页共用),工具栏「显示方式」或「设置 → 通用 → 数据库 → 结果显示方式」切换。长值不再被截断——标签列固定、值区单独横向滚动且滚动条常驻;单击值行选中、在选中行上再点一次进入编辑(Enter 提交、Esc 取消),提交前工具栏会亮出撤销 / SQL 预览 / 提交。
- 字段过滤面板重做:新增字段搜索框(不区分大小写的子串匹配,输入 `id` 同时命中 `id` 与 `tenant_id`)、列表限高滚动并常驻滚动条、标题显示「已显示字段数 / 字段总数」,底部固定「至少保留一列可见」提示与「显示全部字段」。此前是下拉菜单,高度只由条目数决定,几十列的表会一路顶到窗口底部,最后几个字段点不到。
- 表数据页底部状态栏的 SQL 可以整条复制:宽表下这行总被省略号截断,复制到的是完整语句;空 SQL 不写剪贴板,避免把上次的内容悄悄清掉。SQL 编辑器的「注释/取消注释」纳入「设置 → 快捷键 → 数据库」,默认 macOS 为 `Cmd+/`、Windows/Linux 为 `Ctrl+/`,改键后立即生效(此前改键不生效、默认键在编辑器里按不出来);空白行也能先生成 `-- ` 再写 SQL,光标停在标记之后可直接续写。
- SQL 转储支持每条 INSERT 合并多行数据:转储窗口在「转储到」下方新增「每条语句的数据行数」,默认 100(与 Navicat 的「每条语句的数据行数」一致),分页按整批对齐,一批数据不会被页边界拆成两条语句。
- 双击已打开的 RDP/VNC 连接改为切换已有标签页,不再堆出多个指向同一主机的会话,标签身份按「协议 + 连接 id」钉死。同一连接因此不再能开出第二个标签页(需要第二条同主机会话时,可复制一份连接)。

#### 修复与优化

- 修复 macOS 上关闭部分弹窗就闪退的问题(带 Touch Bar 的机型,崩溃栈落在 AppKit 的 Touch Bar 观察者注销上):弹窗关闭改为隐藏并复用,不再销毁原生窗口。本次接入全局代理设置、更新提示、扩展离线包下载与扩展详情、远程图片预览、SQL 悬停详情、导入数据、导出表、运行 SQL 文件、转储 SQL 文件、数据比较、结构比较共 12 个窗口。需要注意的行为变化:同类弹窗(导入数据、导出表、数据比较等)由「可同时开多个」变为「一次一个」。
- 在单元格里编辑时用鼠标拖选文本,网格不再同时开始自己的拖选:此前指针扫过相邻单元格就会把它们纳入选区,提交时把新值批量写到整片选区,现象是「不小心把隔壁一起编辑了」。
- 修复 SQLite 联合主键表的 DDL 显示错误:表设计器打开 WITHOUT ROWID 联合主键表时,DDL 会被渲染成 `"device_id" INTEGER PRIMARY KEY AUTOINCREMENT` 并重复声明主键。现在联合主键的每一列都能正确识别,只有单列 INTEGER 主键才视作自增,生成的建表语句也不再多写一个表级主键。
- SSH 连接:设备在认证阶段掐断连接时,报错不再只有 `Unable to receive more messages from the channel` 或裸 `Disconnected`。现在会记录设备给出的断开原因码与文本(warn 日志),报错里点出常见原因(密码被拒、账号已在别处登录、VTY/并发达上限、RADIUS・TACACS・LDAP 不可达、设备认证超时短于登录往返);若设备是在 keyboard-interactive 往返中断开传输层,会自动改用纯密码认证重试一次(仅本会话生效,一次连接序列最多降级一次)。
- 从 SecureCRT 等工具迁移/导入进来的连接不再默认勾选「双因素认证」:此前每个迁移连接都会优先走 keyboard-interactive,在交换机、防火墙这类设备上一认证就被掐断。迁移源里的「支持多种认证方式」只是服务器返回的方法列表,不等于需要二次认证;确实需要二次认证的设备请手动开启。
- 认证失败的提示文案不再断言「服务器需要 MFA/二次认证」——交换机往往只是声明支持多种认证方式。现在改为说明当前认证方式被拒绝并提示先核对凭据,双因素开关的悬停说明也补充了自动降级的说明。

国内下载:如果 GitHub 下载较慢,可从 [CNB 镜像](https://cnb.cool/navop-dev/navop/-/releases/tag/v0.19.2) 下载桌面端安装包

---

#### What's New

- Query results can now use a vertical "column: value" layout: a wide result set that spans dozens of columns becomes readable when shown field by field, shared by the table data page and the SQL result tabs, and switchable from "Display mode" in the toolbar or Settings → General → Database → Result display mode. Long values are no longer truncated — the label column stays fixed while the value area scrolls horizontally with an always-visible scrollbar. Click a value row to select it, click a selected row again to edit it (Enter commits, Esc cancels), and the toolbar reveals undo / SQL preview / commit while editing.
- The field filter panel was rebuilt: it now has a field search box (case-insensitive substring, so `id` also matches `tenant_id`), a height-capped list with an always-visible scrollbar, a "shown fields / total fields" counter in the title, and a fixed footer with the "at least one field stays visible" hint and "Show all fields". Previously it was a dropdown menu whose height was decided purely by the number of entries, so a table with dozens of columns pushed it past the bottom of the window and the last fields could not be reached.
- The SQL shown in the table data page status bar can now be copied in full: the line is ellipsized on wide tables, and the copy contains the whole statement. An empty statement no longer overwrites the clipboard. "Toggle comment" in the SQL editor is now listed under Settings → Shortcuts → Database, defaulting to `Cmd+/` on macOS and `Ctrl+/` on Windows/Linux, and re-binding takes effect immediately (previously a new binding did not take effect and the default never fired inside the editor). Blank lines can generate `-- ` so you can write the comment before the SQL, with the caret left right after the marker.
- SQL dumps can merge multiple rows into a single INSERT: the dump window gains a "rows per statement" field next to the destination, defaulting to 100 (matching Navicat's equivalent setting), and paging is aligned to whole batches so a batch is never split across two statements.
- Double-clicking an RDP/VNC connection that is already open now switches to its existing tab instead of stacking several sessions for the same host, with the tab identity pinned to "protocol + connection id". The same connection can no longer open a second tab (copy the connection if you need a second session to the same host).

#### Fixes and Improvements

- Fixed Navop crashing on macOS when closing some dialogs on Touch Bar Macs, where the crash frames land in AppKit's Touch Bar observer deregistration: dialogs now hide and get reused instead of destroying the native window. 12 windows are covered — global proxy settings, the update prompt, extension offline package download and extension details, remote image preview, SQL hover details, import data, export table, run SQL file, dump SQL file, data comparison and schema comparison. Note the deliberate behavior change: dialogs such as import data, export table and data comparison now open one at a time instead of allowing several at once.
- Dragging to select text inside a cell that is being edited no longer starts the grid's own drag selection: the pointer used to sweep neighbouring cells into the selection, and committing wrote the new value across the whole selection — effectively editing the neighbours by accident.
- Fixed the DDL shown for SQLite tables with a composite primary key: the table designer used to render `"device_id" INTEGER PRIMARY KEY AUTOINCREMENT` and declare the primary key twice for WITHOUT ROWID tables. Every composite key column is now detected, only a single-column INTEGER primary key counts as auto-increment, and the generated CREATE TABLE statement no longer adds a duplicated table-level primary key.
- SSH: when a device drops the connection during authentication, the error is no longer just `Unable to receive more messages from the channel` or a bare `Disconnected`. The reason code and text sent by the device are now logged as a warning, and the error points at the common causes (rejected credentials, an account already logged in elsewhere, VTY/concurrency limits, unreachable RADIUS・TACACS・LDAP, or a device authentication timeout shorter than the login round trip). If the device drops the transport during the keyboard-interactive exchange, Navop retries once with password authentication only, scoped to that session and at most once per connection sequence.
- Connections migrated or imported from SecureCRT and similar tools no longer enable two-factor authentication by default: every imported connection used to prefer keyboard-interactive and was dropped by switches and firewalls on the first authentication round. The "supports multiple authentication methods" reported by the migration source is just the method list returned by the server, not a requirement for a second factor; devices that genuinely need one can be switched on manually.
- Authentication failures no longer claim that "the server requires MFA / a second factor" — switches often just advertise several authentication methods. The message now states that the current authentication method was rejected and suggests verifying the credentials first, and the two-factor tooltip explains the automatic fallback.

**Full Changelog**: https://github.com/feigeCode/navop/compare/v0.19.1...v0.19.2

## [v0.19.1] - 2026-09-24

#### 修复与优化
Expand Down
5 changes: 4 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ image.workspace = true
smallvec.workspace = true
tempfile = "3"

[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.6"
objc2-app-kit = { version = "0.3.2", default-features = false, features = ["NSResponder", "NSView", "NSWindow"] }
raw-window-handle = { workspace = true, features = ["std"] }

[target.'cfg(target_os = "windows")'.dependencies]
windows = { workspace = true, features = [
"Win32_Storage_FileSystem",
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/keybindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub mod action_id {
pub const DB_SELECT_ALL_OBJECTS: &str = "db.select_all_objects";
pub const SQL_RUN_QUERY: &str = "sql.run_query";
pub const SQL_RUN_ALL_QUERY: &str = "sql.run_all_query";
pub const SQL_TOGGLE_COMMENT: &str = "sql.toggle_comment";
pub const TERMINAL_SEND_TAB: &str = "terminal.send_tab";
pub const TERMINAL_SEND_SHIFT_TAB: &str = "terminal.send_shift_tab";
pub const TERMINAL_COPY: &str = "terminal.copy";
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod keybindings;
pub mod layout;
pub mod license;
pub mod llm;
pub mod popup_lifecycle;
pub mod popup_window;
pub mod session_lock;
pub mod sidebar_contribution;
Expand Down
Loading
Loading