Migrating from v7 to v8
The following sections go over all necessary changes. They also give recommendations on how to structure your PRs and commits.
Many changes can be handled by upgrade scripts. Use them!
The 🤖 emoji marks changes that can be handled by an upgrade script. You just have to execute the script. Below the command there usually is a details drawer that describes the changes made.
Prerequisites
There are some steps that are necessary for the COMET v8 update but can be done beforehand:
Step 1: Upgrade node to v22 (PR #1)
You can skip this step if your project already uses node v22
Create a branch node-22
.
Then make the following changes:
🤖 In development:
npx @comet/upgrade@latest v8/replace-node-with-v22-locally.ts
Details
- 20
+ 22
- "@types/node": "^20.0.0",
+ "@types/node": "^22.0.0",
🤖 In pipeline and deployment:
npx @comet/upgrade@latest v8/replace-node-with-v22-in-gitlab-ci-files.ts
Details
Make sure you use Node 22 in your CI files. When using Gitlab CI, check all files in the .gitlab-ci folders. Make sure to extend the correct jobs and replace all images and base images.
- extends: .lint-npm-node20
+ extends: .lint-npm-node22
- BASE_IMAGE: "ubi/s2i-ubi9-nodejs20-minimal"
+ BASE_IMAGE: "ubi/s2i-ubi9-nodejs22-minimal"
- image: eu.gcr.io/vivid-planet/utils/ubi9-nodejs20-minimal:master
+ image: eu.gcr.io/vivid-planet/utils/ubi9-nodejs22-minimal:master
Now open a PR from node-22
to main
Step 2: Update Typescript to v5 (PR #2)
You can skip this step if your project already uses typescript v5 everywhere
Create a branch typescript-5
.
-
Make the following changes:
package.json- "typescript": "^4.2.3",
+ "typescript": "^5.8.3",api/package.json- "typescript": "^4.2.3",
+ "typescript": "^5.8.3",admin/package.json- "typescript": "^4.2.3",
+ "typescript": "^5.8.3",site/package.json- "typescript": "^4.2.3",
+ "typescript": "^5.8.3", -
Execute
npm install
in each folder (/api
,/admin
,/site
,/
)Check carefully for errors during the install. Errors might occur because of other packages that depend on typescript v4. Update such packages to make the errors disappear.
-
Execute
npm run lint
in the root directory.Fix occurring errors.
You might also see a warning like this:
=============
WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.
You may find that it works just fine, or you may not.
SUPPORTED TYPESCRIPT VERSIONS: >=3.3.1 <5.2.0
YOUR TYPESCRIPT VERSION: 5.8.3
Please only submit bug reports when using the officially supported version.
=============Ignore this warning for now.
-
Check if the app still starts
Now open a PR from typescript-5
to main
Step 3: Switch from @comet/cms-site
to @comet/site-nextjs
(PR #3)
You can skip this step if your project doesn't have a site
This doesn't work if you use other packages that depend on @comet/cms-site
.
In that case, skip this step for now and do it later during the v8 update.
The @comet/cms-site
package has been reworked and renamed to @comet/site-nextjs
. Notable changes are
- Styled components is no longer a required peer dependency
- Instead, SCSS modules are used internally
- The package is now pure ESM
To switch you must
-
Create a branch
switch-to-site-nextjs
-
cd site
-
npm uninstall @comet/cms-site
-
npm install @comet/site-nextjs@7
-
Change all imports from
@comet/cms-site
to@comet/site-nextjs
(with search and replace in your IDE) -
Import the css file exported by the package:
site/src/app/layout.tsx+ import "@comet/site-nextjs/css";
-
Switch the package in
optimizePackageImports
:site/next.config.mjsconst nextConfig = {
// ...
experimental: {
instrumentationHook: true,
- optimizePackageImports: ["@comet/cms-site"],
+ optimizePackageImports: ["@comet/site-nextjs"],
},
// ...
}
Now open a PR from switch-to-site-nextjs
to main
Step 4: Update eslint and prettier (PR #4)
Create a branch update-eslint-to-v9
🤖 Upgrade ESLint from v8 to v9 with ESM
npx @comet/upgrade@latest v8/eslint-dev-dependencies.ts
Handled by @comet/upgrade
Update ESLint to v9
package.json
- "eslint": "^8.0.0",
+ "eslint": "^9.0.0",
An ESM compatible ESLint config is required. Delete the related .eslintrc.json
and move the configured rules to the new ESLint flat configuration eslint.config.mjs
.
Migration Guide of ESLint 9.0 can be found here: Migration Guide
admin/eslint.config.mjs
import cometConfig from "@comet/eslint-config/react.js";
/** @type {import('eslint')} */
const config = [
{
ignores: ["schema.json", "src/fragmentTypes.json", "dist/**", "src/**/*.generated.ts"],
},
...cometConfig
];
export default config;
api/eslint.config.mjs
import cometConfig from "@comet/eslint-config/react.js";
/** @type {import('eslint')} */
import cometConfig from "@comet/eslint-config/nestjs.js";
/** @type {import('eslint')} */
const config = [
{
ignores: ["src/db/migrations/**", "dist/**", "src/**/*.generated.ts"],
},
...cometConfig,
];
export default config;
site/eslint.config.mjs
import cometConfig from "@comet/eslint-config/react.js";
/** @type {import('eslint')} */
import cometConfig from "@comet/eslint-config/nextjs.js";
/** @type {import('eslint')} */
const config = [
{
ignores: ["**/**/*.generated.ts", "dist/**", "lang/**", "lang-compiled/**", "lang-extracted/**", ".next/**", "public/**"],
},
...cometConfig,
];
export default config;
After executing the script, create a commit with --no-verify
.
Migrate custom eslint rules
The upgrade script only creates a simple version of the new eslint.config.mjs
.
It adds the old config from .eslintrc.json
to the new file as a comment at the top.
You must now manually go through all the eslint configs and migrate your custom rules (if you have any).
- Check
api/eslint.config.mjs
,admin/eslint.config.mjs
andsite/eslint.config.mjs
- Migrate custom rules
- Remove the comment from the file
- Create a commit with
--no-verify
🤖 Upgrade Prettier from v2 to v3
npx @comet/upgrade@latest v8/prettier-dev-dependencies.ts
Handled by @comet/upgrade
- "prettier": "^2.8.1",
+ "prettier": "^3.4.2",
After executing the script, create a commit with --no-verify
.
Upgrade @comet/eslint-config
to v8
Yes, you can do that before updating everything else to v8.
-
Change the version numbers:
api/package.json- "@comet/eslint-config": "7.24.0",
+ "@comet/eslint-config": "8.0.0", // replace with the newest v8 versionadmin/package.json- "@comet/eslint-config": "7.24.0",
+ "@comet/eslint-config": "8.0.0", // replace with the newest v8 versionsite/package.json- "@comet/eslint-config": "7.24.0",
+ "@comet/eslint-config": "8.0.0", // replace with the newest v8 version -
Execute
npm install
(it might be necessary to usenpm install --force
) -
Create a commit with
--no-verify
API
- Run
npm run lint:eslint -- --fix
to autofix all fixable issues - Commit your changes with
--no-verify
- Run
npm run lint
and manually fix all open issues - Commit your changes with
--no-verify
Admin
-
Run
npm run lint:eslint -- --fix
to autofix all fixable issues -
Commit your changes with
--no-verify
-
Add
react-jsx
to yourtsconfig.json
:- "jsx": "react",
+ "jsx": "react-jsx", -
🤖 Remove React barrel imports
Importing
React
is no longer necessary due to the new JSX transform, which automatically imports the necessaryreact/jsx-runtime
functions. Use individual named imports instead, e.g,import { useState } from "react"
.Execute the following upgrade script:npx @comet/upgrade@latest v8/remove-react-barrel-imports-admin.ts
-
Commit your changes with
--no-verify
-
🤖 Ignore import restrictions for
@mui/material
(this is done temporarily, we'll fix this later during the v8 update)Execute the following upgrade script:npx @comet/upgrade@latest v8/ignore-restricted-imports-admin.ts
-
Commit your changes with
--no-verify
-
Run
npm run lint
and manually fix all open issues -
Commit your changes with
--no-verify
Site
-
Run
npm run lint:eslint -- --fix
to autofix all fixable issues -
Commit your changes with
--no-verify
-
🤖 Remove React barrel imports
Importing
React
is no longer necessary due to the new JSX transform, which automatically imports the necessaryreact/jsx-runtime
functions. Use individual named imports instead, e.g,import { useState } from "react"
.Execute the following upgrade script:npx @comet/upgrade@latest v8/remove-react-barrel-imports-site.ts
-
Commit your changes with
--no-verify
-
Run
npm run lint
and manually fix all open issueswarningIf your project has knip, you might see an error like this regarding
eslint-config-next
:Details
ERROR: Error loading /project/path/site/eslint.config.mjs Reason: Cannot read config file: /project/path/site/node_modules/eslint-config-next/index.js Error: Failed to patch ESLint because the calling module was not recognized. If you are using a newer ESLint version that may be unsupported, please create a GitHub issue: https://github.com/microsoft/rushstack/issues Referenced from: /project/path/site/node_modules/eslint-config-next/core-web-vitals.js ERROR: "lint:knip" exited with 2.
Then you must install eslint-config-next in the site and add it to knip's ignore list as done in this commit: https://github.com/vivid-planet/comet-starter/pull/884/commits/32d6adfe73bbfc5e18eaaffc5dfc37b57f653aac
-
Commit your changes without
--no-verify
. There should be no remaining errors.
Now open a PR from update-eslint-to-v9
to main
Update process
Once all the above PRs are merged, you can now start the actual v8 update. We recommend doing it service-by-service like this:
- Root
- API
- Update the versions in package.json
- Execute
npm install
- Execute all the steps in the migration guide. Commit with
--no-verify
after each step - Run
npm run lint
and fix all remaining errors - Start the API. Fix runtime errors if there are any.
- Repeat for admin
- Repeat for site
Root
-
Create a
update-to-comet-v8
branch -
Open the root
package.json
-
Change the version for
@comet/cli
:- "@comet/cli": "7.25.4",
+ "@comet/cli": "8.0.0", // replace with the newest v8 version -
Execute
npm install
-
Execute
npm run create-site-configs-env
-
Create a commit
API
Before installing, we must update the following dependency versions:
🤖 Upgrade peer dependencies
The following upgrade script will update peer dependency versions and make some minor changes in the code.
npx @comet/upgrade@latest v8/api/before-install
Updates handled by this batch upgrade script
✅ NestJS
Upgrade all your dependencies to support NestJS v11
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/update-nest-dependencies.ts
{
"dependencies": {
+ "@apollo/server": "^4.0.0",
- "@nestjs/apollo": "^10.0.0",
- "@nestjs/common": "^9.0.0",
- "@nestjs/config": "^2.0.0",
- "@nestjs/core": "^9.0.0",
- "@nestjs/graphql": "^10.0.0",
- "@nestjs/passport": "^9.0.0",
- "@nestjs/platform-express": "^9.0.0",
+ "@nestjs/apollo": "^13.0.0",
+ "@nestjs/common": "^11.0.0",
+ "@nestjs/core": "^11.0.0",
+ "@nestjs/graphql": "^13.0.0",
+ "@nestjs/passport": "^11.0.0",
+ "@nestjs/platform-express": "^11.0.0",
- "apollo-server-core": "^3.0.0",
- "apollo-server-express": "^3.0.0",
- "express": "^4.0.0",
+ "express": "^5.0.0",
- "graphql": "^15.0.0",
+ "graphql": "^16.10.0",
},
"devDependencies": {
- "@nestjs/cli": "^9.0.0",
- "@nestjs/schematics": "^9.0.0",
- "@nestjs/testing": "^9.0.0",
+ "@nestjs/cli": "^11.0.0",
+ "@nestjs/schematics": "^11.0.0",
+ "@nestjs/testing": "^11.0.0",
- "@types/express": "^4.0.0",
+ "@types/express": "^5.0.0",
}
}
✅ Add NestJS peer dependencies
Peer dependencies defined by NestJS have been added as peer dependencies to @comet/cms-api
.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/nest-peer-dependencies.ts
To upgrade, install the dependencies in your project:
{
"dependencies": {
+ "class-transformer": "^0.5.1",
- "reflect-metadata": "^0.1.13",
+ "reflect-metadata": "^0.2.2",
- "rxjs": "^7.0.0",
+ "rxjs": "^7.8.1",
}
}
✅ MikroORM
Upgrade all MikroORM dependencies to v6.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/update-mikro-orm-dependencies.ts
{
"dependencies": {
- "@mikro-orm/cli": "^5.9.8",
- "@mikro-orm/core": "^5.9.8",
- "@mikro-orm/migrations": "^5.9.8",
- "@mikro-orm/nestjs": "^5.2.3",
- "@mikro-orm/postgresql": "^5.9.8",
+ "@mikro-orm/cli": "^6.4.0",
+ "@mikro-orm/core": "^6.4.0",
+ "@mikro-orm/migrations": "^6.4.0",
+ "@mikro-orm/nestjs": "^6.0.2",
+ "@mikro-orm/postgresql": "^6.4.0",
},
}
✅ class-validator
The class-validator peer dependency has been bumped to v0.14.0.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/update-class-validator.ts
{
"dependencies": {
- "class-validator": "0.13.2",
+ "class-validator": "^0.14.0",
}
}
✅ Sentry
The Sentry dependency has been bumped to v9.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/update-sentry.ts
-
Upgrade the "@sentry/node" dependency in your
package.json
file:{
"dependencies": {
- "@sentry/node": "^7.0.0",
+ "@sentry/node": "^9.0.0",
},
} -
Update your
main.ts
file to remove allSentry.Handlers
and addSentry.setupExpressErrorHandler(app)
:- app.use(Sentry.Handlers.requestHandler());
- app.use(Sentry.Handlers.tracingHandler());
- app.use(Sentry.Handlers.errorHandler());
+ Sentry.setupExpressErrorHandler(app);
None of the other breaking changes in @sentry/node
should affect us. If you still encounter problems, consult the official migration guides:
✅ @kubernetes/client-node
The @kubernetes/client-node
peer dependency has been bumped to v1.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/update-kubernetes-client-node.ts
{
"dependencies": {
- "@kubernetes/client-node": "^0.18.0",
+ "@kubernetes/client-node": "^1.0.0",
}
}
✅ Remove @comet/blocks-api
The @comet/blocks-api
package has been merged into the @comet/cms-api
package.
Handled by @comet/upgrade
To upgrade, perform the following steps:
Remove the package:
npx @comet/upgrade@latest v8/api/before-install/remove-blocks-packages-api.ts
- "@comet/blocks-api": "^7.x.x",
✅ Remove nestjs-console and install nest-commander
The nestjs-console package isn't actively maintained anymore. We therefore replace it with nest-command.
The upgrade script will remove the nestjs-console
package and install nest-commander
and @types/inquirer
.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/replace-nestjs-console-with-nest-commander.ts
- Uninstall
nestjs-console
- Install
nest-commander
and@types/inquirer
✅ Remove passport
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/api/before-install/remove-passport.ts
Remove all passport-dependencies and add @nestjs/jwt
{
"dependencies": {
- "@nestjs/passport": "^9.0.0",
- ...other passport dependencies
+ "@nestjs/jwt": "^10.2.0",
}
}
API Generator - Add new package @comet/api-generator
The API Generator has been moved into a separate package @comet/api-generator
.
devDependencies: {
+ "@comet/api-generator": "8.0.0", // replace with newest v8 version
}
Install
Now it's time to run npm install:
-
Enter the /api folder:
cd api
-
Delete
node_modules
andpackage-lock.json
to avoid false positive errors:rm package-lock.json && rm -rf node_modules
-
Update
@comet/
packages to v8 -
npm install
‼️ It's likely that the install fails ‼️The upgrade scripts only updates the packages we have in the starter. You probably have more packages that rely on NestJS or MikroORM in your project. Update them by hand based on the errors you are getting and rerun the install!
-
Once the install passed, commit your changes with
--no-verify
NestJS-related changes
-
🤖 Update the custom
formatError
function to hide GraphQL field suggestionsExecute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/update-graphql-format-error.ts
Details
- import { ValidationError } from "apollo-server-express";
+ import { ValidationError } from "@nestjs/apollo";
/* ... */
GraphQLModule.forRootAsync<ApolloDriverConfig>({
/* ... */
useFactory: (moduleRef: ModuleRef) => ({
/* ... */,
formatError: (error) => {
// Disable GraphQL field suggestions in production
if (process.env.NODE_ENV !== "development") {
- if (error instanceof ValidationError) {
+ if (error.extensions?.code === "GRAPHQL_VALIDATION_FAILED") {
return new ValidationError("Invalid request.");
}
}
return error;
},
}),
}), -
You may need to update some of your routes to support Express v5. See the migration guide for more information.
MikroORM-related changes
Follow the official migration guide to upgrade.
We provide upgrade scripts for basic migrations. Please note that these scripts might not cover all necessary migrations.
-
🤖 Remove generic from
BaseEntity
:Execute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/mikro-orm-base-entity-generic.ts
-
🤖 Rename
customType
totype
:Execute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/mikro-orm-custom-type.ts
-
🤖 Rename
onDelete
todeleteRule
:Execute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/mikro-orm-delete-rule.ts
-
🤖 Add a
mikro-orm
script with a dotenv call topackage.json
:Execute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/mikro-orm-dotenv.ts
-
🤖 Change all imports from
@mikro-orm/core
to@mikro-orm/postgresql
:Execute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/mikro-orm-imports.ts
-
🤖 Wrap config in
defineConfig
:Execute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/mikro-orm-ormconfig.ts
-
🤖 Replace
UseRequestContext
withCreateRequestContext
:Execute the following upgrade script:npx @comet/upgrade@latest v8/api/after-install/mikro-orm-create-request-context.ts
🤖 Replace @comet/blocks-api
imports with @comet/cms-api
The @comet/blocks-api
package has been merged into the @comet/cms-api
package.
Thus, all imports must be updated.
npx @comet/upgrade@latest v8/api/after-install/merge-blocks-api-into-cms-api.ts
Details
To upgrade, perform the following steps:
-
Update all your imports from
@comet/blocks-api
to@comet/cms-api
-
Update imports that have been renamed
-
Remove usages of removed export
getFieldKeys
(probably none)
Execute API generator
npm run api-generator
🤖 Use graphiql instead of GraphQL Playground:
npx @comet/upgrade@latest v8/api/after-install/replace-playground-with-graphiql.ts
🤖 Change s3 blob-storage config structure
It's now possible to configure the S3-client completely.
npx @comet/upgrade@latest v8/api/after-install/update-s3-config.ts
Details
Previously configuration had its own structure, now credentials are nested under credentials
and the accessKeyId
and secretAccessKey
are no longer top-level properties. Bucket is not part of s3-config but still required, so it's passed as a top-level property.
blob: {
storage: {
driver: envVars.BLOB_STORAGE_DRIVER,
file: {
path: envVars.FILE_STORAGE_PATH,
},
azure: {
accountName: envVars.AZURE_ACCOUNT_NAME,
accountKey: envVars.AZURE_ACCOUNT_KEY,
},
s3: {
region: envVars.S3_REGION,
endpoint: envVars.S3_ENDPOINT,
bucket: envVars.S3_BUCKET,
- accessKeyId: envVars.S3_ACCESS_KEY_ID,
- secretAccessKey: envVars.S3_SECRET_ACCESS_KEY,
+ credentials: {
+ accessKeyId: envVars.S3_ACCESS_KEY_ID,
+ secretAccessKey: envVars.S3_SECRET_ACCESS_KEY,
+ },
},
},
storageDirectoryPrefix: envVars.BLOB_STORAGE_DIRECTORY_PREFIX,
},
🤖 Add ImgproxyModule
and change config of BlobStorageModule
and DamModule
The FileUploadsModule
has been completely separated from the DamModule
and now works independently.
Some structural changes were necessary to achieve this.
npx @comet/upgrade@latest v8/api/after-install/move-maxSrcResolution-in-comet-config.ts
npx @comet/upgrade@latest v8/api/after-install/update-dam-configuration.ts
Details
You need to modify your AppModule
as follows:
BlobStorageModule.register({
backend: config.blob.storage,
+ cacheDirectory: `${config.blob.storageDirectoryPrefix}-cache`,
}),
+ ImgproxyModule.register(config.imgproxy),
DamModule.register({
damConfig: {
- apiUrl: config.apiUrl,
secret: config.dam.secret,
allowedImageSizes: config.dam.allowedImageSizes,
allowedAspectRatios: config.dam.allowedImageAspectRatios,
filesDirectory: `${config.blob.storageDirectoryPrefix}-files`,
- cacheDirectory: `${config.blob.storageDirectoryPrefix}-cache`,
maxFileSize: config.dam.uploadsMaxFileSize,
+ maxSrcResolution: config.dam.maxSrcResolution,
},
- imgproxyConfig: config.imgproxy,
Scope: DamScope,
File: DamFile,
Folder: DamFolder,
}),
npx @comet/upgrade@latest v8/api/after-install/move-maxSrcResolution-in-comet-config.ts
{
"dam": {
"allowedImageAspectRatios": ["16x9", "4x3", "3x2", "3x1", "2x1", "1x1", "1x2", "1x3", "2x3", "3x4", "9x16"],
+ "maxSrcResolution": 70,
"uploadsMaxFileSize": 500
},
"images": {
"deviceSizes": [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
"imageSizes": [16, 32, 48, 64, 96, 128, 256, 320, 384]
},
"imgproxy": {
- "maxSrcResolution": 70,
"quality": 80
}
}
Import tracing with import
instead of require
if (process.env.TRACING_ENABLED === "1") {
- require("./tracing");
+ import("./tracing");
}
// ...
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let tracing: any;
if (process.env.TRACING_ENABLED) {
- tracing = require("./tracing");
+ tracing = import("./tracing");
}
Replace nestjs-console with nest-commander
The nestjs-console package isn't actively maintained anymore. We therefore replace it with nest-command.
You have to perform the following steps manually:
-
Update
api/src/console.ts
to usenest-commander
. Minimum example:import { CommandFactory } from "nest-commander";
import { AppModule } from "./app.module";
import { createConfig } from "./config/config";
const config = createConfig(process.env);
async function bootstrap() {
const appModule = AppModule.forRoot(config);
// @ts-expect-error CommandFactory doesn't except DynamicModule, only Type<any>
await CommandFactory.run(appModule, {
logger: ["error", "warn", "log"],
serviceErrorHandler: async (error) => {
console.error(error);
process.exit(1);
},
});
}
bootstrap(); -
Update your commands to the new
nest-commander
syntax:
Migrating nestjs-console commands to nest-commander
This section highlights the necessary changes to convert a nestjs-console command to nest-commander.
-
Replace the
@Console()
decorator with@Command()
:- import { Command, Console } from "nestjs-console";
+ import { Command } from "nest-commander";
- @Injectable()
- @Console()
+ @Command({
+ name: "fixtures",
+ description: "Create fixtures with faker.js",
+ })
export class FixturesConsole {
- @Command({
- command: "fixtures",
- description: "Create fixtures with faker.js",
- })
@CreateRequestContext()
async execute(): Promise<void> {
/* ... */
}
} -
Extend
CommandRunner
:+ import { CommandRunner } from "nest-commander";
- export class FixturesConsole {
+ export class FixturesConsole extends CommandRunner {
/* ... */
} -
Add a
super()
call to the constructor:export class FixturesConsole extends CommandRunner {
constructor(@Inject(CONFIG) private readonly config: Config) {
+ super();
}
} -
Rename the executing function to
run
:export class FixturesConsole extends CommandRunner {
@CreateRequestContext()
- async execute(): Promise<void> {
+ async run(): Promise<void> {
/* ... */
}
} -
If necessary, migrate arguments and options.
Arguments: Move from
command
field intoarguments
field:import-redirects.command.ts@Command({
name: "import-redirects",
+ arguments: "<filepath> [comment]",
description: "Import redirects from a CSV file",
})
export class ImportRedirectsCommand extends CommandRunner {
@Command({
- command: "import-redirects [filepath] [comment]",
description: "Import redirects from csv file",
})
@CreateRequestContext()
- async execute(filepath: string, comment = "Imported"): Promise<void> {
+ async run([filepath, comment = "Imported"]: string[]): Promise<void> {
/* ... */
}
}Options: Use the
@Option()
decorator:refresh-block-index-views.command.ts@Command({
name: "refreshBlockIndexViews",
})
export class RefreshBlockIndexViewsCommand extends CommandRunner {
@Command({
command: "refreshBlockIndexViews",
- options: [
- {
- flags: "-f, --force [boolean]",
- defaultValue: false,
- },
- ],
})
@CreateRequestContext()
- async refreshBlockIndexViews(args: { force: boolean }): Promise<void> {
+ async run(arguments: string[], options: { force?: true }): Promise<void> {
/* ... */
}
+ @Option({
+ flags: "-f, --force",
+ })
+ parseForce() {}
}Review the documentation for more information.
-
Optional: Rename console to command:
- export class FixturesConsole extends CommandRunner {
+ export class FixturesCommand extends CommandRunner {
/* ... */
}
Remove passport
The passport dependencies were removed before the install. The following steps must be done manually:
If you're unsure about how to structure the AuthModule, look at the COMET Starter version.
-
Rename the
strategy
-factories and wrap them in...createAuthGuardProviders()
:- createStaticCredentialsBasicStrategy({ ... }),
- createAuthProxyJwtStrategy({ ... }),
- createStaticAuthedUserStrategy({ ... }),
+ ...createAuthGuardProviders(
+ createBasicAuthService({ ... }),
+ createJwtAuthService({ ... }),
+ createStaticUserAuthService({ ... }),
+ ),Configuration changesThe configuration of the AuthServices have changed slightly compared to the strategies, however they remain similar. Consulting the code completion should help to adapt.
-
Add the new
createSitePreviewAuthService
:...createAuthGuardProviders(
// ...
+ createSitePreviewAuthService({ ... }),
), -
Replace
createCometAuthGuard
with the class name:- useClass: createCometAuthGuard([...]),
+ useClass: CometAuthGuard,Passport not supported anymoreCometAuthGuard
does not support Passport strategies anymore. Consider rewriting or wrapping intoAuthServiceInterface
. However, you still can use passport strategies in conjunction with the providedAuthGuard
from@nestjs/passport
. -
Remove
currentUser
prop fromcreateAuthResolver
:createAuthResolver({
// ...
- currentUser: CurrentUser,
}), -
Import
JwtModule
from@nestjs/jwt
:exports: [UserService, AccessControlService],
+ imports: [JwtModule],
Use strings for date-only columns
Starting with v6 MikroORM maps date-only columns to string
instead of Date
.
Perform the following changes:
-
Use
string
instead ofDate
for date-only columns:class Product {
@Property({ type: types.date, nullable: true })
@Field(() => GraphQLDate, { nullable: true })
- availableSince?: Date = undefined;
+ availableSince?: string = undefined;
} -
Use
GraphQLLocalDate
instead ofGraphQLDate
:- import { GraphQLDate } from "graphql-scalars";
+ import { GraphQLLocalDate } from "graphql-scalars";
class Product {
@Property({ type: types.date, nullable: true })
- @Field(() => GraphQLDate, { nullable: true })
+ @Field(() => GraphQLLocalDate, { nullable: true })
availableSince?: string = undefined;
}Why this change?The
GraphQLDate
scalar coerces strings (e.g.,2025-06-30
) toDate
objects when used as an input type, whereas theGraphQLLocalDate
performs no type coercion.
Pass metadata to gqlArgsToMikroOrmQuery
You now need to pass the entity metadata instead of the repository to gqlArgsToMikroOrmQuery
:
- const where = gqlArgsToMikroOrmQuery({ filter, search }, this.repository);
+ const where = gqlArgsToMikroOrmQuery({ filter, search }, this.entityManager.getMetadata(YourEntity));
Typed Permissions System
Search for all @CrudGenerator
or @RequiredPermission
decorators and move all permissions into the AppPermission enum. Add also module augmentation for PermissionOverrides
to include the new AppPermission
enum.
-
Create a new
AppPermission
enum:api/src/auth/app-permission.enum.tsexport enum AppPermission {
news = "news",
products = "products",
manufacturers = "manufacturers",
} -
Add
AppPermission
toUserPermissionsModule
:api/src/app.module.tsUserPermissionsModule.forRootAsync({
useFactory: (userService: UserService, accessControlService: AccessControlService) => ({
...
}),
inject: [UserService, AccessControlService],
imports: [authModule],
+ AppPermission,
}), -
Create a new file and add module augmentation for
PermissionOverrides
:api/src/auth/permission.interface.tsimport { type AppPermission } from "@src/auth/app-permission.enum";
declare module "@comet/cms-api" {
export interface PermissionOverrides {
app: AppPermission;
}
} -
Update all
@CrudGenerator
decorators where required permissions are not defined:api/src/news/entities/news.entity.ts-@CrudGenerator({ targetDirectory: `${__dirname}/../generated/` })
+@CrudGenerator({ targetDirectory: `${__dirname}/../generated/`, requiredPermission: ["news"] }) -
In admin, also add module augmentation for
PermissionOverrides
with created types from GraphQL Codegen:demo/admin/src/App.tsx+import type { GQLPermission } from "@src/graphql.generated";
...
declare module "@comet/cms-admin" {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface ContentScope extends BaseContentScope {}
+
+ export interface PermissionOverrides {
+ permission: GQLPermission;
+ }
}
API Generator - Removed Special status
Field Behavior
Previously, if entities specified a status
enum, it was automatically added to list queries arguments with a default value.
This special handling has been removed. The status
field now behaves like a normal enum. Filtering by status
can be
done with the normal filtering mechanism.
API Generator - Don't commit generated files
The improved performance of API Generator doesn't make it necessary anymore to add generated files to git. You can remove previously generated files and generate them on demand:
-
Run api-generator in prebuild:
api/package.jsonscripts: {
- "prebuild": "rimraf dist",
+ "prebuild": "rimraf dist && npm run api-generator",
} -
lint:generated-files-not-modified
script can be removed:api/package.jsonscripts: {
- "lint:generated-files-not-modified": "npm run api-generator && git diff --exit-code HEAD -- src/**/generated",
- "lint": "npm run lint:eslint && npm run lint:tsc",
- "lint:ci": "npm run lint && npm run lint:generated-files-not-modified",
+ "lint": "npm run api-generator && run-p lint:eslint lint:tsc",
+ "lint:ci": "npm run lint",
} -
Add generated files to eslint ignore:
api/eslint.config.mjsscripts: {
- ignores: ["src/db/migrations/**", "dist/**", "src/**/*.generated.ts"],
+ ignores: ["src/db/migrations/**", "dist/**", "src/**/*.generated.ts", "src/**/generated/**"],
} -
Add generated files to .gitignore:
api/.gitignore+ # API generator
+ src/**/generated -
And finally delete generated files from git:
git rm -r --cached api/src/*/generated
Fix linting errors
EsLint
cd api
npm run lint:eslint -- --fix
- Commit with
--no-verify
- Manually fix all remaining errors
- Commit with
--no-verify
Type errors
npm run lint:tsc
- Fix all occurring errors
- Commit with
--no-verify
Overall lint
npm run lint
- Fix all occurring errors
- Commit without
--no-verify
Fix runtime errors
- Start docker with
dpm start docker
- Start the api with
dpm start api
- Check the logs with
dpm logs api
- Fix occurring errors
- Once the API runs without problems: Commit without
--no-verify
Admin
🤖 Upgrade peer dependencies
The following upgrade script will update peer dependency versions and make some minor changes in the code.
npx @comet/upgrade@latest v8/admin/before-install
Updates handled by this batch upgrade script
✅ React
The React dependency has been bumped to v18.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/update-react-dependencies.ts
{
"dependencies": {
- "react": "^17.0.2",
- "react-dom": "^17.0.2",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
},
"devDependencies": {
- "@types/react": "^17.0.83",
- "@types/react-dom": "^17.0.26",
+ "@types/react": "^18.3.18",
+ "@types/react-dom": "^18.3.5"
}
}
✅ MUI
The MUI dependencies (@mui/material
, @mui/system
, @mui/utils
, @mui/icons-material
, @mui/lab
) were bumped to v7.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/update-mui-dependencies.ts
- "@mui/icons-material": "^5.0.0",
- "@mui/lab": "^5.0.0-alpha.76",
- "@mui/material": "^5.0.0",
- "@mui/system": "^5.0.0",
- "@mui/utils": "^5.0.0",
+ "@mui/icons-material": "^7.0.0",
+ "@mui/lab": "^7.0.0-beta.9",
+ "@mui/material": "^7.0.0",
+ "@mui/system": "^7.0.0",
+ "@mui/utils": "^7.0.0",
✅ MUI X (DataGrid)
The MUI dependencies (@mui/x-data-grid
, @mui/x-data-grid-pro
) were bumped to v7.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/update-mui-x-dependencies.ts
In package.json
update the version of the MUI X packages to ^7.22.3
.
- "@mui/x-data-grid": "^5.x.x",
- "@mui/x-data-grid-pro": "^5.x.x",
- "@mui/x-data-grid-premium": "^5.x.x",
+ "@mui/x-data-grid": "^7.22.3",
+ "@mui/x-data-grid-pro": "^7.22.3",
+ "@mui/x-data-grid-premium": "^7.22.3",
✅ Vite / SWC
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/update-swc-dependencies.ts
- "@swc/plugin-emotion": "^3.0.13",
- "@vitejs/plugin-react-swc": "^3.7.2",
+ "@swc/plugin-emotion": "^8.7.2",
+ "@vitejs/plugin-react-swc": "^3.8.0",
✅ Remove @comet/blocks-admin
The @comet/blocks-admin
package has been merged into the @comet/cms-admin
package.
Handled by @comet/upgrade
Remove the package:
npx @comet/upgrade@latest v8/admin/before-install/remove-blocks-packages-admin.ts
- "@comet/blocks-admin": "^7.x.x",
✅ Remove @comet/admin-theme
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/remove-admin-theme-package.ts
✅ Remove @comet/admin-react-select
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/remove-comet-admin-react-select-dependency.ts
- "@comet/admin-react-select": "^7.x.x",
✅ Remove ignore-restricted-imports comments
Removes the comments we added in step 4.
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/remove-v8-eslint-disable-comments-admin.ts
-// TODO v8: remove eslint-disable-next-line
-// eslint-disable-next-line no-restricted-imports
Use MUI pickers for DataGrid
Date / DateTime filters
Handled by @comet/upgrade
npx @comet/upgrade@latest v8/admin/before-install/use-mui-date-picker-in-grid.ts
This update improves the UX of date filtering by replacing the current date picker solution with MUI's DatePicker
.
It requires installation of new dependencies and setup of LocalizationProvider
in your app.
Migration steps:
- Install dependencies:
Add the following dependencies to your
package.json
:
"dependencies": {
+ "@mui/x-date-pickers": "^7.29.4",
+ "date-fns": "^4.1.0",
}
Update your application root to include `LocalizationProvider from @mui/x-date-pickers:
+ import { LocalizationProvider } from "@mui/x-date-pickers";
+ import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFnsV3";
+ import { enUS } from "date-fns/locale";
<IntlProvider locale="en" messages={getMessages()}>
+ <LocalizationProvider adapterLocale={enUS} dateAdapter={AdapterDateFns}>
<MuiThemeProvider theme={theme}>{/* App Content */}</MuiThemeProvider>
+ </LocalizationProvider>
</IntlProvider>;
If you are already using the dataGridDateColumn
or dataGridDateTimeColumn
helpers, the new MUI DatePicker will be used automatically for filtering:
import { dataGridDateTimeColumn } from "@comet/admin";
const columns: GridColDef[] = [
{
...dataGridDateTimeColumn,
field: "createdAt",
headerName: "Created at",
},
];
If your application uses internationalization or a language other than English (US), additional configuration is required. The codemod will add a TODO comment at the relevant location to remind you to configure the appropriate locale for the LocalizationProvider.
Add new package @comet/admin-generator
The Admin Generator has been moved into a separate package @comet/admin-generator
.
devDependencies: {
+ "@comet/admin-generator": "8.0.0", // replace with the newest v8 version
}
Install
Now it's time to run npm install:
-
Enter the /admin folder:
cd admin
-
Delete
node_modules
andpackage-lock.json
to avoid false positive errors:rm package-lock.json && rm -rf node_modules
-
Update
@comet/
packages to v8 -
npm install
‼️ It's likely that the install fails ‼️The upgrade scripts only updates the packages we have in the starter. You probably have more packages that rely on MUI or React in your project. Update them by hand based on the errors you are getting and rerun the install!
-
Once the install passed, commit your changes with
--no-verify
Remove @comet/blocks-admin
The @comet/blocks-admin
package has been merged into the @comet/cms-admin
package.
-
🤖 Update all imports:
Execute the following upgrade script:npx @comet/upgrade@latest v8/admin/after-install/clipboard-helpers.ts
npx @comet/upgrade@latest v8/admin/after-install/merge-blocks-admin-into-cms-admin.tsDetails
To upgrade, perform the following steps:
- Update all your imports from
@comet/blocks-admin
to@comet/cms-admin
- Update imports that have been renamed
- Update all your imports from
-
Manually remove usages of removed exports
CannotPasteBlockDialog
,ClipboardContent
,useBlockClipboard
,Collapsible
,CollapsibleSwitchButtonHeader
,usePromise
,DispatchSetStateAction
,SetStateAction
, andSetStateFn
tipUse
Dispatch<SetStateAction<T>>
fromreact
instead ofDispatchSetStateAction
.
🤖 Remove @comet/admin-theme
npx @comet/upgrade@latest v8/admin/after-install/merge-admin-theme-into-admin.ts
Handled by @comet/upgrade
The @comet/admin-theme
package has been merged into @comet/admin
, adjust the imports accordingly:
- import { createCometTheme } from "@comet/admin-theme";
+ import { createCometTheme } from "@comet/admin";
const theme = createCometTheme();
Remove @comet/admin-react-select
@comet/admin-react-select
was removed.
It is recommended to use the AutocompleteField
or the SelectField
components from @comet/admin
instead:
- import { FinalFormReactSelectStaticOptions } from "@comet/admin-react-select";
- <Field name="color" type="text" component={FinalFormReactSelectStaticOptions} fullWidth options={options} />;
+ import { AutocompleteField } from "@comet/admin";
+ <AutocompleteField name="color" label="Color" options={options} fullWidth />;
Add proxy for /api
and /dam
URLs
In our deployed setup, all API requests from the admin are routed through the AuthProxy that runs under the admin domain. To be closer to this setup, we now also do that locally:
# api
API_PORT=4000
-API_URL=http://${DEV_DOMAIN:-localhost}${WORKAROUND_DOTENV_ISSUE}:${API_PORT}/api # or similar
+API_URL=$ADMIN_URL/api
Also, the API now only returns relative URLs for DAM assets.
You must proxy the /dam
URLs in your application to the API.
This must be done for local development and production.
In development:
Add the proxy to your vite config:
//...
server: {
// ...
proxy: process.env.API_URL_INTERNAL
? {
"/api": {
target: new URL(process.env.API_URL_INTERNAL).origin,
changeOrigin: true,
secure: false,
},
"/dam": {
target: process.env.API_URL_INTERNAL,
changeOrigin: true,
secure: false,
},
}
: undefined,
// ...
},
//...
or in your webpack config (for old projects):
const config = (env: unknown, argv: Argv): webpack.Configuration => {
// ...
return {
// ...
devServer: {
// ...
proxy: process.env.API_URL_INTERNAL
? {
"/api": {
target: new URL(process.env.API_URL_INTERNAL).origin,
changeOrigin: true,
secure: false,
},
"/dam": {
target: process.env.API_URL_INTERNAL,
changeOrigin: true,
secure: false,
},
}
: undefined,
},
};
};
In production:
Add the proxy to your admin server:
"dependencies": {
// ...
+ "http-proxy-middleware": "^3.0.3"
// ...
},
+ const { createProxyMiddleware } = require("http-proxy-middleware");
// ...
app.get("/status/health", (req, res) => {
// ...
});
+ const proxyMiddleware = createProxyMiddleware({
+ target: process.env.API_URL_INTERNAL + "/dam",
+ changeOrigin: true,
+ });
+ app.use("/dam", proxyMiddleware);
// ...
You might also need to add API_URL_INTERNAL
to your values.tpl.yaml
for deployment:
admin:
env:
ADMIN_URL: "https://$ADMIN_DOMAIN"
API_URL: "https://$ADMIN_DOMAIN/api"
+ API_URL_INTERNAL: "http://$APP_NAME-$APP_ENV-api:3000/api"
🤖 Merge providers into CometConfigProvider
The separate providers for CMS features (e.g, DamConfigProvider
) have been merged into a CometConfigProvider
.
npx @comet/upgrade@latest v8/admin/after-install/comet-config-provider.ts
Note: This upgrade script is experimental and might not work as expected in your application. Review the result carefully.
Handled by @comet/upgrade
Wrap your application with the CometConfigProvider
:
import { CometConfigProvider } from "@comet/cms-admin";
function App() {
return (
<CometConfigProvider
apiUrl={config.apiUrl}
graphQLApiUrl={`${config.apiUrl}/graphql`}
adminUrl={config.adminUrl}
>
{/* Application */}
</CometConfigProvider>
);
}
Move module configs to the new provider:
<CometConfigProvider
apiUrl={config.apiUrl}
graphQLApiUrl={`${config.apiUrl}/graphql`}
adminUrl={config.adminUrl}
+ dam={{
+ ...config.dam,
+ scopeParts: ["domain"],
+ contentGeneration: {
+ generateAltText: true,
+ generateImageTitle: true,
+ },
+ }}
>
{/* Application */}
</CometConfigProvider>
Remove the old config providers:
- <DamConfigProvider>
{/* Application */}
- </DamConfigProvider>
Update usages of renamed exports:
useSitesConfig()
->useSiteConfigs()
useLocale()
->useContentLanguage()
useCmsBlockContext()
->useBlockContext()
Remove the allCategories
prop from PagesPage
:
<PagesPage
path="/pages/pagetree/main-navigation"
- allCategories={pageTreeCategories}
documentTypes={pageTreeDocumentTypes}
category="MainNavigation"
renderContentScopeIndicator={(scope) => <ContentScopeIndicator scope={scope} />}
/>
This upgrade script is experimental and might not work as expected in your application. Review the result carefully.
Adapt to changes in ContentScopeProvider
Use interface augmentation for ContentScope
+ import { type ContentScope as BaseContentScope } from "@src/site-configs";
+ declare module "@comet/cms-admin" {
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
+ interface ContentScope extends BaseContentScope {}
+ }
export function App() {
The ContentScopeInterface
export from @comet/cms-admin
was removed.
Instead, use ContentScope
directly:
- import { type ContentScopeInterface } from "@comet/cms-admin";
+ import { type ContentScope } from "@comet/cms-admin";
Preferably use ContentScopeProvider directly from Comet
Move the scope labels from admin to the API, for example:
UserPermissionsModule.forRootAsync({
useFactory: (userService: StaticUsersUserService, accessControlService: AccessControlService) => ({
availableContentScopes: config.siteConfigs.flatMap((siteConfig) =>
- siteConfig.scope.languages.map((language) => ({
- domain: siteConfig.scope.domain,
- language,
- })),
+ siteConfig.scope.languages.map((language) => ({
+ scope: {
+ domain: siteConfig.scope.domain,
+ language,
+ },
+ label: { domain: siteConfig.name },
+ })),
),
// ...
}),
// ...
}),
Then you can use the ContentScopeProvider
from @comet/cms-admin
directly in your App.tsx
and delete admin/src/common/ContentScopeProvider.tsx
:
- import { ContentScopeProvider } from "./common/ContentScopeProvider";
+ import { ContentScopeProvider } from "@comet/cms-admin";
// Delete `admin/src/common/ContentScopeProvider.tsx`
You should also use useContentScope
from @comet/cms-admin
.
However, if you need custom behavior, you can keep admin/src/common/ContentScopeProvider.tsx
while skipping above change.
Make sure to remove the generics:
- export function useContentScopeConfig(p: ContentScopeConfigProps): void {
- return useContentScopeConfigLibrary(p);
- }
- ContentScopeValues<ContentScope>
+ ContentScopeValues
- <ContentScopeProviderLibrary<ContentScope>>
+ <ContentScopeProviderLibrary>
React-related changes
The React dependency has been bumped to v18.
Follow the official migration guide to upgrade.
Probably, there's not much to do here. You can also fix potential errors later during the lint step.
Use types-react-codemod to fix potential TypeScript compile errors when upgrading to @types/react@^18.0.0
.
MUI-related changes
The MUI dependencies (@mui/material
, @mui/system
, @mui/utils
, @mui/icons-material
, @mui/lab
) were bumped to v7.
-
🤖 Execute MUI codemods to update your code
Execute the following upgrade script:npx @comet/upgrade@latest v8/admin/after-install/mui-codemods.ts
infoWhen executing the codemods, some errors relating to
fragmentTypes.json
orcomet-config.json
can occur. You can just ignore them. -
Follow the official migration guides to upgrade:
- Upgrade to MUI v6
- Upgrade to MUI v7
info
Probably, there's not much to do here. You can also fix potential errors later during the lint step.
MUI X (DataGrid)-related changes
The MUI dependencies (@mui/x-data-grid
, @mui/x-data-grid-pro
) were bumped to v7.
-
Search for columns with the
type: "dateTime"
. You must add avalueGetter
:<DataGrid
//other props
columns=[
{
field: "updatedAt",
type: "dateTime",
+ valueGetter: (params, row) => row.updatedAt && new Date(row.updatedAt)
}]
/> -
Search for
valueGetter
andvalueFormatter
Change the arguments passed to the functions. Previously, arguments were passed as an object. Now, they are passed directly as individual parameters
<DataGrid
//other props
columns=[
{
field: "updatedAt",
type: "dateTime",
- valueGetter: ({params, row}) => row.updatedAt && new Date(row.updatedAt)
+ valueGetter: (params, row) => row.updatedAt && new Date(row.updatedAt)
- valueFormatter: ({value}) => (value ? intl.formatDate(value, { dateStyle: "medium", timeStyle: "short" }) : ""),
+ valueFormatter: (value) => (value ? intl.formatDate(value, { dateStyle: "medium", timeStyle: "short" }) : ""),
}]
/> -
A lots of props have been renamed from MUI, for a detailed look, see the official migration guide v5 -> v6 and migration guide v6 -> v7.
There is also a codemod from MUI which handles most of the changes:
Execute the following upgrade script:npx @comet/upgrade@latest v8/admin/after-install/mui-x-codemods.ts
Update usage of DataGridToolbar
DataGridToolbar
has been simplified to a basic wrapper component. Props and features from the standard Toolbar
component have been removed, along with the density
prop since density is now controlled by the DataGrid
.
The new usage simplifies the component structure - children can now be passed directly without needing to wrap them in ToolbarItem
and ToolbarActions
components:
- <DataGridToolbar density="compact">
+ <DataGridToolbar>
- <ToolbarItem>
<GridToolbarQuickFilter />
- </ToolbarItem>
- <ToolbarItem>
<GridFilterButton />
- </ToolbarItem>
- <ToolbarItem>
<GridColumnsButton />
- </ToolbarItem>
<FillSpace />
- <ToolbarActions>
<Button responsive variant="outlined">
Secondary action
</Button>
<Button responsive startIcon={<AddIcon />}>
Add item
</Button>
- </ToolbarActions>
</DataGridToolbar>
🤖 Pass columns instead of apiRef to muiGridSortToGql
Function
npx @comet/upgrade@latest v8/admin/after-install/mui-grid-sort-to-gql.ts
Note: This upgrade script will naively change the second argument of muiGridSortToGql
function to columns
, assuming that columns
is available in the current scope.
Details
The muiGridSortToGql
helper now expects the columns instead of the apiRef
:
const columns : GridColDef[] = [/* column definitions*/];
const dataGridRemote = useDataGridRemote();
const persistentColumnState = usePersistentColumnState("persistent_column_state");
- muiGridSortToGql(dataGridRemote.sortModel, persistentColumnState.apiRef);
+ muiGridSortToGql(dataGridRemote.sortModel, columns);
This upgrade script will naively change the second argument of muiGridSortToGql
function to columns
, assuming that columns
is available in the current scope.
Remove error
prop from DataGrid
The error and onError props were removed - the grid no longer catches errors during rendering. To catch errors that happen during rendering use the error boundary. The components.ErrorOverlay slot was also removed.
npx @comet/upgrade@latest v8/admin/after-install/mui-data-grid-remove-error-prop.ts
Note: Error handling must be implemented manually, the upgrade script simply removes all usages of the error prop on DataGrids and adds a TODO: comment.
This upgrade script simply removes all usages of the error prop on DataGrids and adds a TODO: comment. Error handling must be implemented manually.
The recommended way to handle errors is to use the ErrorBoundary
in the parent component and throw errors where the query error happens.
- const { loading, data, error } = useQuery(/* query parameters */)
- <DataGrid error={error} /* other props */ >
+ const { loading, data, error } = useQuery(/* query parameters */)
+ if (error) {
+ throw error
+ }
+ <DataGrid /* other props */ >
useDataGridRemote
Hook - Return Value
The useDataGridRemote
hook has been changed to match the updated DataGrid props:
- const { pageSize, page, onPageSizeChange } = useDataGridRemote();
+ const { paginationModel, onPaginationModelChange } = useDataGridRemote();
rowCount
must be passedBe aware that you must pass rowCount
to the DataGrid when using the useDataGridRemote
hook. Otherwise, the pagination component will show a NaN
value when used with server-side pagination.
i18n for MUI X date picker
In the before-install script, a LocalizationProvider
was added to App.tsx
.
A adapterLocale
is passed to the provider.
If your application uses internationalization or a language other than English (US), make sure to pass the right locale based on the supported languages.
🤖 Rename Menu
and related components to MainNavigation
in @comet/admin
npx @comet/upgrade@latest v8/admin/after-install/rename-menu-components-in-admin.ts
Handled by @comet/upgrade
To better differentiate between imports from @comet/admin
and @mui/material
, the following components and related types have been renamed:
Menu
→MainNavigation
MenuProps
→MainNavigationProps
MenuClassKey
→MainNavigationClassKey
MenuItem
→MainNavigationItem
MenuItemProps
→MainNavigationItemProps
MenuItemClassKey
→MainNavigationItemClassKey
MenuCollapsibleItem
→MainNavigationCollapsibleItem
MenuCollapsibleItemProps
→MainNavigationCollapsibleItemProps
MenuCollapsibleItemClassKey
→MainNavigationCollapsibleItemClassKey
IWithMenu
→WithMainNavigation
withMenu
→withMainNavigation
MenuItemAnchorLink
→MainNavigationItemAnchorLink
MenuItemAnchorLinkProps
→MainNavigationItemAnchorLinkProps
MenuItemGroup
→MainNavigationItemGroup
MenuItemGroupClassKey
→MainNavigationItemGroupClassKey
MenuItemGroupProps
→MainNavigationItemGroupProps
MenuItemRouterLink
→MainNavigationItemRouterLink
MenuItemRouterLinkProps
→MainNavigationItemRouterLinkProps
The MenuContext
has been removed, use the new useMainNavigation
hook instead.
Dialog-related changes
🤖 Import Dialog
from @comet/admin
package
npx @comet/upgrade@latest v8/admin/after-install/update-import-of-dialog.ts
Details
- import { Dialog } from "@mui/material";
+ import { Dialog } from "@comet/admin";
🤖 Add DialogContent
to EditDialog
npx @comet/upgrade@latest v8/admin/after-install/add-dialog-content-to-edit-dialog.ts
Details
The DialogContent
inside EditDialog
has been removed.
To maintain the existing styling of EditDialog
, such as for forms and text, manually wrap the content with DialogContent
to ensure proper spacing.
For grids or other elements that already handle their own spacing (e.g., DataGrid
), adding DialogContent
is not necessary.
<EditDialog>
//...
+ <DialogContent>
+ //...
+ </DialogContent>
// ...
</EditDialog>
Tooltip-related Changes
🤖 Import Tooltip
from @comet/admin
package
npx @comet/upgrade@latest v8/admin/after-install/tooltip-1-update-import.ts
Details
- import { Tooltip } from "@mui/material";
+ import { Tooltip } from "@comet/admin";
🤖 Remove trigger
prop from Tooltip
npx @comet/upgrade@latest v8/admin/after-install/tooltip-2-remove-trigger-prop.ts
Details
The trigger
prop has been removed. The combined hover
/focus
trigger is now the only supported behavior.
Example:
<Tooltip
- trigger="hover"
></Tooltip>
🤖 Import Button
from @comet/admin
package
npx @comet/upgrade@latest v8/admin/after-install/replace-mui-button-with-comet-admin-button.ts
Details
- import { Button } from "@mui/material";
+ import { Button } from "@comet/admin";
Choose correct Button
variant
The Button
from @comet/admin
only has a smaller set of variants defined by UX:
type Variant =
| "primary"
| "secondary"
| "outlined"
| "destructive"
| "success"
| "textLight"
| "textDark";
You must choose visually, which variant is correct for you. Probably the two most common cases are:
- <Button color="primary" variant="contained" />
+ <Button />
- <Button variant="text" />
+ <Button variant="textDark" />
FinalFormToggleButtonGroup
deprecated
FinalFormToggleButtonGroup
has been deprecated and a new component ToggleButtonGroupField
got introduced that has the Final Form Field wrapped around it.
- import { FinalFormToggleButtonGroup } from "@comet/cms-admin";
+ import { ToggleGroupButtonField } from "@comet/admin";
...
+ FormValueType = "value1" | "value2";
- <Field
- name="formValue"
- label={"Field Label"}
- component={FinalFormToggleButtonGroup}
- options={[
- { value: "value1", icon: <Info /> },
- { value: "value2", icon: <Error /> },
- ]}
- optionsPerRow={2}
- />
+ <ToggleGroupButtonField<FormValueType>
+ name="formValue"
+ label={"Field Label"}
+ options={[
+ { value: "value1", label: <Info /> },
+ { value: "value2", label: <Error /> },
+ ]}
+ optionsPerRow={2}
+ />
The FinalFormToggleButtonGroup
component is still available, but moved from @comet/cms-admin
to @comet/admin
package. Furthermore, the value icon
in the options
prop has been renamed to label
.
- <Field
- name="formValue"
- label={"Field Label"}
- component={FinalFormToggleButtonGroup}
- options={[
- { value: "value1", icon: <Info /> },
+ { value: "value1", label: <Info /> },
- { value: "value2", icon: <Info /> },
+ { value: "value2", label: <Info /> },
- ]}
- optionsPerRow={2}
- />
Add the LocalDate
scalar to the GraphQL Codegen config
scalars: rootBlocks.reduce(
(scalars, rootBlock) => ({ ...scalars, [rootBlock]: rootBlock }),
+ { LocalDate: "string" }
)
DashboardWidgetRoot
/ LatestContentUpdates
no longer handles Grid layout
The DashboardWidgetRoot
/ LatestContentUpdates
component no longer wraps its children in a <Grid>
component. This means that layout and sizing must now be handled by the parent component.
Migration steps `DashboardWidgetRoot:
-
Before:
DashboardWidgetRoot
automatically wrapped its content in a grid item, e.g.<DashboardWidgetRoot>{/* widget content */}</DashboardWidgetRoot>
-
After:
You must now wrapDashboardWidgetRoot
in a<Grid item>
yourself:<Grid size={{ xs: 12, lg: 6 }}>
<DashboardWidgetRoot>{/* widget content */}</DashboardWidgetRoot>
</Grid>
Migration steps LatestContentUpdates
:
-
Before:
<LatestContentUpdates />
-
After:
<Grid size={{ xs: 12, lg: 6 }}>
<LatestContentUpdates />
</Grid>
Action required:
Review all usages of DashboardWidgetRoot
/ LatestContentUpdates
in your dashboards and ensure they are wrapped in a <Grid>
(or another layout component as appropriate). This gives you full control over widget placement and sizing.
Move redirects scopeParts
to CometConfigProvider
.
Previously scopeParts
were passed to createRedirectsPage
. Those need to be removed:
const RedirectsPage = createRedirectsPage({
customTargets: { news: NewsLinkBlock },
- scopeParts: ["domain"],
});
Instead add the redirect config to your CometConfigProvider
:
<CometConfigProvider
apiUrl={config.apiUrl}
graphQLApiUrl={`${config.apiUrl}/graphql`}
adminUrl={config.adminUrl}
dam={{
...config.dam,
scopeParts: ["domain"],
contentGeneration: {
generateAltText: true,
generateImageTitle: true,
},
}}
+ redirects={{
+ scopeParts: ["domain"]
+ }}
>
{/* Application */}
</CometConfigProvider>
Rework createRedirectsPage
usage to accept linkBlock
instead of customTargets
.
Previously, customTargets
were passed directly:
const RedirectsPage = createRedirectsPage({
customTargets: { news: NewsLinkBlock },
});
Now, you should first create the RedirectsLinkBlock
and then provide it to createRedirectsPage
:
export const RedirectsLinkBlock = createRedirectsLinkBlock({
news: NewsLinkBlock,
});
export const RedirectsPage = createRedirectsPage({
linkBlock: RedirectsLinkBlock,
});
This change was made because RedirectsLinkBlock
is also needed by RedirectDependency
, and can therefore be reused.
Fix linting errors
EsLint
cd admin
npm run lint:eslint -- --fix
- Commit with
--no-verify
- Manually fix all remaining errors
- Commit with
--no-verify
Type errors
npm run lint:tsc
- Fix all occurring errors
- Commit with
--no-verify
Overall lint
npm run lint
- Fix all occurring errors
- Commit without
--no-verify
Fix runtime errors
- Start the api with
dpm start admin
- Check the logs with
dpm logs admin
- Fix occurring errors
- Once the API runs without problems: Commit without
--no-verify
Site
Switch from @comet/cms-site
to @comet/site-nextjs
Ignore this if you already did it beforehand in step 3. Otherwise, go back and do it now.
Install
Now it's time to run npm install:
- Enter the /site folder:
cd site
- Delete
node_modules
andpackage-lock.json
to avoid false positive errors:rm package-lock.json && rm -rf node_modules
- Update
@comet/
packages to v8 npm install
- Once the install passed, commit your changes with
--no-verify
🤖 Remove graphQLFetch
from sitePreviewRoute
calls
npx @comet/upgrade@latest v8/site/after-install/remove-graphql-client-from-site-preview-handlers.ts
Details
- return sitePreviewRoute(request, createGraphQLFetch());
+ return sitePreviewRoute(request);
Remove x-relative-dam-urls
header from graphQLClient
// ...
return createGraphQLFetchLibrary(
createFetchWithDefaults(fetch, {
// ...
headers: {
- "x-relative-dam-urls": "1",
// ...
},
}),
`${process.env.API_URL_INTERNAL}/graphql`,
);
Add the LocalDate
scalar to the GraphQL Codegen config
scalars: rootBlocks.reduce(
(scalars, rootBlock) => ({ ...scalars, [rootBlock]: rootBlock }),
+ { LocalDate: "string" }
)
Fix linting errors
EsLint
cd site
npm run lint:eslint -- --fix
- Commit with
--no-verify
- Manually fix all remaining errors
- Commit with
--no-verify
Type errors
npm run lint:tsc
- Fix all occurring errors
- Commit with
--no-verify
Overall lint
npm run lint
- Fix all occurring errors
- Commit without
--no-verify
Fix runtime errors
- Start the site with
dpm start site
- Check the logs with
dpm logs site
- Fix occurring errors
- Execute a local prod build:
./build-and-run-site.sh
(if you don't have the script yet, get it from the COMET Starter) - Once the API runs without problems: Commit without
--no-verify