Replace plugin list diagnostics with VS Code-style Features panel #91

Closed
opened 2026-05-22 21:42:29 +00:00 by steve · 0 comments
Owner

Replace the cluttered imperative diagnostics dump in Community/Core plugin list
rows with a shared Svelte panel: Details | Features tabs and a VS Code
Marketplace–style resizable master-detail Features view built from existing
@lapis-notes/ui primitives.

Problem

Community and core plugin rows render 10–15 plain \n-separated <div> blocks
via appendDiagnostics and appendIndexedContributions in
packages/workspace/src/lib/components/configuration/community-plugins.ts.
Permissions, capabilities, and privileges overlap visually; activation events and
indexed contributions are hard to scan; there is no progressive disclosure.

Users need a VS Code Marketplace Features-style layout: top-level tabs, then
a resizable two-column nav + detail pane with scrollable lists and monospace
"code pill" entries for activation events, permissions, and contributions.

Goal

Make plugin permissions, activations, and indexed contributions understandable
at a glance in the Settings → Core plugins and Community plugins tabs, using a
shared inline panel that matches the settings shell and VS Code extension
Features presentation.

Scope

First iteration: replace description clutter only in Community/Core plugin
list rows
— not in the dedicated plugin settings nav.

VS Code reference model

  • DETAILS tab — manifest summary (version, author, description, enablement
    state)
  • FEATURES tab — left category nav + right detail pane listing entries as
    code-style pills

Map Lapis data to equivalent sections (hide empty sections from the left nav):

Section Data source
Runtime Status CommunityPluginDiagnostics / runtime plugin state: classification, host, activation mode, activation trigger, runtime entry, indexed count, state, last failure, contribution diagnostics, trusted-desktop warning
Activation Events LapisIndexedExtension.activationEvents + live activationTrigger when present
Permissions Merge permissions + requestedCapabilities / grantedCapabilities into one section (dedupe overlapping vault/settings/metadata labels); show privileges as a sub-block when non-empty
Commands contributions where kind === "commands"
Configuration kind === "configuration"
Languages kind === "languages"
Views views + editorViews
Services kind === "services"
Other contributions notebookRenderers, markdownPostProcessors, statusBarItems

Architecture

flowchart TB
  subgraph pluginRows [CommunityPlugins / CorePlugins SettingTab]
    SettingRow["Setting row: name + actions"]
    PanelHost["mountComponent host div"]
  end

  subgraph panel [PluginExtensionPanel.svelte]
    Tabs["Tabs: Details | Features"]
    Details["Details tab: version, author, description, status badge"]
    Features["Features tab"]
    subgraph featuresLayout [Resizable master-detail]
      NavPane["ScrollArea + section nav"]
      Handle["ResizableHandle"]
      DetailPane["ScrollArea + section content"]
    end
  end

  subgraph data [plugin-feature-sections.ts]
    Builder["buildPluginFeatureSections()"]
  end

  SettingRow --> PanelHost
  PanelHost --> panel
  Builder --> panel
  diagnostics["getCommunityPluginDiagnostics + getLapisExtension"] --> Builder

Component plan

1. Pure section builder (workspace, testable)

Add packages/workspace/src/lib/components/configuration/plugin-feature-sections.ts:

  • Export PluginFeatureSection type: { id, label, items: PluginFeatureItem[] }
    where items are { kind: 'code' | 'text' | 'warning' | 'error', value, meta? }
  • Export buildPluginFeatureSections({ diagnostics, extension, manifest, pluginState })
    — consolidates today's appendDiagnostics + appendIndexedContributions logic
    (reuse grantedPermissions, formatCapabilities helpers moved here)
  • Unit tests in plugin-feature-sections.test.ts covering: empty extension,
    activation events only, permission/capability merge, invalid contribution
    diagnostics

2. Shared Svelte panel (workspace)

Add under packages/workspace/src/lib/components/configuration/:

