Skip to content

feat(tracker): copy issue templates to another project - #11146

Open
MichaelUray wants to merge 10 commits into
hcengineering:developfrom
MichaelUray:feat/issue-template-copy-project
Open

MichaelUray wants to merge 10 commits into
hcengineering:developfrom
MichaelUray:feat/issue-template-copy-project

Conversation

@MichaelUray

@MichaelUray MichaelUray commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #5892

I added “Copy to project…” for issue templates so I can reuse a template and its children in another project without recreating them by hand.

  • I can open it from an open template’s “...” menu, a list context menu, or Cmd/Ctrl+K, with one or several templates selected. The action uses input: 'any' to accept both a plain template document and the full selection. It is unavailable for issues.
  • One dialog lists every selected template. No target is preselected; the picker offers active projects I belong to, excluding every selected template’s source project.
  • On Copy, submitIssueTemplateCopy rechecks target eligibility and reads the target project type’s task types once for the batch. It creates each selected template separately, with its children embedded and fresh child IDs. This is not an atomic batch; target eligibility is checked before writes, not atomically with them.

I preserve the title, description, priority, assignee, estimation, labels, and child templates. I clear components and milestones because they belong to the source project, and retain a task kind only if the target project type provides it. I do not copy comments or attachments; their counters start at zero. Parent mixin/custom attribute data is not copied.

I preserve assignees on both parent and child templates, including non-members, matching the template editor. Copying does not change project membership or grant access. An unassigned parent stays unassigned, allowing the target project’s default assignee to apply when an issue is created. The existing public-project collaborator rule can add a non-member assignee to the project when an issue is subsequently created; that rule does not apply to private projects.

I also preserve relations to the same documents, including documents in the source project. Template relations are one-sided references: CreateIssueTemplate writes the template’s relations, and RelatedIssueTemplates finds the reverse view by querying that array. Preserving those references lets the copy appear in the existing related-template view without updating the related document. This differs from issue-to-issue relation editing, which explicitly updates both sides for symmetric relations.

I handle copy failures in the dialog’s submission helper:

  • An unavailable target clears the selection and shows a localized message in the dialog. I can select an eligible project and retry.
  • Lookup failures report every pending template; individual write failures report only the failed templates. The dialog reports errors through Analytics.handleError and shows a localized error notification using SimpleNotification, with the failed template titles.
  • The helper remembers successful copies per target for the lifetime of the dialog. Retry submits only the missing templates, including after switching away from a target and back. It blocks overlapping submissions.
  • Changing the target during a pending operation does not cancel its writes. A result for the old target cannot clear the newer selection or close its dialog; failures still produce feedback.
  • A throwing or rejected failure-feedback callback is caught so the save promise resolves and Copy becomes usable again. The dialog stays open and retains successful-copy tracking, although failed feedback itself may not display a notification.

I limited the shared Card change to closeOnSave, defaulting to true. After a synchronous okAction returns normally, or its returned Promise resolves, Card clears okProcessing and dispatches close only when this option is true. The copy dialog sets it to false and closes itself only after all selected templates have copied successfully to the currently selected target. Explicit Close still works. I removed the earlier shared catch/analytics/reset handling: Card retains upstream behavior for throwing or rejected actions, including leaving okProcessing set on failure. Existing callers keep their previous behavior.

I added the three copy-related strings to all 14 tracker locales. I removed the extra jsdom Jest project, custom Svelte transform, component fixtures, and jest-environment-jsdom dependency introduced in the earlier version. The existing Node/ts-jest configuration remains, with no added dependencies.

I kept five focused Node suites, totaling 34 tests:

  • actions.test.ts: production action registration and filtering for a plain template, one or two selected templates, and issue exclusion.
  • copy.test.ts and issue-template-copy.test.ts: copied/cleared fields, compatible task kinds, fresh child IDs, independent arrays, preserved relations, and parent/child assignees.
  • submitCopy.test.ts: target validation, shared lookups, copying both templates and their children, independent write failures, and lookup recovery.
  • copySubmission.test.ts: target changes during pending work, invalidation/recovery, failure feedback, overlapping submissions, retry without repeating successful copies, and throwing/rejected feedback callbacks.

On 992b51c65f, install, build, validate, svelte-check, formatting and the tests pass locally. Browser checks passed 16/16 in each of Chromium, Firefox, and WebKit. I checked the open-template panel menu, list context menus and Cmd/Ctrl+K with one and two selected templates, both templates copied exactly once, and issue exclusion. Archiving the selected target kept the dialog usable; after restoring and reselecting it, retry created both missing copies exactly once. The original parent/child assignee, issue creation, membership, visibility, and private-project access checks also passed.

I confirmed the panel-menu regression check fails as expected on fe515cff1b, where the action uses input: 'selection'. The browser recovery check covers target rejection before writes; partial-write retry and throwing/rejected feedback are covered by the Node tests, not by browser fault injection.

Issue templates are stored in a single project and the only action available on them was Edit, so a template had to be recreated by hand for every new project.

