refactor(frontend): dedupliziere JS-Code und fixe Bugs
- fix: _oldestLoadedMessageId → _oldestLoadedSortKey (chat.js, chat-page.js) - move: formatTimestamp nach ui-helpers.js (war _formatTimestamp in msg-actions.js) - move: _isReviewMessage nach ui-helpers.js (war in history.js) - add: _getSubAgentMeta + _createSubAgentHeader in ui-helpers.js - refactor: stream-ui.js + history.js nutzen _createSubAgentHeader - refactor: flushText() Hilfsfunktion in _renderReviewGroup (history.js) - refactor: shared-page.js nutzt _mergeConsecutiveAssistantTexts statt eigener Kopie - refactor: _initCardMenu + _onCardMenuAction Helper in dashboard.js -53 Zeilen netto
This commit is contained in:
1 parent
57560cbbea
commit
33934b2c4a
9 files changed
+114
-167
No files matched your search
@@ -352,7 +352,7 @@ registerPage('chat', {
|
||||
// State zurücksetzen und History laden
|
||||
lastKnownMessageId = 0;
|
||||
loadedArchiveCount = 0;
|
||||
_oldestLoadedMessageId = 0;
|
||||
_oldestLoadedSortKey = 0;
|
||||
_hasMoreOlderMessages = false;
|
||||
isStreaming = false;
|
||||
|
||||
|
||||
@@ -104,28 +104,15 @@ registerPage('dashboard', {
|
||||
card.addEventListener('click', () => navigateTo('chat', { id: s.sessionId }));
|
||||
}
|
||||
|
||||
const menuTrigger = card.querySelector('.card-menu-trigger');
|
||||
const menuDropdown = card.querySelector('.card-menu-dropdown');
|
||||
menuTrigger.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
_openCardMenu(menuTrigger, menuDropdown);
|
||||
});
|
||||
const { dropdown: sessionMenu } = _initCardMenu(card);
|
||||
chatBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
if (chatBtn.disabled) return;
|
||||
menuDropdown.hidden = true;
|
||||
sessionMenu.hidden = true;
|
||||
navigateTo('chat', { id: s.sessionId });
|
||||
});
|
||||
menuDropdown.querySelector('[data-action="edit"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
navigateTo('session', { id: s.sessionId });
|
||||
});
|
||||
menuDropdown.querySelector('[data-action="openclaw-import"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
showOpenClawImportModal(s.sessionId);
|
||||
});
|
||||
_onCardMenuAction(sessionMenu, 'edit', () => navigateTo('session', { id: s.sessionId }));
|
||||
_onCardMenuAction(sessionMenu, 'openclaw-import', () => showOpenClawImportModal(s.sessionId));
|
||||
grid.appendChild(card);
|
||||
}
|
||||
|
||||
@@ -152,22 +139,9 @@ registerPage('dashboard', {
|
||||
</div>
|
||||
</div>`;
|
||||
titleRow.insertAdjacentHTML('beforeend', menuHtml);
|
||||
const menuTrigger = card.querySelector('.card-menu-trigger');
|
||||
const menuDropdown = card.querySelector('.card-menu-dropdown');
|
||||
menuTrigger.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
_openCardMenu(menuTrigger, menuDropdown);
|
||||
});
|
||||
menuDropdown.querySelector('[data-action="files"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
openFileExplorer({ agentId: a.agentId });
|
||||
});
|
||||
menuDropdown.querySelector('[data-action="edit"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
navigateTo('agent', { id: a.agentId });
|
||||
});
|
||||
const { dropdown: agentMenu } = _initCardMenu(card);
|
||||
_onCardMenuAction(agentMenu, 'files', () => openFileExplorer({ agentId: a.agentId }));
|
||||
_onCardMenuAction(agentMenu, 'edit', () => navigateTo('agent', { id: a.agentId }));
|
||||
agentGrid.appendChild(card);
|
||||
}
|
||||
|
||||
@@ -213,30 +187,14 @@ registerPage('dashboard', {
|
||||
</div>
|
||||
`;
|
||||
|
||||
const menuTrigger = card.querySelector('.card-menu-trigger');
|
||||
const menuDropdown = card.querySelector('.card-menu-dropdown');
|
||||
menuTrigger.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
_openCardMenu(menuTrigger, menuDropdown);
|
||||
});
|
||||
|
||||
menuDropdown.querySelector('[data-action="edit"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
navigateTo('cronjob', { id: cj.cronjobId });
|
||||
});
|
||||
|
||||
menuDropdown.querySelector('[data-action="toggle"]').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
const { dropdown: cjMenu } = _initCardMenu(card);
|
||||
_onCardMenuAction(cjMenu, 'edit', () => navigateTo('cronjob', { id: cj.cronjobId }));
|
||||
_onCardMenuAction(cjMenu, 'toggle', async () => {
|
||||
await apiToggleCronjob(cj.cronjobId);
|
||||
showToast(cj.isEnabled ? 'Cronjob pausiert' : 'Cronjob aktiviert');
|
||||
navigateTo('dashboard', {}, { replace: true });
|
||||
});
|
||||
|
||||
menuDropdown.querySelector('[data-action="run"]').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
_onCardMenuAction(cjMenu, 'run', async () => {
|
||||
showToast('Cronjob wird ausgeführt...');
|
||||
const result = await apiRunCronjob(cj.cronjobId);
|
||||
if (result.status === 'success') {
|
||||
@@ -305,27 +263,13 @@ registerPage('dashboard', {
|
||||
</div>
|
||||
`;
|
||||
|
||||
const menuTrigger = card.querySelector('.card-menu-trigger');
|
||||
const menuDropdown = card.querySelector('.card-menu-dropdown');
|
||||
menuTrigger.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
_openCardMenu(menuTrigger, menuDropdown);
|
||||
});
|
||||
|
||||
menuDropdown.querySelector('[data-action="copy"]').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
const { dropdown: shareMenu } = _initCardMenu(card);
|
||||
_onCardMenuAction(shareMenu, 'copy', async () => {
|
||||
await navigator.clipboard.writeText(shareUrl);
|
||||
showToast('Link kopiert!');
|
||||
});
|
||||
menuDropdown.querySelector('[data-action="open"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
window.open(shareUrl, '_blank');
|
||||
});
|
||||
menuDropdown.querySelector('[data-action="delete"]').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
_onCardMenuAction(shareMenu, 'open', () => window.open(shareUrl, '_blank'));
|
||||
_onCardMenuAction(shareMenu, 'delete', async () => {
|
||||
await apiDeleteShare(s.shareToken);
|
||||
card.remove();
|
||||
if (sharedGrid.children.length === 0) sharedSection.hidden = true;
|
||||
@@ -364,4 +308,30 @@ function _openCardMenu(trigger, dropdown) {
|
||||
if (finalRect.left < 0) dropdown.style.left = '8px';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a card menu: wires up the trigger button to open/close the dropdown.
|
||||
* Returns { trigger, dropdown } for further action wiring.
|
||||
*/
|
||||
function _initCardMenu(card) {
|
||||
const trigger = card.querySelector('.card-menu-trigger');
|
||||
const dropdown = card.querySelector('.card-menu-dropdown');
|
||||
trigger.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
_openCardMenu(trigger, dropdown);
|
||||
});
|
||||
return { trigger, dropdown };
|
||||
}
|
||||
|
||||
/**
|
||||
* Wires a card menu action button (by data-action) to a handler.
|
||||
*/
|
||||
function _onCardMenuAction(dropdown, action, handler) {
|
||||
const btn = dropdown.querySelector(`[data-action="${action}"]`);
|
||||
if (btn) btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
dropdown.hidden = true;
|
||||
handler(e, btn);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ registerPage('shared', {
|
||||
}
|
||||
|
||||
// Aufeinanderfolgende Assistant-Text-Messages mergen (wie im Chat)
|
||||
messages = _mergeConsecutiveTexts(messages);
|
||||
messages = _mergeConsecutiveAssistantTexts(messages);
|
||||
|
||||
for (const msg of messages) {
|
||||
const c = msg.content || '';
|
||||
@@ -73,30 +73,4 @@ registerPage('shared', {
|
||||
destroy: () => {}
|
||||
});
|
||||
|
||||
function _mergeConsecutiveTexts(msgs) {
|
||||
const result = [];
|
||||
for (const msg of msgs) {
|
||||
const c = msg.content || '';
|
||||
if (msg.type === 'web_search_result') {
|
||||
result.push(Object.assign({}, msg));
|
||||
continue;
|
||||
}
|
||||
if (msg.role === 'assistant' && !_isReviewMessage(c) && msg.type !== 'web_search_result') {
|
||||
let prev = null;
|
||||
for (let i = result.length - 1; i >= 0; i--) {
|
||||
if (result[i].type === 'web_search_result') continue;
|
||||
prev = result[i];
|
||||
break;
|
||||
}
|
||||
if (prev && prev.role === 'assistant'
|
||||
&& !_isReviewMessage(prev.content)
|
||||
&& prev.iteration === msg.iteration) {
|
||||
prev.content = (prev.content || '') + '\n\n' + c;
|
||||
if (msg.createdAt) prev.createdAt = msg.createdAt;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result.push(Object.assign({}, msg));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// _mergeConsecutiveTexts → replaced by _mergeConsecutiveAssistantTexts from history.js
|
||||
Reference in new issue
Block a user