Repository navigation
@emdash-cms/admin@1.2.0
Minor Changes
-
#3056
b92f2d6Thanks @emdashbot! - Adds anadmin.localesoption that limits the admin interface to the languages a site uses, which makes the admin bundle smaller.emdash({ admin: { locales: ["en", "de"] }, });
Only the listed languages are built into the admin and offered in its language switcher. Users whose preferred languages aren't listed see English.
enis always included as the fallback, even when the list leaves it out, soadmin: { locales: ["en-GB"] }still ships English alongside British English. A code the admin doesn't ship fails the build, and the error lists the available codes. Sites that don't set the option keep every language. -
#3877
5f69896Thanks @swissky! - Updates the admin user editor to show the name as read-only, with a hint to change it at the identity provider, when an external auth provider such as Cloudflare Access syncs names (the default). Previously the field looked editable, but the change was replaced on that user's next request. SetsyncName: falsein the provider config to make names editable again. -
#3744
1e275aeThanks @swissky! - Adds a Change domain dialog to Settings > General for moving a site to a new domain. Before it changes the Site URL, EmDash checks that the new domain serves the site. Links in emails and plugins, sitemaps,robots.txt, hreflang links, social image URLs, and canonical links set in the SEO panel then use the new domain. If the check can't reach the site, for example onlocalhostor behind a login, the dialog offers to store the address without the check.The Site URL field becomes read-only, and saving Settings > General no longer writes it. When
siteUrl,EMDASH_SITE_URL, orSITE_URLis set, the page names that address, which links in emails and plugins keep using.Passkeys only work at the address where they were created. After a move, keep signing in at the old address, or sign in at the new one with an email link and add a passkey there.
-
#3744
1e275aeThanks @swissky! - Adds an Email users action to Settings > General that tells every other active user where the site now lives. Each user gets an email with a button to the sign-in page at the configuredsiteUrl, or the Site URL when none is set, and a note that passkeys from the old address don't work there. The email does not sign anyone in. The action needs an email provider, passkey sign-in, and theusers:managepermission, and shows how many emails were sent and how many the provider rejected.The emails come from the new
POST /_emdash/api/settings/domain/notifyendpoint. It accepts signed-in sessions only and can be used 3 times per hour per site. -
#3710
06a9146Thanks @khoinguyenpham04! - Redesigns the content editor as a page. The entry's title field is a large heading at the top, thecontentfield's Portable Text editor sits under it without a frame, and one bar above the page holds the back link, the entry title, the save status, and Live View, Preview, and Publish. Distraction-free mode uses the same bar and adds Discard changes and Schedule.- Writing: Enter in the title, or Down Arrow at its end, moves into the body, and Up Arrow on the body's first line moves back. Clicking below the last block continues writing at the end. Select All selects the text of the block holding the caret, and the whole document on a second press. Backspace at the start of a heading or code block turns it into text, and next to an image, divider, or embed selects it before deleting it.
- Toolbar: the formatting toolbar floats above the text and stays in view while you scroll, with the text fading out under it. When it doesn't fit, it scrolls sideways. Its block buttons convert blocks the same way as Turn into and the slash menu, and use the same names.
- Blocks: hovering a block shows +, which starts a line below it with the slash menu open (Alt-click starts one above) and takes the line away again if the menu closes before anything is typed after the slash, and a handle to drag the block or open its menu: Turn into, Align, Continue numbering and Restart numbering, Duplicate, Move up and Move down, and Delete. Escape selects the block holding the caret, and the arrow keys then move between blocks. A block inserted or pasted while another is selected goes after it, and a block inserted with the caret in text goes after that block instead of splitting it. Clicking where there's no line for the caret, such as between two embeds or above an embed at the start, leaves the caret where it was; use + to add a line there.
- Quotes and lists: quotes hold paragraphs, and list items hold text and nested lists, as Portable Text stores them. A heading, code block, image, or other block typed, pasted, or dropped into a quote or list lands beside it, where it's saved, instead of disappearing on save. A pasted quote or list that holds one is split around it, and a numbered list keeps counting after it. Alignment is offered only outside quotes and lists, where it's kept.
- Slash menu: commands are grouped, show the Markdown that creates each block, and match abbreviated searches such as
/blfor Bullet List, whole titles such as/heading 2, and the Markdown itself, such as/#. Headings 4 to 6 appear when you search for them. - Selection toolbar: Turn into, link, bold, italic, underline, strikethrough, and inline code, with subscript, superscript, alignment, and Clear formatting under More formatting. Clicking a link, or otherwise placing the caret in it, shows where it goes, with Edit link and Remove link, instead of selecting the whole link. A link typed as a bare domain, such as
example.com, getshttps://, a relative path such as../about.htmlstays as typed, and a link the editor can't use says so. The selection, link, table, and image toolbars are announced as toolbars, and the Left and Right arrow keys move between their buttons. - Narrow screens: when the bar is narrow, as on phones and tablets, its secondary buttons, Unpublish included, show only their icons, and Publish now and Publish changes read Publish, so the bar stays on one row with the entry title readable. Block handles also show on touch screens wide enough for them.
Other Portable Text fields keep the framed editor.
PortableTextEditoradds avariantprop ("boxed"by default, or"document") and anonArrowUpAtStartcallback. -
#3827
373446fThanks @khoinguyenpham04! - Adds a video block to the rich text editor. Type/videoto choose a Media Library video or upload one. Closing the picker leaves an empty video block in place, which you can fill later by clicking it or dropping a video file on it. Video files dropped or pasted anywhere in the text also upload to the Media Library and appear where you dropped them. The video plays in the editor at the width of the text, with a caption field under it and Replace video and Delete video in its corner. A video's Used in tab in the Media Library lists the entries that use it in a video block.On the site,
Videofromemdash/uirenders thevideoblock as the browser's own player with its caption. Media Library videos play from your storage's public URL when one is configured, and need the block'sasset.url: a block without one renders nothing on the site, and the editor shows it as unplayable. A block whoseasset.providernames a media provider renders from that provider's embed. An empty video block is saved withoutassetand renders nothing.Uploads follow
maxUploadSize, 50 MiB by default. The admin's content security policy now allows media fromblob:andhttps:URLs (media-src 'self' blob: https:), as it already did for images. This lets the admin read a video's size before uploading it, and preview a video block whoseasset.urlis on another site. Before, videos uploaded from the admin in production were saved without a width and height.What should I do?
- If a plugin already defines a
videoblock, the editor keeps using the plugin's block: it doesn't offer the built-in Video block, and dropped video files aren't uploaded. On the site, the plugin's renderer still wins; a plugin without one getsVideofor blocks that have only the built-in fields. In TypeScript, narrowingPortableTextBlockon_type === "video"now givesPortableTextVideoBlock | PortableTextUnknownBlock, so reading the plugin's own fields needs a check. - If you edit Portable Text with
portableTextToProsemirrorandprosemirrorToPortableTextfromemdashin your own TipTap editor, add avideoBlocknode with the attributessrc,mediaId,provider,caption,widthandheightto its schema.portableTextToProsemirrorturns every built-in video block into that node, and a schema without it can't load the document. - The media usage API and
emdash/clientcan now return the reference type"portable_text_video"for a video used in a video block. Code that checks every reference type, or validates the list, needs to accept it. - With Astro's content security policy turned on and media on another host, allow that host in
media-src.
- If a plugin already defines a
-
#3773
e6fe5d4Thanks @khoinguyenpham04! - Adds numbered pages to every collection list in the admin. The All and Trash tabs load one page of entries at a time, so a collection opens with 20 entries instead of fetching 100, and both tabs use the Media Library's pagination footer pinned to the bottom of the screen: the entry range, 20, 50, or 100 entries per page, and controls to jump to any page. The Trash badge counts every trashed entry instead of stopping at 50, and every trashed entry is reachable.Selections persist across pages. Changing the search, a filter, the locale, or the collection clears them.
GET /_emdash/api/content/{collection}andGET /_emdash/api/content/{collection}/trashaccept a 1-basedpageparameter instead ofcursor. A numbered page returnstotaland nonextCursor, and sending bothpageandcursorreturns a400validation error. Cursor pagination is unchanged.ContentListaccepts optionalpaginationandtrashPaginationprops for numbered pages; without them it behaves as before. -
#3744
1e275aeThanks @swissky! - Adds a Continue on button to Settings > General after a site moves to a new domain. Passkeys only work at the address where they were created, so a user signed in at the old address can select the button to sign in at the new one without email. The single-use link expires after 5 minutes and opens Settings > Security, ready to add a passkey for the new address. The button appears when you are signed in at an address other than the Site URL, or the configuredsiteUrlwhen one is set. It is not shown when an external provider such as Cloudflare Access handles sign-in.The link comes from the new
POST /_emdash/api/auth/handoverendpoint, which accepts signed-in sessions only and allows 5 links per user every 5 minutes.GET /_emdash/api/settings/domainnow also returnssiteOrigin, the address the link points to.@emdash-cms/authexportscreateMagicLinkUrl(), which creates a single-use sign-in link without sending an email.
Patch Changes
-
#3878
5c1ebc3Thanks @swissky! - Fixes a blank screen when an entry in the admin content editor fails to open. A missing entry now shows a not-found page, and a subscriber opening an unpublished entry is told that their role can only view published content. Other errors show the error message with a retry button. -
#3798
90f39e0Thanks @DiogoDuart3! - Fixes long block type descriptions in the "Add block" picker of a blocks field running into the next column. Each option now stays within its column and its description wraps. -
#3925
a17408fThanks @danielmlr! - Fixes the byline editor not scrolling when its fields don't fit in the window, which hid the lower fields, such as the linked user, custom fields and translations, behind the dialog's buttons. The form now scrolls, and the title and buttons stay in place. -
#3852
f5406f8Thanks @miljan-aleksic! - Completes the Catalan admin translations so every admin string is localized, keeping the source's punctuation, ICU placeholders, and rich-text tags verbatim, leaving "Token" and technical terms untranslated, and usingexemple.comfor example domains. -
#3831
3787eb9Thanks @emdashbot! - Fixes false conflict errors when saving SEO fields, including OG images, after a clean content editor refreshes a cached entry. Background refreshes preserve unsaved edits and their conflict protection, and delayed older reads cannot replace the revision from a successful save. -
#3728
e63cc44Thanks @huketo! - Keeps the WordPress migration-key and site-URL fields inside their cards on narrow screens, while preserving the wider-screen layout. Technical keys and URLs remain left-to-right in RTL locales, and the site-URL input exposes its localized name to assistive technologies. -
#2791
c77c6cfThanks @SL33PiNg! - Completes the Thai (th) admin translation. Thai admins now see localized text across the publishing calendar, editor image toolbar, site settings, authentication, plugin registry and capability consent dialogs, site transfer, and the media library, which previously fell back to English for 1,725 of 3,188 strings. -
#3558
395087dThanks @kgni! - Translates the new admin strings into Danish, including the Bylines page, the bulk tag dialog, sections, menus and the content type editor. -
#3744
1e275aeThanks @swissky! - Fixes email links pointing to the address a site was set up on after it moved to a new domain. Sign-in, invitation, self-signup, recovery, and comment notification emails now use the Site URL from Settings > General whensiteUrl,EMDASH_SITE_URL, orSITE_URLis not configured, and fall back to the setup address when the field is empty. Only the origin of the Site URL is used, and it must usehttps://unless the host is a loopback address. A configuredsiteUrlstill takes precedence.emdash export-seedno longer copies the Site URL into the seed.If you don't configure
siteUrland the Site URL field holds an address that doesn't serve this site's admin, for example an old domain, links in these emails point there after upgrading. Check the field before upgrading; clearing it restores the previous behavior. Seeds that setsettings.url, including seeds exported by earlier versions, still fill in the Site URL, so removeurlfrom a seed copied from another site before using it. -
#3721
24a4327Thanks @miljan-aleksic! - Updates Spanish (Spain) admin translations to add missing strings, remove deprecated ones, correct wrong and inconsistent translations, and switch to the informal "tú" tone. -
#3796
9f09f60Thanks @DiogoDuart3! - Adds European Portuguese (Português (Portugal),pt-PT) translations for the admin UI. The locale is selectable from the language picker and uses Portuguese date formats in the calendar and date settings. Browsers that ask forpt-PTnow get this locale instead of Brazilian Portuguese, and a site whose language is set topt-PTsends its invite, sign-in and recovery emails in European Portuguese. Other Portuguese variants, and plainpt, still resolve to Brazilian Portuguese. -
#3701
8885267Thanks @ShaneMuir! - Fixes the field editor silently closing and discarding changes when the server rejects a field update, such as togglingrequiredoruniqueon a field that already has content (which needs a manual content migration). The dialog now stays open and shows the server's error message instead of the toggle looking like it reverted on its own. -
#3813
c07437fThanks @emdashbot! - Fixes generated admin identifier slugs for non-ASCII labels in content types, taxonomies, byline fields, relations, and fields.Labels like
Größenow producegroesseandTítulobecomestitulo, including equivalent decomposed Unicode input. Labels that cannot produce a valid ASCII identifier, such as名前or2024年, require a manually entered slug and show an inline message.Adds editable slugs for new repeater sub-fields and blocks duplicate sub-field slugs before saving. Existing sub-field slugs stay read-only so relabeling preserves the keys used by saved content.
-
#3835
b3e17f6Thanks @danielmlr! - Completes the German admin translations so German-speaking editors see localized text for the publishing calendar, domain settings, HTML and iframe blocks, media controls, visual editing, and plugin permissions. -
#3293
595fd15Thanks @itaides! - Adds Hebrew (עברית) to the admin language picker. The admin renders right-to-left in Hebrew, its date pickers use Hebrew month and weekday names, and its strings are translated as of October 2026. Strings added to the admin later appear in English until the catalog is updated. -
#3872
392ade3Thanks @Zahid09987! - Adds Indonesian translations for recently introduced admin UI strings, including slug-generation hints, the sub-field slug placeholder, and sub-field validation messages. -
#3851
3bcd2cbThanks @Zahid09987! - Adds Indonesian translations for the site domain-change flow, general settings screen, marketplace capability labels, and visual-editing toolbar strings. -
#3795
36aee2dThanks @DiogoDuart3! - Fixes the content editor failing to open any entry with a date field when the site timezone setting is not a valid IANA timezone (for exampleLisboainstead ofEurope/Lisbon). The editor now falls back to UTC for such a value instead of crashing, and the settings API and MCP settings tool reject an unrecognized timezone with a validation error. A site that already stores one can still save its other settings, and can fix the timezone in Settings > General. -
#3931
9538600Thanks @danielmlr! - Fixes the error message on the invite and signup pages ending in a bare colon when the server responds with an error page instead of an error message. The message no longer includes the HTTP status text, which browsers leave empty over HTTP/2 and HTTP/3, and it can now be translated. -
#3789
6d2a3bbThanks @maikunari! - Aligns the Japanese admin text with the long-vowel spelling used elsewhere in the catalog: ブラウザー and エディター now replace ブラウザ and エディタ in the passkey messages, the rich text editor label, and the WordPress import notice. -
#3718
841a5b3Thanks @huketo! - Expands the Korean admin translations to cover almost every admin screen and corrects terminology in the existing Korean text. Korean remains disabled in the locale selector.The catalog now covers sign-in, passkeys, invitation and sign-in emails, and device authorization; the dashboard, setup, and shared notifications, error, and loading screens; content lists, editing, publishing, and scheduling; rich-text, image, gallery, and block editing; content types, fields, relationships, and references; media; bylines and taxonomies; menus, widgets, and sections; site settings, users, redirects, backups, and transfer tokens; plugins, themes, and the registry; and site transfer and WordPress imports.
The Korean text distinguishes content authors from public byline profiles, and the permanent-delete confirmation now shows the content title instead of leaving it blank.
-
#3732
2210c2cThanks @ascorbic! - Fixes plugin permissions for sending email, handling outgoing email, and adding page scripts and styles showing as raw capability names in the admin. They now have readable labels in the plugin list, marketplace, and install consent dialog. -
#3923
142da40Thanks @ascorbic! - Reduces the admin's JavaScript by about 220 KB by loading the date picker and date-format localization for the active language on demand, instead of bundling every language. -
#3933
d72b615Thanks @danielmlr! - Fixes admin error messages for menus, taxonomies, widgets, users, and other screens that stayed in English when the server answered with an error page instead of an error message, such as a gateway error. They now follow the admin language. -
#3010
2f59cc3Thanks @eisenbruch! - Fixes the content list showing a "Pending changes" badge on entries that have never been published. A draft or scheduled entry has a draft revision and no live revision, which the list read as a difference between the two. The badge now appears only where there is a published version for the changes to be pending against, matching the state the editor shows for the same entry. -
#3773
e6fe5d4Thanks @khoinguyenpham04! - Fixes keyboard focus in the Media Library pagination controls. Focus no longer jumps to those controls when the library reloads after a search or filter change; it returns to them only after a page they requested finishes loading, and stays wherever you moved it during the load. Picking a page or a page size from a dropdown returns focus to that dropdown, and when the page reached disables the button you pressed, such as Previous on the first page, focus moves to the page picker instead of being lost. -
#3710
06a9146Thanks @khoinguyenpham04! - Fixes newly inserted HTML, iframe, and code blocks in the content editor. HTML and iframe blocks now highlight the selected tab, and their arrow keys move between tabs. Tab now reaches a code block's language and copy buttons, and the arrow keys move between them. Until now, these worked only for blocks that were there when the page loaded. -
#3758
d0c7384Thanks @danielmlr! - Fixes the admin's new-entry form ignoring field default values: a boolean field withdefaultValue: truestarted switched off, and saving the entry untouched could store no value. New entries in the admin now start with each field's default value.Manifest field descriptors now include stored field defaults as
defaultValue, except for relation-bound reference fields. -
#3369
b854616Thanks @danielmlr! - Fixes plugin admin pages and dashboard widgets showing no feedback after a Block Kit button click or other action. Until the plugin responds, the content now dims under a loading indicator, and screen readers announce that it is updating. -
#3546
2c8c12aThanks @swissky! - Addsgroupto plugin admin pages, in native plugin descriptors and inadmin.pagesofemdash-plugin.jsonc, to place them in collapsible admin sidebar folders. A page whose group matches the group of a collection shown in the sidebar appears inside that folder, after its collections and taxonomies. Pages that share any other group, from one plugin or several, fold into one folder in the Plugins section. Pages without a group stay where they are. -
#3737
8867abaThanks @ryofukutani! - Fixes plugin block cards in the content editor droppingnumber_inputvalues from their summary line, so a block whose only identifying field is a number (such as an episode or video number) no longer shows just the block type. -
#1899
e9cf2c3Thanks @swissky! - Adds an optionalurlTemplateprop to thecore:recent-postswidget (e.g."/blog/:slug"or"/:slug"for catch-all routes), using the same:collection,:id,:slug, and:pathtokens as LiveSearch'srouteMap, with a localized label in the admin widget form. Without a template the widget links exactly as before. -
#3559
f6ee57eThanks @khoinguyenpham04! - Fixes Select All inside code blocks in the admin and inline visual editors so it selects only the code instead of the entire document. -
#3810
788a371Thanks @miljan-aleksic! - Updates the Serbian (Latin) admin translations to address the user informally ("ti") throughout. Singular imperatives and second-person wording replace the previous mix of formal and plural forms, passive constructions become active, and redundant possessive pronouns are dropped. A mixed-script character, a misspelling, and a few English calques are also corrected. -
#3771
550e59bThanks @danielmlr! - Fixes the visual editing toolbar's Publish button switching to English after a save when the toolbar is shown in another language. The button now keeps its translated label, and the toolbar's status badges and image popover can be translated as well. -
#3786
8037f5aThanks @emdashbot! - Fixes plugin dashboard widget titles so they translate through the same shared Lingui catalog as admin page labels. Widgets without atitlestill fall back to the raw widget id. -
#3751
dea8f58Thanks @danielmlr! - Fixes the WordPress import's media step stopping partway with "No result received from media import" on Cloudflare Workers Paid, where a batch of large photos could exceed the default 30-second CPU limit. The admin now imports media in smaller batches to stay within that limit. -
#3860
c5cef43Thanks @leevincent! - Completes the Traditional Chinese (Taiwan,zh-TW) admin translations so editors see localized text in the publishing calendar, media library, site transfer tools, plugin permission dialogs, and visual editing toolbar. -
Updated dependencies [
2c8c12a,2210c2c]:- @emdash-cms/plugin-types@0.6.0
- @emdash-cms/blocks@1.2.0