Zgradi upravljalnik opravil

Shranjene vrstice, obrazec, ki doda eno, dejanja na vrsticah, ki zaključijo in izbrišejo, in seznam, ki se po vsakem zapisu znova naloži.

Ta vodnik zgradi upravljalnik opravil z dvema lastnostma na eni strani: seznamom in obrazcem. Opravila so shranjena v brskalniku, zato aplikacija ne potrebuje strežnika.

1. Shranjena entiteta

lolo
1entity Task [persistent: tasks, local] { 2 id : string! 3 title : string! 4 done : boolean = false 5 instances [ 6 { id: "T-1", title: "Sketch the states", done: true }, 7 { id: "T-2", title: "Write the transitions", done: false } 8 ] 9}

local hrani vrstice v brskalniku obiskovalca. instances jih napolni, ko se shramba prvič ustvari.

2. Nalaganje seznama

Seznam začne v loading, ob INIT naloži podatke in se premakne v ready, ko vrstice prispejo. Nalaganje poroča prek dveh dogodkov, ki ju lastnost navede v emits:

lolo
1state loading { 2 INIT -> loading 3 (fetch Task { emit: { success: TasksLoaded, failure: TasksFailed } }) 4 (render-ui main { type: skeleton, variant: list, rows: 3 }) 5 TasksLoaded -> ready 6 (render-ui main { type: data-list, entity: ?data, fields: [{ name: "title", label: "Task", variant: h4 }] }) 7 TasksFailed -> ready 8 (render-ui main { type: alert, variant: error, message: ?error }) 9}

3. Dejanja na vrsticah

itemActions na vsako vrstico postavijo gumbe. Dejanje vrstice pošlje svoj dogodek z { id, row }, when pa za vsako vrstico odloči, ali se gumb pokaže:

lolo
1 2 3 4 ▼itemActions: [ { label: "Complete", event: COMPLETE, variant: ghost, when: (fn row (not (object/get @row done false))) }, { label: "Delete", event: DELETE, variant: danger } ]
lolo
1COMPLETE -> loading 2 (persist update Task (object/merge ?row { done: true })) 3 (fetch Task { emit: { success: TasksLoaded, failure: TasksFailed } }) 4DELETE -> loading 5 (persist delete Task ?id) 6 (fetch Task { emit: { success: TasksLoaded, failure: TasksFailed } })

4. Obrazec

Druga lastnost pokaže form-section. Oddaja pošlje SAVE z vrednostmi obrazca kot ?data; lastnost vrstico shrani in odda TASK_ADDED:

lolo
1 2 3 SAVE -> editing (persist create Task ?data) (emit TASK_ADDED)

Seznam posluša in se znova naloži:

lolo
1 2 3 ▼listens { TaskForm.TASK_ADDED -> RELOAD }

5. Dokončana aplikacija

Avtomat stanj

TaskList

on Task · states: 2 · transitions: 6
listensTASK_ADDEDemitsTasksLoadedemitsTasksFailedemitsMOVED
INIT
TasksLoaded
TasksFailed
COMPLETE
DELETE
RELOAD
1loading
nowready

TaskForm

on Task · states: 1 · transitions: 2
emitsTASK_ADDEDemitsMOVED
INIT
SAVE
nowediting
Teče v živo

Sketch the states

Yes

Write the transitions

No

Run orb validate

No

Zgornji program kot avtomati stanj, eden za vsako lastnost: vsak okvir je stanje, vsaka puščica dogodek, ki ga premakne, ikone na puščici pa so učinki, ki jih ta dogodek izvede. ◇ na puščici je varovalo; z miško pojdite nanj in preberite pogoj. Kako brati AVL

