Enhance ISO build process and documentation for Archipelago
- Updated BUILD-GUIDE.md to clarify instructions for building the Archipelago Auto-Installer ISO, emphasizing the recommended method of building directly on the target server. - Added auto-installation of missing dependencies (xorriso, podman) when running the build script with sudo. - Enhanced the build-auto-installer-iso.sh script to capture container images from the live server, ensuring the ISO includes the same set of applications as the dev server. - Revised deployment documentation to stress the importance of building the Rust backend on the Linux dev server and included new instructions for capturing system-level changes for ISO builds. - Improved UI components and added new bundled applications (BTCPay Server, Mempool Explorer, Nostr Relay, Strfry Relay, Tailscale) to enhance user experience.
This commit is contained in:
@@ -79,7 +79,7 @@
|
||||
Launch
|
||||
</button>
|
||||
<button
|
||||
v-if="pkg.state === 'stopped'"
|
||||
v-if="pkg.state === 'stopped' || pkg.state === 'exited'"
|
||||
@click.stop="startApp(id as string)"
|
||||
:disabled="loadingActions[id as string]"
|
||||
class="flex-1 px-4 py-2 bg-green-500/20 border border-green-500/40 rounded-lg text-green-200 text-sm font-medium hover:bg-green-500/30 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
||||
@@ -97,7 +97,7 @@
|
||||
<span>{{ loadingActions[id as string] ? 'Starting...' : 'Start' }}</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="pkg.state === 'running'"
|
||||
v-if="pkg.state === 'running' || pkg.state === 'starting'"
|
||||
@click.stop="stopApp(id as string)"
|
||||
:disabled="loadingActions[id as string]"
|
||||
class="flex-1 px-4 py-2 bg-yellow-500/20 border border-yellow-500/40 rounded-lg text-yellow-200 text-sm font-medium hover:bg-yellow-500/30 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
||||
@@ -202,8 +202,9 @@ function canLaunch(pkg: any): boolean {
|
||||
// For dummy apps, allow launch if running (they have interface addresses)
|
||||
// For real apps, check for UI interface
|
||||
const hasUI = pkg.manifest.interfaces?.main?.ui || pkg.installed?.['interface-addresses']?.main
|
||||
const isRunning = pkg.state === 'running'
|
||||
return hasUI && isRunning
|
||||
// Allow launch when running or starting (so buttons show even while backend reports "starting")
|
||||
const canLaunchState = pkg.state === 'running' || pkg.state === 'starting'
|
||||
return hasUI && canLaunchState
|
||||
}
|
||||
|
||||
function launchApp(id: string) {
|
||||
|
||||
@@ -241,7 +241,7 @@ async function handleRemove() {
|
||||
actionLoading.value = true
|
||||
try {
|
||||
await store.removeContainer(appId.value)
|
||||
router.push('/dashboard/containers')
|
||||
router.push('/dashboard/apps')
|
||||
} catch (e) {
|
||||
error.value = e instanceof Error ? e.message : 'Failed to remove container'
|
||||
} finally {
|
||||
|
||||
@@ -105,6 +105,18 @@
|
||||
<span>{{ store.isAppLoading(app.id) ? 'Starting...' : 'Start' }}</span>
|
||||
</button>
|
||||
|
||||
<!-- Starting (created): show progress, no Launch yet -->
|
||||
<div
|
||||
v-else-if="store.getAppState(app.id) === 'created'"
|
||||
class="flex-1 flex items-center justify-center gap-2 px-4 py-2 text-white/70 text-sm"
|
||||
>
|
||||
<svg class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span>Starting…</span>
|
||||
</div>
|
||||
|
||||
<!-- Running: Stop and Launch buttons -->
|
||||
<template v-else-if="store.getAppState(app.id) === 'running'">
|
||||
<button
|
||||
@@ -183,7 +195,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, computed } from 'vue'
|
||||
import { onMounted, onUnmounted, computed } from 'vue'
|
||||
import { useContainerStore, type BundledApp } from '@/stores/container'
|
||||
import ContainerStatus from '@/components/ContainerStatus.vue'
|
||||
|
||||
@@ -195,15 +207,30 @@ const bundledApps = computed(() => store.enrichedBundledApps)
|
||||
// Get current host for launch URLs
|
||||
const currentHost = computed(() => window.location.hostname)
|
||||
|
||||
let startingPollInterval: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
onMounted(async () => {
|
||||
await store.fetchContainers()
|
||||
await store.fetchHealthStatus()
|
||||
|
||||
|
||||
// Refresh every 10 seconds
|
||||
setInterval(async () => {
|
||||
await store.fetchContainers()
|
||||
await store.fetchHealthStatus()
|
||||
}, 10000)
|
||||
|
||||
// When any bundled app is in 'created' (starting), poll every 2s so state updates to running
|
||||
startingPollInterval = setInterval(async () => {
|
||||
const anyStarting = bundledApps.value.some((app) => store.getAppState(app.id) === 'created')
|
||||
if (anyStarting) {
|
||||
await store.fetchContainers()
|
||||
await store.fetchHealthStatus()
|
||||
}
|
||||
}, 2000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (startingPollInterval) clearInterval(startingPollInterval)
|
||||
})
|
||||
|
||||
// Containers that aren't bundled apps
|
||||
@@ -237,6 +264,8 @@ function getStatusBadgeClass(appId: string): string {
|
||||
case 'stopped':
|
||||
case 'exited':
|
||||
return 'bg-gray-500/20 text-gray-400'
|
||||
case 'created':
|
||||
return 'bg-yellow-500/20 text-yellow-400'
|
||||
case 'not-installed':
|
||||
default:
|
||||
return 'bg-blue-500/20 text-blue-400'
|
||||
@@ -270,17 +299,28 @@ function getStatusText(appId: string): string {
|
||||
return 'Stopped'
|
||||
case 'not-installed':
|
||||
return 'Ready to Start'
|
||||
case 'created':
|
||||
return 'Starting'
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const backendPort = 5678
|
||||
|
||||
function getLaunchUrl(app: BundledApp): string {
|
||||
// Prefer lan_address from backend (for apps with custom UIs)
|
||||
if (app.lan_address) {
|
||||
return app.lan_address
|
||||
// Replace localhost so Launch works when browsing from another machine (e.g. 192.168.1.228)
|
||||
let url = app.lan_address.replace(/localhost/i, currentHost.value)
|
||||
// LND UI (and other app UIs) need backend URL for live data (logs, getinfo proxy)
|
||||
if (app.id === 'lnd') {
|
||||
const backend = `http://${currentHost.value}:${backendPort}`
|
||||
url += (url.includes('?') ? '&' : '?') + 'backend=' + encodeURIComponent(backend)
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
|
||||
// Fallback to first configured port
|
||||
const port = app.ports[0]?.host
|
||||
if (!port) return '#'
|
||||
|
||||
@@ -184,16 +184,6 @@
|
||||
>
|
||||
Not Available
|
||||
</button>
|
||||
<a
|
||||
v-if="app.repoUrl"
|
||||
:href="app.repoUrl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg text-white text-sm font-medium transition-all"
|
||||
@click.stop
|
||||
>
|
||||
GitHub
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -95,18 +95,6 @@
|
||||
</svg>
|
||||
{{ installing ? 'Installing...' : 'Install' }}
|
||||
</button>
|
||||
<a
|
||||
v-if="app.repoUrl"
|
||||
:href="app.repoUrl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="px-4 py-2.5 glass-button rounded-lg text-sm font-medium hover:bg-white/15 transition-colors flex items-center gap-2"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.840 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
||||
Source
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -172,19 +160,6 @@
|
||||
</svg>
|
||||
{{ installing ? 'Installing...' : 'Install' }}
|
||||
</button>
|
||||
<a
|
||||
v-if="app.repoUrl"
|
||||
:href="app.repoUrl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:class="isInstalled ? 'col-span-1' : 'col-span-2'"
|
||||
class="px-4 py-2.5 glass-button rounded-lg text-sm font-medium hover:bg-white/15 transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.840 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
||||
Source
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Installation Error Banner (Mobile) -->
|
||||
@@ -315,24 +290,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Links Card -->
|
||||
<div v-if="app.repoUrl || app.manifestUrl" class="glass-card p-6">
|
||||
<!-- Links Card (no GitHub - repo link removed per product) -->
|
||||
<div v-if="app.manifestUrl" class="glass-card p-6">
|
||||
<h3 class="text-lg font-bold text-white mb-4">Links</h3>
|
||||
<div class="space-y-2">
|
||||
<a
|
||||
v-if="app.repoUrl"
|
||||
:href="app.repoUrl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center gap-2 text-blue-400 hover:text-blue-300 transition-colors"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.840 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
||||
GitHub Repository
|
||||
</a>
|
||||
<a
|
||||
v-if="app.manifestUrl"
|
||||
:href="app.manifestUrl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
Reference in New Issue
Block a user