diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-04-27 00:02:20 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-27 00:02:20 +0100 |
| commit | 136f126296af65f50da598d084d1485c0e40437a (patch) | |
| tree | 2725c7932ebbcb9b48b5af98eb9b72329a400260 /apps/web/app/settings/rules/page.tsx | |
| parent | ca47be7fe7be128f459c37614a04902a873fe289 (diff) | |
| download | karakeep-136f126296af65f50da598d084d1485c0e40437a.tar.zst | |
feat: Implement generic rule engine (#1318)
* Add schema for the new rule engine
* Add rule engine backend logic
* Implement the worker logic and event firing
* Implement the UI changesfor the rule engine
* Ensure that when a referenced list or tag are deleted, the corresponding event/action is
* Dont show smart lists in rule engine events
* Add privacy validations for attached tag and list ids
* Move the rules logic into a models
Diffstat (limited to 'apps/web/app/settings/rules/page.tsx')
| -rw-r--r-- | apps/web/app/settings/rules/page.tsx | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/apps/web/app/settings/rules/page.tsx b/apps/web/app/settings/rules/page.tsx new file mode 100644 index 00000000..98a30bcc --- /dev/null +++ b/apps/web/app/settings/rules/page.tsx @@ -0,0 +1,89 @@ +"use client"; + +import { useState } from "react"; +import { RuleEditor } from "@/components/dashboard/rules/RuleEngineRuleEditor"; +import RuleList from "@/components/dashboard/rules/RuleEngineRuleList"; +import { Button } from "@/components/ui/button"; +import { FullPageSpinner } from "@/components/ui/full-page-spinner"; +import { useTranslation } from "@/lib/i18n/client"; +import { api } from "@/lib/trpc"; +import { Tooltip, TooltipContent, TooltipTrigger } from "components/ui/tooltip"; +import { FlaskConical, PlusCircle } from "lucide-react"; + +import { RuleEngineRule } from "@karakeep/shared/types/rules"; + +export default function RulesSettingsPage() { + const { t } = useTranslation(); + const [editingRule, setEditingRule] = useState< + (Omit<RuleEngineRule, "id"> & { id: string | null }) | null + >(null); + + const { data: rules, isLoading } = api.rules.list.useQuery(undefined, { + refetchOnWindowFocus: true, + refetchOnMount: true, + }); + + const handleCreateRule = () => { + const newRule = { + id: null, + name: "New Rule", + description: "Description of the new rule", + enabled: true, + event: { type: "bookmarkAdded" as const }, + condition: { type: "alwaysTrue" as const }, + actions: [{ type: "addTag" as const, tagId: "" }], + }; + setEditingRule(newRule); + }; + + const handleDeleteRule = (ruleId: string) => { + if (editingRule?.id === ruleId) { + // If the rule being edited is being deleted, reset the editing rule + setEditingRule(null); + } + }; + + return ( + <div className="rounded-md border bg-background p-4"> + <div className="flex flex-col gap-2"> + <div className="flex items-center justify-between"> + <span className="flex items-center gap-2 text-lg font-medium"> + {t("settings.rules.rules")} + <Tooltip> + <TooltipTrigger className="text-muted-foreground"> + <FlaskConical size={15} /> + </TooltipTrigger> + <TooltipContent side="bottom"> + {t("common.experimental")} + </TooltipContent> + </Tooltip> + </span> + <Button onClick={handleCreateRule} variant="default"> + <PlusCircle className="mr-2 h-4 w-4" /> + {t("settings.rules.ceate_rule")} + </Button> + </div> + <p className="text-sm italic text-muted-foreground"> + {t("settings.rules.description")} + </p> + {!rules || isLoading ? ( + <FullPageSpinner /> + ) : ( + <RuleList + rules={rules.rules} + onEditRule={(r) => setEditingRule(r)} + onDeleteRule={handleDeleteRule} + /> + )} + <div className="lg:col-span-7"> + {editingRule && ( + <RuleEditor + rule={editingRule} + onCancel={() => setEditingRule(null)} + /> + )} + </div> + </div> + </div> + ); +} |
