Tutorial 21
Write some static content.
Example
// Copyright (c) 2025 worldiety GmbH
//
// This file is part of the NAGO Low-Code Platform.
// Licensed under the terms specified in the LICENSE file.
//
// SPDX-License-Identifier: Custom-License
package main
import (
"fmt"
"go.wdy.de/nago/application"
"go.wdy.de/nago/pkg/data"
"go.wdy.de/nago/pkg/std"
"go.wdy.de/nago/pkg/xtime"
"go.wdy.de/nago/presentation/core"
"go.wdy.de/nago/presentation/ui"
"go.wdy.de/nago/presentation/ui/crud"
"go.wdy.de/nago/web/vuejs"
"log"
"log/slog"
"net/http"
"time"
)
import _ "net/http/pprof"
type PID string
type Score int
type Grade float64
type Color string
type Birthday xtime.Date
type Vacation struct {
Start xtime.Date
End xtime.Date
}
type Person struct {
ID PID
Title string
Firstname string
Lastname string
Friends []PID // this is like foreign keys, however they become stale and are not automatically updated
BestFriend std.Option[PID] // this the same as above, but the one-to-one case
Score Score
Grade Grade
Proofed bool
FavoriteColor std.Option[Color]
FavoriteColor2 std.Option[ui.Color]
Colors []Color
Birthday Birthday
Vacation Vacation
WorkDuration time.Duration
}
func (p Person) Identity() PID {
return p.ID
}
type Persons data.Repository[Person, PID]
func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
application.Configure(func(cfg *application.Configurator) {
cfg.SetApplicationID("de.worldiety.tutorial")
cfg.Serve(vuejs.Dist())
persons := application.SloppyRepository[Person, PID](cfg)
persons.SaveAll(func(yield func(Person) bool) {
yield(Person{
ID: "1",
Firstname: "bilbo",
Lastname: "beutlin",
Score: 1,
})
yield(Person{
ID: "2",
Firstname: "Frodo",
Lastname: "Beutlin",
BestFriend: std.Some[PID]("1"),
Score: 2,
})
})
cfg.RootView(".", func(wnd core.Window) core.View {
bnd := crud.NewBinding[Person](wnd)
bnd.Add(
crud.Text(crud.TextOptions{Label: "Vorname"}, crud.Ptr(func(entity *Person) *string {
return &entity.Firstname
})).WithValidation(func(person Person) (errorText string, infrastructureError error) {
if person.Firstname != "Torben" {
return "Du bist nicht Torben", nil
}
return "", nil
}).WithSupportingText("Gib Torben ein"),
crud.Text(crud.TextOptions{Label: "Nachname"}, crud.Ptr(func(entity *Person) *string {
return &entity.Lastname
})),
crud.Int(crud.IntOptions{Label: "Score"}, crud.Ptr(func(model *Person) *Score {
return &model.Score
})).WithValidation(func(person Person) (errorText string, infrastructureError error) {
if person.Score != 42 {
return "muss 42 sein", nil
}
return "", nil
}),
crud.Float(crud.FloatOptions{Label: "Grade"}, crud.Ptr(func(model *Person) *Grade {
return &model.Grade
})),
crud.Bool(crud.BoolOptions{Label: "Proofed"}, crud.Ptr(func(model *Person) *bool {
return &model.Proofed
})).WithSupportingText("Check me if this is ok"),
crud.BoolToggle(crud.BoolOptions{Label: "Proofed2"}, crud.Ptr(func(model *Person) *bool {
return &model.Proofed
})).WithSupportingText("don't bind same fields into the same form"),
crud.PickMultiple(crud.PickMultipleOptions[Color]{Label: "Colors", Values: []Color{"red", "green", "blue"}}, crud.Ptr(func(model *Person) *[]Color {
return &model.Colors
})),
crud.PickOne(crud.PickOneOptions[Color]{Label: "Color", Values: []Color{"red", "green", "blue"}}, crud.Ptr(func(model *Person) *std.Option[Color] {
return &model.FavoriteColor
})),
crud.OneToMany(crud.OneToManyOptions[Person, PID]{
Label: "Friendos",
ForeignEntities: persons.All(),
ForeignPickerRenderer: func(t Person) core.View {
return ui.Text(fmt.Sprintf("%s %s", t.Firstname, t.Lastname))
},
}, crud.Ptr(func(model *Person) *[]PID {
return &model.Friends
})),
crud.OneToOne(crud.OneToOneOptions[Person, PID]{
Label: "Best Friend",
ForeignEntities: persons.All(),
ForeignPickerRenderer: func(t Person) core.View {
return ui.Text(fmt.Sprintf("%s %s", t.Firstname, t.Lastname))
},
}, crud.PropertyFuncs[Person, std.Option[PID]](func(p *Person) std.Option[PID] {
return p.BestFriend
}, func(dst *Person, v std.Option[PID]) {
dst.BestFriend = v
})),
crud.Date(crud.DateOptions{Label: "Geburtstag"}, crud.Ptr(func(model *Person) *Birthday {
return &model.Birthday
})),
crud.DateRange(crud.DateRangeOptions{Label: "Urlaub"}, crud.Ptr(func(model *Person) *xtime.Date {
return &model.Vacation.Start
}), crud.Ptr(func(model *Person) *xtime.Date {
return &model.Vacation.End
})),
crud.Time(crud.TimeOptions{Label: "Arbeitszeit", ShowHours: true, ShowSeconds: true}, crud.Ptr(func(model *Person) *time.Duration {
return &model.WorkDuration
})),
crud.PickOneColor(crud.PickOneColorOptions{Label: "Lieblingsfarbe 2"}, crud.Ptr(func(model *Person) *std.Option[ui.Color] {
return &model.FavoriteColor2
})),
crud.AggregateActions("Optionen",
crud.Optional[Person](crud.ButtonDelete[Person](wnd, func(p Person) error {
slog.Info("delete person", "id", p.ID)
return nil
}), func(person Person) bool {
return person.ID != "1"
}),
crud.ButtonEdit[Person](bnd, func(p Person) (string, error) {
slog.Info("update person", "id", p.ID, "person", p)
return "", persons.Save(p)
}),
),
)
return ui.VStack(
crud.View[Person, PID](
crud.Options[Person, PID](bnd).
Actions(
crud.ButtonCreate[Person](bnd, Person{ID: "do not randomize here"}, func(person Person) (errorText string, infrastructureError error) {
if !bnd.Validates(person) {
return "irgendein validation fehler, gugg hin", nil
}
if person.Firstname == "" {
return "Vorname darf nicht leer sein", nil
}
person.ID = data.RandIdent[PID]() // create a unique ID here
return "", persons.Save(person)
}),
).
FindAll(persons.All()).
Title("Personen"),
),
).Padding(ui.Padding{}.All(ui.L16)).Frame(ui.Frame{}.FullWidth())
})
}).Run()
}
Info
More static content.