Skip to content

Status page: split sensor data and jobs into tabs - #2470

Open
Ahmad-Wahid wants to merge 9 commits into
mainfrom
issue-2446-status-page-tabs
Open

Status page: split sensor data and jobs into tabs#2470
Ahmad-Wahid wants to merge 9 commits into
mainfrom
issue-2446-status-page-tabs

Conversation

@Ahmad-Wahid

@Ahmad-Wahid Ahmad-Wahid commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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.

  • Split the page into a Jobs tab and a Sensor data tab
  • Each table loads only when its tab is opened, so a page load makes 1 request instead of 1 + one per sensor
  • Jobs is the default tab, and the tab you last opened is remembered in your session (like the graph legend position)
  • Added POST /api/v3_0/assets/status_page_tab to store that preference
  • Added changelog item in documentation/changelog.rst

Look & Feel

Jobs tab:
image

Sensors data tab:
image

...

How to test

  1. Check out this branch and start FlexMeasures.
  2. Open an asset's status page (/assets/<id>/status). It opens on Jobs.
  3. Open your browser's network tab and reload. Only /api/v3_0/assets/<id>/jobs is requested — no /sensors/<id>/status calls.
  4. Click Sensor data. The sensor rows now load, one request per sensor.
  5. Go to another page and come back to the status page. It opens on Sensor data, because that is where you left off.
  6. Switch back and forth between the tabs. Both keep showing their rows, without needing a reload.
  7. Click a row in the Jobs table. It still opens that job.

Automated tests:

pytest flexmeasures/ui/tests/test_asset_crud.py -k status
pytest flexmeasures/api/v3_0/tests/test_assets_api.py -k status_page_tab

They cover which tab opens, that the endpoint stores and validates the preference, and that neither table carries a class by which flexmeasures.js would build it on page load (see below).

Further Improvements

flexmeasures.js builds a DataTable on page load for any table with the paginate or nav-on-click class, the latter via clickableTable(). 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 applies clickableTable() 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

Ahmad-Wahid and others added 8 commits September 3, 2026 11:55
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>
@read-the-docs-community

read-the-docs-community Bot commented Sep 3, 2026

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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_tab to 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" and aria-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") %}
Comment on lines +16 to +23
<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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Status page: Split sensor data from jobs, in tabs

2 participants