Skip to content

Commit d1288bb

Browse files
[dev] [Marfuen] mariano/tasks-stuff (#1713)
* fix: auto enable automation when publishing * fix: show success criteria on first render * fix(TestResultsPanel): use actual evaluation criteria for rendering * fix(TestResultsPanel): use shared chat context for automation ID * feat(automation): add file writing activity component and version handling * feat(automation): enhance publish dialog with post-publish options and version testing * fix(automation): update SWR type for automation runs data --------- Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
1 parent b604b18 commit d1288bb

File tree

15 files changed

+523
-81
lines changed

15 files changed

+523
-81
lines changed

apps/app/package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949
"@tiptap/extension-table-cell": "^3.4.4",
5050
"@tiptap/extension-table-header": "^3.4.4",
5151
"@tiptap/extension-table-row": "^3.4.4",
52-
"@trigger.dev/react-hooks": "4.0.0",
53-
"@trigger.dev/sdk": "4.0.0",
52+
"@trigger.dev/react-hooks": "4.0.6",
53+
"@trigger.dev/sdk": "4.0.6",
5454
"@trycompai/db": "^1.3.7",
5555
"@trycompai/email": "workspace:*",
5656
"@types/canvas-confetti": "^1.9.0",
@@ -117,7 +117,7 @@
117117
"@testing-library/dom": "^10.4.0",
118118
"@testing-library/jest-dom": "^6.6.3",
119119
"@testing-library/react": "^16.3.0",
120-
"@trigger.dev/build": "4.0.0",
120+
"@trigger.dev/build": "4.0.6",
121121
"@types/d3": "^7.4.3",
122122
"@types/jspdf": "^2.0.0",
123123
"@types/node": "^24.0.3",
@@ -157,7 +157,7 @@
157157
"db:getschema": "node ../../packages/db/scripts/combine-schemas.js && cp ../../packages/db/dist/schema.prisma prisma/schema.prisma",
158158
"db:migrate": "cd ../../packages/db && bunx prisma migrate dev && cd ../../apps/app",
159159
"deploy:trigger-prod": "npx trigger.dev@4.0.0 deploy",
160-
"dev": "bun i && bunx concurrently --kill-others --names \"next,trigger\" --prefix-colors \"yellow,blue\" \"next dev --turbo -p 3000\" \"bun run trigger:dev\"",
160+
"dev": "bun i && bunx concurrently --kill-others --names \"next,trigger\" --prefix-colors \"yellow,blue\" \"next dev --turbo -p 3000\" \"bunx trigger.dev@4.0.6 dev\"",
161161
"lint": "next lint && prettier --check .",
162162
"prebuild": "bun run db:generate",
163163
"start": "next start",
@@ -173,7 +173,6 @@
173173
"test:e2e:ui": "playwright test --ui",
174174
"test:ui": "vitest --ui",
175175
"test:watch": "vitest --watch",
176-
"trigger:dev": "npx trigger.dev@4.0.0 dev",
177176
"typecheck": "tsc --noEmit"
178177
}
179178
}

apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/actions/task-automation-actions.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ export async function executeAutomationScript(data: {
186186
orgId: string;
187187
taskId: string;
188188
automationId: string;
189+
version?: number; // Optional: test specific version
189190
}) {
190191
try {
191192
const result = await callEnterpriseApi('/api/tasks-automations/trigger/execute', {
@@ -361,6 +362,12 @@ export async function publishAutomation(
361362
},
362363
});
363364

365+
// Enable automation if not already enabled
366+
await db.evidenceAutomation.update({
367+
where: { id: automationId },
368+
data: { isEnabled: true },
369+
});
370+
364371
return {
365372
success: true,
366373
version,

apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/components/PublishDialog.tsx

Lines changed: 102 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import {
1212
import { Label } from '@comp/ui/label';
1313
import { Textarea } from '@comp/ui/textarea';
1414
import { Loader2 } from 'lucide-react';
15-
import { useParams } from 'next/navigation';
15+
import { useParams, useRouter } from 'next/navigation';
1616
import { useState } from 'react';
1717
import { toast } from 'sonner';
18-
import { publishAutomation } from '../actions/task-automation-actions';
18+
import { executeAutomationScript, publishAutomation } from '../actions/task-automation-actions';
1919
import { useAutomationVersions } from '../hooks/use-automation-versions';
2020
import { useSharedChatContext } from '../lib/chat-context';
2121

@@ -25,6 +25,7 @@ interface PublishDialogProps {
2525
}
2626

2727
export function PublishDialog({ open, onOpenChange }: PublishDialogProps) {
28+
const router = useRouter();
2829
const { orgId, taskId } = useParams<{
2930
orgId: string;
3031
taskId: string;
@@ -33,8 +34,20 @@ export function PublishDialog({ open, onOpenChange }: PublishDialogProps) {
3334
const { automationIdRef } = useSharedChatContext();
3435
const [changelog, setChangelog] = useState('');
3536
const [isPublishing, setIsPublishing] = useState(false);
37+
const [showPostPublishOptions, setShowPostPublishOptions] = useState(false);
38+
const [publishedVersion, setPublishedVersion] = useState<number | null>(null);
3639
const { mutate } = useAutomationVersions();
3740

41+
const handleDialogChange = (newOpen: boolean) => {
42+
onOpenChange(newOpen);
43+
// Reset state when dialog closes
44+
if (!newOpen) {
45+
setChangelog('');
46+
setShowPostPublishOptions(false);
47+
setPublishedVersion(null);
48+
}
49+
};
50+
3851
const handlePublish = async () => {
3952
setIsPublishing(true);
4053

@@ -50,51 +63,105 @@ export function PublishDialog({ open, onOpenChange }: PublishDialogProps) {
5063
throw new Error(result.error || 'Failed to publish');
5164
}
5265

53-
toast.success(`Version ${result.version?.version} published successfully!`);
54-
setChangelog('');
55-
onOpenChange(false);
66+
const versionNumber = result.version?.version;
67+
toast.success(`Version ${versionNumber} published successfully!`);
68+
setPublishedVersion(versionNumber || null);
5669

5770
// Refresh versions list
5871
await mutate();
72+
73+
// Trigger a test run with the new version
74+
if (versionNumber) {
75+
const runResult = await executeAutomationScript({
76+
orgId,
77+
taskId,
78+
automationId: automationIdRef.current,
79+
version: versionNumber,
80+
});
81+
82+
if (runResult.success) {
83+
toast.success('Running automation with published version');
84+
} else {
85+
toast.error(runResult.error || 'Failed to start automation run');
86+
}
87+
}
88+
89+
// Show post-publish options instead of closing
90+
setShowPostPublishOptions(true);
5991
} catch (error) {
6092
toast.error(error instanceof Error ? error.message : 'Failed to publish automation');
6193
} finally {
6294
setIsPublishing(false);
6395
}
6496
};
6597

98+
const handleGoToOverview = () => {
99+
handleDialogChange(false);
100+
router.push(`/${orgId}/tasks/${taskId}/automations/${automationIdRef.current}/overview`);
101+
};
102+
103+
const handleStayHere = () => {
104+
handleDialogChange(false);
105+
};
106+
66107
return (
67-
<Dialog open={open} onOpenChange={onOpenChange}>
108+
<Dialog open={open} onOpenChange={handleDialogChange}>
68109
<DialogContent>
69-
<DialogHeader>
70-
<DialogTitle>Publish Automation</DialogTitle>
71-
<DialogDescription>
72-
Create a new version of this automation. The current draft will remain editable.
73-
</DialogDescription>
74-
</DialogHeader>
75-
76-
<div className="space-y-4 py-4">
77-
<div className="space-y-2">
78-
<Label htmlFor="changelog">Changelog (optional)</Label>
79-
<Textarea
80-
id="changelog"
81-
placeholder="Describe what changed in this version..."
82-
value={changelog}
83-
onChange={(e) => setChangelog(e.target.value)}
84-
rows={4}
85-
/>
86-
</div>
87-
</div>
88-
89-
<DialogFooter>
90-
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={isPublishing}>
91-
Cancel
92-
</Button>
93-
<Button onClick={handlePublish} disabled={isPublishing}>
94-
{isPublishing && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
95-
{isPublishing ? 'Publishing...' : 'Publish'}
96-
</Button>
97-
</DialogFooter>
110+
{!showPostPublishOptions ? (
111+
<>
112+
<DialogHeader>
113+
<DialogTitle>Publish Automation</DialogTitle>
114+
<DialogDescription>
115+
Create a new version of this automation. The current draft will remain editable.
116+
</DialogDescription>
117+
</DialogHeader>
118+
119+
<div className="space-y-4 py-4">
120+
<div className="space-y-2">
121+
<Label htmlFor="changelog">Changelog (optional)</Label>
122+
<Textarea
123+
id="changelog"
124+
placeholder="Describe what changed in this version..."
125+
value={changelog}
126+
onChange={(e) => setChangelog(e.target.value)}
127+
rows={4}
128+
/>
129+
</div>
130+
</div>
131+
132+
<DialogFooter>
133+
<Button
134+
variant="outline"
135+
onClick={() => handleDialogChange(false)}
136+
disabled={isPublishing}
137+
>
138+
Cancel
139+
</Button>
140+
<Button onClick={handlePublish} disabled={isPublishing}>
141+
{isPublishing && <Loader2 className="h-4 w-4 mr-2 animate-spin" />}
142+
{isPublishing ? 'Publishing...' : 'Publish'}
143+
</Button>
144+
</DialogFooter>
145+
</>
146+
) : (
147+
<>
148+
<DialogHeader>
149+
<DialogTitle>Automation Published!</DialogTitle>
150+
<DialogDescription>
151+
Version {publishedVersion} has been published and is now running. Where would you like to go?
152+
</DialogDescription>
153+
</DialogHeader>
154+
155+
<DialogFooter className="flex-col sm:flex-row gap-2">
156+
<Button variant="outline" onClick={handleStayHere} className="w-full sm:w-auto">
157+
Stay Here
158+
</Button>
159+
<Button onClick={handleGoToOverview} className="w-full sm:w-auto">
160+
Go to Overview
161+
</Button>
162+
</DialogFooter>
163+
</>
164+
)}
98165
</DialogContent>
99166
</Dialog>
100167
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
'use client';
2+
3+
import { CheckCircle2, FileText, Loader2, XCircle } from 'lucide-react';
4+
import { useEffect, useState } from 'react';
5+
6+
interface FileWritingActivityProps {
7+
input: any;
8+
state: 'input-streaming' | 'input-available' | 'output-available' | 'output-error';
9+
output?: any;
10+
isAnimating: boolean;
11+
}
12+
13+
export function FileWritingActivity({
14+
input,
15+
state,
16+
output,
17+
isAnimating,
18+
}: FileWritingActivityProps) {
19+
const isComplete = state === 'output-available';
20+
const isError = state === 'output-error';
21+
const isLoading = state === 'input-streaming' || state === 'input-available';
22+
const [startTime] = useState(() => Date.now());
23+
const [duration, setDuration] = useState<number | null>(null);
24+
const [isExpanded, setIsExpanded] = useState(false);
25+
26+
// Track actual timing
27+
useEffect(() => {
28+
if ((isComplete || isError) && duration === null) {
29+
const elapsed = Math.round((Date.now() - startTime) / 1000);
30+
setDuration(elapsed);
31+
}
32+
}, [isComplete, isError, startTime, duration]);
33+
34+
const getIcon = () => {
35+
if (isError) return <XCircle className="h-4 w-4 text-muted-foreground" />;
36+
if (isComplete) return <CheckCircle2 className="h-4 w-4 text-muted-foreground" />;
37+
if (isLoading) return <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />;
38+
return <FileText className="h-4 w-4 text-muted-foreground" />;
39+
};
40+
41+
const getTitle = () => {
42+
if (isError) {
43+
return duration ? `Failed to save after ${duration}s` : 'Failed to save automation';
44+
}
45+
46+
if (isComplete && duration !== null) {
47+
return `Saved in ${duration}s`;
48+
}
49+
return 'Creating automation...';
50+
};
51+
52+
const getResultSummary = () => {
53+
// Only show summary when complete and available
54+
if (!isComplete || !output?.summary) return null;
55+
56+
return (
57+
<div className="mt-2">
58+
<p className="text-xs text-muted-foreground">{output.summary}</p>
59+
</div>
60+
);
61+
};
62+
63+
return (
64+
<div className="py-0.5">
65+
<button
66+
type="button"
67+
className="flex items-center gap-2 text-xs text-muted-foreground hover:text-foreground transition-colors"
68+
onClick={() => setIsExpanded(!isExpanded)}
69+
>
70+
<div className="w-1 h-1 rounded-full bg-muted-foreground/40" />
71+
<span>{getTitle()}</span>
72+
</button>
73+
{isExpanded && (isComplete || isError) && output?.summary && (
74+
<div className="mt-1 ml-3 text-xs text-muted-foreground/80 leading-relaxed">
75+
{output.summary}
76+
</div>
77+
)}
78+
</div>
79+
);
80+
}

apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/components/chat/message-part/index.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { memo } from 'react';
33
import { DataPart } from '../../../lib/types/data-parts';
44
import { Metadata } from '../../../lib/types/metadata';
55
import { TaskAutomationToolSet } from '../../../tools/task-automation-tools';
6+
import { FileWritingActivity } from './file-writing-activity';
67
import { PromptInfo } from './prompt-info';
78
import { PromptSecret } from './prompt-secret';
89
import { Reasoning } from './reasoning';
@@ -62,6 +63,15 @@ export const MessagePart = memo(function MessagePart({
6263
isAnimating={partIndex === 0}
6364
/>
6465
);
66+
} else if (part.type === 'tool-storeToS3') {
67+
return (
68+
<FileWritingActivity
69+
input={part.input}
70+
state={part.state}
71+
output={part.output}
72+
isAnimating={partIndex === 0}
73+
/>
74+
);
6575
}
6676
return null;
6777
});

0 commit comments

Comments
 (0)