mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-07-14 15:11:28 +08:00
feat(editor): 数据源与代码块历史记录不再合并相邻操作
每条操作独立展示,与页面历史的合并策略区分开。
This commit is contained in:
parent
273d13dd1f
commit
89cef4e9a9
@ -100,8 +100,8 @@
|
|||||||
/**
|
/**
|
||||||
* 历史记录面板:在顶部 NavMenu 上点击图标打开 popover,分三个 tab:
|
* 历史记录面板:在顶部 NavMenu 上点击图标打开 popover,分三个 tab:
|
||||||
* - 页面:当前活动页面的历史栈,连续修改同一节点的多步会被合并成一组
|
* - 页面:当前活动页面的历史栈,连续修改同一节点的多步会被合并成一组
|
||||||
* - 数据源:以 dataSource.id 分组,每组内部相邻的连续 update 自动合并
|
* - 数据源:以 dataSource.id 分桶,每条操作记录独立展示
|
||||||
* - 代码块:同上,按 codeBlock.id 分组并合并相邻 update
|
* - 代码块:同上,按 codeBlock.id 分桶,每条操作记录独立展示
|
||||||
*
|
*
|
||||||
* 数据通过 historyService 暴露的聚合 API 读取,UI 仅用于只读展示,
|
* 数据通过 historyService 暴露的聚合 API 读取,UI 仅用于只读展示,
|
||||||
* 同时支持点击任意一条记录跳转至该状态:
|
* 同时支持点击任意一条记录跳转至该状态:
|
||||||
|
|||||||
@ -526,11 +526,8 @@ class History extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取出全部代码块的历史栈,按 codeBlockId 分组。
|
* 取出全部代码块的历史栈,按 codeBlockId 分桶展示。
|
||||||
* 同一栈内相邻、同 opType 且作用于同一 id 的多步会被合并为一个 group:
|
* 同一栈内每条操作记录独立成组,不做相邻 update 合并。
|
||||||
* - 这正是"代码块/数据源各自按 id 分栈"的天然表现,再叠加"连续修改同目标的相邻步骤合并展示"。
|
|
||||||
* - 合并后 group 暴露子步骤数组,UI 可展开查看每一步的 changeRecords。
|
|
||||||
* - applied 字段:组内最后一步是否处于已应用段。
|
|
||||||
*/
|
*/
|
||||||
public getCodeBlockHistoryGroups(): CodeBlockHistoryGroup[] {
|
public getCodeBlockHistoryGroups(): CodeBlockHistoryGroup[] {
|
||||||
const groups: CodeBlockHistoryGroup[] = [];
|
const groups: CodeBlockHistoryGroup[] = [];
|
||||||
@ -622,7 +619,7 @@ class History extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取出全部数据源的历史栈,按 dataSourceId 分组。同上。
|
* 取出全部数据源的历史栈,按 dataSourceId 分桶展示。同上,每条操作独立成组。
|
||||||
*/
|
*/
|
||||||
public getDataSourceHistoryGroups(): DataSourceHistoryGroup[] {
|
public getDataSourceHistoryGroups(): DataSourceHistoryGroup[] {
|
||||||
const groups: DataSourceHistoryGroup[] = [];
|
const groups: DataSourceHistoryGroup[] = [];
|
||||||
|
|||||||
@ -121,8 +121,7 @@ export const markStackSaved = <S extends { saved?: boolean }>(undoRedo?: UndoRed
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 把单个「按 id 分栈」的历史栈(代码块 / 数据源)拆成若干 group:
|
* 把单个「按 id 分栈」的历史栈(代码块 / 数据源)拆成若干 group:
|
||||||
* - 把"新增/删除"独立成组(语义上属于一次性事件,不应与 update 合并);
|
* 每条操作记录独立成组,不做相邻 update 合并(与页面历史的合并策略不同)。
|
||||||
* - 连续 'update' 合并到同一组,组内 steps 顺序就是发生顺序。
|
|
||||||
*
|
*
|
||||||
* 代码块与数据源除 `kind` 外结构完全一致,统一由本方法处理;`kind` 决定返回的具体分组类型。
|
* 代码块与数据源除 `kind` 外结构完全一致,统一由本方法处理;`kind` 决定返回的具体分组类型。
|
||||||
*/
|
*/
|
||||||
@ -139,38 +138,19 @@ export const mergeStackSteps = <S extends BaseStepValue, K extends 'code-block'
|
|||||||
applied: boolean;
|
applied: boolean;
|
||||||
isCurrent?: boolean;
|
isCurrent?: boolean;
|
||||||
}[] => {
|
}[] => {
|
||||||
type Group = {
|
|
||||||
kind: K;
|
|
||||||
id: Id;
|
|
||||||
opType: HistoryOpType;
|
|
||||||
steps: { step: S; index: number; applied: boolean; isCurrent?: boolean }[];
|
|
||||||
applied: boolean;
|
|
||||||
isCurrent?: boolean;
|
|
||||||
};
|
|
||||||
const groups: Group[] = [];
|
|
||||||
let current: Group | null = null;
|
|
||||||
const currentIndex = cursor - 1;
|
const currentIndex = cursor - 1;
|
||||||
list.forEach((step, index) => {
|
return list.map((step, index) => {
|
||||||
const { opType } = step;
|
|
||||||
const applied = index < cursor;
|
const applied = index < cursor;
|
||||||
const isCurrent = index === currentIndex;
|
const isCurrent = index === currentIndex;
|
||||||
if (opType === 'update' && current?.opType === 'update') {
|
return {
|
||||||
current.steps.push({ step, index, applied, isCurrent });
|
kind,
|
||||||
current.applied = applied;
|
id,
|
||||||
if (isCurrent) current.isCurrent = true;
|
opType: step.opType,
|
||||||
} else {
|
steps: [{ step, index, applied, isCurrent }],
|
||||||
current = {
|
applied,
|
||||||
kind,
|
isCurrent,
|
||||||
id,
|
};
|
||||||
opType,
|
|
||||||
steps: [{ step, index, applied, isCurrent }],
|
|
||||||
applied,
|
|
||||||
isCurrent,
|
|
||||||
};
|
|
||||||
groups.push(current);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return groups;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -122,18 +122,20 @@ describe('markStackSaved', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('mergeStackSteps', () => {
|
describe('mergeStackSteps', () => {
|
||||||
test('连续 update 合并为一组', () => {
|
test('连续 update 各自独立成组', () => {
|
||||||
const list = [
|
const list = [
|
||||||
{ opType: 'update', uuid: '1' },
|
{ opType: 'update', uuid: '1' },
|
||||||
{ opType: 'update', uuid: '2' },
|
{ opType: 'update', uuid: '2' },
|
||||||
] as CodeBlockStepValue[];
|
] as CodeBlockStepValue[];
|
||||||
const groups = mergeStackSteps('code-block', 'code_1', list, 2);
|
const groups = mergeStackSteps('code-block', 'code_1', list, 2);
|
||||||
expect(groups).toHaveLength(1);
|
expect(groups).toHaveLength(2);
|
||||||
expect(groups[0].steps).toHaveLength(2);
|
expect(groups[0].steps).toHaveLength(1);
|
||||||
|
expect(groups[1].steps).toHaveLength(1);
|
||||||
expect(groups[0].opType).toBe('update');
|
expect(groups[0].opType).toBe('update');
|
||||||
|
expect(groups[1].opType).toBe('update');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('add / update 不合并', () => {
|
test('add / update 各自独立成组', () => {
|
||||||
const list = [
|
const list = [
|
||||||
{ opType: 'add', uuid: '1' },
|
{ opType: 'add', uuid: '1' },
|
||||||
{ opType: 'update', uuid: '2' },
|
{ opType: 'update', uuid: '2' },
|
||||||
@ -148,10 +150,12 @@ describe('mergeStackSteps', () => {
|
|||||||
{ opType: 'update', uuid: '2' },
|
{ opType: 'update', uuid: '2' },
|
||||||
] as CodeBlockStepValue[];
|
] as CodeBlockStepValue[];
|
||||||
const groups = mergeStackSteps('code-block', 'code_1', list, 1);
|
const groups = mergeStackSteps('code-block', 'code_1', list, 1);
|
||||||
expect(groups[0].applied).toBe(false);
|
expect(groups[0].applied).toBe(true);
|
||||||
expect(groups[0].steps[0].applied).toBe(true);
|
expect(groups[0].steps[0].applied).toBe(true);
|
||||||
expect(groups[0].steps[0].isCurrent).toBe(true);
|
expect(groups[0].steps[0].isCurrent).toBe(true);
|
||||||
expect(groups[0].steps[1].applied).toBe(false);
|
expect(groups[0].isCurrent).toBe(true);
|
||||||
|
expect(groups[1].applied).toBe(false);
|
||||||
|
expect(groups[1].steps[0].applied).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user