التوثيق

ابنِ مدير مهام

صفوف مخزّنة، ونموذج يضيف صفًا، وإجراءات صف تُكمل وتحذف، وقائمة تُعاد تحميلها بعد كل كتابة.

يبني هذا الدرس مدير مهام بسمتين في صفحة واحدة: قائمة ونموذج. تُخزَّن المهام في المتصفح، فلا يحتاج التطبيق إلى خادم.

1. كيان مخزّن

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 الصفوف في متصفح الزائر، ويعبّئها instances في أول مرة يُنشأ فيها المخزن.

2. تحميل القائمة

تبدأ القائمة في loading، وتجلب البيانات عند INIT، وتنتقل إلى ready حين تصل الصفوف. يبلّغ الجلب عبر حدثين تعلنهما السمة في 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. إجراءات الصف

تضع itemActions أزرارًا على كل صف. يرسل إجراء الصف حدثه مع { id, row }، ويقرر when لكل صف ما إذا كان الزر يظهر:

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. النموذج

تعرض سمة ثانية form-section. الإرسال يبعث SAVE مع قيم النموذج في ?data، فتخزّن السمة الصف وتبث TASK_ADDED:

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

تستمع القائمة وتعيد التحميل:

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

5. التطبيق المكتمل

آلة الحالات

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
يعمل الآن مباشرة

Sketch the states

Yes

Write the transitions

No

Run orb validate

No

البرنامج أعلاه كآلات حالات، واحدة لكل سمة: كل مربع حالة، وكل سهم حدث ينقلها، والأيقونات على السهم هي التأثيرات التي يشغّلها ذلك الحدث. الرمز ◇ على السهم شرط حارس؛ مرّر المؤشر فوقه لتقرأ الشرط. كيف تقرأ 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}

ما الذي يحدث عندما يقع الحدث 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

كيف تتحادث السمات فيما بينها، بالترتيب:

TaskListTaskFormTaskListTaskFormالمستخدمSAVEpersist create TaskTASK_ADDED → RELOADfetch TaskTasksLoaded → readyrender-ui mainالمستخدم

أضف مهمة، وأكمل واحدة، واحذف أخرى. أعد تحميل الصفحة: المهام ما زالت هناك لأنها مخزّنة في متصفحك.

Orb

اللغة التي تكون فيها القاعدة هي البرنامج.

© 2026 المدار. ليوبليانا، سلوفينيا.
Not reported here