-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: add optional editable task titles #8689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Review Complete ✅Re-reviewed the 6 new commits since the last review. After examining the implementation, tests, and integration points, I found no issues that require changes. SummaryThis PR successfully implements editable task titles with:
The implementation is production-ready and can be merged. Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
…ow render without font-semibold
89c105b to
9765932
Compare
|
Rebased |
heyseth
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Executive Summary
This PR introduces editable task titles as a user-facing feature, allowing users to label active work, persist those titles into task history, and search them.
The implementation is well-architected and demonstrates strong attention to detail. The code quality is high, with proper separation of concerns, comprehensive i18n support, and excellent test coverage.
Strengths
- ✅ Architecture: Clean separation between backend persistence and frontend state.
- ✅ Quality Assurance: Comprehensive test coverage across UI components, search hooks, and backend logic.
- ✅ UX/UI: Thoughtful implementation with inline editing, keyboard shortcuts, and full internationalization support.
- ✅ State Management: Proper handling of merge semantics for history updates.
Suggested Enhancements (Code Included)
I’ve included a few specific code suggestions inline to help handle edge cases and polish the UI behavior:
1. Defense-in-Depth for Long Titles
I noticed that extremely long titles could break the visual layout of the sidebar. I've added a two-pronged fix:
- CSS: Added
block truncateclasses to ensure the UI handles overflow gracefully on small screens. - Schema: Added a Zod limit to ensure data consistency at the source.
2. Robust Input Sanitization
Since titles might come from copy-pasted text or LLM outputs (in future updates), trim() might not be enough. I provided a stricter sanitizer snippet that:
- Strips invisible control characters (safety for JSON/Logging).
- Collapses newlines and multiple spaces (keeps the history list clean).
- Enforces a hard character limit with a warning log.
3. Visual Polish
I suggested a small tweak to the CSS to match the hover behavior described in the PR (hiding the edit pencil by default and only showing it on hover).
Conclusion
The core implementation is solid and ready for production! Once those edge cases are patched up, this is a great addition. Great work!
|
|
||
| if (currentTitle.length > 0) { | ||
| return ( | ||
| <span className="truncate text-base" data-testid="task-title-text"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| <span className="truncate text-base" data-testid="task-title-text"> | |
| <span className="block truncate text-base" data-testid="task-title-text"> |
This handles the visual overflow of task titles we discussed. Adding block ensures the text cuts off with an ellipsis if it gets too long for the sidebar.
|
|
||
| if (currentTitle.length > 0) { | ||
| return ( | ||
| <span className="text-base" data-testid="task-title-text"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| <span className="text-base" data-testid="task-title-text"> | |
| <span className="block truncate text-base" data-testid="task-title-text"> |
This handles the visual overflow of task titles we discussed. Adding block truncate ensures the text cuts off with an ellipsis if it gets too long for the sidebar.
| parentTaskId: z.string().optional(), | ||
| number: z.number(), | ||
| ts: z.number(), | ||
| title: z.string().optional(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Defense-in-Depth for Long Titles
I noticed that extremely long titles can visually overlap the edit button in the history sidebar (see screenshot). I recommend a two-pronged approach to handle this:
1. Data Integrity
We can enforce a hard limit here to prevent edge cases or massive strings.
| title: z.string().optional(), | |
| title: z.string().max(255).optional(), |
2. CSS truncation
Add the block truncate classes to both title spans. This ensures that the titles properly truncate with an ellipsis (...) when they get too long. (see suggestions for TaskHeader.tsx)
| const trimmedTitle = rawTitle.trim() | ||
| const normalizedTitle = trimmedTitle.length > 0 ? trimmedTitle : undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While .trim() handles the basics, we should probably be a bit more defensive here since this title might come from copy-pasted text.
I’ve drafted a stricter sanitizer that adds three layers of safety:
- Strip Control Characters: Removes invisible chars (like
\x00) that can cause issues in JSON serialization or logs. - Normalize Whitespace: Collapses multiple spaces and newlines into a single space. This keeps the history sidebar clean even if the user pastes a paragraph with line breaks.
- Graceful Truncation: Enforces the 255-char limit with a warning log, so we never accidentally store a massive string.
This ensures that normalizedTitle is always display-ready before it hits our state.
| const trimmedTitle = rawTitle.trim() | |
| const normalizedTitle = trimmedTitle.length > 0 ? trimmedTitle : undefined | |
| const MAX_TITLE_LENGTH = 255 | |
| // Sanitize: remove control characters and normalize whitespace | |
| const sanitized = rawTitle | |
| // eslint-disable-next-line no-control-regex | |
| .replace(/[\x00-\x1F\x7F-\x9F]/g, "") // Remove control characters | |
| .replace(/\s+/g, " ") // Normalize whitespace | |
| .trim() | |
| // Truncate if too long, or clear if empty | |
| let normalizedTitle: string | undefined | |
| if (sanitized.length === 0) { | |
| normalizedTitle = undefined // Clear empty titles | |
| } else if (sanitized.length > MAX_TITLE_LENGTH) { | |
| normalizedTitle = sanitized.slice(0, MAX_TITLE_LENGTH).trim() // Truncate and trim | |
| console.warn( | |
| `[setTaskTitle] Title truncated from ${sanitized.length} to ${MAX_TITLE_LENGTH} chars for task(s): ${ids.join(", ")}`, | |
| ) | |
| } else { | |
| normalizedTitle = sanitized // Use as-is | |
| } |
| }} | ||
| aria-label={t(tooltipKey)} | ||
| data-testid="task-title-edit-button"> | ||
| <Pencil size={16} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a suggestion to fix the hover behavior so it matches the PR description (hiding the pencil by default and displaying on hover).
| <Pencil size={16} /> | |
| <Pencil size={16} className="opacity-0 group-hover:opacity-100" /> |
Before:
before.mp4
After:
Related GitHub Issue
Closes: #8366
Description
This feature introduces editable titles for tasks, allowing users to label active work, persist those titles into task history, and search them—while providing a settings toggle and aligning the visual treatment across the UI.
Server↔️ Webview plumbing
HistoryItemwithtitleand updateClineProvider.updateTaskHistoryto merge partial updates so existing titles survive incremental syncs; explicitly allowundefinedto clear a title.setTaskTitlebranch inwebviewMessageHandlerthat normalizes/dedupes task IDs, trims/sanitizes the incoming title, skips no-op updates, persists viaupdateTaskHistory, and re-syncs the webview state.taskTitlesEnabledflag through extension messages/state and surface it to the webview context so both chat and history components react to the toggle.Webview UI
TaskHeader.tsx): introduce an inline editing experience (VS Code styled input, focus/keyboard handling, hover pencil) gated by the feature flag; when a title exists, display the text with standard weight instead of bolding.TaskItem.tsx): prefer titles when enabled, apply shared truncation/highlight behaviour, and render HTML highlights without the previousfont-semiboldclass so edited titles visually match default entries.useTaskSearch.ts): augment FZF selector to search titles + task prompts, split highlight ranges between title/task, and retain results ordering across sort modes.Settings & Telemetry
UISettingsthat toggles the new flag and emitsui_settings_task_titles_enabled_changed.Tests & Localization
Test Procedure
pnpm vitest webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsxpnpm vitest webview-ui/src/components/history/__tests__/TaskItem.spec.tsxpnpm vitest webview-ui/src/components/history/__tests__/useTaskSearch.spec.tsxScreenshots / Videos
Documentation Updates
Important
Introduces editable task titles feature with UI support and settings toggle, including backend logic and tests.
taskTitlesEnabledflag inglobal-settings.tsandhistory.ts.ClineProviderto handle task title updates and sync with webview.setTaskTitleandsetTaskTitlesEnabledmessage types inwebviewMessageHandler.TaskHeader.tsx: Implements inline editing for task titles with a pencil icon, focus handling, and keyboard shortcuts.TaskItem.tsx: Displays task titles if enabled, with fallback to task text.UISettings.tsx: Adds checkbox to toggle task titles feature.TaskHeader.spec.tsx,TaskItem.spec.tsx, anduseTaskSearch.spec.tsxto cover new title editing and display logic.chat.jsonandsettings.json.This description was created by
for abf7eca. You can customize this summary. It will automatically update as commits are pushed.