From 8c37ff412c20162b7144aa8e5016b98797e83a41 Mon Sep 17 00:00:00 2001 From: archipelago Date: Sun, 13 Sep 2026 03:06:22 -0400 Subject: [PATCH] fix: present Cuprate as one launchable app --- neode-ui/src/views/apps/__tests__/appsConfig.test.ts | 9 ++++----- neode-ui/src/views/apps/appsConfig.ts | 6 +++++- neode-ui/src/views/apps/serviceNames.ts | 6 ++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/neode-ui/src/views/apps/__tests__/appsConfig.test.ts b/neode-ui/src/views/apps/__tests__/appsConfig.test.ts index 52f563b7..c363b68d 100644 --- a/neode-ui/src/views/apps/__tests__/appsConfig.test.ts +++ b/neode-ui/src/views/apps/__tests__/appsConfig.test.ts @@ -78,12 +78,11 @@ describe('appsConfig service filtering', () => { it('shows Cuprate as one My Apps entry while hiding its daemon dependency', () => { const entries: Array<[string, PackageDataEntry]> = [ - ['cuprate-ui', makePkg('cuprate-ui', 'Cuprate UI', 'money')], - ['cuprate', makePkg('cuprate', 'Cuprate daemon', 'money')], + ['cuprate', makePkg('cuprate', 'Cuprate', 'money')], + ['archy-cuprate-ui', makePkg('archy-cuprate-ui', 'Cuprate UI companion', 'money')], ] - ;(entries[0]![1].manifest as unknown as Record).interfaces = { main: { ui: 'http://localhost:18091' } } - expect(filterEntriesForTab(entries, 'apps', 'all').map(([id]) => id)).toEqual(['cuprate-ui']) - expect(filterEntriesForTab(entries, 'services', 'all').map(([id]) => id)).toEqual(['cuprate']) + expect(filterEntriesForTab(entries, 'apps', 'all').map(([id]) => id)).toEqual(['cuprate']) + expect(filterEntriesForTab(entries, 'services', 'all').map(([id]) => id)).toEqual([]) }) it('falls back to packaged app icon when static icon token is not a path', () => { diff --git a/neode-ui/src/views/apps/appsConfig.ts b/neode-ui/src/views/apps/appsConfig.ts index 8a487160..1d2952b0 100644 --- a/neode-ui/src/views/apps/appsConfig.ts +++ b/neode-ui/src/views/apps/appsConfig.ts @@ -20,6 +20,10 @@ export const isServiceContainer = sharedIsServiceContainer const INTERNAL_TOOLING_NAMES = new Set([ 'buildx_buildkit_default', + // Cuprate's dashboard is bundled as a companion of the primary cuprate + // package; showing the generated container as a second Services entry + // defeats the one-app presentation. + 'archy-cuprate-ui', ]) export function isInternalToolingPackage(id: string, pkg?: PackageDataEntry): boolean { @@ -37,7 +41,7 @@ export function isServicePackage(id: string, pkg?: PackageDataEntry): boolean { // Known app -> category mappings (matches App Store categorisation) export const APP_CATEGORY_MAP: Record = { - 'bitcoin-core': 'money', 'bitcoin-knots': 'money', 'bitcoin-ui': 'money', 'cuprate-ui': 'money', 'electrumx': 'money', 'electrs': 'money', + 'bitcoin-core': 'money', 'bitcoin-knots': 'money', 'bitcoin-ui': 'money', 'cuprate': 'money', 'cuprate-ui': 'money', 'electrumx': 'money', 'electrs': 'money', 'lnd': 'money', 'mempool': 'money', 'mempool-web': 'money', 'btcpay-server': 'commerce', 'fedimint': 'money', 'fedimint-gateway': 'money', 'indeedhub': 'media', 'jellyfin': 'media', 'photoprism': 'media', 'immich': 'media', diff --git a/neode-ui/src/views/apps/serviceNames.ts b/neode-ui/src/views/apps/serviceNames.ts index ddb8e489..aba90be8 100644 --- a/neode-ui/src/views/apps/serviceNames.ts +++ b/neode-ui/src/views/apps/serviceNames.ts @@ -14,8 +14,10 @@ // SERVICE_NAMES set that used to live in appsConfig.ts verbatim. export const SERVICE_NAMES = new Set([ 'dwn', 'archy-mempool-db', 'archy-btcpay-db', 'archy-nbxplorer', 'archy-tor', - // Cuprate's daemon is the backend dependency of the Cuprate UI app. - 'cuprate', + // Cuprate is presented as one user-facing app. Its companion container + // (archy-cuprate-ui) is the implementation detail; do not classify the + // primary package as a Service or it disappears from My Apps and loses its + // launch button during/after install. // Headless backends with no user-facing UI: the Fedimint ecash client daemon, // the Nostr relay, and the Meshtastic LoRa daemon (its chat UI lives in the // built-in Mesh tab) belong in Services, not My Apps.