Show full dashboard room content
This commit is contained in:
@@ -208,4 +208,42 @@ describe('RoomCardV2', () => {
|
|||||||
);
|
);
|
||||||
expect(html).toContain('bar-chart-label-fit-playwright.png');
|
expect(html).toContain('bar-chart-label-fit-playwright.png');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders expanded watcher messages without truncating content', () => {
|
||||||
|
const watcherTail = 'WATCHER_TAIL_VISIBLE';
|
||||||
|
const html = renderToStaticMarkup(
|
||||||
|
createElement(RoomCardV2, {
|
||||||
|
activity: activity({
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
id: 'watcher-1',
|
||||||
|
sender: 'bot-1',
|
||||||
|
senderName: 'reviewer',
|
||||||
|
content: `[Watcher] ${'검증 로그 '.repeat(40)} ${watcherTail}`,
|
||||||
|
timestamp: '2026-04-28T02:00:00.000Z',
|
||||||
|
isFromMe: false,
|
||||||
|
isBotMessage: true,
|
||||||
|
sourceKind: 'bot',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
activityLoading: false,
|
||||||
|
busy: false,
|
||||||
|
draft: '',
|
||||||
|
entry,
|
||||||
|
expanded: true,
|
||||||
|
inboxItems: [],
|
||||||
|
locale: 'ko',
|
||||||
|
onDraftChange: () => {},
|
||||||
|
onSendMessage: () => {},
|
||||||
|
onToggle: () => {},
|
||||||
|
pinned: true,
|
||||||
|
t,
|
||||||
|
...formatters,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(html).toContain('class="room-watcher-fold"');
|
||||||
|
expect(html).toContain(watcherTail);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -870,7 +870,7 @@ function RoomWatcherFold({
|
|||||||
</strong>
|
</strong>
|
||||||
<time>{formatDate(message.timestamp, locale)}</time>
|
<time>{formatDate(message.timestamp, locale)}</time>
|
||||||
</header>
|
</header>
|
||||||
<ParsedBody text={message.content} truncate={200} />
|
<ParsedBody text={message.content} />
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ body:has(.view-stack.view-rooms) .error-card {
|
|||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
scroll-padding-bottom: 96px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-stack.view-rooms .rooms-detail .room-card-v2.is-pinned {
|
.view-stack.view-rooms .rooms-detail .room-card-v2.is-pinned {
|
||||||
@@ -290,7 +291,7 @@ body:has(.view-stack.view-rooms) .error-card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.view-stack.view-rooms .rooms-detail .room-thread-section {
|
.view-stack.view-rooms .rooms-detail .room-thread-section {
|
||||||
padding: 4px 12px 4px 0;
|
padding: 4px 12px 96px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-stack.view-rooms .rooms-detail .room-card-head {
|
.view-stack.view-rooms .rooms-detail .room-card-head {
|
||||||
|
|||||||
@@ -238,6 +238,8 @@ describe('web dashboard data', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('builds redacted room activity from messages and paired turn output', () => {
|
it('builds redacted room activity from messages and paired turn output', () => {
|
||||||
|
const longMessageTail = 'TAIL_MESSAGE_VISIBLE';
|
||||||
|
const longOutputTail = 'TAIL_OUTPUT_VISIBLE';
|
||||||
const task = makePairedTask({
|
const task = makePairedTask({
|
||||||
id: 'paired-room-1',
|
id: 'paired-room-1',
|
||||||
chat_jid: 'dc:ops',
|
chat_jid: 'dc:ops',
|
||||||
@@ -281,21 +283,12 @@ describe('web dashboard data', () => {
|
|||||||
last_error: 'OPENAI_API_KEY=plain-secret-value',
|
last_error: 'OPENAI_API_KEY=plain-secret-value',
|
||||||
};
|
};
|
||||||
const outputs: PairedTurnOutput[] = [
|
const outputs: PairedTurnOutput[] = [
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
task_id: task.id,
|
|
||||||
turn_number: 1,
|
|
||||||
role: 'owner',
|
|
||||||
output_text: 'owner output',
|
|
||||||
verdict: 'step_done',
|
|
||||||
created_at: '2026-04-26T05:25:00.000Z',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
task_id: task.id,
|
task_id: task.id,
|
||||||
turn_number: 2,
|
turn_number: 2,
|
||||||
role: 'reviewer',
|
role: 'reviewer',
|
||||||
output_text: 'reviewer output with BOT_TOKEN=plain-secret-value',
|
output_text: `reviewer output with BOT_TOKEN=plain-secret-value ${'x'.repeat(1900)} ${longOutputTail}`,
|
||||||
verdict: null,
|
verdict: null,
|
||||||
created_at: '2026-04-26T05:30:00.000Z',
|
created_at: '2026-04-26T05:30:00.000Z',
|
||||||
},
|
},
|
||||||
@@ -306,7 +299,7 @@ describe('web dashboard data', () => {
|
|||||||
chat_jid: 'dc:ops',
|
chat_jid: 'dc:ops',
|
||||||
sender: 'user-1',
|
sender: 'user-1',
|
||||||
sender_name: '눈쟁이',
|
sender_name: '눈쟁이',
|
||||||
content: 'latest message',
|
content: `latest message ${'y'.repeat(950)} ${longMessageTail}`,
|
||||||
timestamp: '2026-04-26T05:29:00.000Z',
|
timestamp: '2026-04-26T05:29:00.000Z',
|
||||||
is_from_me: false,
|
is_from_me: false,
|
||||||
is_bot_message: false,
|
is_bot_message: false,
|
||||||
@@ -347,12 +340,17 @@ describe('web dashboard data', () => {
|
|||||||
{
|
{
|
||||||
turnNumber: 2,
|
turnNumber: 2,
|
||||||
role: 'reviewer',
|
role: 'reviewer',
|
||||||
outputText: 'reviewer output with BOT_TOKEN=<redacted>',
|
outputText: expect.stringMatching(
|
||||||
|
new RegExp(`BOT_TOKEN=<redacted>[\\s\\S]*${longOutputTail}`),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
expect(activity.messages).toMatchObject([
|
expect(activity.messages).toMatchObject([
|
||||||
{ senderName: '눈쟁이', content: 'latest message' },
|
{
|
||||||
|
senderName: '눈쟁이',
|
||||||
|
content: expect.stringContaining(longMessageTail),
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -163,8 +163,6 @@ const SECRET_ASSIGNMENT_RE =
|
|||||||
/\b([A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|API_KEY|AUTH|PRIVATE_KEY)[A-Z0-9_]*)\s*=\s*([^\s"'`]+)/gi;
|
/\b([A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|API_KEY|AUTH|PRIVATE_KEY)[A-Z0-9_]*)\s*=\s*([^\s"'`]+)/gi;
|
||||||
const SECRET_VALUE_RE =
|
const SECRET_VALUE_RE =
|
||||||
/\b(?:sk-[A-Za-z0-9_-]{12,}|gh[pousr]_[A-Za-z0-9_]{12,}|xox[baprs]-[A-Za-z0-9-]{12,}|eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{10,})\b/g;
|
/\b(?:sk-[A-Za-z0-9_-]{12,}|gh[pousr]_[A-Za-z0-9_]{12,}|xox[baprs]-[A-Za-z0-9-]{12,}|eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{10,})\b/g;
|
||||||
const ROOM_MESSAGE_PREVIEW_MAX_LENGTH = 900;
|
|
||||||
const ROOM_OUTPUT_PREVIEW_MAX_LENGTH = 1800;
|
|
||||||
|
|
||||||
function redactSensitiveText(value: string): string {
|
function redactSensitiveText(value: string): string {
|
||||||
return value
|
return value
|
||||||
@@ -185,8 +183,8 @@ function buildInboxPreview(value: string): string {
|
|||||||
return truncateText(redactSensitiveText(value).replace(/\s+/g, ' ').trim());
|
return truncateText(redactSensitiveText(value).replace(/\s+/g, ' ').trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildRoomPreview(value: string, maxLength: number): string {
|
function buildRoomBody(value: string): string {
|
||||||
return truncateText(redactSensitiveText(value).trim(), maxLength);
|
return redactSensitiveText(value).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeCommonHtmlEntities(value: string): string {
|
function decodeCommonHtmlEntities(value: string): string {
|
||||||
@@ -485,7 +483,7 @@ function sanitizeRoomMessage(
|
|||||||
id: message.id,
|
id: message.id,
|
||||||
sender: message.sender,
|
sender: message.sender,
|
||||||
senderName: message.sender_name || message.sender,
|
senderName: message.sender_name || message.sender,
|
||||||
content: buildRoomPreview(normalized.text, ROOM_MESSAGE_PREVIEW_MAX_LENGTH),
|
content: buildRoomBody(normalized.text),
|
||||||
attachments: normalized.attachments,
|
attachments: normalized.attachments,
|
||||||
timestamp: message.timestamp,
|
timestamp: message.timestamp,
|
||||||
isFromMe: !!message.is_from_me,
|
isFromMe: !!message.is_from_me,
|
||||||
@@ -576,10 +574,7 @@ function sanitizeRoomTurn(
|
|||||||
completedAt,
|
completedAt,
|
||||||
lastError:
|
lastError:
|
||||||
(attempt?.last_error ?? turn.last_error)
|
(attempt?.last_error ?? turn.last_error)
|
||||||
? buildRoomPreview(
|
? buildRoomBody(attempt?.last_error ?? turn.last_error ?? '')
|
||||||
attempt?.last_error ?? turn.last_error ?? '',
|
|
||||||
ROOM_MESSAGE_PREVIEW_MAX_LENGTH,
|
|
||||||
)
|
|
||||||
: null,
|
: null,
|
||||||
progressText,
|
progressText,
|
||||||
progressUpdatedAt,
|
progressUpdatedAt,
|
||||||
@@ -598,10 +593,7 @@ function sanitizeRoomTurnOutput(
|
|||||||
role: output.role,
|
role: output.role,
|
||||||
verdict: output.verdict ?? null,
|
verdict: output.verdict ?? null,
|
||||||
createdAt: output.created_at,
|
createdAt: output.created_at,
|
||||||
outputText: buildRoomPreview(
|
outputText: buildRoomBody(normalized.text),
|
||||||
normalized.text,
|
|
||||||
ROOM_OUTPUT_PREVIEW_MAX_LENGTH,
|
|
||||||
),
|
|
||||||
attachments: normalized.attachments,
|
attachments: normalized.attachments,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user