Skip to content

Dynamic collections

FireCMS offers the possibility to define collections dynamically. This means that collections can be built asynchronously, based on the logged-in user, based on the data of other collections, or based on any other arbitrary condition.

Instead of defining your collections as an array, use a EntityCollectionsBuilder, a function that returns a promise of an object containing the collections.

import { EntityCollectionsBuilder } from "@firecms/core";
// ...
const collectionsBuilder: EntityCollectionsBuilder = async ({
user,
authController,
dataSource
}) =>
({
collections: [
buildCollection({
path: "products",
properties: {}, // ...
name: "Products"
})
]
});

It may be the case that a collection config depends on the data of another one. For example, you may want to fetch the enum values of a property from a different collection.

In this example we will fetch data from a collection called categories and use it to populate the enum values of a property called category, in the products collection.

import { useCallback } from "react";
import { buildCollection, EntityCollectionsBuilder } from "@firecms/core";
const collectionsBuilder: EntityCollectionsBuilder = async ({
user,
authController,
dataSource
}) => {
// let's assume you have a database collection called "categories"
const categoriesData: Entity<any>[] = await dataSource.fetchCollection({
path: "categories"
});
return {
collections: [
buildCollection({
id: "products",
path: "products",
properties: {
// ...
category: {
dataType: "string",
name: "Category",
// we can use the enumValues property to define the enum values
// the stored value will be the id of the category
// and the UI label will be the name of the category
enumValues: categoriesData.map((category: any) => ({
id: category.id,
label: category.values.name
}))
}
// ...
},
name: "Products"
})
]
}
};

The AuthController handles the auth state. It can also be used to store any arbitrary object related to the user.

A typical use case is to store some additional data related to the user, for example, the roles or the permissions.

import { useCallback } from "react";
const myAuthenticator: Authenticator<FirebaseUserWrapper> = useCallback(async ({
user,
authController
}) => {
if (user?.email?.includes("flanders")) {
throw Error("Stupid Flanders!");
}
console.log("Allowing access to", user?.email);
// This is an example of retrieving async data related to the user
// and storing it in the controller's extra field.
const sampleUserRoles = await Promise.resolve(["admin"]);
authController.setExtra(sampleUserRoles);
return true;
}, []);

Then you can access the extra data in the collectionsBuilder callback.

const collectionsBuilder: EntityCollectionsBuilder = useCallback(async ({
user,
authController,
dataSource
}) => {
const userRoles = authController.extra;
if (userRoles?.includes("admin")) {
return {
collections: [
buildCollection({
path: "products",
properties: {}, // ...
name: "Products"
})
]
};
} else {
return {
collections: []
};
}
}, []);

In the Cloud version of FireCMS, simply add the collectionsBuilder to the collections prop of your main app config.

const collectionsBuilder: EntityCollectionsBuilder = async ({
user,
authController,
dataSource
}) => {
return {
collections: [] // your collections here
};
};
export const appConfig: FireCMSAppConfig = {
version: "1",
collections: collectionsBuilder
};

In the PRO version of FireCMS, you can use the collectionsBuilder in the useBuildNavigationController hook.

const navigationController = useBuildNavigationController({
collections: collectionsBuilder
});