Saltearse al contenido

Vistas de nivel superior

Si necesitas desarrollar una vista personalizada que no se asigne directamente a una colección de fuente de datos (datasource), puedes implementarla como un componente de React. Esto es útil para implementar paneles de control personalizados (dashboards), visualizaciones de datos, o cualquier otra funcionalidad personalizada que necesites.

Las vistas de nivel superior se pueden personalizar en función del usuario que ha iniciado sesión, para que puedas implementar vistas personalizadas para diferentes roles de usuario, o incluso ocultarlas completamente para usuarios no autenticados.

Puedes usar todos los componentes y hooks proporcionados por FireCMS. Consulta la galería de componentes para obtener más información.

También puedes usar todos los ganchos (hooks), incluidos la autenticación, la navegación, la fuente de datos (Firestore), el almacenamiento (storage), etc.

También puedes incluir vistas de colección dentro de tus vistas personalizadas, o usar el panel lateral para ver los detalles de la entidad, o usarlas con componentes completamente personalizados.

Necesitas definir el nombre, la ruta (route) y el componente, y añadirlo a la navegación principal, como en el ejemplo a continuación.

Por defecto, se mostrará en la vista de navegación principal.

Para las vistas personalizadas, puedes definir las siguientes propiedades (props):

  • path: string

Ruta del CMS desde la que puedes acceder a esta vista. Si incluyes múltiples rutas, solo la primera se incluirá en el menú principal.

  • name: string

Nombre de esta vista.

  • description?: string

Descripción opcional de esta vista. Puedes usar Markdown.

  • hideFromNavigation?: boolean

¿Debería ocultarse esta vista del panel de navegación principal? Seguirá siendo accesible si accedes a la ruta especificada.

  • view: React.ReactNode

Componente a renderizar. Puede ser cualquier componente React y puede usar cualquiera de los hooks proporcionados.

  • group?: string

Campo opcional utilizado para agrupar entradas de navegación de nivel superior bajo una vista de navegación.

Ejemplo usando FireCMS autoalojado (self-hosted)

Sección titulada «Ejemplo usando FireCMS autoalojado (self-hosted)»

Para FireCMS autoalojado, puedes definir tus vistas de nivel superior personalizadas añadiéndolas a tu componente useBuildNavigationController. Puedes pasarlas como un array de objetos CMSView o una función callback que devuelva un array de objetos CMSView. En el callback, puedes usar el objeto user para mostrar u ocultar vistas condicionalmente según el rol del usuario, así como acceder a los hooks de autenticación (authentication) y navegación (navigation).

import {CMSView, useBuildNavigationController} from "@firecms/core";
import {useMemo} from "react";
// resto del código de tu aplicación principal
const customViews: CMSView[] = useMemo([{
path: "additional",
name: "Additional view",
description: "This is an example of an additional view that is defined by the user",
// Esto puede ser cualquier componente React
view: <ExampleCMSView/>
}], []);
const navigationController = useBuildNavigationController({
views: ({ user }) =>{
if(!user) {
return [];
}
return customViews;
},
collections,
authController,
dataSourceDelegate: firestoreDelegate
});

En FireCMS Cloud, puedes definir tus vistas de nivel superior personalizadas añadiéndolas a tu FireCMSAppConfig. Puedes usar un callback o añadirlas directamente a la propiedad views. El callback incluye el usuario (user) con sesión iniciada, para que puedas usarlo para mostrar u ocultar vistas condicionalmente basándote en el rol del usuario.

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}
/>;
}

Tu vista personalizada se implementa como cualquier componente React regular. Puedes usar cualquiera de los hooks proporcionados, incluyendo autenticación, navegación, fuente de datos (datasource), almacenamiento (storage), etapa de la aplicación (app stage), 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>
);
}