feat: extensions — custom admin pages with sidebar navigation#572
feat: extensions — custom admin pages with sidebar navigation#572mohamedmostafa58 wants to merge 4 commits into
Conversation
🦋 Changeset detectedLatest commit: 6cf11bd The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
|
This would be cool! I hope we can add this. |
|
A lot of this could be done already with trusted plugins (which I'd like to rename something like native plugins): https://docs.emdashcms.com/plugins/sandbox/ |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
|
@ascorbic A few things trusted plugins currently cannot do:
Exposing Happy to go either direction. |
|
I am going to close this for now because features need a discussion first, but please do open a discussion instead. I will say I am skeptical: a lot of this could be accomplished with native plugins, custom PT blocks and/or Astro integrations. Look at the embeds plugin in the monorepo for an example. |
Extensions: Custom Admin Pages
Why
Plugins run in a constrained environment -- they interact with the CMS through hooks and a scoped API. Some use cases need direct database access, full Astro rendering, or custom server-side logic that does not fit the plugin model. Examples: static site export, analytics dashboards, bulk content tools, deployment management.
Extensions fill this gap. They are first-class Astro pages that live inside the project, have full access to Astro.locals (database, storage, auth), and appear as sidebar items in the admin UI.
Developer Experience
Configuration
File Structure
Extension Page
A standard Astro page with full access to the CMS runtime:
Sidebar Integration
Each extension appears in one of three sidebar groups based on the
groupfield:contentmanageadminThe admin UI renders a TanStack Router route at
/ext/$namethat loads the extension page in an iframe pointing to/_emdash/ext/{name}. This keeps the sidebar and header chrome visible while the extension has full control over its content area.How It Works
At build time, the integration validates each extension name against
/^[a-z0-9]+(?:-[a-z0-9]+)*$/, resolvessrc/extensions/{name}/page.astro, and callsinjectRouteto register it at/_emdash/ext/{name}.The serialized extension metadata (label, icon, group, URL) is baked into the virtual config module and included in the manifest response.
The admin sidebar reads extensions from the manifest and adds nav items to the appropriate group. Clicking an extension navigates to the TanStack Router route, which renders the iframe.
If
integration.tsexists, it is dynamically imported at build time and can inject additional routes or modify the Astro config.Security
/^[a-z0-9]+(?:-[a-z0-9]+)*$/. No dots, slashes, or special characters.startsWith(projectRoot)to prevent escaping the project root.Icon Mapping
Extensions specify icons by name. Currently supported:
rocketuploaddatabasegearlistglobeFalls back to Upload if the icon name is not recognized.
Extensions vs Plugins
Use extensions when you need full server-side control for site-specific tooling. Use plugins when building reusable functionality that other sites can install.