Zum Inhalt springen

Entity-Aktionen

Entity-Aktionen sind benutzerdefinierte Schaltflächen, die bei einzelnen Entitäten angezeigt werden. Verwenden Sie sie für Vorgänge wie das Veröffentlichen, Archivieren, Klonen oder das Auslösen externer Workflows.

import { defineCollection } from "@rebasepro/cms-types";
import { resolveSelection } from "@rebasepro/cms";
import { iconSize } from "@rebasepro/ui";
import { Copy, Upload } from "lucide-react";
const articlesCollection = defineCollection({
slug: "articles",
name: "Articles",
table: "articles",
properties: {
id: { name: "ID", type: "number", isId: "increment" },
name: { name: "Name", type: "string" },
status: { name: "Status", type: "string" },
publishedAt: { name: "Published At", type: "date" }
},
admin: {
entityActions: [
{
name: "Publish",
icon: <Upload size={iconSize.small}/>,
onClick: async ({ entity, context }) => {
if (!entity || !context) return;
await context.data.collection<Record<string, unknown>>(entity.path)
.update(entity.id, { status: "published", publishedAt: new Date() });
context.snackbarController?.open({
type: "success",
message: "Article published!"
});
}
},
{
name: "Clone",
icon: <Copy size={iconSize.small}/>,
onClick: async ({ entity, context }) => {
if (!entity || !context) return;
const { id, ...values } = entity.values;
await context.data.collection<Record<string, unknown>>(entity.path)
.create({ ...values, name: values.name + " (Copy)" });
}
}
]
}
});

Eine Aktion erscheint am Datensatz, sowohl im Bearbeitungsformular als auch in der schreibgeschützten Ansicht, und in den Tabellenzeilen der Collection. Standardmäßig wartet sie an beiden Stellen im Überlaufmenü (⋮).

Setzen Sie collapsed: false für die Aktion, wegen der man den Datensatz öffnet, und sie erhält eine eigene Schaltfläche:

  • Am Datensatz wird sie zu einer beschrifteten Schaltfläche in der Leiste, vor „Speichern“ (bzw. „Bearbeiten“ in der schreibgeschützten Ansicht). Wird der Platz in der Leiste knapp, etwa in einem Seitenpanel, einem Dialog oder einem schmalen Fenster, verlieren die Schaltflächen zuerst ihre Beschriftung und behalten das Symbol, mit dem Namen als Tooltip. Reicht das immer noch nicht, wandern die zuletzt deklarierten zurück ins Menü. Deklarieren Sie die wichtigste daher zuerst.
  • In einer Tabellenzeile wird sie zu einem Symbol neben „Bearbeiten“, solange der Mauszeiger über der Zeile liegt.
{
name: "Publish",
icon: "Upload",
collapsed: false, // eine Schaltfläche am Datensatz, ein Symbol in der Zeile
onClick: async ({ entity, context }) => { /* … */ }
}

Reservieren Sie das für die ein oder zwei Aktionen, wegen derer der Datensatz geöffnet wird. Alle anderen sind im Menü besser aufgehoben, das sie in drei Gruppen auflistet: zuerst die eigenen Aktionen der Collection in der deklarierten Reihenfolge, dann Kopieren, Verlauf und Untersuchen, dann Löschen, zuletzt und abgesetzt.

Eigenschaft Standard Wirkung
collapsed true false macht die Aktion zu einer Schaltfläche am Datensatz und zu einem Symbol in der Tabellenzeile
includeInForm true false hält die Aktion vom Datensatz fern und lässt sie in den Zeilen der Collection
showActionsInListView false true zeigt die Aktion als Symbol in jeder Zeile der Listenansicht
isEnabled — Geben Sie false zurück, um die Aktion deaktiviert anzuzeigen, als Schaltfläche oder als Menüeintrag
disabledReason — Sagt, warum eine deaktivierte Aktion nicht verfügbar ist: unter ihrem Namen im Menü und als Tooltip einer deaktivierten Schaltfläche oder eines Symbols
nameKey — Ein Übersetzungsschlüssel für den Namen. Der Admin zeigt dessen Übersetzung in der aktuellen Sprache und name, wo der Schlüssel keine hat. Die eingebauten Aktionen setzen ihn, sodass Edit, Copy und Delete der Admin-Sprache folgen

Eine deaktivierte Aktion, die nicht sagt warum, wirkt defekt. disabledReason erhält dieselben Props wie isEnabled und kann daher benennen, was fehlt:

{
name: "Resend to Shopify",
isEnabled: ({ entity }) => Boolean(entity?.values.shopify_id),
disabledReason: () => "Dieser Kunde hat kein Shopify-Konto",
onClick: async ({ entity, context }) => { /* … */ }
}

Am Datensatz zeigt eine Schaltfläche, deren onClick ein noch offenes Promise zurückgibt, einen Ladeindikator und lässt sich erst wieder drücken, wenn das Promise abgeschlossen ist. Wirft die Aktion einen Fehler oder wird ihr Promise abgelehnt, sieht der Benutzer den Fehler in einer Benachrichtigung. Die schreibgeschützte Ansicht hat kein Formular, daher ist formContext dort undefined.

Für Aktionen auf Symbolleistenebene, die sich auf die Collection oder ausgewählte Entitäten beziehen:

import { defineCollection } from "@rebasepro/cms-types";
import { useData } from "@rebasepro/app";
import { resolveSelection } from "@rebasepro/cms";
function PublishSelectedAction({ selectionController, path }: CollectionActionsProps) {
const data = useData();
const handlePublish = async () => {
// `selection` is either the rows that were ticked or a query standing
// for every row that matches — `resolveSelection` reads them, one page
// at a time, and refuses rather than returning a prefix.
const selected = await resolveSelection({
selection: selectionController.selection,
accessor: data.collection(path)
});
for (const entity of selected) {
await data.collection(entity.path).update(entity.id, { status: "published" });
}
};
return (
<button onClick={handlePublish}>
Publish {selectionController.selectedCount ?? "all"} selected
</button>
);
}
// Register — `Actions` is an array, so several can be composed.
const collection = defineCollection({
slug: "products",
name: "Products",
table: "products",
properties: { /* … */ },
admin: {
Actions: [PublishSelectedAction]
}
});

Collection-Aktionen