Name waiting apps, align card actions, and update Angor icon
Demo images / Build & push demo images (push) Failing after 39s

This commit is contained in:
archipelago
2026-09-30 12:43:53 -04:00
parent d50be13232
commit ef8254272c
11 changed files with 62 additions and 20 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 948 KiB

+2 -2
View File
@@ -658,7 +658,7 @@
],
"category": "money",
"tier": "optional",
"icon": "/assets/img/app-icons/angor.svg",
"icon": "/assets/img/app-icons/angor-green.png",
"repoUrl": "https://github.com/block-core/angor"
},
{
@@ -671,7 +671,7 @@
"requires": [],
"category": "nostr",
"tier": "optional",
"icon": "/assets/img/app-icons/angor.svg",
"icon": "/assets/img/app-icons/angor-green.png",
"repoUrl": "https://github.com/hoytech/strfry"
}
]
+9 -9
View File
@@ -4,7 +4,7 @@
:data-controller-launch="canLaunch(pkg) ? '' : undefined"
tabindex="0"
role="link"
class="glass-card p-6 transition-all hover:-translate-y-1 cursor-pointer relative min-w-0 overflow-hidden"
class="glass-card flex flex-col h-full p-6 transition-all hover:-translate-y-1 cursor-pointer relative min-w-0 overflow-hidden"
:class="{ 'card-stagger': showStagger }"
:style="{ '--stagger-index': index }"
@click="$emit('goToApp', id)"
@@ -56,9 +56,9 @@
{{ description }}
</p>
<div v-if="!isInstalling && !isUninstalling && pkg.state !== 'installing'" class="flex items-center gap-2">
<div v-if="!isInstalling && !isUninstalling && pkg.state !== 'installing'" class="flex items-center gap-2 min-w-0">
<span
class="inline-flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium"
class="shrink-0 inline-flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium"
:class="getStatusClass(pkg.state, pkg.health, pkg['exit-code'])"
>
<svg
@@ -74,14 +74,14 @@
<span v-if="pkg.state === 'running' && pkg.health === 'unhealthy'" class="w-1.5 h-1.5 rounded-full bg-orange-400 animate-pulse"></span>
{{ getStatusLabel(pkg.state, pkg.health, pkg['exit-code']) }}
</span>
<p v-if="blockedReason" :title="blockedReason" class="min-w-0 truncate text-xs leading-snug text-yellow-200/80">
{{ blockedReason }}
</p>
</div>
<p v-if="blockedReason" class="mt-2 text-xs leading-snug text-yellow-200/80">
{{ blockedReason }}
</p>
<!-- Quick Actions — icon buttons in uniform dark containers -->
<!-- Installing progress — replaces action buttons -->
<div v-if="isInstalling || pkg.state === 'installing'" class="mt-4">
<div v-if="isInstalling || pkg.state === 'installing'" class="mt-auto pt-4">
<div class="flex items-center justify-between mb-1.5">
<span class="text-xs text-white/70 flex items-center gap-1.5">
<svg class="animate-spin h-3 w-3" fill="none" viewBox="0 0 24 24">
@@ -101,7 +101,7 @@
</div>
<!-- Uninstalling progress — truthful stage-driven bar (mirrors install) -->
<div v-else-if="isUninstalling" class="mt-4">
<div v-else-if="isUninstalling" class="mt-auto pt-4">
<div class="flex items-center justify-between mb-1.5">
<span class="text-xs text-white/70 flex items-center gap-1.5">
<svg class="animate-spin h-3 w-3" fill="none" viewBox="0 0 24 24">
@@ -120,7 +120,7 @@
</div>
</div>
<div v-else class="mt-4 flex gap-2">
<div v-else class="mt-auto pt-4 flex gap-2">
<!-- Update available -->
<button
v-if="pkg['available-update'] && pkg.state !== 'updating'"
@@ -167,7 +167,7 @@ describe('appsConfig service filtering', () => {
pkg.health = null
expect(isAppReadyForLaunch(pkg)).toBe(false)
expect(canLaunch(pkg)).toBe(false)
expect(launchBlockedReason(pkg.manifest.id, pkg)).toContain('Starting up')
expect(launchBlockedReason(pkg.manifest.id, pkg)).toBe('Waiting for GitWorkshop…')
pkg.health = 'healthy'
expect(canLaunch(pkg)).toBe(true)
})
@@ -202,7 +202,7 @@ describe('HTTP readiness independent of container health', () => {
pkg.health = 'healthy'
expect(canLaunch(pkg)).toBe(false)
expect(isAppReadyForLaunch(pkg)).toBe(false)
expect(launchBlockedReason(id, pkg)).toContain('Waiting')
expect(launchBlockedReason(id, pkg)).toBe(`Waiting for ${resolveAppTitle(id, pkg)}…`)
pkg['ui-ready'] = true
expect(isAppReadyForLaunch(pkg)).toBe(true)
}
@@ -224,3 +224,13 @@ describe('manifest-generated service names', () => {
expect(resolveAppTitle('unknown-service', makePkg('unknown-service', 'unknown-service', ''))).toBe('unknown-service')
})
})
it('does not display a stale Mempool frontend alias beside its live package', () => {
const main = makePkg('mempool', 'Mempool', 'money')
const alias = makePkg('mempool-web', 'Mempool', 'money')
alias.state = PackageState.Restarting
const entries: Array<[string, PackageDataEntry]> = [['mempool', main], ['mempool-web', alias]]
const shown = [...filterEntriesForTab(entries, 'apps', 'all'), ...filterEntriesForTab(entries, 'services', 'all')]
expect(shown.map(([id]) => id)).toEqual(['mempool'])
expect(filterEntriesForTab([['mempool-web', alias]], 'apps', 'all').map(([id]) => id)).toEqual(['mempool-web'])
})
+9 -2
View File
@@ -111,7 +111,12 @@ export function filterEntriesForTab(
activeTab: AppsTab,
selectedCategory: string,
): Array<[string, PackageDataEntry]> {
const hasMempool = entries.some(([id]) => id === 'mempool')
return entries.filter(([id, pkg]) => {
// Older daemons can retain the frontend manifest alias during a restart.
// Keep one tile while the updated scanner converges; a legacy-only node
// must still be able to see and operate its sole Mempool entry.
if (hasMempool && ['mempool-web', 'mempool-frontend', 'archy-mempool-web'].includes(id)) return false
if (isInternalToolingPackage(id, pkg)) return false
const wantsWebsites = activeTab === 'websites' || activeTab === 'services'
const isWebsite = isWebsitePackage(id, pkg)
@@ -231,6 +236,7 @@ function serviceParentIcon(id: string): string | undefined {
export const DEFAULT_APP_ICON = '/assets/icon/favico-black-v2.svg'
export function resolveAppIcon(id: string, pkg: PackageDataEntry, curatedIcon?: string): string {
if (id === 'angor-indexer' || id === 'angor-relay') return '/assets/img/app-icons/angor-green.png'
const rawIcon = (pkg["static-files"]?.icon || "").trim()
const icon = rawIcon === '/assets/img/favico.png' ? '' : rawIcon
if (
@@ -296,9 +302,10 @@ export function isAppReadyForLaunch(pkg: PackageDataEntry): boolean {
export function launchBlockedReason(id: string, pkg?: PackageDataEntry | null): string {
const appId = pkg?.manifest?.id || id
const title = pkg ? resolveAppTitle(appId, pkg) : id
if (pkg?.['ui-ready'] === false && !isServicePackage(appId, pkg)) {
if (pkg.state === PackageState.Stopped || pkg.state === PackageState.Exited) return 'App is stopped. Start it to open it.'
return 'Waiting for the app to be ready…'
return `Waiting for ${title}…`
}
if (
(appId === 'fedimint' || appId === 'fedimintd') &&
@@ -307,7 +314,7 @@ export function launchBlockedReason(id: string, pkg?: PackageDataEntry | null):
return 'Guardian opens a wait page until Bitcoin finishes initial sync.'
}
if (pkg && pkg.state === PackageState.Running && !isAppReadyForLaunch(pkg)) {
return 'Starting up — Launch will appear when the app is ready.'
return `Waiting for ${title}…`
}
return ''
}