feat: F018 human review queue — 2-panel governance workspace
Replaces the old ad-hoc ReviewQueue page with a full governance-compliant workflow: filterable task list, detail panel with confidence/risk context, role-aware approve/reject/escalate/more-data actions, and persistent notes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,29 +1,51 @@
|
||||
import { MockupReviewProvider } from '../provider/MockupReviewProvider'
|
||||
import type { ReviewFilters } from '../provider/IReviewProvider'
|
||||
import type { ReviewQueueItem } from '../domain/review'
|
||||
import type { ReviewTask, ReviewTaskStatus, ReviewNote } from '../domain/review'
|
||||
import type { DashboardReviewTask } from '../domain/dashboard'
|
||||
import type { ListResponse, ItemResponse } from './types'
|
||||
|
||||
const provider = MockupReviewProvider
|
||||
|
||||
export const reviewService = {
|
||||
async getQueue(filters?: ReviewFilters): Promise<ListResponse<ReviewQueueItem>> {
|
||||
async getQueue(filters?: ReviewFilters): Promise<ListResponse<ReviewTask>> {
|
||||
const data = await provider.getQueue(filters)
|
||||
return { data, meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
|
||||
},
|
||||
async getById(id: string): Promise<ItemResponse<ReviewQueueItem | null>> {
|
||||
|
||||
async getTasks(filters?: ReviewFilters): Promise<ListResponse<ReviewTask>> {
|
||||
return this.getQueue(filters)
|
||||
},
|
||||
|
||||
async getById(id: string): Promise<ItemResponse<ReviewTask | null>> {
|
||||
const data = await provider.getById(id)
|
||||
return { data }
|
||||
},
|
||||
async approve(id: string, reviewedBy: string, notes?: string): Promise<ItemResponse<ReviewQueueItem>> {
|
||||
|
||||
async getTask(id: string): Promise<ItemResponse<ReviewTask | null>> {
|
||||
return this.getById(id)
|
||||
},
|
||||
|
||||
async updateStatus(id: string, status: ReviewTaskStatus, userId: string, note?: string): Promise<ItemResponse<ReviewTask>> {
|
||||
const data = await provider.updateStatus(id, status, userId, note)
|
||||
return { data }
|
||||
},
|
||||
|
||||
async addNote(id: string, note: Omit<ReviewNote, 'id'>): Promise<ItemResponse<ReviewTask>> {
|
||||
const data = await provider.addNote(id, note)
|
||||
return { data }
|
||||
},
|
||||
|
||||
async approve(id: string, reviewedBy: string, notes?: string): Promise<ItemResponse<ReviewTask>> {
|
||||
const data = await provider.approve(id, reviewedBy, notes)
|
||||
return { data }
|
||||
},
|
||||
async reject(id: string, reviewedBy: string, notes?: string): Promise<ItemResponse<ReviewQueueItem>> {
|
||||
|
||||
async reject(id: string, reviewedBy: string, notes?: string): Promise<ItemResponse<ReviewTask>> {
|
||||
const data = await provider.reject(id, reviewedBy, notes)
|
||||
return { data }
|
||||
},
|
||||
async assign(id: string, assignTo: string): Promise<ItemResponse<ReviewQueueItem>> {
|
||||
|
||||
async assign(id: string, assignTo: string): Promise<ItemResponse<ReviewTask>> {
|
||||
const data = await provider.assign(id, assignTo)
|
||||
return { data }
|
||||
},
|
||||
@@ -35,12 +57,15 @@ export const reviewService = {
|
||||
|
||||
async getDashboardTasks(): Promise<DashboardReviewTask[]> {
|
||||
const items = await provider.getQueue()
|
||||
return items.slice(0, 8).map(r => ({
|
||||
id: r.id,
|
||||
title: `Match ${r.matchId} · Score ${r.matchScore}`,
|
||||
priority: r.priority,
|
||||
status: r.status,
|
||||
type: 'REVIEW',
|
||||
}))
|
||||
return items
|
||||
.filter(r => r.status === 'PENDING' || r.status === 'IN_REVIEW' || r.status === 'ESCALATED')
|
||||
.slice(0, 8)
|
||||
.map(r => ({
|
||||
id: r.id,
|
||||
title: r.title,
|
||||
priority: r.priority as 'HIGH' | 'MEDIUM' | 'LOW',
|
||||
status: r.status,
|
||||
type: r.entityType,
|
||||
}))
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user