2026-01-24 22:59:20 +00:00
|
|
|
<template>
|
|
|
|
|
<div class="pb-6">
|
2026-03-22 03:30:21 +00:00
|
|
|
<!-- Nav header -- tabs + categories + search -->
|
2026-03-18 22:22:39 +00:00
|
|
|
<div class="mb-4">
|
|
|
|
|
<!-- Desktop: page tabs + category tabs + search -->
|
|
|
|
|
<div class="hidden md:flex items-center gap-4">
|
|
|
|
|
<div class="mode-switcher flex-shrink-0">
|
|
|
|
|
<button class="mode-switcher-btn" :class="{ 'mode-switcher-btn-active': activeTab === 'apps' }" @click="activeTab = 'apps'; router.replace({ query: {} })">My Apps</button>
|
2026-03-19 16:12:01 +00:00
|
|
|
<RouterLink to="/dashboard/discover" class="mode-switcher-btn">App Store</RouterLink>
|
2026-03-18 22:22:39 +00:00
|
|
|
<button class="mode-switcher-btn" :class="{ 'mode-switcher-btn-active': activeTab === 'services' }" @click="activeTab = 'services'; router.replace({ query: { tab: 'services' } })">Services</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="activeTab === 'apps' && categoriesWithApps.length > 1" class="mode-switcher flex-shrink-0">
|
|
|
|
|
<button
|
|
|
|
|
v-for="category in categoriesWithApps"
|
|
|
|
|
:key="category.id"
|
|
|
|
|
@click="selectedCategory = category.id"
|
|
|
|
|
class="mode-switcher-btn"
|
|
|
|
|
:class="{ 'mode-switcher-btn-active': selectedCategory === category.id }"
|
|
|
|
|
>{{ category.name }}</button>
|
|
|
|
|
</div>
|
|
|
|
|
<input
|
|
|
|
|
v-model="searchQuery"
|
|
|
|
|
type="text"
|
|
|
|
|
:placeholder="t('apps.searchPlaceholder')"
|
|
|
|
|
:aria-label="t('apps.searchLabel')"
|
|
|
|
|
class="flex-1 px-4 py-2 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-white/40 transition-colors"
|
|
|
|
|
/>
|
2026-03-17 02:23:30 +00:00
|
|
|
</div>
|
2026-01-24 22:59:20 +00:00
|
|
|
|
2026-03-18 22:22:39 +00:00
|
|
|
<!-- Mobile: search only (tabs handled by Dashboard.vue header) -->
|
|
|
|
|
<div class="md:hidden">
|
|
|
|
|
<input
|
|
|
|
|
v-model="searchQuery"
|
|
|
|
|
type="text"
|
|
|
|
|
:placeholder="t('apps.searchPlaceholder')"
|
|
|
|
|
:aria-label="t('apps.searchLabel')"
|
|
|
|
|
class="w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-white/40 transition-colors"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-03-05 08:06:07 +00:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-11 17:33:42 +00:00
|
|
|
<!-- Loading Skeleton -->
|
2026-05-06 09:23:57 -04:00
|
|
|
<div v-if="isLoadingApps" class="text-center py-16 pb-6">
|
|
|
|
|
<div class="glass-card p-8 max-w-md mx-auto">
|
|
|
|
|
<svg class="animate-spin h-8 w-8 mx-auto mb-4 text-white/70" viewBox="0 0 24 24" fill="none">
|
|
|
|
|
<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>
|
|
|
|
|
<h3 class="text-lg font-semibold text-white mb-2">Loading apps</h3>
|
|
|
|
|
<p class="text-white/60 text-sm">Checking the latest app status before showing launch controls.</p>
|
2026-03-11 17:33:42 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
<!-- Connection Error -->
|
|
|
|
|
<div v-else-if="connectionError && sortedPackageEntries.length === 0" class="text-center py-12 pb-6">
|
|
|
|
|
<div class="glass-card p-8 max-w-md mx-auto">
|
|
|
|
|
<div class="alert-error mb-4">{{ connectionError }}</div>
|
|
|
|
|
<button
|
|
|
|
|
@click="connectionError = ''; store.connectWebSocket()"
|
|
|
|
|
class="glass-button px-6 py-3 rounded-lg font-medium"
|
|
|
|
|
>
|
|
|
|
|
Retry Connection
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-11 13:04:31 +00:00
|
|
|
<!-- Empty State -->
|
2026-03-11 17:33:42 +00:00
|
|
|
<div v-else-if="sortedPackageEntries.length === 0 && !searchQuery" class="text-center py-16 pb-6">
|
2026-01-24 22:59:20 +00:00
|
|
|
<div class="glass-card p-12 max-w-md mx-auto">
|
|
|
|
|
<svg class="w-16 h-16 mx-auto text-white/40 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" />
|
|
|
|
|
</svg>
|
2026-03-11 13:45:59 +00:00
|
|
|
<h3 class="text-xl font-semibold text-white mb-2">{{ t('apps.noAppsTitle') }}</h3>
|
|
|
|
|
<p class="text-white/70 mb-6">{{ t('apps.noAppsMessage') }}</p>
|
2026-01-24 22:59:20 +00:00
|
|
|
<RouterLink
|
|
|
|
|
to="/dashboard/marketplace"
|
|
|
|
|
class="inline-block glass-button px-6 py-3 rounded-lg font-medium transition-all hover:bg-black/70 hover:border-white/30"
|
|
|
|
|
>
|
2026-03-11 13:45:59 +00:00
|
|
|
{{ t('apps.browseAppStore') }}
|
2026-01-24 22:59:20 +00:00
|
|
|
</RouterLink>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-03-05 08:06:07 +00:00
|
|
|
<!-- No Results -->
|
|
|
|
|
<div v-if="filteredPackageEntries.length === 0 && searchQuery" class="text-center py-12">
|
2026-03-11 13:45:59 +00:00
|
|
|
<p class="text-white/70">{{ t('apps.noResults', { query: searchQuery }) }}</p>
|
2026-03-05 08:06:07 +00:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-30 21:03:00 +01:00
|
|
|
<!-- Mobile: iPhone-style icon grid -->
|
|
|
|
|
<div class="md:hidden">
|
|
|
|
|
<AppIconGrid
|
|
|
|
|
:apps="filteredPackageEntries as [string, PackageDataEntry][]"
|
|
|
|
|
@go-to-app="goToApp"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Desktop: Card grid -->
|
|
|
|
|
<div class="hidden md:grid grid-cols-2 lg:grid-cols-3 gap-4 pb-6">
|
2026-03-22 03:30:21 +00:00
|
|
|
<AppCard
|
2026-03-09 07:43:12 +00:00
|
|
|
v-for="([id, pkg], index) in filteredPackageEntries"
|
2026-01-24 22:59:20 +00:00
|
|
|
:key="id"
|
2026-03-22 03:30:21 +00:00
|
|
|
:id="id as string"
|
|
|
|
|
:pkg="pkg"
|
|
|
|
|
:index="index"
|
|
|
|
|
:show-stagger="showStagger"
|
|
|
|
|
:is-loading="!!actions.loadingActions.value[id as string]"
|
2026-03-29 00:13:39 +00:00
|
|
|
:is-installing="serverStore.isInstalling(id as string)"
|
|
|
|
|
:install-progress="serverStore.installingApps.get(id as string)"
|
2026-03-31 21:00:01 +01:00
|
|
|
:is-uninstalling="actions.uninstallingApps.has(id as string)"
|
2026-03-22 03:30:21 +00:00
|
|
|
@go-to-app="goToApp"
|
|
|
|
|
@launch="launchApp"
|
|
|
|
|
@start="actions.startApp"
|
|
|
|
|
@stop="actions.stopApp"
|
|
|
|
|
@restart="actions.restartApp"
|
2026-04-22 08:29:56 -04:00
|
|
|
@update="updateApp"
|
2026-03-22 03:30:21 +00:00
|
|
|
@show-uninstall="showUninstallModal"
|
|
|
|
|
/>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
<AppsUninstallModal
|
|
|
|
|
:show="uninstallModal.show"
|
|
|
|
|
:app-title="uninstallModal.appTitle"
|
|
|
|
|
:uninstalling="actions.uninstalling.value"
|
|
|
|
|
@close="closeUninstallModal"
|
|
|
|
|
@confirm="onConfirmUninstall"
|
|
|
|
|
/>
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
|
2026-03-11 13:04:31 +00:00
|
|
|
<!-- Action error toast -->
|
|
|
|
|
<Transition name="fade">
|
2026-03-22 03:30:21 +00:00
|
|
|
<div v-if="actions.actionError.value" class="fixed bottom-20 left-1/2 -translate-x-1/2 z-50 max-w-md w-full px-4" role="alert" aria-live="assertive">
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
<div class="alert-error backdrop-blur-sm rounded-lg px-4 py-3 text-sm flex items-center justify-between gap-3">
|
2026-03-22 03:30:21 +00:00
|
|
|
<span>{{ actions.actionError.value }}</span>
|
|
|
|
|
<button @click="actions.actionError.value = ''" :aria-label="t('apps.dismissError')" class="text-red-300 hover:text-white shrink-0">×</button>
|
2026-03-11 13:04:31 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Transition>
|
2026-01-24 22:59:20 +00:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
2026-03-19 16:12:01 +00:00
|
|
|
<script lang="ts">
|
2026-03-22 03:30:21 +00:00
|
|
|
// Module-level -- persists across component unmount/remount within same session
|
2026-03-19 16:12:01 +00:00
|
|
|
let appsAnimationDone = false
|
|
|
|
|
</script>
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
<script setup lang="ts">
|
2026-03-21 03:01:38 +00:00
|
|
|
import { computed, ref, watch, onMounted, onBeforeUnmount } from 'vue'
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
import { useRouter, useRoute, RouterLink } from 'vue-router'
|
2026-03-11 13:45:59 +00:00
|
|
|
import { useI18n } from 'vue-i18n'
|
2026-03-22 03:30:21 +00:00
|
|
|
import { useAppStore } from '@/stores/app'
|
2026-03-29 00:13:39 +00:00
|
|
|
import { useServerStore } from '@/stores/server'
|
2026-03-22 03:30:21 +00:00
|
|
|
import { useAppLauncherStore } from '@/stores/appLauncher'
|
2026-04-07 19:44:00 +01:00
|
|
|
import { type PackageDataEntry, type PackageState } from '@/types/api'
|
2026-03-22 03:30:21 +00:00
|
|
|
import AppCard from './apps/AppCard.vue'
|
2026-03-30 21:03:00 +01:00
|
|
|
import AppIconGrid from './apps/AppIconGrid.vue'
|
2026-03-22 03:30:21 +00:00
|
|
|
import AppsUninstallModal from './apps/AppsUninstallModal.vue'
|
|
|
|
|
import { useAppsActions } from './apps/useAppsActions'
|
|
|
|
|
import {
|
2026-04-28 15:00:58 -04:00
|
|
|
filterEntriesForTab, isWebOnlyApp,
|
2026-03-22 03:30:21 +00:00
|
|
|
WEB_ONLY_APPS, buildAllCategories, useCategoriesWithApps,
|
|
|
|
|
} from './apps/appsConfig'
|
2026-01-24 22:59:20 +00:00
|
|
|
|
2026-03-19 16:12:01 +00:00
|
|
|
const { t } = useI18n()
|
2026-01-24 22:59:20 +00:00
|
|
|
const router = useRouter()
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
const route = useRoute()
|
2026-01-24 22:59:20 +00:00
|
|
|
const store = useAppStore()
|
2026-03-29 00:13:39 +00:00
|
|
|
const serverStore = useServerStore()
|
2026-03-22 03:30:21 +00:00
|
|
|
const actions = useAppsActions()
|
2026-01-24 22:59:20 +00:00
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
// Only stagger-animate on first mount
|
2026-03-19 16:12:01 +00:00
|
|
|
const showStagger = !appsAnimationDone
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
// Tabs
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
const activeTab = ref<'apps' | 'services'>(
|
|
|
|
|
route.query.tab === 'services' ? 'services' : 'apps'
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
// Search (debounced)
|
2026-03-05 08:06:07 +00:00
|
|
|
const searchQuery = ref('')
|
2026-03-21 03:01:38 +00:00
|
|
|
const debouncedSearchQuery = ref('')
|
|
|
|
|
let searchDebounceTimer: ReturnType<typeof setTimeout> | undefined
|
|
|
|
|
watch(searchQuery, (val) => {
|
|
|
|
|
clearTimeout(searchDebounceTimer)
|
|
|
|
|
searchDebounceTimer = setTimeout(() => { debouncedSearchQuery.value = val }, 150)
|
|
|
|
|
})
|
|
|
|
|
onBeforeUnmount(() => { clearTimeout(searchDebounceTimer) })
|
2026-03-05 08:06:07 +00:00
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
// Category filter
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
const selectedCategory = ref('all')
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
const ALL_CATEGORIES = computed(() => buildAllCategories(t))
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
|
2026-04-07 19:44:00 +01:00
|
|
|
// Merge real packages from store with web-only app bookmarks + installing placeholders
|
2026-03-22 03:30:21 +00:00
|
|
|
const packages = computed(() => {
|
|
|
|
|
const realPackages = store.packages || {}
|
2026-04-07 19:44:00 +01:00
|
|
|
const merged: Record<string, PackageDataEntry> = { ...WEB_ONLY_APPS, ...realPackages }
|
|
|
|
|
|
|
|
|
|
// Inject placeholder entries for apps being installed that aren't in backend data yet
|
|
|
|
|
for (const [appId, progress] of serverStore.installingApps) {
|
|
|
|
|
if (!merged[appId]) {
|
|
|
|
|
merged[appId] = {
|
|
|
|
|
state: 'installing' as PackageState,
|
|
|
|
|
manifest: {
|
|
|
|
|
id: appId,
|
|
|
|
|
title: progress.title,
|
|
|
|
|
version: '',
|
2026-04-08 09:20:18 +02:00
|
|
|
description: { short: '', long: '' },
|
2026-04-07 19:44:00 +01:00
|
|
|
'release-notes': '', license: '', 'wrapper-repo': '', 'upstream-repo': '',
|
|
|
|
|
'support-site': '', 'marketing-site': '', 'donation-url': null,
|
|
|
|
|
},
|
|
|
|
|
'static-files': { license: '', instructions: '', icon: '' },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return merged
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
})
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
const categoriesWithApps = useCategoriesWithApps(packages, ALL_CATEGORIES)
|
feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
(bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha
Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00
|
|
|
|
2026-05-06 09:23:57 -04:00
|
|
|
const isLoadingApps = computed(() => !store.hasLoadedInitialData && !connectionError.value)
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
// Connection error state
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
const connectionError = ref('')
|
|
|
|
|
let connectionTimer: ReturnType<typeof setTimeout> | undefined
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
2026-03-19 16:12:01 +00:00
|
|
|
appsAnimationDone = true
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
if (!store.isConnected) {
|
|
|
|
|
connectionTimer = setTimeout(() => {
|
2026-05-06 09:23:57 -04:00
|
|
|
if (!store.hasLoadedInitialData && sortedPackageEntries.value.length === 0) {
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
connectionError.value = 'Unable to connect to server. Check that the backend is running.'
|
|
|
|
|
}
|
|
|
|
|
}, 15000)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
if (connectionTimer) clearTimeout(connectionTimer)
|
2026-01-24 22:59:20 +00:00
|
|
|
})
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
// Sorted entries: web-only first, then alphabetical by title
|
2026-01-27 22:47:51 +00:00
|
|
|
const sortedPackageEntries = computed(() => {
|
|
|
|
|
const entries = Object.entries(packages.value)
|
2026-04-28 15:00:58 -04:00
|
|
|
const filtered = filterEntriesForTab(entries, activeTab.value, selectedCategory.value)
|
2026-03-17 02:23:30 +00:00
|
|
|
return filtered.sort(([idA, a], [idB, b]) => {
|
2026-03-12 00:19:30 +00:00
|
|
|
const aWeb = isWebOnlyApp(idA) ? 0 : 1
|
|
|
|
|
const bWeb = isWebOnlyApp(idB) ? 0 : 1
|
|
|
|
|
if (aWeb !== bWeb) return aWeb - bWeb
|
|
|
|
|
return (a.manifest?.title ?? '').localeCompare(b.manifest?.title ?? '', undefined, { sensitivity: 'base' })
|
|
|
|
|
})
|
2026-01-27 22:47:51 +00:00
|
|
|
})
|
|
|
|
|
|
2026-03-05 08:06:07 +00:00
|
|
|
const filteredPackageEntries = computed(() => {
|
2026-03-21 03:01:38 +00:00
|
|
|
if (!debouncedSearchQuery.value) return sortedPackageEntries.value
|
|
|
|
|
const q = debouncedSearchQuery.value.toLowerCase()
|
2026-03-05 08:06:07 +00:00
|
|
|
return sortedPackageEntries.value.filter(([id, pkg]) =>
|
|
|
|
|
(pkg.manifest?.title ?? '').toLowerCase().includes(q) ||
|
|
|
|
|
(pkg.manifest?.description?.short ?? '').toLowerCase().includes(q) ||
|
|
|
|
|
id.toLowerCase().includes(q)
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
// Uninstall modal
|
|
|
|
|
const uninstallModal = ref({ show: false, appId: '', appTitle: '' })
|
2026-03-18 19:24:52 +00:00
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
function showUninstallModal(id: string, pkg: PackageDataEntry) {
|
|
|
|
|
uninstallModal.value = { show: true, appId: id, appTitle: pkg.manifest.title }
|
2026-01-24 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
function closeUninstallModal() {
|
|
|
|
|
uninstallModal.value.show = false
|
2026-01-24 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
async function onConfirmUninstall() {
|
|
|
|
|
const { appId } = uninstallModal.value
|
2026-04-21 19:11:36 -04:00
|
|
|
// Close the modal immediately so the user can fire off concurrent
|
|
|
|
|
// uninstalls. Each AppCard surfaces its own live stage label while
|
|
|
|
|
// its uninstall is in flight.
|
2026-03-22 03:30:21 +00:00
|
|
|
uninstallModal.value.show = false
|
|
|
|
|
await actions.confirmUninstall(appId)
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-24 22:59:20 +00:00
|
|
|
function goToApp(id: string) {
|
2026-03-01 18:07:35 +00:00
|
|
|
router.push(`/dashboard/apps/${id}`).catch(() => {})
|
2026-01-24 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-22 03:30:21 +00:00
|
|
|
function launchApp(id: string) {
|
|
|
|
|
useAppLauncherStore().openSession(id)
|
2026-01-24 22:59:20 +00:00
|
|
|
}
|
2026-04-22 08:29:56 -04:00
|
|
|
|
|
|
|
|
async function updateApp(id: string) {
|
|
|
|
|
try {
|
|
|
|
|
await serverStore.updatePackage(id)
|
|
|
|
|
} catch (err) {
|
|
|
|
|
actions.actionError.value = `Failed to update ${id}: ${err instanceof Error ? err.message : 'Unknown error'}`
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-24 22:59:20 +00:00
|
|
|
</script>
|