PhoenixKitManufacturing. Web. MachineTypeTemplateLive
(PhoenixKitManufacturing v0.3.2)
Copy Markdown
View Source
Hidden-route mini-editor for a single machine_type entity's
field_template — the list of dynamic metadata fields rendered on the
machine form for machines linked to that type (see
Machines.merged_field_template/1).
Why this exists
machine_type CRUD moved to the generic phoenix_kit_entities admin UI
as part of the entities migration (dev_docs/ENTITIES_MIGRATION_SPEC.md),
but that generic form only renders fields_definition-declared fields —
field_template is deliberately not declared there (declaring it would
expose a raw, unvalidated JSON-array editor with none of this module's
row-level validation). It also isn't stored in data at all: the generic
form's Multilang.put_language_data/3 fully replaces the primary-language
data block with only its declared fields on every save, which would
silently drop an undeclared key living there. So field_template lives in
metadata["field_template"] instead (see EntitiesRegistry's "Record
shape" moduledoc section), a column the generic entities form never
touches — and this small standalone LiveView is the only way to edit it.
Route
manufacturing/machine-types/:uuid/template, visible: false in
PhoenixKitManufacturing.admin_tabs/0 — never appears in the sidebar.
:uuid is the machine_type entity-data record's own uuid. Reachable
from a pencil icon next to each type badge on Web.MachineFormLive's
General tab, or by direct URL (Paths.machine_type_template/1).
Row shape & validation
Reuses the row shape and per-row validation rules of the pre-migration
machine_type_form_live.ex (removed in E12): each row is a string-keyed
map with key (~r/^[a-z0-9_]+$/, must be unique within the template),
label, type (text/number/date/boolean/select), an optional
unit, an optional required flag, and — mandatory and non-empty only
when type == "select" — an options list. Unlike the removed schema's
version, validation here is plain Elixir (validate_rows/1), not an Ecto
changeset — field_template is a nested array inside EntityData's
freeform metadata map, not a field of its own to cast/3.
@field_template_rows is a plain assign, not changeset-bound: every row
input uses a raw name="field_template[IDX][key]" (not @form[:atom]),
refreshed from submitted params on every phx-change="validate", same
convention MachineFormLive uses for its dynamic metadata inputs.
Persistence
Saves via EntityData.update/3 with only metadata: in the attrs —
Map.putted onto the record's existing metadata (not replaced) so
legacy_uuid (and any other key living there) survives untouched. Reads
are a plain EntityData.get/2 (not through EntitiesRegistry — this page
edits a single record it already knows the uuid of, so the ETS cache
buys nothing); EntityData.update/3 broadcasts its own
PhoenixKitEntities.Events message, so EntitiesRegistry picks up the
change on its own.
persist/2 re-reads the record via EntityData.get/1 immediately before
merging, rather than reusing socket.assigns.entity_data (the mount-time
snapshot) — the session can sit open on this page for a while, and
another process (e.g. the trash flow writing trashed_from_status,
see phoenix_kit_entities) may have written a different metadata key
in the meantime. Merging onto a fresh read avoids clobbering that
concurrent write with the stale snapshot's copy of the same key.