diff --git a/docs/architecture/glances-v5-architecture-decisions.md b/docs/architecture/glances-v5-architecture-decisions.md index 5d8f388b..3204e161 100644 --- a/docs/architecture/glances-v5-architecture-decisions.md +++ b/docs/architecture/glances-v5-architecture-decisions.md @@ -1236,8 +1236,42 @@ curses surface — as its own owned group. No implementation in parity wave 1 cannot avoid** — the TUI shows the path prefix only when `os.path.isdir(path)` holds (`render_curses_v5.py:329`), and a browser has no filesystem, so it shows the prefix whenever `cmdline[0]` carried one. -- **The 9 remaining data-type toggles** (`b`/`B` byte/bit, `%`, `S`, …), plus - `F` (fs free space), moved here from the show/hide line above. +- **The data-type toggles** (2.X-c, 2026-09-22). **Six of the nine shipped**, + on both surfaces, plus `F` (fs free space) which moved here from the + show/hide line above. Three are blocked, and NONE of the three is a hotkey + problem — the key is one table entry either way; what is missing is the + second render mode's DATA. + + Shipped because v5 already rendered both modes, so the key was the whole + feature: `b` (network bit/s ↔ byte/s), `6` (GPU per-card ↔ mean), `F` + (filesystem used ↔ free). + + Shipped after writing the second mode, the data being already collected: + `B` (disk I/O byte/s ↔ IOPS — `read_count`/`write_count` were collected and + `internal`, and now carry the `IOR/s`/`IOW/s` short names v4 uses), `0` + (load average ↔ Irix percentage — `cpucore` was collected and `internal`), + `T` (network Rx/Tx apart ↔ combined). + + `T` carries a deliberate divergence in route, not in value: v4 renders a + `bytes_all` field its model computes; v5's schema has no such field, so both + renderers sum the two rates they already have. The sum of two rates over one + interval is the combined rate. + + **Blocked, each needing model or infrastructure work first:** + - `U` (network live ↔ cumulative) — `_transform_gauge` + (`plugins/plugin/base_v5.py`) REPLACES a counter with its rate and keeps + the raw value only in `_raw_previous`. Exposing it is a field-contract + change to the REST payload, not a renderer change. + - `L` (disk I/O byte/s ↔ latency) — `read_time`/`write_time` are not + collected at all, explicitly deferred (`diskio/model_v5.py`). + - `S` (quicklook bar ↔ sparkline) — no v5 history store + (`quicklook/model_v5.py`). + + `F` needed a shape neither group had used: `[fs] free_space` is plugin + CONFIG and reaches the renderer as payload metadata, so the TUI's ViewState + field is tri-state (`None` = follow the payload) and the browser seeds it + from the fs payload rather than from `serverArgs`, which carries only the + CLI flag and reads `false` for a config-set `true`. - **`F5` / `Ctrl-R`** forced refresh and the sort-navigation arrow keys. The `ViewState` mechanism this group builds on already exists diff --git a/glances/outputs/glances_curses_v5.py b/glances/outputs/glances_curses_v5.py index 59bb8ef7..4ff1cb7d 100644 --- a/glances/outputs/glances_curses_v5.py +++ b/glances/outputs/glances_curses_v5.py @@ -142,6 +142,9 @@ class ViewState: # flipped by their keys. byte: bool = False meangpu: bool = False + diskio_iops: bool = False + load_irix: bool = False + network_sum: bool = False # Tri-state, unlike the two above: `[fs] free_space` lives in the fs # plugin's CONFIG and reaches the renderer as payload metadata, not as a # constructor argument the TUI could seed from. `None` therefore means @@ -236,6 +239,9 @@ class TuiV5(threading.Thread): # through the per-cycle `view` dict. "b": {"switch": "byte", "group": "TOGGLE VIEW", "desc": "Network I/O in bit/s or byte/s"}, "6": {"switch": "meangpu", "group": "TOGGLE VIEW", "desc": "GPU: per-card or mean"}, + "B": {"switch": "diskio_iops", "group": "TOGGLE VIEW", "desc": "Disk I/O in byte/s or IOPS"}, + "0": {"switch": "load_irix", "group": "TOGGLE VIEW", "desc": "Load average or Irix percentage"}, + "T": {"switch": "network_sum", "group": "TOGGLE VIEW", "desc": "Network Rx/Tx apart or combined"}, # Tri-state, so it cannot be a plain `switch`: `None` means "follow # `[fs] free_space`", which is why it has its own verb. "F": {"action": "fs_free_space", "group": "TOGGLE VIEW", "desc": "Filesystem: used or free space"}, @@ -939,6 +945,9 @@ class TuiV5(threading.Thread): view["fahrenheit"] = self._fahrenheit view["hide_public_info"] = self._hide_public_info view["byte"] = self._view.byte + view["diskio_iops"] = self._view.diskio_iops + view["load_irix"] = self._view.load_irix + view["network_sum"] = self._view.network_sum # Only published when the viewer has pressed `F`; absent means the fs # renderer keeps reading its payload metadata. if self._view.fs_free_space is not None: diff --git a/glances/outputs/static/js/v5/PluginDiskio.vue b/glances/outputs/static/js/v5/PluginDiskio.vue index 4236d17e..cf919bd1 100644 --- a/glances/outputs/static/js/v5/PluginDiskio.vue +++ b/glances/outputs/static/js/v5/PluginDiskio.vue @@ -4,7 +4,7 @@