Dashboard Designer and Publication

Developer guide for the Enezaframework dashboard system. Part of the Dashboards series.

Table of Contents

  1. Overview
  2. Access and Prerequisites
  3. Routes
  4. Create a Dashboard
  5. Wireframe Catalogue
  6. The Designer Canvas
  7. The Widget Editor
  8. The Tab Editor
  9. Dashboard Settings
  10. Preview
  11. Publish
  12. Versions and Restore
  13. Ownership, Clone, Unpublish, Deactivate
  14. Viewer Experience and Preferences
  15. Operational Notes
  16. Related Guides

Overview

The designer is the browser workflow for building dashboards. It edits a draft version; viewers never see the draft until it is published.

flowchart LR
    CREATE[Create dashboard] --> WIRE[Choose wireframe + data source]
    WIRE --> DRAFT[Draft tabs and widgets]
    DRAFT --> EDIT[Bind fields, layout, filters]
    EDIT --> PREVIEW[Preview with real data]
    PREVIEW --> PUBLISH[Publish]
    PUBLISH --> LIVE[Published version]
    PUBLISH --> NEXT[New draft clone]

The designer and the declarative seeder write the same records and obey the same publication validation. The difference is who owns the dashboard: designer-created dashboards are admin-owned; seeded dashboards are seed-owned.


Access and Prerequisites

To use the designer, a user needs:

  1. Login — all designer views require authentication.
  2. The manage action — action.enezadashboard.manage, enforced by DesignerMixin (enezadashboard/views/designer.py:153-160).
  3. Eligible reports — at least one report must pass data-source eligibility and the user's output permission.
  4. A module with menu_verbose_name — the create form lists only apps that declare a menu label (enezadashboard/forms.py:78-84).

The action is registered at app startup (enezadashboard/apps.py:9-16). Run:

bash
python manage.py rbac_sync

after deployment so RBAC discovers it and the menu targets.

Designer views set current_app_override = "enezaadminstrator" by default so their pages appear under the administrator shell (enezadashboard/views/designer.py:156-160). The create form temporarily switches the override to the selected business module while it renders (enezadashboard/views/designer.py:184-201).


Routes

URL Name Purpose
/dashboards/ index Published dashboards by module.
/dashboards/manage/ manage_list All dashboards for designers.
/dashboards/manage/create/ create Create a dashboard.
/dashboards/manage/report-meta/ report_meta JSON metadata for one report.
/dashboards/manage/<uuid>/ designer Draft canvas.
/dashboards/manage/<uuid>/edit/ edit Dashboard settings.
/dashboards/manage/<uuid>/apply-wireframe/ apply_wireframe Replace the draft with a wireframe.
/dashboards/manage/<uuid>/clone/ clone Clone as a new draft.
/dashboards/manage/<uuid>/deactivate/ deactivate Deactivate.
/dashboards/manage/<uuid>/unpublish/ unpublish Unpublish.
/dashboards/manage/<uuid>/publish/ publish Validate and publish.
/dashboards/manage/<uuid>/take-ownership/ take_ownership Protect from seed updates.
/dashboards/manage/<uuid>/preview/ preview Render the draft with real data.
/dashboards/manage/<uuid>/versions/ versions Version history.
/dashboards/manage/<uuid>/versions/<uuid>/restore/ restore_version Restore as a new draft.
/dashboards/manage/<uuid>/tabs/ tab_create Add a tab.
/dashboards/manage/<uuid>/tabs/<uuid>/ tab_update Edit a tab.
/dashboards/manage/<uuid>/tabs/<uuid>/delete/ tab_delete Delete a tab from the draft.
/dashboards/manage/<uuid>/tabs/<uuid>/widgets/ widget_create Add a widget.
/dashboards/manage/<uuid>/tabs/<uuid>/widgets/<uuid>/ widget_update Edit a widget.
/dashboards/manage/<uuid>/tabs/<uuid>/widgets/<uuid>/delete/ widget_delete Delete a widget from the draft.
/dashboards/manage/<uuid>/tabs/<uuid>/widgets/<uuid>/preview/ widget_preview Render one draft widget.
/dashboards/manage/<uuid>/tabs/<uuid>/widgets/<uuid>/layout/ widget_layout Save a dragged layout.

The route definitions are in enezadashboard/urls.py:7-129.


Create a Dashboard

Open /dashboards/manage/create/ (optionally with ?module=<label>), or use Create dashboard from a module's dashboard list.

The form is split into four tabs.

Basics

Field Required Effect
module Yes Owning app. Fixed after the first publication.
code Yes Slug. Unique with module. Fixed after the first publication.
name Yes Display name.
description No Long description.

Data source

Field Required Effect
default_report_ref No Pre-binds new wireframe slots and supplies default measures, dimensions, and columns.
default_period No Dashboard-wide default date range.
reference_date_field No Date field used to apply periods. Overrides the report date field.
data_limit No Caps rows loaded by table, chart, and preview widgets. KPI/gauge aggregates are not capped.

