diff --git a/app.go b/app.go index 99e89cd..e17a8b8 100644 --- a/app.go +++ b/app.go @@ -244,9 +244,14 @@ func (a *App) startup(ctx context.Context) { a.deviceInfoCache = deviceInfoCache a.metadata = vellum.NewMetadataStore() - if err := a.metadata.Load(); err != nil { - fmt.Printf("Warning: could not load metadata: %v\n", err) - } + go func() { + if err := a.metadata.Load(); err != nil { + debug.Printf("[DEBUG] Failed to load metadata: %v\n", err) + runtime.EventsEmit(a.ctx, "metadata:error", err.Error()) + return + } + runtime.EventsEmit(a.ctx, "metadata:loaded") + }() go func() { settings.OnSignalSettingChanged(func(changed settings.Changed) { diff --git a/app_packages.go b/app_packages.go index c3eb532..201df4a 100644 --- a/app_packages.go +++ b/app_packages.go @@ -141,6 +141,9 @@ func (a *App) RefreshMetadata() error { func (a *App) GetPackages(deviceType, firmware, arch string) []PackageInfo { debug.Printf("[DEBUG] GetPackages called, metadata=%p, deviceType=%s, firmware=%s, arch=%s\n", a.metadata, deviceType, firmware, arch) + if a.metadata == nil || !a.metadata.Ready() { + return []PackageInfo{} + } packages := a.metadata.GetAllPackagesForDevice(deviceType, firmware, arch) debug.Printf("[DEBUG] GetPackages got %d packages\n", len(packages)) result := []PackageInfo{} diff --git a/frontend/src/pages/ConnectPage.tsx b/frontend/src/pages/ConnectPage.tsx index f55401d..4e97b18 100644 --- a/frontend/src/pages/ConnectPage.tsx +++ b/frontend/src/pages/ConnectPage.tsx @@ -1,4 +1,4 @@ -import { useState, useRef, useMemo } from 'react' +import { useState, useRef, useMemo, useEffect } from 'react' import { toast } from 'sonner' import { handleError, getUserFriendlyMessage } from '@/lib/errorMessages' import { Button } from '@/components/ui/button' @@ -43,13 +43,24 @@ export function ConnectPage({ const [showPassword, setShowPassword] = useState(false) const [keyPassphrase, setKeyPassphrase] = useState('') const [showKeyPassphrase, setShowKeyPassphrase] = useState(false) - const [availableKeys] = useState(initialKeys) + const [availableKeys, setAvailableKeys] = useState(initialKeys) const [selectedKey, setSelectedKey] = useState(initialKeys.length > 0 ? initialKeys[0].path : '') const [customKeyName, setCustomKeyName] = useState('') - const [sshAgentAvailable] = useState(initialAgentAvailable) + const [sshAgentAvailable, setSSHAgentAvailable] = useState(initialAgentAvailable) const [connecting, setConnecting] = useState(false) const connectAttemptRef = useRef(0) + useEffect(() => { + setAvailableKeys(initialKeys) + if (initialKeys.length > 0 && !selectedKey) { + setSelectedKey(initialKeys[0].path) + } + }, [initialKeys]) + + useEffect(() => { + setSSHAgentAvailable(initialAgentAvailable) + }, [initialAgentAvailable]) + const [showAddForm, setShowAddForm] = useState(false) const [editingDevice, setEditingDevice] = useState(null) const [deviceName, setDeviceName] = useState('') diff --git a/go.sum b/go.sum index 6529850..42b6427 100644 --- a/go.sum +++ b/go.sum @@ -212,8 +212,6 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rmitchellscott/remarkable-go v0.3.0 h1:4Fr0Dw1IIGXPz67TH8wKaKdAQpOwKwYvyUgAKng8ho0= -github.com/rmitchellscott/remarkable-go v0.3.0/go.mod h1:thnO3JUMAzlyRbl0jxwqDlSVWcwoco+F4wR9ohg5Pjg= github.com/rmitchellscott/remarkable-go v0.3.1 h1:mBe4KdpOVOziQVRmh5b2TAIBwujWIL0MusjHyVCscYA= github.com/rmitchellscott/remarkable-go v0.3.1/go.mod h1:thnO3JUMAzlyRbl0jxwqDlSVWcwoco+F4wR9ohg5Pjg= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= diff --git a/internal/vellum/fallback_packages.json b/internal/vellum/fallback_packages.json deleted file mode 100644 index 5a63471..0000000 --- a/internal/vellum/fallback_packages.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "generated": "2025-01-01T00:00:00Z", - "packages": { - "xovi": { - "0.3.1": { - "pkgdesc": "Core mod framework for reMarkable tablets", - "upstream_author": "asivery", - "categories": ["framework"], - "license": "GPL-3.0", - "url": "https://github.com/asivery/xovi", - "os_min": "3.20", - "os_max": "3.25", - "devices": ["rm1", "rm2", "rmpp", "rmppmove", "rmppure"], - "depends": [], - "conflicts": [], - "arch": ["aarch64", "armv7"] - } - }, - "qt-resource-rebuilder": { - "0.3.0": { - "pkgdesc": "Enables UI modifications by rebuilding Qt resources", - "upstream_author": "asivery", - "categories": ["framework"], - "license": "GPL-3.0", - "url": "https://github.com/asivery/xovi", - "devices": ["rm1", "rm2", "rmpp", "rmppmove", "rmppure"], - "depends": ["xovi"], - "conflicts": [], - "arch": ["aarch64", "armv7"] - } - }, - "tripletap": { - "1.0.0": { - "pkgdesc": "Triple-press power button to start xovi", - "upstream_author": "asivery", - "categories": ["utilities"], - "license": "MIT", - "url": "https://github.com/asivery/xovi-tripletap", - "devices": ["rm1", "rm2", "rmpp", "rmppmove", "rmppure"], - "depends": ["xovi"], - "conflicts": [], - "arch": ["aarch64", "armv7"] - } - }, - "appload": { - "0.2.0": { - "pkgdesc": "Run third-party applications on reMarkable", - "upstream_author": "asivery", - "categories": ["apps"], - "license": "GPL-3.0", - "url": "https://github.com/asivery/xovi", - "devices": ["rm1", "rm2", "rmpp", "rmppmove", "rmppure"], - "depends": ["xovi"], - "conflicts": [], - "arch": ["aarch64", "armv7"] - } - } - } -} diff --git a/internal/vellum/fallback_remanager.json b/internal/vellum/fallback_remanager.json deleted file mode 100644 index 7758b59..0000000 --- a/internal/vellum/fallback_remanager.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "packages": { - "xovi": { - "maintenanceCommands": [ - { - "id": "start", - "label": "Start UI with Mods", - "description": "Start or restart xovi", - "command": "/home/root/xovi/start", - "requiresTerminal": true, - "allowStop": false - }, - { - "id": "stock", - "label": "Start UI without Mods", - "description": "Restart interface without mods applied", - "command": "/home/root/xovi/stock", - "requiresTerminal": true, - "allowStop": false - }, - { - "id": "debug", - "label": "Debug", - "description": "Run xovi in debug mode for troubleshooting issues", - "command": "/home/root/xovi/debug", - "requiresTerminal": true, - "allowStop": true - } - ] - }, - "qt-resource-rebuilder": { - "hooks": { - "postInstall": "rebuild_hashtable_dialog" - }, - "maintenanceCommands": [ - { - "id": "rebuild_hashtable", - "label": "Rebuild Hashtable", - "description": "Rebuild Qt hashtable (required after OS upgrades)", - "command": "/home/root/xovi/rebuild_hashtable", - "requiresTerminal": false, - "allowStop": false, - "hook": "rebuild_hashtable_dialog" - } - ] - } - } -} diff --git a/internal/vellum/metadata.go b/internal/vellum/metadata.go index 68f7165..5a01c6f 100644 --- a/internal/vellum/metadata.go +++ b/internal/vellum/metadata.go @@ -9,8 +9,6 @@ import ( "sync" "time" - _ "embed" - "reManager/internal/debug" "reManager/internal/httputil" versionpkg "reManager/internal/version" @@ -22,12 +20,6 @@ const ( MetadataTimeout = 10 * time.Second ) -//go:embed fallback_packages.json -var fallbackPackagesJSON []byte - -//go:embed fallback_remanager.json -var fallbackRemanagerJSON []byte - type OSConstraint struct { Version string `json:"version"` Operator string `json:"operator"` @@ -137,6 +129,8 @@ type MetadataStore struct { mu sync.RWMutex packages PackagesMetadata remanager RemanagerMetadata + loaded bool + err error } func NewMetadataStore() *MetadataStore { @@ -145,25 +139,30 @@ func NewMetadataStore() *MetadataStore { func (m *MetadataStore) Load() error { if err := m.loadPackagesMetadata(); err != nil { - debug.Printf("[DEBUG] HTTP fetch packages failed: %v, using fallback\n", err) - if err := json.Unmarshal(fallbackPackagesJSON, &m.packages); err != nil { - return fmt.Errorf("failed to parse fallback packages metadata: %w", err) - } + m.err = fmt.Errorf("failed to fetch packages metadata: %w", err) + return m.err } normalizePackagesMetadata(&m.packages) debug.Printf("[DEBUG] Loaded %d packages from metadata\n", len(m.packages.Packages)) if err := m.loadRemanagerMetadata(); err != nil { - debug.Printf("[DEBUG] HTTP fetch remanager failed: %v, using fallback\n", err) - if err := json.Unmarshal(fallbackRemanagerJSON, &m.remanager); err != nil { - return fmt.Errorf("failed to parse fallback remanager metadata: %w", err) - } + m.err = fmt.Errorf("failed to fetch remanager metadata: %w", err) + return m.err } debug.Printf("[DEBUG] Loaded %d remanager package configs\n", len(m.remanager.Packages)) + m.loaded = true return nil } +func (m *MetadataStore) Ready() bool { + return m.loaded +} + +func (m *MetadataStore) Err() error { + return m.err +} + func (m *MetadataStore) Refresh() error { client := httputil.NewClient(MetadataTimeout) @@ -207,6 +206,8 @@ func (m *MetadataStore) Refresh() error { if len(newRemanager.Packages) > 0 { m.remanager = newRemanager } + m.loaded = true + m.err = nil m.mu.Unlock() debug.Printf("[DEBUG] Refreshed metadata: %d packages, %d remanager configs\n", len(m.packages.Packages), len(m.remanager.Packages))