Skip to content

feat(shell): load SDK plugins and YAML navigation folders - #114

Open
imneov wants to merge 7 commits into
mainfrom
feat/installed-plugins
Open

imneov wants to merge 7 commits into
mainfrom
feat/installed-plugins

Conversation

@imneov

@imneov imneov commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

What type of PR is this?

  • feature
  • cleanup / refactor
  • documentation
  • install / chart
  • CI / tooling

What this PR does and why

Console now loads enabled built-in modules and separately delivered SDK frontends from one startup YAML tree. Operators control module order and nested menu directories through configuration. Built-ins resolve against the compiled registry; remote entries register their actual pages through the ModelSphere SDK. Permission filtering hides empty folders, active detail routes open their ancestors, and collapsed navigation retains descendant links.

Maintain the reusable SDK in web/packages/plugin-sdk as @modelsphere/plugin-sdk, with source attribution and compatible host-global aliases. The host shares its actual React, Router, Query, UI, locale and authenticated API transport. Plugin development uses Vite, the same-origin WebSocket proxy and the host React Refresh runtime; compatible component edits and new shared imports preserve local state. Production serves built JavaScript/CSS from a static-resource image.

The embedded YAML provides default built-in navigation. Explicit trees select only their listed modules; plugins: [] disables modules, and omitted/null configuration uses defaults. Legacy unmarked remote declarations retain default built-ins followed by remotes. Configuration changes require a backend restart and browser refresh; changing menu position or folders does not require rebuilding the plugin image.

Which issue(s) this PR fixes

Fixes #113

How it was tested

Check Result
Console types, tests, production build Passed; 58 files and 511 tests
SDK types, tests, standard build Passed; 14 files and 188 tests
Go formatting, full tests and vet Passed
Helm dependency build and strict lint Passed
External frontend types, bundle and tests Passed; 109 tests
External image build/publish Run 42192372759 succeeded
Browser development Real component edits and new shared imports updated through both proxies while preserving document identity and selected filter state
Browser static image Discovery, JS, CSS and provenance returned 200; the real bundle registered and rendered under host providers
Browser folders Nested collapse/expand, route-driven ancestor reopening and collapsed descendant links verified
Browser recovery Resource failure showed a plugin error with the shell usable; service restoration re-registered the plugin; empty configuration removed its entry

Browser component checks used web/test/plugin-runtime.html; authenticated business endpoints returned 401 in the anonymous test session. Screenshots and local environment configuration remain outside the repository.

Checks

  • go test ./..., go vet ./..., and changed Go files formatted
  • Web typecheck, tests and production build
  • SDK typecheck, tests and build
  • helm lint --strict helm/console
  • Architecture, startup example and development/deployment guide updated
  • No private business implementation, binary bundles or credentials committed

Notes for reviewers

Start with docs/development/plugins.md and the SDK/configured-navigation proposals in docs/plans/.

  • internal/config/default-plugins.yaml and navigation.go: default/legacy/explicit tree semantics and validation.
  • internal/server/plugin_service.go: tree discovery and resource-only proxying of remote leaves.
  • web/src/shell/plugin-tree.ts, plugins.ts, Sidebar.tsx: preflight mount collision checks, ordered loading and nested directories.
  • web/packages/plugin-sdk/src/dev.ts and dev-shared.ts: host runtime sharing and Vite Fast Refresh.

Discovery failures keep only the shell rather than enabling unconfigured modules. Remote load failures preserve other valid configured modules. Folder metadata changes neither page permissions nor business API authorization.

Release note

Console supports YAML-ordered built-in modules and remote SDK frontends with nested menu folders, Vite Fast Refresh for development, and static-resource image delivery. Omitted or null plugins uses the default modules; an explicit plugins: [] disables modules.

GitHub verification

Latest head: cc29e7a (includes navigation commit 4745dbc). CI 42247317988 and publish 42247318085 passed. PR #114 is conflict-free and awaiting an Approver review.

imneov and others added 3 commits November 3, 2026 17:56
Discover trusted package manifests at runtime and reuse ConsoleModule for menus, routes and overview cards. Share host React and shell providers without adding plugin management UI.

Fixes #113
@imneov imneov changed the title feat(shell): load installed frontend module packages feat(shell): add ModelSphere Plugin SDK with Vite HMR and image delivery Nov 6, 2026
Resolve built-in and remote modules through one startup navigation tree. Preserve sibling order, nested folders and existing page permissions; reject invalid declarations and mount collisions before executing remote entries.

Refs #113
@imneov imneov changed the title feat(shell): add ModelSphere Plugin SDK with Vite HMR and image delivery feat(shell): load SDK plugins and YAML navigation folders Nov 6, 2026

@huskcass huskcass left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blockers (design scope / existing UI behavior):

  1. Built-ins now depend on plugin discovery. main.tsx waits for /plugins/index.json before the first render, login included. In plugins.ts, a failed discovery returns modules: []. A remote menu.path that equals a built-in base path passes Go validation. validateFrontendPaths then throws in the outer try and drops every module, not just the bad remote; I checked this locally. On main, the five built-ins always render. Keep built-ins from the compiled registry no matter what happens to discovery. Reject built-in base paths in Go at startup. Let a failure affect only the remote that caused it.
  2. The vendored SDK is much larger than its one consumer needs. The canary frontend uses createPlugin, getBusiness().console, ./build and ./dev. These parts have no caller and no backend in Console:
    • cluster-resource-api (/oapis/resources.theriseunion.io)
    • scope-filter and cluster-display-name
    • create-instance
    • the SDK i18n channel and locales, and testing
    • slots, the event bus and the nav stub in core.ts, plus most of types.ts
      That is roughly 2.5k lines of source and tests. Host extras that only mirror that surface can go too: ScopeContext, getScope, get("auth"), apiClient, formatDate, and the __GLOBAL_SDK__/__RISE_SDK__ aliases. Keeping the SDK in a separate pnpm lockfile and CI job, beside the npm web project, doubles the toolchain for a private package. Trim it to the used surface and build it with the existing web job.
  3. The config tree has more modes than any current need. plugins doesn't exist on main, so the "legacy unmarked remote list" mode supports a format that was never released. Its browser branch is also dead, because Go stamps every leaf with a source. default-plugins.yaml duplicates modules/index.ts. source: builtin selection and nested folders have no requester today. Simpler: leave plugins unset for the compiled modules, and have each entry be a remote appended after them. Add folders or built-in selection when someone actually needs them.

Non-blocking:

  • The menu is declared twice. The plugin's createPlugin({ menus }) is ignored by the host, while the YAML has to repeat title, label, path and component. Pick one source.
  • Development mode (WebSocket hijack, Host/Origin forwarding) sits in the production proxy behind a values flag. The console Vite dev server could proxy /plugins/<id> straight to the plugin's Vite server instead. If it stays, keep development: true out of production values.
  • Each asset load waits up to 15s, one after another, before first paint. An unreachable plugin service delays the whole console.
  • The asset proxy forwards any relative path to the configured upstream, not only the declared entry and styles. That's fine for a static image, but worth restricting.

Verified at cc29e7a: go build, go vet and go test ./... pass, and web tsc -b and vitest pass (511 tests).

Verdict: loading one trusted remote frontend is justified, but trim to that before merge.

— Review Golden

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

design: Console plugin SDK and configured navigation folders

2 participants