fix: route installs to apps or services
Demo images / Build & push demo images (push) Successful in 3m39s
Demo images / Build & push demo images (push) Successful in 3m39s
This commit is contained in:
@@ -365,6 +365,7 @@ import AppGrid from './discover/AppGrid.vue'
|
|||||||
import InstallVersionModal from '@/components/InstallVersionModal.vue'
|
import InstallVersionModal from '@/components/InstallVersionModal.vue'
|
||||||
import type { MarketplaceApp, FeaturedApp } from './discover/types'
|
import type { MarketplaceApp, FeaturedApp } from './discover/types'
|
||||||
import { getCuratedAppList, INSTALLED_ALIASES, FEATURED_DEFINITIONS, categorizeCommunityApp, fetchAppCatalog, type CatalogFeatured, type CatalogStorefront } from './discover/curatedApps'
|
import { getCuratedAppList, INSTALLED_ALIASES, FEATURED_DEFINITIONS, categorizeCommunityApp, fetchAppCatalog, type CatalogFeatured, type CatalogStorefront } from './discover/curatedApps'
|
||||||
|
import { isServiceContainer } from './apps/serviceNames'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const store = useAppStore()
|
const store = useAppStore()
|
||||||
@@ -733,6 +734,16 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
|
function installToast(app: MarketplaceApp) {
|
||||||
|
const service = isServiceContainer(app.id)
|
||||||
|
const destination = service ? 'Services' : 'My Apps'
|
||||||
|
toast.action(
|
||||||
|
`Installing ${app.title ?? app.id} — it will appear in ${destination}`,
|
||||||
|
{ label: `View ${destination}`, onClick: () => router.push({ path: '/dashboard/apps', query: service ? { tab: 'services' } : {} }) },
|
||||||
|
{ variant: 'info', duration: 15000 },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function installBlockedReason(appId: string): string | undefined {
|
function installBlockedReason(appId: string): string | undefined {
|
||||||
if (!bitcoinPruned.value) return undefined
|
if (!bitcoinPruned.value) return undefined
|
||||||
if (appId !== 'electrumx' && appId !== 'electrs' && appId !== 'mempool-electrs') return undefined
|
if (appId !== 'electrumx' && appId !== 'electrs' && appId !== 'mempool-electrs') return undefined
|
||||||
@@ -766,8 +777,7 @@ function failInstall(app: MarketplaceApp, err: unknown) {
|
|||||||
async function installApp(app: MarketplaceApp, versionOverride?: string) {
|
async function installApp(app: MarketplaceApp, versionOverride?: string) {
|
||||||
if (installingApps.has(app.id) || isInstalled(app.id)) return
|
if (installingApps.has(app.id) || isInstalled(app.id)) return
|
||||||
queueInstall(app)
|
queueInstall(app)
|
||||||
toast.info("Installing " + (app.title ?? app.id) + " - check My Apps")
|
installToast(app)
|
||||||
router.push('/dashboard/apps').catch(() => {})
|
|
||||||
try {
|
try {
|
||||||
const installUrl = app.url || app.manifestUrl || app.s9pkUrl
|
const installUrl = app.url || app.manifestUrl || app.s9pkUrl
|
||||||
await rpcClient.call({ method: 'package.install', params: { id: app.id, url: installUrl, version: versionOverride || app.version }, timeout: 600000 })
|
await rpcClient.call({ method: 'package.install', params: { id: app.id, url: installUrl, version: versionOverride || app.version }, timeout: 600000 })
|
||||||
@@ -780,8 +790,7 @@ async function installApp(app: MarketplaceApp, versionOverride?: string) {
|
|||||||
async function installCommunityApp(app: MarketplaceApp, versionOverride?: string) {
|
async function installCommunityApp(app: MarketplaceApp, versionOverride?: string) {
|
||||||
if (installingApps.has(app.id) || isInstalled(app.id) || !app.dockerImage) return
|
if (installingApps.has(app.id) || isInstalled(app.id) || !app.dockerImage) return
|
||||||
queueInstall(app)
|
queueInstall(app)
|
||||||
toast.info("Installing " + (app.title ?? app.id) + " - check My Apps")
|
installToast(app)
|
||||||
router.push('/dashboard/apps').catch(() => {})
|
|
||||||
try {
|
try {
|
||||||
const installParams: Record<string, unknown> = { id: app.id, dockerImage: app.dockerImage, version: versionOverride || app.version }
|
const installParams: Record<string, unknown> = { id: app.id, dockerImage: app.dockerImage, version: versionOverride || app.version }
|
||||||
if ((app as Record<string, unknown>).containerConfig) {
|
if ((app as Record<string, unknown>).containerConfig) {
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ import {
|
|||||||
getCuratedAppList,
|
getCuratedAppList,
|
||||||
} from './marketplace/marketplaceData'
|
} from './marketplace/marketplaceData'
|
||||||
import { fetchAppCatalog } from './discover/curatedApps'
|
import { fetchAppCatalog } from './discover/curatedApps'
|
||||||
|
import { isServiceContainer } from './apps/serviceNames'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -207,6 +208,17 @@ const appStoreSections = computed(() => APP_STORE_SECTIONS)
|
|||||||
const installingApps = server.installingApps
|
const installingApps = server.installingApps
|
||||||
const electrumxArchiveWarning = 'You need a full archival bitcoin node before downloading ElectrumX'
|
const electrumxArchiveWarning = 'You need a full archival bitcoin node before downloading ElectrumX'
|
||||||
|
|
||||||
|
function installToast(app: MarketplaceApp) {
|
||||||
|
const service = isServiceContainer(app.id)
|
||||||
|
const tab = service ? 'services' : 'apps'
|
||||||
|
const destination = service ? 'Services' : 'My Apps'
|
||||||
|
toast.action(
|
||||||
|
`Installing ${app.title ?? app.id} — it will appear in ${destination}`,
|
||||||
|
{ label: `View ${destination}`, onClick: () => router.push({ path: '/dashboard/apps', query: service ? { tab } : {} }) },
|
||||||
|
{ variant: 'info', duration: 15000 },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Install progress tracking is now in serverStore (global watcher on WebSocket data)
|
// Install progress tracking is now in serverStore (global watcher on WebSocket data)
|
||||||
// so it works regardless of which page is active
|
// so it works regardless of which page is active
|
||||||
|
|
||||||
@@ -518,7 +530,7 @@ async function installApp(app: MarketplaceApp) {
|
|||||||
// Stay on the store page: the tile itself shows install progress via the
|
// Stay on the store page: the tile itself shows install progress via the
|
||||||
// global watcher, and a forced jump to My Apps yanked the user out of the
|
// global watcher, and a forced jump to My Apps yanked the user out of the
|
||||||
// page they were deliberately browsing.
|
// page they were deliberately browsing.
|
||||||
toast.info("Installing " + (app.title ?? app.id) + " — it will appear in My Apps")
|
installToast(app)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const installUrl = app.url || app.manifestUrl || app.s9pkUrl
|
const installUrl = app.url || app.manifestUrl || app.s9pkUrl
|
||||||
@@ -543,7 +555,7 @@ async function installCommunityApp(app: MarketplaceApp) {
|
|||||||
|
|
||||||
queueInstall(app)
|
queueInstall(app)
|
||||||
// Stay on the store page (see installApp).
|
// Stay on the store page (see installApp).
|
||||||
toast.info("Installing " + (app.title ?? app.id) + " — it will appear in My Apps")
|
installToast(app)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const installParams: Record<string, unknown> = { id: app.id, dockerImage: app.dockerImage, version: app.version }
|
const installParams: Record<string, unknown> = { id: app.id, dockerImage: app.dockerImage, version: app.version }
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export function isServicePackage(id: string, pkg?: PackageDataEntry): boolean {
|
|||||||
|
|
||||||
// Known app -> category mappings (matches App Store categorisation)
|
// Known app -> category mappings (matches App Store categorisation)
|
||||||
export const APP_CATEGORY_MAP: Record<string, string> = {
|
export const APP_CATEGORY_MAP: Record<string, string> = {
|
||||||
'bitcoin-core': 'money', 'bitcoin-knots': 'money', 'bitcoin-ui': 'money', 'electrumx': 'money', 'electrs': 'money',
|
'bitcoin-core': 'money', 'bitcoin-knots': 'money', 'bitcoin-ui': 'money', 'cuprate-ui': 'money', 'electrumx': 'money', 'electrs': 'money',
|
||||||
'lnd': 'money', 'mempool': 'money', 'mempool-web': 'money', 'btcpay-server': 'commerce',
|
'lnd': 'money', 'mempool': 'money', 'mempool-web': 'money', 'btcpay-server': 'commerce',
|
||||||
'fedimint': 'money', 'fedimint-gateway': 'money',
|
'fedimint': 'money', 'fedimint-gateway': 'money',
|
||||||
'indeedhub': 'media', 'jellyfin': 'media', 'photoprism': 'media', 'immich': 'media',
|
'indeedhub': 'media', 'jellyfin': 'media', 'photoprism': 'media', 'immich': 'media',
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
// SERVICE_NAMES set that used to live in appsConfig.ts verbatim.
|
// SERVICE_NAMES set that used to live in appsConfig.ts verbatim.
|
||||||
export const SERVICE_NAMES = new Set([
|
export const SERVICE_NAMES = new Set([
|
||||||
'dwn', 'archy-mempool-db', 'archy-btcpay-db', 'archy-nbxplorer', 'archy-tor',
|
'dwn', 'archy-mempool-db', 'archy-btcpay-db', 'archy-nbxplorer', 'archy-tor',
|
||||||
|
// Cuprate's daemon is the backend dependency of the Cuprate UI app.
|
||||||
|
'cuprate',
|
||||||
// Headless backends with no user-facing UI: the Fedimint ecash client daemon,
|
// 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
|
// the Nostr relay, and the Meshtastic LoRa daemon (its chat UI lives in the
|
||||||
// built-in Mesh tab) belong in Services, not My Apps.
|
// built-in Mesh tab) belong in Services, not My Apps.
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ export function getCuratedAppList(): MarketplaceApp[] {
|
|||||||
// Supporting containers (DBs, caches, workers) do NOT — having only a DB
|
// Supporting containers (DBs, caches, workers) do NOT — having only a DB
|
||||||
// without the main app should not mark the app as installed in the UI.
|
// without the main app should not mark the app as installed in the UI.
|
||||||
export const INSTALLED_ALIASES: Record<string, string[]> = {
|
export const INSTALLED_ALIASES: Record<string, string[]> = {
|
||||||
|
'cuprate-ui': ['cuprate-ui', 'cuprate'],
|
||||||
mempool: ['mempool', 'mempool-web', 'archy-mempool-web'],
|
mempool: ['mempool', 'mempool-web', 'archy-mempool-web'],
|
||||||
bitcoin: ['bitcoin-knots'],
|
bitcoin: ['bitcoin-knots'],
|
||||||
btcpay: ['btcpay-server'],
|
btcpay: ['btcpay-server'],
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ const REGISTRY = 'source.archipelago-foundation.org/lfg2025'
|
|||||||
|
|
||||||
/** Marketplace app ID -> backend package keys (for "Already Installed" when first-boot/deploy created them) */
|
/** Marketplace app ID -> backend package keys (for "Already Installed" when first-boot/deploy created them) */
|
||||||
export const INSTALLED_ALIASES: Record<string, string[]> = {
|
export const INSTALLED_ALIASES: Record<string, string[]> = {
|
||||||
|
'cuprate-ui': ['cuprate-ui', 'cuprate'],
|
||||||
mempool: ['mempool-web', 'mempool-api', 'archy-mempool-web', 'archy-mempool-db'],
|
mempool: ['mempool-web', 'mempool-api', 'archy-mempool-web', 'archy-mempool-db'],
|
||||||
bitcoin: ['bitcoin-knots'],
|
bitcoin: ['bitcoin-knots'],
|
||||||
btcpay: ['btcpay-server', 'archy-btcpay-db', 'archy-nbxplorer'],
|
btcpay: ['btcpay-server', 'archy-btcpay-db', 'archy-nbxplorer'],
|
||||||
|
|||||||
Reference in New Issue
Block a user