From d053421f575accd9442ab98a101751de46b47216 Mon Sep 17 00:00:00 2001
From: Eliezer Steinbock <3090527+elie222@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:01:35 +0200
Subject: [PATCH] Refactor components to process tab (instead of test tab)
---
apps/web/app/(app)/automation/Process.tsx | 4 +-
.../(app)/automation/ProcessResultDisplay.tsx | 123 +++++++++++
.../{TestRules.tsx => ProcessRules.tsx} | 208 +-----------------
.../app/(app)/automation/ReportMistake.tsx | 10 +-
.../(app)/automation/TestCustomEmailForm.tsx | 69 ++++++
apps/web/utils/actions/ai-rule.ts | 9 +-
apps/web/utils/actions/validation.ts | 5 +
7 files changed, 220 insertions(+), 208 deletions(-)
create mode 100644 apps/web/app/(app)/automation/ProcessResultDisplay.tsx
rename apps/web/app/(app)/automation/{TestRules.tsx => ProcessRules.tsx} (58%)
create mode 100644 apps/web/app/(app)/automation/TestCustomEmailForm.tsx
diff --git a/apps/web/app/(app)/automation/Process.tsx b/apps/web/app/(app)/automation/Process.tsx
index 64b141a4..8ef3d268 100644
--- a/apps/web/app/(app)/automation/Process.tsx
+++ b/apps/web/app/(app)/automation/Process.tsx
@@ -1,7 +1,7 @@
"use client";
import { useState } from "react";
-import { TestRulesContent } from "@/app/(app)/automation/TestRules";
+import { ProcessRulesContent } from "@/app/(app)/automation/ProcessRules";
import { Toggle } from "@/components/Toggle";
import {
Card,
@@ -34,7 +34,7 @@ export function Process() {
/>
-
+
);
}
diff --git a/apps/web/app/(app)/automation/ProcessResultDisplay.tsx b/apps/web/app/(app)/automation/ProcessResultDisplay.tsx
new file mode 100644
index 00000000..f3451adc
--- /dev/null
+++ b/apps/web/app/(app)/automation/ProcessResultDisplay.tsx
@@ -0,0 +1,123 @@
+"use client";
+
+import Link from "next/link";
+import { capitalCase } from "capital-case";
+import { CheckCircle2Icon, EyeIcon, ExternalLinkIcon } from "lucide-react";
+import type { RunRulesResult } from "@/utils/ai/choose-rule/run-rules";
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { HoverCard } from "@/components/HoverCard";
+import { Badge } from "@/components/Badge";
+import { isAIRule } from "@/utils/condition";
+
+export function ProcessResultDisplay({
+ result,
+ prefix,
+}: {
+ result: RunRulesResult;
+ prefix?: string;
+}) {
+ if (!result) return null;
+
+ if (!result.rule) {
+ return (
+
+ No rule matched
+
+
+ This email does not match any of the rules you have set.
+
+
+ Reason: {result.reason || "No reason provided"}
+
+
+
+ }
+ >
+
+ {prefix ? prefix : ""}No rule matched
+
+
+
+ );
+ }
+
+ const MAX_LENGTH = 280;
+
+ const aiGeneratedContent = result.actionItems?.map((action, i) => (
+
+
+ {capitalCase(action.type)}
+
+ {Object.entries(action)
+ .filter(
+ ([key, value]) =>
+ value &&
+ ["label", "subject", "content", "to", "cc", "bcc", "url"].includes(
+ key,
+ ),
+ )
+ .map(([key, value]) => (
+
+
+ {capitalCase(key)}:
+
+
+ {value}
+
+
+ ))}
+
+ ));
+
+ return (
+
+
+
+ Matched rule "{result.rule.name}"
+
+ View rule
+
+
+
+
+ {isAIRule(result.rule) && (
+
+ AI Instructions:
+ {result.rule.instructions.substring(0, MAX_LENGTH)}
+ {result.rule.instructions.length >= MAX_LENGTH && "..."}
+
+ )}
+ {!!aiGeneratedContent?.length && (
+ {aiGeneratedContent}
+ )}
+ {!!result.reason && (
+
+ Reason:
+ {result.reason}
+
+ )}
+
+
+ }
+ >
+
+ {prefix ? prefix : ""}
+ {result.rule.name}
+
+
+
+ );
+}
diff --git a/apps/web/app/(app)/automation/TestRules.tsx b/apps/web/app/(app)/automation/ProcessRules.tsx
similarity index 58%
rename from apps/web/app/(app)/automation/TestRules.tsx
rename to apps/web/app/(app)/automation/ProcessRules.tsx
index 5aa9607e..69518939 100644
--- a/apps/web/app/(app)/automation/TestRules.tsx
+++ b/apps/web/app/(app)/automation/ProcessRules.tsx
@@ -1,45 +1,32 @@
"use client";
import { useCallback, useState, useRef, useMemo } from "react";
-import { type SubmitHandler, useForm } from "react-hook-form";
import useSWR from "swr";
import useSWRInfinite from "swr/infinite";
-import Link from "next/link";
import { useSession } from "next-auth/react";
import { parseAsBoolean, useQueryState } from "nuqs";
-import { capitalCase } from "capital-case";
import {
BookOpenCheckIcon,
- CheckCircle2Icon,
SparklesIcon,
PenSquareIcon,
PauseIcon,
- EyeIcon,
- ExternalLinkIcon,
ChevronsDownIcon,
RefreshCcwIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
-import { Input } from "@/components/Input";
import { toastError } from "@/components/Toast";
import { LoadingContent } from "@/components/LoadingContent";
-import { SlideOverSheet } from "@/components/SlideOverSheet";
import type { MessagesResponse } from "@/app/api/google/messages/route";
import { Separator } from "@/components/ui/separator";
import { TestRulesMessage } from "@/app/(app)/cold-email-blocker/TestRulesMessage";
-import {
- runRulesAction,
- testAiCustomContentAction,
-} from "@/utils/actions/ai-rule";
+import { runRulesAction } from "@/utils/actions/ai-rule";
import type { RulesResponse } from "@/app/api/user/rules/route";
import { Table, TableBody, TableRow, TableCell } from "@/components/ui/table";
import { CardContent } from "@/components/ui/card";
import { isActionError } from "@/utils/error";
import type { RunRulesResult } from "@/utils/ai/choose-rule/run-rules";
import { SearchForm } from "@/components/SearchForm";
-import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { ReportMistake } from "@/app/(app)/automation/ReportMistake";
-import { HoverCard } from "@/components/HoverCard";
import { Badge } from "@/components/Badge";
import {
isAIRule,
@@ -49,29 +36,12 @@ import {
} from "@/utils/condition";
import { BulkRunRules } from "@/app/(app)/automation/BulkRunRules";
import { cn } from "@/utils";
+import { TestCustomEmailForm } from "@/app/(app)/automation/TestCustomEmailForm";
+import { ProcessResultDisplay } from "@/app/(app)/automation/ProcessResultDisplay";
type Message = MessagesResponse["messages"][number];
-export function TestRules(props: { disabled?: boolean }) {
- return (
-
-
-
- }
- >
-
-
- );
-}
-
-export function TestRulesContent({ testMode }: { testMode: boolean }) {
+export function ProcessRulesContent({ testMode }: { testMode: boolean }) {
const [searchQuery, setSearchQuery] = useQueryState("search");
const [showCustomForm, setShowCustomForm] = useQueryState(
"custom",
@@ -198,7 +168,7 @@ export function TestRulesContent({ testMode }: { testMode: boolean }) {
{hasAiRules && showCustomForm && testMode && (
-
+
@@ -214,7 +184,7 @@ export function TestRulesContent({ testMode }: { testMode: boolean }) {
{messages.map((message) => (
- {
- const [testResult, setTestResult] = useState();
-
- const {
- register,
- handleSubmit,
- formState: { errors, isSubmitting },
- } = useForm();
-
- const onSubmit: SubmitHandler = useCallback(async (data) => {
- const result = await testAiCustomContentAction({ content: data.message });
- if (isActionError(result)) {
- toastError({
- title: "Error testing email",
- description: result.error,
- });
- } else {
- setTestResult(result);
- }
- }, []);
-
- return (
-
-
- {testResult && (
-
-
-
- )}
-
- );
-};
-
-function TestRulesContentRow({
+function ProcessRulesRow({
message,
userEmail,
isRunning,
@@ -331,7 +252,7 @@ function TestRulesContentRow({
{result.existing && (
Already processed
)}
-
+