Documentation
¶
Overview ¶
Package admin generates screens to manage an app's data from Go structs: a list with search, filters, sorting and pages for each kind of record, and a form to create, edit and delete one, checked against the struct's validate tags.
Describe each kind of record with a struct, and keep it in a Table, or in a Store of your own:
type Link struct {
ID int64 `admin:"key"`
Title string `validate:"required,max=200" admin:"list,search"`
URL string `validate:"required,url" admin:"list,search"`
Read bool `admin:"list,filter"`
AddedAt time.Time `admin:"list,readonly"`
}
links, err := admin.NewTable[Link](db, "links", "")
panel := admin.New(admin.Options{Authorize: onlyAdmins},
admin.Resource("links", links),
)
Add the panel to the app with kit.WithPlugins, and give it a route, such as src/routes/admin/path.rest:
// page.server.go
func Load(c *kit.Ctx) (admin.Page, error) { return admin.Load(c) }
var Actions = admin.Actions
<!-- +page.svelte -->
<script lang="ts">
import { Admin } from '@ternkit/tern/ui';
let { data, form } = $props();
</script>
<Admin {data} {form} />
The admin tag takes key, list, search, filter, readonly, textarea, date and ref=resource; "-" leaves a field out. Fields take their label, help and rules from the label, description and validate tags, as forms do.
Index ¶
- Variables
- type Admin
- type Field
- type Info
- type List
- type Nav
- type Option
- type Options
- type Page
- type Query
- type Record
- type Res
- type Row
- type Store
- type Table
- func (t *Table[T]) Create(ctx context.Context, rec T) (string, error)
- func (t *Table[T]) Delete(ctx context.Context, key string) error
- func (t *Table[T]) Get(ctx context.Context, key string) (T, error)
- func (t *Table[T]) List(ctx context.Context, q Query) ([]T, int, error)
- func (t *Table[T]) Update(ctx context.Context, key string, rec T, columns []string) error
Constants ¶
This section is empty.
Variables ¶
var Actions = kit.Actions{
"save": save,
"delete": remove,
}
Actions are the panel's route's actions: save and delete.
var ErrNotFound = errors.New("admin: not found")
ErrNotFound is what a Store returns for a record that doesn't exist.
Functions ¶
This section is empty.
Types ¶
type Admin ¶
type Admin struct {
// contains filtered or unexported fields
}
Admin is a panel of screens. It's a kit.Plugin.
type Field ¶
type Field struct {
Name string `json:"name"`
Label string `json:"label"`
Description string `json:"description"`
// Input is the control: text, textarea, number, checkbox, date,
// datetime-local, email, url, password or select.
Input string `json:"input"`
Options []string `json:"options"`
List bool `json:"list"`
Filter bool `json:"filter"`
ReadOnly bool `json:"readonly"`
// Ref is the resource this field holds a key of, linked from the list.
Ref string `json:"ref"`
// Rules are the field's validate rules, for the browser to check.
Rules formrules.Field `json:"rules"`
}
Field is a field on screen.
type Info ¶
type Info struct {
Name string `json:"name"`
Label string `json:"label"`
Singular string `json:"singular"`
Href string `json:"href"`
Key string `json:"key"`
Fields []Field `json:"fields"`
Search bool `json:"search"`
Create bool `json:"create"`
Edit bool `json:"edit"`
Delete bool `json:"delete"`
}
Info describes the resource on screen.
type List ¶
type List struct {
Rows []Row `json:"rows"`
Total int `json:"total"`
Page int `json:"page"`
Pages int `json:"pages"`
PerPage int `json:"perPage"`
Search string `json:"search"`
Sort string `json:"sort"`
Desc bool `json:"desc"`
Filters map[string]string `json:"filters"`
}
List is a page of records.
type Option ¶
type Option func(*resource)
An Option changes how a resource is shown.
func AfterDelete ¶
AfterDelete runs fn after a record is deleted, with its key.
func AfterSave ¶
AfterSave runs fn after a record is created or saved, with its key, such as to update a search index or a cache. An error fails the request, though the record stays saved.
type Options ¶
type Options struct {
// Title is the panel's name, shown above its menu. Default: "Admin".
Title string
// Path is where its route is. Default: "/admin".
Path string
// Authorize runs before every screen and action, and returns an error,
// such as a redirect to sign in or kit.Error(403, ""), for anyone who
// may not use the panel. It's required: a panel without it would let
// anyone change everything.
Authorize func(c *kit.Ctx) error
// PerPage is how many records a list shows at a time. Default: 25.
PerPage int
}
Options configure a panel.
type Page ¶
type Page struct {
Title string `json:"title"`
Base string `json:"base"`
Resources []Nav `json:"resources"`
// View is "home", "list" or "form".
View string `json:"view"`
Resource *Info `json:"resource"`
List *List `json:"list"`
Record *Record `json:"record"`
Counts []int `json:"counts"`
Notice string `json:"notice"`
}
Page is what a panel's route loads.
type Query ¶
type Query struct {
// Search is text to look for in the searchable fields, or "".
Search string
// Filters maps columns to the values they must equal, as forms post them.
Filters map[string]string
// Sort is the column to sort by, or "" for the store's own order.
Sort string
Desc bool
// Offset and Limit page the results.
Offset, Limit int
}
Query is what a list asks a Store for.
type Record ¶
type Record struct {
// Key is "" for a new record.
Key string `json:"key"`
Values map[string]string `json:"values"`
}
Record is the record being created or edited.
type Res ¶
type Res struct {
// contains filtered or unexported fields
}
Res is a resource for New; make one with Resource.
type Row ¶
Row is a record in a list: its key, and each listed field's value, as a form would post it.
type Store ¶
type Store[T any] interface { // List returns a page of the records that match, and how many match in all. List(ctx context.Context, q Query) (records []T, total int, err error) // Get returns the record with this key, or ErrNotFound. Get(ctx context.Context, key string) (T, error) // Create adds a record and returns its key. Create(ctx context.Context, record T) (key string, err error) // Update replaces the record with this key. columns are the ones the // form edited. Update(ctx context.Context, key string, record T, columns []string) error // Delete removes the record with this key. Delete(ctx context.Context, key string) error }
Store keeps the records of one kind. Table is a Store for a SQL table; implement it for data kept elsewhere, such as behind an API.
type Table ¶
type Table[T any] struct { // contains filtered or unexported fields }
Table is a Store for a SQL table, in SQLite or PostgreSQL, whose columns are T's fields: each field's db tag, else its name in snake_case.
func NewTable ¶
NewTable returns a Store for table. order is the list's order when nobody chose one, such as "id DESC"; "" is the key, newest first.
func (*Table[T]) Create ¶
Create implements Store. Read-only fields are left to the database's defaults, and so is a numeric key that is zero.