MishkaCmsCore.Runtime.ComponentCopy (Mishka CMS Core v0.0.1)

Copy Markdown View Source

A new component made from an existing one — the inspector modal's Duplicate.

The copy is written through the resource's own :master_create or :create, chosen by the actor the same way MishkaCmsCore.Runtime.PageBuilder.Helpers.save_section/4 chooses. Nothing is inserted around them, so a copy is validated, signed, versioned, broadcast and compiled exactly like a component somebody typed in — and refused the same way: to an actor who may not write the component, and, for one carrying helpers, while the deployment's :page_code switch is off.

What a copy keeps, and what it does not

Every attribute the create action accepts is carried over, read from the action rather than listed here, so a field added to the resource is copied without anyone remembering this module. Five things are not the source's to pass on:

  • The name. copy_name/1 — <name>-copy-<4 characters>.
  • The kit. extra.ui_kit, extra.ui_kit_version and extra.ui_kit_digest go, and extra.copied_from names the source instead. All three are one stamp — MishkaCmsCore.Runtime.Handlers.UiKitUpgrade writes them together and reads them together — and a copy that kept the fingerprint would be claiming to be what a kit installed. A copy of chelekom-button still starts with chelekom-, and MishkaCmsCore.Runtime.Handlers.UiKitHandler purges by that prefix on an uninstall or a cleanup: true reinstall — through :master_permanent_destroy, which leaves no archive and no version. copied_from is what it reads to leave a user's copy alone.
  • required. It says the CMS cannot run without the component, which is true of the kit's icon and of nobody's copy of it.
  • precompile. A copy is built by the first render that names it, not at every boot.
  • Its elements' classes. See below.

A copy stays where its source is

A master copies any row into the source's own scope: a global row makes a global copy, a site's row a copy in that site. A site copies only its own rows. A shared row copied into a site would be a fork its examples cannot find — they say site="Global" — so that is refused rather than guessed at.

It names itself

A component's examples are real invocations, <.component component_name="chelekom-card" …/>, and so is the occasional template that renders itself. Copied verbatim, the copy's Preview tab and the builder's Examples modal would draw the ORIGINAL. Every exact component_name="<source>" in the template, the body, the examples and anything under extra is rewritten to the copy's name. The closing quote is part of the match, so chelekom-button-group is not a reference to chelekom-button; a computed component_name={@name} is not rewritten.

Its elements are its own

Every minted pb-xxxxxxxx class in the copied text is swapped for a fresh one and the source's CSS for those classes is written under the new ones in the copy's own row — the shared MishkaCmsCore.Runtime.PageBuilder.ElementScopes, which says what a kept class costs.

Summary

Functions

<name>-copy-<suffix>: four lowercase base32 characters, the base cut so the whole stays within 100 characters.

Copy source as actor, trying a fresh name when the last one was taken.

Functions

copy_name(name)

@spec copy_name(String.t()) :: String.t()

<name>-copy-<suffix>: four lowercase base32 characters, the base cut so the whole stays within 100 characters.

Already in the form the resource's slugify(:name) stores, so the name the self-references are rewritten to is the name the row is saved under.

duplicate(source, actor, opts \\ [])

@spec duplicate(MishkaCmsCore.Runtime.Component.t(), map() | nil, keyword()) ::
  {:ok, MishkaCmsCore.Runtime.Component.t()} | {:error, term()}

Copy source as actor, trying a fresh name when the last one was taken.

:names is the candidates to try, in order; by default three from copy_name/1. Only a taken name moves on to the next one — any other refusal is returned as it came.

Returns the resource's own {:ok, copy} / {:error, error}, or {:error, :out_of_scope} when the actor is a site and source is not that site's.