File Role
plugin-extension-panel.svelte Top-level Details | Features tabs; props: sections, details summary object
plugin-extension-features.svelte Horizontal Resizable.PaneGroup: left nav (~25%), handle, right detail (~75%); both panes wrapped in ScrollArea
plugin-feature-nav-item.svelte Nav button styled like settings nav (Sidebar.MenuButton pattern or plain Button variant="ghost")
plugin-feature-detail.svelte Section heading + list of Badge variant="outline" code pills (activation events) or Item rows (commands with title/id)

Layout constraints for inline use inside .setting-item-description:

  • Fixed bounded height (min-h-48 max-h-72 or similar) so rows stay scannable
  • Resizable.Handle withHandle for drag resize within the panel
  • Default selected section: first non-empty section (prefer Runtime Status)

3. UI primitives (existing @lapis-notes/ui)

Primitive Usage
@lapis-notes/ui/resizable Master-detail split (same paneforge API as tabs-split.svelte)
@lapis-notes/ui/scroll-area Both nav and detail panes
@lapis-notes/ui/badge Activation event / permission code pills
@lapis-notes/ui/separator Tab underline / pane divider accent
@lapis-notes/ui/button Section nav items
@lapis-notes/ui/item Structured contribution rows (command title + id)
@lapis-notes/ui/alert Trusted-desktop and last-failure warnings in Runtime Status

Tabs prerequisite: Add a minimal shadcn-style tabs/ wrapper in
packages/ui around bits-ui Tabs (mirrors how scroll-area and
resizable wrap bits-ui/paneforge). Export @lapis-notes/ui/tabs. (~4 files:
root, list, trigger, content + index export).

4. Integrate into plugin list tabs

community-plugins.ts:

  • Remove appendDiagnostics / appendIndexedContributions from setDesc
    fragments
  • Mount PluginExtensionPanel via mountComponent into a dedicated host div
    inside setDesc
  • Track mounted instances in a private panelMounts: MountComponent[] array;
    destroy all in display() before containerEl.empty() and in hide() to
    avoid leaks on re-render

core-plugins.ts:

  • Same panel with a reduced section set (Runtime Status + Activation Events +
    Privileges); builder accepts a variant: 'community' | 'core' flag to omit
    permissions/contribution sections when data is absent

CSS: Add scoped hooks in workspace-shell.css for .plugin-extension-panel
— full width inside description, border, rounded-md, subtle background so it
reads as an embedded card distinct from action buttons.

Non-goals

  • Embedding the panel in dedicated plugin settings nav (configuration.svelte)
  • Full CommunityPlugins → Svelte SettingTab rewrite
  • README/Details markdown rendering (VS Code Details tab is README; ours stays
    manifest summary)
  • Playwright e2e for settings UI (no existing community-plugin diagnostics e2e
    today)

Acceptance Criteria

  • Community and core plugin list rows show a tabbed inline panel instead of flat
    diagnostic <div> stacks.
  • Details tab shows version, author, description, and enablement/status
    summary.
  • Features tab shows a resizable two-column layout: left section nav, right
    scrollable detail pane.
  • Empty contribution categories are hidden from the nav (VS Code parity).
  • Activation events and permissions render as monospace code pills (Badge variant="outline").
  • Commands and other contributions render as structured rows where title/id
    metadata exists.
  • Runtime Status surfaces trusted-desktop warnings and last-failure messages
    via Alert when applicable.
  • Re-render flows (toggle enable, restart plugin) do not leak or duplicate mounted
    panels.
  • Unit tests cover buildPluginFeatureSections for empty extension, activation
    events, permission/capability merge, and invalid contribution diagnostics.
  • Specs updated: spec/src/20-packages/workspace/index.md and
    packages/workspace/spec.md describe the tabbed inline Features panel.
  • make spec-lint, package check, and root pnpm test:smoke pass.

Implementation Notes

VS Code parity notes (document in spec, do not over-implement)

  • VS Code auto-hides empty contribution categories; match that behavior.
  • VS Code Features lists raw activation event strings as pills — match with
    Badge variant="outline" font-mono.
  • VS Code Details tab is README markdown; our Details tab stays manifest summary
    since README rendering is out of scope.

