Use manifest names for new services and document release acceptance
Demo images / Build & push demo images (push) Failing after 38s

This commit is contained in:
archipelago
2026-09-30 12:20:29 -04:00
parent 5ab65f7581
commit 439b55a236
6 changed files with 41 additions and 11 deletions
+2 -5
View File
@@ -214,7 +214,7 @@ import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import type { PackageDataEntry } from '@/types/api'
import {
isWebOnlyApp, opensInTab, canLaunch, launchBlockedReason, resolveAppIcon,
isWebOnlyApp, opensInTab, canLaunch, launchBlockedReason, resolveAppIcon, resolveAppTitle,
getStatusClass, getStatusLabel, handleImageError,
} from './appsConfig'
import { getCuratedAppList } from '../discover/curatedApps'
@@ -255,10 +255,7 @@ const isWebOnly = computed(() => isWebOnlyApp(props.id))
// Enrich from marketplace when backend data is sparse (e.g. during install)
const curated = computed(() => curatedMap.get(props.id))
const title = computed(() => {
const t = props.pkg.manifest?.title
return (t && t !== props.id) ? t : (curated.value?.title || t || props.id)
})
const title = computed(() => resolveAppTitle(props.id, props.pkg, curated.value?.title))
const description = computed(() => {
const d = props.pkg.manifest?.description?.short
return (d && d !== 'Installing...') ? d : (curated.value?.description || d || '')
+2 -4
View File
@@ -132,7 +132,7 @@ import type { AppCredential, AppCredentialsResponse, PackageDataEntry } from '@/
import { rpcClient } from '@/api/rpc-client'
import { resolveAppUrl } from '@/views/appSession/appSessionConfig'
import { resolveAppCredentials } from './appCredentials'
import { canLaunch, handleImageError, isWebsitePackage, opensInTab, resolveAppIcon, resolveRuntimeLaunchUrl, WEB_ONLY_APP_URLS } from './appsConfig'
import { canLaunch, handleImageError, isWebsitePackage, opensInTab, resolveAppIcon, resolveAppTitle, resolveRuntimeLaunchUrl, WEB_ONLY_APP_URLS } from './appsConfig'
import { getCuratedAppList } from '../discover/curatedApps'
const ITEMS_PER_PAGE = 16 // 4 columns x 4 rows
@@ -194,9 +194,7 @@ const pages = computed(() => {
})
function getTitle(id: string, pkg: PackageDataEntry): string {
const t = pkg.manifest?.title
if (t && t !== id) return t
return curatedMap.get(id)?.title || t || id
return resolveAppTitle(id, pkg, curatedMap.get(id)?.title)
}
function getIcon(id: string, pkg: PackageDataEntry): string {
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest'
import { ref } from 'vue'
import { PackageState, type PackageDataEntry } from '@/types/api'
import { APP_CATEGORY_MAP, canLaunch, filterEntriesForTab, hasFrontendUi, isServiceContainer, isServicePackage, isWebsitePackage, isAppReadyForLaunch, launchBlockedReason, resolveAppIcon, useCategoriesWithApps, DEFAULT_APP_ICON } from '../appsConfig'
import { APP_CATEGORY_MAP, canLaunch, filterEntriesForTab, hasFrontendUi, isServiceContainer, isServicePackage, isWebsitePackage, isAppReadyForLaunch, launchBlockedReason, resolveAppIcon, resolveAppTitle, useCategoriesWithApps, DEFAULT_APP_ICON } from '../appsConfig'
function makePkg(id: string, title: string, category: string): PackageDataEntry {
return {
@@ -214,3 +214,13 @@ describe('HTTP readiness independent of container health', () => {
expect(isAppReadyForLaunch(pkg)).toBe(true)
})
})
describe('manifest-generated service names', () => {
it('gives a new headless service its declared name without a hardcoded curated entry', () => {
const pkg = makePkg('angor-relay', 'angor-relay', 'money')
expect(resolveAppTitle('angor-relay', pkg)).toBe('Angor Relay')
pkg.manifest.title = 'My project relay'
expect(resolveAppTitle('angor-relay', pkg)).toBe('My project relay')
expect(resolveAppTitle('unknown-service', makePkg('unknown-service', 'unknown-service', ''))).toBe('unknown-service')
})
})
+9
View File
@@ -4,6 +4,7 @@ import type { Ref } from 'vue'
import { computed } from 'vue'
import { PackageState, type PackageDataEntry } from '@/types/api'
import { matchPageScheme, resolveAppUrl } from '../appSession/appSessionConfig'
import { GENERATED_APP_TITLES } from '../appSession/generatedAppSessionConfig'
import { portIsGateFronted } from '../discover/curatedApps'
import { isAutoTabApp } from '@/utils/autoTabApps'
import {
@@ -13,6 +14,14 @@ import {
export type AppsTab = 'apps' | 'websites' | 'services'
/** Use manifest-generated names when a new service has only its ID in runtime state. */
export function resolveAppTitle(id: string, pkg: PackageDataEntry, curatedTitle?: string): string {
const title = pkg.manifest?.title
if (title && title !== id) return title
return curatedTitle || GENERATED_APP_TITLES[id] || title || id
}
// Re-exported for every existing caller — the canon moved to serviceNames.ts
// so the App Store's catalog merge can share it without a circular import.
export const SERVICE_NAMES = SHARED_SERVICE_NAMES