Skip to content

fix(views): guard server info before dereferencing in templates - #933

Open
TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/server-info-null-guard
Open

fix(views): guard server info before dereferencing in templates#933
TimeToBuildBob wants to merge 1 commit into
ActivityWatch:masterfrom
TimeToBuildBob:fix/server-info-null-guard

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Problem

useServerStore starts with info: null and is only populated from App.vue's
mounted hook — which runs after the first child render. Two templates
dereferenced info unguarded, so a cold load of either view throws:

TypeError: null is not an object (evaluating 't.info.version')

It renders as a red error banner over an otherwise perfectly working install.

Worse, when the server is unreachable the crash is permanent, not a
first-paint race: getInfo() catches the connection error and leaves info
null forever, so the banner never clears.

Sites

File Expression Status
src/views/Home.vue:74 !info.version.includes('rust') fixed
src/views/Buckets.vue:20 serverStore.info.hostname == device.hostname fixed
src/components/Footer.vue:12,15 info.hostname / info.version already safe — ancestor v-if="info"
src/stores/buckets.ts:44,187 serverStore.info && ... already safe

Regression test

test/unit/serverInfoGuard.test.js walks the pug template tree by indentation
and rejects any info.* dereference not covered by a guard on itself or an
ancestor. The indentation-awareness matters: a naive per-line check would
false-positive on Footer.vue, whose guard sits on the wrapping span. Covered
both ways — an ancestor guard passes, a sibling after a closed guard block
does not.

Verified against the pre-fix files from master: the detector flags both
offending lines and reports Footer clean, then reports all three clean after the
fix.

Verification

  • npx jest --selectProjects jsdom — 14 suites, 69 tests pass
  • make lint clean on the changed files

Origin

Found while triaging a participant's test report on the ActivityWatch Research
Edition build (v0.14.0b3-research). The install was working correctly and the
privacy filter was doing its job, but the banner made it look broken.

useServerStore starts with `info: null` and is only populated from App.vue's
`mounted` hook, which runs after the first child render. Two templates
dereferenced `info` unguarded, so a cold load of either view threw:

    TypeError: null is not an object (evaluating 't.info.version')

surfacing as a red error banner over an otherwise working install. When the
server is unreachable the crash is permanent, not transient: getInfo() catches
the connection error and leaves `info` null forever.

- Home.vue: `!info.version.includes('rust')` -> guard `info` first
- Buckets.vue: `serverStore.info.hostname == device.hostname` -> same

Footer.vue was already safe via an ancestor `v-if="info"`.

Adds a pug-indentation-aware regression test that walks the template tree and
rejects any `info.*` dereference not covered by a guard on itself or an
ancestor, so an ancestor `v-if="info"` (Footer's pattern) still passes while a
sibling after a closed guard block does not.

Reported against the ActivityWatch Research Edition build (v0.14.0b3-research),
where a participant read the banner as "ActivityWatch isn't working".
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 42.53%. Comparing base (7db0598) to head (2f19aa1).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #933   +/-   ##
=======================================
  Coverage   42.53%   42.53%           
=======================================
  Files          44       44           
  Lines        2417     2417           
  Branches      519      519           
=======================================
  Hits         1028     1028           
  Misses       1368     1368           
  Partials       21       21           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps

greptile-apps Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds null guards around server-info dereferences so Home and Buckets render safely before server metadata loads or when the server remains unavailable.

  • Guards the Home API-browser version check.
  • Guards the Buckets “this device” hostname comparison.
  • Adds an indentation-aware regression test for guarded Pug template dereferences.

Confidence Score: 5/5

The PR appears safe to merge, with both affected template dereferences guarded and focused regression coverage added.

The new short-circuit conditions prevent null server metadata from reaching either property access without changing behavior once metadata is available.

Important Files Changed

Filename Overview
src/views/Home.vue Correctly short-circuits the version check while server info is null.
src/views/Buckets.vue Correctly guards the hostname comparison while preserving the badge behavior after metadata loads.
test/unit/serverInfoGuard.test.js Adds focused regression coverage for inline, ancestor, and closed-sibling guard behavior.

Reviews (1): Last reviewed commit: "fix(views): guard server info before der..." | Re-trigger Greptile

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

CI-green and mergeable (Greptile 5/5) — waiting only on a maintainer click.

This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted.

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.

1 participant