108 KiB
@emdash-cms/admin
0.29.0
Minor Changes
- #1524
d237e96Thanks @swissky! - Adds bulk actions to the content list. Select multiple entries with checkboxes (or the header "select all" box) and publish, set to draft, or move them to trash in one step.
Patch Changes
-
#1865
582ea2cThanks @khoinguyenpham04! - Fixes the admin dashboard scheduled-content summary so it counts entries with pending schedules instead of inferring the count from other statuses. -
#1865
582ea2cThanks @khoinguyenpham04! - Updates the admin dashboard and header with more consistent Kumo card styling, aligned loading and error states, and collection quick actions that open new entries directly. -
#1866
d2f5ddcThanks @khoinguyenpham04! - Updates admin UI status colors to use Kumo semantic tokens instead of hard-coded palette classes, so email settings, role and comment badges, content type indicators, the dashboard, and other status displays now theme consistently in both light and dark mode. Also fixes warning highlights in the marketplace audit badge and the plugin capability consent dialog, which previously referenced a nonexistent color token and rendered unstyled. -
#1720
9792226Thanks @segmentationfaulter! - Fixes OAuth provider login buttons (Google, GitHub) generating broken URLs on the admin login page. Non-admin/_emdash/paths are no longer routed through TanStack Router, which was incorrectly prepending the admin basepath and causing 404s. -
#1719
7c5de08Thanks @swissky! - Adds ataxonomies:readplugin capability with read-only taxonomy access: plugins that declare it getctx.taxonomiesto list taxonomy definitions (getAll()), fetch the terms of a taxonomy (getTerms()), and read the terms assigned to a content entry (getEntryTerms()) — in-process and in both sandbox runners. -
#1886
60811c0Thanks @swissky! - Adds atoolbarconfig option for reliable editor-toolbar delivery behind shared caches.toolbar: "client"keeps public HTML identical for every visitor and shows a client-side "Edit" pill for logged-in editors that opens a fresh, uncached editor render via an_editquery param;toolbar: falsedisables the toolbar entirely. The toolbar can now also be dismissed in the browser via its × button. The default ("server") is unchanged. -
Updated dependencies [
7c5de08]:- @emdash-cms/plugin-types@0.2.0
- @emdash-cms/registry-lexicons@0.2.0
- @emdash-cms/registry-client@0.3.3
- @emdash-cms/blocks@0.29.0
0.28.1
Patch Changes
- Updated dependencies []:
0.28.0
Minor Changes
-
#1849
b36d15cThanks @swissky! - Fixes "Worker exceeded resource limits" when importing large WordPress sites on Cloudflare. The plugin import now runs as a sequence of small requests — content pages, then comments, then menus and site identity — with a live progress bar instead of an indefinite spinner, and media files upload in bounded batches. An interrupted import can safely be re-run: already-imported content is skipped and the import fast-forwards to where it stopped. -
#1830
15b4d2dThanks @swissky! - Improves WordPress plugin imports: taxonomy terms and assignments (custom post type taxonomies are created as EmDash taxonomies automatically, scoped to the collections they map to), Yoast/Rank Math SEO titles and descriptions, ACF and custom meta fields (suggested as collection fields during analysis and populated on import), navigation menus, and comments (with authors, dates, threading, and approval status) are now imported. Site identity — title, tagline, logo, and favicon — is taken over from the WordPress site, replacing the starter template's placeholders. Internal links in imported content are rewritten to root-relative URLs so they stay on the new site instead of pointing back to the old WordPress domain. Fetches the full media library instead of the first 500 files, supports sites with plain permalinks via a?rest_route=fallback, and the import screen accepts a migration key generated by the EmDash Exporter plugin wizard.
Patch Changes
-
#1848
c1e2c3eThanks @dacoto! - Adds a Catalan (ca) locale catalog to the admin UI -
#1824
99b8a33Thanks @khoinguyenpham04! - Updates the media library controls, empty states, and asset details dialog for clearer media management, including provider asset deletion when supported. -
#1739
b6ba0d7Thanks @marcusbellamyshaw-cell! - Adds nested (parent/child) menu items to the admin menu editor. Items can now be assigned a parent via the edit dialog, are shown indented under their parent, and reorder buttons move an item relative to its siblings instead of the whole flat list. -
#1823
fd8ff27Thanks @khoinguyenpham04! - Updates admin settings success and error feedback to use Kumo toasts across settings pages. -
Updated dependencies []:
0.27.0
Patch Changes
-
#1713
8a93e1dThanks @ahliweb! - Updates Indonesian translations for the latest admin UI strings. -
Updated dependencies []:
0.26.0
Patch Changes
-
#1570
dc32673Thanks @marcusbellamyshaw-cell! - Fixes a crash on the content list when an action that refetches (changing the sort, fast navigation) coincides with a load error. Closes #1415. -
#1673
fe832ceThanks @ascorbic! - Fixes the code block language picker losing focus and closing as soon as you type in it. You can now type to filter and choose a language. -
Updated dependencies []:
0.25.1
Patch Changes
-
#1594
3960d49Thanks @ArtisanXL! - Add Turkish admin UI translations. -
Updated dependencies []:
0.25.0
Minor Changes
- #1657
e277989Thanks @swissky! - Adds search/typeahead toselectsub-fields inside repeater fields. Long option lists (for example taxonomy-derived options) are now filterable as you type instead of a plain scrolling dropdown.
Patch Changes
-
#1663
8c4108eThanks @scottbuscemi! - Fixes the pointer cursor not showing when hovering the "Log out" button in the admin user menu. -
#1627
1ad7b6dThanks @nemvalid! - Adds Hungarian translations for the admin UI. -
Updated dependencies []:
0.24.1
Patch Changes
- Updated dependencies []:
0.24.0
Patch Changes
-
#1630
f5566e8Thanks @ascorbic! - Fixes invisible primary buttons in the admin (notably "Sign in with Passkey" on the login page and "Register Passkey"), which could render as white text on a white background and leave passkey login unreachable by keyboard or sight. The admin's prebuilt stylesheet now matches the design-system version it ships against, so emphasis buttons paint their gradient background correctly. -
#1633
d063b51Thanks @khoinguyenpham04! - Fixes Kumo style loading and updates the admin sidebar to use Kumo's native collapse and theme behavior. -
#1568
43a70d4Thanks @marcusbellamyshaw-cell! - Fixes the publish controls not updating after editing a published post. Saving a change now immediately shows the "Publish changes" button, and publishing immediately switches it to "Unpublish" — previously, on sites without i18n configured, both required a manual page refresh. Closes #1557. -
Updated dependencies []:
0.23.0
Patch Changes
- Updated dependencies []:
0.22.0
Patch Changes
-
#1545
f4925b1Thanks @swissky! - Declare@tiptap/extension-drag-handle's collaboration peer dependencies@emdash-cms/adminuses@tiptap/extension-drag-handle, which declares@tiptap/extension-collaboration,@tiptap/y-tiptap(and transitivelyyjs,y-protocols) as peer dependencies. They were never installed because the collaboration feature is unused, and the admin bundle only worked because Rollup silently externalized the unresolved imports.Astro 7 switches Vite to Rolldown, which fails the build on unresolved imports instead of externalizing them, so the admin build breaks on this chain. Declaring it fixes the build under Rolldown/Astro 7 — and is correct dependency hygiene regardless of bundler. Closes #1544.
-
Updated dependencies []:
0.21.0
Minor Changes
- #1508
e9cd7b7Thanks @swissky! - Add a "Gone (410)" rule type. Redirect rules now support410(Content Deleted) and451(Unavailable For Legal Reasons) as terminal statuses — served directly with no destination — and the 404 log offers a one-click "Mark as Gone (410)" action next to "Create redirect". A 410 tells search engines a URL was intentionally and permanently removed, so it is deindexed faster than a 404.
Patch Changes
-
#1521
1b10c1dThanks @ascorbic! - Fixes the byline search box still blanking the page while you type. Searching now keeps the current results on screen as the new query loads, instead of collapsing into a full-page loader and dropping the input's focus on each settled keystroke. -
Updated dependencies []:
0.20.0
Minor Changes
-
#1427
acfeb89Thanks @swissky! - Media details show the file URL with a Copy URL actionThe media library previously exposed no way to obtain a file's URL — the detail panel now shows the absolute file URL (relative local-storage paths are resolved against the current origin) with a one-click copy button, so editors can paste media URLs wherever a URL field is needed.
-
#1425
3e344afThanks @swissky! - Repeater fields supportimagesub-fields with the media picker (#1424)Repeater rows previously rendered every non-scalar sub-field as a plain text input, so galleries had to be built from hand-pasted URLs. Image sub-fields now render the same media-picker UI as top-level image fields (select, preview, change, remove) and store the same MediaValue shape — legacy string URLs keep working.
Includes:
imagein the schema-builder sub-field type select, the sharedImageFieldRendererextracted out ofContentEditorfor reuse, and the sub-field type whitelists in core (REPEATER_SUB_FIELD_TYPES+ the API Zod enum) extended — the Zod enum also gains the previously missingurlentry that the builder already offered.
Patch Changes
-
#1447
141aa11Thanks @ascorbic! - Fixes@atcutepeer dependency warnings on install (#1435)Installing EmDash pulled in mismatched
@atcutepackage versions, sopnpm install/npm installreported unmet peer warnings for@atcute/identityand@atcute/lexicons. The bundled@atcutedependencies are now aligned on v2 and installs are clean. If your project also depends on@atcutepackages directly, note they have moved to v2 (@atcute/client5,@atcute/lexicons2,@atcute/atproto4,@atcute/oauth-node-client2). -
#1478
ddf8f0dThanks @pitscher! - Fixes localization for sections API fallback error messages in the admin UI -
#1473
68840a9Thanks @pitscher! - Fixes localization for the dashboard API fallback error message in the admin UI -
#1468
eaedec0Thanks @pitscher! - Fixes localization for the generic dialog error fallback in the admin UI -
#1465
8bb20c4Thanks @pitscher! - Fixes untranslated MediaPickerModal references for the library -
#1486
fb31240Thanks @ascorbic! - Adds an avatar image picker to the byline editor. TheavatarMediaIdfield was already part of the byline model and API but had no admin control, so byline avatars could only be set programmatically, and editing a byline through the UI cleared any avatar that had been set. You can now choose, change, and remove a byline's avatar from the editor. -
#1476
022fd66Thanks @pitscher! - Fixes localization for search API fallback error messages in the admin UI -
#1454
5d8358bThanks @pitscher! - Fixes untranslated ContentTypeEditor form text to let it be translatable -
#1499
ce96271Thanks @swissky! - Capitalize German status labels (published,scheduled,archived,pending) in the admin UI. As standalone badge labels these are nouns and should follow German capitalization (e.g. "publiziert" → "Publiziert"), matching the already-capitalized "Entwurf". -
#1470
b2e65acThanks @pitscher! - Fixes localization for media API fallback error messages in the admin UI -
#1475
589d07fThanks @pitscher! - Fixes localization for the current-user API fallback error message in the admin UI -
#1411
d6269e7Thanks @memdigital! - Adds an en-GB (British English) locale to the admin UI. British spelling and morphology only - terminology is unchanged. en-GB browsers are auto-selected via the existing Accept-Language resolution. -
#1477
325c673Thanks @pitscher! - Fixes localization for shared API fallback messages in the admin UI -
#1496
af4af50Thanks @ahliweb! - Fixes the remaining untranslated Indonesian admin strings. -
#1472
c48604bThanks @pitscher! - Fixes localization for settings API fallback error messages in the admin UI -
#1455
52ea731Thanks @pitscher! - Fixes untranslated PluginFieldErrorBoundary strings -
#1507
6c1fe5cThanks @ascorbic! - Speeds up browsing and searching large media libraries. The media library and the media picker now load small resized thumbnails through Astro's image endpoint instead of fetching every grid item's full-size original, so opening the library and searching for older items no longer waits on full-resolution downloads (#1488). Where no runtime image service is available the original is served as before, so nothing renders worse than it did. -
#1500
6246774Thanks @swissky! - Fix unreadable "Published" status badge in dark mode. The content editor rendered the published badge as<Badge variant="primary" className="text-white">, which produces white text on a light inverted background in dark mode. Use the semanticvariant="success"(green) instead, which is dark-mode aware and matches the green "published" badge used on the content overview list. -
#1461
b01aa9bThanks @ascorbic! - Fixes registry installs failing with "Plugin manifest has changed since you consented" for plugins that declare hook-registration capabilities (email transport, email events, page fragments) or read user records. Plugin bundles now declare their access as a structureddeclaredAccesscontract that the registry record, the install-consent dialog, and the sandbox all read consistently, so every capability a plugin declares is shown for consent and enforced — no capability is silently dropped. Re-publish affected plugins to adopt the new bundle format; existing installs are unaffected. -
#1471
5f7cd11Thanks @pitscher! - Fixes localization for email settings API fallback error messages in the admin UI -
#1469
263392fThanks @pitscher! - Fixes localization for plugin API fallback error messages in the admin UI -
#1466
eddadf8Thanks @pitscher! - Fixes localization for code block language labels in the admin editor -
Updated dependencies [
141aa11,b01aa9b]:- @emdash-cms/registry-client@0.3.2
- @emdash-cms/registry-lexicons@0.1.1
- @emdash-cms/plugin-types@0.1.0
- @emdash-cms/blocks@0.20.0
0.19.0
Minor Changes
- #1442
e96587fThanks @ascorbic! - Add status, author, and date-range filtering to the admin content list (#1288). The content list API gainsauthorId,dateField,dateFrom, anddateToquery params (all additive and optional), and a newGET /_emdash/api/content/{collection}/authorsendpoint lists the distinct authors of a collection's content (gated oncontent:read). Filtering runs server-side, so it works across the whole collection rather than only the loaded page.
Patch Changes
-
#1307
cedfcc5Thanks @emdashbot! - Forwardlocalequery param through admin content edit route, content list navigation links, and API client to resolve correct i18n variant for slug-based lookups (#1242) -
#1417
7e70abcThanks @emdashbot! - Fix taxonomy term edit dialog overflow with many locales (#1269)Adds
max-h-[85vh] flex flex-colto theTermFormDialogand makes its body scrollable withflex-1 overflow-y-auto, keeping the header and footer pinned. This prevents the Cancel/Update buttons from falling off-screen when the Translations panel lists a large number of locales. -
#1440
783e663Thanks @diogoascarneiro! - Add a visible WYSIWYG toolbar button for inserting HTML blocks, matching the existing/htmlshortcut. -
#1142
157237dThanks @OrangeManLi! - Fixes nested-list serialization in the Portable Text editor.convertListnow recurses into nestedbulletList/orderedListchildren and emits each block with the correctlevelvalue, so Tab-indented list items in the editor round-trip throughonChangeas real nested portable-text blocks instead of being flattened to a single top-level list with every item atlevel: 1. -
Updated dependencies []:
0.18.0
Patch Changes
-
#1384
d2829e3Thanks @ahliweb! - Updates the Indonesian admin catalog for the byline schema and custom-field management UI with formal, complete translations. -
Updated dependencies []:
0.17.2
Patch Changes
-
#1305
4ee75f8Thanks @eyupcanakman! - Fixes plugin admin pages showing a Plugin Error when opened from the Plugin Manager. The Settings gear opens a plugin at its root (/plugins/<id>/), but a plugin that registers its page at/settingsrather than/had no page there, so the admin fell through to a 404. Plugin page resolution now resolves the plugin root to the first registered page and treats/settingsand/settings/as the same path, so a single registration works from the Plugin Manager gear and the sidebar regardless of trailing slash. -
Updated dependencies []:
0.17.1
Patch Changes
-
#1342
83daa41Thanks @bergaaberg! - Adds Norwegian Bokmål (nb) locale to the admin UI. -
#1334
dfabafeThanks @theobaidur! - Honor theiconfield on pluginadminPagesin the sidebar nav.Plugin admin pages declared via
adminPages: [{ path, label, icon }]previously rendered with a hardcodedPuzzlePieceglyph — theiconfield was accepted in the types but never read at runtime. The sidebar now resolves the icon name to its@phosphor-icons/reactcomponent: common documented names (settings,chart,history,image,trophy, …) are statically mapped so they resolve synchronously, and any other name is matched against the full Phosphor set by converting it to PascalCase (e.g.chart-bar→ChartBar) and lazy-loading it from a code-split chunk. The full set is therefore reachable without bundling it into the admin's main chunk. Unknown or omitted names fall back toPuzzlePiece, so the change is purely additive. -
Updated dependencies []:
0.17.0
Minor Changes
-
#1258
28432b9Thanks @MohamedH1998! - Adds custom fields to bylines. Sites can define site-specific byline metadata (Twitter handle, pronouns, company, localised job title, etc.) via the new/byline-schemaadmin screen, accessed from the Byline schema link button at the top of the Bylines admin page (admin-only).Per-field
translatableflag picks whether values are stored per-locale (one value per locale row in atranslation_group) or shared across every locale variant of the same byline identity. Schema management is gated byschema:manage; value editing bybylines:manage.Custom-field values can be set at both create and update time.
POSTandPUTon/_emdash/api/admin/bylinesaccept the samecustomFieldsmap; the row write and the custom-field writes share a single transaction on Node/PG so a partial failure rolls both back. On D1 (no transactions), a retry POST is treated as completing an abandoned create iff three checks all pass: (a) every fixed column on the existing row matches the new payload (displayName,bio,avatarMediaId,websiteUrl,userId,isGuest, effective locale — null-vs-undefined normalised); (b) the existing row'stranslationGroupmatches what a fresh create with the same input would produce (sourceGroupwhentranslationOfis present,existing.idwhen it isn't); (c) every custom-field value already stored on the row appears in the input payload with an equal value (subset-match, so partial mid-loop crashes can be completed). The recovery branch is conservative on every axis: any fixed-column mismatch, any translation-group mismatch, any overlapping custom-field value mismatch, an input that omits a key the existing row stores, or an input with no custom fields at all → standardCONFLICT. Validation runs before any DB write so a bad value (unknown slug, type mismatch, select-choice miss, non-URL or non-http(s) URL for aurlfield) returns 400VALIDATION_ERRORwithout leaving partial state behind. In the admin, registered fields render inline with Name, Bio, etc. — no separate section header — and are available in the New byline dialog as well as edit.BylineSummarygains an optionalcustomFields: Record<string, CustomFieldValue>property. Existing object-literal consumers stay source-compatible because the property is optional and runtime always returns{}when no fields are registered.Hydration is symmetric with writes: rows are only applied to a byline when they live in the table matching the field's current
translatableflag, so stale rows from atranslatableflip can't leak into hydrated output. Schema mutations on/byline-schemainvalidate the samebyline-fieldsquery the byline form reads, so newly-registered fields appear in the editor without a page reload.urlfield values are parsed withnew URL(...)AND restricted tohttp:/https:schemes at write time so they can't shipjavascript:/data:/mailto:payloads to link rendering. TheBylineFieldEditor"Save" button stays disabled until aselectfield has at least one option; and select-option lists are accumulated on a null-prototype object so option values that collide withObject.prototypekeys render correctly.The field-definitions cache uses parity on
options.byline_fields_versionas a dirty bit: schema mutations flip the counter to odd before the write lands and to a new even value after, with the cache treating any odd version as "bypass the global holder, read fresh from the DB".markVersionDirtyis parity-aware (ensures odd, no-op if already odd) so a crashed prior attempt's leftover dirty state can't get inverted.markVersionCleanis always-advance (+2when starting even,+1when starting odd) so two concurrent mutators can't collapse on the same even key and pin the cache on a partial-set snapshot — every committed mutation produces an observable counter change for cache readers. Idempotent-retry exits (FIELD_EXISTSon create,FIELD_NOT_FOUNDon update/delete, no-op input on update) callmarkVersionCleantoo, which doubles as both the dirty-crash recovery and the false-clean recovery. All version writes useINSERT … ON CONFLICT DO UPDATEso a missing options row can't silently turn invalidation into a no-op.Implements #1174. Builds on the bylines-i18n foundation from #1146.
-
#1215
590b2f9Thanks @scottbuscemi! - First-class HTML block in the admin editor. The existinghtmlBlockPortable Text type (produced by the WordPress and Contentful importers) is now a fully editable block in the rich-text editor. Authors can insert an HTML block via the/htmlslash command and edit raw HTML in a textarea. ImportedhtmlBlockcontent that previously fell through to an opaquepluginBlockplaceholder is now rendered in the same editable UI. The inline (visual-editing) editor preserves HTML blocks as read-only placeholders to prevent data loss.
Patch Changes
-
#1297
cccf4f2Thanks @emdashbot! - Fix content entity editor block menu actions (Duplicate / Delete) not working when the drag handle sets a NodeSelection (#1261). -
#1225
886f2d1Thanks @scottbuscemi! - Add search to the byline picker on content entities and remove the effective 100-byline cap. The picker now performs a debounced server-side search via the bylines API instead of rendering a fixed dropdown of the first 100 results, so bylines beyond the first page can be found and credited. Credited bylines from the saved entry are also resolved from the entry itself, so a credit that falls outside the initial list still renders its name instead of disappearing. -
#1222
a5dafb3Thanks @scottbuscemi! - Fixes the byline search box reloading the whole page on every keystroke. The search term is now debounced (300ms) before it feeds the bylines query, and the full-page loader only takes over when there is no data yet (isLoading && !data) instead of on every new query key. Typing now stays responsive and keeps the input focused, matching the behaviour of the users page. The load-more snapshot and its filter-match check both use the debounced search value so appended pages are no longer discarded. -
#1226
9422d6aThanks @scottbuscemi! - Make content list search work on large collections (#1219). The admin content list previously filtered only the rows already loaded on the current page, so an entry far back in a big collection could not be found until you navigated near it. The list endpoint now accepts aqparameter and performs a case-insensitive substring search across the collection's title/name/slug columns server-side (LIKE wildcards in the query are escaped), and the admin search box drives that query (debounced) instead of filtering in memory. Also adds locale-aware composite indexes (idx_{table}_loc_upd/idx_{table}_loc_crt) so locale-filtered content lists stay index-served on large, i18n-enabled tables. -
#1224
67f5992Thanks @scottbuscemi! - Fix taxonomy terms not being locale-aware in the content editor (#1218). Term assignments are stored against the per-locale content row while the term'stranslation_groupspans every locale, so resolving terms for an entry must scope to the entry's locale. The content terms endpoint (/content/:collection/:id/terms/:taxonomy) now derives the entry's locale server-side and passes it togetTermsForEntry, and the adminTaxonomySidebarthreads the entry locale through its fetch/save calls (and into its React Query keys, so switching translations refetches). Previously a localized post showed and applied every locale variant of a tag instead of just the variant for its own locale. -
#1227
a40e455Thanks @scottbuscemi! - Add search and filtering to the media library (#1221). The media list endpoint now accepts aqparameter for a case-insensitive filename substring search (which also matches extensions, with LIKE wildcards escaped), alongside the existingmimeTypefilter. The Media Library page gains a filename search box and a type filter (images / video / audio / documents), and the media picker in the content editor now searches the local library by filename too. Previously neither surface could search or filter local media, which made large libraries hard to navigate. -
#1223
34afc14Thanks @scottbuscemi! - The rich-text editor formatting toolbar now stays pinned to the top of the editing area while scrolling through long posts, instead of scrolling out of view. The toolbar usesposition: stickyand the editor wrapper switched fromoverflow-hiddentooverflow-clipso corners stay clipped without creating a nested scroll container that would break sticky positioning. Distraction-free / minimal editors (e.g. Widgets) are unaffected since they don't render the toolbar. -
#1309
019d9e4Thanks @ahliweb! - Fix the remaining Indonesian admin translations. -
#1310
ba0f3d4Thanks @emdashbot! - Fix "Add Content" in the menu editor: the admin was sending the raw collection slug (e.g.pages) as the menu itemtype, which the API'smenuItemTypeEnumrejects with a 400. Map the picker's collection to the correct enum value (pages→page,posts→post, everything else →collection) so picking a page or post actually adds it to the menu. (#1173) -
#1290
aacdf20Thanks @SL33PiNg! - i18n(th): translate remaining untranslated Thai (ไทย) admin UI strings, including the newly-added plugin registry and Portable Text HTML-block strings -
#1245
7d55db6Thanks @SL33PiNg! - Adds Thai (ไทย) locale to the admin UI. -
Updated dependencies [
69bdc97]:- @emdash-cms/registry-client@0.3.1
- @emdash-cms/blocks@0.17.0
0.16.1
Patch Changes
-
#1277
2c36d55Thanks @ahliweb! - Completes the Indonesian translations for the admin UI and keepsidas the canonical locale code. -
#1278
930d23bThanks @ascorbic! - Fix admin sidebar rendering white text on a light background in light mode. Kumo 2.4 moved the sidebar surface to an inner container painted withbg-(--sidebar-bg), where--sidebar-bgis resolved from the wrapper's default (light)--color-kumo-base. The sidebar's dark-chrome override only set--color-kumo-base, which no longer reaches that surface, so the dark background was lost while the white text remained. The override now sets--sidebar-bgdirectly. -
Updated dependencies []:
0.16.0
Minor Changes
-
#1238
60c0b2eThanks @ascorbic! - Registry plugins can now declare environment requirements. A plugin's manifest may set a release-levelrequiresblock (e.g.{ "env:emdash": ">=1.0.0", "env:astro": ">=4.16" }), which is published into the release record. When browsing a registry plugin, the admin compares those constraints against the running EmDash and Astro versions: if the host doesn't satisfy them, it shows a compatibility warning and disables the Install button. The server enforces the same check on install and update, refusing an incompatible release withENV_INCOMPATIBLEso the gate can't be bypassed. -
#1239
1a4918fThanks @ascorbic! - Plugins published to the experimental registry can now ship icon, screenshot, and banner images. Declare them inemdash-plugin.jsoncunderrelease.artifactsas file refs;emdash-plugin publish --artifact-base-url <url>measures each image's dimensions, uploads it, and records it in the release. The admin plugin detail page renders the icon, banner, and a screenshot gallery, fetched through a server-side image proxy. The proxy resolves each artifact's URL server-side from the validated release record (the client sends only the artifact's coordinates, never a URL), then applies SSRF defences and an image content-type allowlist before serving the bytes. Supported image types are PNG, JPEG, WebP, GIF, and AVIF; SVG is rejected at both publish and proxy because it is active content. -
#1253
d2f2679Thanks @ascorbic! - The registry plugin detail page now surfaces a plugin's long-form profile sections. Publishers'description,installation,faq,changelog, andsecuritysections render as sanitized Markdown (the shared auditedrenderMarkdown— raw HTML, scripts, and images stripped, https-only links) in a tabbed view below the install action, with one tab per non-empty section. The page also shows an SBOM badge with the document format and a guarded direct download link (rendered only for safe http(s) URLs), the publisher-assertedlastUpdatedtime labelled distinctly from the aggregator'sindexedAt, and an accessible tooltip on the verified-publisher shield naming the labeller DID that issued the verification.
Patch Changes
-
#1257
62619c2Thanks @Rimander! - Completes the Spanish (Spain) admin translation, filling the 54 remaining untranslated strings across the plugin registry, SEO/social-image settings, the code-block editor, byline/content strings, and the capability-consent dialog. Thees-EScatalog is now fully translated. -
#1255
3d540daThanks @ascorbic! - Fix admin crash on authenticated load with @cloudflare/kumo 2.4.x (#1240). The sidebar was usingSidebar.GroupContentand group-levelcollapsible/defaultOpenprops, which were removed in kumo 2.4.0. The four nav sections (Content, Manage, Admin, Plugins) now render as plainSidebar.Groupblocks. The workspace catalog range for@cloudflare/kumois bumped from^2.3.0to^2.4.0to match. -
#1248
b89e988Thanks @mvanhorn! - Fixes the flat taxonomy tag picker so focusing an empty input shows available existing terms for the collection. -
#1244
4612749Thanks @pitscher! - Fixes admin UI translations for permission counts and action labels so languages can use their correct plural forms and word order -
Updated dependencies [
60c0b2e]:- @emdash-cms/registry-client@0.3.0
- @emdash-cms/blocks@0.16.0
0.15.0
Minor Changes
-
#1146
11b3001Thanks @MohamedH1998! - Adds first-class i18n support for bylines, mirroring the row-per-locale model already used by menus and taxonomies (PR #916, migrations 036).Schema (migration 040)
_emdash_bylinesgains two columns:locale—TEXT NOT NULL DEFAULT 'en'. Every row now belongs to exactly one locale.translation_group—TEXT NOT NULL. Shared across every locale variant of a single byline identity. The anchor row'stranslation_groupequals itsid; siblings inherit it.
A partial unique index
idx_bylines_group_locale_uniqueenforces one row per(translation_group, locale). The pre-existing(slug)unique index becomes(slug, locale)to allow the same slug across locales.Existing rows are backfilled to the configured
defaultLocale(or'en'if i18n isn't configured) withtranslation_group = id. Monolingual sites see no functional change; multilingual sites continue rendering the same byline data at the default locale until editors create translations.Credit hydration: strict per-locale
_emdash_content_bylines.byline_idnow stores the byline'stranslation_group, not its row id. When an entry is rendered, credits are filtered by joining the junction against the byline sibling whoselocalematches the entry'slocale. If no sibling exists at the entry's locale, the credit hydrates as empty — there is no fallback to other locales' bios.Author-inferred bylines (where an entry has no explicit credits but its author is linked to a byline) still fall back per-locale and respect the strictness gate: an entry with explicit credits at any locale will not infer from the author even if the explicit credits don't resolve at the rendering locale.
This is a deliberate behavior change for multilingual sites. The motivation is correctness: chain-walking credits across locales renders the wrong-language bio on translated entries.
The "explicit credit suppresses author fallback" check reads
primary_byline_iddirectly from the content row — set bysetContentBylinesiff junction rows exist, backfilled by migration 040 for pre-existing rows. No separate probe against_emdash_content_bylinesis needed at hydration time; the column is folded into the single per-entry context fetch (author_id+primary_byline_idin one query). Both monolingual and multilingual sites get the same query count.Identity lookups: chain-walk
getBylineBySlug(slug, { locale })walks the configured fallback chain (resolveLocaleChain), likegetMenuandgetTerm. Author pages for un-translated bylines still render an identity rather than 404'ing. This is conceptually distinct from credit hydration and runs throughrequestCachedfor per-render dedupe.Admin
- TranslationsPanel in the bylines editor lists every configured locale with Edit / Translate buttons. The Translate action POSTs to the new
POST /_emdash/api/admin/bylines/:id/translationsendpoint. - LocaleSwitcher on
/bylinesfilters the list strictly to one locale. Cross-locale navigation via TranslationsPanel routes through/bylines?locale=…. - The byline picker on the content editor is locale-pinned to the entry's locale. Editors only see bylines that will actually hydrate at the entry's locale.
- The byline credit empty state on a locale with no bylines yet shows a CTA linking to
/bylines?locale=…for inline creation. - Translating an entry (
POST /content/:collectionwithtranslationOf) callscopyContentBylinesto inherit the source's credits — these resolve at the new entry's locale via the strict-hydration model, so credits "follow" the content across translations once sibling bylines exist.
API additions
GET /_emdash/api/admin/bylines/:id/translations— list every sibling row sharing a translation_group.POST /_emdash/api/admin/bylines/:id/translations— create a sibling at a target locale. Body defaults (slug, displayName, websiteUrl, avatar) inherit from the source.POST /_emdash/api/admin/bylinesacceptstranslationOf+localeto create a sibling in one call.GET /_emdash/api/admin/bylines?locale=…filters strictly.BylineSummarygainslocale: stringandtranslationGroup: string | null(additive — existing consumers ignore the new fields).
Permissions
Two new entries on
@emdash-cms/auth:bylines:read— minimumSUBSCRIBER.bylines:manage— minimumEDITOR.
All byline routes (list, get, update, delete, translations) now check these instead of
content:read/Role.EDITOR. Role thresholds are unchanged, so existing users see no permission differences. Custom RBAC configurations that bind to the old strings should add the new permission names.Repository
BylineRepositoryis strict per-locale:findMany,findBySlug,findByIdaccept an optionallocaleand return rows matching that locale (or all locales when omitted, for the manager view).- New methods:
listTranslations(id),findByTranslationGroup(group),copyContentBylines(collection, fromId, toId). setContentBylinesdeduplicates bytranslation_groupafter resolving wire row ids, so passing two sibling row ids of the same identity collapses to one credit row.deleteis sibling-aware: removing one locale variant leaves siblings standing.
Notable trade-offs
- Strict hydration over chain-walking for credits. Chain-walking would render mismatched-language bios on translated content. The honest answer is to show nothing rather than the wrong thing; the picker tells editors which bylines will resolve at the entry's locale, and the empty-state CTA makes creating a sibling a one-click flow.
- Schema is row-per-locale, not a separate
byline_translationsside-table. Matches the existing content / menu / taxonomy convention so query patterns and indexes are consistent across the codebase.
-
#1176
fae97eeThanks @ascorbic! - Code blocks in the rich text editor now have an inline language picker. Hover over any code block to reveal a chip in the corner; click it to enter a language (free-form input with curated suggestions for ~30 common languages including TypeScript, Python, Bash, Rust, Astro, SQL, and more). Aliases resolve automatically -- typingtsstorestypescript,c++storescpp, etc. The existing markdown shortcut (typing```htmlfollowed by a space or Enter) continues to pre-populate the language. The chosen language persists on the Portable Textlanguagefield and is emitted as alanguage-{id}class on the rendered<pre>so frontend syntax highlighters can pick it up. The visual (in-place) editor gets the same picker UI. -
#1114
9a30607Thanks @ascorbic! - Plugins installed from the experimental registry can now be uninstalled and updated from the admin, the same way marketplace plugins always could. The "uninstall is not yet available for registry plugins" placeholder is gone — registry plugin rows now show the same Uninstall and Update buttons.The Plugins page's "updates available" indicator now covers registry plugins too. If the registry aggregator is unreachable, marketplace updates still load (and vice versa).
Updates that need newly-declared permissions, or that newly expose a public (unauthenticated) route, prompt for re-consent before installing the new version — matching the gate that marketplace updates already have.
-
#1125
d0ff94bThanks @ascorbic! - Adds a version picker to the registry plugin detail page. Older releases of a registry-hosted plugin are now selectable from a dropdown next to the Install button, and the displayed version, indexed date, permissions, and source link swap to match the selected release. Pre-release versions (e.g.1.0.0-alpha.1) are flagged with a "Pre-release" badge so admins can spot them before installing. Versions still inside the configured minimum-release-age holdback remain visible in the dropdown but stay non-installable until they age into the window.
Patch Changes
-
#1177
b9cc08eThanks @ascorbic! - Bumps@cloudflare/kumofrom 1.16 to 2.3. Two internal call sites picked up breaking API changes from Kumo 2.0:Collapsibleis now a compound component (Collapsible.Root/.DefaultTrigger/.DefaultPanelinstead of<Collapsible label=...>), used by the accordion block; andChartPalette.color()was renamed toChartPalette.categorical()in the chart block. No public API changes -- consumers see identical behaviour. Tests in@emdash-cms/adminthat asserted onButton's nativetitleattribute now readaria-labelinstead, because Kumo 2 wraps<Button title>in a Tooltip popup rather than setting the DOM attribute. -
#1119
393dd26Thanks @adentdk! - Fixes auto-save not detecting plugin block field changes. When editing an existing block's attributes via the Block Kit modal, the change now correctly triggers TipTap'sonUpdatecallback, propagating through to the auto-save dirty detection. -
Updated dependencies [
cf3c706,b9cc08e]:- @emdash-cms/registry-client@0.2.0
- @emdash-cms/blocks@0.15.0
0.14.0
Minor Changes
- #1112
3756168Thanks @ascorbic! - Renders the full registry package profile in the admin. The plugin detail page now shows the license (linked to spdx.org for single SPDX identifiers), keywords, all authors, all security contacts, and a link to the source repository. The browse cards show the license alongside the description.
Patch Changes
-
#1101
e539731Thanks @ascorbic! - Fixes experimental registry navigation and allows the configured registry aggregator through the admin CSP. -
Updated dependencies [
3756168]:- @emdash-cms/registry-client@0.1.0
- @emdash-cms/blocks@0.14.0
0.13.0
Minor Changes
-
#1052
0d5843fThanks @Rimander! - Fixes menu REST API consistency:POST /menus/:name/itemsno longer accepts unknown keys silently. Sendingcustom_url(snake_case) orurlused to return 201 withcustom_url: nullbecause Zod's default.strip()quietly dropped them. The schemas now use.strict()and return 400VALIDATION_ERRORwithUnrecognized key: "custom_url". The documented camelCase keys (customUrl,sortOrder,referenceCollection, etc.) are unchanged and persist as before. Thetypefield is now validated against the canonical enum ("custom" | "page" | "post" | "taxonomy" | "collection"); previously any string passed.- Moves per-item writes to
PUTandDELETE /menus/:name/items/:id(path-style). Every other EmDash resource (content,taxonomies,redirects,sections,widget-areas) addresses items by URL path; menus were the lone outlier requiring?id=<id>in the query string. The legacy query-string form is removed (it was undocumented and only used by the admin, which is updated in this PR). Callers should usePUT /menus/:name/items/:id/DELETE /menus/:name/items/:id. - Menu and menu-item API responses are now camelCase, aligning with the rest of EmDash's REST surface (
content,taxonomies,redirects, …).created_at→createdAt,updated_at→updatedAt,menu_id→menuId,parent_id→parentId,sort_order→sortOrder,reference_collection→referenceCollection,reference_id→referenceId,custom_url→customUrl,title_attr→titleAttr,css_classes→cssClasses,translation_group→translationGroup. Breaking for direct REST consumers that depend on snake_case keys in the response body. The admin UI is already updated. - Refactors menus to the standard repository pattern. Adds
MenuRepositorynext toContentRepository,TaxonomyRepository,RedirectRepository,MediaRepository,CommentRepository. Handlers become thin orchestrators; the repository is now the single place where snake_case rows become camelCase entities.
These changes do not touch any database schema or migration. Existing data is preserved.
-
#1011
dbaea9cThanks @ascorbic! - Adds experimental support for the decentralized plugin registry (see RFC #694). Configure withexperimental.registry.aggregatorUrlinastro.config.mjs; the admin UI then uses the registry instead of the centralized marketplace for browse and install. Marketplace behavior is unchanged when the option is not set.The experimental config accepts a
policy.minimumReleaseAgeduration (e.g."48h") that holds back releases below that age from install and update prompts, with apolicy.minimumReleaseAgeExcludeallowlist for trusted publishers or specific packages. The minimum-release-age check is enforced both client-side (for UX) and server-side (in the install endpoint), so stale browser tabs and deep links still hit the gate.
Patch Changes
-
#751
05440b1Thanks @edrpls! - Fix the admin collection list pagination denominator so it no longer grows in increments of 5 as the user pages forward.The
GET /_emdash/api/content/{collection}response now includes atotalfield with the full filtered row count (independent oflimit). The admin uses it as the pagination denominator, so a 143-entry collection reads1/8on page 1 instead of1/5 → 5/10 → 10/15 → …as successive API pages load.The
totalfield is optional; pre-upgrade clients that ignore it still work, and the admin falls back to the loaded-item count when an older server doesn't return it.Also handles the edge case where the current page exceeds
totalPagesafter filtering or deletion — the admin clamps the active page so the table doesn't render empty while waiting for a refetch. -
#1050
484e7abThanks @wojtekpiskorz! - Fixes broken image collapsing media picker container — addsonErrorhandler and fallback placeholder so Change/Remove buttons remain accessible when referenced image is missing from storage -
#1013
0cd8c6dThanks @ascorbic! - Fixes the slash command menu's initial selection getting overridden when the menu opens under a stationary pointer. The menu items previously reacted tomouseenterunconditionally, so an item rendered beneath the cursor would steal selection from the keyboard default before any user interaction. Mouse-hover-selects still works, but only after the user actually moves the pointer over the menu. -
#1020
d014b48Thanks @ahliweb! - Adds missing Indonesian (id) translations for SEO settings labels and replaces "Edit" with "Sunting" and "Tagline" with "Slogan" across the admin UI. -
Updated dependencies []:
0.12.0
Minor Changes
-
#997
7b45cbaThanks @ascorbic! - Adds support for a site-wide default Open Graph image. The setting is exposed in the admin SEO settings page (Settings -> SEO -> Default Social Image), resolved to a URL on read bygetSiteSettings(), and automatically emitted asog:image/twitter:image(and BlogPosting JSON-LDimage) byEmDashHead.astrowhenever a page has no image of its own. Per-page images still take precedence.This wires up an existing data model that was previously defined in the schema and MCP tools but never used: stored values were not resolved and no template path read the setting.
Emitted URLs are absolutized using
SiteSettings.url, the page'ssiteUrl, or the request origin so crawlers and JSON-LD consumers that reject relative URLs work correctly.Also adds a
localOnlyprop toMediaPickerModalthat suppresses the "Insert from URL" input and external provider tabs. Used by SEO settings to ensure the picker only returns locally-stored media (since the setting only persists a localmediaId).Media metadata updates and deletes now invalidate the worker-scoped site-settings cache, so resolved logo/favicon/default-social-image URLs and dimensions stay in sync with the underlying media row.
Patch Changes
-
#996
19576beThanks @r2sake! - Fix media library admin page and the media picker modal (used by the rich text editor and image fields when embedding media into content) to support libraries larger than 50 items by wiring up cursor-based infinite scroll (mirrors the content list fix from #135) -
#1004
35791ffThanks @ascorbic! - Fixes a stale ref race in the slash command menu's keyboard handlers. The state ref was synced viauseEffect(post-commit), so TipTap's Suggestion plugin could read stale state when invokingonKeyDownsynchronously -- causing Enter to occasionally fail to execute commands and arrow navigation to skip selections on slower runs. -
Updated dependencies []:
0.11.1
Patch Changes
- Updated dependencies []:
0.11.0
Minor Changes
-
#942
7c536e5Thanks @MA2153! - Adds per-field allowed MIME types forfileandimagefields. Field-levelallowedTypesis now honored end-to-end: it filters the media picker, widens upload acceptance for that field (so e.g. a zip-only field can accept zip uploads even though the global allowlist excludes them), and validates referenced media against the destination field on content save. The schema editor in admin gains an "Allowed types" control with curated presets and freeform entry.Behavior change: the
imagebuilder'sallowedTypesoption was previously accepted but read by nothing. It is now load-bearing — a code-first schema that already passedallowedTypes(e.g.["image/png"]) will now actually narrow the picker and gate uploads. Most users will see no change; if you set this option intending the old (silent) behavior, drop it.Behavior change: updating a field via the admin schema editor now explicitly clears its validation when the form contains no validation settings, instead of leaving an existing
validationvalue intact. This only affects fields with pre-existing validation that is not expressible in the editor UI. -
#921
530b013Thanks @jcheese1! - Adds table support to the PortableText editor. Users can now insert and edit tables via the slash command menu (/table) or toolbar button. Tables support header rows, column/row insertion and deletion, and include a bubble menu for quick editing.
Patch Changes
-
#958
7f6b6eaThanks @ascorbic! - Fixes admin lists, tables and info cards rendering as transparent against the page background. Card containers in the content list, content type list, content type editor, media library, comments, users and device authorization views now have an explicitbg-kumo-basesurface so they're visually distinct from the body.Also fixes column header labels in content list tables ("Title", "Status", etc.) rendering pale because of an undefined Tailwind class (
text-kumo-fg) -- they now use the default text color and rely on the sort indicator icon to signal active state. -
#952
131bea6Thanks @ascorbic! - Replaces 20 raw<input type="checkbox">elements across the admin UI with Kumo'sSwitchandCheckboxcomponents. Single-boolean toggles (SEO, Enable comments, Required, etc.) becomeSwitch; multi-select / list-context checkboxes (collection multi-select, term tree nodes) becomeCheckbox. Drops manual styling and label markup that duplicated what the Kumo components provide built-in. -
#956
54b5aa1Thanks @CacheMeOwside! - Fixes broken checkboxes on the comments moderation page (/_emdash/admin/comments). Selecting a comment threw a JavaScript error and did not select the row. -
#934
c630e31Thanks @ascorbic! - Fixes button and link inconsistencies across the admin UI. Standardises on Kumo'sButtoniconprop andLinkButton(withexternalfor new-tab links) instead of manual icon spacing and raw anchor styling, removes a<Link><Button>invalid HTML nesting in the plugin manager, and translates two stray English strings in the user list empty state. -
#949
7aa1897Thanks @ascorbic! - Fixes invalid<a><button>HTML produced by<Link><Button>...</Button></Link>patterns across the admin UI. Introduces aRouterLinkButtoncomponent that wraps TanStack Router's<Link>with Kumo button styling (variant,size,shape,iconprops), and migrates all existing<Link className={buttonVariants(...)}>usages to use it. Extracts the duplicated "Back to settings" header link into a sharedBackToSettingsLinkcomponent. -
#940
0b8a319Thanks @ascorbic! - Fixes the long tail of untranslated English strings in the admin UI: settings panels, marketplace, sandboxed-plugin host, auth flows, taxonomy/menu management, and lib/api fallback messages. After this PR, EmDash admin UI is fully localizable across all known surfaces. -
#957
13ff061Thanks @ascorbic! - Fixes the OG image picker in the content editor only appearing for collections with a field literally namedfeatured_image. The OG image control now lives in the SEO sidebar panel alongside the other SEO fields, so any collection withseoenabled can set a social preview image regardless of whether it has a featured image field. -
#955
49b66d9Thanks @ascorbic! - Removes the sticky editor header from content / content-type / section / settings pages. The sticky implementation had transparency artifacts (backdrop-blur over varied content), layout fragility (negative margins canceling parent padding), z-index conflicts with the app bar, and ~85px of permanent vertical chrome. Each editor now renders a Save button at the bottom of the form so users can save without scrolling back to the top header. The distraction-free hover-overlay header in the content editor is preserved. -
#966
1b2fa77Thanks @ahliweb! - i18n(id): complete Indonesian translation (320 strings) -
#937
af15975Thanks @ascorbic! - Fixes ~250 untranslated English strings in the admin UI's most-used screens (router toasts, content type editor, widgets, byline and user routes, invite-accept flow, portable text editor toolbar, image and embed editor nodes, user list). Alltitle=,aria-label=,placeholder=, and toast messages in these areas now flow through Lingui. -
#950
a4968c1Thanks @ascorbic! - Replaces raw<select>and<input type="search">elements across the admin UI with Kumo'sSelectandInputcomponents. This gives consistent styling, proper focus rings, accessibility (label association via the Field wrapper), and dark-mode handling for free instead of relying on hand-rolled Tailwind classes that bypassed the design system. -
#973
f80fb58Thanks @ahliweb! - Translates the remaining untranslated string in the Indonesian locale, bringing it to 100% coverage. -
Updated dependencies []:
0.10.0
Patch Changes
-
#719
2e2b8e9Thanks @ascorbic! - Fixes thefilefield type rendering as a plain text input in the content editor. Adds aFileFieldRendererthat opens the media picker (with mime filter disabled) so any file type can be attached. Also adds ahideUrlInputprop toMediaPickerModalso non-image pickers can hide the image-specific "Insert from URL" input.Aligns the Zod schema and generated TypeScript types for
imageandfilefields with the shape the admin actually stores:provider?,meta?(for both), andpreviewUrl?(for image). Previously these fields were stripped on validation and missing from generated types, so site code could not reliably resolve local media URLs frommeta.storageKey. -
Updated dependencies [
5eb4318]:
0.9.0
Minor Changes
-
#731
9dfc65cThanks @drudge! - Adds amedia_pickerBlock Kit element: a thumbnail preview with a modal library picker and mime-type filter. Usable in plugin block forms and in Block Kit field widgets. The stored value is the selected asset's URL string, so it is value-compatible with a plaintext_input— existing content continues to work after swapping. Themime_type_filteris restricted to image MIME types (image/orimage/<subtype>); wildcards and non-image types are rejected. -
#809
e7df21fThanks @ascorbic! - Adds an optionalcategoryfield toPortableTextBlockConfigfor plugin-contributed block types. Plugins can now choose how their blocks are grouped in the admin slash menu (e.g. "Sections", "Marketing", "Media", "Layout") instead of always falling under "Embeds". Existing plugins that omit the field continue to render under "Embeds" exactly as before. -
#814
a838000Thanks @arashackdev! - rtl srtyle improvements and LTR/RTL compatible arrow/caret icons -
#854
491aeecThanks @ask-bonk! - Adds consistently-placed sticky Save buttons across editor pages so unsaved changes are always visible. The Content editor, Section editor, Content Type editor, and Settings sub-pages (General, SEO, Social Links) now render their primary save action in a sticky top-right header that stays visible while users scroll long forms. The existing bottom-of-form save buttons are preserved so keyboard and screen-reader users still hit a save action as the last interactive control on the page (DOM order is unchanged). Introduces a sharedEditorHeadercomponent for editor pages that want the same sticky-header pattern. Fixes #233.
Patch Changes
-
#849
d6754aeThanks @drudge! - Fixes thedatetimefield widget so existing values display in the editor and new values pass server validation. The widget passed raw ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ) into<input type="datetime-local">, which silently rendered empty, and emittedYYYY-MM-DDTHH:mmon save, which the field's zod schema rejected. Strips the suffix for display, appends:00.000Zon save, and normalizes date-only stored values to UTC midnight for the input. Applies to the top-leveldatetimewidget in the content editor and thedatetimesub-field type insideRepeaterField. -
#702
0ee372aThanks @ilicfilip! - Adds@emdash-cms/plugin-field-kit— composable field widgets forjsonfields. Four widgets (object-form,list,grid,tags) are configured entirely through seedoptionsso site builders don't need to write React to get a usable editing UI. Widgets store clean JSON (no nesting, no mutation of shape), so removing the plugin leaves valid data in the database. See discussion #571 for background.Widens
FieldDescriptor.optionstoArray<{ value: string; label: string }> | Record<string, unknown>so plugin widgets can accept arbitrary widget config (not only enum choices). The array shape forselect/multiSelectcontinues to work unchanged. -
#856
ef3f076Thanks @ask-bonk! - Fixesnpm installpeer dependency conflicts (#819) by removingreactandreact-domfromdependencies. They were declared in bothdependenciesandpeerDependencies, which made npm think the admin package required an exact pinned React version and conflicted with the host Astro app's React. They remainpeerDependencies(^18.0.0 || ^19.0.0), and the host app supplies React. -
#821
8d0feb3Thanks @r2sake! - Fixes the Settings (gear) icon on the Plugin Manager so it links to the plugin's primary admin page instead of a non-existent/settingssub-route. -
#862
8354088Thanks @ask-bonk! - Fixes slug-style<input pattern="...">attributes so HTML form validation works in current browsers. The patterns used[a-z0-9-]+, which is rejected asInvalid character classwhen compiled with thev(unicode-sets) flag — the mode browsers now use for thepatternattribute. The dangling-is now escaped ([a-z0-9\-]+), restoring slug validation in the Sections list/edit, Menus list, and Widgets create-area dialogs. Resolves #845. -
#887
254a443Thanks @ascorbic! - Fixes stale content shown in the Portable Text editor when switching between translations of the same content. Previously, navigating from one locale's editor to another (e.g. from the English version of a post to the French version) kept the previous locale's body in the editor, and any subsequent edit would silently overwrite the new translation's content. The form now resets synchronously when the underlying content item changes, and field editors are keyed by item id so they remount cleanly on a translation switch. -
#885
25128b2Thanks @ahliweb! - Fixes malformed ICU plural syntax in Indonesian (id) locale — ContentList item count now renders correctly -
#872
ab45916Thanks @ahliweb! - Enables Indonesian (Bahasa Indonesia) locale in the admin UI -
#807
0913a39Thanks @ascorbic! - Sizes the plugin block edit modal based on field complexity so Block Kit forms have room to breathe. Simple URL embeds keep the previous compact dialog; forms with several fields get a wider one, and forms containing a repeater open at the largest size. Inputs inside the dialog now fill the available width. -
#815
ddbf808Thanks @ascorbic! - Fixes content list loading state showingNo results for ""instead of a loader while items are being fetched. The trash tab gets the same treatment. -
#870
1c958fbThanks @CacheMeOwside! - Fixes the image-settings icon in the Section editor so it actually opens<ImageDetailPanel>in the sidebar. -
#816
d4be24fThanks @ask-bonk! - Unifies plugin capability names under a single<resource>[.<sub-resource>]:<verb>[:<qualifier>]formula so capabilities read like RBAC permissions, separates hook-registration permissions from data-access ones for clearer audits, and replaces the overloaded:anyqualifier with the more conspicuous:unrestricted. Old names are still accepted with@deprecatedwarnings;emdash plugin bundleandemdash plugin validatewarn for each deprecated name andemdash plugin publishrefuses manifests that still use them.The Cloudflare sandbox bridge and HTTP fetch helper now enforce canonical names (
content:read,content:write,media:read,media:write,users:read,network:request,network:request:unrestricted). Manifests that still declare legacy names continue to work — the runner normalizes capabilities before passing them into the bridge, so installed plugins withread:contentresolve tocontent:readand reach the same code path.Old New read:contentcontent:readwrite:contentcontent:writeread:mediamedia:readwrite:mediamedia:writeread:usersusers:readnetwork:fetchnetwork:requestnetwork:fetch:anynetwork:request:unrestrictedemail:providehooks.email-transport:registeremail:intercepthooks.email-events:registerpage:injecthooks.page-fragments:registerExisting installs keep working — manifests are normalized at every external boundary and
diffCapabilitiesnormalizes both sides so version upgrades that only rename do not trigger a "capability changed" prompt. Deprecated names will be removed in the next minor. -
Updated dependencies [
7b8d496,9dfc65c,a838000]:- @emdash-cms/blocks@0.9.0
0.8.0
Minor Changes
-
#679
493e317Thanks @drudge! - Adds arepeaterBlock Kit element: array-of-objects with scalar sub-fields, drag-to-reorder, and collapsible item cards. Plugin block forms can now capture repeating data (FAQ rows, carousel slides, card grids) inline in the portable-text editor. -
#779
e402890Thanks @ascorbic! - Addssettings_getandsettings_updateMCP tools so agents can read and update site-wide settings (title, tagline, logo, favicon, URL, posts-per-page, date format, timezone, social, SEO).settings_getresolves media references (logo/favicon/seo.defaultOgImage) to URLs;settings_updateis a partial update that preserves omitted fields. Newsettings:read(EDITOR+) andsettings:manage(ADMIN) API token scopes back the tools, with matching options in the personal API token settings UI. -
#398
31333dcThanks @simnaut! - Adds pluggable auth provider system with AT Protocol as the first plugin-based provider. Refactors GitHub and Google OAuth from hardcoded buttons into the sameAuthProviderDescriptorinterface. All auth methods (passkey, AT Protocol, GitHub, Google) are equal options on the login page and setup wizard.
Patch Changes
-
#611
86b26f6Thanks @drudge! - Wires up the block configuration sidebar insideWidgetEditor.PortableTextEditornow receivesonBlockSidebarOpen/onBlockSidebarClosecallbacks that hold the activeBlockSidebarPanelin local state, and rendersImageDetailPanelwhen the panel type is"image"— mirroring the content-entry editor. Without this, clicking a block's settings button or the media picker inside widget content had no visible effect. -
#786
e998083Thanks @smart-cau! - Adds Korean translations for 21 admin UI strings that previously fell back to English. Korean (ko) coverage is now complete. -
#670
37ada52Thanks @segmentationfaulter! - Change text direction of input fields and tiptap editor depending upon the language entered -
#720
acab807Thanks @Pouf5! - Fix taxonomies not nesting correctly in a RTL layout -
#750
0ecd3b4Thanks @edrpls! - Make the admin collection list column headers sortable.Title,Status,Locale, andDateare now clickable buttons that toggle direction; the current sort state is exposed viaaria-sorton the<th>so screen readers announce it correctly.The server's
orderByfield whitelist now acceptsstatus,locale, andnamealongside the existing date fields — unchanged from a security standpoint, the repo still rejects unknown field names to prevent column enumeration.Callers of
<ContentList>that don't passonSortChangerender the previous static-label headers, so legacy integrations (e.g. the content picker) are unaffected. -
#184
4c9f04dThanks @masonjames! - Fixes plugin block defaults so initial values are seeded without overriding later edits. -
#700
ed4d880Thanks @dcardosods! - Prefill site title and tagline in Setup Wizard from seed file -
Updated dependencies [
6e0e921,493e317]:- @emdash-cms/blocks@1.0.0
0.7.0
Minor Changes
- #705
8ebdf1aThanks @eba8! - Adds admin white-labeling support viaadminconfig inastro.config.mjs. Agencies can set a custom logo, site name, and favicon for the admin panel, separate from public site settings.
Patch Changes
-
#680
2e4b205Thanks @CacheMeOwside! - Fixes dark mode toggle having no effect with the classic theme. -
#732
e3e18aaThanks @jcheese1! - Fixes select dropdown appearing behind dialog by removing explicit z-index values and addingisolateto the admin body for proper stacking context. -
#647
743b080Thanks @arashackdev! - Adds Persian (Farsi) locale with full admin translations. Adds Vazirmatn as the default font family for Farsi. -
#689
fa8d753Thanks @edrpls! - Fixes the taxonomy term picker to match across diacritic boundaries.Typing
Mexicoin the admin picker now surfaces a term labeledMéxicoinstead of prompting a duplicate create. Input and term labels are folded via NFD decomposition + lowercase before substring-matching, so editors who type without diacritics — or with locale keyboards that produce precomposed vs. combining forms — still see the canonical term.Before this fix,
"mexico"and"méxico"were treated as distinct strings, so the picker showed zero suggestions and the editor had no way to find the existing term except to create a duplicate. Duplicate terms then split the taxonomy and broke public-facing filter pages that group content by slug.The exact-match check that gates the "Create new term" button uses the same fold, so typing
MexicowhenMéxicoexists also suppresses Create — closing the duplicate-creation loop. -
Updated dependencies []:
- @emdash-cms/blocks@0.7.0
0.6.0
Minor Changes
- #565
913cb62Thanks @ophirbucai! - Adds full RTL (right-to-left) support to the admin UI by converting all directional Tailwind classes to their direction-aware equivalents.
Patch Changes
-
#610
dfcb0cdThanks @drudge! - Passes plugin block definitions into thePortableTextEditornested insideWidgetEditor, so custom plugin-registered block types (image blocks, marker blocks, etc.) can be inserted and rendered inside content-type widgets. The manifest is fetched with react-query in the top-levelWidgetscomponent, flattened into aPluginBlockDef[]list, and threaded throughWidgetAreaPanel→WidgetItem→WidgetEditor. -
#568
cf63b02Thanks @Vallhalen! - Fix document outline not showing headings on initial load. The outline now defers initial extraction to next tick (so TipTap finishes hydrating) and also listens for transaction events to catch programmatic content changes. -
#564
0b32b2fThanks @ascorbic! - Replaces the horizontal language-switch button bar on the admin login page with a dropdown, so the selector stays usable as more locales are added. -
#592
6c92d58Thanks @asdfgl98! - Adds Korean locale support to the admin UI. -
#559
a2d5afbThanks @ayfl269! - Adds Chinese (Traditional) translation for the admin UI, including login page, settings page, and locale switching. -
#604
39d285eThanks @all3f0r1! - Fixes loading spinner not centered under logo on the login page. -
Updated dependencies []:
- @emdash-cms/blocks@0.6.0
0.5.0
Minor Changes
- #551
598026cThanks @ophirbucai! - Adds RTL (right-to-left) language support infrastructure. Enables proper text direction for RTL languages like Arabic, Hebrew, Farsi, and Urdu. Includes LocaleDirectionProvider component that syncs HTML dir/lang attributes with Kumo's DirectionProvider for automatic layout mirroring when locale changes.
Patch Changes
-
#489
9ea4cf7Thanks @all3f0r1! - Adds JSON field editor in admin UI content forms -
#542
64f90d1Thanks @mohamedmostafa58! - Fixes invite flow: corrects invite URL to point to admin UI page, adds InviteAcceptPage for passkey registration. -
Updated dependencies []:
- @emdash-cms/blocks@0.5.0
0.4.0
Minor Changes
Patch Changes
-
#490
3a96aa7Thanks @all3f0r1! - Fixes mobile sidebar nav sections not displaying their pages -
#87
c869df2Thanks @txhno! - Fixes SEO sidebar text fields firing a PUT on every keystroke by debouncing saves; guards against stale server responses overwriting newer local edits. -
#302
10ebfe1Thanks @ideepakchauhan7! - Fixes autosave form reset bug. Autosave no longer invalidates the query cache, preventing form fields from reverting to server state after autosave completes. -
#36
275a21cThanks @scottbuscemi! - Fixes image field removal not persisting after save by sending null instead of undefined, which JSON.stringify was silently dropping. -
#502
af0647cThanks @pagelab! - Adds Portuguese (Brazil) locale with full pt-BR translations following the WordPress pt-BR glossary standard. -
#521
b89e7f3Thanks @ascorbic! - Wraps all user-visible strings in the admin shell and core content screens with Lingui macros so they are translatable. Covers: Sidebar (nav labels, group headings), Header (View Site, Log out, Settings), ThemeToggle, Dashboard (headings, empty states, status indicators), ContentList (table headers, actions, dialogs, status badges), SaveButton, and ContentEditor (publish panel, schedule controls, byline editor, author selector, all dialogs). Runslocale:extractto add 116 new message IDs to all catalog files. -
#528
ba0a5afThanks @ascorbic! - Wraps all remaining admin UI components with Lingui macros, completing full i18n coverage of the admin interface. Catalog grows from 296 to 1,216 message IDs. Covers media library, menus, sections, redirects, taxonomies, content types, field editor, plugins, marketplace, SEO panels, setup wizard, auth flows, and all settings pages. -
#504
e2f96aaThanks @ascorbic! - Fixes client-side locale switching and replaces toggle buttons with a Select dropdown. -
#471
4645103Thanks @ayfl269! - Adds Chinese (Simplified) translation for the admin UI, including login page, settings page, and locale switching. -
Updated dependencies []:
- @emdash-cms/blocks@0.4.0
0.3.0
Patch Changes
-
#351
c70f66fThanks @CacheMeOwside! - Fixes redirect loops causing the ERR_TOO_MANY_REDIRECTS error, by detecting circular chains when creating or editing redirects on the admin Redirects page. -
#499
0b4e61bThanks @ascorbic! - Fixes admin failing to load when installed from npm due to broken locale catalog resolution. -
Updated dependencies []:
- @emdash-cms/blocks@0.3.0
0.2.0
Minor Changes
Patch Changes
-
#467
0966223Thanks @sakibmd! - fix: move useMemo above early returns in ContentListPage -
#349
53dec88Thanks @tsikatawill! - Fixes menu editor rejecting relative URLs like /about by changing input type from url to text with pattern validation. -
#99
3b6b75bThanks @all3f0r1! - Fix content list not fetching beyond the first API page when navigating to the last client-side page -
#247
a293708Thanks @NaeemHaque! - Fixes email settings page showing empty by registering the missing API route. Adds error state to the admin UI so fetch failures are visible instead of silently swallowed. -
#316
c9bf640Thanks @mvanhorn! - Allow relative URLs in menu custom links by changing input type from "url" to "text" -
#377
5eeab91Thanks @Pouf5! - Fixes new content always being created with localeenregardless of which locale is selected in the collection locale switcher. The "Add New" link now forwards the active locale to the new-content route, and the new-content page passes it through to the create API. -
#185
e3f7db8Thanks @ophirbucai! - Fixes field scroll-into-view not triggering when navigating to a field via URL parameter. -
#93
a5e0603Thanks @eyupcanakman! - Fix taxonomy links missing from admin sidebar -
Updated dependencies [
e1349e3]:- @emdash-cms/blocks@0.2.0
0.1.1
Patch Changes
-
#328
12d73ffThanks @jdevalk! - Add OG Image field to content editor -
#200
422018aThanks @ascorbic! - Replace placeholder text branding with proper EmDash logo SVGs across admin UI, playground loading page, and preview interstitial -
#306
71744fbThanks @JULJERYT! - Align back button position in API Tokens section -
#135
018be7fThanks @fzihak! - Fix content list for large collections by implementing infinite scroll pagination -
#181
9d10d27Thanks @ilicfilip! - fix(admin): use collection urlPattern for preview button fallback URL -
#225
d211452Thanks @seslly! - AddspasskeyPublicOriginonemdash()so WebAuthnoriginandrpIdmatch the browser when dev sits behind a TLS-terminating reverse proxy. Validates the value at integration load time and threads it through all passkey-related API routes.Updates the admin passkey setup and login flows to detect non-secure origins and explain that passkeys need HTTPS or
http://localhostrather than implying the browser lacks WebAuthn support. -
#268
ab21f29Thanks @doguabaris! - Fixes passkey login error handling when no credential is returned from the authenticator -
#221
bfcda12Thanks @tohaitrieu! - Fixes form state not updating when switching between taxonomy terms in the editor dialog. -
#45
5f448d1Thanks @Flynsarmy! - Adds Back navigation to Security and Domain settings pages
0.1.0
Minor Changes
Patch Changes
- Updated dependencies [
755b501]:- @emdash-cms/blocks@0.1.0