Repository navigation
Feature/composed dashs crud and composition - #85
Conversation
Implements basic list, create, read, and delete endpoints for composed dashboards alongside a frontend list page. This provides the foundational API and UI for managing composed dashboards before composition and deployment logic. - Backend: Added composed_dashboards views with pagination (list), single GET, POST create, and DELETE endpoints; all require authentication and order by created_at DESC - Routes: Registered all four endpoints under /global-api/composed-dashboards - Frontend: Added ComposedDashboardService with query/get/create/delete methods - Frontend: Added ComposedDashboardList page reusing main-app list building blocks (ItemsList, ItemsTable, Paginator) for consistency with existing patterns - Frontend: Added /composed-dashboards route to GlobalApplicationArea - Tests: Added comprehensive test coverage for all endpoints, pagination, ordering, 404 handling, and authentication requirements Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Enables creating ordered lists of subdashboards within a composed dashboard. Users can add, remove, and reorder subdashboard entries via a dedicated edit page with inline reordering controls. Backend: - Added entry list/create/delete/reorder endpoints under /global-api/composed-dashboards/<id>/entries - Entry creation auto-assigns order_index, reorder updates indices - GET entries returns array ordered by order_index - All endpoints require authentication Frontend: - Extended composedDashboard service with getEntries, addEntry, removeEntry, reorderEntries methods matching backend API - Added ComposedDashboardEdit page with modal for adding, table for managing, and Up/Down buttons for reordering entries - Modal filters available subdashboards to prevent duplicate entries - Added /composed-dashboards/:id/edit route and "Edit composition" link in the list view Tests: - Tests verify authentication, CRUD operations, order_index management, 404 handling, and cross-dashboard isolation Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Handle unique constraint violation in dashboard creation (return 409 instead of 500) - Fix order_index auto-increment logic for dashboard entries (0 is falsy, was breaking sequence)
berinhard
left a comment
There was a problem hiding this comment.
The code looks good to me, but I feel we are missing input cleansing in the endpoints that receives data.
| page = int(request.args.get("page", 1)) | ||
| page_size = int(request.args.get("page_size", 25)) |
There was a problem hiding this comment.
Blocker
We should avoid 500 errors if the querystring gets build like ?page=str-value. Same for the page_size.
| query = ComposedDashboard.query.order_by(ComposedDashboard.created_at.desc()) | ||
|
|
||
| total = query.count() | ||
| composed_dashboards = query.offset((page - 1) * page_size).limit(page_size).all() |
There was a problem hiding this comment.
Blocker
Considering this page - 1, we should also avoid page values lower or equal to 0.
There was a problem hiding this comment.
Thank you, this is handled also in this commit ee32a4e
| name = body.get("name") | ||
| url_identifier = body.get("url_identifier") | ||
|
|
||
| composed_dashboard = ComposedDashboard(name=name, url_identifier=url_identifier) |
There was a problem hiding this comment.
Blocker
What will happen if the JSON post is something like {"name": "", "url_identifier": ""}? I think we should enforce validation on these both these fields being present to prevent errors of partially configured ComposedDashboard
There was a problem hiding this comment.
name and url_identifier are being required from the frontend side and this is only consumed by the frontend, I understand the worry but would it still be a blocker in that context?
| def composed_dashboard_entry_create(composed_dashboard_id): | ||
| ComposedDashboard.query.get_or_404(composed_dashboard_id) | ||
| body = request.get_json(silent=True) or {} | ||
| template_dashboard_id = body.get("template_dashboard_id") |
There was a problem hiding this comment.
Blocker
Same question about input validation here. What does it happens when this information is in they JSON by with empty/invalid data?
There was a problem hiding this comment.
the value for template_dashboard_id when creating a composed dashboard entry is selected from a dropdown with available valid values and this is only consumed there
| def composed_dashboard_entries_reorder(composed_dashboard_id): | ||
| composed_dashboard = ComposedDashboard.query.get_or_404(composed_dashboard_id) | ||
| body = request.get_json(silent=True) or {} | ||
| entry_ids = body.get("entry_ids", []) |
There was a problem hiding this comment.
Blocker
Same about input validaiton. What if the paylod comes with an entry_ids=42 or even an string, which is valid iterable and will work within the for-loop.
There was a problem hiding this comment.
this value is never directly given by the user , it should always come valid from the frontend
For the validation concerns (name, url_identifier, template_dashboard_id, entry_ids), these are already validated on the frontend and only used by our frontend code. Given that we have a planned Pydantic integration , I think it makes sense to do it at this point I believe. Thank you for your review! |
berinhard
left a comment
There was a problem hiding this comment.
As we have the pydantic related issue, I'm fine on moving the blockers here to become expected part of the work from the issue.
Thank you ! |
Closes https://github.com/metr-systems/backlog/issues/4754
Closes https://github.com/metr-systems/backlog/issues/4755
AI Disclaimer: Assisted by Claude, these PR is mostly crud operations and UI for it, so I generated the code and then reviewed it
Summary
A new feature called that lets you combine multiple sub-dashboards (coming from se template dashboards) into one dashboard and manage them
Coding Strategy
QA