Status page: split sensor data and jobs into tabs - #2470
Conversation
Context: - Issue #2446: the status page stacks the sensor connectivity table and the jobs table on one page, so every visit pays for both, even though a visitor is usually after one of them. Change: - Put each table in its own tab, and build a table only when its tab is first shown, so the page queries only what it displays. - Open the jobs tab by default, and remember the tab the user last opened in their session, as we do for the preferred graph legend position. - Add POST /api/v3_0/assets/status_page_tab to record that preference. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Context: - Issue #2446 splits the status page into a jobs tab and a sensor data tab, of which only the opened one loads. Change: - Assert that the status page opens the jobs tab by default, and the sensor data tab once the session records that preference. - Assert that the new endpoint stores an accepted tab in the session, and rejects a tab the status page does not have. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Context: - With both tables built up front, the "paginate" class was harmless: the global initializer in flexmeasures.js found them already built and just handed back their API. - Building a table only when its tab opens changed that. At page load the hidden table does not exist yet, so the global initializer created it with default options and no data source. Opening its tab could then no longer initialize it, DataTables refuses to reinitialize, and the swallowed error left an empty table behind until the page was reloaded. Change: - Drop the "paginate" class from both tables, as this page initializes them itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change: - Check that neither status table carries the "paginate" class, which would let flexmeasures.js build the table sitting in the tab that is not open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Context: - Dropping the "paginate" class fixed only one of the two ways flexmeasures.js builds a table on page load. clickableTable(), which it applies to every "nav-on-click" table, initializes the table as its first step. - So the jobs table was still built empty whenever the page opened on the sensor data tab, and opening the jobs tab then found it already built and left it empty until a reload. Change: - Drop the "nav-on-click" class as well, and apply clickableTable() from the jobs table's own initialization instead. Its row handler is delegated, so it keeps working for the rows that arrive later. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change: - Cover the "nav-on-click" class next to "paginate", for each of the two tabs the page can open on, and check the jobs rows stay navigable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Documentation build overview
8 files changed ·
|
There was a problem hiding this comment.
🟡 Changes recommended
The updated status page template needs small but important robustness and accessibility fixes (session value validation and proper ARIA roles/attributes for tabs).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR improves the asset status page UX and performance by splitting the previously stacked “Jobs” and “Sensor data” tables into Bootstrap tabs, and lazily initializing each DataTable only when its tab is shown. It also adds an API endpoint to persist the user’s last-opened tab in their session and updates tests/OpenAPI/changelog accordingly.
Changes:
- Split the status page into Jobs and Sensor data tabs, initializing each table only when first shown.
- Add
POST /api/v3_0/assets/status_page_tabto store the preferred tab in the user session (plus schema + OpenAPI export). - Add UI and API tests, and a main changelog entry for the behavior change.
File summaries
| File | Description |
|---|---|
| flexmeasures/ui/tests/test_asset_crud.py | Adds UI tests asserting the correct default/remembered tab and guarding against eager DataTable auto-init. |
| flexmeasures/ui/templates/sensors/status.html | Implements the tabbed UI, lazy table initialization, and POST to remember the selected tab. |
| flexmeasures/ui/static/openapi-specs.json | Updates generated OpenAPI specs to include the new endpoint and schema. |
| flexmeasures/api/v3_0/tests/test_assets_api.py | Adds API tests verifying the session preference is stored and unknown tabs are rejected. |
| flexmeasures/api/v3_0/assets.py | Adds StatusPageTabJSONSchema and the update_status_page_tab endpoint. |
| flexmeasures/api/v3_0/init.py | Registers the new schema for OpenAPI generation. |
| documentation/changelog.rst | Adds a user-facing changelog entry for the new status page tab behavior. |
Review details
Suppressed comments (1)
flexmeasures/ui/templates/sensors/status.html:49
- This tab pane should be marked up as a tab panel and tied to its corresponding tab for accessibility (e.g.,
role="tabpanel"andaria-labelledby).
<div class="tab-pane fade {{ 'show active' if status_page_tab == 'sensors' }}" id="sensors">
- Files reviewed: 7/7 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| @@ -1,5 +1,6 @@ | |||
| {% extends "base.html" %} | |||
| {% set active_page = "assets" %} | |||
| {% set status_page_tab = session.get("status_page_tab", "jobs") %} | |||
| <ul class="nav nav-tabs" id="statusTabs"> | ||
| <li class="nav-item"> | ||
| <a class="nav-link {{ 'active' if status_page_tab == 'jobs' }}" id="jobs-tab" data-bs-toggle="tab" href="#jobs" data-status-page-tab="jobs">Jobs</a> | ||
| </li> | ||
| <li class="nav-item"> | ||
| <a class="nav-link {{ 'active' if status_page_tab == 'sensors' }}" id="sensors-tab" data-bs-toggle="tab" href="#sensors" data-status-page-tab="sensors">Sensor data</a> | ||
| </li> | ||
| </ul> |
| <div class="tab-content pt-3"> | ||
|
|
||
| <!-- JOBS TABLE --> | ||
| <div class="tab-pane fade {{ 'show active' if status_page_tab == 'jobs' }}" id="jobs"> |
…e-tabs # Conflicts: # documentation/changelog.rst
Description
The status page showed the sensor connectivity table and the jobs table stacked on one page, so every visit loaded both, even though you normally only want one of them.
1 + one per sensorPOST /api/v3_0/assets/status_page_tabto store that preferencedocumentation/changelog.rstLook & Feel
Jobs tab:

Sensors data tab:

...
How to test
/assets/<id>/status). It opens on Jobs./api/v3_0/assets/<id>/jobsis requested — no/sensors/<id>/statuscalls.Automated tests:
They cover which tab opens, that the endpoint stores and validates the preference, and that neither table carries a class by which
flexmeasures.jswould build it on page load (see below).Further Improvements
flexmeasures.jsbuilds a DataTable on page load for any table with thepaginateornav-on-clickclass, the latter viaclickableTable(). That is fine for tables that are visible right away, but it silently claims a table that a page wants to build itself later, leaving it empty. This PR just keeps the two status tables out of those classes and appliesclickableTable()itself. Other pages that load tables lazily will hit the same trap, so it may be worth making those helpers skip tables that are not visible yet.Related Items
Closes #2446