Copier une entité d'une collection à une autre

Dans ce tutoriel, nous allons montrer comment vous pouvez ajouter un bouton à votre collection qui vous permettra de copier des entités depuis une autre collection.
Il est très courant dans les bases de données NoSQL, comme Firestore, de conserver des données dénormalisées dans différentes collections. C’est-à-dire conserver la même information à plusieurs endroits, au lieu des bases de données normalisées où l’information devrait idéalement être stockée une seule fois.
Déclarer vos collections
Section intitulée « Déclarer vos collections »À des fins d’illustration, créons deux collections products simples, depuis et vers lesquelles nous copierons :
import { buildCollection, buildProperties } from "@firecms/core";
export type Product = { name: string; price: number;}
// Common properties of our target and source collectionsexport const properties = buildProperties<Product>({ name: { name: "Name", validation: { required: true }, dataType: "string" }, price: { name: "Price", validation: { required: true, min: 0 }, dataType: "number" }});
// Source collectionexport const productsCollection = buildCollection<Product>({ name: "Products", id: "products", path: "products", properties});
// Target collectionexport const productsCollectionCopy = buildCollection<Product>({ name: "Products copy target", id: "products_copied", path: "products_copied", properties});Ajouter une action personnalisée à votre collection
Section intitulée « Ajouter une action personnalisée à votre collection »Pour l’étape suivante, nous allons ajouter un bouton personnalisé à notre collection cible. Ce bouton ouvrira un dialogue de référence et permettra aux utilisateurs de sélectionner une entité dans la source.
Cet exemple utilise quelques hooks fournis par FireCMS pour développer des composants personnalisés.
import { useCallback } from "react";import { Entity, EntityCollection, useDataSource, useReferenceDialog, useSnackbarController } from "@firecms/core";import { Button } from "@firecms/ui";
export type CopyEntityButtonProps = { pathFrom: string; pathTo: string; collectionFrom: EntityCollection; collectionTo: EntityCollection;};
export function CopyEntityButton({ pathFrom, collectionFrom, pathTo, collectionTo }: CopyEntityButtonProps) {
// The datasource allows us to create new documents const dataSource = useDataSource();
// We use a snackbar to indicate success const snackbarController = useSnackbarController();
// We declare a callback function for the reference dialog that will // create the new entity and show a snackbar when completed const copyEntity = useCallback((entity: Entity<any> | null) => { if (entity) { dataSource.saveEntity({ path: pathTo, values: entity.values, entityId: entity.id, collection: collectionTo, status: "new" }).then(() => { snackbarController.open({ type: "success", message: "Copied entity " + entity.id }); }); } }, [collectionTo, dataSource, pathTo, snackbarController]);
// This dialog is used to prompt the selected collection const referenceDialog = useReferenceDialog({ path: pathFrom, collection: collectionFrom, multiselect: false, onSingleEntitySelected: copyEntity });
return ( <Button onClick={referenceDialog.open}> Copy from {pathFrom} </Button> );}Ajouter l’action de copie personnalisée
Section intitulée « Ajouter l’action de copie personnalisée »Une fois votre composant prêt, vous pouvez le brancher dans les Actions de vos collections :
import { buildCollection, CollectionActionsProps } from "@firecms/core";import { CopyEntityButton } from "./copy_button";import { Product, productsCollection, properties } from "./simple_product_collection";
export const productsCollectionCopy = buildCollection<Product>({ id: "products_copied", name: "Products copy target", path: "products_copied", properties, Actions: ({ path, collection }: CollectionActionsProps<Product>) => <CopyEntityButton pathFrom={"products"} collectionFrom={productsCollection} pathTo={path} collectionTo={collection} />});Code complet
Section intitulée « Code complet »import { useCallback } from "react";import { buildCollection, buildProperties, CollectionActionsProps, Entity, EntityCollection, useDataSource, useReferenceDialog, useSnackbarController} from "@firecms/core";import { Button } from "@firecms/ui";
type Product = { name: string; price: number;}
type CopyEntityButtonProps = { pathFrom: string; pathTo: string; collectionFrom: EntityCollection<any>; collectionTo: EntityCollection<any>;};
function CopyEntityButton({ pathFrom, collectionFrom, pathTo, collectionTo }: CopyEntityButtonProps) {
// The datasource allows us to create new documents const dataSource = useDataSource();
// We use a snackbar to indicate success const snackbarController = useSnackbarController();
// We declare a callback function for the reference dialog that will // create the new entity and show a snackbar when completed const copyEntity = useCallback((entity: Entity<any> | null) => { if (entity) { dataSource.saveEntity({ path: pathTo, values: entity.values, entityId: entity.id, collection: collectionTo, status: "new" }).then(() => { snackbarController.open({ type: "success", message: "Copied entity " + entity.id }); }); } }, [collectionTo, dataSource, pathTo, snackbarController]);
// This dialog is used to prompt the selected collection const referenceDialog = useReferenceDialog({ path: pathFrom, collection: collectionFrom, multiselect: false, onSingleEntitySelected: copyEntity });
return ( <Button onClick={referenceDialog.open}> Copy from {pathFrom} </Button> );}
// Common properties of our target and source collectionsconst properties = buildProperties<Product>({ name: { name: "Name", validation: { required: true }, dataType: "string" }, price: { name: "Price", validation: { required: true, min: 0 }, dataType: "number" }});
// Source collectionexport const productsCollection = buildCollection<Product>({ name: "Products", id: "products", path: "products", properties});
// Target collectionexport const productsCollectionCopy = buildCollection<Product>({ name: "Products copy target", id: "products_copied", path: "products_copied", properties, Actions: ({ path, collection }: CollectionActionsProps<Product>) => <CopyEntityButton pathFrom={"products"} collectionFrom={productsCollection} pathTo={path} collectionTo={collection} />});