The data-source list contains only eligible reports the current user may execute (enezadashboard/forms.py:168-174).

If you leave the data source blank, a wireframe still creates placeholder widgets, but their report_ref is empty. They render an error and cannot be published until each widget is bound.

Layout

Field Required Effect
layout_template No A wireframe code, or blank for a blank dashboard. Disabled in this form after creation; use Apply wireframe to replace the draft later.

A blank dashboard still receives an empty Overview tab, because the create flow always applies a template (an empty slot list when no wireframe is chosen).

Choosing a wireframe creates the initial tab and its placeholder slots. The wireframe is a starting point, not a constraint: every slot can be changed, added to, removed, moved, or resized afterwards.

Visibility

Field Required Effect
is_active No Inactive dashboards are not visible.
is_default No Default dashboard for the module. Only one active default is allowed.
sort_order No List order.
access_code No Optional RBAC permission required to view the dashboard.

Submitting creates the dashboard, its draft version, and the initial tab. The designer opens the new tab (enezadashboard/views/designer.py:211-239).


Wireframe Catalogue

Wireframes live in enezadashboard/wireframes.py:53-276. All ten use a 12-column grid.

Code Name Family Density Tab Slots Best for
command_center Command Center Analyze High Overview 7 Operations teams watching queues, errors, and spend at once.
executive_brief Executive Brief Report Low Brief 8 Weekly leadership readouts where the headline is the point.
data_explorer Data Explorer Analyze Very high Explorer 4 Analysts slicing records before summarizing them.
pipeline_board Pipeline Board Operate Medium Pipeline 5 Sales, fulfillment, or review queues with named stages.
geo_monitor Geo Monitor Operate Medium Coverage 5 Logistics and field operations watching regional coverage.
inbox_detail Inbox & Detail Operate High Queue 3 Support and moderation queues with structured records.
ops_calendar Ops Calendar Operate Medium Schedule 3 Scheduling desks, staffing rotas, and campaign calendars.
board_report Board Report Report Low Report 6 Monthly board packs and printable performance reviews.
monitoring_wall Monitoring Wall Operate High Wall 12 NOC floors where the screen is read from ten feet away.
growth_review Growth Review Analyze Medium Growth 8 Growth and retention reviews built on cohorts.

Slot composition:

  • KPI slots become kpi widgets.
  • Trend/mix/distribution slots become chart widgets with a preset chart_type.
  • Grid/list slots become table widgets.
  • Queue/agenda/watchlist slots become report_preview widgets.

Applying a wireframe is destructive to the draft: apply_wireframe_template(..., replace=True) deletes every existing draft tab before creating the new one (enezadashboard/services/wireframes.py:88-92). The published version is untouched.

When a data source is chosen, slots are pre-bound where possible:

  • KPIs use the first measure and its first supported aggregation;
  • charts use the first dimension and the first measure;
  • tables and previews use the first four or six columns (enezadashboard/services/wireframes.py:12-62).

The Designer Canvas

The canvas at /dashboards/manage/<uuid>/ shows the draft version.

Typical workflow:

  1. Select a tab, or add one.
  2. Add a widget, or open a placeholder slot.
  3. Bind the widget to a report and a field/measure.
  4. Drag or edit its grid position.
  5. Preview the tab.
  6. Publish.

Canvas actions:

Action Effect
Add tab / edit tab / delete tab Changes the draft only.
Add widget / edit widget / delete widget Changes the draft only.
Drag or resize Saves x, y, w, h to the draft.
Preview widget Renders one widget with the draft configuration.
Apply wireframe Replaces all draft tabs with a new composition.
Publish Validates and promotes the draft.
Versions Lists history and restores a version as a new draft.

The layout endpoint enforces x 0–11, y 0–200, w 2–12, h 2–8, and x + w <= 12 (enezadashboard/views/designer.py:637-654). Publication uses the same grid rules without the y cap (enezadashboard/services/validation.py:28-49).


The Widget Editor

The widget form is split into five tabs (enezadashboard/views/designer.py:39-80).

Basics

Field Required Effect
code Yes Stable widget code, unique within the tab.
title Yes Card/chart/table title.
description No Supporting text.
sort_order No Order within the tab.
is_active No Inactive widgets are skipped.

Data

Field Required Effect
widget_type Yes kpi, chart, table, or report_preview.
report_ref Yes Eligible data source. The list is filtered by module and permission.

Changing the report reloads its metadata so the field pickers show that report's columns and measures.

Display

The form shows the fields relevant to the selected widget type:

Widget Fields
kpi measure, aggregation, format, decimals, prefix, suffix, sparkline category/value/limit.
chart chart_type, category_field, value_field, series_field, comparison_field, line_field, size_field, chart_limit, target, scale_max, chart_sort, show_legend, plus measure/aggregation for gauges.
table table_columns, page_size, sortable, dense, show_header.
report_preview table_columns, preview_rows, show_header.

Field pickers are populated from report metadata. You can type a value, but publication rejects values that are not part of the report.

