Aller au contenu

Copier une entité d'une collection à une autre

Sélection de produit

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.

À 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 collections
export const properties = buildProperties<Product>({
name: {
name: "Name",
validation: { required: true },
dataType: "string"
},
price: {
name: "Price",
validation: {
required: true,
min: 0
},
dataType: "number"
}
});
// Source collection
export const productsCollection = buildCollection<Product>({
name: "Products",
id: "products",
path: "products",
properties
});
// Target collection
export 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>
);
}

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}
/>
});
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 collections
const properties = buildProperties<Product>({
name: {
name: "Name",
validation: { required: true },
dataType: "string"
},
price: {
name: "Price",
validation: {
required: true,
min: 0
},
dataType: "number"
}
});
// Source collection
export const productsCollection = buildCollection<Product>({
name: "Products",
id: "products",
path: "products",
properties
});
// Target collection
export 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}
/>
});