aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/dashboard/rules/RuleEngineRuleList.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/components/dashboard/rules/RuleEngineRuleList.tsx')
-rw-r--r--apps/web/components/dashboard/rules/RuleEngineRuleList.tsx166
1 files changed, 166 insertions, 0 deletions
diff --git a/apps/web/components/dashboard/rules/RuleEngineRuleList.tsx b/apps/web/components/dashboard/rules/RuleEngineRuleList.tsx
new file mode 100644
index 00000000..206a3550
--- /dev/null
+++ b/apps/web/components/dashboard/rules/RuleEngineRuleList.tsx
@@ -0,0 +1,166 @@
+import { ActionButton } from "@/components/ui/action-button";
+import ActionConfirmingDialog from "@/components/ui/action-confirming-dialog";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent } from "@/components/ui/card";
+import { Switch } from "@/components/ui/switch";
+import { toast } from "@/components/ui/use-toast";
+import { useClientConfig } from "@/lib/clientConfig";
+import { Edit, Trash2 } from "lucide-react";
+import { useTranslation } from "react-i18next";
+
+import type { RuleEngineRule } from "@karakeep/shared/types/rules";
+import {
+ useDeleteRule,
+ useUpdateRule,
+} from "@karakeep/shared-react/hooks/rules";
+
+export default function RuleList({
+ rules,
+ onEditRule,
+ onDeleteRule,
+}: {
+ rules: RuleEngineRule[];
+ onEditRule: (rule: RuleEngineRule) => void;
+ onDeleteRule?: (ruleId: string) => void;
+}) {
+ const { t } = useTranslation();
+ const { demoMode } = useClientConfig();
+ const { mutate: updateRule, isPending: isUpdating } = useUpdateRule({
+ onSuccess: () => {
+ toast({
+ description: t("settings.rules.rule_has_been_updated"),
+ });
+ },
+ onError: (e) => {
+ toast({
+ description: e.message,
+ variant: "destructive",
+ });
+ },
+ });
+
+ const { mutate: deleteRule, isPending: isDeleting } = useDeleteRule({
+ onSuccess: (_ret, req) => {
+ toast({
+ description: t("settings.rules.rule_has_been_deleted"),
+ });
+ onDeleteRule?.(req.id);
+ },
+ onError: (e) => {
+ toast({
+ description: e.message,
+ variant: "destructive",
+ });
+ },
+ });
+
+ if (rules.length === 0) {
+ return (
+ <div className="rounded-lg border border-dashed p-8 text-center">
+ <h3 className="text-lg font-medium">
+ {t("settings.rules.no_rules_created_yet")}
+ </h3>
+ <p className="mt-2 text-sm text-muted-foreground">
+ {t("settings.rules.create_your_first_rule")}
+ </p>
+ </div>
+ );
+ }
+
+ return (
+ <div className="space-y-4">
+ {rules.map((rule) => (
+ <Card key={rule.id} className={rule.enabled ? "" : "opacity-70"}>
+ <CardContent className="p-4">
+ <div className="flex items-center justify-between">
+ <div className="mr-4 flex-1">
+ <h3 className="font-medium">{rule.name}</h3>
+ <p className="line-clamp-2 text-sm text-muted-foreground">
+ {rule.description}
+ </p>
+ <div className="mt-2 flex items-center text-xs text-muted-foreground">
+ <span className="flex items-center">
+ <span className="mr-1">Trigger:</span>
+ <span className="font-medium">
+ {formatEventType(rule.event.type)}
+ </span>
+ </span>
+ <span className="mx-2">•</span>
+ <span>
+ {rule.actions.length} action
+ {rule.actions.length !== 1 ? "s" : ""}
+ </span>
+ </div>
+ </div>
+ <div className="flex items-center space-x-2">
+ <Switch
+ disabled={!!demoMode || isUpdating}
+ checked={rule.enabled}
+ onCheckedChange={(checked) =>
+ updateRule({
+ ...rule,
+ enabled: checked,
+ })
+ }
+ />
+ <Button
+ variant="ghost"
+ size="icon"
+ onClick={() => onEditRule(rule)}
+ >
+ <Edit className="h-4 w-4" />
+ </Button>
+ <ActionConfirmingDialog
+ title={t("settings.rules.delete_rule")}
+ description={t("settings.rules.delete_rule_confirmation")}
+ actionButton={(setDialogOpen) => (
+ <ActionButton
+ loading={isDeleting}
+ variant="destructive"
+ onClick={() => {
+ deleteRule({ id: rule.id });
+ setDialogOpen(true);
+ }}
+ >
+ <Trash2 className="mr-2 h-4 w-4" />
+ {t("actions.delete")}
+ </ActionButton>
+ )}
+ >
+ <Button
+ variant="ghost"
+ size="icon"
+ className="text-red-500 hover:text-red-600"
+ >
+ <Trash2 className="h-4 w-4" />
+ </Button>
+ </ActionConfirmingDialog>
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ ))}
+ </div>
+ );
+}
+
+function formatEventType(type: string): string {
+ switch (type) {
+ case "bookmarkAdded":
+ return "Bookmark Added";
+ case "tagAdded":
+ return "Tag Added";
+ case "tagRemoved":
+ return "Tag Removed";
+ case "addedToList":
+ return "Added to List";
+ case "removedFromList":
+ return "Removed from List";
+ case "favourited":
+ return "Favourited";
+ case "archived":
+ return "Archived";
+ default:
+ return type;
+ }
+}