Frontend Templating
===================

Overview
--------

The frontend is configured by YAML files. Page definitions and plot
configurations live in the frontend repo and are validated at load time.
This allows per-page templating and per-plot configuration without
backend changes.

Page index and user overrides
-----------------------------

The topbar menus for telescope types (LST, MST, SST) and the
Aux menu are always present. The YAML index only controls which pages
appear under those fixed menus; it does not allow adding or removing the
top-level menus themselves.

The default page index is in ``frontend/view/pages/pages_index.yaml``.
A user override index can be provided in
``frontend/view/pages/user_pages/pages_index.yaml``. If the user index
is present and valid, it replaces the default pages list.

Example index:

.. code-block:: yaml

    pages:
      - name: interleaved_pedestals
        source: default_pages/interleaved_pedestals.yaml
      - name: broken_plot_page
        source: user_pages/broken_plot_page.yaml

    auxiliary_subitems:
      - Lidar
      - Weather Station

Page config structure
---------------------

Each page defines a list of plots in order. Plot entries are flat and
contain the plot configuration directly. Every plot entry requires a title,
which is used for display purposes only.

.. code-block:: yaml

    name: interleaved_pedestals
    label: Interleaved pedestals
    plots:
      - title: Pedestal mean charge (Gain 0)
        plotType: scatterplot
        data:
          path_tail: pedestal_charge_mean
          field: mean
        x:
          label: Pixel ID
          scale: linear
        y:
          label: Pedestal mean charge
          scale: linear
        line: none
    layout:
      rows: 2
      cols: 3
      max_per_row: 3
    css:
      - badger
      - scatterplot
    js:
      - d3
      - scatterplot
      - plot


Plot placeholders
-----------------

Plots without ``plotType`` act as placeholders. They require a title but
skip plot-type validation and are ignored by the plot renderer. This is
useful when you want a reserved grid slot without data yet.

Plots with a ``plotType`` must also provide a ``data`` block. Placeholders
do not need a data block.

Plot configuration by type
--------------------------

Plot configs are validated per plot type using a discriminated union on
``plotType``. Only the fields relevant to each plot type are accepted.
If ``plotType`` is missing, the entry is treated as a placeholder and
validation is skipped.

Data requirements
^^^^^^^^^^^^^^^^^

When ``plotType`` is present, the plot entry must include a ``data`` block
with:

- ``field`` (required): dataset field to extract
- ``path`` (optional): full dataset path without the trailing ``tel_###``
- ``path_tail`` (optional): suffix appended to
  ``/dl1/monitoring/telescope/quality``

Either ``path`` or ``path_tail`` is required. If both are set, ``path``
takes precedence. The backend appends the telescope id from the query
(``tel_{tel_id:03d}``) to the resolved path.

Plot type field
^^^^^^^^^^^^^^^

- ``plotType`` (optional): ``scatterplot``, ``cameraview``, ``histogram1d``

Scatterplot
^^^^^^^^^^^

Fields:

- ``title`` (str, required)
- ``subtitle`` (str, optional)
- ``x`` (object, required)

  - ``label`` (str, required)
  - ``domain`` (list[float], optional)
  - ``unit`` (str, optional)
  - ``scale`` (str, optional): ``linear``, ``log``, ``time``, ``ordinal``, ``band``, ``point``
- ``y`` (object, required)

  - ``label`` (str, required)
  - ``domain`` (list[float], optional)
  - ``unit`` (str, optional)
  - ``scale`` (str, optional): ``linear``, ``log``, ``time``, ``ordinal``, ``band``, ``point``
- ``line`` (str, optional): ``none``, ``solid``, ``dashed``, ``dotted``, ``dot-dashed``, ``dot-dashed-dashed``
- ``marks`` (object, optional)

  - ``type`` (str, optional): ``circle``, ``triangle``, ``cross``, ``wye``, ``star``, ``square``, ``diamond``
  - ``fill`` (str, optional)
  - ``stroke`` (str, optional)
  - ``strokeWidth`` (float, optional)
  - ``opacity`` (float, optional)
  - ``size`` (float, optional)

Camera view
^^^^^^^^^^^

Fields:

- ``title`` (str, required)
- ``subtitle`` (str, optional)
- ``x`` (object, optional)

  - ``label`` (str, optional)
  - ``domain`` (list[float], optional)
  - ``unit`` (str, optional)
  - ``scale`` (str, optional): ``linear``
- ``y`` (object, optional)

  - ``label`` (str, optional)
  - ``domain`` (list[float], optional)
  - ``unit`` (str, optional)
  - ``scale`` (str, optional): ``linear``

Histogram1D
^^^^^^^^^^^

Fields:

- ``title`` (str, required)
- ``subtitle`` (str, optional)
- ``x`` (object, required)

  - ``label`` (str, required)
  - ``domain`` (list[float], optional)
  - ``unit`` (str, optional)
  - ``scale`` (str, optional): ``linear``, ``log``
- ``y`` (object, required)

  - ``label`` (str, required)
  - ``domain`` (list[float], optional)
  - ``unit`` (str, optional)
  - ``scale`` (str, optional): ``linear``, ``log``
- ``bins`` (int, optional)
- ``marks`` (object, optional)

  - ``fill`` (str, optional)
  - ``stroke`` (str, optional)
  - ``strokeWidth`` (float, optional)
  - ``opacity`` (float, optional)

Validation and soft-fail behavior
---------------------------------

Invalid plot configs do not prevent the page from loading. The plot tile
shows an inline error message, and the client-side plotter skips that
plot. Invalid page configs still return a page error template. Duplicate
plot entries that resolve to the same data mapping are treated as a
page-level validation error.
