Skip to content

feat: optional target-radio validation hints in CRUD UI #86

Description

@pskillen

Problem

Radio-specific limits (max channels, zone member slots, channel name display length, feature availability) are intentionally kept off the internal model and enforced at the import/export boundary — see data-model, radio profiles, and the make-a-plan vendor-neutral rule.

That remains the direction of travel for hard enforcement. In practice, operators often target one or two known radios (e.g. Baofeng 1701 + OpenGD77) and only discover length/capacity problems at export time — frustrating when editing channels, zones, and TG lists in CRUD.

We need optional, non-blocking validation hints in the UI, driven by radios the operator selects for the project.

Intended outcome

Let operators select one or more target radio profiles on a codeplug project. Those profiles drive warning-level validation hints across edit forms, detail pages, and list views — without preventing save or mutating the internal model.

Design principles

Layer Role
Internal model + CRUD validation Vendor-neutral; errors only (required fields, duplicate names, FK integrity, parse failures) — unchanged
Import/export adapters Hard limits — truncate, reject, or warn in export report — unchanged
Radio hint validation (new) Warnings only — highlight fields/rows that exceed selected profile constraints; operator may ignore

Hints must never block addChannel / updateChannel / save. Export may still emit errors/truncation independently.

Data model — CodeplugProject

Add optional target radio selection on the project wrapper (not on Codeplug):

// Illustrative — final shape TBD
targetRadioProfileIds: string[]  // e.g. ['opengd77:baofeng-1701']

Machine-readable profile constraints

Markdown radio profiles are authoritative for humans; validation needs a code registry mirroring them:

  • e.g. src/lib/radioProfiles/registry.ts + per-profile modules
  • MVP: Baofeng 1701 constraints (channel name ~16 chars, 1023 channels, 80 zone members, 32 TG list members, feature flags)
  • Each rule: { id, field, check(entity, codeplug), message(profileId) }
  • Docs in radioProfiles must stay in sync with docs/reference/opengd77/radios/*.md (mirror pattern: bands.tsbands.md)

Multi-profile semantics: when several radios are selected, run checks against each profile; surface combined warnings (e.g. "Exceeds 16-char LCD limit (1701)" / "Exceeds 16 scan members (DM32)"). A field fails hint if any selected profile is violated.

Validation engine

New module e.g. src/lib/validation/radioHints.ts:

Function Purpose
validateChannelHints(channel, profiles) Per-channel warnings
validateZoneHints(zone, codeplug, profiles) Member count, unresolved names
validateRxGroupListHints(list, profiles) Member count cap
validateCodeplugHints(codeplug, profiles) Project-level: total channel count, aggregate caps
bulkValidateCodeplug(codeplug, profiles) Full scan — used when profiles change

Reuse existing ValidationIssue shape (severity: 'warning') from src/lib/validation/channel.ts.

Bulk re-validation: when targetRadioProfileIds changes, run bulkValidateCodeplug once and cache results on project context (or memoize per entity id) so list pages stay performant.

UI surfaces

Surface Behaviour
Edit forms (channel, zone, RGL, …) Inline field warning (Mantine Input error/warning styles or Text c="orange") on blur/submit; save still allowed
Detail pages Warning badge or row highlight on offending fields; summary strip "2 radio compatibility warnings"
List pages Row indicator (icon/badge) when entity has hints; optional filter "show warnings only"; project-level banner when channel count exceeds cap
Summary (#61) Optional compatibility summary when profiles set

Style hints as compatibility warnings (amber/outline) — not error red, not unread-notification badges (#81).

Export relationship

  • Export continues to enforce/truncate per target format/profile at serialisation.
  • Optionally pre-export report: "12 hints would become export errors for Baofeng 1701" — nice-to-have, not required for v1.
  • Hint profiles and export format picker (#43 follow-up) may diverge — hints are project-level; export is per-session format choice. Document that hints are advisory for selected project radios, not a guarantee export passes.

Affected

  • src/models/codeplugProject.ts + storage migration
  • src/state/codeplugStore.tsxupdateProject, hint cache invalidation
  • src/lib/radioProfiles/ (new registry)
  • src/lib/validation/radioHints.ts
  • Edit/detail/list routes: channels, zones, rx group lists (extend to contacts/TG as rules exist)
  • Project edit UI (#60 or settings)
  • docs/features/codeplug-project/, docs/reference/opengd77/radios/, docs/features/crud/
  • Tests: profile rule unit tests, bulk validation, UI smoke for warning display

Notes / dependencies

Out of scope

  • Blocking save on hint violations.
  • Storing radio-specific fields on Channel / Zone entities.
  • Auto-selecting target radios from import source (optional follow-up).
  • Validating against every known OpenGD77 radio without operator selection.

Manual verify

  1. Project with no target radios → no hint UI (unchanged).
  2. Select Baofeng 1701 → channel name 20 chars → edit form warning; save succeeds.
  3. Detail + list show same warning for that channel.
  4. Zone with 85 members → zone list/detail warning (80 cap).
  5. Change target radios → bulk re-validation updates list indicators without reload.
  6. Export still produces CSV (may truncate per adapter).

Workflow note

Multi-commit feature: branch from origin/main, atomic conventional commits (profile registry → project field → hint engine → channel UI → zone/RGL → bulk refresh → docs/tests), PR linking Closes #.

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