std-orb-docex-tasks.lolololo
1app std-orb-docex-tasks "1.0.0" 2"std-orb-docex-tasks — a task manager: stored tasks, a form that adds one, row actions that complete or delete, and a list that reloads after every write." 3orbital TasksOrbital { 4 entity Task [persistent: docex_tasks, local] { 5 id : string! 6 title : string! 7 done : boolean = false 8 instances [ 9 { id: "T-1", title: "Sketch the states", done: true }, 10 { id: "T-2", title: "Write the transitions", done: false }, 11 { id: "T-3", title: "Run orb validate", done: false } 12 ] 13 } 14 15 trait TaskList -> Task [interaction, collection] { 16 initial: loading 17 18 state loading { 19 INIT -> loading 20 (fetch Task { emit: { success: TasksLoaded, failure: TasksFailed } }) 21 (render-ui main { type: skeleton, variant: list, rows: 3 }) 22 TasksLoaded -> ready 23 (emit MOVED { event: "TasksLoaded" }) 24 (render-ui main { type: data-list, entity: ?data, fields: [{ name: "title", label: "Task", variant: h4 }, { name: "done", label: "Done", variant: badge, labels: { "true": "Done", "false": "Open" } }], itemActions: [{ label: "Complete", event: COMPLETE, variant: ghost, when: (fn row (not (object/get @row done false))) }, { label: "Delete", event: DELETE, variant: danger }], emptyTitle: "Nothing to do", emptyDescription: "Add a task with the form.", emptyIcon: "check-circle" }) 25 TasksFailed -> ready 26 (emit MOVED { event: "TasksFailed" }) 27 (render-ui main { type: alert, variant: error, message: ?error }) 28 } 29 30 state ready { 31 COMPLETE -> loading 32 (emit MOVED { event: "COMPLETE" }) 33 (persist update Task (object/merge ?row { done: true })) 34 (fetch Task { emit: { success: TasksLoaded, failure: TasksFailed } }) 35 DELETE -> loading 36 (emit MOVED { event: "DELETE" }) 37 (persist delete Task ?id) 38 (fetch Task { emit: { success: TasksLoaded, failure: TasksFailed } }) 39 RELOAD -> loading 40 (emit MOVED { event: "RELOAD" }) 41 (fetch Task { emit: { success: TasksLoaded, failure: TasksFailed } }) 42 } 43 44 emits { 45 TasksLoaded { 46 data : [Task] 47 } 48 TasksFailed { 49 error : string 50 } 51 MOVED -> external { 52 event : string! 53 } 54 @description "Each move names the event it took, so the diagram beside the demo can follow it." 55 } 56 57 listens { 58 TaskForm.TASK_ADDED -> RELOAD 59 COMPLETE { 60 id : Task.id! 61 row : Task! 62 } 63 DELETE { 64 id : Task.id! 65 } 66 } 67 } 68 69 trait TaskForm -> Task [interaction, instance] { 70 initial: editing 71 72 state editing { 73 INIT -> editing 74 (render-ui main { type: form-section, fields: ["title"], submitEvent: SAVE, mode: create, entity: {} }) 75 SAVE -> editing 76 (emit MOVED { event: "SAVE" }) 77 (persist create Task ?data) 78 (emit TASK_ADDED) 79 (render-ui main { type: form-section, fields: ["title"], submitEvent: SAVE, mode: create, entity: {} }) 80 } 81 82 emits { 83 TASK_ADDED 84 @description "A task was stored." 85 MOVED -> external { 86 event : string! 87 } 88 @description "Each move names the event it took, so the diagram beside the demo can follow it." 89 } 90 91 listens { 92 SAVE { 93 data : @entity! 94 } 95 } 96 } 97 98 page "/tasks" -> TaskList, TaskForm 99}

Kaj se zgodi, ko se sproži COMPLETE:

readyCOMPLETE
→
loading
Effects (2)What runs, in order, when the transition fires.
(persist "update" "Task" (object/merge @payload.row { done: true }))
"update""Task"@payload.rowtruedone{ }object/mergepersist
(fetch "Task" { emit: { failure: "TasksFailed", success: "TasksLoaded" } })
"Task""TasksFailed"failure"TasksLoaded"success{ }emit{ }fetch

Kako se lastnosti pogovarjajo med seboj, po vrsti:

TaskListTaskFormTaskListTaskFormUporabnikSAVEpersist create TaskTASK_ADDED → RELOADfetch TaskTasksLoaded → readyrender-ui mainUporabnik

Dodaj opravilo, zaključi eno, izbriši eno. Znova naloži stran: opravila so še vedno tam, ker so shranjena v tvojem brskalniku.

© 2026 Almadar. Ljubljana, Slovenija.
Not reported here