Skip to content

feat(bulk-duplicate): add "Create more" toggle to Deep Duplicate modal#50

Open
fathiraz wants to merge 5 commits into
mainfrom
feat/create-more-deep-duplicate
Open

feat(bulk-duplicate): add "Create more" toggle to Deep Duplicate modal#50
fathiraz wants to merge 5 commits into
mainfrom
feat/create-more-deep-duplicate

Conversation

@fathiraz

@fathiraz fathiraz commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add a Create more toggle beside the Deep Duplicate button — mirrors GitHub's "Create more" on the new-issue form: queue a copy without leaving the modal
  • Checked → queue the copy, reset the form to source defaults, keep the modal open to queue more copies of the same item; unchecked → close and hand off to the queue tracker
  • Drop the blocking await so the modal no longer stays frozen until every duplication finishes — the background worker runs each copy to completion regardless

Changes

Modal (src/features/bulk-duplicate-modal.tsx)

  • Extract applyPreviewDefaults() as the single source-defaults reset path, shared by the initial preview load and the Create-more re-arm
  • Add createMore state (unchecked, no persistence — resets each open)
  • Rewrite handleDuplicate to fire-and-forget the duplicateItem message; keep the 3-concurrent cap guard; checked re-arms the form, unchecked closes

Review step (src/features/bulk-duplicate-steps.tsx)

  • ReviewStep gains createMore / onToggleCreateMore props
  • Add a Primer Checkbox + label in the footer beside the Duplicate button (Primer + sx only, inside the existing Shadow DOM / ShadowThemeProvider tree)

Docs (CONTEXT.md)

  • Glossary of the domain terms (Deep Duplicate, Source item, Source defaults, Create more, Duplication queue, Queue tracker)

Stacked on the ponytail refactor cleanup (bulk-duplicate-steps.tsx extraction) already on this line — those commits are included in the diff against main.

Test Plan

  • Open Deep Duplicate on a project item; confirm a Create more checkbox sits beside the Duplicate button
  • With it checked, click Duplicate → form resets to <title> (copy) defaults, modal stays open, copy flies to the queue tracker; repeat to queue several
  • Queue 3 concurrent copies, then click a 4th → concurrent-limit Flash shows, form is kept, nothing enqueued
  • With it unchecked, click Duplicate → modal closes immediately, copy flies to the tracker, duplication completes in the background
  • Run pnpm typecheck && pnpm lint && pnpm test — 0 type errors, 0 lint errors, 415 tests pass

Summary by cubic

Add a Create more toggle to the Deep Duplicate modal so you can queue multiple copies without closing the modal. Duplication now runs in the background to keep the modal responsive, with progress handed off to the queue tracker.

  • New Features

    • Add Create more checkbox beside Duplicate. Checked queues the copy, resets to source defaults, and keeps the modal open; unchecked closes and hands off to the queue tracker.
    • Switch to fire-and-forget duplication; UI no longer waits. Keep the 3-concurrent cap with a warning on the 4th attempt.
    • Review step surfaces the Create more toggle. State is not persisted and resets each time the modal opens.
  • Refactors

    • Extract SelectSectionsStep and ReviewStep to src/features/bulk-duplicate-steps.tsx. Add applyPreviewDefaults() as the single reset path.
    • Split bulk-edit subcomponents into bulk-edit-value-picker.tsx and bulk-edit-field-row.tsx; move firstRepoNameFromDom to helpers. No behavior change.
    • Remove unused modal-factory, use-subscription-ref, and UI primitives (empty-state, progress-state, section-header) and related tests; prune orphaned imports.
    • Add targeted react-hooks/set-state-in-effect eslint-disable comments with reasons; dedupe sprint endDate mapping via a local withEndDate helper.

Written for commit c0deeb9. Summary will update on new commits.

Review in cubic

fathiraz added 4 commits July 3, 2026 02:55
- delete unused modal-factory + use-subscription-ref hooks and the unused
  progress-state / empty-state / section-header UI primitives (~560 LOC)
