Skip to main content

Dependencies

Register fields to be added to the block index

Add @RootBlockEntity() and @RootBlock() decorators to entity

The entity needs to be annotated with @RootBlockEntity().

All fields containing block data need to be annotated with @RootBlock(). The Block used by this field must be passed as an argument.

//...
@RootBlockEntity()
export class News extends BaseEntity<News, "id"> {
// ...

@RootBlock(DamImageBlock)
@Property({ customType: new RootBlockType(DamImageBlock) })
@Field(() => RootBlockDataScalar(DamImageBlock))
image: BlockDataInterface;

@RootBlock(NewsContentBlock)
@Property({ customType: new RootBlockType(NewsContentBlock) })
@Field(() => RootBlockDataScalar(NewsContentBlock))
content: BlockDataInterface;

// ...
}

Correctly display a dependency target

1. Add @EntityInfo() to entity (API)

You can provide the entity info in two ways:

GetEntityInfo Method

The simple way is to provide a function returning a name and (optional) secondaryInformation based on the entity instance.

// news.entity.ts
@EntityInfo<News>((news) => ({ name: news.title, secondaryInformation: news.slug }))

EntityInfoService

If you need to load additional information from a service or repository to provide the entity info, you can implement an EntityInfoService. In this service, you can use Nest's dependency injection.

The service must offer a getEntityInfo() method returning a name and (optional) secondaryInformation.

// file.entity.ts
@EntityInfo<DamFile>(FilesEntityInfoService)
// files-entity-info.service.ts
@Injectable()
export class FilesEntityInfoService implements EntityInfoServiceInterface<FileInterface> {
constructor(
@Inject(forwardRef(() => FilesService))
private readonly filesService: FilesService,
) {}

async getEntityInfo(file: FileInterface) {
return { name: file.name, secondaryInformation: await this.filesService.getDamPath(file) };
}
}

2. Implement the DependencyInterface (Admin)

The DependencyInterface requires a translatable displayName and a resolvePath() method providing a path to edit an entity or its blocks.

// NewsDependency.tsx
export const NewsDependency: DependencyInterface = {
displayName: <FormattedMessage id="news.displayName" defaultMessage="News" />,
resolvePath: async ({ apolloClient, id, rootColumnName, jsonPath }) => {
const { data, error } = await apolloClient.query<
GQLNewsDependencyQuery,
GQLNewsDependencyQueryVariables
>({
query: gql`
query NewsDependency($id: ID!) {
news(id: $id) {
id
content
}
}
`,
variables: {
id,
},
});

if (error) {
throw new Error(`News.getUrl: Could not find a News with id ${id}`);
}

let dependencyPath = "";
if (rootColumnName === "content") {
dependencyPath = `form/${NewsContentBlock.resolveDependencyPath(
NewsContentBlock.input2State(data.news.content),
jsonPath.substring("root.".length),
)}`;
}

return `/structured-content/news/${data.news.id}/edit/${dependencyPath}`;
},
};

You may also use the createDependencyMethods helper to simplify resolving the path to the entity/block. Use the basePath option to specify where the entity is located in the Admin.

// NewsDependency.tsx
import { createDependencyMethods } from "@comet/cms-admin";

// ...

export const NewsDependency: DependencyInterface = {
displayName: <FormattedMessage id="news.displayName" defaultMessage="News" />,
...createDependencyMethods({
rootQueryName: "news",
rootBlocks: { content: { block: NewsContentBlock, path: "/form" }, image: DamImageBlock },
basePath: ({ id }) => `/structured-content/news/${id}/edit`,
}),
};

For document types you may use the createDocumentDependencyMethods helper that also loads the page tree node the document is attached to:

// Page.tsx
import { createDocumentDependencyMethods } from "@comet/cms-admin";

// ...

export const Page: DocumentInterface<Pick<GQLPage, "content" | "seo">, GQLPageInput> &
DependencyInterface = {
// ...
...createDocumentDependencyMethods({
rootQueryName: "page",
rootBlocks: {
content: PageContentBlock,
seo: { block: SeoBlock, path: "/config" },
},
basePath: ({ pageTreeNode }) =>
`/pages/pagetree/${categoryToUrlParam(pageTreeNode.category)}/${pageTreeNode.id}/edit`,
}),
};

3. Register the DependencyInterface at the DependenciesConfigProvider

The key must be the name of the GraphQL object type associated with the entity.

// App.tsx
// ...
<DependenciesConfigProvider
entityDependencyMap={{
// ...
News: NewsDependency,
}}
>
// ...
</DependenciesConfigProvider>
// ...