Files
ShadowsocksX-NG/docs/design/server-three-column-table.md
T

6.7 KiB
Raw Blame History

服务器三栏视图

状态:实现与自动检查完成(2026-10-09);视觉及原生交互交给人工验证。 日期:2026-10-09。

本文记录本次任务的需求与设计决定,不代表当前实现。

确定要求

  • 服务器页面使用三栏 HSplitView:左栏为来源边栏,中栏为服务器列表,右栏为原详情视图。用户后续要求用 HSplitView 替换最初批准的 NavigationSplitView。
  • 不修改原服务器详情与配置组详情。
  • 来源边栏只有「本地」和「订阅」。主窗口原「订阅」管理页面保留。
  • 「本地」展示手动来源的根层节点与后代,不展示虚拟目录根。
  • 「订阅」展示订阅组与后代。
  • Content 用 SwiftUI Table 展示层级,类似 Finder 列表大纲。
  • 三列为「名称」「创建时间」「修改时间」。名称列含配置组/服务器图标、左对齐的名称,以及右对齐的活动目标图标。
  • 活动目标图标只标记目标节点本身,包含配置组目标,不级联标记后代。保留无效服务器与包含无效后代的配置组的警告图标。
  • 单击选择节点,激活继续使用现有命令。列表保持单选。
  • 切换来源清空节点选择,详情显示原有空状态。
  • 默认展示目录顺序。列头排序只改变展示顺序,不改写目录;每组的直接子节点分别排序。
  • 拖动仅改变父分组,不提供同级重排。移除右键菜单「移动到…」。其余现有操作保留,继续调用 CatalogWorkflow。
  • 时间采用系统本地化日期和时间,精度到分钟;未知时间显示「—」。时间事实遵循 GLOSSARY「节点时间戳」与 ADR-0031。
  • 拖放仅接受手动分组与「本地」列表空白;空白代表目录根。新父分组不同才执行移动,移动后追加到目标目录顺序末尾。服务器、订阅节点、自身及后代均不接受落点。
  • 列头排序时,分组和服务器一起排序;未知时间始终排在最后,相等值保持目录顺序。
  • 折叠包含选中节点的配置组时,选择切换到收起的配置组,详情同步切换。
  • 创建、导入或订阅组复制产生手动节点后,切换到「本地」,展开其祖先并选择新节点。
  • 支持列宽调整,固定显示三列。名称列占剩余宽度,时间列初始宽度按日期文本确定。
  • 三栏保持显示;改用 HSplitView 后不提供 NavigationSplitView 的系统边栏显隐按钮。
  • 来源、排序与展开状态在本次运行内跨主窗口页面切换保留,不落盘。重启恢复「本地」、目录顺序和全部展开。来源切换仍清空节点选择。
  • 英文文案为 Local、Subscriptions、Name、Date Created、Date Modified。
  • 增加列表排序菜单;「无」表示不施加展示排序、按目录顺序展示。英文为 None。列头继续切换对应列的升序与降序。
  • 拖动移动成功后展开目标的祖先和目标分组,选择移动的节点,详情同步显示该节点。移到根层时无需展开目标分组。

实施前代码核实

  • ServersView 使用 HSplitView 和扁平可见行 List。
  • CatalogTreeNode 已包含来源、父节点与子树,但尚未包含创建时间与修改时间。
  • CatalogEntry 已保存两个可空时间戳,无需重新定义时间语义。
  • 现有目录移动命令支持同父重排;新列表必须拒绝同父拖放。
  • 当前服务器管理的展开状态跨工作区页面切换保留,不落盘,重启全部展开。

最终确认

用户确认全部交互决定,并批准「无」的英文 None。用户要求使用 implement 流程,完成后提交当前分支;视觉验证交给人工,不由 Agent 执行。

Module 方向

沿用 CatalogWorkflow 的 Interface 提供目录事实与变更命令。列表展示排序不进入目录持久化。树投影补充非敏感时间事实。视图持有来源、排序、展开和选择的呈现状态。具体 Interface 在交互规则确定后核实,不增加仅转发调用的 Module。

浏览状态需由跨工作区页面切换仍存续的持有者管理;不能只放入随页面卸载的 ServersView 局部状态。来源与排序属于服务器页面呈现,不加入工作区顶层路由或持久配置。新 Table 直接使用节点身份驱动选择与展开,替换原扁平 List 呈现。保留原详情 View 与现有变更工作流。

文档范围

本次沿用配置目录、服务器配置、配置组、手动组、订阅组、活动目标与节点时间戳的既有定义,不新增领域术语。本次布局与呈现决定可以局部修改,不新增 ADR。

实现验证范围

  • 核实非敏感树投影中的时间戳与来源筛选。
  • 验证每层排序、未知时间、相等值及目录顺序恢复。
  • 验证同父拖放不提交目录变更,跨父移动仍使用现有工作流。
  • 构建 macOS App,检查原详情与现有操作的编译集成。
  • 视觉与原生交互由人工验证:三栏、层级 Table、列宽、选择、展开、排序菜单与拖放。Agent 不执行视觉验证,构建与 hostless 测试不替代该证据。

实现期间的补充决定

  • 排序按钮直接展开字段列表;Picker 使用 inline 样式,不产生额外「排序」子菜单。
  • 用户要求只给树展开图标设置最小宽度。名称列的展开按钮设置最小宽度 24 点、最小高度 28 点;图标不放大。
  • Table 的行由树投影按来源、每层展示排序与展开状态生成,名称列按深度缩进。展开按钮显式绑定既有展开状态,以控制点击宽度和折叠选择规则。
  • TableRowContent.dropDestination 不提供拒绝返回值,因此不使用该行级接口。统一 DropDelegate 借用原生 NSTableView.row(at:) 区分行与空白;无效行不得回退为根落点。AppKit Adapter 不替换 Table 或其 delegate。
  • 目录节点拖放使用本进程专用载荷类型,释放时再次核对载荷身份与移动资格。

验证记录(2026-10-09)

  • 定向验证树投影时间戳、来源筛选、每层排序、未知时间最后、相等值稳定、折叠选择和同父移动拒绝。
  • Debug 构建通过;全量 hostless 摘要为 976 个测试通过、0 失败、0 跳过,包含 1062 次参数化执行。
  • 两组 Python 离线检查分别通过 4 项与 17 项。
  • 格式化和 diff 检查通过;SwiftLint 为 22 条非严重警告,严重违规为 0。ServersView 文件长度仍有警告。
  • code-review 的 Standards 与 Spec 两轴最终均为 0 项发现;初次发现的无效行落点问题在复核中关闭。
  • 原生拖放命中、菜单呈现、展开按钮点击区域与三栏视觉未验证,按用户要求由人工验证。