feat(ui): automation settings start with everyday tabs and confirm risky actions

- Tabs ordered from everyday (suggestions, recurring tasks, labels) to
  technical (calendar sync, API keys, webhooks); the page opens on
  "Vorschläge" instead of Webhooks, and says in one sentence what it is.
- Resetting a number counter, deactivating a label template and ending a
  recurring task now ask first and say plainly what happens.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-01 07:36:28 +02:00
1 parent 78325af1fe
commit dff6c364c8
4 files changed
+38 -32

No files matched your search

@@ -12,6 +12,7 @@ import { AutomationRule, AutomationTriggerType } from "@/lib/automation/types";
import { formatGeneratedNumber } from "@/lib/automation/number-format"; import { formatGeneratedNumber } from "@/lib/automation/number-format";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { ConfirmDialog } from "@/components/confirm-dialog";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -207,15 +208,16 @@ function RuleCard({ rule }: { rule: AutomationRule }) {
</Button> </Button>
</div> </div>
{numberFormatRule ? ( {numberFormatRule ? (
<Button <ConfirmDialog
type="button" triggerLabel="Zähler zurücksetzen"
variant="ghost" triggerVariant="ghost"
size="sm" triggerDisabled={resetMutation.isPending}
disabled={resetMutation.isPending} title="Zähler zurücksetzen?"
onClick={() => resetMutation.mutate()} description="Die nächste Nummer beginnt wieder bei 1. Gibt es im selben Zeitraum schon Nummern, können doppelte Los-/Chargennummern entstehen. Nur zurücksetzen, wenn ein neuer Zeitraum beginnt."
> confirmLabel="Zurücksetzen"
{resetMutation.isPending ? "Wird zurückgesetzt…" : "Zähler zurücksetzen"} isPending={resetMutation.isPending}
</Button> onConfirm={() => resetMutation.mutate()}
/>
) : null} ) : null}
</CardContent> </CardContent>
</Card> </Card>
@@ -7,6 +7,7 @@ import { toast } from "sonner";
import { deactivateLabelTemplate, fetchLabelTemplates } from "@/lib/label-templates/api"; import { deactivateLabelTemplate, fetchLabelTemplates } from "@/lib/label-templates/api";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { ConfirmDialog } from "@/components/confirm-dialog";
import { EmptyState } from "@/components/empty-state"; import { EmptyState } from "@/components/empty-state";
import { EntityCard } from "@/components/entity-card"; import { EntityCard } from "@/components/entity-card";
@@ -74,15 +75,16 @@ export function LabelTemplatesTab() {
<Pencil className="size-3.5" /> <Pencil className="size-3.5" />
Bearbeiten Bearbeiten
</Button> </Button>
<Button <ConfirmDialog
type="button" triggerLabel="Deaktivieren"
variant="ghost" triggerVariant="ghost"
size="sm" triggerDisabled={deactivateMutation.isPending}
disabled={deactivateMutation.isPending} title="Vorlage deaktivieren?"
onClick={() => deactivateMutation.mutate(template.id)} description={`„${template.name}“ steht danach beim Etikettendruck nicht mehr zur Auswahl. Bereits gedruckte Etiketten bleiben unverändert.`}
> confirmLabel="Deaktivieren"
Deaktivieren isPending={deactivateMutation.isPending}
</Button> onConfirm={() => deactivateMutation.mutate(template.id)}
/>
</> </>
} }
/> />
@@ -22,14 +22,15 @@ type Tab =
| "calendar-sync" | "calendar-sync"
| "api-keys"; | "api-keys";
// Everyday settings first, connections to other systems last.
const TABS: { value: Tab; label: string }[] = [ const TABS: { value: Tab; label: string }[] = [
{ value: "webhooks", label: "Webhooks" }, { value: "rules", label: "Vorschläge" },
{ value: "task-templates", label: "Wiederkehrende Aufgaben" }, { value: "task-templates", label: "Wiederkehrende Aufgaben" },
{ value: "label-templates", label: "Etikettenvorlagen" }, { value: "label-templates", label: "Etikettenvorlagen" },
{ value: "social-media", label: "Stammdaten & Web" }, { value: "social-media", label: "Stammdaten & Web" },
{ value: "rules", label: "Regeln" },
{ value: "calendar-sync", label: "Kalender-Sync" }, { value: "calendar-sync", label: "Kalender-Sync" },
{ value: "api-keys", label: "API-Schlüssel" }, { value: "api-keys", label: "API-Schlüssel" },
{ value: "webhooks", label: "Webhooks" },
]; ];
function isTab(value: string | null): value is Tab { function isTab(value: string | null): value is Tab {
@@ -39,7 +40,7 @@ function isTab(value: string | null): value is Tab {
function AutomationPageContent() { function AutomationPageContent() {
const router = useRouter(); const router = useRouter();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const tab: Tab = isTab(searchParams.get("tab")) ? (searchParams.get("tab") as Tab) : "webhooks"; const tab: Tab = isTab(searchParams.get("tab")) ? (searchParams.get("tab") as Tab) : "rules";
function setTab(next: Tab) { function setTab(next: Tab) {
router.replace(`/settings/automation?tab=${next}`); router.replace(`/settings/automation?tab=${next}`);
@@ -50,7 +51,7 @@ function AutomationPageContent() {
<PageHeader <PageHeader
icon={Zap} icon={Zap}
title="Automatisierung" title="Automatisierung"
description="Webhooks, wiederkehrende Aufgaben, Etikettenvorlagen, Social Media, Regeln, Kalender-Sync und API-Schlüssel" description="Was ApiCore dir abnimmt – und wie es mit anderen Systemen verbunden ist."
gradient="var(--gradient-sky)" gradient="var(--gradient-sky)"
/> />
@@ -7,7 +7,7 @@ import { toast } from "sonner";
import { deactivateTaskTemplate, fetchTaskTemplates } from "@/lib/task-templates/api"; import { deactivateTaskTemplate, fetchTaskTemplates } from "@/lib/task-templates/api";
import { TaskTemplate, TaskTemplateRecurrenceType } from "@/lib/task-templates/types"; import { TaskTemplate, TaskTemplateRecurrenceType } from "@/lib/task-templates/types";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { ConfirmDialog } from "@/components/confirm-dialog";
import { EmptyState } from "@/components/empty-state"; import { EmptyState } from "@/components/empty-state";
import { EntityCard } from "@/components/entity-card"; import { EntityCard } from "@/components/entity-card";
import { ActiveHistoryTabs, type EntityLifecycleTab } from "@/components/active-history-tabs"; import { ActiveHistoryTabs, type EntityLifecycleTab } from "@/components/active-history-tabs";
@@ -106,15 +106,16 @@ export function TaskTemplatesTab() {
actions={ actions={
<> <>
<EditTaskTemplateDialog template={template} /> <EditTaskTemplateDialog template={template} />
<Button <ConfirmDialog
type="button" triggerLabel="Deaktivieren"
variant="ghost" triggerVariant="ghost"
size="sm" triggerDisabled={!template.active || deactivateMutation.isPending}
disabled={!template.active || deactivateMutation.isPending} title="Wiederkehrende Aufgabe beenden?"
onClick={() => deactivateMutation.mutate(template.id)} description={`Für „${template.title}“ werden keine neuen Aufgaben mehr angelegt. Bereits angelegte Aufgaben bleiben in der Liste.`}
> confirmLabel="Beenden"
Deaktivieren isPending={deactivateMutation.isPending}
</Button> onConfirm={() => deactivateMutation.mutate(template.id)}
/>
</> </>
} }
/> />