Skip to content

Feature/composed dashs crud and composition - #85

Merged
imenattatra merged 7 commits into
metr-mainfrom
feature/composed-dashs-crud-and-composition
Aug 20, 2026
Merged

imenattatra merged 7 commits into
metr-mainfrom
feature/composed-dashs-crud-and-composition

Conversation

@imenattatra

Copy link
Copy Markdown

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

  • You can create a new composed dashboard from the UI
Screenshot 2026-08-18 at 14 59 26
  • You can add sub-dashboards into it from the UI
Screenshot 2026-08-18 at 15 00 09
  • You can remove sub-dashboards from it from the UI
  • You can change the order of the sub-dashboards in a composed dashboard "edit composition" page
Screenshot 2026-08-18 at 15 00 21
  • You can delete a composed dashboard completely
Screenshot 2026-08-18 at 15 00 31

Coding Strategy

  • Started with basic save/read/delete operations for composed dashboards (the CRUD part)
  • Added the ability to manage sub-dashboards inside them: adding, removing, and reordering
  • Followed existing app patterns on the frontend so it looks and feels consistent with other dashboard features
  • Fixed edge cases like preventing duplicate dashboard names and handling auto-increment correctly

QA

imenattatra and others added 6 commits August 18, 2026 14:24
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)
@imenattatra
imenattatra requested review from a team and helenalebreton August 18, 2026 13:04
@imenattatra imenattatra self-assigned this Aug 18, 2026

@berinhard berinhard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good to me, but I feel we are missing input cleansing in the endpoints that receives data.

Comment on lines +21 to +22
page = int(request.args.get("page", 1))
page_size = int(request.args.get("page_size", 25))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker

We should avoid 500 errors if the querystring gets build like ?page=str-value. Same for the page_size.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, please find it updated here ee32a4e

query = ComposedDashboard.query.order_by(ComposedDashboard.created_at.desc())

total = query.count()
composed_dashboards = query.offset((page - 1) * page_size).limit(page_size).all()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker

Considering this page - 1, we should also avoid page values lower or equal to 0.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this is handled also in this commit ee32a4e

Comment on lines +48 to +51
name = body.get("name")
url_identifier = body.get("url_identifier")

composed_dashboard = ComposedDashboard(name=name, url_identifier=url_identifier)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker

Same question about input validation here. What does it happens when this information is in they JSON by with empty/invalid data?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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", [])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this value is never directly given by the user , it should always come valid from the frontend

@imenattatra
imenattatra changed the base branch from feature/composed-dashs-deployment-redeployment to metr-main August 19, 2026 12:15
@imenattatra

imenattatra commented Aug 19, 2026 •

Copy link
Copy Markdown
Author

The code looks good to me, but I feel we are missing input cleansing in the endpoints that receives data.

@berinhard

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.
Would you be open to reconsidering these as blockers? Knowing that it is needed to merge that ASAP because it will make the composed dashboard deployment tests much easier and faster.

Thank you for your review!

@berinhard berinhard left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@imenattatra

Copy link
Copy Markdown
Author

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 !

@imenattatra
imenattatra merged commit 67a24f1 into metr-main Aug 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants