feat: Waves 3+4 — frontend wiring, NATS integration, stores (19 files)
All checks were successful
Test Asgard Runner / test (push) Successful in 2s
All checks were successful
Test Asgard Runner / test (push) Successful in 2s
Frontend:
- Wire Dashboard quick actions (start/stop/trigger wipe) + next wipe schedule
- Wire Console WebSocket streaming for real-time output
- Implement TOTP 2FA challenge flow in LoginView
- Wire Plugin load/unload toggle + uninstall buttons with confirmations
- Wire WipesView profile selector, disable trigger when no profiles
- Build full WipeProfiles create/edit modal with all config fields
- Wire MapsView file upload with multipart FormData
- Fix SettingsView empty catch blocks → toast error messages
- Fix stale localStorage token reads in CSV exports → auth store
- Fix auth store hardcoded permissions → JWT-decoded role permissions
- Fix wipe store onMounted lifecycle bug → explicit subscribe action
- Update EarlyAccessView from countdown to "Now Live" state
Backend:
- Wire wipe trigger to publish NATS cmd (corrosion.{id}.cmd.wipe)
- Wire plugin reload/uninstall to publish NATS cmd
- Expand NatsBridgeService: add files, wipe status, server status subs
- Add PATCH schedules/:id/toggle endpoint for task toggling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { usePluginStore } from '@/stores/plugins'
|
||||
import { useToastStore } from '@/stores/toast'
|
||||
import type { PluginEntry } from '@/types'
|
||||
import { Puzzle, Search, Download, RefreshCw, Power, PowerOff, Trash2 } from 'lucide-vue-next'
|
||||
|
||||
const pluginStore = usePluginStore()
|
||||
const toast = useToastStore()
|
||||
|
||||
const searchQuery = ref('')
|
||||
const tab = ref<'installed' | 'browse'>('installed')
|
||||
@@ -37,6 +39,26 @@ function sourceBadgeClass(source: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleToggleLoad(plugin: PluginEntry) {
|
||||
try {
|
||||
await pluginStore.reloadPlugin(plugin.id)
|
||||
toast.success(`${plugin.plugin_name} ${plugin.is_loaded ? 'unloaded' : 'loaded'} successfully`)
|
||||
await pluginStore.fetchPlugins()
|
||||
} catch {
|
||||
toast.error(`Failed to toggle ${plugin.plugin_name}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUninstall(plugin: PluginEntry) {
|
||||
if (!confirm(`Uninstall ${plugin.plugin_name}? This cannot be undone.`)) return
|
||||
try {
|
||||
await pluginStore.uninstallPlugin(plugin.id)
|
||||
toast.success(`${plugin.plugin_name} uninstalled`)
|
||||
} catch {
|
||||
toast.error(`Failed to uninstall ${plugin.plugin_name}`)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
pluginStore.fetchPlugins()
|
||||
})
|
||||
@@ -144,13 +166,18 @@ onMounted(() => {
|
||||
<td class="px-4 py-3 text-right">
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<button
|
||||
@click="handleToggleLoad(plugin)"
|
||||
class="p-1.5 rounded transition-colors"
|
||||
:class="plugin.is_loaded ? 'text-neutral-500 hover:text-yellow-400' : 'text-neutral-500 hover:text-green-400'"
|
||||
:title="plugin.is_loaded ? 'Unload' : 'Load'"
|
||||
>
|
||||
<component :is="plugin.is_loaded ? PowerOff : Power" class="w-4 h-4" />
|
||||
</button>
|
||||
<button class="p-1.5 text-neutral-500 hover:text-red-400 rounded transition-colors" title="Uninstall">
|
||||
<button
|
||||
@click="handleUninstall(plugin)"
|
||||
class="p-1.5 text-neutral-500 hover:text-red-400 rounded transition-colors"
|
||||
title="Uninstall"
|
||||
>
|
||||
<Trash2 class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user