Implementation todos

  1. Add minimal shadcn-style Tabs wrapper to packages/ui and export
    @lapis-notes/ui/tabs
  2. Create plugin-feature-sections.ts + unit tests; migrate diagnostics/format
    helpers from community-plugins.ts
  3. Build PluginExtensionPanel + PluginExtensionFeatures with Resizable,
    ScrollArea, Badge, Item, Alert
  4. Wire mountComponent into community-plugins.ts and core-plugins.ts with
    proper destroy lifecycle; add workspace-shell CSS
  5. Update workspace spec pages, run check + test:smoke

Suggested Files or Specs To Inspect

  • packages/workspace/src/lib/components/configuration/community-plugins.ts
  • packages/workspace/src/lib/components/configuration/core-plugins.ts
  • packages/workspace/src/lib/components/configuration/configuration.svelte
    (settings shell reference for nav styling)
  • packages/workspace/src/lib/components/tabs/tabs-split.svelte (Resizable
    usage reference)
  • packages/api/src/lib/lapis-extension.ts (LapisIndexedExtension,
    LapisContributionIndexEntry)
  • packages/api/src/lib/plugin-manager.ts (CommunityPluginDiagnostics)
  • spec/src/20-packages/workspace/index.md (Community Plugins Tab section)
  • spec/src/50-roadmap/complete-daily-use-app.md

Validation Commands

pnpm --filter @lapis-notes/ui check
pnpm --filter @lapis-notes/workspace check
pnpm test:smoke
make spec-lint

Manual: open Settings → Community plugins with plugin-test / indexed Lapis
fixtures; verify Features tab sections, resize handle, scroll, and that
re-render (toggle enable, restart) does not leak or duplicate panels.

Follow-up Tasks

  • Embed the panel at the top of a plugin's dedicated settings view when opened
    from the gear button
  • Playwright e2e coverage for community-plugin diagnostics UI

Implementation Summary

Replaced flat plugin diagnostics with expandable inline features panels, added full-width feature expansion with Show Features fallback, and made command entries executable from the plugin features view.

