Aller au contenu

Vues de niveau supérieur

Si vous avez besoin de développer une vue personnalisée qui ne correspond pas directement à une collection de source de données, vous pouvez l’implémenter en tant que composant React. C’est utile pour implémenter des tableaux de bord personnalisés, des visualisations de données, ou toute autre fonctionnalité personnalisée dont vous avez besoin.

Les vues de niveau supérieur peuvent être personnalisées en fonction de l’utilisateur connecté, vous pouvez donc implémenter des vues personnalisées pour différents rôles d’utilisateurs, ou même les masquer complètement pour les utilisateurs non authentifiés.

Vous pouvez utiliser tous les composants et hooks fournis par FireCMS. Consultez la galerie de composants pour plus d’informations.

Vous pouvez également utiliser tous les hooks, y compris l’authentification, la navigation, la source de données (Firestore), le stockage, etc.

Vous pouvez également inclure des vues de collection dans vos vues personnalisées, ou utiliser le panneau latéral pour voir les détails d’entités, ou utiliser des composants entièrement personnalisés.

Vous devez définir le nom, la route et le composant, et l’ajouter à la navigation principale, comme dans l’exemple ci-dessous.

Par défaut, il s’affichera dans la vue de navigation principale.

Pour les vues personnalisées, vous pouvez définir les props suivantes :

  • path : string

Chemin CMS à partir duquel vous pouvez atteindre cette vue. Si vous incluez plusieurs chemins, seul le premier sera inclus dans le menu principal.

  • name : string

Nom de cette vue.

  • description ? : string

Description optionnelle de cette vue. Vous pouvez utiliser le Markdown.

  • hideFromNavigation ? : boolean

Cette vue doit-elle être masquée du panneau de navigation principal. Elle sera toujours accessible si vous atteignez le chemin spécifié.

  • view : React.ReactNode

Composant à rendre. Il peut s’agir de n’importe quel composant React, et peut utiliser n’importe lequel des hooks fournis.

  • group ? : string

Champ optionnel utilisé pour regrouper les entrées de navigation de niveau supérieur sous une vue de navigation.

Pour FireCMS auto-hébergé, vous pouvez définir vos vues de niveau supérieur personnalisées en les ajoutant dans votre composant useBuildNavigationController. Vous pouvez les passer comme un tableau d’objets CMSView ou une fonction de callback qui retourne un tableau d’objets CMSView.

import {CMSView, useBuildNavigationController} from "@firecms/core";
import {useMemo} from "react";
// reste de votre code d'application principale
const customViews: CMSView[] = useMemo([{
path: "additional",
name: "Additional view",
description: "This is an example of an additional view that is defined by the user",
// Il peut s'agir de n'importe quel composant React
view: <ExampleCMSView/>
}], []);
const navigationController = useBuildNavigationController({
views: ({ user }) =>{
if(!user) {
return [];
}
return customViews;
},
collections,
authController,
dataSourceDelegate: firestoreDelegate
});

Dans FireCMS Cloud, vous pouvez définir vos vues de niveau supérieur personnalisées en les ajoutant à votre FireCMSAppConfig. Vous pouvez utiliser un callback ou les ajouter directement à la propriété views. Le callback inclut l’user connecté, vous pouvez donc l’utiliser pour afficher ou masquer conditionnellement des vues en fonction du rôle de l’utilisateur.

import { buildCollection, CMSView } from "@firecms/core";
import { ExampleCMSView } from "./ExampleCMSView";
import { FireCMSAppConfig, FireCMSCloudApp } from "@firecms/cloud";
const projectId = "YOUR_PROJECT_ID";
const customViews: CMSView[] = [{
path: "additional",
name: "Additional view",
description: "This is an example of an additional view that is defined by the user",
// This can be any React component
view: <ExampleCMSView/>
}];
const productCollection = buildCollection<any>({
name: "Product",
id: "products",
path: "products",
properties: {
name: {
name: "Name",
validation: { required: true },
dataType: "string"
}
}
});
const appConfig: FireCMSAppConfig = {
version: "1",
collections: ({ user }) => [
productCollection
],
views: ({ user }) => customViews
};
export default function App() {
return <FireCMSCloudApp
projectId={projectId}
appConfig={appConfig}
/>;
}

Votre vue personnalisée est implémentée comme n’importe quel composant React ordinaire. Vous pouvez utiliser n’importe lequel des hooks fournis, y compris l’authentification, la navigation, la source de données, le stockage, l’état de l’application, etc.

