feat: add plugin UI host (sidebar, view container, settings panel) + storage API

- internal/core/storage/api.go — plugin namespace JSON storage (settings/data/cache)
- internal/core/storage/api_test.go — 8 tests (write/read, path traversal, atomic)
- internal/api/app.go — Wails bindings for storage (Read/WritePluginSettings, Read/WritePluginDataJSON)
- main.go — initialize storage service, pass to NewApp
- Sidebar.svelte — plugin sidebar items from contributions (filtered by ui.register)
- ViewContainer.svelte — plugin view host with degraded status
- PluginCard.svelte — Settings button + permission warnings
- PluginManager.svelte — settings panel modal with test form
- App.svelte — integrated sidebar + view container layout
This commit is contained in:
2026-06-17 03:01:37 +08:00
parent 70d4c75d7e
commit ca7eb79a40
9 changed files with 983 additions and 69 deletions
@@ -2,9 +2,12 @@
export let p = {};
export let capabilities = [];
export let permissions = [];
export let contributions = {};
export let onSettings = () => {};
$: m = p.manifest || {};
$: hasSettingsPanel = (contributions.settingsPanels || []).some(sp => sp.pluginId === pluginId);
$: hasUIPermission = (m.permissions || []).includes('ui.register');
$: hasStoragePermission = (m.permissions || []).includes('storage.namespace');
$: hasCommandsPermission = (m.permissions || []).includes('commands.register');
$: statusColor = ({
loaded: '#4ecca3',
@@ -160,6 +163,20 @@
{#if p.error}
<div class="error-box">{p.error}</div>
{/if}
<!-- Actions -->
<div class="card-actions">
{#if hasSettingsPanel}
<button class="btn-settings" on:click={() => onSettings(m.id)} type="button">
⚙ Settings
</button>
{/if}
</div>
<!-- Permission warnings -->
{#if !hasUIPermission && (m.contributes && (m.contributes.views || m.contributes.sidebarItems || m.contributes.settingsPanels).length > 0)}
<p class="warning">⚠ Plugin has UI contributions but lacks ui.register permission</p>
{/if}
</div>
<style>
@@ -327,4 +344,26 @@
color: #e94560;
font-family: monospace;
}
.card-actions {
display: flex;
gap: 0.5rem;
margin-top: 0.75rem;
padding-top: 0.5rem;
border-top: 1px solid #0f3460;
}
.btn-settings {
background: #0f3460;
border: 1px solid #1a3a5c;
color: #e0e0f0;
padding: 0.3rem 0.75rem;
border-radius: 4px;
cursor: pointer;
font-size: 0.8rem;
}
.btn-settings:hover {
background: #1a3a5c;
}
</style>