Shared admin UI primitives used across multiple ui.* sections.
Leaf namespace: URL helpers, field-value rendering, list-column width heuristics, and small formatting/label utilities. Must NOT require any other wagoe.admin.core.ui.* implementation namespace — it is the dependency root that the focused sections build on.
Shared admin UI primitives used across multiple ui.* sections. Leaf namespace: URL helpers, field-value rendering, list-column width heuristics, and small formatting/label utilities. Must NOT require any other wagoe.admin.core.ui.* implementation namespace — it is the dependency root that the focused sections build on.
(->decimal value)A stored number as a BigDecimal, or nil. Drivers hand back BigDecimal, Long, Double or — SQLite — a string.
A stored number as a BigDecimal, or nil. Drivers hand back BigDecimal, Long, Double or — SQLite — a string.
(current-list-url entity-name table-query filters)Build the current admin list URL with filters/pagination applied.
Used to seed return-to on links that navigate away from a list view
(notably the delegated create flow), so the user lands back on the
same filtered/paginated page after cancel or success. Returns the
plain /web/admin/<entity> when no meaningful query params exist.
Build the current admin list URL with filters/pagination applied. Used to seed `return-to` on links that navigate away from a list view (notably the delegated create flow), so the user lands back on the same filtered/paginated page after cancel or success. Returns the plain `/web/admin/<entity>` when no meaningful query params exist.
(date-distance value now display)Days from today (in display's zone, at now) to the stored date value:
positive in the future, negative in the past. Nil when value is not a date.
Days from today (in `display`'s zone, at `now`) to the stored date `value`: positive in the future, negative in the past. Nil when `value` is not a date.
(datetime-input-offset value input-zone server-zone)The UTC offset value has when shown in input-zone, e.g. -05:00, or nil.
The form sends it back beside the wall time so parse-datetime-input can
tell the two occurrences of a repeated local time apart.
The UTC offset `value` has when shown in `input-zone`, e.g. `-05:00`, or nil. The form sends it back beside the wall time so `parse-datetime-input` can tell the two occurrences of a repeated local time apart.
(datetime-input-step formatted)The step a datetime-local needs for formatted, the output of
format-for-datetime-input: nil on the minute, "1" with seconds,
"0.001" with milliseconds.
The default step is 60 seconds. A value with seconds is then a step mismatch and the browser refuses to submit the form — keeping the seconds without this would turn silent truncation into a form that cannot be saved.
The `step` a datetime-local needs for `formatted`, the output of `format-for-datetime-input`: nil on the minute, "1" with seconds, "0.001" with milliseconds. The default step is 60 seconds. A value with seconds is then a step mismatch and the browser refuses to submit the form — keeping the seconds without this would turn silent truncation into a form that cannot be saved.
(entity-create-url entity-name entity-config)(entity-create-url entity-name entity-config caller-url)Resolve the URL used for the 'New' button on an entity.
Entities may expose a dedicated create flow via :create-redirect-url
(e.g. split-table entities that cannot be created via the generic admin
CRUD path). Falls back to /web/admin/<entity>/new when no override is
configured.
When caller-url is provided AND the entity delegates via
:create-redirect-url, the caller URL is threaded through as a
return-to query parameter so the delegated flow (e.g. the user
module's /web/users/new page) can bring the admin back to their
current filtered/paginated list view on cancel or success. The value
is URL-encoded to survive embedded &/= characters from filters
and pagination.
caller-url is ignored for the non-delegated path because the generic
admin create handler re-renders the default list view directly and
does not honor return-to.
Resolve the URL used for the 'New' button on an entity. Entities may expose a dedicated create flow via `:create-redirect-url` (e.g. split-table entities that cannot be created via the generic admin CRUD path). Falls back to `/web/admin/<entity>/new` when no override is configured. When `caller-url` is provided AND the entity delegates via `:create-redirect-url`, the caller URL is threaded through as a `return-to` query parameter so the delegated flow (e.g. the user module's `/web/users/new` page) can bring the admin back to their current filtered/paginated list view on cancel or success. The value is URL-encoded to survive embedded `&`/`=` characters from filters and pagination. `caller-url` is ignored for the non-delegated path because the generic admin create handler re-renders the default list view directly and does not honor `return-to`.
(filtered-list-url entity field value)The entity list filtered to field = value, in the filter bar's own
format, so the bar shows the filter.
The `entity` list filtered to `field` = `value`, in the filter bar's own format, so the bar shows the filter.
(form-zones display)The zones a form renders and parses :instant fields in, from display:
:input-zone (the client's, else the configured, else the server's — chosen
by the shell) and :server-zone. Both come from the same map, so a form can
never show in one zone and save in another (BOU-523).
The zones a form renders and parses :instant fields in, from `display`: `:input-zone` (the client's, else the configured, else the server's — chosen by the shell) and `:server-zone`. Both come from the same map, so a form can never show in one zone and save in another (BOU-523).
(format-date value display)Render a stored date for display. Same passthrough rule as format-instant.
Render a stored date for display. Same passthrough rule as `format-instant`.
(format-field-label field-name)Format field name as human-readable label.
Args: field-name: Keyword field name
Returns: Capitalized string label
Format field name as human-readable label. Args: field-name: Keyword field name Returns: Capitalized string label
(format-for-date-input value)Coerce a stored value to the YYYY-MM-DD an <input type="date"> accepts.
Returns nil when the value cannot be read as a date, so the caller can leave the input empty rather than feed it something the browser will drop.
Coerce a stored value to the `YYYY-MM-DD` an `<input type="date">` accepts. Returns nil when the value cannot be read as a date, so the caller can leave the input empty rather than feed it something the browser will drop.
(format-for-datetime-input value input-zone server-zone)Coerce a stored timestamp to what an <input type="datetime-local">
accepts, as wall time in input-zone, at the precision the value has:
YYYY-MM-DDTHH:mm on the minute, …:ss with seconds, …:ss.SSS with
milliseconds.
The value is read as the instant it denotes (see ->instant) and shown in
input-zone — the zone the form is also parsed back in, which is what makes
an edit to another field leave it unchanged (BOU-519, BOU-523). Seconds are
kept because the form submits every editable field; finer than
milliseconds cannot survive the widget. Pair with datetime-input-step.
Coerce a stored timestamp to what an `<input type="datetime-local">` accepts, as wall time in `input-zone`, at the precision the value has: `YYYY-MM-DDTHH:mm` on the minute, `…:ss` with seconds, `…:ss.SSS` with milliseconds. The value is read as the instant it denotes (see `->instant`) and shown in `input-zone` — the zone the form is also parsed back in, which is what makes an edit to another field leave it unchanged (BOU-519, BOU-523). Seconds are kept because the form submits every editable field; finer than milliseconds cannot survive the widget. Pair with `datetime-input-step`.
(format-instant value display)Render a stored timestamp for display, in display's zone and pattern.
The value is whatever JDBC produced — list-entities does no read-side
coercion, so it is a String, java.sql.Timestamp, OffsetDateTime or
LocalDateTime depending on the driver. Anything unparseable is passed
through as-is rather than swallowed, so a format nobody anticipated stays
visible.
Render a stored timestamp for display, in `display`'s zone and pattern. The value is whatever JDBC produced — `list-entities` does no read-side coercion, so it is a String, java.sql.Timestamp, OffsetDateTime or LocalDateTime depending on the driver. Anything unparseable is passed through as-is rather than swallowed, so a format nobody anticipated stays visible.
(format-money value currency display)value in currency (an ISO code) for display's locale: € 1.234,50 in
Dutch, €1,234.50 in English. An unknown currency code or a value that is
not a number is shown as it is.
`value` in `currency` (an ISO code) for `display`'s locale: € 1.234,50 in Dutch, €1,234.50 in English. An unknown currency code or a value that is not a number is shown as it is.
(format-number value display)value with the locale's grouping and decimals: 1.234,5 or 1,234.5.
`value` with the locale's grouping and decimals: 1.234,5 or 1,234.5.
(get-field-errors errors field-name)Extract errors for a specific field from validation result.
Args: errors: Validation errors map or vector field-name: Keyword field name
Returns: Vector of error messages for the field
Extract errors for a specific field from validation result. Args: errors: Validation errors map or vector field-name: Keyword field name Returns: Vector of error messages for the field
(instant-distance value now display)Seconds from now to the stored timestamp value: positive in the future.
Nil when value is not a timestamp.
Seconds from `now` to the stored timestamp `value`: positive in the future. Nil when `value` is not a timestamp.
(list-column-styles list-fields entity-config)Given the ordered list-fields and the entity config, return a seq of
Hiccup [:col {:style ...}] elements with proportional width:N% for the
data columns. The select/actions framing columns are sized via CSS classes
elsewhere, so widths here sum to 100% of the remaining data area.
Returns a seq (not a vector) so Hiccup splices the elements into the
surrounding :colgroup rather than treating them as a single element.
Pure helper — no I/O.
Given the ordered list-fields and the entity config, return a seq of
Hiccup `[:col {:style ...}]` elements with proportional `width:N%` for the
data columns. The select/actions framing columns are sized via CSS classes
elsewhere, so widths here sum to 100% of the remaining data area.
Returns a seq (not a vector) so Hiccup splices the elements into the
surrounding `:colgroup` rather than treating them as a single element.
Pure helper — no I/O.(list-column-weight field field-config)(list-column-weight field field-config role)Relative width weight for a list column, used to distribute table width proportionally instead of evenly.
Resolution order:
:width in the field config (interpreted as a weight) wins.:type, with a name-based heuristic for strings
(e.g. "description" gets more room than "status").Pure: takes a field keyword + its config map, returns a positive number.
Relative width weight for a list column, used to distribute table width proportionally instead of evenly. Resolution order: 1. Explicit `:width` in the field config (interpreted as a weight) wins. 2. Otherwise derived from `:type`, with a name-based heuristic for strings (e.g. "description" gets more room than "status"). Pure: takes a field keyword + its config map, returns a positive number.
(list-path entity-name)The entity's list page. Its controls request it too: an htmx request aimed at the table gets the table back, and the pushed URL is the page.
The entity's list page. Its controls request it too: an htmx request aimed at the table gets the table back, and the pushed URL is the page.
(number-input-step field-type)The step a number input needs for a field of field-type. The default
is 1, so without it 12.50 fails validation and the form will not submit.
The `step` a number input needs for a field of `field-type`. The default is 1, so without it `12.50` fails validation and the form will not submit.
(option-label field-config value)The label :options gives an enum value, or nil.
The label `:options` gives an enum `value`, or nil.
(parent-breadcrumbs {:keys [label href title title-href]} & tail)Admin / the parent's list / the parent / tail: the trail of a page under
a parent record, trail as the shell's parent-trail gives it. tail are
the crumbs after the parent, the page itself last.
Admin / the parent's list / the parent / `tail`: the trail of a page under a parent record, `trail` as the shell's `parent-trail` gives it. `tail` are the crumbs after the parent, the page itself last.
(parse-datetime-input s input-zone server-zone)(parse-datetime-input s input-zone server-zone preferred-offset)Read what a datetime-local submitted — wall time in input-zone — and return
the instant as an ISO string carrying server-zone's offset, or nil when it
is not a date-time.
The offset is the server's, not UTC's, on purpose. Measured: PostgreSQL
drops the zone of a value written into a TIMESTAMP column without one and
keeps the wall time, so …10:00:50Z read back as 08:00:50Z on an Amsterdam
server. With the server's offset the wall time is the server's own, which
is right for a zone-less column; zone-aware columns and SQLite read the
offset and get the exact instant either way (BOU-523).
Read what a datetime-local submitted — wall time in `input-zone` — and return the instant as an ISO string carrying `server-zone`'s offset, or nil when it is not a date-time. The offset is the server's, not UTC's, on purpose. Measured: PostgreSQL drops the zone of a value written into a TIMESTAMP column without one and keeps the wall time, so `…10:00:50Z` read back as 08:00:50Z on an Amsterdam server. With the server's offset the wall time is the server's own, which is right for a zone-less column; zone-aware columns and SQLite read the offset and get the exact instant either way (BOU-523).
(relative-date value now display)A stored date as "today", "in 5 d", "3 d ago" — or the formatted
date when it is further than the horizon. Nil when value is not a date.
A stored date as "today", "in 5 d", "3 d ago" — or the formatted date when it is further than the horizon. Nil when `value` is not a date.
(relative-instant value now display)A stored timestamp as "just now", "5 min ago", "in 3 h", "2 d ago" —
or the date alone beyond the horizon. Days count calendar days in
the display zone, so yesterday 23:00 is "yesterday", not "1 h ago" at
midnight. Nil when value is not a timestamp.
A stored timestamp as "just now", "5 min ago", "in 3 h", "2 d ago" — or the date alone beyond the horizon. Days count calendar days in the display zone, so yesterday 23:00 is "yesterday", not "1 h ago" at midnight. Nil when `value` is not a timestamp.
(render-field-value field-name value field-config)(render-field-value _field-name value field-config display)Deprecated: no admin page renders through this any more. Use
wagoe.admin.core.ui.cells/cell, which renders by display role (ADR-040).
Render field value for display in table or detail view.
Args: field-name: Keyword field name value: Field value to render field-config: Field configuration map display: Optional {:zone-id :date-time-format :date-format} from the shell. Absent, timestamps render at UTC in the default patterns — core may not read the machine's clock or zone.
Returns: Hiccup structure or string for display
Deprecated: no admin page renders through this any more. Use
`wagoe.admin.core.ui.cells/cell`, which renders by display role (ADR-040).
Render field value for display in table or detail view.
Args:
field-name: Keyword field name
value: Field value to render
field-config: Field configuration map
display: Optional {:zone-id :date-time-format :date-format} from the shell.
Absent, timestamps render at UTC in the default patterns — core
may not read the machine's clock or zone.
Returns:
Hiccup structure or string for display(url-encode s)URL-encode a string for use as a query-string value.
Required when threading return_to (or any contextual URL containing
its own ?/& characters) through query parameters — otherwise the
embedded & splits into a second top-level parameter and the receiving
handler sees a truncated value.
URL-encode a string for use as a query-string value. Required when threading `return_to` (or any contextual URL containing its own `?`/`&` characters) through query parameters — otherwise the embedded `&` splits into a second top-level parameter and the receiving handler sees a truncated value.
(value-name value)An enum value as the string the config names it by: :paid, "paid"
and paid are all "paid".
An enum value as the string the config names it by: `:paid`, `"paid"` and `paid` are all "paid".
(workflow-state-link workflow)An entity's workflow state, linking to its instance page, or a dash when
it has no instance (BOU-563). workflow is {:instance-id :state}. Toned
and labelled as the workflow pages show a current state.
An entity's workflow state, linking to its instance page, or a dash when
it has no instance (BOU-563). `workflow` is {:instance-id :state}. Toned
and labelled as the workflow pages show a current state.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |