WebShell中实现命令面板

最近做的WebShell-命令面板功能上线,这里Mark下其中的设计/思考

解决痛点

先解释下,为什么要做。

网页WebShell的功能在不断增加,不可避免会造成用户进行一些操作时,整个操作路径会很长。举个🌰,用户想登录一台机器。没有命令面板之前,需要这样做e

  1. 光标点击连接管理
  2. 光标聚焦搜索
  3. 光标选中连接配置
  4. 点击登录

可以看出这个操作路径是长的,怎么缩短大量这样的操作路径呢。命令面板就是一个解决方案。整个功能类似于Mac下比较火的效率启动器Alfred/Raycast.

即命令面板提供一个用户不离开键盘即可快速完成动作的一个交互方式。

有了命令面板支持后

  1. 热键唤起命令面板
  2. 输入框+方向键组合执行选中连接配置-某个连接
  3. 回车登录

似乎步骤上并不算少,但用户手可以不用离开键盘,几个操作即登录一台机器

设计

命令面板根本上来说,即一堆操作的列表展示,那么这里就是先把命令抽象下。so,抽象这样一个概念即CommandAction,命令面板任何一个菜单即一个CommandAction,

CommandAction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 {
uid: string;
icon?: React.ReactNode;
title: string;
match?: string[];
render?: (item?: CommandAction) => React.ReactNode;
hotkey?: GlobalAction;
action: ({ setQuery }: { setQuery: (q: string) => void }) => void;
actionMap?: {
[comboKey: string]: ({ close, shaking }) => void
};
windowDontCloseOnAction?: boolean;
preCheck?: () => React.ReactNode;
variables?: {
[index: string]: any;
},
};

解释部分属性设计

  1. uid确保了每一个命令可以唯一,这样在做命令历史排序等有用

  2. match的话,这里学习的Alfred的设计,如果只是单纯靠title来匹配检索,有时候觉得很不对,比如搜索关键词会命中谷歌,在命令面板这里怎么做到呢,最好方式是针对命令可以有机会配置命中关键词

  3. action可以定义命令回车动作,但随着命令面板发展会发现单纯的回车不够使用了,那么为了丰富功能,可以再搭配修饰键+回车,这样就可以丰富了,因此也就有了actionMap的需求。action可以视作actionMap中的[enter]键值

  4. hotkey用于显示该命令的操作热键

  5. variables定义该命令下的一些变量,这些变量用于在该命令选中/执行时作为上下文

CommandAction List

有了CommandAction,那么这样的列表从何来呢,一种是固定值即程序里提前声明的,还有一种是JS动态生成的,比如call后台请求build出CommandAction表。命令面板在接收这样的数据后显示处理即可。

检索/筛选

针对已全量显示的命令列表,筛选的话简单

  1. 针对title进行模糊匹配,中文命令面板的话,支持下拼音检索的话,UE会更好
    • 内存区保存着全量的命令列表数据,不断根据关键词进行筛选和显示
  2. match配置的话,完整匹配,如果这里也是模糊匹配,有时命中项太多,从而质量也就低了

多级CommandAction List

命令面板发展起来后,会发现一级不足够了,比如提供给了用户SSH连接的命令,但是现在希望用户可以直接在面板里选择目标连接,回车进行连接。为此命令面板就有了多级需求。

这里最关键的是如何联系起这多级命令呢。

方法1

创建一个ScriptCommandsMap,key即关键词,value即命令面板列表生成函数,注意这里的关键词不是用户的筛选关键词而是触发关键词,比如一级命令就是空,连接配置如果作为二级命令,比如叫connect。这样用户当输入关键词为connect时,命令面板识别到,从而根据ScriptCommandsMap找到对应的显示命令列表函数,进而执行即可。

方法2

CommandAction可以增加一个属性比如叫type,用于区分该命令的类型,如果是一个subcommand,说明用户回车后面板并不需要关闭,同时执行action的结果为列表,从而继续显示

个人目前采用的方案1,但之后考虑切换到2,这样做的好处是内存区其实不用管理一个大大的ScriptCommandsMap,而是每个命令自己根据实际情况关联logic。整个控制上更易维护

同类调研

看到Shell类也有些产品实现了类似的feat

  • xterminal
    • 目前仅有一级命令
  • warp
    • 支持了如上的二级命令,比如sessions查询会话

抛开Shell领域的话,Alfred/Raycast才是这块的大哥,如果做同类产品功能,很推荐学习下

写在最后

命令面板本身并没有给用户带来任何新的feat,而是缩短部分功能的操作路径。这一点已足够了。