- add targeted eslint-disable + reason on legit external-sync effects
  (fetch / timer / reset-on-prop) flagged by react-hooks/set-state-in-effect
- dedupe the 3x iteration+endDate mapping in sprint-handlers via a local
  withEndDate helper
…siblings

Split bulk-edit-flyout.tsx (717 -> 440 LOC) by moving the presentational
sub-components into bulk-edit-value-picker.tsx and bulk-edit-field-row.tsx,
and the DOM helper firstRepoNameFromDom into bulk-edit-flyout-helpers.ts.
No behavior change; public component + props unchanged.
Move SelectSectionsStep and ReviewStep out of bulk-duplicate-modal.tsx
(1490 -> 1199 LOC) into bulk-duplicate-steps.tsx. No behavior change;
BulkDuplicateModal public API unchanged.
Remove the Primer components, icons, and helpers that are no longer
referenced in bulk-edit-flyout.tsx / bulk-duplicate-modal.tsx after their
sub-components moved to sibling modules.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor auto review

No actionable issues found on changed lines.

The Create more feature is well-structured, but rapid Duplicate clicks can bypass the 3-concurrent guard: queueStore.getActiveCount() is checked before the background worker registers the job, so extra requests are silently dropped after flyToTracker already ran.

Generated automatically when this PR was submitted using Cursor CLI with --model auto.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 27 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/features/bulk-duplicate-modal.tsx">

<violation number="1" location="src/features/bulk-duplicate-modal.tsx:399">
P2: Rapid repeated clicks with Create more can silently drop duplicate requests instead of showing the 3-concurrent warning. The modal now sends `duplicateItem` without awaiting, so local active-count checks can be stale before queue broadcasts land, while background rejects extra jobs without surfacing an error; consider adding an immediate local in-flight counter (or disabling button until first queue tick) to close this race.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

await sendMessage('duplicateItem', {
// Fire-and-forget: the duplication runs to completion in the background SW
// regardless of the modal's lifecycle; errors surface via the queue tracker.
void sendMessage('duplicateItem', {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Rapid repeated clicks with Create more can silently drop duplicate requests instead of showing the 3-concurrent warning. The modal now sends duplicateItem without awaiting, so local active-count checks can be stale before queue broadcasts land, while background rejects extra jobs without surfacing an error; consider adding an immediate local in-flight counter (or disabling button until first queue tick) to close this race.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/features/bulk-duplicate-modal.tsx, line 399:

<comment>Rapid repeated clicks with Create more can silently drop duplicate requests instead of showing the 3-concurrent warning. The modal now sends `duplicateItem` without awaiting, so local active-count checks can be stale before queue broadcasts land, while background rejects extra jobs without surfacing an error; consider adding an immediate local in-flight counter (or disabling button until first queue tick) to close this race.</comment>

<file context>
@@ -686,13 +394,23 @@ export function BulkDuplicateModal({
-    await sendMessage('duplicateItem', {
+    // Fire-and-forget: the duplication runs to completion in the background SW
+    // regardless of the modal's lifecycle; errors surface via the queue tracker.
+    void sendMessage('duplicateItem', {
       itemId: preview.resolvedItemId || itemId,
       projectId: preview.projectId || projectId,
</file context>

Mirror GitHub's new-issue "Create more": queue a copy without leaving the
modal. Checked keeps the modal open and resets edits to source defaults so
the user can queue another copy of the same item; unchecked closes and hands
off to the queue tracker.

Also drop the blocking await in handleDuplicate so the modal no longer stays
frozen until every duplication finishes — the background service worker runs
the copy to completion regardless, and errors surface via the queue tracker.

Extract applyPreviewDefaults() as the single source-defaults reset path,
shared by the initial preview load and the Create-more re-arm.
@fathiraz fathiraz force-pushed the feat/create-more-deep-duplicate branch from 95c28aa to c0deeb9 Compare July 3, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant