resource

package
v0.63.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package resource renders CRUD-backed list, detail, and form screens from Config.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PublicIsland added in v0.55.0

func PublicIsland() appui.Policy

PublicIsland is the policy for a list on a screen anyone may view. It has to be stated rather than left nil: with no policy at all TableHandler requires sign-in, so an anonymous visitor's first sort click on a public list would come back 401.

Types

type Config

type Config struct {
	Entity      string
	Title       string
	Singular    string
	BasePath    string // app route, e.g. "/app/customers"
	APIPath     string // auto-CRUD JSON endpoint, e.g. "/api/customers"
	Crud        DataSource
	Fields      []Field
	Search      string
	Filters     []Filter // facet filters rendered as a toolbar above the table
	PageSize    int
	Relations   map[string]Relation
	CanCreate   bool          // List shows "New"; a /new create form is mounted
	CanEdit     bool          // Detail shows Edit + Delete; a /{id}/edit form is mounted
	Heading     string        // overrides the list's title (the block's text:)
	EmptyText   string        // overrides the empty-state description (the block's empty_text:)
	Related     []RelatedList // reverse relations surfaced on the detail page
	Transitions []Transition  // status-transition workflow buttons on the detail page

	// ExtraActions are appended to the list page header's action cluster
	// (e.g. a data-fui-open trigger for a quick-add modal).
	ExtraActions []render.HTML

	// IslandPath, when set, renders the list's DataTable in island mode:
	// sort headers and pagination fire GET RPCs at this endpoint and the
	// runtime swaps just the table — no document navigation. Mount
	// TableHandler at the same path.
	IslandPath string

	// IslandPolicy gates the island endpoint. It MUST be the same policy
	// that gates the screen showing this list: the island serves the same
	// rows over a route the screen's policy never sees, so leaving it nil
	// on a role-gated screen publishes that screen's data to every signed-in
	// user. TableHandler enforces it before rendering.
	IslandPolicy appui.Policy
}

Config drives the server-rendered list + detail + form screens for one entity.

func (Config) Detail

func (c Config) Detail(ctx context.Context, id string) render.HTML

Detail renders the single-record detail screen.

func (Config) Form

func (c Config) Form(ctx context.Context, id string) render.HTML

Form renders the create (id == "") or edit (id != "") form for one record. It submits as an island: data-fui-rpc posts/puts JSON to the entity's auto-CRUD endpoint, then SPA-navigates back to the list/detail on success.

func (Config) List

func (c Config) List(ctx context.Context) render.HTML

List renders the entity list screen.

func (Config) Table

func (c Config) Table(ctx context.Context) render.HTML

Table renders the list's DataTable for ctx's query state. It is shared by List (initial SSR) and TableHandler (island RPC responses), so a sort/page swap returns exactly the HTML the initial render painted.

func (Config) TableHandler

func (c Config) TableHandler() http.HandlerFunc

TableHandler serves the island endpoint: it renders the same table HTML List paints, for the RPC's query string. The runtime writes the response into the island's data-fui-signal wrapper — no document navigation.

It is a SECOND route onto the rows the screen shows, so it repeats every gate the screen and the JSON API apply: sign-in, the screen's own policy (IslandPolicy), and the entity's declared read permission. A gate that lives only on the screen route is not a gate.

func (Config) WithActions

func (c Config) WithActions(a ...render.HTML) Config

WithActions appends extra page-header actions to the list screen.

func (Config) WithColumns

func (c Config) WithColumns(keys ...string) Config

WithColumns returns a copy showing only the named fields, in the given order.

func (Config) WithCreate

func (c Config) WithCreate() Config

func (Config) WithEdit

func (c Config) WithEdit() Config

WithEdit shows Edit + Delete on the detail screen (a /{id}/edit form is mounted).

func (Config) WithEmpty

func (c Config) WithEmpty(s string) Config

func (Config) WithFilters

func (c Config) WithFilters(fs ...Filter) Config