Layout

layout_x, layout_y, layout_w, layout_h map directly to the stored layout object. The same limits as dragging apply.

Advanced

Field Shape Effect
parameter_config JSON object Report parameter values.
filter_config JSON object Query-builder filter rules for this widget.

These are validated against the selected report on save and publication.

Per-type configuration details are in Dashboard Reference — Widget configuration.


The Tab Editor

Field Effect
code Stable tab code, unique in the version.
name Display name.
description Description.
icon One of the fixed tab icon keys.
sort_order Tab order.
default_period Date range loaded when the tab opens: inherit, a preset, or custom.
default_start_date, default_end_date Required when the default is custom.
reference_date_field Date field used to apply the period for this tab.
data_limit Row cap for this tab.
filter_config Advanced JSON. The tab form writes date_range and data keys from the fields above; other keys are preserved.

Leaving default_period on Use dashboard default inherits the dashboard's data_settings.default_period. Selecting Default explicitly means no date range at all. A custom range requires both dates and validates that start is on or before end (enezadashboard/forms.py:477-534).

Tab data settings live inside filter_config.data and override dashboard settings for that tab (enezadashboard/services/renderer.py:222-231).


Dashboard Settings

Edit settings changes the dashboard record, not the tabs:

  • module and code (fixed after first publication);
  • name, description;
  • default data source;
  • default period;
  • reference date field;
  • data load limit;
  • active, default, sort order, access code;
  • wireframe provenance (disabled in this form after creation; use Apply wireframe to replace the draft composition).

Changes to data settings take effect on the next render. Changes to module and code are blocked after the first publication (enezadashboard/forms.py:204-208).


Preview

Preview renders the draft with real report data, using the same renderer as the live page (enezadashboard/views/designer.py:577-596).

Preview is the place to catch:

  • a widget bound to the wrong report;
  • a measure that is not numeric;
  • a chart type that needs a series or size field;
  • a date field that produces no rows;
  • a filter that excludes everything.

Preview does not validate publication rules; only Publish does that.


Publish

Publishing runs the full validation:

  • dashboard module and code;
  • at least one tab;
  • each tab has a name and a unique code;
  • at least one active widget per tab;
  • unique widget codes;
  • known widget types;
  • report reference resolves and is eligible;
  • widget configuration passes the type's validation;
  • layout is inside the 12-column grid;
  • parameter names and filter fields are allowed.

The checks are in enezadashboard/services/validation.py:79-146.

If validation fails, the designer shows the errors and the draft remains unchanged. If it passes:

  1. the draft becomes published;
  2. published_at, published_by, and notes are stored;
  3. the dashboard points at it and becomes published;
  4. a new draft clone is created for further work (enezadashboard/services/publication.py:68-101).

Published versions are immutable.


Versions and Restore

The versions page lists every version with its number, status, author, and publication time.

  • Restore clones the selected version into a new draft. It does not change the live dashboard.
  • The previous draft is archived unless it is the currently published version (enezadashboard/services/publication.py:104-118).
  • After restoring, review the draft and publish it to go live.

Ownership, Clone, Unpublish, Deactivate

Action Effect
Take ownership Sets managed_by = "admin". Future seed_dashboards runs skip it unless --force.
Clone Creates <code>_copy (or _copy_2, …), copies the published version if present (otherwise the draft), and leaves the clone as an admin-owned draft.
Unpublish Sets status to unpublished, clears the published version, clears is_default, and keeps version history.
Deactivate Sets is_active = False and clears is_default.

Implementation: enezadashboard/services/publication.py:121-192.


Viewer Experience and Preferences

A viewer opens:

text
/dashboards/<module>/

The module entry selects the user's preferred dashboard, then the module default, then the first visible dashboard (enezadashboard/services/selection.py:9-25).

On a dashboard page, the viewer can:

  • switch between visible dashboards for the module;
  • switch tabs;
  • set a period preset or custom range;
  • enable comparison against the previous period or previous year;
  • build per-report filters when the report supports them;
  • page and sort tables;
  • follow a widget's View report link, when the report has a URL.

Preferences are per user and per module (DashboardPreference):

  • preferred dashboard;
  • preferred tab.

Preferences never modify the published configuration. If a preference points to something no longer visible, selection falls back (enezadashboard/services/preferences.py:7-25).

Comparison behavior:

  • KPI widgets compare the aggregate for the current and comparison periods and show a delta;
  • line and area charts can overlay the comparison series;
  • other widget types do not support period comparison (enezadashboard/services/renderer.py:604-619).

Operational Notes

  • Run python manage.py rbac_sync after deployment.
  • Run python manage.py seed_dashboards --dry-run before deploying definition changes.
  • Report discovery metadata is cached per process. Restart the process or call clear_dashboard_report_cache() after changing report code.
  • Query results are reused only within one request; the cache key includes user and entity identity (enezadashboard/services/query_cache.py:7-39).
  • Dashboard visibility is not data protection. Every widget still checks the report permission and report access function.