Skip to content

Copy a milestone, on its own or with its tasks - #564

Merged
doomlab merged 2 commits into
fix/server-side-notification-checksfrom
feat/533-copy-milestone
Oct 9, 2026
Merged

doomlab merged 2 commits into
fix/server-side-notification-checksfrom
feat/533-copy-milestone

Conversation

@doomlab

@doomlab doomlab commented Oct 9, 2026

Copy link
Copy Markdown
Member

Closes #533

Stacked on #563 (the combined server-side access checks), because the new endpoint uses its requireManagerOf helper. Merge #563 into dev first; this will then retarget to dev (retarget it by hand if it doesn't). Do not merge this into fix/server-side-notification-checks and consider it done: it would not reach dev.

What

A Copy Milestone button on the milestone page (project managers only, like Edit and Delete). It opens a dialog with the choice:

  • Copy milestone only: a new milestone, <name> (Copy), with the same description, tags and dates. Its tasks stay with the original, because a task can belong to only one milestone ("Update Tasks" moves them).
  • Copy milestone and N tasks: also copies the milestone's tasks as new tasks under the copy (disabled when it has none).
  • Cancel.

Either way you land on the new milestone, ready to rename.

How copied tasks behave

Same as when a whole project is copied: new tasks with the same name, description, dates, tags, form, roles, column and settings, placed at the end of their column, back to "not completed", created by the person copying. Nobody is assigned, and no logs, responses, comments or notifications are copied, so a copy never carries someone else's progress. Tasks keep their original names (they sit under the copied milestone), so on the board they look like the originals until renamed. The whole copy happens in one database transaction, so a failure part-way doesn't leave a half-copied milestone.

Access

copyMilestone requires the caller to be a project manager of the milestone's project, with or without tasks. It is in the shared "refuses outsiders and plain contributors" test.

Testing

  • copyMilestone.test.ts (5): milestone-only copies details and touches no tasks; with tasks each task is copied unassigned, reset, under the copy and at the end of its column (ordering checked across two columns); empty fields and no tasks; stops without copying tasks if the caller has no member row; non-managers refused both ways.
  • CopyMilestoneButton.test.tsx (7): the dialog, each choice calls the right option and opens the copy, singular/plural label, disabled with no tasks, cancel, failure stays on the page.
  • Added to mutationAccess.test.ts (both variants refused for an outsider and a contributor).
  • Typecheck (apart from the existing getJsonSchema.test.ts errors), lint and the full suite (292 tests, run twice) pass.
  • Not yet checked in a browser: please copy a milestone both ways and look at the copied tasks on the board and in the milestone.

🤖 Generated with Claude Code

doomlab and others added 2 commits October 9, 2026 02:12
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@doomlab
doomlab merged commit 654961a into fix/server-side-notification-checks Oct 9, 2026
1 check passed
doomlab added a commit that referenced this pull request Oct 9, 2026
…n-checks

Copy a milestone, on its own or with its tasks (gets #564 onto dev)
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