Add a "Copy to project…" action for issue templates. It opens a popup with the existing project selector (excluding the template's own project) and creates a copy of the template in the chosen project, including its child templates, description, priority, assignee, labels and estimation. Component and milestone belong to the source project and are cleared; a task type is kept only when the target project type provides it. Child templates get fresh ids; comments and attachments are not copied. The data mapping lives in a small pure helper covered by unit tests.

Fixes hcengineering#5892

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
@MichaelUray
MichaelUray force-pushed the feat/issue-template-copy-project branch from 8e6d455 to 939307f Compare October 19, 2026 06:42
@ArtyomSavchenko

Copy link
Copy Markdown
Member

@MichaelUray The data mapping and the unit tests look good.

Question: the assignee is copied as is, but they may not be a member of the target project. Should it be cleared in that case, or is it intentional to keep it?

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…copy error

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Limit the shared Card change to what the template copy dialog needs
(closeOnSave and resetting the spinner after a failed action). The
translated Close tooltip and native Enter activation on buttons affect
every dialog and are dropped from this change, together with their tests
and fixtures.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
@MichaelUray

Copy link
Copy Markdown
Contributor Author

Thanks for the review!

  1. Keeping the assignee is intentional. The template editor already lets you assign employees who are not members of the project, so clearing them on copy would drop assignments the editor allows. Copying the template itself does not add anyone to the target project or grant access (one caveat: in a public project, creating an issue from it assigned to a non-member makes that person a project member through the existing rule that adds collaborators of public-space documents as members; that happens for any issue assigned to a non-member, private projects are unaffected), and an unassigned template stays unassigned, so the target project's default assignee still applies when an issue is created from it. This is covered by preserves parent and child assignees when copying to another project and keeps unassigned templates and children unassigned in plugins/tracker-resources/src/__tests__/issue-template-copy.test.ts.

Also changed: submitting rechecks that the target project is still active and that you are a member, and errors stay in the dialog so you can retry. To support this, the shared Card gets a closeOnSave option (default true) and resets its spinner after a failed action instead of staying stuck (submitCopy.test.ts, copy-dialog.test.ts).

Verification (head fe1d1f7): local CI is green (install, build, validate, svelte-check, format, unit tests including the four template-copy suites, bundle). Browser checks on a local stack pass 10/10 in Chromium, Firefox and WebKit: for a target project where the assignee is a member, a public project where they are not, a private project where they are not, and an unassigned template, the copied parent/child templates keep their assignees after reopening, issues created from the copy carry them, copying leaves the target's member list unchanged, and in the private project the non-member can neither see the project nor open the issues.

@ArtyomSavchenko

Copy link
Copy Markdown
Member

@MichaelUray Please take a look at the following review comments:

  1. Multi-select silently copies only the first template. The action is enabled in browser mode, but copyIssueTemplateToProject takes template[0] and drops the rest. Either restrict the action to a single selection or copy all selected templates.
  2. relations are copied as-is. The copy keeps links to whatever the source template was related to (usually objects in the source project). The doc comment says this is intentional; worth confirming that’s the desired behavior and that relations aren’t stored bidirectionally (otherwise the far side won’t know about the copy).
  3. Card now swallows errors. Failures go only to Analytics.handleError — the global unhandledrejection hook is analytics-only too, so nothing user-visible changes vs today. Other dialogs will just stay open with no message. Fine, but worth saying in the PR description since it’s a shared component.
  4. Test infrastructure is heavy for the feature. There’s a second jest project with jsdom, a custom Svelte/TS transform, and ~10 fixture modules that stub ui, presentation, core and tracker (and map @hcengineering/view to the tracker fixture). It works and the race tests are valuable, but maintainers may prefer keeping only the pure-function and submitCopy tests over a bespoke component-test harness in one plugin.

…ify the tests

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
… the dialog usable when failure feedback throws

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
@MichaelUray

Copy link
Copy Markdown
Contributor Author

@ArtyomSavchenko I addressed all four points:

  1. I now copy the full selection in one dialog. The action uses input: 'any', so it also works from an open template’s plain-document panel menu. Each template and its children are copied separately; retry skips successful copies per target within the dialog. I added action-filtering and batch/retry tests, and checked the panel menu, list context menu, and Cmd/Ctrl+K with one and two selected templates in all three browsers.

  2. I confirmed template relations are one-sided references. CreateIssueTemplate writes only the template’s relations; RelatedIssueTemplates queries that array for the reverse view. I kept the original references intentionally, so copies remain related to the same documents without a far-side write, and documented this in the helper and PR description. Tests cover preserved values and an independent relation array.

  3. I removed the shared Card error-catching change. Its only change from upstream is closeOnSave, default true, which gates automatic closing after a normally returning/resolved action. Error behavior for existing callers remains unchanged. The copy dialog opts out of automatic closing and handles lookup/write errors itself, with analytics and a localized notification naming failed templates. It stays open for retry. I also catch throwing/rejected feedback callbacks locally so they cannot leave Copy stuck, and added tests for both cases. The description now explains this behavior.

  4. I removed the second Jest project, jsdom dependency, custom Svelte transform, and component fixtures. I kept the existing Node/ts-jest setup and test the submission races through the production helper. There are five focused suites with 34 tests and no added dependencies.

On 992b51c65f, install, build, validate, svelte-check, formatting and the tests pass locally, and the browser checks pass 16/16 in each of Chromium, Firefox, and WebKit, including the original assignee/parent-child/access checks and archived-target recovery. The panel-menu check fails as expected on fe515cff1b with input: 'selection'. Partial-write retry and feedback failures are covered by Node tests; the browser recovery check rejects the target before writes.

Could you approve the workflow run for this push?

This branch has not been deployed

No deployments
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.

Feature request: Copying template from a project to another project

2 participants