Skip to content

Commit a92f54c

Browse files
committed
Changelog update
1 parent d40ccae commit a92f54c

6 files changed

Lines changed: 8335 additions & 8060 deletions

File tree

‎.claude/launch.json‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,21 @@
136136
"cd /Users/francesco/rebase/saas/frontend && node /private/tmp/claude-501/-Users-francesco-firecms/76484292-e280-48c5-9c9e-01bdab5e2c18/scratchpad/db-harness/serve.mjs"
137137
],
138138
"port": 5190
139+
},
140+
{
141+
"name": "example-pro",
142+
"runtimeExecutable": "npm",
143+
"runtimeArgs": [
144+
"run",
145+
"dev",
146+
"--prefix",
147+
"examples/example_pro",
148+
"--",
149+
"--port",
150+
"5214",
151+
"--strictPort"
152+
],
153+
"port": 5214
139154
}
140155
]
141-
}
156+
}

‎CHANGELOG.md‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,74 @@
1+
## [3.5.0] - 2026-09-16
2+
3+
- **FireCMS PRO: a license problem pauses PRO features instead of blocking the CMS**:
4+
- A failed license check used to replace the whole CMS with a "License needed" screen. That screen is gone: the app always renders. When the license check answers `blocked` (a trial that has ended, a license key used on a project its license does not list, or a project beyond the production projects a license pays for), the PRO plugins pause and everything else keeps working: sign-in, your data, collections defined in code and custom views. Paused plugins are removed both inside `FireCMS` and from the navigation controller built above it, so collection modifications, injected collections, views and home page entries go with them.
5+
- `user_management` never pauses, since it provides sign-in and roles. Its Users and Roles views show a "PRO features paused" notice with a link to get or update a license instead of the editors, and the home page widget for creating roles is hidden.
6+
- **New `LicenseBanner`**, rendered by the default `Scaffold` above the main content: the days left in a trial (dismissible), or why PRO is paused and what to do (an ended trial, a project missing from its license, or a license that pays for fewer projects in production). Place it yourself only in a custom layout.
7+
- **New `useLicenseStatus()`** hook, also available as `FireCMSContext.licenseStatus`, plus `isProPaused(status)` and `getLicenseSubscribeUrl(status)`. The hook works inside `FireCMS` and above it, in the component that calls `useBuildNavigationController`.
8+
- A license covers as many projects in production as it pays for. When more of its projects run in production, the ones that went live first keep PRO and the others pause until the license pays for them. Local development never counts.
9+
- `telemetry={false}` skips the license check only in apps with no `apiKey` and no PRO plugin mounted. With one, the request is the license check itself, so skipping it would unlock PRO.
10+
- A failed license request no longer rejects unhandled. `t()` accepts numbers, so i18next picks plural forms. The `license_needed` and `license_description` translation keys are removed.
11+
- **Upgrade to get this.** Apps on 3.4.0 or earlier still replace the whole CMS with the block screen when a license check answers `blocked`.
12+
- **Smaller bundles: icons, translations and the CMS shell load on demand**:
13+
- Rendering the FireCMS Cloud login form used to pull 6.5 MB of JavaScript. Every Material icon, every date-fns locale, every translation of every package, ProseMirror, the spreadsheet importer and the whole CMS shell were reached statically. Measured on a canary deployment against production with a cold cache, the last critical chunk arrives in 0.7 s instead of 3.9 s.
14+
- The 2,198 icon components share one factory and are marked pure, so apps bundling from source tree-shake the ones they don't use. date-fns locales load one at a time, when a locale is set.
15+
- **Nothing is removed from the public API.** Components that moved behind a lazy boundary (`FireCMSEditor`, `FireCMSCloudApp` and others) are re-exported by wrappers with the same signature and their own `Suspense`, so they stay drop-in. The built packages export more names than before, not fewer.
16+
- `FireCMSPlugin.i18n` accepts a loader function for each locale (`() => import("./locales/de")`) alongside the plain object it always took.
17+
- Fixed a language picked from the language toggle loading its strings but leaving the UI in English, and nested translation providers overwriting the host app's overrides. Each plugin translation bundle is now written once, rather than on every render of a component that rebuilds its plugin list.
18+
- **Projects install again on npm 12 and pnpm 11**:
19+
- `@firecms/data_import` depended on SheetJS by URL, and every FireCMS project pulled it in through `@firecms/firebase`. npm 12 and pnpm 11 refuse URL-resolved packages by default, so no project on 3.4.0 installed on a current package manager without changing its settings. Spreadsheets are now read with `read-excel-file`, still loaded only when a spreadsheet is imported, and CSV with a built-in parser that also reads `;` and tab delimiters.
20+
- `@firecms/core` no longer lists `vite-plugin-static-copy` as a dependency. It was never imported, and its peer range installed Vite 8 into every app, which Astro warns about on every start.
21+
- `@firecms/cli` no longer depends on `googleapis`, which it never imported: `npx @firecms/cli` and `npx create-firecms-app` downloaded 200 MB less on first run.
22+
- **Data import**:
23+
- A blank CSV cell is left out of the row, so collection defaults apply, instead of arriving as `""` and becoming `0`, `false`, an invalid date or a broken reference.
24+
- An `.xlsx` date is read in local time: a cell showing 2024-01-15 no longer imports as the 14th west of UTC. Times no longer lose a millisecond (12:30:00 read as 12:29).
25+
- CSV values are typed from the target property: `TRUE`/`FALSE` in any case, formatted numbers (`1,234.5`, `12,5`, `$5.00`, `50%`) and ISO dates. Unreadable values become `null`, never `NaN` or an invalid date, and text like `00123` stays text.
26+
- Repeated headers get a suffix (`name`, `name_1`) instead of overwriting a column. A blank header column no longer shifts the columns after it. A table may start below blank rows, a lone CR ends a line (Excel for Mac), and a comma-separated list mapped into an array property maps each item.
27+
- A header row with nothing under it, a legacy `.xls` or a CSV renamed `.xlsx` is refused with a message saying what to do instead. Header keys from an uploaded file can no longer reach an object's prototype.
28+
- The import dialog's actions stay pinned to the bottom when the mapping list is long, and the saving step is centred.
29+
- **Data export**:
30+
- **Export only the selected rows.** With rows selected in the collection view, the export dialog offers "All entities" or "Selected entities (n)", defaulting to the selection. The selected entities are fetched again, so edits made since they were ticked are included, and they come out in the table's order. `exportAllowed` still receives the collection's count. The `export_collection` analytics event gains a `scope` parameter (`all` or `selected`).
31+
- The dialog is regrouped around segmented choices: which entities, the format (with "Flatten arrays" shown only for CSV) and how values are written, with a caption showing how a date will read in the file.
32+
- The dialog stays open until the file downloads and shows progress on the Download button. A failed export (missing permissions, a dropped connection, a timeout) shows its reason in the dialog instead of doing nothing. Closing the dialog abandons an export in progress.
33+
- **AI autofill (`@firecms/data_enhancement`)**:
34+
- Enhancing a single field replaces its value instead of appending the suggestion to the existing text.
35+
- Streamed suggestions longer than one network chunk no longer fail with "Unterminated string in JSON". Failures show a snackbar ("Autofill failed", or the subscription warning on a 402) instead of an unhandled rejection.
36+
- Fixed "Maximum update depth exceeded" when typing fast into a text field on React 19.
37+
- Submitting the prompt closes the autofill menu, and clicking away from it no longer closes the entity side panel underneath.
38+
- **Entity history**: records `entity_history_opened` (once per entity) and `entity_history_reverted` through the analytics controller. `useAnalyticsController` is now exported for plugins.
39+
- **Core and UI fixes**:
40+
- A collection matches a URL path only at a segment boundary. A collection called `products_archive` or a custom path `/products-test` no longer resolves to `products` with an entity id of `_archive` or `-test`.
41+
- Disabled buttons are readable: a disabled filled button is a flat muted surface at over 6.5:1 contrast, where stacked transparency put it at 3.6:1. `InfoLabel` sets its own text colour, so it no longer turns dark on dark outside a `Scaffold`. A non-expandable `SearchBar` fills its container.
42+
- The app bar keeps the same left edge and logo position with and without a drawer.
43+
- Tooltips open on keyboard focus only (`:focus-visible`), so a tooltip can no longer float over a dialog after the window regains focus. Hover is unchanged.
44+
- Dialogs with a `maxWidth` keep a side gutter on narrow screens again, as in Tailwind v3: 11/12 of the screen up to the maximum width. Desktop sizes are unchanged.
45+
- `ToggleButtonGroup` has a new optional `fullWidth` prop.
46+
- The rich text editor no longer throws when an image finishes uploading, or an AI completion arrives, after the entity was closed.
47+
- **CLI and templates**:
48+
- **A canary CLI scaffolds its own version.** `npx @firecms/cli@canary init --pro` used to pin `^3.0.0`, which installed the latest stable release; a prerelease CLI now pins every `@firecms` package to its own version.
49+
- Every template installs, builds and runs with npm, pnpm 10 and 11 and yarn 2+. pnpm 11 used to refuse to install or run any template until their install scripts were approved; each template now approves exactly what it needs. Each declares the Node version it needs, instead of failing later with "Cannot find native binding" on Node 18.
50+
- The PRO templates pass their plugins to `useBuildNavigationController` instead of the deprecated `plugins` prop, so navigation-level features work (the collection editor's home page drag-and-drop and saved groups never did in the PRO template).
51+
- **License keys:** the Next.js template reads `NEXT_PUBLIC_FIRECMS_API_KEY` and the Astro template `PUBLIC_FIRECMS_API_KEY`, and both pass it to `FireCMS`. Neither passed a key before, so there was nowhere to put one.
52+
- The Next.js template no longer ships FireCMS's own demo Firebase project. It uses placeholders like the others, filled in by `--projectId`. It imports firebase from its public entry points, so it builds under pnpm. Its `/products` and `/blog` pages revalidate once a minute instead of never showing content edited in the CMS.
53+
- The Astro template generates FireCMS's styles (its Tailwind `@source` pointed at a folder that doesn't exist), renders in `astro dev`, uses the standard login view, and its blog no longer lists drafts. The cloud template builds under pnpm.
54+
- The PRO template mounts entity history, so there is a History tab. Unavailable products can be edited and imported (`price` was required and cleared at the same time). Its products collection has working text search.
55+
- The community template mounts its products collection, so the demo collection's references resolve.
56+
- Scaffolded projects get a `.gitignore`, which npm never packed, and the CLI tarball dropped from 1.73 MB to 0.67 MB.
57+
- `firecms --help`, `-h` and `init --help` print usage. Unknown commands and usage errors exit 1. `init` works with absolute paths and missing parent folders, validates `--projectId`, and never writes "undefined" into config files. Two template flags at once is an error.
58+
- `firecms init --yes` never prompts for a login. `login` prints where to sign in before opening a browser, reports a busy port, and gives up after 5 minutes. A corrupt `tokens.json` reads as logged out instead of breaking every command.
59+
- `firecms deploy` says why it failed and exits 1 instead of crashing. It refuses to upload before a build (it used to replace the live deployment with an empty zip), and while logged out it only offers to log in where someone can answer.
60+
- A scaffolded project that has not been given a Firebase config names the file to fill in, instead of rendering a blank page.
61+
- **FireCMS Cloud**:
62+
- **Graduated PRO pricing:** one price per currency and interval, with the first project at one rate and each additional project on the same license at a lower one. Licenses edit their projects through a new endpoint that keeps the Stripe quantity in step. `FireCMSCloudLoginView` takes `variant: "pro"` for the PRO purchase path. Prices are shown as excluding VAT.
63+
- Tenant bundles load with a short-lived asset token scoped to the revision, instead of carrying the user's Firebase ID token in the URL.
64+
- When a project's service account stops working, the error names the cause (deleted, key invalid, disabled, Authentication not enabled, unreadable). "Recreate service account" is offered only where it can help, and it no longer reports success whatever the backend answered.
65+
- The login buttons stay clickable before the terms are accepted and say what is missing, instead of doing nothing.
66+
- `AutoSetUpCollectionsButton`'s `onError` receives the error, and `onNoCollections` receives diagnostics that tell a project with no collections apart from one whose collections could not be listed. Both are additive.
67+
- DataTalk is linked from the admin section of the home page, and its background requests no longer fail as unhandled rejections.
68+
- Stripe billing portal links are created when clicked, with a message when one fails, instead of on every page view.
69+
- The app bar stays on screen while a project's CMS loads.
70+
- **Releases**: packages publish with npm provenance again. The repository URL in every `package.json` had the wrong case, so npm refused every provenance statement since August.
71+
172
## [3.4.0] - 2026-08-26
273

