feat(chat): extract and render action buttons from task cards (Cancel, Review Changes)
This commit is contained in:
@@ -433,6 +433,14 @@ body {
|
|||||||
padding: 8px 14px 10px;
|
padding: 8px 14px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.msg-card-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-top: 1px solid var(--border-subtle);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.msg-step {
|
.msg-step {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|||||||
@@ -173,6 +173,35 @@ class ChatPanel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 카드 내부 액션 버튼 (Cancel, Review Changes 등)
|
||||||
|
if (msg.actions && msg.actions.length > 0) {
|
||||||
|
const actionsDiv = document.createElement('div');
|
||||||
|
actionsDiv.className = 'msg-card-actions';
|
||||||
|
|
||||||
|
for (const btn of msg.actions) {
|
||||||
|
const el = document.createElement('button');
|
||||||
|
el.className = 'msg-action-btn';
|
||||||
|
el.textContent = btn.label;
|
||||||
|
|
||||||
|
if (['Proceed', 'Approve', 'Accept', 'Yes', 'Allow'].some(k => btn.label.includes(k))) {
|
||||||
|
el.classList.add('msg-action-primary');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn.x && btn.y) {
|
||||||
|
el.style.cursor = 'pointer';
|
||||||
|
el.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation(); // 카드 토글 방지
|
||||||
|
if (this.onActionClick) {
|
||||||
|
this.onActionClick({ label: btn.label, x: btn.x, y: btn.y });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsDiv.appendChild(el);
|
||||||
|
}
|
||||||
|
card.appendChild(actionsDiv);
|
||||||
|
}
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,12 +174,27 @@ class CDPClient {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 카드 내부 액션 버튼 추출 (Cancel, Review Changes 등)
|
||||||
|
const actionKeywords = ['Proceed','Cancel','Open','View','Review','Approve','Reject','Yes','No','Accept','Deny','Allow','Skip'];
|
||||||
|
const cardBtns = Array.from(card.querySelectorAll('button')).map(b => {
|
||||||
|
const label = b.textContent.trim();
|
||||||
|
const rect = b.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
label,
|
||||||
|
x: Math.round(rect.left + rect.width / 2),
|
||||||
|
y: Math.round(rect.top + rect.height / 2),
|
||||||
|
w: Math.round(rect.width),
|
||||||
|
h: Math.round(rect.height),
|
||||||
|
};
|
||||||
|
}).filter(b => b.label && b.w > 0 && actionKeywords.some(k => b.label.includes(k)));
|
||||||
|
|
||||||
messages.push({
|
messages.push({
|
||||||
type: 'task',
|
type: 'task',
|
||||||
title: titleEl ? titleEl.textContent.trim() : '',
|
title: titleEl ? titleEl.textContent.trim() : '',
|
||||||
summary: summaryEl ? summaryEl.textContent.trim().substring(0, 500) : '',
|
summary: summaryEl ? summaryEl.textContent.trim().substring(0, 500) : '',
|
||||||
collapsed: expanded ? expanded.getAttribute('aria-expanded') === 'false' : true,
|
collapsed: expanded ? expanded.getAttribute('aria-expanded') === 'false' : true,
|
||||||
steps: steps.slice(0, 20),
|
steps: steps.slice(0, 20),
|
||||||
|
actions: cardBtns.slice(0, 5),
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user