Skip to content

Commit c80c1b4

Browse files
committed
feat: add cc suggestion checkboxes
1 parent 655bd01 commit c80c1b4

File tree

2 files changed

+58
-13
lines changed

2 files changed

+58
-13
lines changed

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ Read `docs/dev-rules.md` before writing any code. Key rules:
132132
- Minimal CI build workflow (GitHub Actions: `npm ci && npm run build`)
133133
- Deployment guide (`docs/deployment.md`) for single-port runtime, env vars, reverse proxy, and Docker/OpenClaw notes
134134
- Global CLI packaging entrypoint (`bin/agentclick.mjs`) for `agentclick` command startup
135+
- npm package published: `agentclick@0.1.0`
136+
- CC suggestions checkbox UI (returns selected suggestions in review completion payload)
135137

136138
**Pending:**
137-
- npm publish execution (`npm publish`) after final package review
138-
- CC suggestions as checkboxes (currently free-text input; agent can pass `ccSuggestions[]`)
139139

140140
---
141141

packages/web/src/pages/ReviewPage.tsx

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,19 @@ interface EmailItem {
2121
timestamp: number
2222
}
2323

24+
interface CcSuggestion {
25+
name: string
26+
email: string
27+
}
28+
2429
interface InboxPayload {
2530
inbox: EmailItem[]
2631
draft: {
2732
replyTo: string
2833
to: string
2934
subject: string
3035
paragraphs: Paragraph[]
36+
ccSuggestions?: CcSuggestion[]
3137
}
3238
}
3339

@@ -88,7 +94,7 @@ export default function ReviewPage() {
8894
const [rightView, setRightView] = useState<'draft' | 'summary' | 'empty'>('empty')
8995
const [markedAsRead, setMarkedAsRead] = useState<string[]>([])
9096
const [userIntention, setUserIntention] = useState('')
91-
const [cc, setCc] = useState('')
97+
const [selectedCcEmails, setSelectedCcEmails] = useState<string[]>([])
9298
const [summaryEmail, setSummaryEmail] = useState<EmailItem | null>(null)
9399

94100
useEffect(() => {
@@ -155,8 +161,17 @@ export default function ReviewPage() {
155161
const submit = async (confirmed: boolean) => {
156162
setSubmitting(true)
157163
const hasInbox = payload && 'inbox' in payload && Array.isArray((payload as InboxPayload).inbox)
164+
const ccSuggestions = hasInbox ? ((payload as InboxPayload).draft.ccSuggestions ?? []) : []
165+
const selectedCcSuggestions = ccSuggestions.filter(s => selectedCcEmails.includes(s.email))
158166
const body = hasInbox
159-
? JSON.stringify({ actions, confirmed, regenerate: !confirmed, markedAsRead, userIntention, cc })
167+
? JSON.stringify({
168+
actions,
169+
confirmed,
170+
regenerate: !confirmed,
171+
markedAsRead,
172+
userIntention,
173+
selectedCcSuggestions,
174+
})
160175
: JSON.stringify({ actions, confirmed, regenerate: !confirmed })
161176
const result = await fetch(`http://localhost:3001/api/sessions/${id}/complete`, {
162177
method: 'POST',
@@ -204,6 +219,15 @@ export default function ReviewPage() {
204219
const inboxPayload = payload as InboxPayload
205220
const visibleEmails = inboxPayload.inbox.filter(e => !markedAsRead.includes(e.id)).slice(0, 10)
206221
const hasActions = actions.length > 0
222+
const ccSuggestions = inboxPayload.draft.ccSuggestions ?? []
223+
224+
const toggleCcSuggestion = (email: string) => {
225+
setSelectedCcEmails(current =>
226+
current.includes(email)
227+
? current.filter(x => x !== email)
228+
: [...current, email]
229+
)
230+
}
207231

208232
const renderParagraphs = (paragraphs: Paragraph[]) =>
209233
paragraphs.map(p => {
@@ -383,16 +407,37 @@ export default function ReviewPage() {
383407
/>
384408
</div>
385409

386-
{/* CC */}
410+
{/* CC Suggestions */}
387411
<div className="mb-6">
388-
<label className="block text-xs text-zinc-500 mb-1">CC</label>
389-
<input
390-
type="text"
391-
className="w-full text-sm border border-gray-200 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-300"
392-
placeholder="e.g. hanwen@company.com"
393-
value={cc}
394-
onChange={e => setCc(e.target.value)}
395-
/>
412+
<label className="block text-xs text-zinc-500 mb-2">CC Suggestions</label>
413+
{ccSuggestions.length === 0 ? (
414+
<p className="text-xs text-zinc-400 border border-gray-100 rounded-lg px-3 py-2">No CC suggestions</p>
415+
) : (
416+
<div className="space-y-2">
417+
{ccSuggestions.map(suggestion => {
418+
const checked = selectedCcEmails.includes(suggestion.email)
419+
return (
420+
<label
421+
key={suggestion.email}
422+
className={`flex items-center gap-3 p-3 border rounded-lg cursor-pointer transition-colors ${
423+
checked ? 'border-blue-200 bg-blue-50' : 'border-gray-100 hover:border-gray-200 bg-white'
424+
}`}
425+
>
426+
<input
427+
type="checkbox"
428+
checked={checked}
429+
onChange={() => toggleCcSuggestion(suggestion.email)}
430+
className="h-4 w-4 rounded border-gray-300 text-blue-500 focus:ring-blue-300"
431+
/>
432+
<div className="min-w-0">
433+
<p className="text-sm text-zinc-700 truncate">{suggestion.name}</p>
434+
<p className="text-xs text-zinc-400 truncate">{suggestion.email}</p>
435+
</div>
436+
</label>
437+
)
438+
})}
439+
</div>
440+
)}
396441
</div>
397442

398443
{/* Footer buttons */}

0 commit comments

Comments
 (0)