Personalizando o Admin
O admin é construído a partir de partes que você mesmo pode usar. Para personalizá-lo, você escreve um componente React comum e o coloca em um local. Esse é o modelo completo:
- Blocos de construção que você renderiza — a tabela de uma coleção, o formulário de um registro, o kit de UI.
- Hooks para dados, o usuário autenticado, toasts e navegação.
- Locais para colocar um componente — uma página, um modo de visualização de coleção, um botão de barra de ferramentas, uma aba de registro, um campo, um slot ao lado de uma parte nativa, ou um override que substitui uma.
Se um bloco de construção não fizer o que você precisa, copie seu código-fonte para o seu projeto e altere-o. Nada aqui precisa que uma opção de configuração exista previamente. Veja Copiar uma parte nativa.
Receitas
Seção intitulada “Receitas”Exemplos funcionais e testados acompanham o @rebasepro/cms, portanto, os exemplos em
node_modules/@rebasepro/cms/recipes sempre correspondem à sua versão instalada. Eles
importam apenas pacotes públicos: copie um para o seu projeto como está.
| Receita | O que demonstra |
|---|---|
site-settings.tsx |
Um singleton: um único registro de configurações em sua própria página, criado no primeiro salvamento. |
my-preferences.tsx |
Configurações por usuário: cada usuário edita o registro indexado pelo seu uid. |
bulk-set-status.tsx |
Um botão de barra de ferramentas que atualiza todas as linhas selecionadas. |
calendar-view.tsx |
Um novo modo de visualização: as linhas de uma coleção em uma grade mensal. |
orders-dashboard.tsx |
Uma página que lê dados, desenha um gráfico e vincula ao admin. |
custom-login.tsx |
Substituição da tela de login. |
O README.md ao lado deles é a referência completa de blocos de construção, hooks e locais.
Exemplo: um singleton
Seção intitulada “Exemplo: um singleton”Um singleton não é um tipo especial de coleção. É uma tabela comum cuja página
sempre abre a mesma linha. Ao receber um id, o EntityFormPanel edita esse registro
e o cria sob esse id na primeira vez, de modo que nenhum seeding é necessário.
import React from "react";import { defineCollection } from "@rebasepro/cms-types";import type { AppView } from "@rebasepro/cms-types";import { EntityFormPanel } from "@rebasepro/cms";import { Container, Typography } from "@rebasepro/ui";
// config/collections/site_settings.ts — `rebase db push` creates the table.export const siteSettingsCollection = defineCollection({ name: "Site settings", slug: "site_settings", table: "site_settings", properties: { id: { name: "ID", type: "string", isId: true }, siteName: { name: "Site name", type: "string", validation: { required: true } }, maintenanceMode: { name: "Maintenance mode", type: "boolean" } }, admin: { hideFromNavigation: true, hideIdFromForm: true }});
// Add to <RebaseCMS views={[siteSettingsView]}>.export const siteSettingsView: AppView = { slug: "settings/site", name: "Site settings", icon: "Settings", view: ( <Container maxWidth={"3xl"} className={"py-8"}> <Typography variant={"h4"} gutterBottom>Site settings</Typography> <EntityFormPanel collection={siteSettingsCollection} entityId={"site"}/> </Container> )};A mesma estrutura com entityId={user.uid} (vindo de useAuthController()) é uma
página de configurações por usuário.
| Para adicionar… | Coloque um componente em |
|---|---|
| Uma página | <RebaseCMS views={[{ slug, name, icon, view }]}> |
| Um modo de visualização para uma coleção | collectionViews={[{ key, name, Builder }]} e admin.customViews: ["key"] — consulte Modos de Visualização |
| Um botão na barra de ferramentas de uma coleção | admin.Actions: [Component] |
| Um botão em um registro | admin.entityActions — consulte Ações de Entidade |
| Uma aba em um registro | admin.entityViews — consulte Visualizações de Entidade |
| Como um campo é editado ou exibido | admin.Field / admin.Preview — consulte Campos Personalizados |
| Algo ao lado de uma parte nativa | <Rebase slots> — consulte Slots |
| Uma substituição para uma parte nativa | <Rebase components> — consulte Substituições de Componentes |
O que cada local entrega ao seu componente
Seção intitulada “O que cada local entrega ao seu componente”| Local | Seu componente recebe |
|---|---|
Uma página (views) |
Nada: leia o que precisar com os hooks. Ela é renderizada dentro do router do admin, então useUrlController().navigate(…) (ou react-router) funciona. |
Um Builder de modo de visualização |
CollectionCustomViewParams: collection, path, tableController (seu data são as linhas que a busca e os filtros da barra de ferramentas selecionam, dataLoading, …), onEntityClick(entity) para abrir uma linha do jeito que a coleção abre linhas, selectionController, emptyComponent. |
admin.Actions |
CollectionActionsProps: path, collection, selectionController (hasSelection, selection, clearSelection()), tableController, openNewDocument(defaults?). Transforme selection em linhas com resolveSelection({ selection, accessor: useData().collection(path) }) — ela pode representar “todas as linhas que correspondem ao filtro”, não só as marcadas. |
Builder de admin.entityViews |
EntityCustomViewParams: collection, o registro (entity, ausente enquanto está sendo criado), seus valores não salvos (modifiedValues) e o formulário (formContext). |
"Auth.LoginView" |
{ authController }. Entre com authController.emailPasswordLogin?.(email, password) (opcional: presente quando o login por e-mail está ativado); uma falha lança um erro e também fica em authController.authProviderError. Assim que authController.user é definido, o admin substitui sua tela sozinho. |
| Qualquer outro override | As props da parte que ele substitui; com wrap: true, essas mais OriginalComponent. |
| Hook | Pacote | Fornece |
|---|---|---|
useData |
@rebasepro/app |
useData().collection("orders").find / findById / create / update / delete, por meio do servidor, para que callbacks e regras de segurança se apliquem. |
useCollection / useFetch |
@rebasepro/app |
Uma lista de linhas em tempo real / um registro em tempo real. |
useAuthController |
@rebasepro/app |
O user autenticado (uid, roles), login e logout. |
useSnackbarController |
@rebasepro/app |
open({ type, message }) para um toast. |
useSidePanel |
@rebasepro/cms |
Abre qualquer registro no painel lateral. |
useUrlController |
@rebasepro/cms |
URLs e navegação do admin. |
resolveSelection |
@rebasepro/cms |
Uma seleção da tabela — linhas marcadas ou “todas correspondentes” — como linhas. |
Copiar uma parte nativa
Seção intitulada “Copiar uma parte nativa”Quando uma parte nativa está perto do que você quer, copie seu código-fonte do repositório de @rebasepro/cms (ou @rebasepro/app) para o seu projeto, aponte seus imports relativos para os pacotes, altere-a e registre-a com o seu nome em <Rebase components>. Tudo o que uma parte importa é uma exportação pública, então a cópia compila — em todas as partes menos três, e essas três são deliberadas:
Collection.Viewé a composição de todos os modos de visualização — lista, tabela, cards, quadro, dividida — com edição inline, o editor de campo em popup, o diálogo de exclusão e o estado do modo de visualização na URL. O que ela importa são os detalhes internos desses modos. Substitua em vez disso uma de suas partes (Collection.Table,Collection.Card,Collection.Actions,Collection.EmptyState, que podem ser copiadas), adicione um modo de visualização próprio ou envolva-a comwrap: true.DetailViewé a composição da visualização de um registro: barra de identidade, abas, inspetor e os botões da lista dividida, em torno de ids de aba que são valores da URL. Personalize um registro com entity views, entity actions, os slotsform.*ou os overridesEntity.FormeEditView.FormActions, que podem ser copiados.HomePagepode ser copiada, exceto pela reordenação de cards e grupos por arrastar e soltar, que não tem uma API própria para exportar. Uma página inicial sua compõeNavigationGroup,NavigationCardBindingeFavouritesViewsobreuseNavigationStateController().topLevelNavigation; para acrescentar algo à página padrão, use o slothome.cards.