Skip to content

feat: duplicate codeplug entities (channel, zone, talk group, RX group list, contact) #179

Description

@pskillen

Problem / outcome

Operators often want a near-copy of an existing entity — e.g. a second channel with one field changed, a zone template with the same member order, or a talk group with the same DMR ID on a different slot. Today every entity must be recreated manually in CRUD.

Add a Duplicate action on each base codeplug entity detail page (and optionally list row actions) that creates a new entity from the source record.

In scope: entities on Codeplugchannel, zone, talk group, RX group list, contact.

Out of scope: duplicating a whole codeplug project (#31).

Behaviour

Shallow copy (default)

  • Assign a new UUID id.
  • Copy all scalar / nested fields from the source.
  • Disambiguate name so validation passes (shared TG/contact namespace, zone/channel name uniqueness). Suggested default: append (copy) or (2), (3), … until unique.
  • Preserve FK refs to other entities unchanged:
    • Channel → contactRef, rxGroupListId
    • Zone → same memberChannelIds / member entries (still pointing at the original channels)
    • RX group list → same memberRefs (talk groups / contacts)
  • Clear or strip import/provenance fields that identify a specific remote listing (meta.repeaterDirectory, wire-only provenance) so the copy is clearly operator-authored; keep benign operator metadata if any.
  • After duplicate: navigate to the new entity’s edit or detail page.

UX

  • Detail page header: Duplicate beside Edit / Delete (match existing action placement).
  • Optional follow-up: list-row duplicate — only if it does not clutter tables; detail action is the MVP.
  • Confirm when duplicating would create a name collision that cannot be auto-resolved (should be rare if suffix logic is solid).

Implementation notes

Area Location
Mutations src/lib/codeplugMutations.tsduplicateChannel, duplicateZone, … (thin wrappers over existing add* + field copy)
Name uniquification Reuse validation helpers / shared uniqueName utility; respect TG+contact shared namespace
Store codeplugStore expose duplicate* actions
UI src/routes/channels/detail.tsx, zones/detail.tsx, talk-groups/detail.tsx, rx-group-lists/detail.tsx, contacts/detail.tsx
Tests Mutation unit tests per entity; one smoke test that zone duplicate keeps member channel ids

Vendor boundaries

Internal model only — no radio caps, no export wire names beyond what the entity already carries. Duplication does not belong in import/export adapters.

Acceptance criteria

  • Each of the five entity types has a working Duplicate action.
  • New record gets a new id and a unique name.
  • FK refs behave as shallow copy (zone members still reference original channels).
  • Validation passes on the duplicated record without manual edits.
  • npm run test covers mutation behaviour.

Relates to

  • #11 / #12 / #13 — CRUD foundation
  • #31 — duplicate project (separate concern)

Workflow note

Branch from origin/main, atomic conventional commits per entity or per layer (mutations → store → UI), PR linking Closes #N.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions