Package su.onno.ui

Class PageBuilder

java.lang.Object
su.onno.ui.PageBuilder

public final class PageBuilder extends Object
Composes a Page's content: an optional header, a grid of dashboard widgets, and freeform PageComponent blocks. Widgets reuse the same builder as UiLayoutBuilder.widget(...), so the full widget config (type, entity, calendar/kanban/chart options) is available here.

Rendered order is header → widget grid → components.

  • Constructor Details

    • PageBuilder

      public PageBuilder()
  • Method Details

    • title

      public PageBuilder title(String title)
    • subtitle

      public PageBuilder subtitle(String subtitle)
    • header

      public PageBuilder header(boolean show)
      Show or hide the page header — the title/subtitle row the framework renders above the content. On by default. Hide it for a page that supplies its own heading (a hero widget, a custom banner) or a chrome-less surface. bare() is the shorthand for header(false).
    • bare

      public PageBuilder bare()
      Drop the page header entirely — shorthand for header(false).
    • widget

      public UiLayoutBuilder.WidgetBuilder<Void> widget(String title)
      Add a dashboard widget; returns the widget builder for further config.
    • text

      public PageBuilder text(String text)
      Add a freeform text block.
    • actions

      public PageBuilder actions(String heading, Consumer<ActionSpec> configurer)
      Add a section of action buttons — each runs an обработка-style server handler (or routes the client) when clicked. Reuses the same ActionSpec DSL as entity actions, but the buttons live on the page itself rather than a list toolbar, so triggering backend logic is a first-class page primitive:
       b.actions("Reports", a -> {
           a.action("createDrafts").label("Create draft reports").icon("file-plus")
            .handler(ctx -> { reports.createDrafts(); return ActionResult.refresh(ActionToast.success("Drafts created")); });
           a.action("postPending").label("Post pending drafts").icon("send")
            .handler(ctx -> { reports.postPending(); return ActionResult.toast(ActionToast.success("Posted")); });
       });
       

      A button's server handler runs only for an authenticated user. Because a page action has no entity to gate on, declare .roles("MANAGER") to restrict who may run (and see) it; without roles, any authenticated user may run it and the handler enforces its own finer authorization via ctx.user().

    • custom

      public PageBuilder custom(String customType, Map<String,Object> payload)
      Add a div-custom extension block (chart, kanban, ...).
    • aside

      public PageBuilder aside(Consumer<PageBuilder> configurer)
      Compose a right rail beside the main content — a narrow side column for stats, filters, or a summary that sits next to a list rather than stacked above it. The rail takes the same block DSL as the page itself (widget, text, constants, custom), so you can drop stat tiles to the right of a list surface:
       b.list(Order.class);                                  // main
       b.aside(a -> {
           a.widget("Open").type("count").document(Order.class).config("filter", "open = true");
           a.widget("Revenue").type("metric").document(Order.class).config("metric", "sum")...;
       });
       

      Desktop lays the rail out to the right of the main content (which flexes to fill the rest); mobile stacks it below. Repeated calls extend the same rail. Widgets in the rail always stack one-per-row (it is a narrow column). A nested aside(...) inside the rail is ignored.

    • row

      public PageBuilder row(Consumer<PageBuilder.RowBuilder> configurer)
      Add a multi-column layout band — the general layout primitive. Split the page into columns of any width and compose any block in each; nest further rows inside a column for arbitrary structure. Columns lay out side by side on desktop and stack on mobile.
       b.row(r -> {
           r.col("2/3", c -> c.list(Order.class));            // main
           r.col("1/3", c -> {                                 // side
               c.widget("Open").type("count").document(Order.class).config("filter", "open = true");
               c.widget("Revenue").type("metric").document(Order.class)
                .config("metric", "sum").config("metricField", "total");
           });
       });
       

      Rows render after the page's own widget grid and freeform blocks, in the order added. A column is itself a full PageBuilder, so it takes every block method (and further row(...) calls).

    • list

      public PageBuilder list(Class<?> entity)
      Embed the full interactive list of a catalog/document — the same surface as its own route, with the New button, custom action buttons, search/sort and rows that open a detail beside the page. Lets a page (e.g. Settings) manage reference data inline. entity is the catalog or document class.
    • list

      public PageBuilder list(Class<?> entity, Consumer<PageBuilder.ListDefaults> configurer)
      Embed an entity list opened on a default view — preset filter selections, grouping, sorting, and/or a base feed constraint. The viewer can still change the selected filters, grouping, and sort; only PageBuilder.ListDefaults.filter(String) is a permanent feed constraint. Reuses the same col op value filter grammar as dashboard widgets:
       b.list(Order.class, v -> v.filter("open = true")
                                 .defaultFirstFilterOption("assignedTo")
                                 .groupBy("created_at", DateGranularity.DAY)
                                 .sort("_date", true));   // newest first
       
    • title

      public String title()
    • subtitle

      public String subtitle()
    • showHeader

      public boolean showHeader()
      Whether the renderer should emit the header row (title/subtitle).
    • aside

      public PageBuilder aside()
      The right-rail sub-builder, or null if the page composed no aside(...).
    • rows

      public List<PageRow> rows()
      The explicit layout rows composed with row(...), in declaration order.
    • widgets

    • components

      public List<PageComponent> components()
    • pageActions

      public List<ActionSpec.Action> pageActions()
      The page's action-button handlers, in declaration order (resolved by key on post-back).
    • pageAction

      public ActionSpec.Action pageAction(String key)
      The page action with this key, or null if the page declares none.