WithFilters sets the facet filters shown in the toolbar above the list.

func (Config) WithHeading

func (c Config) WithHeading(s string) Config

WithHeading overrides the list's title; WithEmpty overrides the empty-state text.

func (Config) WithIsland

func (c Config) WithIsland(endpoint string) Config

WithIsland turns the list's table into an island: sort + pagination RPC against endpoint instead of navigating. Register TableHandler there.

func (Config) WithIslandPolicy added in v0.55.0

func (c Config) WithIslandPolicy(p appui.Policy) Config

WithIslandPolicy gates the island endpoint with the screen's own policy.

func (Config) WithLimit

func (c Config) WithLimit(n int) Config

func (Config) WithSearch

func (c Config) WithSearch(field string) Config

WithSearch sets the LIKE-search field. WithLimit sets the page size. WithCreate shows a "New" action linking to BasePath/new.

func (Config) WithTransitions

func (c Config) WithTransitions(ts ...Transition) Config

WithTransitions sets the detail-page status-transition workflow buttons.

type DataSource

type DataSource interface {
	CountAll(context.Context, crud.ListOptions) (int, error)
	ListAll(context.Context, crud.ListOptions) ([]map[string]any, error)
	GetOne(context.Context, string, []string) (map[string]any, error)
}

DataSource is the CRUD read seam Config needs. *crud.CrudHandler satisfies it.

type Field

type Field struct {
	Key     string
	Label   string
	Type    string   // string,text,int,float,decimal,bool,enum,date,timestamp,uuid,relation,...
	Values  []string // enum: the allowed values (drives <option>s on the form)
	NoQuery bool     // shown in the grid, but the API refuses to filter or sort on it
}

Field is one displayed entity field.

type Filter

type Filter struct {
	Key    string
	Label  string
	Type   string   // "enum" | "bool" | "relation"
	Values []string // enum: the allowed values
}

Filter is one facet-filter dimension on the list screen: a column the user can narrow the list by. Type is "enum", "bool", or "relation" — it selects both the facet control (pills vs select) and how options are sourced (Values for enums, yes/no for bools, related rows for relations).

type Registry

type Registry map[string]Config

Registry holds the resource configs used by generated screens and dashboard blocks.

func (Registry) GroupBars

func (r Registry) GroupBars(ctx context.Context, entity, groupBy string) []ui.BarChartBar

func (Registry) GroupSlices

func (r Registry) GroupSlices(ctx context.Context, entity, groupBy string) []ui.PieSlice

func (Registry) LineChart

func (r Registry) LineChart(ctx context.Context, entity, groupBy string) render.HTML

LineChart renders a single-series line chart over the grouped counts. Fewer than two groups renders ui.LineChart's calm empty state.

func (Registry) StatValue

func (r Registry) StatValue(ctx context.Context, entity, agg, field, filterStr, format string) string

StatValue computes a single metric over an entity for a stat_card: agg "count" (optionally filtered "field=value") or "sum" of a numeric field.

type RelatedList

type RelatedList struct {
	Title      string // e.g. "Invoices"
	ForeignKey string // the FK column on the related entity, e.g. "customer_id"
	BasePath   string // the related entity's app route, e.g. "/app/invoices"
	Crud       DataSource
	Fields     []Field
	Relations  map[string]Relation // for resolving the related rows' own FKs
}

RelatedList is a reverse relation surfaced on a detail page: the records of another entity that point back at this one via ForeignKey. Turns a detail page from a row editor into an account view (a customer + their invoices).

type Relation

type Relation struct {
	Crud    DataSource
	Display string
}

Relation resolves a foreign-key column to a related record's label.

type Transition

type Transition struct {
	Label   string
	Status  string
	Variant string // "primary" | "secondary" | "danger" | "ghost" (default secondary)
	Stamp   string // optional date field stamped with today on transition
}

Transition is a status-change workflow action shown on a detail page — a button that PUTs {status: Status} to the entity, then refreshes (Mark paid).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL