feat(hub): hide standalones not provisioned on this deploy #130

Merged
padreug merged 1 commit from feat/hub-hide-disabled-standalones into dev 2026-06-20 07:28:24 +00:00
Owner

Closes the behavior in #129.

Problem

The hub rendered all 8 standalones statically and greyed out any whose VITE_HUB_<APP>_URL was unset — so an events-only deploy showed 7 dead "coming soon" tiles. The greyed path was overloaded: hubLink() returned null for both "not deployed" and "logged out", so the template couldn't tell them apart.

Approach — registry → resolver → view-model

Rather than special-casing, the hub now resolves an explicit availability state per app:

state meaning render
available provisioned + reachable link
auth-locked provisioned, needs login, logged out greyed, prompts login (unchanged)
inactive provisioned but switched off (active:false) greyed, inert
unavailable not provisioned on this instance hidden
  • availabilityOf(m) is the single resolver (app, env, auth) → state.
  • A tiles computed maps the catalog → view-models and drops unavailable, so the grid only ever renders provisioned apps.
  • auth-locked preserves today's greyed + login-toast behavior for deployed-but-logged-out apps (wallet, chat, tasks, libra).

Forward-compatibility (per the install/remove model discussed)

  • inactive / the optional active flag is wired now as a greyed, inert seam for a future deploy-time "disable a provisioned app" capability — no app sets it yet, no UI/config committed. This is the "greyed-out button" case: the app is enabled on deploy, then marked off.
  • The view treats the catalog as an opaque list, so the source can later move from this in-code array to a runtime feed (an LNbits /hub/apps response or a NIP-78 replaceable event) for Nextcloud-style install/remove — without touching the render path. Resolver and view stay as-is; only where the list comes from changes.

Verification

  • vue-tsc -b build passes.
  • Behavioral note: dev .env sets all VITE_HUB_*_URL, so locally every tile is available and the hide path can't be exercised — it shows on a real partial deploy (e.g. events-only). Logic is a straightforward env-presence + auth check.

Decision taken (open Q in #129)

Went with (a): any app with no live URL ⇒ hidden. Deliberate greyed teasers are now expressed via active:false (the inactive state) rather than an env-less tile, so the two intents stay distinct.

🤖 Generated with Claude Code

Closes the behavior in #129. ## Problem The hub rendered all 8 standalones statically and greyed out any whose `VITE_HUB_<APP>_URL` was unset — so an events-only deploy showed 7 dead "coming soon" tiles. The greyed path was overloaded: `hubLink()` returned `null` for both "not deployed" *and* "logged out", so the template couldn't tell them apart. ## Approach — registry → resolver → view-model Rather than special-casing, the hub now resolves an explicit availability state per app: | state | meaning | render | |---|---|---| | `available` | provisioned + reachable | link | | `auth-locked` | provisioned, needs login, logged out | greyed, prompts login *(unchanged)* | | `inactive` | provisioned but switched off (`active:false`) | greyed, inert | | `unavailable` | not provisioned on this instance | **hidden** | - `availabilityOf(m)` is the single resolver `(app, env, auth) → state`. - A `tiles` computed maps the catalog → view-models and **drops `unavailable`**, so the grid only ever renders provisioned apps. - `auth-locked` preserves today's greyed + login-toast behavior for deployed-but-logged-out apps (wallet, chat, tasks, libra). ## Forward-compatibility (per the install/remove model discussed) - `inactive` / the optional `active` flag is wired now as a greyed, inert seam for a **future deploy-time "disable a provisioned app"** capability — no app sets it yet, no UI/config committed. This is the "greyed-out button" case: the app is enabled on deploy, then marked off. - The view treats the catalog as an **opaque list**, so the source can later move from this in-code array to a **runtime feed** (an LNbits `/hub/apps` response or a NIP-78 replaceable event) for Nextcloud-style install/remove — without touching the render path. Resolver and view stay as-is; only where the list comes from changes. ## Verification - `vue-tsc -b` build passes. - Behavioral note: dev `.env` sets *all* `VITE_HUB_*_URL`, so locally every tile is `available` and the hide path can't be exercised — it shows on a real partial deploy (e.g. events-only). Logic is a straightforward env-presence + auth check. ## Decision taken (open Q in #129) Went with **(a)**: any app with no live URL ⇒ hidden. Deliberate greyed teasers are now expressed via `active:false` (the `inactive` state) rather than an env-less tile, so the two intents stay distinct. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The hub rendered all 8 standalones statically and greyed out any whose
VITE_HUB_<APP>_URL was unset — so an events-only deploy showed 7 dead
"coming soon" tiles. The greyed path was overloaded: hubLink() returned
null for both "not deployed" and "logged out", which the template then
couldn't tell apart.

Replace that with a registry → resolver → view-model pipeline:

- availabilityOf(m) resolves an explicit state from deploy config + auth:
  available | auth-locked | inactive | unavailable.
- A `tiles` computed maps the catalog to view-models and drops
  'unavailable' (not provisioned) entirely — no more ghost tiles.
- 'auth-locked' keeps today's greyed + login-prompt behavior for
  deployed-but-logged-out apps (wallet, chat, tasks, libra).
- 'inactive' (active:false) is wired as a greyed, inert state — an unused
  seam for a future install/disable model; no app sets it yet.

The view treats the catalog as an opaque list, so the source can later
move from this in-code array to a runtime feed (LNbits /hub/apps or a
NIP-78 event) without touching the render path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
padreug deleted branch feat/hub-hide-disabled-standalones 2026-06-20 07:28:24 +00:00
Sign in to join this conversation.
No description provided.