feat(v2/approvals): per-card titles and structured options
Approval cards now carry a required title (Add MCP Request, Install Packages Request, Rebuild Request, Credentials Request) and structured options with distinct pre-click label, post-click selectedLabel (e.g. "✅ Approved" / "❌ Rejected"), and value used for click routing. The title and normalized options are persisted in pending_questions so the post-click card edit can render the correct per-type title and selected label on both chat-sdk channels and Discord interactions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -375,11 +375,15 @@ describe('pending questions', () => {
|
||||
platform_id: 'chan-1',
|
||||
channel_type: 'discord',
|
||||
thread_id: null,
|
||||
title: 'Test',
|
||||
options: [{ label: 'Yes', selectedLabel: 'Yes', value: 'yes' }],
|
||||
created_at: now(),
|
||||
});
|
||||
const result = getPendingQuestion('q-1');
|
||||
expect(result).toBeDefined();
|
||||
expect(result!.session_id).toBe('sess-1');
|
||||
expect(result!.title).toBe('Test');
|
||||
expect(result!.options[0].value).toBe('yes');
|
||||
});
|
||||
|
||||
it('should delete', () => {
|
||||
@@ -390,6 +394,8 @@ describe('pending questions', () => {
|
||||
platform_id: null,
|
||||
channel_type: null,
|
||||
thread_id: null,
|
||||
title: 'Test',
|
||||
options: [{ label: 'Yes', selectedLabel: 'Yes', value: 'yes' }],
|
||||
created_at: now(),
|
||||
});
|
||||
deletePendingQuestion('q-1');
|
||||
|
||||
@@ -61,6 +61,8 @@ export const migration001: Migration = {
|
||||
platform_id TEXT,
|
||||
channel_type TEXT,
|
||||
thread_id TEXT,
|
||||
title TEXT NOT NULL,
|
||||
options_json TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
`);
|
||||
|
||||
@@ -64,6 +64,8 @@ CREATE TABLE pending_questions (
|
||||
platform_id TEXT,
|
||||
channel_type TEXT,
|
||||
thread_id TEXT,
|
||||
title TEXT NOT NULL,
|
||||
options_json TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
`;
|
||||
|
||||
@@ -75,16 +75,29 @@ export function deleteSession(id: string): void {
|
||||
export function createPendingQuestion(pq: PendingQuestion): void {
|
||||
getDb()
|
||||
.prepare(
|
||||
`INSERT INTO pending_questions (question_id, session_id, message_out_id, platform_id, channel_type, thread_id, created_at)
|
||||
VALUES (@question_id, @session_id, @message_out_id, @platform_id, @channel_type, @thread_id, @created_at)`,
|
||||
`INSERT INTO pending_questions (question_id, session_id, message_out_id, platform_id, channel_type, thread_id, title, options_json, created_at)
|
||||
VALUES (@question_id, @session_id, @message_out_id, @platform_id, @channel_type, @thread_id, @title, @options_json, @created_at)`,
|
||||
)
|
||||
.run(pq);
|
||||
.run({
|
||||
question_id: pq.question_id,
|
||||
session_id: pq.session_id,
|
||||
message_out_id: pq.message_out_id,
|
||||
platform_id: pq.platform_id,
|
||||
channel_type: pq.channel_type,
|
||||
thread_id: pq.thread_id,
|
||||
title: pq.title,
|
||||
options_json: JSON.stringify(pq.options),
|
||||
created_at: pq.created_at,
|
||||
});
|
||||
}
|
||||
|
||||
export function getPendingQuestion(questionId: string): PendingQuestion | undefined {
|
||||
return getDb().prepare('SELECT * FROM pending_questions WHERE question_id = ?').get(questionId) as
|
||||
| PendingQuestion
|
||||
| undefined;
|
||||
const row = getDb()
|
||||
.prepare('SELECT * FROM pending_questions WHERE question_id = ?')
|
||||
.get(questionId) as (Omit<PendingQuestion, 'options'> & { options_json: string }) | undefined;
|
||||
if (!row) return undefined;
|
||||
const { options_json, ...rest } = row;
|
||||
return { ...rest, options: JSON.parse(options_json) };
|
||||
}
|
||||
|
||||
export function deletePendingQuestion(questionId: string): void {
|
||||
|
||||
Reference in New Issue
Block a user