上半部分收敛成一条规则:草稿和已保存一致时显示内核现状;不一致时显示 按草稿保存后的样子,将移除的画删除线、新增的虚线描边,即将被移除的当前 选中用危险色警示。点击语义只看卡片:现在就存在的成员点了立刻生效,保存 后才加入的点了是预选,保存成功后再作为运行时动作选上。预览的集合运算在 web/member-preview.ts,组件里只留接线。 其余:订阅选择器重写成可搜索多选(原平铺标签订阅一多就是一面墙);删除 入站换成页面内确认对话框;列表右列解析到最终出口并标注链式;「高级配置」 更名「配置」;表单重置改按内容比较(按引用的话任何一次运行时刷新都会冲掉 未保存的草稿,watch 传返回数组的 getter 同样触发这个问题);保存后先刷 运行时再换配置数据,避免卡片区闪空。
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { describe, expect, it } from 'bun:test'
|
|
import { mergeMemberPreview } from './member-preview.ts'
|
|
import type { ProxyInfo } from './api.ts'
|
|
|
|
const info = (name: string) => ({ name, type: 'Vmess' }) as ProxyInfo
|
|
const noLookup = () => undefined
|
|
|
|
describe('成员预览', () => {
|
|
it('草稿和现状一致时谁都不标', () => {
|
|
const cards = mergeMemberPreview([{ name: 'A', info: info('A') }], ['A'], noLookup)
|
|
expect(cards).toEqual([{ name: 'A', info: info('A'), removed: false, added: false }])
|
|
})
|
|
|
|
it('不在保存后名单里的现有成员标为将移除', () => {
|
|
const cards = mergeMemberPreview(
|
|
[
|
|
{ name: 'A', info: info('A') },
|
|
{ name: 'B', info: info('B') },
|
|
],
|
|
['B'],
|
|
noLookup,
|
|
)
|
|
expect(cards.map((c) => [c.name, c.removed])).toEqual([
|
|
['A', true],
|
|
['B', false],
|
|
])
|
|
})
|
|
|
|
it('新增的追加在末尾,线路信息从 lookup 取', () => {
|
|
const cards = mergeMemberPreview([{ name: 'A', info: info('A') }], ['A', 'C'], info)
|
|
expect(cards[1]).toEqual({ name: 'C', info: info('C'), removed: false, added: true })
|
|
})
|
|
|
|
it('现有成员保持原序在前,新增按保存后名单的顺序在后', () => {
|
|
// 顺序稳定才不会出现「改一个筛选,卡片全部跳位」
|
|
const cards = mergeMemberPreview(
|
|
[
|
|
{ name: 'B', info: undefined },
|
|
{ name: 'A', info: undefined },
|
|
],
|
|
['C', 'A', 'D'],
|
|
noLookup,
|
|
)
|
|
expect(cards.map((c) => c.name)).toEqual(['B', 'A', 'C', 'D'])
|
|
})
|
|
})
|