diff --git a/packages/compliance/src/dashboards/control_posture.dashboard.ts b/packages/compliance/src/dashboards/control_posture.dashboard.ts index ec53c9c..e864440 100644 --- a/packages/compliance/src/dashboards/control_posture.dashboard.ts +++ b/packages/compliance/src/dashboards/control_posture.dashboard.ts @@ -86,40 +86,9 @@ export const ControlPostureDashboard: Dashboard = { layout: { x: 9, y: 0, w: 3, h: 2 }, options: { icon: 'ClipboardCheck', format: '0,0' }, }, - { - id: 'failing_table', - dataset: 'compliance_control_metrics', - values: ['control_count'], - title: 'Failing Controls (Action Required)', - type: 'table', - filter: { last_status: { $in: ['failed', 'partial'] } }, - layout: { x: 0, y: 2, w: 8, h: 5 }, - options: { - columns: ['code', 'title', 'framework', 'criticality', 'last_assessed_at'], - pageSize: 10, - sort: [ - { field: 'criticality', order: 'asc' }, - { field: 'code', order: 'asc' }, - ], - }, - }, - { - id: 'expiring_evidence_table', - dataset: 'compliance_evidence_metrics', - values: ['evidence_count'], - title: 'Evidence Expiring Soon', - type: 'table', - filter: { - status: 'approved', - expires_on: { $gte: '{today}' }, - }, - layout: { x: 8, y: 2, w: 4, h: 5 }, - options: { - columns: ['title', 'control', 'expires_on'], - pageSize: 10, - sort: [{ field: 'expires_on', order: 'asc' }], - }, - }, + // Record listings moved to object-bound ListViews (ADR-0017): `failing_table` + // is the Controls "Failing" tab; `expiring_evidence_table` is the Evidence + // "Expiring ≤ 30d" tab. KPI widgets above keep the counts here. { id: 'assessments_by_month', dataset: 'compliance_assessment_metrics', diff --git a/packages/content/src/dashboards/editorial_calendar.dashboard.ts b/packages/content/src/dashboards/editorial_calendar.dashboard.ts index 8217edd..4ad3d1b 100644 --- a/packages/content/src/dashboards/editorial_calendar.dashboard.ts +++ b/packages/content/src/dashboards/editorial_calendar.dashboard.ts @@ -83,23 +83,8 @@ export const EditorialCalendarDashboard: Dashboard = { options: { icon: 'AlertTriangle', format: '0,0' }, }, - { - id: 'calendar_main', - dataset: 'content_piece_metrics', - values: ['piece_count'], - title: 'Upcoming Calendar', - type: 'table', - filter: { - status: { $in: ['approved', 'scheduled', 'published'] }, - publish_at: { $gte: '{last_month_start}' }, - }, - layout: { x: 0, y: 2, w: 8, h: 6 }, - options: { - columns: ['title', 'status', 'format', 'target_channels', 'publish_at'], - pageSize: 25, - sort: [{ field: 'publish_at', order: 'asc' }], - }, - }, + // Record listing moved to an object-bound ListView (ADR-0017): the former + // `calendar_main` is the Pieces "Calendar" tab (editorial_calendar view). { id: 'publications_by_channel', dataset: 'content_publication_metrics', diff --git a/packages/content/src/dashboards/roi_by_channel.dashboard.ts b/packages/content/src/dashboards/roi_by_channel.dashboard.ts index b17f28e..3b0daeb 100644 --- a/packages/content/src/dashboards/roi_by_channel.dashboard.ts +++ b/packages/content/src/dashboards/roi_by_channel.dashboard.ts @@ -110,27 +110,8 @@ export const RoiByChannelDashboard: Dashboard = { layout: { x: 6, y: 2, w: 6, h: 5 }, }, - { - id: 'top_publications', - dataset: 'content_publication_metrics', - values: ['publication_count'], - title: 'Top 10 Publications by Signups', - type: 'table', - - layout: { x: 0, y: 7, w: 12, h: 5 }, - options: { - columns: [ - 'piece', - 'channel', - 'published_at', - 'total_views', - 'total_clicks', - 'total_signups', - 'total_revenue', - ], - pageSize: 10, - sort: [{ field: 'total_signups', order: 'desc' }], - }, - }, + // Record listing moved to an object-bound ListView (ADR-0017): the former + // `top_publications` is the Publications "Top Performers" tab + // (top_publications view, sorted by signups). ], }; diff --git a/packages/content/src/dashboards/today_workbench.dashboard.ts b/packages/content/src/dashboards/today_workbench.dashboard.ts index 6cd6ac7..cd8bc0f 100644 --- a/packages/content/src/dashboards/today_workbench.dashboard.ts +++ b/packages/content/src/dashboards/today_workbench.dashboard.ts @@ -85,37 +85,8 @@ export const TodayWorkbenchDashboard: Dashboard = { options: { icon: 'Send', format: '0,0' }, }, - { - id: 'my_pieces_table', - dataset: 'content_piece_metrics', - values: ['piece_count'], - title: 'Pieces I own (or unassigned), not done', - type: 'table', - filter: { - $or: [{ assignee: '{current_user_id}' }, { assignee: null }], - status: { $in: ['backlog', 'drafting', 'in_review', 'approved', 'scheduled'] }, - }, - layout: { x: 0, y: 2, w: 7, h: 5 }, - options: { - columns: ['title', 'status', 'format', 'publish_at'], - pageSize: 10, - sort: [{ field: 'publish_at', order: 'asc' }], - }, - }, - - { - id: 'signals_to_triage', - dataset: 'content_signal_metrics', - values: ['signal_count'], - title: 'Signals to Triage', - type: 'table', - filter: { status: 'captured' }, - layout: { x: 7, y: 2, w: 5, h: 5 }, - options: { - columns: ['headline', 'source_kind', 'impact', 'captured_at'], - pageSize: 10, - sort: [{ field: 'impact', order: 'desc' }], - }, - }, + // Record listings moved to object-bound ListViews (ADR-0017): `my_pieces_table` + // is covered by the Pieces "My Drafts" tab; `signals_to_triage` is the Signals + // "My Triage" tab (my_triage_queue, status=captured). ], }; diff --git a/packages/content/src/views/content_publication.view.ts b/packages/content/src/views/content_publication.view.ts index 286a7f7..49609db 100644 --- a/packages/content/src/views/content_publication.view.ts +++ b/packages/content/src/views/content_publication.view.ts @@ -27,12 +27,32 @@ export const PublicationViews = defineView({ exportOptions: ['csv', 'xlsx'], tabs: [ { name: 'all', label: 'All', view: 'all_publications', isDefault: true, pinned: true }, + { name: 'top', label: 'Top Performers', icon: 'trophy', view: 'top_publications' }, { name: 'week', label: 'This Week', icon: 'calendar', view: 'this_week_publications' }, { name: 'by_channel', label: 'By Channel', icon: 'layers', view: 'by_channel_publications' }, ], }, listViews: { + // Top publications by signups — surfaces the former `top_publications` + // dashboard table as an object-bound ListView (ADR-0017). + top_publications: { + name: 'top_publications', + type: 'grid', + label: 'Top Performers', + data: { provider: 'object', object: 'content_publication' }, + columns: [ + 'piece', + 'channel', + 'published_at', + 'total_views', + 'total_clicks', + 'total_signups', + 'total_revenue', + ], + sort: [{ field: 'total_signups', order: 'desc' }], + }, + this_week_publications: { name: 'this_week_publications', type: 'grid', diff --git a/packages/contracts/src/dashboards/renewals_at_risk.dashboard.ts b/packages/contracts/src/dashboards/renewals_at_risk.dashboard.ts index d15473f..8e8465a 100644 --- a/packages/contracts/src/dashboards/renewals_at_risk.dashboard.ts +++ b/packages/contracts/src/dashboards/renewals_at_risk.dashboard.ts @@ -88,41 +88,9 @@ export const RenewalsAtRiskDashboard: Dashboard = { layout: { x: 9, y: 0, w: 3, h: 2 }, options: { icon: 'TrendingUp', format: '$0,0' }, }, - { - id: 'expiring_table', - dataset: 'contracts_contract_metrics', - values: ['contract_count'], - title: 'Expiring Contracts (Next 60d)', - type: 'table', - // Only `{today}` is resolved client-side by the data endpoint; tokens - // like `{60_days_from_now}` only work inside the analytics service. - // We sort ascending by end_date and rely on pageSize to cap the list - // to the nearest renewals. - filter: { - status: 'active', - end_date: { $gte: '{today}' }, - }, - layout: { x: 0, y: 2, w: 8, h: 5 }, - options: { - columns: ['title', 'contract_type', 'end_date', 'auto_renew', 'total_value'], - pageSize: 10, - sort: [{ field: 'end_date', order: 'asc' }], - }, - }, - { - id: 'pending_obligations', - dataset: 'contracts_obligation_metrics', - values: ['obligation_count'], - title: 'Open Obligations', - type: 'table', - filter: { status: 'open' }, - layout: { x: 8, y: 2, w: 4, h: 5 }, - options: { - columns: ['summary', 'due_date', 'amount'], - pageSize: 10, - sort: [{ field: 'due_date', order: 'asc' }], - }, - }, + // Record listings moved to object-bound ListViews (ADR-0017): the former + // `expiring_table` is the Contracts "Expiring ≤ 60d" tab; `pending_obligations` + // is the Obligations "Open" tab. KPI widgets above keep the counts here. { id: 'signed_by_month', dataset: 'contracts_contract_metrics', diff --git a/packages/contracts/src/views/contracts_obligation.view.ts b/packages/contracts/src/views/contracts_obligation.view.ts index 989d358..5d70c11 100644 --- a/packages/contracts/src/views/contracts_obligation.view.ts +++ b/packages/contracts/src/views/contracts_obligation.view.ts @@ -25,12 +25,25 @@ export const ObligationViews = defineView({ exportOptions: ['csv', 'xlsx'], tabs: [ { name: 'all', label: 'All', view: 'all_obligations', isDefault: true, pinned: true }, + { name: 'open', label: 'Open', icon: 'circle-dot', view: 'open_obligations' }, { name: 'mine_open', label: 'My Open', icon: 'user', view: 'my_open_obligations' }, { name: 'overdue', label: 'Overdue', icon: 'clock', view: 'overdue_obligations' }, ], }, listViews: { + // Pending (open) obligations — surfaces the former `pending_obligations` + // dashboard table as an object-bound ListView (ADR-0017). + open_obligations: { + name: 'open_obligations', + type: 'grid', + label: 'Open Obligations', + data: { provider: 'object', object: 'contracts_obligation' }, + columns: ['summary', 'due_date', 'amount'], + filter: [{ field: 'status', operator: 'equals', value: 'open' }], + sort: [{ field: 'due_date', order: 'asc' }], + }, + my_open_obligations: { name: 'my_open_obligations', type: 'grid', diff --git a/packages/expense/src/dashboards/expenses_overview.dashboard.ts b/packages/expense/src/dashboards/expenses_overview.dashboard.ts index db66eee..a3102c5 100644 --- a/packages/expense/src/dashboards/expenses_overview.dashboard.ts +++ b/packages/expense/src/dashboards/expenses_overview.dashboard.ts @@ -73,34 +73,10 @@ export const ExpensesOverviewDashboard: Dashboard = { layout: { x: 9, y: 0, w: 3, h: 2 }, options: { icon: 'CheckCircle', format: '$0,0' }, }, - { - id: 'pending_reports_table', - dataset: 'expense_report_metrics', - values: ['report_count'], - title: 'Reports Awaiting Approval', - type: 'table', - filter: { status: 'submitted' }, - layout: { x: 0, y: 2, w: 8, h: 5 }, - options: { - columns: ['title', 'requester', 'total_amount', 'cost_center', 'submitted_at'], - pageSize: 10, - sort: [{ field: 'total_amount', order: 'desc' }], - }, - }, - { - id: 'to_reimburse_table', - dataset: 'expense_report_metrics', - values: ['report_count'], - title: 'Approved — To Reimburse', - type: 'table', - filter: { status: 'approved' }, - layout: { x: 8, y: 2, w: 4, h: 5 }, - options: { - columns: ['title', 'requester', 'total_amount'], - pageSize: 10, - sort: [{ field: 'approved_at', order: 'asc' }], - }, - }, + // Record listings moved to object-bound ListViews (ADR-0017): the former + // `pending_reports_table` / `to_reimburse_table` now live on the Reports + // object as the "Awaiting Approval" / "To Reimburse" tabs. The metric + // widgets above keep the at-a-glance counts on this dashboard. { id: 'spend_by_category', dataset: 'expense_line_metrics', diff --git a/packages/helpdesk/src/dashboards/agent_workbench.dashboard.ts b/packages/helpdesk/src/dashboards/agent_workbench.dashboard.ts index a152e24..0fe112f 100644 --- a/packages/helpdesk/src/dashboards/agent_workbench.dashboard.ts +++ b/packages/helpdesk/src/dashboards/agent_workbench.dashboard.ts @@ -82,39 +82,8 @@ export const AgentWorkbenchDashboard: Dashboard = { options: { icon: 'Sparkles', format: '0,0' }, }, - { - id: 'my_queue_table', - dataset: 'ticket_metrics', - values: ['ticket_count'], - title: 'My Queue (Priority Sorted)', - type: 'table', - filter: { - assignee: '{currentUser}', - status: { $nin: ['closed', 'resolved'] }, - }, - layout: { x: 0, y: 2, w: 8, h: 5 }, - options: { - columns: ['ticket_number', 'name', 'priority', 'ai_sentiment', 'first_response_due_at'], - pageSize: 10, - sort: [{ field: 'priority', order: 'desc' }], - }, - }, - { - id: 'breaching_table', - dataset: 'ticket_metrics', - values: ['ticket_count'], - title: 'SLA Breaches', - type: 'table', - filter: { - status: { $nin: ['closed', 'resolved'] }, - resolution_due_at: { $lt: '{today}' }, - }, - layout: { x: 8, y: 2, w: 4, h: 5 }, - options: { - columns: ['ticket_number', 'priority', 'resolution_due_at'], - pageSize: 10, - sort: [{ field: 'resolution_due_at', order: 'asc' }], - }, - }, + // Record listings moved to object-bound ListViews (ADR-0017): `my_queue_table` + // is the Tickets "My Queue" tab (my_queue view); `breaching_table` is the + // Tickets "Breaching SLA" tab. KPI widgets above keep the counts here. ], }; diff --git a/packages/helpdesk/src/dashboards/manager_overview.dashboard.ts b/packages/helpdesk/src/dashboards/manager_overview.dashboard.ts index 9cb3947..2f32846 100644 --- a/packages/helpdesk/src/dashboards/manager_overview.dashboard.ts +++ b/packages/helpdesk/src/dashboards/manager_overview.dashboard.ts @@ -115,28 +115,8 @@ export const ManagerOverviewDashboard: Dashboard = { layout: { x: 6, y: 6, w: 6, h: 4 }, }, - { - id: 'recent_escalated', - dataset: 'ticket_metrics', - values: ['ticket_count'], - title: 'Recently Escalated', - type: 'table', - filter: { status: 'escalated' }, - layout: { x: 0, y: 10, w: 12, h: 5 }, - options: { - columns: [ - 'ticket_number', - 'name', - 'customer', - 'team', - 'assignee', - 'ai_sentiment', - 'priority', - ], - pageSize: 10, - sort: [{ field: 'priority', order: 'desc' }], - }, - }, + // Record listing moved to an object-bound ListView (ADR-0017): the former + // `recent_escalated` is the Tickets "Escalated" tab (escalated_tickets view). { id: 'resolutions_by_day', dataset: 'ticket_metrics', diff --git a/packages/helpdesk/src/views/helpdesk_ticket.view.ts b/packages/helpdesk/src/views/helpdesk_ticket.view.ts index cd1d69f..07577a6 100644 --- a/packages/helpdesk/src/views/helpdesk_ticket.view.ts +++ b/packages/helpdesk/src/views/helpdesk_ticket.view.ts @@ -37,7 +37,9 @@ export const TicketViews = defineView({ icon: 'alert-triangle', view: 'breaching_tickets', }, + { name: 'escalated', label: 'Escalated', icon: 'trending-up', view: 'escalated_tickets' }, { name: 'angry', label: 'Angry', icon: 'flame', view: 'angry_tickets' }, + { name: 'my_queue', label: 'My Queue', icon: 'user', view: 'my_queue' }, ], }, @@ -78,6 +80,26 @@ export const TicketViews = defineView({ sort: [{ field: 'priority', order: 'desc' }], }, + // Escalated tickets — surfaces the former `recent_escalated` dashboard + // table as an object-bound ListView (ADR-0017). + escalated_tickets: { + name: 'escalated_tickets', + type: 'grid', + label: 'Escalated', + data: { provider: 'object', object: 'helpdesk_ticket' }, + columns: [ + 'ticket_number', + 'name', + 'customer', + 'team', + 'assignee', + 'ai_sentiment', + 'priority', + ], + filter: [{ field: 'status', operator: 'equals', value: 'escalated' }], + sort: [{ field: 'priority', order: 'desc' }], + }, + breaching_tickets: { name: 'breaching_tickets', type: 'grid', diff --git a/packages/hr/src/dashboards/hr_admin.dashboard.ts b/packages/hr/src/dashboards/hr_admin.dashboard.ts index 44c372f..86e8ca6 100644 --- a/packages/hr/src/dashboards/hr_admin.dashboard.ts +++ b/packages/hr/src/dashboards/hr_admin.dashboard.ts @@ -109,52 +109,10 @@ export const HrAdminDashboard: Dashboard = { filter: { status: { $ne: 'terminated' } }, layout: { x: 0, y: 4, w: 6, h: 4 }, }, - { - id: 'ooo_today', - dataset: 'hr_time_off_request_metrics', - values: ['request_count'], - title: 'Out of Office Today', - type: 'table', - filter: { - status: 'approved', - start_date: { $lte: '{today}' }, - end_date: { $gte: '{today}' }, - }, - layout: { x: 6, y: 4, w: 6, h: 4 }, - options: { - columns: ['employee', 'leave_type', 'start_date', 'end_date'], - pageSize: 10, - sort: [{ field: 'end_date', order: 'asc' }], - }, - }, - { - id: 'pending_time_off_table', - dataset: 'hr_time_off_request_metrics', - values: ['request_count'], - title: 'My Pending Time-Off Requests', - type: 'table', - filter: { status: 'submitted', approver: '{current_user_id}' }, - layout: { x: 0, y: 8, w: 8, h: 5 }, - options: { - columns: ['employee', 'leave_type', 'start_date', 'end_date', 'days', 'submitted_at'], - pageSize: 10, - sort: [{ field: 'start_date', order: 'asc' }], - }, - }, - { - id: 'expiring_docs_table', - dataset: 'hr_document_metrics', - values: ['document_count'], - title: 'Documents Expiring Soon', - type: 'table', - filter: { expires_at: { $gte: '{today}', $lte: '{today+30}' } }, - layout: { x: 8, y: 8, w: 4, h: 5 }, - options: { - columns: ['name', 'employee', 'doc_type', 'expires_at'], - pageSize: 10, - sort: [{ field: 'expires_at', order: 'asc' }], - }, - }, + // Record listings moved to object-bound ListViews (ADR-0017): `ooo_today` + // is the Time-Off "Out Today" tab (out_of_office_today view); `pending_time_off_table` + // is the Time-Off "Pending" tab; `expiring_docs_table` is the Documents + // "Expiring ≤ 30d" tab. KPI widgets above keep the counts here. { id: 'hires_by_month', dataset: 'hr_employee_metrics', diff --git a/packages/hr/src/views/hr_time_off_request.view.ts b/packages/hr/src/views/hr_time_off_request.view.ts index 10b52fb..8a8c21f 100644 --- a/packages/hr/src/views/hr_time_off_request.view.ts +++ b/packages/hr/src/views/hr_time_off_request.view.ts @@ -34,11 +34,28 @@ export const TimeOffRequestViews = defineView({ }, { name: 'pipeline', label: 'Approval Pipeline', icon: 'columns', view: 'time_off_pipeline' }, { name: 'approved', label: 'Approved', icon: 'check', view: 'approved_time_off' }, + { name: 'ooo_today', label: 'Out Today', icon: 'plane', view: 'out_of_office_today' }, { name: 'all', label: 'All', view: 'all_time_off' }, ], }, listViews: { + // Out of office today — surfaces the former `ooo_today` dashboard table as + // an object-bound ListView (ADR-0017): approved leave spanning today. + out_of_office_today: { + name: 'out_of_office_today', + type: 'grid', + label: 'Out of Office Today', + data: { provider: 'object', object: 'hr_time_off_request' }, + columns: ['employee', 'leave_type', 'start_date', 'end_date'], + filter: [ + { field: 'status', operator: 'equals', value: 'approved' }, + { field: 'start_date', operator: 'lte', value: '{today}' }, + { field: 'end_date', operator: 'gte', value: '{today}' }, + ], + sort: [{ field: 'end_date', order: 'asc' }], + }, + time_off_pipeline: { name: 'time_off_pipeline', type: 'kanban', diff --git a/packages/procurement/src/dashboards/spend_at_a_glance.dashboard.ts b/packages/procurement/src/dashboards/spend_at_a_glance.dashboard.ts index 23db451..6e9f30b 100644 --- a/packages/procurement/src/dashboards/spend_at_a_glance.dashboard.ts +++ b/packages/procurement/src/dashboards/spend_at_a_glance.dashboard.ts @@ -80,34 +80,9 @@ export const SpendAtAGlanceDashboard: Dashboard = { layout: { x: 9, y: 0, w: 3, h: 2 }, options: { icon: 'TrendingUp', format: '$0,0' }, }, - { - id: 'pending_requests_table', - dataset: 'procurement_request_metrics', - values: ['request_count'], - title: 'Requests Awaiting Approval', - type: 'table', - filter: { status: 'submitted' }, - layout: { x: 0, y: 2, w: 8, h: 5 }, - options: { - columns: ['title', 'vendor', 'category', 'estimated_amount', 'needed_by'], - pageSize: 10, - sort: [{ field: 'estimated_amount', order: 'desc' }], - }, - }, - { - id: 'open_pos_table', - dataset: 'procurement_order_metrics', - values: ['order_count'], - title: 'Open Purchase Orders', - type: 'table', - filter: { status: { $in: ['sent', 'partial'] } }, - layout: { x: 8, y: 2, w: 4, h: 5 }, - options: { - columns: ['po_number', 'vendor', 'total_amount', 'expected_delivery'], - pageSize: 10, - sort: [{ field: 'expected_delivery', order: 'asc' }], - }, - }, + // Record listings moved to object-bound ListViews (ADR-0017): `pending_requests_table` + // is the Requests "Awaiting Approval" tab; `open_pos_table` is the Orders "Open" tab. + // KPI widgets above keep the counts here. { id: 'po_value_by_month', dataset: 'procurement_order_metrics', diff --git a/packages/todo/src/dashboards/my_work.dashboard.ts b/packages/todo/src/dashboards/my_work.dashboard.ts index fc41479..55941e1 100644 --- a/packages/todo/src/dashboards/my_work.dashboard.ts +++ b/packages/todo/src/dashboards/my_work.dashboard.ts @@ -69,23 +69,8 @@ export const MyWorkDashboard: Dashboard = { layout: { x: 8, y: 0, w: 4, h: 2 }, options: { icon: 'Trophy', format: '0,0' }, }, - { - id: 'recent_overdue_list', - dataset: 'todo_task_metrics', - values: ['task_count'], - title: 'Overdue Tasks', - type: 'table', - filter: { - assignee: '{current_user_id}', - status: { $in: ['todo', 'doing'] }, - due_date: { $lt: '{today}' }, - }, - layout: { x: 0, y: 2, w: 12, h: 4 }, - options: { - columns: ['subject', 'priority', 'labels', 'due_date'], - pageSize: 10, - }, - }, + // Record listing moved to an object-bound ListView (ADR-0017): the former + // `recent_overdue_list` is the Tasks "Overdue" tab (overdue_tasks view). { id: 'throughput_by_week', dataset: 'todo_task_metrics',