374
- **FireCMS Cloud: tenant customizations share the host's React**:

‎examples/example_pro/src/FirestoreApp/App.tsx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,14 +387,15 @@ export function App() {
387387
storageSource
388388
});
389389

390+
// The deployed demo swaps the import for a stub, so visitors can't write to its
391+
// database; `vite dev` gets the real import plugin.
390392
const plugins = [
391393
userManagementPlugin,
392394
dataEnhancementPlugin,
393-
// importPlugin,
395+
import.meta.env.DEV ? importPlugin : demoPlugin,
394396
exportPlugin,
395397
entityHistoryPlugin,
396398
// mediaManagerPlugin,
397-
demoPlugin,
398399
collectionEditorPlugin
399400
];
400401

‎packages/cli/scripts/templates/smoke-published.mjs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,13 @@ const waitMinutes = Number(opts["wait-minutes"] ?? 10);
5757

5858
/**
5959
* A publish that just finished can take a few minutes to be installable everywhere, so
60-
* wait until npm serves every package at `version` (those that exist there at all).
60+
* wait until npm serves every package at `version`. Every one, not a sample: the
61+
* templates pin all of them, and on 2026-09-16 @firecms/schema_inference, published
62+
* near the end of the run, was still missing when the five sampled ones were there,
63+
* so every install failed with ETARGET.
6164
*/
6265
async function waitForRegistry() {
63-
const names = ["@firecms/cli", "@firecms/core", "@firecms/ui", "@firecms/firebase", "@firecms/cloud"];
66+
const names = Object.keys(localPackages());
6467
const deadline = Date.now() + waitMinutes * 60_000;
6568
for (const name of names) {
6669
for (;;) {

0 commit comments

Comments
 (0)