import React from "react";
import {
buildCollection,
Entity,
EntityCollectionView,
useAuthController,
useReferenceDialog,
useSelectionController,
useSideEntityController,
useSnackbarController
} from "@firecms/core";
import { Button, GitHubIcon, IconButton, Paper, Tooltip, Typography, } from "@firecms/ui";
const usersCollection = buildCollection({
path: "users",
id: "users",
name: "Users",
singularName: "User",
group: "Main",
description: "Registered users",
textSearchEnabled: true,
icon: "Person",
properties: {
first_name: {
name: "First name",
dataType: "string"
},
last_name: {
name: "Last name",
dataType: "string"
},
email: {
name: "Email",
dataType: "string",
email: true
},
phone: {
name: "Phone",
dataType: "string"
},
liked_products: {
dataType: "array",
name: "Liked products",
description: "Products this user has liked",
of: {
dataType: "reference",
path: "products"
}
},
picture: {
name: "Picture",
dataType: "map",
properties: {
large: {
name: "Large",
dataType: "string",
url: "image"
},
thumbnail: {
name: "Thumbnail",
dataType: "string",
url: "image"
}
},
previewProperties: ["large"]
}
},
additionalFields: [
{
key: "sample_additional",
name: "Sample additional",
Builder: ({ entity }) => <>{`Generated column: ${entity.values.first_name}`}</>,
dependencies: ["first_name"]
}
]
});
/**
* Sample CMS view not bound to a collection, customizable by the developer
*/
export function ExampleCMSView() {
// hook to display custom snackbars
const snackbarController = useSnackbarController();
const selectionController = useSelectionController();
console.log("Selection from ExampleCMSView", selectionController.selectedEntities);
// hook to open the side dialog that shows the entity forms
const sideEntityController = useSideEntityController();
// hook to do operations related to authentication
const authController = useAuthController();
// hook to open a reference dialog
const referenceDialog = useReferenceDialog({
path: "products",
onSingleEntitySelected(entity: Entity<any> | null) {
snackbarController.open({
type: "success",
message: "Selected " + entity?.values.name
})
}
});
const customProductCollection = buildCollection({
id: "custom_product",
path: "custom_product",
name: "Custom products",
properties: {
name: {
name: "Name",
validation: { required: true },
dataType: "string"
},
very_custom_field: {
name: "Very custom field",
dataType: "string"
}
}
});
const githubLink = (
<Tooltip
asChild={true}
title="Get the source code of this example view">
<IconButton
href={"https://github.com/firecmsco/firecms/blob/main/examples/example_cloud/src/views/ExampleCMSView.tsx"}
rel="noopener noreferrer"
target="_blank"
component={"a"}
size="large">
<GitHubIcon/>
</IconButton>
</Tooltip>
);
return (
<div className="flex h-full">
<div className="m-auto flex flex-col items-center max-w-4xl">
<div className="flex flex-col gap-12 items-start">
<div className="mt-24">
<Typography variant="h4">
This is an example of an additional view
</Typography>
<p>
{authController.user
? <>Logged in as {authController.user.displayName}</>
: <>You are not logged in</>}
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-2">
<Paper className={"w-full flex flex-col p-4 items-start"}>
<p className="mb-4 flex-grow">
Use this button to select an entity under the path `products` programmatically
</p>
<Button
variant={"outlined"}
size={"small"}
onClick={referenceDialog.open}>
Test reference dialog
</Button>
</Paper>
<Paper className="w-full flex flex-col p-4 items-start">
<p className="mb-4 flex-grow">
Use this button to open a snackbar
</p>
<Button
variant={"outlined"}
size={"small"}
onClick={() => snackbarController.open({
type: "success",
message: "This is pretty cool"
})}>
Test snackbar
</Button>
</Paper>
<Paper className="w-full flex flex-col p-4 items-start">
<p className="mb-4 flex-grow">
Use this button to open an entity in a custom path with a custom schema
</p>
<Button
size={"small"}
variant={"outlined"}
onClick={() => sideEntityController.open({
entityId: "B003WT1622",
path: "/products-test",
collection: customProductCollection,
width: 1000
})}>
Open custom entity
</Button>
</Paper>
</div>
<div className="w-full">
<p className="mb-4">
You can include full entity collections in your views:
</p>
<Paper
className={"h-[400px]"}>
<EntityCollectionView {...usersCollection}
fullPath={"users"}
selectionController={selectionController}/>
</Paper>
</div>
<div className="mt-auto">
{githubLink}
</div>
</div>
</div>
</div>
);
}