Added
- Add a
/publishpage and turn the navbar's Publish button into a drop target: a file drag anywhere in the app turns the button into a drop area, and every.vsixpackage dropped on it — or on the publish page's own drop area — is queued and uploaded straight away, with no confirmation dialog. The page shows the queue as a line of extension cards — a skeleton while a package uploads, the real card once the registry accepts it, labelled with whatever the registry did with it — and keeps polling anything left under review or still missing its icon - Export
PublishButton, which carries the publish link, itspshortcut and the app's.vsixdrop target in one component, so a deployment with its own menu content keeps drag-and-drop publishing - Add a "Data Consistency" page to the admin dashboard (#1622): a live overview of every registered consistency check's finding count, with actions to refresh it and to fix findings one at a time or all at once
- Show a "Namespace not verified" state on an extension card when it can't be activated because its namespace already exists in a referenced external gallery and hasn't been verified, in both the "My Extensions" and namespace member extension lists. The card keeps its colour and takes a warning-toned frame and icon, since this is the publisher's to fix rather than an extension that is simply switched off
- Show a warning notice with a claim action wherever an unverified namespace is holding something back — the extension settings page when the extension has a namespace ownership conflict, and the namespace settings page for any unverified namespace — making clear the namespace must be claimed (verified) first. The action is the deployment's configured
elements.claimNamespace, falling back to the namespace access documentation when none is configured. The admin dashboard's extension and namespace views show the same explanation without the claim action, since claiming is the publisher's action to take, not an admin's on someone else's behalf - Add a "Search Index" page to the admin dashboard: which engine answers searches, how many extensions the index holds against how many it is built from, and a button to rebuild it where there is an index to rebuild. The two counts sit side by side because an index that has quietly lost entries answers searches perfectly well, just with nothing in them, which is indistinguishable from an empty registry unless both numbers are visible at once
- Mark a version that was published through a trusted publishing workflow with an icon next to "Published by" on the extension detail page, linking to the deployment's trusted publishing documentation. The default deployment points that link at the Trusted Publishing wiki page
Changed
- Redesign the user settings: a sidebar (a pill strip below
md) navigating profile, access tokens, trusted publishers, extensions and rate limiting, with the user's namespaces listed alongside it and each one deep-linkable at/user-settings/namespaces/:namespace. Every view is rebuilt on the cards, grids, placeholders and theme shape tokens the rest of the site uses, and the namespace detail is now a single component shared with the admin dashboard - Revoking a single access token asks for confirmation first, like every other destructive action
- Present the unsigned publisher agreement on the access tokens page as a warning notice with a link to sign it, instead of a plain paragraph
- Mark a removed extension version in red across its row — version number, status pill and timeline dot — and disable its delete action. Every version of a rejected extension is marked too, and "Latest" is reserved for extensions the registry actually serves, so one that is inactive or removed has no version marked latest
- Publish from the navbar's Publish button, the
pshortcut and the settings Extensions tab through the new publish page, replacing the one-file-at-a-time publish dialog - Add an
outlinedWarningstyle toMuiButton, so a warning-toned outlined button follows the theme like the secondary and error ones instead of MUI's default half-opacity border - Breaking:
elements.claimNamespacenow receives{ namespace, extension?, sx? }instead of{ extension, sx? }. The namespace settings page offers the same claim action and has no extension to pass, so implementations must read the namespace fromnamespacerather thanextension.namespace - Publishing goes through TanStack Query:
publishExtensionandcreateNamespaceare mutation hooks (usePublishExtension,useCreateNamespace), and both service methods lose theirAbortControllerparameter — writes are no longer aborted, and retries are the query client's to own. The user's extension list is a query too (useUserExtensions), read by the settings tab and by the publish queue as it follows a package, so a card appears in the list as soon as the registry has the package ExtensionCardaccepts anExtensionas well as aSearchEntry, and takes optionalto,linkState,overlay,footerStart,dimmed,toneandiconPendingprops so other surfaces can reuse it instead of copying it- Show an extension card's rating as one star and the score rather than five stars, and no rating at all on an extension nobody has reviewed. Five icons could not shrink, so beside a long download count the count spilled out of the card
Added
- Add a
Pillcomponent — the clickable glass pill the category pills are built on, now usable on its own — and extract theMonoSlash,glassSurfaceandcompactControlpage primitives out of the search field, the pills and the search header - Add
userLoadingtoMainContext, so custom pages can tell "not logged in" from "still resolving the user" - Add a
userMenuContentslot toPageSettings.elements: extra entries for the logged-in account menu, rendered above the admin entry. The slot receives aMenuEntrycomponent to build entries with, so each entry is styled by the menu it appears in — the desktop and mobile menus style theirs differently, and a consumer cannot match both on its own - Add an
adminPagesslot toPageSettings.elements: extra admin dashboard pages, each declaring a name, icon, optional description and optional category, and each appearing in the side panel, as a card on the dashboard overview and as a route. Contributions are additive — a category name matching a built-in group appends to it, and a page whose path would shadow a built-in one is ignored - Widen the published API for consumers building their own pages: the request layer (
sendRequest,sendNonRetriableRequest,ErrorResponse,controllerFromSignal),MainContext,AppProviders,NotFound,createDefaultThemewith theMONO_FONT/NAVBAR_HEIGHTtokens, thecreateRoute/createAbsoluteURL/addQuery/formatCompactNumber/toRelativeTimeutils, theuseDebouncedCallbackanduseGridCursorhooks, the navbar-chrome, search-focus and page-search-bar hooks, the category icon helpers,ExtensionDetailRoutes, and theitemIcon/MenuItemTextbuilding blocks foruserMenuContententries
Changed
- Rename
ScrollToToptoScrollRestoration, matching what it does on back/forward navigation - Rename the extension tint context to
navbar-chrome-contextand add a second channel to it: a page with sections pinned under the navbar can extend the navbar's blur fan down to back them (useExtendNavbarBlur) - Give Popover and Autocomplete popups the same floating-paper treatment as the other menus, and stop Popovers locking body scroll — the lock jumps the scroll position on mobile and shifts the pinned chrome
Fixed
- Fix a React warning ("Received
truefor a non-boolean attributenotched") from the admin dashboard's publisher role filter, whose customInputBasedoesn't consume thenotchedprop MUI'sSelectinjects for the (unused) outlined variant - Fix the admin dashboard Scan tab getting stuck on the loading spinner after switching tabs, even though the new tab's data had already loaded successfully
- Fix the page jumping to the top whenever a menu, select or dialog opens.
- Fix the extension detail page's download menu so each target-platform option is clickable across its whole row, not just its text: the option was an inline link nested inside a non-interactive menu item, rather than the menu item itself being the link
- Fix
sendRequestre-enabling fetch-retry's own retries for the request that follows a 429 wait, because the recursive call didn't forward the originalretryflag. AsendStrictRequest/sendNonRetriableRequestcall that hit a 429 could end up having its follow-up request retried twice - once by fetch-retry and once by the query client - Fix the create-namespace dialog acting on Enter when its button is disabled: an empty or over-long name was submitted anyway, and a held key sent the request more than once
- Fix
isErrorcounting an emptyerrorstring as an error, and make it andisSuccessanswer anullresponse body instead of throwing on it (typeof null === 'object'). The registry aggregates per-version outcomes when deleting extension versions, so a delete where every version succeeded answered with an empty error next to the success message - which raised an error dialog with nothing in it
Dependencies
- Remove the
react-dropzonedependency; the publish page and the navbar's drop target handle their own drag events, and nothing else imports it - Remove nine dependencies that nothing imports:
clsx,prop-typesandpunycodefrom the runtime dependencies, and@types/d3-scale,@types/d3-shape,@types/prop-types,@types/punycode,@types/react-transition-groupandts-nodefrom the development ones. All but@types/punycodeandts-nodestay in the tree through MUI or the URL parsers that actually use them, so only those two leave the install - Bump express from
4.22.1to5.2.1and@types/expressfrom4.17to5.0. Express 4 capsqsat~6.14.0, which is why aqsresolution was needed to move past it; Express 5 declares^6.14.0, so that resolution is gone andqsresolves to6.16.0on its own. The standalone frontend server's catch-all route is now/{*splat}, which is how Express 5 spells the*it no longer accepts - Bump @humanfs/node from 0.16.6 to 0.16.8
- Bump js-yaml from 4.3.1 to 4.3.2