Skip to content

fix(webui): read the ports status as the API sends it, and use the web alert - #3695

Merged
nicolargo merged 1 commit into
nicolargo:developfrom
ntdatt812:fix/webui-ports-status
Aug 29, 2026
Merged

nicolargo merged 1 commit into
nicolargo:developfrom
ntdatt812:fix/webui-ports-status

Conversation

@ntdatt812

Copy link
Copy Markdown
Contributor

plugin-ports.vue disagrees with the ports plugin on two counts. I verified both against a live /api/4/ports response rather than inferring them from the source.

Ground truth

Ran a local server against a closed port and an unreachable URL:

[{"host":"127.0.0.1","port":"1","description":"ClosedPort","status":false,"rtt_warning":null,...},
 {"url":"http://127.0.0.1:1/nope","description":"UnreachableWeb","status":"Error","elapsed":0,"rtt_warning":null,...}]

status is a JSON boolean / number / string. rtt_warning defaults to null. Both bugs fall out of that.

1. URL rows used the port alert; getWebDecoration was dead code

The template called getPortDecoration(port) for both branches. getWebDecoration is defined in the same file and never called.

getPortDecoration compares status against an rtt threshold, but a URL's status is an HTTP code or 'Error':

URL state rtt_warning WebUI showed TUI shows
status: "Error" (unreachable) null (default) ok 🟢 CRITICAL
status: 404 null (default) ok 🟢 CRITICAL
status: 404 1 warning CRITICAL
status: 200 (healthy) 1 warning OK

The default row is the bad one: 200 > 1 and 404 > 1 are both true, but with no threshold configured everything falls through to "ok" — an unreachable URL renders green.

2. The status text compared against strings

<span v-if="port.status == 'null'">Scanning</span>
<span v-else-if="port.status == 'false'">Timeout</span>
<span v-else-if="port.status == 'true'">Open</span>
<span v-else>{{ $filters.number(port.status * 1000.0, 0) }}ms</span>

false == 'false' is 0 == NaN in JavaScript — none of the three branches can ever match. A closed or timed-out port falls through to false * 1000 and renders "0ms", which reads as an instant, perfect response for a port that is down. Scanning renders "0ms" too.

The 'true' branch is dead twice over: _port_scan_tcp / the ping path only ever assign None, a float, or False — never True.

Note the file already knew this: getPortDecoration right below compares === null and === false against the real values. Only the template was written against strings.

The fix

Both branches now mirror the plugin, which is the authority — set_status_if_host, set_status_if_url, get_conds_if_url. The URL branch falls through to the raw status string exactly as set_status_if_url does, instead of special-casing 'Error'.

I checked the severity ordering too, since that is what bit #3690: get_default_ret_value resolves CRITICAL → WARNING → CAREFUL, and getWebDecoration's existing order is equivalent for these mutually-exclusive conditions, so it needed no change — only calling.

Evidence

The WebUI has no JS test runner, so the proof is the rebuilt bundle:

symbol before after
getPortDecoration 3 2
getWebDecoration 1 2
"null" literals 4 2
"false" literals 4 3

3 → 2 and 1 → 2 is definition-plus-two-call-sites becoming definition-plus-one, and definition-only becoming definition-plus-call-site. glances.js 686883 → 686888 bytes; only the component and the bundle changed.

npx eslint on the component: 0 errors. The single vue/require-default-prop warning is on the untouched props block and predates this change.

…b alert

`plugin-ports.vue` disagreed with the ports plugin on two counts. Both were
verified against a live `/api/4/ports` response rather than inferred.

1. URL rows were decorated by `getPortDecoration`. `getWebDecoration` was
   defined in the same file and never called.

   The port form compares `status` against an rtt threshold, but a URL's
   status is an HTTP code or the string 'Error'. With the default
   `rtt_warning: null` every URL therefore fell through to "ok": an
   unreachable URL rendered green while the TUI rendered it CRITICAL. With a
   threshold configured it was still wrong the other way -- `200 > 1` is true,
   so a healthy URL rendered "warning", and a 404 rendered "warning" instead
   of "critical".

2. The status text compared against the strings 'null', 'false' and 'true'.
   The API sends real JSON values. Captured from a running server:

     {"description": "ClosedPort", "status": false, "rtt_warning": null, ...}
     {"description": "UnreachableWeb", "status": "Error", "elapsed": 0, ...}

   `false == 'false'` is `0 == NaN` in JavaScript, so none of the three
   branches could ever match. A closed or timed-out port fell through to
   `false * 1000` and displayed "0ms" -- which reads as an instant, perfect
   response for a port that is down. "Scanning" and "Timeout" never rendered
   at all, and the 'true' branch was doubly dead: the scanner only ever sets
   `status` to None, a float, or False.

Both now mirror the plugin, which is the authority: `set_status_if_host`,
`set_status_if_url` and `get_conds_if_url`. The URL branch falls through to
the raw status string as `set_status_if_url` does, rather than special-casing
'Error'.

Evidence, since the WebUI has no JS test runner -- counted in the rebuilt
bundle:

  getPortDecoration  3 -> 2   (definition + two call sites -> + one)
  getWebDecoration   1 -> 2   (definition only -> definition + call site)
  "null" literals    4 -> 2
  "false" literals   4 -> 3

`npx eslint` on the component: 0 errors (the one `vue/require-default-prop`
warning is on the untouched `props` block and predates this change).
@ntdatt812

Copy link
Copy Markdown
Contributor Author

Reworked per your note on #3699: rebased onto current develop and dropped glances/outputs/static/public/glances.js, so this is now the single .vue source file and nothing generated. The source diff is byte-identical to the one you already saw, and the bundle was the only thing these branches conflicted on.

@nicolargo nicolargo added this to the Glances 4.5.7 milestone Aug 29, 2026
@nicolargo
nicolargo merged commit 278d643 into nicolargo:develop Aug 29, 2026
17 of 19 checks passed
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.

2 participants