Feat: Add ability to duplicate a feature and duplicate as a child#774
Feat: Add ability to duplicate a feature and duplicate as a child#774gsxdsm wants to merge 1 commit intoAutoMaker-Org:v0.15.0rcfrom
Conversation
Summary of ChangesHello @gsxdsm, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enhances the application by introducing robust feature duplication capabilities. Users can now create copies of existing features, either as independent entities or as child features that maintain a dependency on their parent. This addresses a previous limitation where duplicate feature names could cause issues during conflict resolution. The backend has been streamlined by removing redundant duplicate title validation, while the frontend provides intuitive access to these new duplication options across various board views. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
📝 WalkthroughWalkthroughThe PR removes duplicate title validation from the backend feature creation and update endpoints, then adds comprehensive UI support for duplicating features either as siblings or as children within the board view, kanban cards, and list views. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces the ability to duplicate features, either as a standalone copy or as a child of the original feature. This is achieved by removing the backend validation that prevented duplicate feature titles and adding the necessary UI elements and logic on the frontend. The core logic for duplication in use-board-actions.ts is well-implemented.
My main feedback is regarding the UI implementation in kanban-card/card-header.tsx and list-view/row-actions.tsx. In both files, the menu for duplicating features has been added in multiple places, leading to significant code duplication. I've left specific comments suggesting how to refactor this by creating a reusable component within each file to improve maintainability.
| {onDuplicate && ( | ||
| <DropdownMenuSub> | ||
| <div className="flex items-center"> | ||
| <DropdownMenuItem | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| onDuplicate(); | ||
| }} | ||
| className="text-xs flex-1 pr-0 rounded-r-none" | ||
| > | ||
| <Copy className="w-3 h-3 mr-2" /> | ||
| Duplicate | ||
| </DropdownMenuItem> | ||
| {onDuplicateAsChild && ( | ||
| <DropdownMenuSubTrigger className="text-xs px-1 rounded-l-none border-l border-border/30 h-8" /> | ||
| )} | ||
| </div> | ||
| {onDuplicateAsChild && ( | ||
| <DropdownMenuSubContent> | ||
| <DropdownMenuItem | ||
| onClick={(e) => { | ||
| e.stopPropagation(); | ||
| onDuplicateAsChild(); | ||
| }} | ||
| className="text-xs" | ||
| > | ||
| <GitFork className="w-3 h-3 mr-2" /> | ||
| Duplicate as Child | ||
| </DropdownMenuItem> | ||
| </DropdownMenuSubContent> | ||
| )} | ||
| </DropdownMenuSub> | ||
| )} |
There was a problem hiding this comment.
There's significant code duplication for the 'Duplicate' feature menu. This same block of JSX is repeated four times in this file for different feature statuses (running, backlog, waiting/verified, and in-progress).
To improve maintainability and reduce redundancy, I suggest extracting this logic into a dedicated component within this file.
Here's an example of what that component could look like:
const DuplicateFeatureSubMenu = ({
onDuplicate,
onDuplicateAsChild,
}: {
onDuplicate?: () => void;
onDuplicateAsChild?: () => void;
}) => {
if (!onDuplicate) {
return null;
}
return (
<DropdownMenuSub>
<div className="flex items-center">
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation();
onDuplicate();
}}
className="text-xs flex-1 pr-0 rounded-r-none"
>
<Copy className="w-3 h-3 mr-2" />
Duplicate
</DropdownMenuItem>
{onDuplicateAsChild && (
<DropdownMenuSubTrigger className="text-xs px-1 rounded-l-none border-l border-border/30 h-8" />
)}
</div>
{onDuplicateAsChild && (
<DropdownMenuSubContent>
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation();
onDuplicateAsChild();
}}
className="text-xs"
>
<GitFork className="w-3 h-3 mr-2" />
Duplicate as Child
</DropdownMenuItem>
</DropdownMenuSubContent>
)}
</DropdownMenuSub>
);
};You could then replace each duplicated block with:
<DuplicateFeatureSubMenu onDuplicate={onDuplicate} onDuplicateAsChild={onDuplicateAsChild} />| {handlers.onDuplicate && ( | ||
| <DropdownMenuSub> | ||
| <div className="flex items-center"> | ||
| <DropdownMenuItem | ||
| onClick={withClose(handlers.onDuplicate)} | ||
| className="flex-1 pr-0 rounded-r-none" | ||
| > | ||
| <Copy className="w-4 h-4 mr-2" /> | ||
| Duplicate | ||
| </DropdownMenuItem> | ||
| {handlers.onDuplicateAsChild && ( | ||
| <DropdownMenuSubTrigger className="px-1 rounded-l-none border-l border-border/30 h-8" /> | ||
| )} | ||
| </div> | ||
| {handlers.onDuplicateAsChild && ( | ||
| <DropdownMenuSubContent> | ||
| <MenuItem | ||
| icon={GitFork} | ||
| label="Duplicate as Child" | ||
| onClick={withClose(handlers.onDuplicateAsChild)} | ||
| /> | ||
| </DropdownMenuSubContent> | ||
| )} | ||
| </DropdownMenuSub> | ||
| )} |
There was a problem hiding this comment.
Similar to the changes in kanban-card/card-header.tsx, the JSX for the 'Duplicate' feature menu is duplicated multiple times in this file (five times, to be exact). This makes the component harder to read and maintain.
I recommend refactoring this into a reusable component within this file. This will make the code cleaner and easier to manage if the duplicate menu ever needs to be changed.
Here's a possible implementation for the component:
const DuplicateFeatureSubMenu = ({
handlers,
withClose,
}: {
handlers: { onDuplicate?: () => void; onDuplicateAsChild?: () => void };
withClose: (handler: () => void) => () => void;
}) => {
if (!handlers.onDuplicate) {
return null;
}
return (
<DropdownMenuSub>
<div className="flex items-center">
<DropdownMenuItem
onClick={withClose(handlers.onDuplicate)}
className="flex-1 pr-0 rounded-r-none"
>
<Copy className="w-4 h-4 mr-2" />
Duplicate
</DropdownMenuItem>
{handlers.onDuplicateAsChild && (
<DropdownMenuSubTrigger className="px-1 rounded-l-none border-l border-border/30 h-8" />
)}
</div>
{handlers.onDuplicateAsChild && (
<DropdownMenuSubContent>
<MenuItem
icon={GitFork}
label="Duplicate as Child"
onClick={withClose(handlers.onDuplicateAsChild)}
/>
</DropdownMenuSubContent>
)}
</DropdownMenuSub>
);
};You can then use it like this in place of the repeated blocks:
<DuplicateFeatureSubMenu handlers={handlers} withClose={withClose} />There was a problem hiding this comment.
🧹 Nitpick comments (2)
apps/ui/src/components/views/board-view/hooks/use-board-actions.ts (1)
1086-1104: Consider stripping run‑state fields when duplicating a feature.Spreading the full
Featurecopies transient state (e.g.,planSpec,startedAt,error,summary,passes), which can make the duplicate look pre-run. If that’s not intended, omit those fields before callinghandleAddFeature.♻️ Suggested refinement
- const { id: _id, status: _status, ...featureData } = feature; + const { + id: _id, + status: _status, + startedAt: _startedAt, + justFinishedAt: _justFinishedAt, + planSpec: _planSpec, + error: _error, + summary: _summary, + passes: _passes, + titleGenerating: _titleGenerating, + descriptionHistory: _descriptionHistory, + ...featureData + } = feature;Also applies to: 1126-1126
apps/ui/src/components/views/board-view/components/list-view/row-actions.tsx (1)
414-437: Optional: extract the duplicate submenu to reduce repetition.The same
DropdownMenuSubblock is repeated across status branches; a small helper would cut maintenance overhead.Also applies to: 491-515, 562-586, 638-662, 690-714
Add ability to duplicate a feature. Fixes an issue where pull and resolve conflicts fails the second time because a duplicate feature name exists.
This feature is useful for running a feature through multiple times, trying different models or to ensure correctness. A duplicate can be created as a child such that the feature can be run in a loop in auto mode (Ralph style)
Summary by CodeRabbit