Skip to content

feat: add plugin navigation and custom permissions support#275

Merged
pikann merged 4 commits into
masterfrom
feature/add-plugin-navigation-and-custom-permission-support
Jul 15, 2026
Merged

feat: add plugin navigation and custom permissions support#275
pikann merged 4 commits into
masterfrom
feature/add-plugin-navigation-and-custom-permission-support

Conversation

@pikann

@pikann pikann commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Lets plugins contribute full, routed sidebar pages (not just embedded extension-point fragments) and declare their own permission keys that plug into the existing role editor and permission checks.

Changes

Plugin-owned pages (project.page / admin.page extension points)

  • New extension points let a plugin declare frontend.navItems[] in its manifest, each routing to a full-page component instead of an embedded <ExtensionPoint> fragment.
  • New routes /projects/:projectId/plugins/:pluginId/:slug and /admin/plugins/:pluginId/:slug render the matched component via RemoteComponent, with a load-failure fallback.
  • Sidebar renders these via new PluginProjectPages / PluginAdminPages in app-sidebar.tsx, sourced from usePluginRegistry().getNavItems().
  • resolvePluginIcon maps a manifest's lucide-react icon name to a component, falling back to a generic puzzle icon for typos/omissions.

Plugin-declared custom permissions

  • Manifest gains customPermissions[] (key/label/description/scope) so plugins can define permission keys beyond the built-in set (e.g. time_logging.manage_all).
  • These are merged into the project role editor under a synthetic "plugins" domain, labeled straight from the manifest since plugins can't reference host i18n keys.
  • New WASM host function paca.permission_check lets plugin backend code check a permission against the caller's effective project/global role — same resolution path as the requirePermissions route middleware — without a second host round-trip.
  • Fixed normalizePermissionsToWildcards to collapse permissions by their own key prefix instead of by UI domain. Multiple plugins share the synthetic "plugins" domain, so domain-based collapsing would've produced a bogus plugins.* key and over-granted every other plugin's permissions in that group.

Bug fix: plugin request query params were dropped

  • PluginHandler.ProxyRequest never read r.URL.Query(), so req.QueryParam(...) inside every plugin backend always saw an empty map — query-string-driven filtering/pagination was silently a no-op for all plugins. Now forwarded through HTTPRequest.Query.
  • Regression test: TestE2EPluginRuntime_APICall_QueryParamsPropagate.

Other

  • docker-compose.dev.yml: stop publishing Postgres's port 5432 to the host.
  • i18n: added plugins/projectPage/adminPage strings across all locales.

Testing

  • TestE2EPluginRuntime_APICall_QueryParamsPropagate (new e2e test covering the query-param fix)

pikann added 2 commits July 15, 2026 07:02
- Introduced new sidebar navigation items for plugins in both project and admin scopes.
- Enhanced plugin manifest to include custom permissions, allowing plugins to define their own permission keys.
- Implemented backend support for checking custom permissions via the `permission_check` function.
- Added routes for rendering plugin components in both project and admin contexts.
- Updated internationalization files to include new terms related to plugins in multiple languages.
- Refactored permission normalization logic to accommodate plugin-defined permissions.
- Improved query parameter handling in plugin requests to ensure they are forwarded correctly.
@pullfrog

pullfrog Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

See the formal review posted above for detailed feedback.

Pullfrog  | View workflow run | via Pullfrog | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

test body

Pullfrog  | Fix it ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

This PR introduces plugin navigation and custom permissions, but several gaps need addressing before merge: global-scoped custom permissions are not wired into the global role editor, the project role editor can miss plugin permissions on first open, the new admin and project plugin routes lack appropriate permission gates, and plugin-declared permission keys are not validated for collisions with built-in permissions.

Reviewed changes — plugin-contributed sidebar navigation for project and admin scopes, plugin-declared custom permissions surfaced in the project role editor, backend permission_check host function in the plugin runtime, and query-param forwarding for plugin HTTP routes.

  • Added project.page and admin.page extension points with TanStack Router routes and sidebar nav-item helpers in app-shell/app-sidebar.tsx.
  • Extended plugin manifests with navItems and customPermissions; wired project-scoped custom permissions into ProjectRoleFormDialog via collectPluginCustomPermissions/toPluginKnownPermissions.
  • Added backend paca.permission_check host function in internal/platform/plugin/runtime.go using the shared Authorizer.
  • Forwarded URL query parameters through PluginHandler.ProxyRequest and added an e2e regression test.
  • Updated i18n files for the new sidebar group and extension point labels across all supported locales.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Comment thread apps/web/src/lib/plugin-api.ts
Comment thread apps/web/src/components/projects/roles/ProjectRoleFormDialog.tsx
Comment thread apps/web/src/components/app-shell/app-sidebar.tsx Outdated
Comment thread services/api/internal/domain/plugin/entity.go
Comment thread deploy/docker-compose.dev.yml

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No critical issues — minor suggestions inline.

Reviewed changes — the new commits address all prior Pullfrog feedback:

  • Wired global-scoped custom permissions into the global role editor (RoleFormDialog) and added a synthetic plugins permission group, mirroring the project role editor.
  • Re-derived permission state in both role editors via useEffect when the dialog opens or allKnownPermissions changes, so plugin permissions loaded after mount are no longer silently dropped.
  • Filtered sidebar plugin pages by each nav item's requiredPermission and made the admin section render only when at least one visible plugin admin item exists.
  • Added route-level permission gates to the admin and project plugin pages, reading each nav item's requiredPermission (admin falls back to users.write).
  • Added PluginManifest.Validate() to enforce that custom permission keys are namespaced under the plugin's derived ID prefix.

ℹ️ Test coverage gaps

The only remaining carry-forward risk is missing automated coverage for the new behavior these incremental commits introduced: PluginManifest.Validate() namespace enforcement, route-level permission gates, and the existing paca.permission_check host function. Worth adding tests or a follow-up issue.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Kimi K2 (free via Pullfrog for OSS) | 𝕏

Comment thread apps/web/src/components/app-shell/app-sidebar.tsx
@pikann pikann merged commit ebf034b into master Jul 15, 2026
8 checks passed
@pikann pikann deleted the feature/add-plugin-navigation-and-custom-permission-support branch July 15, 2026 11:55
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.

1 participant