Add branch button for messages in chat panel

This commit is contained in:
dimitrievgs 2026-05-10 18:14:56 +03:00
parent 3d3af78563
commit a7019c8a7f
2 changed files with 42 additions and 0 deletions

View File

@ -1018,6 +1018,27 @@ export class ChatPanel {
this.props.plugin.eventBus.emit('regenerate-message', { graphId, nodeId, model: this.selectedModel }); this.props.plugin.eventBus.emit('regenerate-message', { graphId, nodeId, model: this.selectedModel });
}); });
// Кнопка "Начать новую ветку отсюда"
const branchButton = toolsetContainer.createEl('button', {
cls: 'text-token-text-secondary hover:bg-token-bg-secondary rounded-lg ml-1',
attr: {
'aria-label': 'Перейти к этому сообщению (начать новую ветку отсюда)',
'data-testid': 'branch-turn-action-button',
'data-state': 'closed'
}
});
const branchIconContainer = branchButton.createSpan({ cls: 'flex items-center justify-center touch:w-10 h-8 w-8' });
setIcon(branchIconContainer, 'git-branch'); // Иконка разветвления диалога
branchButton.addEventListener('click', () => {
// Отправляем событие выбора узла. ChatView перехватит его,
// обрежет сообщения ниже этого узла и сделает его текущим.
// Следующее отправленное пользователем сообщение станет новой веткой!
this.props.plugin.eventBus.emit('node-selected', { nodeId: nodeId, graphId: graphId });
// Необязательно, но приятно: уведомляем пользователя
new Notice('История обрезана до этого сообщения. Следующий ответ создаст новую ветку.', 3000);
});
// Кнопка "Наверх сообщения" // Кнопка "Наверх сообщения"
const scrollToTopButton = toolsetContainer.createEl('button', { const scrollToTopButton = toolsetContainer.createEl('button', {
cls: 'text-token-text-secondary hover:bg-token-bg-secondary rounded-lg ml-1', cls: 'text-token-text-secondary hover:bg-token-bg-secondary rounded-lg ml-1',

View File

@ -194,6 +194,7 @@ export class GraphView extends ItemView {
private setupEventListeners() { private setupEventListeners() {
this.plugin.eventBus.on('new-chat', this.handleNewChat.bind(this)); this.plugin.eventBus.on('new-chat', this.handleNewChat.bind(this));
this.plugin.eventBus.on('graph-selected', this.handleGraphSelected.bind(this)); this.plugin.eventBus.on('graph-selected', this.handleGraphSelected.bind(this));
this.plugin.eventBus.on('node-selected', this.handleNodeSelectedFromBus); // слушаем выбор узла извне
this.plugin.eventBus.on('delete-node', this.handleDeleteNodeFromChat.bind(this)); this.plugin.eventBus.on('delete-node', this.handleDeleteNodeFromChat.bind(this));
this.plugin.eventBus.on('ws-graph-title-updated', this.handleGraphTitleUpdated.bind(this)); this.plugin.eventBus.on('ws-graph-title-updated', this.handleGraphTitleUpdated.bind(this));
this.plugin.eventBus.on('ws-node-title-updated', this.handleNodeTitleUpdated.bind(this)); this.plugin.eventBus.on('ws-node-title-updated', this.handleNodeTitleUpdated.bind(this));
@ -220,6 +221,7 @@ export class GraphView extends ItemView {
this.plugin.eventBus.off('new-chat', this.handleNewChat); this.plugin.eventBus.off('new-chat', this.handleNewChat);
this.plugin.eventBus.off('graph-selected', this.handleGraphSelected); this.plugin.eventBus.off('graph-selected', this.handleGraphSelected);
this.plugin.eventBus.off('node-selected', this.handleNodeSelectedFromBus);
this.plugin.eventBus.off('delete-node', this.handleDeleteNodeFromChat); this.plugin.eventBus.off('delete-node', this.handleDeleteNodeFromChat);
// WebSocket Event Cleanup // WebSocket Event Cleanup
@ -641,6 +643,25 @@ export class GraphView extends ItemView {
await this.fetchGraphData(data.graphId); await this.fetchGraphData(data.graphId);
} }
/**
* Обработчик события выбора узла из других компонентов (например, ChatPanel).
* Синхронизирует визуальное состояние графа (подсветку текущего узла).
*/
private handleNodeSelectedFromBus = (data: { nodeId: string; graphId: string }) => {
// Реагируем только если это для нашего текущего графа
if (this.selectedGraphId === data.graphId) {
this.currentNode = data.nodeId;
// Если какие-то узлы подсвечены руками (через Shift), сбрасываем это
if (this.selectedNodeIds.size > 0) {
this.selectedNodeIds.clear();
}
// Перерисовываем канвас (это передаст новый activeNodeId в ReactFlow и сдвинет фокус)
this.renderGraphPanel();
}
};
/** /**
* Обработчик события удаления узла из ChatPanel. * Обработчик события удаления узла из ChatPanel.
*/ */