Skip to content

Commit f54777b

Browse files
committed
refactor(templates): simplify apply flow to chip-only
Remove the intermediate "describe your data" popup from the template drawer. Clicking Apply now sets the chip in the chat input and closes the drawer immediately, letting the user type naturally.
1 parent 5dd6191 commit f54777b

1 file changed

Lines changed: 10 additions & 115 deletions

File tree

  • apps/app/src/components/template-library

apps/app/src/components/template-library/index.tsx

Lines changed: 10 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,8 @@
11
"use client";
22

3-
import { useState, useCallback } from "react";
43
import { useAgent } from "@copilotkit/react-core/v2";
54
import { TemplateCard } from "./template-card";
65

7-
/** Submit a message through the CopilotChat textarea so it goes through the full rendering pipeline */
8-
function submitChatPrompt(text: string) {
9-
const textarea = document.querySelector<HTMLTextAreaElement>(
10-
'[data-testid="copilot-chat-textarea"]'
11-
);
12-
if (!textarea) {
13-
console.warn("submitChatPrompt: CopilotChat textarea not found — template apply message was not sent.");
14-
return;
15-
}
16-
17-
const setter = Object.getOwnPropertyDescriptor(
18-
window.HTMLTextAreaElement.prototype, "value"
19-
)?.set;
20-
setter?.call(textarea, text);
21-
textarea.dispatchEvent(new Event("input", { bubbles: true }));
22-
23-
setTimeout(() => {
24-
const form = textarea.closest("form");
25-
if (form) form.requestSubmit();
26-
}, 150);
27-
}
28-
296
interface TemplateLibraryProps {
307
open: boolean;
318
onClose: () => void;
@@ -46,41 +23,24 @@ export function TemplateLibrary({ open, onClose }: TemplateLibraryProps) {
4623
const { agent } = useAgent();
4724
const templates: Template[] = agent.state?.templates || [];
4825

49-
// Apply flow: show input for new data before sending
50-
const [applyingTemplate, setApplyingTemplate] = useState<Template | null>(null);
51-
const [applyData, setApplyData] = useState("");
52-
5326
const handleApplyClick = (id: string) => {
5427
const template = templates.find((t) => t.id === id);
55-
if (template) {
56-
setApplyingTemplate(template);
57-
setApplyData("");
58-
}
59-
};
60-
61-
const handleApplyConfirm = useCallback(() => {
62-
if (!applyingTemplate) return;
63-
const dataDesc = applyData.trim();
64-
if (!dataDesc) return;
28+
if (!template) return;
6529

66-
// Set pending_template in agent state so the agent knows which template to apply.
67-
// Spread full state to guard against replace-style setState.
30+
// Attach template as a chip in the chat input — user types their prompt naturally
6831
agent.setState({
6932
...agent.state,
70-
pending_template: { id: applyingTemplate.id, name: applyingTemplate.name },
33+
pending_template: { id: template.id, name: template.name },
7134
});
72-
73-
// Send only the user's data description — no template ID in the message
74-
submitChatPrompt(dataDesc);
75-
76-
setApplyingTemplate(null);
77-
setApplyData("");
7835
onClose();
79-
}, [agent, applyingTemplate, applyData, onClose]);
8036

81-
const handleApplyCancel = () => {
82-
setApplyingTemplate(null);
83-
setApplyData("");
37+
// Focus the chat textarea so user can start typing immediately
38+
setTimeout(() => {
39+
const textarea = document.querySelector<HTMLTextAreaElement>(
40+
'[data-testid="copilot-chat-textarea"]'
41+
);
42+
textarea?.focus();
43+
}, 100);
8444
};
8545

8646
const handleDelete = (id: string) => {
@@ -193,71 +153,6 @@ export function TemplateLibrary({ open, onClose }: TemplateLibraryProps) {
193153
)}
194154
</div>
195155

196-
{/* Apply data input — slides up from bottom of drawer */}
197-
{applyingTemplate && (
198-
<div
199-
className="shrink-0 px-4 pb-4 pt-3"
200-
style={{
201-
borderTop: "1px solid var(--color-border-glass, rgba(0,0,0,0.1))",
202-
animation: "tmpl-slideIn 0.2s ease-out",
203-
}}
204-
>
205-
<p
206-
className="text-xs font-semibold mb-1"
207-
style={{ color: "var(--text-primary, #1a1a1a)" }}
208-
>
209-
Apply &quot;{applyingTemplate.name}&quot;
210-
</p>
211-
<p
212-
className="text-[11px] mb-2"
213-
style={{ color: "var(--text-tertiary, #999)" }}
214-
>
215-
Describe the new data you want to populate this template with:
216-
</p>
217-
<textarea
218-
value={applyData}
219-
onChange={(e) => setApplyData(e.target.value)}
220-
onKeyDown={(e) => {
221-
if (e.key === "Enter" && !e.shiftKey) {
222-
e.preventDefault();
223-
handleApplyConfirm();
224-
}
225-
if (e.key === "Escape") handleApplyCancel();
226-
}}
227-
autoFocus
228-
placeholder='e.g. "$2,400 web design project for Sarah Chen, due April 15"'
229-
rows={2}
230-
className="w-full text-xs px-3 py-2 rounded-lg outline-none resize-none"
231-
style={{
232-
background: "var(--color-background-secondary, #f5f5f5)",
233-
color: "var(--text-primary, #1a1a1a)",
234-
border: "1px solid var(--color-border-tertiary, rgba(0,0,0,0.1))",
235-
}}
236-
/>
237-
<div className="flex gap-2 mt-2">
238-
<button
239-
onClick={handleApplyConfirm}
240-
disabled={!applyData.trim()}
241-
className="flex-1 text-xs font-medium py-1.5 rounded-lg text-white transition-all duration-150 disabled:opacity-40"
242-
style={{
243-
background: "linear-gradient(135deg, var(--color-lilac-dark, #6366f1), var(--color-mint-dark, #10b981))",
244-
}}
245-
>
246-
Apply Template
247-
</button>
248-
<button
249-
onClick={handleApplyCancel}
250-
className="text-xs px-3 py-1.5 rounded-lg"
251-
style={{
252-
border: "1px solid var(--color-border-tertiary, rgba(0,0,0,0.1))",
253-
color: "var(--text-secondary, #666)",
254-
}}
255-
>
256-
Cancel
257-
</button>
258-
</div>
259-
</div>
260-
)}
261156
</div>
262157
</>
263158
);

0 commit comments

Comments
 (0)