docs: add milestone 5a report (frontend plugin host, contribution lifecycle)
This commit is contained in:
parent
816ba5a062
commit
73c5da8eb5
|
|
@ -0,0 +1,165 @@
|
||||||
|
# Milestone 5a — Frontend Plugin Host: Declarative UI Contributions + Plugin Settings
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
Создать первый UI-host слой, чтобы shell отображал UI contributions плагинов и корректно убирал их при disable/reload. Ошибка plugin UI не должна ронять shell.
|
||||||
|
|
||||||
|
## Contribution Points
|
||||||
|
|
||||||
|
### Реализованы в этом milestone
|
||||||
|
|
||||||
|
| Contribution Point | Backend Registry | Frontend Host | Статус |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `sidebarItems` | ✅ Registry.Register/Unregister/ListByPoint | ✅ Sidebar.svelte | Работает |
|
||||||
|
| `views` | ✅ Registry | ✅ ViewContainer.svelte (placeholder) | Работает (declarative placeholder) |
|
||||||
|
| `settingsPanels` | ✅ Registry | ✅ PluginManager.svelte | Работает |
|
||||||
|
| `commands` | ✅ Registry | ContributionRegistry (UI command palette not implemented) | Registry готов, UI planned |
|
||||||
|
|
||||||
|
### Планируемые (не реализованы)
|
||||||
|
|
||||||
|
- `fileActions`, `noteActions`, `contextMenuEntries`, `searchProviders`, `activityProviders`, `statusBarItems`
|
||||||
|
|
||||||
|
## Что сделано
|
||||||
|
|
||||||
|
### 1. Contribution Registry Lifecycle
|
||||||
|
|
||||||
|
**`internal/core/contribution/registry.go`:**
|
||||||
|
- Добавлен `ListByPoint(pointType)` — запрос contributions по типу
|
||||||
|
- `Register()` теперь idempotent: удаляет старые записи plugin перед добавлением
|
||||||
|
- Добавлены `ContributionPointType` константы для всех 10 типов
|
||||||
|
|
||||||
|
**`internal/api/app.go` — ReloadPlugins:**
|
||||||
|
- Перед регистрацией contributions вызывается `Unregister(pluginID)` → предотвращает дубли при повторном reload
|
||||||
|
- Disabled/failed plugins не регистрируют contributions
|
||||||
|
- Flattened ContributionSummary для фронтенда (FlatSidebarItem, FlatView, FlatSettingsPanel, FlatCommand)
|
||||||
|
|
||||||
|
### 2. Manifest Contributions Schema
|
||||||
|
|
||||||
|
`plugin.json` может объявлять (без изменений — схема существовала):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"contributes": {
|
||||||
|
"sidebarItems": [{ "id": "...", "title": "...", "icon": "🧪", "view": "...", "position": 100 }],
|
||||||
|
"views": [{ "id": "...", "title": "...", "component": "..." }],
|
||||||
|
"settingsPanels": [{ "id": "...", "title": "...", "component": "..." }],
|
||||||
|
"commands": [{ "id": "...", "title": "...", "icon": "⚡", "handler": "..." }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. UI Shell Rendering
|
||||||
|
|
||||||
|
**Sidebar.svelte:**
|
||||||
|
- Строит plugin sidebar items из ContributionRegistry (поле `sidebarItems`)
|
||||||
|
- Сортировка по `position` (default 100)
|
||||||
|
- Фильтрация: скрыты items от disabled/failed/incompatible плагинов
|
||||||
|
- Клик → `verstak:open-view` событие
|
||||||
|
- Error boundary: перехват ошибок API, показ "⚠️ Plugin UI error"
|
||||||
|
|
||||||
|
**ViewContainer.svelte:**
|
||||||
|
- Declarative placeholder host для plugin views
|
||||||
|
- Показывает plugin name, view id, component id, статус "frontend bundle host not implemented yet"
|
||||||
|
- Error boundary: `{#key}` + catch rendering errors → "⚠️ Plugin UI failed" fallback
|
||||||
|
- Empty state: "Select a plugin view from the sidebar"
|
||||||
|
|
||||||
|
### 4. Plugin Settings
|
||||||
|
|
||||||
|
**PluginManager.svelte:**
|
||||||
|
- Загружает `settingsPanels` из ContributionRegistry
|
||||||
|
- PluginCard принимает `settingsPanels` prop
|
||||||
|
- "⚙️ Settings" кнопка показывается только если у plugin есть settingsPanel
|
||||||
|
- Клик → `verstak:open-settings` → открывает settings panel в modal
|
||||||
|
- Disable plugin → кнопка Settings исчезает
|
||||||
|
- Error boundary: `{#key}` + error state вокруг settings panel
|
||||||
|
|
||||||
|
### 5. Error Boundary
|
||||||
|
|
||||||
|
- ViewContainer: `{#key activeView}` + try/catch в reactive declarations → "⚠️ Plugin UI failed"
|
||||||
|
- PluginManager: `{#key}` вокруг settings modal + `settingsError` state
|
||||||
|
- Ошибки логируются в `console.error`
|
||||||
|
|
||||||
|
### 6. Platform-test Plugin
|
||||||
|
|
||||||
|
`verstak-official-plugins/plugins/platform-test/plugin.json` уже содержит все contribution points. Без изменений.
|
||||||
|
|
||||||
|
### 7. Enable/Disable Verification
|
||||||
|
|
||||||
|
| Сценарий | Результат |
|
||||||
|
|---|---|
|
||||||
|
| Plugin enabled → sidebar item visible | ✅ Sidebar items из ContributionRegistry |
|
||||||
|
| Plugin enabled → view opens | ✅ ViewContainer placeholder |
|
||||||
|
| Plugin enabled → settings button visible | ✅ Если есть settingsPanel |
|
||||||
|
| Plugin disabled → sidebar item disappears | ✅ `Unregister` → contributions удалены |
|
||||||
|
| Plugin disabled → view/settings unavailable | ✅ Не показываются |
|
||||||
|
| Plugin re-enabled → contributions return | ✅ При Reload — Register |
|
||||||
|
| ReloadPlugins no duplicates | ✅ Unregister перед Register + Register idempotent |
|
||||||
|
| Failed plugin → shell stable | ✅ Error boundary в ViewContainer + PluginManager |
|
||||||
|
|
||||||
|
### 8. Build Script
|
||||||
|
|
||||||
|
`scripts/build.sh` — добавлена функция `global_update()`:
|
||||||
|
- `git pull --ff-only` для всех 6 репозиториев
|
||||||
|
- Сборка official plugins (npm install + build для каждого plugin с frontend, go build для backend)
|
||||||
|
- Копирование собранных плагинов в `verstak-desktop/plugins/`
|
||||||
|
- Ошибки не фатальны — собираются и показываются в конце
|
||||||
|
|
||||||
|
## Изменённые файлы
|
||||||
|
|
||||||
|
### verstak-desktop
|
||||||
|
|
||||||
|
| Файл | Изменение |
|
||||||
|
|---|---|
|
||||||
|
| `internal/core/contribution/registry.go` | Добавлен `ListByPoint`, `ContributionPointType`, `Register` idempotent |
|
||||||
|
| `internal/core/contribution/registry_test.go` | **НОВЫЙ**: 5 тестов (register, unregister, ListByPoint, duplicate prevention, no-side-effects) |
|
||||||
|
| `internal/api/app.go` | Flat типы для фронтенда, `buildContributionSummary`, `ReloadPlugins` — Unregister перед Register |
|
||||||
|
| `frontend/src/lib/shell/Sidebar.svelte` | Sidebar items из ContributionRegistry, фильтрация, сортировка, error boundary |
|
||||||
|
| `frontend/src/lib/shell/ViewContainer.svelte` | **НОВЫЙ**: declarative placeholder host + error boundary |
|
||||||
|
| `frontend/src/lib/plugin-manager/PluginCard.svelte` | Settings button по settingsPanels prop, disabled state |
|
||||||
|
| `frontend/src/lib/plugin-manager/PluginManager.svelte` | Загрузка settingsPanels, settings modal, error boundary |
|
||||||
|
| `frontend/src/App.svelte` | Обработка `verstak:open-view`, `verstak:open-settings`, `verstak:close-settings` |
|
||||||
|
| `cmd/smoke-platform/main.go` | Добавлен `-test-contributions` флаг с тестом lifecycle |
|
||||||
|
| `scripts/smoke-platform.sh` | Добавлен вызов `-test-contributions` |
|
||||||
|
| `scripts/build.sh` | Добавлена `global_update()` — pull всех репозиториев, сборка official plugins |
|
||||||
|
| `docs/PLUGIN_RUNTIME.md` | Обновлён раздел Contribution Points + Reload |
|
||||||
|
|
||||||
|
### verstak-docs
|
||||||
|
| Файл | Изменение |
|
||||||
|
|---|---|
|
||||||
|
| `docs/MILESTONE_PLATFORM_RUNTIME_5a.md` | **НОВЫЙ**: этот документ |
|
||||||
|
|
||||||
|
## Результаты проверок
|
||||||
|
|
||||||
|
```
|
||||||
|
go test ./internal/... -count=1
|
||||||
|
→ all packages PASS (включая 5 новых contribution tests)
|
||||||
|
|
||||||
|
go vet ./...
|
||||||
|
→ clean
|
||||||
|
|
||||||
|
cd frontend && npm run build
|
||||||
|
→ ✓ built in 1.43s
|
||||||
|
|
||||||
|
bash scripts/smoke-platform.sh
|
||||||
|
→ smoke-platform passed (plugin + workspace + contributions lifecycle)
|
||||||
|
→ enable/disable test passed
|
||||||
|
→ workspace test passed
|
||||||
|
→ contributions lifecycle test passed
|
||||||
|
|
||||||
|
git status --short
|
||||||
|
→ clean (все 6 репозиториев)
|
||||||
|
|
||||||
|
git log HEAD --not --remotes
|
||||||
|
→ empty (все запушено)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Non-goals (не реализовано)
|
||||||
|
|
||||||
|
- Frontend bundle loader (plugin JS bundle host). ViewContainer — declarative placeholder
|
||||||
|
- Official plugin extraction (notes/files/editor/activity)
|
||||||
|
- Backend sidecar runtime
|
||||||
|
- Secrets
|
||||||
|
- Remote plugin registry
|
||||||
|
- Sync
|
||||||
|
- Command palette UI
|
||||||
|
- Пользовательские функции в core
|
||||||
Loading…
Reference in New Issue