Skip to content

Commit

Permalink
Migration Guide from v4 to v5 (#1406)
Browse files Browse the repository at this point in the history
Co-authored-by: Johannes Obermair <48853629+johnnyomair@users.noreply.github.com>
  • Loading branch information
thomasdax98 and johnnyomair authored Nov 21, 2023
1 parent cde6c8c commit 02ac607
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/docs/migration/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: Migration
sidebar_position: 12
---
185 changes: 185 additions & 0 deletions docs/docs/migration/migration-from-v4-to-v5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
---
title: Migrating from v4 to v5
sidebar_position: 1
---

# Migrating from v4 to v5

## API

### blocks-meta.json

The key (type) of OneOfBlocks is now included in the `blocks-meta.json`.

This is only a problem if you still have your own `generate-block-types.ts` in your project. In that case, you must switch to `@comet/cli`:

1. Install `@comet/cli` as a dev dependency
2. Replace the scripts in the package.json of your admin:

```diff
- "generate-block-types": "dotenv -c -- ts-node generate-block-types.ts",
+ "generate-block-types": "comet generate-block-types --inputs",
```

3. Replace the scripts in the package.json of your site:

```diff
- "generate-block-types": "dotenv -c -- ts-node generate-block-types.ts",
+ "generate-block-types": "comet generate-block-types",
```

### indexData()

Previously, `BlockIndexData` had one field: `damFileIds`. It could only represent dependencies to DAM files. Now, `BlockIndexData` has a generic `dependencies` field. It can represent dependencies to any entity.

The `indexData()` method of a block must be refactored

```diff
indexData(): BlockIndexData {
- return {
- damFileIds: this.damFileId ? [this.damFileId] : [],
- };
+ if (this.damFileId === undefined) {
+ return {};
+ }
+
+ return {
+ dependencies: [
+ {
+ targetEntityName: File.name,
+ id: this.damFileId,
+ },
+ ],
+ };
}
```

### FilesService.upload()

The method signature changed.
The second argument is now an options object.
You may have to adjust this in your fixtures.

```diff
- await filesService.upload(file, folderId);
+ await filesService.upload(file, { folderId });
```

### @IsOptional() -> @IsUndefinable() and @IsNullable()

`class-validator` offers the `@IsOptional()` decorator that allows `undefined` and `null`.
COMET now offers the more specific `@IsUndefinable()` and `@IsNullable()` decorators to avoid bugs.
Use these decorators from now on and (if possible) replace existing `@IsOptional()` with `@IsUndefinable()` or `@IsNullable()`.

### PartialType

COMET now has an own implementation of `PartialType` using `@IsUndefinable()` (instead of `@IsOptional()`).
Uses of `PartialType` from `@nestjs/mapped-types` should be replaced with `PartialType` from `@comet/cms-api`.

## Admin

### Admin Generator

Add the following command to the `package.json` of your admin app:

```diff
+ "admin-generator": "rimraf 'src/*/generated' && comet-admin-generator generate crud-generator-config.ts",
```

### Documents (DocumentInterface)

The `DocumentInterface` now requires a `dependencies()` and a `replaceDependenciesInOutput()` method. However, you don't have to implement them yourself.

**Instead, use the new `createDocumentRootBlocksMethods()` to generate the methods.**
It further generates `anchors()` and `inputToOutput()`.

```diff
export const Page: DocumentInterface<Pick<GQLPage, "content" | "seo">, GQLPageInput> = {
// ...
- inputToOutput: (input) => {},
- anchors: (input) => {},
+ ...createDocumentRootBlocksMethods({
+ content: PageContentBlock,
+ seo: SeoBlock,
+ }),
};
```

### Blocks (BlockInterface)

The `BlockInterface` now has the methods `dependencies()` and `replaceDependenciesInOutput()`.
However, you usually don't have to implement them. Only if your block has dependencies to some entity (e.g. a link to a `PageTreeNode` or uses a `DamFile`).

`dependencies()` returns the dependency information for the block. It could look like this:

```tsx
dependencies: (state) => {
const dependencies: BlockDependency[] = [];

if (state.damFile?.id) {
dependencies.push({
targetGraphqlObjectType: "DamFile",
id: state.damFile.id,
data: {
damFile: state.damFile,
},
});
}

return dependencies;
};
```

`replaceDependenciesInOutput()` replaces the IDs of your dependencies when copying the block to another scope:

```tsx
replaceDependenciesInOutput: (output, replacements) => {
const clonedOutput: PixelImageBlockInput = deepClone(output);
const replacement = replacements.find((replacement) => replacement.type === "DamFile" && replacement.originalId === output.damFileId);

if (replacement) {
clonedOutput.damFileId = replacement.replaceWithId;
}

return clonedOutput;
};
```

### BlockPreview

The `BlockPreview` component was removed. Instead, use `BlockPreviewContent`:

```diff
- const state = linkBlock.input2State(params.value);

- return <BlockPreview title={linkBlock.dynamicDisplayName?.(state) ?? linkBlock.displayName} content={linkBlock.previewContent(state)} />;
+ return <BlockPreviewContent block={linkBlock} input={params.value} />;
```

### @comet/admin

#### Loading

The `Loading` component now uses our `BallTriangle` instead of MUI's `CircularProgress`. If you use the `size` prop, you must now use `sx` instead:

```diff
- <Loading behavior="fillParent" size={20} color="inherit" />
+ <Loading behavior="fillParent" sx={{ fontSize: 20 }} color="inherit" />
```

#### FinalFormSelect

The `getOptionSelected()` prop was removed from `FinalFormSelect` and replaced with `getOptionValue()` in order to support multi-select.

If you had a custom implementation of `getOptionSelected()`, you may need to replace it with a custom `getOptionValue()`. However, for most cases the [default implementation](https://github.com/vivid-planet/comet/commit/fe5e0735#diff-ef93179fe4c6d99e9e776fb1e928ac8b5af12c27fa2d2a6ea124e46028fb8b95R28-R31) will be sufficient.

#### FilterBarMoreFilters

The `textWrapper` class of `FilterBarMoreFilters` was removed. Use the new `button` class instead.

## ESLint

### no-private-sibling-import

The new rule `no-private-sibling-import` bans imports of private sibling files.
Meaning, a file called `Foo.gql.ts` next to a `Foo.ts` can only be imported by `Foo.ts` and no other file.

0 comments on commit 02ac607

Please sign in to comment.