Replace the cluttered imperative diagnostics dump in Community/Core plugin list rows with a shared Svelte panel: **Details | Features** tabs and a VS Code Marketplace–style resizable master-detail Features view built from existing `@lapis-notes/ui` primitives. ## Problem Community and core plugin rows render 10–15 plain `\n`-separated `<div>` blocks via `appendDiagnostics` and `appendIndexedContributions` in `packages/workspace/src/lib/components/configuration/community-plugins.ts`. Permissions, capabilities, and privileges overlap visually; activation events and indexed contributions are hard to scan; there is no progressive disclosure. Users need a VS Code Marketplace **Features**-style layout: top-level tabs, then a resizable two-column nav + detail pane with scrollable lists and monospace "code pill" entries for activation events, permissions, and contributions. ## Goal Make plugin permissions, activations, and indexed contributions understandable at a glance in the Settings → Core plugins and Community plugins tabs, using a shared inline panel that matches the settings shell and VS Code extension Features presentation. ## Scope **First iteration:** replace description clutter **only in Community/Core plugin list rows** — not in the dedicated plugin settings nav. ### VS Code reference model - **DETAILS** tab — manifest summary (version, author, description, enablement state) - **FEATURES** tab — left category nav + right detail pane listing entries as code-style pills Map Lapis data to equivalent sections (hide empty sections from the left nav): | Section | Data source | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Runtime Status | `CommunityPluginDiagnostics` / runtime plugin state: classification, host, activation mode, activation trigger, runtime entry, indexed count, state, last failure, contribution diagnostics, trusted-desktop warning | | Activation Events | `LapisIndexedExtension.activationEvents` + live `activationTrigger` when present | | Permissions | Merge `permissions` + `requestedCapabilities` / `grantedCapabilities` into one section (dedupe overlapping vault/settings/metadata labels); show `privileges` as a sub-block when non-empty | | Commands | `contributions` where `kind === "commands"` | | Configuration | `kind === "configuration"` | | Languages | `kind === "languages"` | | Views | `views` + `editorViews` | | Services | `kind === "services"` | | Other contributions | notebookRenderers, markdownPostProcessors, statusBarItems | ### Architecture ```mermaid flowchart TB subgraph pluginRows [CommunityPlugins / CorePlugins SettingTab] SettingRow["Setting row: name + actions"] PanelHost["mountComponent host div"] end subgraph panel [PluginExtensionPanel.svelte] Tabs["Tabs: Details | Features"] Details["Details tab: version, author, description, status badge"] Features["Features tab"] subgraph featuresLayout [Resizable master-detail] NavPane["ScrollArea + section nav"] Handle["ResizableHandle"] DetailPane["ScrollArea + section content"] end end subgraph data [plugin-feature-sections.ts] Builder["buildPluginFeatureSections()"] end SettingRow --> PanelHost PanelHost --> panel Builder --> panel diagnostics["getCommunityPluginDiagnostics + getLapisExtension"] --> Builder ``` ### Component plan #### 1. Pure section builder (workspace, testable) Add `packages/workspace/src/lib/components/configuration/plugin-feature-sections.ts`: - Export `PluginFeatureSection` type: `{ id, label, items: PluginFeatureItem[] }` where items are `{ kind: 'code' | 'text' | 'warning' | 'error', value, meta? }` - Export `buildPluginFeatureSections({ diagnostics, extension, manifest, pluginState })` — consolidates today's `appendDiagnostics` + `appendIndexedContributions` logic (reuse `grantedPermissions`, `formatCapabilities` helpers moved here) - Unit tests in `plugin-feature-sections.test.ts` covering: empty extension, activation events only, permission/capability merge, invalid contribution diagnostics #### 2. Shared Svelte panel (workspace) Add under `packages/workspace/src/lib/components/configuration/`: | File | Role | | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | `plugin-extension-panel.svelte` | Top-level **Details \| Features** tabs; props: `sections`, `details` summary object | | `plugin-extension-features.svelte` | Horizontal `Resizable.PaneGroup`: left nav (~25%), handle, right detail (~75%); both panes wrapped in `ScrollArea` | | `plugin-feature-nav-item.svelte` | Nav button styled like settings nav (`Sidebar.MenuButton` pattern or plain `Button variant="ghost"`) | | `plugin-feature-detail.svelte` | Section heading + list of `Badge variant="outline"` code pills (activation events) or `Item` rows (commands with title/id) | **Layout constraints for inline use inside `.setting-item-description`:** - Fixed bounded height (`min-h-48 max-h-72` or similar) so rows stay scannable - `Resizable.Handle withHandle` for drag resize within the panel - Default selected section: first non-empty section (prefer Runtime Status) #### 3. UI primitives (existing `@lapis-notes/ui`) | Primitive | Usage | | ----------------------------- | --------------------------------------------------------------- | | `@lapis-notes/ui/resizable` | Master-detail split (same paneforge API as `tabs-split.svelte`) | | `@lapis-notes/ui/scroll-area` | Both nav and detail panes | | `@lapis-notes/ui/badge` | Activation event / permission code pills | | `@lapis-notes/ui/separator` | Tab underline / pane divider accent | | `@lapis-notes/ui/button` | Section nav items | | `@lapis-notes/ui/item` | Structured contribution rows (command title + id) | | `@lapis-notes/ui/alert` | Trusted-desktop and last-failure warnings in Runtime Status | **Tabs prerequisite:** Add a minimal shadcn-style `tabs/` wrapper in `packages/ui` around `bits-ui` `Tabs` (mirrors how `scroll-area` and `resizable` wrap bits-ui/paneforge). Export `@lapis-notes/ui/tabs`. (~4 files: root, list, trigger, content + index export). #### 4. Integrate into plugin list tabs **`community-plugins.ts`:** - Remove `appendDiagnostics` / `appendIndexedContributions` from `setDesc` fragments - Mount `PluginExtensionPanel` via `mountComponent` into a dedicated host div inside `setDesc` - Track mounted instances in a `private panelMounts: MountComponent[]` array; destroy all in `display()` before `containerEl.empty()` and in `hide()` to avoid leaks on re-render **`core-plugins.ts`:** - Same panel with a reduced section set (Runtime Status + Activation Events + Privileges); builder accepts a `variant: 'community' | 'core'` flag to omit permissions/contribution sections when data is absent **CSS:** Add scoped hooks in `workspace-shell.css` for `.plugin-extension-panel` — full width inside description, border, rounded-md, subtle background so it reads as an embedded card distinct from action buttons. ## Non-goals - Embedding the panel in dedicated plugin settings nav (`configuration.svelte`) - Full CommunityPlugins → Svelte `SettingTab` rewrite - README/Details markdown rendering (VS Code Details tab is README; ours stays manifest summary) - Playwright e2e for settings UI (no existing community-plugin diagnostics e2e today) ## Acceptance Criteria - Community and core plugin list rows show a tabbed inline panel instead of flat diagnostic `<div>` stacks. - **Details** tab shows version, author, description, and enablement/status summary. - **Features** tab shows a resizable two-column layout: left section nav, right scrollable detail pane. - Empty contribution categories are hidden from the nav (VS Code parity). - Activation events and permissions render as monospace code pills (`Badge variant="outline"`). - Commands and other contributions render as structured rows where title/id metadata exists. - Runtime Status surfaces trusted-desktop warnings and last-failure messages via `Alert` when applicable. - Re-render flows (toggle enable, restart plugin) do not leak or duplicate mounted panels. - Unit tests cover `buildPluginFeatureSections` for empty extension, activation events, permission/capability merge, and invalid contribution diagnostics. - Specs updated: `spec/src/20-packages/workspace/index.md` and `packages/workspace/spec.md` describe the tabbed inline Features panel. - `make spec-lint`, package `check`, and root `pnpm test:smoke` pass. ## Implementation Notes ### VS Code parity notes (document in spec, do not over-implement) - VS Code auto-hides empty contribution categories; match that behavior. - VS Code Features lists raw activation event strings as pills — match with `Badge variant="outline" font-mono`. - VS Code Details tab is README markdown; our Details tab stays manifest summary since README rendering is out of scope. ### Implementation todos 1. Add minimal shadcn-style Tabs wrapper to `packages/ui` and export `@lapis-notes/ui/tabs` 2. Create `plugin-feature-sections.ts` + unit tests; migrate diagnostics/format helpers from `community-plugins.ts` 3. Build `PluginExtensionPanel` + `PluginExtensionFeatures` with Resizable, ScrollArea, Badge, Item, Alert 4. Wire `mountComponent` into `community-plugins.ts` and `core-plugins.ts` with proper destroy lifecycle; add workspace-shell CSS 5. Update workspace spec pages, run check + test:smoke ## Suggested Files or Specs To Inspect - `packages/workspace/src/lib/components/configuration/community-plugins.ts` - `packages/workspace/src/lib/components/configuration/core-plugins.ts` - `packages/workspace/src/lib/components/configuration/configuration.svelte` (settings shell reference for nav styling) - `packages/workspace/src/lib/components/tabs/tabs-split.svelte` (Resizable usage reference) - `packages/api/src/lib/lapis-extension.ts` (`LapisIndexedExtension`, `LapisContributionIndexEntry`) - `packages/api/src/lib/plugin-manager.ts` (`CommunityPluginDiagnostics`) - `spec/src/20-packages/workspace/index.md` (Community Plugins Tab section) - `spec/src/50-roadmap/complete-daily-use-app.md` ## Validation Commands ```bash pnpm --filter @lapis-notes/ui check pnpm --filter @lapis-notes/workspace check pnpm test:smoke make spec-lint ``` Manual: open Settings → Community plugins with `plugin-test` / indexed Lapis fixtures; verify Features tab sections, resize handle, scroll, and that re-render (toggle enable, restart) does not leak or duplicate panels. ## Follow-up Tasks - Embed the panel at the top of a plugin's dedicated settings view when opened from the gear button - Playwright e2e coverage for community-plugin diagnostics UI ## Implementation Summary Replaced flat plugin diagnostics with expandable inline features panels, added full-width feature expansion with Show Features fallback, and made command entries executable from the plugin features view. <!-- backlog:task_id=ROADMAP-009 source_spec=spec/src/50-roadmap/complete-daily-use-app.md -->
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lapis-notes/lapis#91
No description provided.