Use manifest names for new services and document release acceptance
Demo images / Build & push demo images (push) Failing after 38s
Demo images / Build & push demo images (push) Failing after 38s
This commit is contained in:
@@ -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 || '')
|
||||
|
||||
@@ -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')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user