Skip to content
Merged
28 changes: 11 additions & 17 deletions apps/web/app/(app)/automation/BulkRunRules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ export function BulkRunRules() {

return (
<div>
<Tooltip content="Select emails to process with AI">
<Tooltip content="Bulk process emails">
<Button type="button" size="icon" variant="outline" onClick={openModal}>
<HistoryIcon className="size-4" />
<span className="sr-only">Select emails to process with AI</span>
<span className="sr-only">Select emails to process</span>
</Button>
</Tooltip>
<Modal
Expand Down Expand Up @@ -114,21 +114,15 @@ export function BulkRunRules() {
</div>

<SectionDescription className="mt-4">
To process specific emails:
<ol className="mt-1 list-inside list-decimal">
<li>
Go to the{" "}
<Link
href="/mail"
className="font-semibold hover:underline"
>
Mail
</Link>{" "}
page
</li>
<li>Select the desired emails</li>
<li>Click the "Run AI Rules" button</li>
</ol>
You can also process specific emails by visiting the{" "}
<Link
href="/mail"
target="_blank"
className="font-semibold hover:underline"
>
Mail
</Link>{" "}
page.
</SectionDescription>
</>
)}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/(app)/automation/Pending.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ function PendingTable({
/>
</TableCell>
<TableCell>
<RuleCell rule={p.rule} reason={p.reason} />
<RuleCell rule={p.rule} reason={p.reason} message={p.message} />
</TableCell>
<TableCell>
<ActionItemsCell actionItems={p.actionItems} />
Expand Down
40 changes: 40 additions & 0 deletions apps/web/app/(app)/automation/Process.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import { useState } from "react";
import { TestRulesContent } from "@/app/(app)/automation/TestRules";
import { Toggle } from "@/components/Toggle";
import {
Card,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";

export function Process() {
const [applyMode, setApplyMode] = useState(false);

return (
<Card>
<CardHeader>
<CardTitle>Process your emails</CardTitle>

<CardDescription>
{applyMode
? "Run your rules on previous emails."
: "Check how your rules perform against previous emails."}
</CardDescription>

<div className="flex pt-1">
<Toggle
name="test-mode"
label="Test"
labelRight="Apply"
enabled={applyMode}
onChange={setApplyMode}
/>
</div>
</CardHeader>
<TestRulesContent testMode={!applyMode} />
</Card>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
} from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { TestRulesContent } from "@/app/(app)/automation/TestRules";
import { Loading } from "@/components/Loading";

/*
Expand Down
45 changes: 25 additions & 20 deletions apps/web/app/(app)/automation/ReportMistake.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import { Button } from "@/components/ui/button";
import { Label } from "@/components/Input";
import { toastError, toastSuccess } from "@/components/Toast";
import { isActionError } from "@/utils/error";
import type { TestResult } from "@/utils/ai/choose-rule/run-rules";
import type { RunRulesResult } from "@/utils/ai/choose-rule/run-rules";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { reportAiMistakeAction, testAiAction } from "@/utils/actions/ai-rule";
import { reportAiMistakeAction, runRulesAction } from "@/utils/actions/ai-rule";
import type { MessagesResponse } from "@/app/api/google/messages/route";
import { zodResolver } from "@hookform/resolvers/zod";
import {
Expand All @@ -45,6 +45,7 @@ import { TestResultDisplay } from "@/app/(app)/automation/TestRules";
import { isReplyInThread } from "@/utils/thread";
import { isAIRule, isGroupRule, isStaticRule } from "@/utils/condition";
import { Loading } from "@/components/Loading";
import type { ParsedMessage } from "@/utils/types";

type ReportMistakeView = "select-expected-rule" | "ai-fix" | "manual-fix";

Expand All @@ -55,7 +56,7 @@ export function ReportMistake({
result,
}: {
message: MessagesResponse["messages"][number];
result: TestResult | null;
result: RunRulesResult | null;
}) {
const { data, isLoading, error } = useSWR<RulesResponse, { error: string }>(
"/api/user/rules",
Expand Down Expand Up @@ -99,7 +100,7 @@ function Content({
}: {
rules: RulesResponse;
message: MessagesResponse["messages"][number];
result: TestResult | null;
result: RunRulesResult | null;
actualRule: Rule | null;
}) {
const [loadingAiFix, setLoadingAiFix] = useState(false);
Expand Down Expand Up @@ -244,7 +245,7 @@ function Content({
loadingAiFix={loadingAiFix}
fixedInstructions={fixedInstructions ?? null}
fixedInstructionsRule={fixedInstructionsRule ?? null}
messageId={message.id}
message={message}
onBack={onBack}
onReject={() => onSetView("manual-fix")}
/>
Expand All @@ -271,7 +272,7 @@ function AIFixView({
loadingAiFix,
fixedInstructions,
fixedInstructionsRule,
messageId,
message,
onBack,
onReject,
}: {
Expand All @@ -281,7 +282,7 @@ function AIFixView({
fixedInstructions: string;
} | null;
fixedInstructionsRule: Rule | null;
messageId: string;
message: ParsedMessage;
onBack: () => void;
onReject: () => void;
}) {
Expand Down Expand Up @@ -310,7 +311,7 @@ function AIFixView({

{fixedInstructions?.ruleId && (
<SuggestedFix
messageId={messageId}
message={message}
ruleId={fixedInstructions.ruleId}
fixedInstructions={fixedInstructions.fixedInstructions}
onReject={onReject}
Expand All @@ -328,7 +329,7 @@ function RuleMismatch({
rules,
onSelectExpectedRuleId,
}: {
result: TestResult | null;
result: RunRulesResult | null;
rules: RulesResponse;
onSelectExpectedRuleId: (ruleId: string | null) => void;
}) {
Expand Down Expand Up @@ -454,7 +455,7 @@ function ManualFixView({
actualRule?: Rule | null;
expectedRule?: Rule | null;
message: MessagesResponse["messages"][number];
result: TestResult | null;
result: RunRulesResult | null;
onBack: () => void;
}) {
return (
Expand Down Expand Up @@ -495,7 +496,7 @@ function ManualFixView({
<Separator />
</>
)}
<RerunTestButton messageId={message.id} />
<RerunTestButton message={message} />
<BackButton onBack={onBack} />
</>
);
Expand Down Expand Up @@ -559,7 +560,7 @@ function AIFixForm({
expectedRuleId,
}: {
message: MessagesResponse["messages"][number];
result: TestResult | null;
result: RunRulesResult | null;
expectedRuleId: string | null;
}) {
const [fixedInstructions, setFixedInstructions] = useState<{
Expand Down Expand Up @@ -642,7 +643,7 @@ function AIFixForm({

{fixedInstructions && (
<SuggestedFix
messageId={message.id}
message={message}
ruleId={fixedInstructions.ruleId}
fixedInstructions={fixedInstructions.fixedInstructions}
onReject={() => setFixedInstructions(undefined)}
Expand All @@ -654,13 +655,13 @@ function AIFixForm({
}

function SuggestedFix({
messageId,
message,
ruleId,
fixedInstructions,
onReject,
showRerunTestButton,
}: {
messageId: string;
message: ParsedMessage;
ruleId: string;
fixedInstructions: string;
onReject: () => void;
Expand All @@ -676,7 +677,7 @@ function SuggestedFix({
{accepted ? (
showRerunTestButton && (
<div className="mt-2">
<RerunTestButton messageId={messageId} />
<RerunTestButton message={message} />
</div>
)
) : (
Expand Down Expand Up @@ -729,9 +730,9 @@ function Instructions({
);
}

function RerunTestButton({ messageId }: { messageId: string }) {
function RerunTestButton({ message }: { message: ParsedMessage }) {
const [checking, setChecking] = useState(false);
const [testResult, setTestResult] = useState<TestResult>();
const [testResult, setTestResult] = useState<RunRulesResult>();

return (
<>
Expand All @@ -740,14 +741,18 @@ function RerunTestButton({ messageId }: { messageId: string }) {
onClick={async () => {
setChecking(true);

const result = await testAiAction({ messageId });
const result = await runRulesAction({
isTest: true,
messageId: message.id,
threadId: message.threadId,
});
if (isActionError(result)) {
toastError({
title: "There was an error testing the email",
description: result.error,
});
} else {
setTestResult(result);
setTestResult(result as RunRulesResult);
}
setChecking(false);
}}
Expand Down
Loading