@elaraai/e3-ui 1.0.94 → 1.0.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/allocation/adapters.d.ts +159 -0
- package/dist/src/allocation/adapters.d.ts.map +1 -0
- package/dist/src/allocation/adapters.js +241 -0
- package/dist/src/allocation/adapters.js.map +1 -0
- package/dist/src/allocation/functions.d.ts +664 -0
- package/dist/src/allocation/functions.d.ts.map +1 -0
- package/dist/src/allocation/functions.js +782 -0
- package/dist/src/allocation/functions.js.map +1 -0
- package/dist/src/allocation/index.d.ts +2985 -0
- package/dist/src/allocation/index.d.ts.map +1 -0
- package/dist/src/allocation/index.js +499 -0
- package/dist/src/allocation/index.js.map +1 -0
- package/dist/src/allocation/types.d.ts +832 -0
- package/dist/src/allocation/types.d.ts.map +1 -0
- package/dist/src/allocation/types.js +360 -0
- package/dist/src/allocation/types.js.map +1 -0
- package/dist/src/bind/func.d.ts +14 -0
- package/dist/src/bind/func.d.ts.map +1 -1
- package/dist/src/bind/func.js +22 -1
- package/dist/src/bind/func.js.map +1 -1
- package/dist/src/calendar/index.d.ts +510 -1639
- package/dist/src/calendar/index.d.ts.map +1 -1
- package/dist/src/calendar/index.js +56 -29
- package/dist/src/calendar/index.js.map +1 -1
- package/dist/src/flowchart/canvas.d.ts +9 -21
- package/dist/src/flowchart/canvas.d.ts.map +1 -1
- package/dist/src/flowchart/canvas.js +10 -22
- package/dist/src/flowchart/canvas.js.map +1 -1
- package/dist/src/flowchart/flowchart.d.ts +19 -13
- package/dist/src/flowchart/flowchart.d.ts.map +1 -1
- package/dist/src/flowchart/flowchart.js.map +1 -1
- package/dist/src/flowchart/index.d.ts +44 -21
- package/dist/src/flowchart/index.d.ts.map +1 -1
- package/dist/src/flowchart/index.js +43 -20
- package/dist/src/flowchart/index.js.map +1 -1
- package/dist/src/flowchart/library.d.ts +166 -81
- package/dist/src/flowchart/library.d.ts.map +1 -1
- package/dist/src/flowchart/library.js +232 -105
- package/dist/src/flowchart/library.js.map +1 -1
- package/dist/src/flowchart/over.d.ts +9 -16
- package/dist/src/flowchart/over.d.ts.map +1 -1
- package/dist/src/flowchart/over.js +9 -16
- package/dist/src/flowchart/over.js.map +1 -1
- package/dist/src/flowchart/payload.d.ts +710 -508
- package/dist/src/flowchart/payload.d.ts.map +1 -1
- package/dist/src/flowchart/payload.js +128 -74
- package/dist/src/flowchart/payload.js.map +1 -1
- package/dist/src/flowchart/window.d.ts +132 -347
- package/dist/src/flowchart/window.d.ts.map +1 -1
- package/dist/src/flowchart/window.js +48 -55
- package/dist/src/flowchart/window.js.map +1 -1
- package/dist/src/index.d.ts +11 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +14 -6
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +18 -7
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +28 -9
- package/dist/src/internal.js.map +1 -1
- package/dist/src/plan/event-rows.d.ts +26 -10
- package/dist/src/plan/event-rows.d.ts.map +1 -1
- package/dist/src/plan/event-rows.js +39 -13
- package/dist/src/plan/event-rows.js.map +1 -1
- package/dist/src/plan/ir.d.ts +244 -815
- package/dist/src/plan/ir.d.ts.map +1 -1
- package/dist/src/plan/ir.js +8 -6
- package/dist/src/plan/ir.js.map +1 -1
- package/dist/src/plan/library.d.ts +3 -0
- package/dist/src/plan/library.d.ts.map +1 -1
- package/dist/src/plan/library.js +1 -1
- package/dist/src/plan/library.js.map +1 -1
- package/dist/src/plan/ordered-source.d.ts +1 -0
- package/dist/src/plan/ordered-source.d.ts.map +1 -1
- package/dist/src/plan/plan.d.ts +559 -1667
- package/dist/src/plan/plan.d.ts.map +1 -1
- package/dist/src/plan/plan.js +123 -45
- package/dist/src/plan/plan.js.map +1 -1
- package/dist/src/plan/root.d.ts +16 -20
- package/dist/src/plan/root.d.ts.map +1 -1
- package/dist/src/plan/root.js +23 -33
- package/dist/src/plan/root.js.map +1 -1
- package/dist/src/roster/coverage.d.ts +17 -231
- package/dist/src/roster/coverage.d.ts.map +1 -1
- package/dist/src/roster/coverage.js +94 -90
- package/dist/src/roster/coverage.js.map +1 -1
- package/dist/src/roster/fit.d.ts +59 -0
- package/dist/src/roster/fit.d.ts.map +1 -0
- package/dist/src/roster/fit.js +155 -0
- package/dist/src/roster/fit.js.map +1 -0
- package/dist/src/roster/index.d.ts +2862 -3662
- package/dist/src/roster/index.d.ts.map +1 -1
- package/dist/src/roster/index.js +383 -81
- package/dist/src/roster/index.js.map +1 -1
- package/dist/src/roster/library.d.ts +37 -92
- package/dist/src/roster/library.d.ts.map +1 -1
- package/dist/src/roster/library.js +25 -64
- package/dist/src/roster/library.js.map +1 -1
- package/dist/src/roster/lists.d.ts +195 -0
- package/dist/src/roster/lists.d.ts.map +1 -0
- package/dist/src/roster/lists.js +233 -0
- package/dist/src/roster/lists.js.map +1 -0
- package/dist/src/roster/rules.d.ts +17 -260
- package/dist/src/roster/rules.d.ts.map +1 -1
- package/dist/src/roster/rules.js +135 -132
- package/dist/src/roster/rules.js.map +1 -1
- package/dist/src/roster/targets.d.ts +115 -0
- package/dist/src/roster/targets.d.ts.map +1 -0
- package/dist/src/roster/targets.js +213 -0
- package/dist/src/roster/targets.js.map +1 -0
- package/dist/src/roster/times.d.ts +251 -0
- package/dist/src/roster/times.d.ts.map +1 -0
- package/dist/src/roster/times.js +174 -0
- package/dist/src/roster/times.js.map +1 -0
- package/dist/src/roster/types.d.ts +828 -183
- package/dist/src/roster/types.d.ts.map +1 -1
- package/dist/src/roster/types.js +224 -97
- package/dist/src/roster/types.js.map +1 -1
- package/dist/src/schedule/accessor.d.ts +28 -0
- package/dist/src/schedule/accessor.d.ts.map +1 -0
- package/dist/src/schedule/accessor.js +39 -0
- package/dist/src/schedule/accessor.js.map +1 -0
- package/dist/src/schedule/events.d.ts +170 -42
- package/dist/src/schedule/events.d.ts.map +1 -1
- package/dist/src/schedule/events.js +431 -171
- package/dist/src/schedule/events.js.map +1 -1
- package/dist/src/schedule/index.d.ts +41 -4
- package/dist/src/schedule/index.d.ts.map +1 -1
- package/dist/src/schedule/index.js +35 -3
- package/dist/src/schedule/index.js.map +1 -1
- package/dist/src/schedule/library.d.ts +13 -3
- package/dist/src/schedule/library.d.ts.map +1 -1
- package/dist/src/schedule/library.js +11 -4
- package/dist/src/schedule/library.js.map +1 -1
- package/dist/src/schedule/periods.d.ts +115 -0
- package/dist/src/schedule/periods.d.ts.map +1 -0
- package/dist/src/schedule/periods.js +215 -0
- package/dist/src/schedule/periods.js.map +1 -0
- package/dist/src/schedule/record-window.d.ts +25 -3
- package/dist/src/schedule/record-window.d.ts.map +1 -1
- package/dist/src/schedule/record-window.js +31 -18
- package/dist/src/schedule/record-window.js.map +1 -1
- package/dist/src/schedule/resources.d.ts +82 -4
- package/dist/src/schedule/resources.d.ts.map +1 -1
- package/dist/src/schedule/resources.js +44 -14
- package/dist/src/schedule/resources.js.map +1 -1
- package/dist/src/schedule/session.d.ts +69 -0
- package/dist/src/schedule/session.d.ts.map +1 -0
- package/dist/src/schedule/session.js +121 -0
- package/dist/src/schedule/session.js.map +1 -0
- package/dist/src/schedule/templates.d.ts +14 -2
- package/dist/src/schedule/templates.d.ts.map +1 -1
- package/dist/src/schedule/templates.js +5 -3
- package/dist/src/schedule/templates.js.map +1 -1
- package/dist/src/schedule/types.d.ts +1671 -37
- package/dist/src/schedule/types.d.ts.map +1 -1
- package/dist/src/schedule/types.js +196 -5
- package/dist/src/schedule/types.js.map +1 -1
- package/dist/src/schedule/window.d.ts +14 -0
- package/dist/src/schedule/window.d.ts.map +1 -1
- package/dist/src/schedule/window.js +14 -4
- package/dist/src/schedule/window.js.map +1 -1
- package/dist/src/schedule/words.d.ts +22 -0
- package/dist/src/schedule/words.d.ts.map +1 -0
- package/dist/src/schedule/words.js +25 -0
- package/dist/src/schedule/words.js.map +1 -0
- package/dist/src/sheet/index.d.ts +61 -27
- package/dist/src/sheet/index.d.ts.map +1 -1
- package/dist/src/sheet/index.js +59 -25
- package/dist/src/sheet/index.js.map +1 -1
- package/dist/src/sheet/library.d.ts +21 -3
- package/dist/src/sheet/library.d.ts.map +1 -1
- package/dist/src/sheet/library.js +23 -6
- package/dist/src/sheet/library.js.map +1 -1
- package/dist/src/sheet/registers.d.ts +100 -85
- package/dist/src/sheet/registers.d.ts.map +1 -1
- package/dist/src/sheet/registers.js +100 -85
- package/dist/src/sheet/registers.js.map +1 -1
- package/dist/src/sheet/root.d.ts +8 -12
- package/dist/src/sheet/root.d.ts.map +1 -1
- package/dist/src/sheet/root.js +6 -40
- package/dist/src/sheet/root.js.map +1 -1
- package/dist/src/sheet/sheet.d.ts +598 -2349
- package/dist/src/sheet/sheet.d.ts.map +1 -1
- package/dist/src/sheet/sheet.js +124 -37
- package/dist/src/sheet/sheet.js.map +1 -1
- package/dist/src/sheet/sub-rows.d.ts +74 -28
- package/dist/src/sheet/sub-rows.d.ts.map +1 -1
- package/dist/src/sheet/sub-rows.js +74 -28
- package/dist/src/sheet/sub-rows.js.map +1 -1
- package/dist/src/sheet/templates.d.ts +98 -34
- package/dist/src/sheet/templates.d.ts.map +1 -1
- package/dist/src/sheet/templates.js +102 -58
- package/dist/src/sheet/templates.js.map +1 -1
- package/dist/src/sheet/types.d.ts +289 -1359
- package/dist/src/sheet/types.d.ts.map +1 -1
- package/dist/src/sheet/types.js +20 -26
- package/dist/src/sheet/types.js.map +1 -1
- package/dist/src/sheet/views.d.ts +10 -11
- package/dist/src/sheet/views.d.ts.map +1 -1
- package/dist/src/sheet/views.js +15 -20
- package/dist/src/sheet/views.js.map +1 -1
- package/dist/src/{roster/visibility.d.ts → utils/key-visibility.d.ts} +42 -7
- package/dist/src/utils/key-visibility.d.ts.map +1 -0
- package/dist/src/utils/key-visibility.js +36 -0
- package/dist/src/utils/key-visibility.js.map +1 -0
- package/dist/src/utils/ordered-source.d.ts +1 -0
- package/dist/src/utils/ordered-source.d.ts.map +1 -1
- package/dist/src/utils/ordered-source.js +8 -3
- package/dist/src/utils/ordered-source.js.map +1 -1
- package/dist/src/utils/record-sources.d.ts +107 -0
- package/dist/src/utils/record-sources.d.ts.map +1 -0
- package/dist/src/utils/record-sources.js +132 -0
- package/dist/src/utils/record-sources.js.map +1 -0
- package/dist/test/allocation/allocation.examples.d.ts +2902 -0
- package/dist/test/allocation/allocation.examples.d.ts.map +1 -0
- package/dist/test/allocation/allocation.examples.js +643 -0
- package/dist/test/allocation/allocation.examples.js.map +1 -0
- package/dist/test/allocation/fit.examples.d.ts +546 -0
- package/dist/test/allocation/fit.examples.d.ts.map +1 -0
- package/dist/test/allocation/fit.examples.js +171 -0
- package/dist/test/allocation/fit.examples.js.map +1 -0
- package/dist/test/allocation/kiln-yard.d.ts +181 -0
- package/dist/test/allocation/kiln-yard.d.ts.map +1 -0
- package/dist/test/allocation/kiln-yard.js +228 -0
- package/dist/test/allocation/kiln-yard.js.map +1 -0
- package/dist/test/bind/data/data.examples.d.ts +651 -1
- package/dist/test/bind/data/data.examples.d.ts.map +1 -1
- package/dist/test/bind/data/data.examples.js +140 -2
- package/dist/test/bind/data/data.examples.js.map +1 -1
- package/dist/test/bind/func/func.examples.d.ts +10 -1
- package/dist/test/bind/func/func.examples.d.ts.map +1 -1
- package/dist/test/bind/func/func.examples.js +8 -1
- package/dist/test/bind/func/func.examples.js.map +1 -1
- package/dist/test/bind/record/record.examples.d.ts +633 -1
- package/dist/test/bind/record/record.examples.d.ts.map +1 -1
- package/dist/test/bind/record/record.examples.js +26 -2
- package/dist/test/bind/record/record.examples.js.map +1 -1
- package/dist/test/calendar/calendar-records.examples.d.ts.map +1 -1
- package/dist/test/calendar/calendar-records.examples.js +18 -14
- package/dist/test/calendar/calendar-records.examples.js.map +1 -1
- package/dist/test/calendar/calendar.examples.d.ts +521 -16
- package/dist/test/calendar/calendar.examples.d.ts.map +1 -1
- package/dist/test/calendar/calendar.examples.js +182 -135
- package/dist/test/calendar/calendar.examples.js.map +1 -1
- package/dist/test/examples-package.d.ts +75 -0
- package/dist/test/examples-package.d.ts.map +1 -0
- package/dist/test/examples-package.js +263 -0
- package/dist/test/examples-package.js.map +1 -0
- package/dist/test/flowchart/flowchart.examples.d.ts +211 -19
- package/dist/test/flowchart/flowchart.examples.d.ts.map +1 -1
- package/dist/test/flowchart/flowchart.examples.js +102 -75
- package/dist/test/flowchart/flowchart.examples.js.map +1 -1
- package/dist/test/plan/plan-events.examples.d.ts +1439 -209
- package/dist/test/plan/plan-events.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-events.examples.js +199 -59
- package/dist/test/plan/plan-events.examples.js.map +1 -1
- package/dist/test/plan/plan-records.examples.d.ts +420 -0
- package/dist/test/plan/plan-records.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-records.examples.js +70 -19
- package/dist/test/plan/plan-records.examples.js.map +1 -1
- package/dist/test/plan/plan-windows.examples.d.ts +636 -55
- package/dist/test/plan/plan-windows.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-windows.examples.js +69 -33
- package/dist/test/plan/plan-windows.examples.js.map +1 -1
- package/dist/test/plan/plan.examples.d.ts +153 -31
- package/dist/test/plan/plan.examples.d.ts.map +1 -1
- package/dist/test/plan/plan.examples.js +178 -101
- package/dist/test/plan/plan.examples.js.map +1 -1
- package/dist/test/roster/domain.examples.d.ts +467 -250
- package/dist/test/roster/domain.examples.d.ts.map +1 -1
- package/dist/test/roster/domain.examples.js +92 -29
- package/dist/test/roster/domain.examples.js.map +1 -1
- package/dist/test/roster/roster-records.examples.d.ts +430 -586
- package/dist/test/roster/roster-records.examples.d.ts.map +1 -1
- package/dist/test/roster/roster-records.examples.js +102 -43
- package/dist/test/roster/roster-records.examples.js.map +1 -1
- package/dist/test/roster/roster.examples.d.ts +2319 -606
- package/dist/test/roster/roster.examples.d.ts.map +1 -1
- package/dist/test/roster/roster.examples.js +456 -148
- package/dist/test/roster/roster.examples.js.map +1 -1
- package/dist/test/roster/warehouse.d.ts +172 -63
- package/dist/test/roster/warehouse.d.ts.map +1 -1
- package/dist/test/roster/warehouse.js +172 -39
- package/dist/test/roster/warehouse.js.map +1 -1
- package/dist/test/schedule/schedule.examples.d.ts +3499 -0
- package/dist/test/schedule/schedule.examples.d.ts.map +1 -0
- package/dist/test/schedule/schedule.examples.js +192 -0
- package/dist/test/schedule/schedule.examples.js.map +1 -0
- package/dist/test/sheet/sheet-records.examples.d.ts.map +1 -1
- package/dist/test/sheet/sheet-records.examples.js +22 -18
- package/dist/test/sheet/sheet-records.examples.js.map +1 -1
- package/dist/test/sheet/sheet.examples.d.ts +715 -26
- package/dist/test/sheet/sheet.examples.d.ts.map +1 -1
- package/dist/test/sheet/sheet.examples.js +204 -130
- package/dist/test/sheet/sheet.examples.js.map +1 -1
- package/package.json +17 -10
- package/dist/src/roster/people.d.ts +0 -50
- package/dist/src/roster/people.d.ts.map +0 -1
- package/dist/src/roster/people.js +0 -32
- package/dist/src/roster/people.js.map +0 -1
- package/dist/src/roster/visibility.d.ts.map +0 -1
- package/dist/src/roster/visibility.js +0 -25
- package/dist/src/roster/visibility.js.map +0 -1
|
@@ -20,6 +20,16 @@
|
|
|
20
20
|
* events on one resource at once are a conflict (`overlaps`), and the kind's
|
|
21
21
|
* own inspector for one event (`inspector`, #1197).
|
|
22
22
|
*
|
|
23
|
+
* The builders over the app's own records take their roles beside Plan's
|
|
24
|
+
* (#1367, `Builder Interfaces Spec.md` §4.1): the Roster's — the fields a
|
|
25
|
+
* duty's shift, group, position and activity are (`shift`, `group`,
|
|
26
|
+
* `position`, `activity`), and the hours it counts (`hours`, an accessor) —
|
|
27
|
+
* and the Allocation's — the fields a bin's arrival, parts, hold and kind are
|
|
28
|
+
* (`arrival`, `parts`, `hold`, `kind`). A kind is one builder's or the
|
|
29
|
+
* other's. A builder ignores the roles it has no use for, so one record of
|
|
30
|
+
* duties drives a Calendar and the Roster at once. `title` is optional: the
|
|
31
|
+
* Calendar and Plan, which draw it, refuse a kind without one.
|
|
32
|
+
*
|
|
23
33
|
* The kind closes the record behind East functions over beast2 bytes
|
|
24
34
|
* ({@link ScheduleKindType}): its events over a window and its backlog, each
|
|
25
35
|
* with the drafts in place; a gesture written into an entry; the author's
|
|
@@ -28,13 +38,15 @@
|
|
|
28
38
|
* true })`); and its history. A builder's payload is one type whatever the
|
|
29
39
|
* records hold, and the renderer never needs a row type.
|
|
30
40
|
*
|
|
31
|
-
* A
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
41
|
+
* A builder's `Slice.bindRecords` narrows a kind through the source it names
|
|
42
|
+
* after the kind's slot (#1343): the builder hands that part to `build(slot,
|
|
43
|
+
* part)`, and the kind reads overlap queries through its declared interval
|
|
44
|
+
* indexes (the source's `range` naming the start field). It shares the
|
|
45
|
+
* toolbar's filters and window, counts original events once, and reads backlog
|
|
46
|
+
* through the same choices with an Unset start. It requires `entries` for
|
|
47
|
+
* original-key inspection and Save. Existing drafts outside a new narrowing
|
|
48
|
+
* remain in the session; Save includes them. A kind narrowed so takes no
|
|
49
|
+
* `window` or `backlogWindow`.
|
|
38
50
|
*
|
|
39
51
|
* A large record may also be read a window at a time (#1199, `window.ts`): given
|
|
40
52
|
* `window`, a paged read of a day index keyed by `Schedule.days`, the kind's
|
|
@@ -50,36 +62,41 @@
|
|
|
50
62
|
* editing session's, which is a session over the record's revision rather
|
|
51
63
|
* than its snapshot — its drafts held by key, each checked by the record
|
|
52
64
|
* against what it began from, and a Save's entries read back by key. It builds
|
|
53
|
-
*
|
|
54
|
-
* `build(slot)` is the Calendar's kind, which takes no notice of Plan's
|
|
55
|
-
* options
|
|
56
|
-
* kind with how it draws, its roles, and its events as Plan draws them
|
|
65
|
+
* four ways:
|
|
66
|
+
* `build(slot, part)` is the Calendar's kind, which takes no notice of Plan's
|
|
67
|
+
* options; `buildPlan(slot, part)` Plan's ({@link PlanEventKindType}), the
|
|
68
|
+
* same kind with how it draws, its roles, and its events as Plan draws them;
|
|
69
|
+
* and `buildRoster(slot, part)` the Roster's ({@link ScheduleRosterKindType})
|
|
70
|
+
* and `buildAllocation(slot, part)` the Allocation's
|
|
71
|
+
* ({@link ScheduleAllocationKindType}): the Calendar's kind, its form over the
|
|
72
|
+
* fields none of the builder's roles writes, with the stored rows of a
|
|
73
|
+
* period, and the builder's roles read from a row and written into one —
|
|
74
|
+
* every other field of the row as it was (B1), a new row's its type's
|
|
75
|
+
* default.
|
|
57
76
|
*
|
|
58
77
|
* A record may be keyed by any type: an event is named by its key's text, a
|
|
59
78
|
* String key as it is, any other key as East prints it.
|
|
60
79
|
*
|
|
61
80
|
* @packageDocumentation
|
|
62
81
|
*/
|
|
63
|
-
import { ArrayType, BlobType, BooleanType, DateTimeType, DictType, East, Expr, FloatType, IntegerType, OptionType, StringType, StructType, isTypeEqual, none, printType, some, toEastTypeValue, variant, } from "@elaraai/east";
|
|
64
|
-
import { EventStateType } from "@elaraai/east-ui";
|
|
65
|
-
import {
|
|
66
|
-
import { Record } from "../bind/record.js";
|
|
82
|
+
import { ArrayType, BlobType, BooleanType, DateTimeType, DictType, East, Expr, FloatType, IntegerType, OptionType, StringType, StructType, defaultValue, isTypeEqual, none, printType, some, toEastTypeValue, variant, } from "@elaraai/east";
|
|
83
|
+
import { EventStateType, TimeStepType } from "@elaraai/east-ui";
|
|
84
|
+
import { EditingDraftFieldType, EditingReadinessType, Fields, FieldSpecType, TickFormatType } from "@elaraai/east-ui/internal";
|
|
67
85
|
import { RowInspectorType, rowInspector } from "../utils/row-inspector.js";
|
|
86
|
+
import { scheduleAccessor } from "./accessor.js";
|
|
68
87
|
import { SCHEDULE_TEMPLATES, checkedTemplates } from "./templates.js";
|
|
69
88
|
import { SCHEDULE_DEF } from "./resources.js";
|
|
70
89
|
import { scheduleRecordWindow } from "./record-window.js";
|
|
71
|
-
import {
|
|
72
|
-
import {
|
|
90
|
+
import { scheduleRecordSession } from "./session.js";
|
|
91
|
+
import { checkEntries, checkIndexWindow, optionOf, scheduleBacklogWindow, scheduleDayWindow, typeText } from "./window.js";
|
|
92
|
+
import { PlanEventItemType, PlanEventKindType, PlanEventReadType, ScheduleAllocationEntryType, ScheduleAllocationKindType, ScheduleAllocationRolesType, ScheduleClockType, ScheduleDraftsType, ScheduleDurationType, ScheduleItemType, ScheduleKindType, ScheduleReadyEntryType, ScheduleResourceRefType, ScheduleRosterEntryType, ScheduleRosterKindType, ScheduleRosterRolesType, ScheduleStatusCasesFor, ScheduleStatusType, ScheduleWriteType, ScheduleTemplateType, ScheduleReadType, } from "./types.js";
|
|
93
|
+
/** The Roster's roles, as a kind's options name them. */
|
|
94
|
+
const ROSTER_ROLES = ["shift", "group", "position", "activity", "hours"];
|
|
95
|
+
/** The Allocation's roles, as a kind's options name them. */
|
|
96
|
+
const ALLOCATION_ROLES = ["arrival", "parts", "hold", "kind"];
|
|
73
97
|
// ============================================================================
|
|
74
98
|
// Reading East types
|
|
75
99
|
// ============================================================================
|
|
76
|
-
/** Whether a type is an Option, and of what. */
|
|
77
|
-
function optionOf(type) {
|
|
78
|
-
if (type.type !== "Variant")
|
|
79
|
-
return undefined;
|
|
80
|
-
const some = type.cases["some"];
|
|
81
|
-
return some !== undefined && isTypeEqual(type, OptionType(some)) ? some : undefined;
|
|
82
|
-
}
|
|
83
100
|
/** A variant's cases, when every one of them holds a String. */
|
|
84
101
|
function stringCases(type) {
|
|
85
102
|
if (type.type !== "Variant" || optionOf(type) !== undefined)
|
|
@@ -91,17 +108,19 @@ function stringCases(type) {
|
|
|
91
108
|
function fieldOf(row, name) {
|
|
92
109
|
return row[name];
|
|
93
110
|
}
|
|
94
|
-
/** A type as the refusals name it: an Option as an Option of what it holds. */
|
|
95
|
-
function typeText(type) {
|
|
96
|
-
const inner = optionOf(type);
|
|
97
|
-
return inner === undefined ? printType(type) : `an Option of ${printType(inner)}`;
|
|
98
|
-
}
|
|
99
111
|
/** The ways a kind draws. */
|
|
100
112
|
const DRAWS = ["span", "buckets", "cards", "marks"];
|
|
101
113
|
export function scheduleEvents(record, input) {
|
|
102
114
|
const config = input;
|
|
103
115
|
const where = `Schedule.events: "${config.name}"`;
|
|
104
|
-
|
|
116
|
+
// The options #1343 moved to the builder, refused by name for an app that still passes them.
|
|
117
|
+
if ("slice" in config) {
|
|
118
|
+
throw new Error(`${where}: \`slice\` moves to the builder — name a source of its Slice.bindRecords after this kind's slot, ` +
|
|
119
|
+
"slice={{ slice: Slice.bindRecords(key, { <slot>: { source, fields, range } }) }}, and the builder narrows the kind through it");
|
|
120
|
+
}
|
|
121
|
+
if ("filter" in config) {
|
|
122
|
+
throw new Error(`${where}: \`filter\` is gone — narrow the kind through its builder's Slice.bindRecords, a source named after its slot, over the record's indexes`);
|
|
123
|
+
}
|
|
105
124
|
const handleType = Expr.type(record);
|
|
106
125
|
const read = handleType.type === "Struct" ? handleType.fields["read"] : undefined;
|
|
107
126
|
if (handleType.type !== "Struct" || read === undefined || read.type !== "Function"
|
|
@@ -121,9 +140,10 @@ export function scheduleEvents(record, input) {
|
|
|
121
140
|
throw new Error(`${where}: \`${prop}\` names "${name}", a field the row does not have (${Object.keys(fields).join(", ")})`);
|
|
122
141
|
return type;
|
|
123
142
|
};
|
|
124
|
-
// The title.
|
|
125
|
-
|
|
126
|
-
|
|
143
|
+
// The title: optional, as the Roster and the Allocation draw none (#1367); the Calendar and Plan refuse a kind without one.
|
|
144
|
+
const titleField = config.title;
|
|
145
|
+
if (titleField !== undefined && !isTypeEqual(fieldType("title", titleField), StringType)) {
|
|
146
|
+
throw new Error(`${where}: \`title\` names a String field — "${titleField}" holds ${typeText(fields[titleField])}`);
|
|
127
147
|
}
|
|
128
148
|
// The times: `start` and `end`, DateTime or Options of DateTime alike; or an instant kind's `at`, in their place.
|
|
129
149
|
const instantKind = config.at !== undefined;
|
|
@@ -229,6 +249,33 @@ export function scheduleEvents(record, input) {
|
|
|
229
249
|
const stateField = role("state", config.state, EventStateType, "an EventStateType field, the lifecycle an event wears");
|
|
230
250
|
const quantityField = role("quantity.field", config.quantity === undefined ? undefined : config.quantity.field, FloatType, "a Float field, the quantity a bar prints");
|
|
231
251
|
const laneField = role("lane", config.lane, StringType, "a String field, the lane a tile sits in");
|
|
252
|
+
// The builders' roles (#1367, `Builder Interfaces Spec.md` §4.1), each a field of the row, checked as Plan's are. A
|
|
253
|
+
// kind is the Roster's duties or the Allocation's bins, never both.
|
|
254
|
+
const given = (roles) => roles.filter((r) => config[r] !== undefined);
|
|
255
|
+
const rosterGiven = given(ROSTER_ROLES);
|
|
256
|
+
const allocationGiven = given(ALLOCATION_ROLES);
|
|
257
|
+
if (rosterGiven.length > 0 && allocationGiven.length > 0) {
|
|
258
|
+
throw new Error(`${where}: holds roles of both the Roster (${rosterGiven.join(", ")}) and the Allocation (${allocationGiven.join(", ")}) — ` +
|
|
259
|
+
"a kind is the Roster's duties or the Allocation's bins: give it one builder's roles");
|
|
260
|
+
}
|
|
261
|
+
const shiftField = role("shift", config.shift, StringType, "a String field");
|
|
262
|
+
const groupField = role("group", config.group, StringType, "a String field");
|
|
263
|
+
const positionField = role("position", config.position, StringType, "a String field");
|
|
264
|
+
const activityField = role("activity", config.activity, OptionType(StringType), "an Option of a String field");
|
|
265
|
+
const arrivalField = role("arrival", config.arrival, OptionType(StringType), "an Option of a String field");
|
|
266
|
+
const partsField = role("parts.field", config.parts === undefined ? undefined : config.parts.field, DictType(StringType, FloatType), "a Dict of String to Float field");
|
|
267
|
+
if (config.parts !== undefined && (typeof config.parts.of !== "string" || config.parts.of === "")) {
|
|
268
|
+
throw new Error(`${where}: \`parts.of\` names the resource slot its keys are of — the builder's resources a bin is allocated to (of: "kilns")`);
|
|
269
|
+
}
|
|
270
|
+
const holdField = role("hold", config.hold, TimeStepType, "a TimeStep field");
|
|
271
|
+
const kindField = role("kind", config.kind, OptionType(StringType), "an Option of a String field");
|
|
272
|
+
// The fields none of the Allocation's roles maps (#1371): what an arrival's values give a booked bin (B13) — every
|
|
273
|
+
// field but its time, its lane and its roles' fields — which the Allocation reads at build, and `buildAllocation` writes.
|
|
274
|
+
const allocationMapped = new Set([startField, endField, ...[resource?.field, arrivalField, quantityField, partsField, holdField, kindField]
|
|
275
|
+
.filter((name) => name !== undefined)]);
|
|
276
|
+
const allocationValues = StructType(Object.fromEntries(Object.entries(fields).filter(([name]) => !allocationMapped.has(name))));
|
|
277
|
+
// The hours a duty counts, reified once and called per row.
|
|
278
|
+
const hoursOf = config.hours === undefined ? undefined : scheduleAccessor(rowType, keyType, FloatType, config.hours, (returns) => `${where}: \`hours\` returns a Float, the hours a duty counts — and this one returns ${returns}`);
|
|
232
279
|
// The removed verdict, named (#1260) — a plain JS caller would otherwise lose it silently.
|
|
233
280
|
if ("review" in config) {
|
|
234
281
|
throw new Error(`${where}: \`review\` is removed (#1260) — a Plan approves and rejects nothing: its changes are drafts of its session, saved together`);
|
|
@@ -241,6 +288,17 @@ export function scheduleEvents(record, input) {
|
|
|
241
288
|
const valuesType = StructType(Object.fromEntries(Object.entries(fields).filter(([name]) => !placed.has(name))));
|
|
242
289
|
const boundTemplates = config.templates !== undefined && SCHEDULE_TEMPLATES in config.templates
|
|
243
290
|
? checkedTemplates(config.templates, valuesType, where) : undefined;
|
|
291
|
+
// A templates record's events run as long as each says, or — an instant kind's — are one time (#1344).
|
|
292
|
+
if (config.templates !== undefined && SCHEDULE_TEMPLATES in config.templates) {
|
|
293
|
+
if (!instantKind && !config.templates.timed) {
|
|
294
|
+
throw new Error(`${where}: its templates give each event's \`duration\` — Schedule.templates(rows, { …, duration: (row) => variant("hours", …) }), how long the event a template creates runs`);
|
|
295
|
+
}
|
|
296
|
+
if (instantKind && config.templates.timed) {
|
|
297
|
+
throw new Error(`${where}: an instant kind's events are one time, and its templates give a \`duration\` — leave it out of Schedule.templates`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// The builder's source whose shown keys filter the templates: the one a templates list names (#1343).
|
|
301
|
+
const templatesSource = config.templates !== undefined && SCHEDULE_TEMPLATES in config.templates ? config.templates.source : undefined;
|
|
244
302
|
const templates = config.templates !== undefined && !(SCHEDULE_TEMPLATES in config.templates) ? config.templates : [];
|
|
245
303
|
const seen = new Set();
|
|
246
304
|
for (const t of templates) {
|
|
@@ -255,9 +313,6 @@ export function scheduleEvents(record, input) {
|
|
|
255
313
|
}
|
|
256
314
|
}
|
|
257
315
|
// The windows (#1199): the days in view through a day index, the backlog through a backlog index.
|
|
258
|
-
if (config.slice !== undefined && (config.window !== undefined || config.backlogWindow !== undefined || config.filter !== undefined)) {
|
|
259
|
-
throw new Error(`${where}: slice replaces window, backlogWindow and local filter; narrow through the record's indexes`);
|
|
260
|
-
}
|
|
261
316
|
const dayWindow = config.window === undefined ? undefined
|
|
262
317
|
: checkIndexWindow(config.window, "window", keyType, rowType, DateTimeType, where);
|
|
263
318
|
let backlogWindow;
|
|
@@ -275,34 +330,24 @@ export function scheduleEvents(record, input) {
|
|
|
275
330
|
// Nor one event: it is read by its key through the record's own entries.
|
|
276
331
|
let entries;
|
|
277
332
|
if (config.entries !== undefined) {
|
|
278
|
-
if (dayWindow === undefined && config.slice === undefined) {
|
|
279
|
-
throw new Error(`${where}: \`entries\` reads one event by its key beside \`window\` or record \`slice\` — give one of those with it`);
|
|
280
|
-
}
|
|
281
333
|
entries = checkEntries(config.entries, keyType, rowType, `${where}: \`entries\``);
|
|
282
334
|
}
|
|
283
|
-
else if (dayWindow !== undefined
|
|
335
|
+
else if (dayWindow !== undefined) {
|
|
284
336
|
throw new Error(`${where}: an indexed kind reads only the window — and one event, the inspector's ` +
|
|
285
337
|
"or its editing's, is read by its key: give `entries` beside it, Data.bindPaged(record), the record's own entries");
|
|
286
338
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
//
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
// The
|
|
293
|
-
//
|
|
294
|
-
const
|
|
339
|
+
// The record's session (`session.ts`): its reads, whole and by key, and its Save, one patch commit through the
|
|
340
|
+
// record's patch door, its entries checked against what the drafts began from — declared now, so a record bound
|
|
341
|
+
// without its patch door is refused where its kind is.
|
|
342
|
+
const session = scheduleRecordSession(record, keyType, rowType, entries);
|
|
343
|
+
const { readAll, byKey, idOf, keyOf } = session;
|
|
344
|
+
// The inspector's form: the fields a gesture does not write, in the hints' order. A builder over the app's own
|
|
345
|
+
// records draws its roles in its own sections, so its form leaves out the fields they name too.
|
|
346
|
+
const formOver = (omitted) => Fields.specs(rowType, (config.fields ?? {}), [...new Set(omitted.filter((name) => name !== undefined))]);
|
|
347
|
+
const formSpecs = formOver([titleField, ...placed, config.status?.field]);
|
|
295
348
|
// ── The East the seams share ─────────────────────────────────────────
|
|
296
349
|
const draftType = EditingDraftFieldType(rowType);
|
|
297
350
|
const EntryRowType = StructType({ id: StringType, key: keyType, row: rowType });
|
|
298
|
-
const readAll = handle["read"];
|
|
299
|
-
// An entry's id is its key's text: a String key as it is, any other key as East prints it.
|
|
300
|
-
const idOf = (keyType.type === "String"
|
|
301
|
-
? East.function([StringType], StringType, (_$, key) => key)
|
|
302
|
-
: East.function([keyType], StringType, (_$, key) => East.print(key)));
|
|
303
|
-
const keyOf = (keyType.type === "String"
|
|
304
|
-
? East.function([StringType], StringType, (_$, id) => id)
|
|
305
|
-
: East.function([StringType], keyType, (_$, id) => id.parse(keyType)));
|
|
306
351
|
// The entry a draft leaves: the drafted entry, none for one deleted, the held one for a draft it cannot read.
|
|
307
352
|
const drafted = East.function([BlobType, OptionType(rowType)], OptionType(rowType), (_$, bytes, held) => bytes.decodeBeast(draftType, "v2").match({
|
|
308
353
|
value: (_$2, row) => East.value(some(row), OptionType(rowType)),
|
|
@@ -313,7 +358,7 @@ export function scheduleEvents(record, input) {
|
|
|
313
358
|
// entries it does not hold: a draft moved into a window shows, and one moved out of it leaves by its times.
|
|
314
359
|
// Erased as the record's own read is, so the record whole and a window of it are one type.
|
|
315
360
|
const HeldType = DictType(keyType, rowType);
|
|
316
|
-
const
|
|
361
|
+
const withDraftsFor = (narrowed) => East.function([HeldType, ScheduleDraftsType], ArrayType(EntryRowType), ($, held, drafts) => {
|
|
317
362
|
const idText = $.const(idOf);
|
|
318
363
|
const parse = $.const(keyOf);
|
|
319
364
|
const draft = $.const(drafted);
|
|
@@ -332,7 +377,7 @@ export function scheduleEvents(record, input) {
|
|
|
332
377
|
// Existing drafts outside an indexed result stay in the session,
|
|
333
378
|
// but do not leak back into a different narrowing. New entries
|
|
334
379
|
// remain an explicit unsaved layer until their first Save.
|
|
335
|
-
if (
|
|
380
|
+
if (narrowed && byKey !== undefined) {
|
|
336
381
|
const find = $3.const(byKey);
|
|
337
382
|
$3.if(find(id).hasTag("absent").not(), $4 => { $4.continue(label); });
|
|
338
383
|
}
|
|
@@ -461,44 +506,73 @@ export function scheduleEvents(record, input) {
|
|
|
461
506
|
}
|
|
462
507
|
};
|
|
463
508
|
collect(rowType, []);
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
509
|
+
const readsOf = (slot, part) => {
|
|
510
|
+
if (part === undefined) {
|
|
511
|
+
if (entries !== undefined && dayWindow === undefined) {
|
|
512
|
+
throw new Error(`${where}: \`entries\` reads one event by its key beside \`window\`, or beside the kind's source of its builder's ` +
|
|
513
|
+
`Slice.bindRecords (one named "${slot}") — give one of those with it`);
|
|
514
|
+
}
|
|
515
|
+
const unscheduled = backlogWindow === undefined ? undefined : scheduleBacklogWindow(backlogWindow, keyType, rowType, where);
|
|
516
|
+
return {
|
|
517
|
+
days: dayWindow === undefined ? undefined : scheduleDayWindow(dayWindow, keyType, rowType, where),
|
|
518
|
+
// A backlog index's read takes no window: the window is given, and read past.
|
|
519
|
+
backlog: unscheduled === undefined ? undefined : East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, _from, _to) => {
|
|
520
|
+
const read = $.const(unscheduled);
|
|
521
|
+
return read();
|
|
522
|
+
}),
|
|
523
|
+
withDrafts: withDraftsFor(false),
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
if (dayWindow !== undefined || backlogWindow !== undefined) {
|
|
527
|
+
throw new Error(`${where}: the builder's source "${slot}" narrows this kind through its record's indexes — leave \`window\` and \`backlogWindow\` out`);
|
|
528
|
+
}
|
|
529
|
+
if (entries === undefined) {
|
|
530
|
+
throw new Error(`${where}: the builder's source "${slot}" reads only its narrowing — and one event, the inspector's ` +
|
|
531
|
+
"or its editing's, is read by its key: give `entries` beside it, Data.bindPaged(record), the record's own entries");
|
|
532
|
+
}
|
|
533
|
+
const scheduled = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, false, where);
|
|
534
|
+
if (!optional)
|
|
535
|
+
return { days: scheduled, backlog: undefined, withDrafts: withDraftsFor(true) };
|
|
536
|
+
// A kind with a backlog reads both through its source as one: what its narrowing holds over the window and in
|
|
537
|
+
// its backlog. A draft then moves an event between the two by its times alone, and a draft the narrowing does
|
|
538
|
+
// not hold never shows in either (#1343).
|
|
539
|
+
const backlogged = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, true, where);
|
|
540
|
+
const both = East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, from, to) => {
|
|
541
|
+
const inWindow = $.const(scheduled);
|
|
542
|
+
const inBacklog = $.const(backlogged);
|
|
543
|
+
const result = $.let(East.value(none, OptionType(HeldType)), OptionType(HeldType));
|
|
544
|
+
$.match(inWindow(from, to), {
|
|
545
|
+
some: ($2, rows) => {
|
|
546
|
+
$2.match(inBacklog(from, to), {
|
|
547
|
+
some: ($3, more) => {
|
|
548
|
+
const all = $3.let(rows.copy());
|
|
549
|
+
$3(all.unionInPlace(more, (_$4, held) => held));
|
|
550
|
+
$3.assign(result, East.value(some(all), OptionType(HeldType)));
|
|
551
|
+
},
|
|
552
|
+
});
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
return result;
|
|
476
556
|
});
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
// Adapt the author's typed predicate once; Slice owns its semantics and state.
|
|
480
|
-
const filter = config.filter === undefined ? undefined
|
|
481
|
-
: East.function([rowType, keyType], BooleanType, (_$, row, key) => config.filter(row, key));
|
|
557
|
+
return { days: both, backlog: both, withDrafts: withDraftsFor(true) };
|
|
558
|
+
};
|
|
482
559
|
/** An item seam over a window: the events whose items `itemFn` makes that overlap `[from, to)`. */
|
|
483
|
-
const windowOf = (itemType, itemFn) => East.function([DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, from, to, drafts) => {
|
|
484
|
-
const inPlace = $.const(withDrafts);
|
|
560
|
+
const windowOf = (itemType, itemFn, reads) => East.function([DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, from, to, drafts) => {
|
|
561
|
+
const inPlace = $.const(reads.withDrafts);
|
|
485
562
|
const item = $.const(itemFn);
|
|
486
|
-
const accepts = filter === undefined ? undefined : $.const(filter);
|
|
487
563
|
const result = $.let(East.value(none, OptionType(ArrayType(itemType))), OptionType(ArrayType(itemType)));
|
|
488
564
|
let read;
|
|
489
|
-
if (
|
|
565
|
+
if (reads.days === undefined) {
|
|
490
566
|
read = $.let(East.value(some(readAll()), OptionType(HeldType)));
|
|
491
567
|
}
|
|
492
568
|
else {
|
|
493
|
-
const days = $.const(
|
|
569
|
+
const days = $.const(reads.days);
|
|
494
570
|
read = $.let(days(from, to));
|
|
495
571
|
}
|
|
496
572
|
$.match(read, {
|
|
497
573
|
some: ($2, rows) => {
|
|
498
574
|
const out = $2.let([], ArrayType(itemType));
|
|
499
|
-
$2.for(inPlace(rows, drafts), ($3, entry
|
|
500
|
-
if (accepts !== undefined)
|
|
501
|
-
$3.if(accepts(entry.row, entry.key).not(), $4 => { $4.continue(label); });
|
|
575
|
+
$2.for(inPlace(rows, drafts), ($3, entry) => {
|
|
502
576
|
// Every item type holds what every view draws, its start and end among them.
|
|
503
577
|
const one = $3.const(item(entry));
|
|
504
578
|
$3.match(one.start, {
|
|
@@ -520,28 +594,25 @@ export function scheduleEvents(record, input) {
|
|
|
520
594
|
});
|
|
521
595
|
return result;
|
|
522
596
|
});
|
|
523
|
-
/** An item seam over the backlog: the rows with no time, as `itemFn` makes them. */
|
|
524
|
-
const backlogOf = (itemType, itemFn) => East.function([ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, drafts) => {
|
|
597
|
+
/** An item seam over the backlog: the rows with no time, as `itemFn` makes them, the window the canvas reads given. */
|
|
598
|
+
const backlogOf = (itemType, itemFn, reads) => East.function([DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, from, to, drafts) => {
|
|
525
599
|
const result = $.let(East.value(some([]), OptionType(ArrayType(itemType))), OptionType(ArrayType(itemType)));
|
|
526
600
|
if (optional) {
|
|
527
|
-
const inPlace = $.const(withDrafts);
|
|
601
|
+
const inPlace = $.const(reads.withDrafts);
|
|
528
602
|
const item = $.const(itemFn);
|
|
529
|
-
const accepts = filter === undefined ? undefined : $.const(filter);
|
|
530
603
|
let read;
|
|
531
|
-
if (
|
|
604
|
+
if (reads.backlog === undefined) {
|
|
532
605
|
read = $.let(East.value(some(readAll()), OptionType(HeldType)));
|
|
533
606
|
}
|
|
534
607
|
else {
|
|
535
|
-
const backlog = $.const(
|
|
536
|
-
read = $.let(backlog());
|
|
608
|
+
const backlog = $.const(reads.backlog);
|
|
609
|
+
read = $.let(backlog(from, to));
|
|
537
610
|
}
|
|
538
611
|
$.assign(result, East.value(none, OptionType(ArrayType(itemType))));
|
|
539
612
|
$.match(read, {
|
|
540
613
|
some: ($2, rows) => {
|
|
541
614
|
const out = $2.let([], ArrayType(itemType));
|
|
542
|
-
$2.for(inPlace(rows, drafts), ($3, entry
|
|
543
|
-
if (accepts !== undefined)
|
|
544
|
-
$3.if(accepts(entry.row, entry.key).not(), $4 => { $4.continue(label); });
|
|
615
|
+
$2.for(inPlace(rows, drafts), ($3, entry) => {
|
|
545
616
|
const one = $3.const(item(entry));
|
|
546
617
|
$3.if(one.start.hasTag("none"), ($4) => { $4(out.pushLast(one)); });
|
|
547
618
|
});
|
|
@@ -551,7 +622,7 @@ export function scheduleEvents(record, input) {
|
|
|
551
622
|
}
|
|
552
623
|
return result;
|
|
553
624
|
});
|
|
554
|
-
const readEvent = (makeItem, readType) => East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType], OptionType(readType), ($, id, drafts, from, to) => {
|
|
625
|
+
const readEvent = (makeItem, readType, reads) => East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType], OptionType(readType), ($, id, drafts, from, to) => {
|
|
555
626
|
const parse = $.const(keyOf);
|
|
556
627
|
const make = $.const(makeItem);
|
|
557
628
|
const key = $.const(parse(id));
|
|
@@ -567,17 +638,17 @@ export function scheduleEvents(record, input) {
|
|
|
567
638
|
});
|
|
568
639
|
});
|
|
569
640
|
$.if(unread, ($2) => {
|
|
570
|
-
if (byKey === undefined ||
|
|
641
|
+
if (byKey === undefined || reads.days === undefined) {
|
|
571
642
|
const held = $2.const(readAll());
|
|
572
643
|
$2.assign(row, held.tryGet(key));
|
|
573
644
|
return;
|
|
574
645
|
}
|
|
575
|
-
const days = $2.const(
|
|
646
|
+
const days = $2.const(reads.days);
|
|
576
647
|
$2.match(days(from, to), { some: ($3, held) => { $3.assign(row, held.tryGet(key)); } });
|
|
577
|
-
if (
|
|
578
|
-
const backlog = $2.const(
|
|
648
|
+
if (reads.backlog !== undefined) {
|
|
649
|
+
const backlog = $2.const(reads.backlog);
|
|
579
650
|
$2.if(row.hasTag("none"), ($3) => {
|
|
580
|
-
$3.match(backlog(), { some: ($4, held) => { $4.assign(row, held.tryGet(key)); } });
|
|
651
|
+
$3.match(backlog(from, to), { some: ($4, held) => { $4.assign(row, held.tryGet(key)); } });
|
|
581
652
|
});
|
|
582
653
|
}
|
|
583
654
|
const find = $2.const(byKey);
|
|
@@ -590,8 +661,12 @@ export function scheduleEvents(record, input) {
|
|
|
590
661
|
none: (_$2) => East.value(none, OptionType(readType)),
|
|
591
662
|
});
|
|
592
663
|
});
|
|
593
|
-
/**
|
|
594
|
-
|
|
664
|
+
/**
|
|
665
|
+
* The Calendar's kind, part by part, under its slot and through its source's part, its form `form` — and the
|
|
666
|
+
* function that makes one of its events.
|
|
667
|
+
*/
|
|
668
|
+
const kindParts = (slot, part, form) => {
|
|
669
|
+
const reads = readsOf(slot, part);
|
|
595
670
|
// One event, as every view draws it.
|
|
596
671
|
const itemOf = East.function([EntryRowType], ScheduleItemType, ($, entry) => {
|
|
597
672
|
const row = entry.row;
|
|
@@ -626,7 +701,8 @@ export function scheduleEvents(record, input) {
|
|
|
626
701
|
return East.value({
|
|
627
702
|
kind: slot,
|
|
628
703
|
key: entry.id,
|
|
629
|
-
title
|
|
704
|
+
// A kind with no title titles its events with nothing (#1367): the Calendar and Plan refuse one.
|
|
705
|
+
title: titleField === undefined ? "" : fieldOf(row, titleField),
|
|
630
706
|
start,
|
|
631
707
|
end,
|
|
632
708
|
resource: ref(row),
|
|
@@ -635,8 +711,8 @@ export function scheduleEvents(record, input) {
|
|
|
635
711
|
due,
|
|
636
712
|
}, ScheduleItemType);
|
|
637
713
|
});
|
|
638
|
-
const items = windowOf(ScheduleItemType, itemOf);
|
|
639
|
-
const unscheduled = backlogOf(ScheduleItemType, itemOf);
|
|
714
|
+
const items = windowOf(ScheduleItemType, itemOf, reads);
|
|
715
|
+
const unscheduled = backlogOf(ScheduleItemType, itemOf, reads);
|
|
640
716
|
// Each template's values, by key, as the templates on the wire carry them.
|
|
641
717
|
const templateRows = boundTemplates ?? East.value(templates.map((t) => ({
|
|
642
718
|
key: t.key, name: t.name, group: t.group === undefined ? none : some(t.group),
|
|
@@ -714,61 +790,9 @@ export function scheduleEvents(record, input) {
|
|
|
714
790
|
});
|
|
715
791
|
});
|
|
716
792
|
})();
|
|
717
|
-
// The shared session over the record: whole-entry drafts, keyed batches, Save through the
|
|
718
|
-
//
|
|
719
|
-
|
|
720
|
-
const batchType = EditingChangeSetTypeFor(rowType, keyType);
|
|
721
|
-
const encodedEntry = (row) => East.value(some(East.Blob.encodeBeast(row, "v2")), OptionType(BlobType));
|
|
722
|
-
const readEntry = byKey === undefined
|
|
723
|
-
? East.function([StringType, IntegerType], OptionType(BlobType), ($, id, _offset) => {
|
|
724
|
-
const parse = $.const(keyOf);
|
|
725
|
-
const held = $.const(readAll());
|
|
726
|
-
return held.tryGet(parse(id)).match({
|
|
727
|
-
some: (_$2, row) => encodedEntry(row),
|
|
728
|
-
none: (_$2) => East.value(none, OptionType(BlobType)),
|
|
729
|
-
});
|
|
730
|
-
})
|
|
731
|
-
: East.function([StringType, IntegerType], OptionType(BlobType), ($, id, _offset) => {
|
|
732
|
-
const find = $.const(byKey);
|
|
733
|
-
const result = $.let(none, OptionType(BlobType));
|
|
734
|
-
$.match(find(id), { held: ($2, row) => { $2.assign(result, encodedEntry(row)); } });
|
|
735
|
-
return result;
|
|
736
|
-
});
|
|
737
|
-
const onApply = East.asyncFunction([BlobType], EditingApplyResultType, ($, blob) => {
|
|
738
|
-
const commit = $.const(apply);
|
|
739
|
-
return commit(blob.decodeBeast(batchType, "v2"));
|
|
740
|
-
});
|
|
741
|
-
const editing = East.value({
|
|
742
|
-
sourceId: handle["binding"].name,
|
|
743
|
-
entryType: toEastTypeValue(rowType),
|
|
744
|
-
idField: none,
|
|
745
|
-
draftType: toEastTypeValue(draftType),
|
|
746
|
-
children: none,
|
|
747
|
-
keyType: some(toEastTypeValue(keyType)),
|
|
748
|
-
snapshot: byKey === undefined ? some(East.Blob.encodeBeast(readAll(), "v2")) : none,
|
|
749
|
-
readEntry,
|
|
750
|
-
onPatch: none,
|
|
751
|
-
onApply: some(East.value(variant("async", onApply), EditingWireApplyType)),
|
|
752
|
-
mode: variant("batch", null),
|
|
753
|
-
}, EditingType);
|
|
754
|
-
// The record read by key (#1199): its revision and a move to another, one event's row, and its largest key.
|
|
755
|
-
let entriesSeam;
|
|
756
|
-
if (entries === undefined || byKey === undefined || lastKey === undefined) {
|
|
757
|
-
entriesSeam = East.value(none, OptionType(ScheduleEntriesType));
|
|
758
|
-
}
|
|
759
|
-
else {
|
|
760
|
-
const pinned = entries;
|
|
761
|
-
const entry = East.function([StringType], OptionType(OptionType(BlobType)), ($, id) => {
|
|
762
|
-
const find = $.const(byKey);
|
|
763
|
-
const result = $.let(none, OptionType(OptionType(BlobType)));
|
|
764
|
-
$.match(find(id), {
|
|
765
|
-
held: ($2, row) => { $2.assign(result, some(encodedEntry(row))); },
|
|
766
|
-
absent: ($2) => { $2.assign(result, some(none)); },
|
|
767
|
-
});
|
|
768
|
-
return result;
|
|
769
|
-
});
|
|
770
|
-
entriesSeam = East.value(some({ revision: pinned.revision, refresh: pinned.refresh, entry, last: lastKey }), OptionType(ScheduleEntriesType));
|
|
771
|
-
}
|
|
793
|
+
// The shared session over the record (`session.ts`): whole-entry drafts, keyed batches, Save through the
|
|
794
|
+
// patch door; its base the record's snapshot, or for a kind read a window at a time (#1199) its revision.
|
|
795
|
+
const { editing, entries: entriesSeam } = session.build();
|
|
772
796
|
const fieldsOfKind = {
|
|
773
797
|
key: slot,
|
|
774
798
|
name: config.name,
|
|
@@ -777,22 +801,76 @@ export function scheduleEvents(record, input) {
|
|
|
777
801
|
status: statusTable === undefined || statusCases === undefined ? [] : statusCases.map((c) => ({ case: c, status: fieldOf(statusTable, c) })),
|
|
778
802
|
backlog: optional,
|
|
779
803
|
templates: templateRows,
|
|
780
|
-
|
|
804
|
+
templatesSource: templatesSource === undefined ? none : some(templatesSource),
|
|
805
|
+
fields: East.value(form, ArrayType(FieldSpecType)),
|
|
781
806
|
items,
|
|
782
807
|
unscheduled,
|
|
783
808
|
write,
|
|
784
809
|
ready: ready === undefined ? none : some(ready),
|
|
785
810
|
editing,
|
|
786
811
|
entries: entriesSeam,
|
|
787
|
-
history:
|
|
788
|
-
event: readEvent(itemOf, ScheduleReadType),
|
|
789
|
-
|
|
812
|
+
history: session.history,
|
|
813
|
+
event: readEvent(itemOf, ScheduleReadType, reads),
|
|
814
|
+
// A kind with no title names none: the Calendar and Plan, whose inspectors draw it, refuse one.
|
|
815
|
+
schedule: { title: titleField ?? "", start: startField, end: endField,
|
|
790
816
|
resource: resource === undefined ? none : some(resource.field),
|
|
791
817
|
status: config.status === undefined ? none : some(config.status.field) },
|
|
792
818
|
overlaps: variant(overlaps, null),
|
|
793
819
|
inspector: inspector === undefined ? none : some(inspector),
|
|
794
820
|
};
|
|
795
|
-
return { fields: fieldsOfKind, itemOf };
|
|
821
|
+
return { fields: fieldsOfKind, itemOf, reads };
|
|
822
|
+
};
|
|
823
|
+
// ── The builders over the app's own records (#1367) ─────────────────────
|
|
824
|
+
/**
|
|
825
|
+
* The stored rows overlapping `[from, to)`, by their key's text: each its roles, read by `rolesOf` in the pass that
|
|
826
|
+
* reads the row, and the row as bytes — through the kind's reads (its source's part, its day index, or the record
|
|
827
|
+
* whole), `none` while a read is in flight. Overlap is the views' rule: a row starts before the window ends and
|
|
828
|
+
* ends after it starts, or, of no length, sits inside it. The builder puts its drafts in place itself (`Builder
|
|
829
|
+
* Interfaces Spec.md` §9). The times are plain DateTime fields: both builds refuse Option times.
|
|
830
|
+
*/
|
|
831
|
+
const storedRows = (reads, EntryType, rolesOf) => {
|
|
832
|
+
const RowsType = OptionType(DictType(StringType, EntryType));
|
|
833
|
+
return East.function([DateTimeType, DateTimeType], RowsType, ($, from, to) => {
|
|
834
|
+
const text = $.const(idOf);
|
|
835
|
+
const roles = $.const(rolesOf);
|
|
836
|
+
const result = $.let(East.value(none, RowsType), RowsType);
|
|
837
|
+
let read;
|
|
838
|
+
if (reads.days === undefined) {
|
|
839
|
+
read = $.let(East.value(some(readAll()), OptionType(HeldType)));
|
|
840
|
+
}
|
|
841
|
+
else {
|
|
842
|
+
const days = $.const(reads.days);
|
|
843
|
+
read = $.let(days(from, to));
|
|
844
|
+
}
|
|
845
|
+
$.match(read, {
|
|
846
|
+
some: ($2, held) => {
|
|
847
|
+
const out = $2.let(new Map(), DictType(StringType, EntryType));
|
|
848
|
+
$2.for(held, ($3, row, key) => {
|
|
849
|
+
const start = $3.const(fieldOf(row, startField));
|
|
850
|
+
const end = $3.const(fieldOf(row, endField));
|
|
851
|
+
$3.if(East.less(start, to).and(() => East.greater(end, from).or(() => East.greaterEqual(start, from))), ($4) => {
|
|
852
|
+
const id = $4.const(text(key));
|
|
853
|
+
$4(out.insert(id, East.value({ roles: roles(row, id), row: East.Blob.encodeBeast(row, "v2") }, EntryType)));
|
|
854
|
+
});
|
|
855
|
+
});
|
|
856
|
+
$2.assign(result, East.value(some(out), RowsType));
|
|
857
|
+
},
|
|
858
|
+
});
|
|
859
|
+
return result;
|
|
860
|
+
});
|
|
861
|
+
};
|
|
862
|
+
/** Refuses two of a builder's roles naming one field: a builder writes each of its roles into a field of its own (B1). */
|
|
863
|
+
const oneFieldEach = (builder, named) => {
|
|
864
|
+
const seen = new Map();
|
|
865
|
+
for (const [prop, name] of named) {
|
|
866
|
+
if (name === undefined)
|
|
867
|
+
continue;
|
|
868
|
+
const prior = seen.get(name);
|
|
869
|
+
if (prior !== undefined) {
|
|
870
|
+
throw new Error(`${where}: \`${prior}\` and \`${prop}\` both name "${name}" — the ${builder} writes each of its roles into a field of its own`);
|
|
871
|
+
}
|
|
872
|
+
seen.set(name, prop);
|
|
873
|
+
}
|
|
796
874
|
};
|
|
797
875
|
return {
|
|
798
876
|
[SCHEDULE_DEF]: "events",
|
|
@@ -800,13 +878,195 @@ export function scheduleEvents(record, input) {
|
|
|
800
878
|
rowType,
|
|
801
879
|
name: config.name,
|
|
802
880
|
icon: config.icon,
|
|
881
|
+
title: titleField,
|
|
803
882
|
takes,
|
|
804
883
|
draw: draw,
|
|
805
|
-
|
|
806
|
-
|
|
884
|
+
templatesSource,
|
|
885
|
+
templatesList: config.templates === undefined ? "none" : SCHEDULE_TEMPLATES in config.templates ? "record" : "code",
|
|
886
|
+
roles: [...rosterGiven, ...allocationGiven],
|
|
887
|
+
partsOf: config.parts?.of,
|
|
888
|
+
allocationValues,
|
|
889
|
+
build(slot, part) {
|
|
890
|
+
return East.value(kindParts(slot, part, formSpecs).fields, ScheduleKindType);
|
|
891
|
+
},
|
|
892
|
+
buildRoster(slot, part) {
|
|
893
|
+
// A duty runs from its start to its end, keyed by String, on its slot's shift and group, rostered to someone.
|
|
894
|
+
if (instantKind) {
|
|
895
|
+
throw new Error(`${where}: the Roster reads a duty's \`start\` and \`end\`; this kind is one instant (\`at\`) — give \`start\` and \`end\` in its place`);
|
|
896
|
+
}
|
|
897
|
+
if (optional)
|
|
898
|
+
throw new Error(`${where}: a duty has its times — \`start\` and \`end\` are DateTime fields, not Options`);
|
|
899
|
+
if (keyType.type !== "String") {
|
|
900
|
+
throw new Error(`${where}: the Roster's duties are keyed by String — a duty is named by its key, and this record is keyed by ${printType(keyType)}`);
|
|
901
|
+
}
|
|
902
|
+
if (shiftField === undefined || groupField === undefined) {
|
|
903
|
+
throw new Error(`${where}: the Roster places a duty by its \`shift\` and its \`group\` — give both`);
|
|
904
|
+
}
|
|
905
|
+
if (resource === undefined || resourceValue === undefined) {
|
|
906
|
+
throw new Error(`${where}: the Roster rosters each duty to a person or an agency, its \`resource\` — give it, resource: { field, of: "people" }`);
|
|
907
|
+
}
|
|
908
|
+
oneFieldEach("Roster", [["start", startField], ["end", endField], ["resource.field", resource.field], ["shift", shiftField],
|
|
909
|
+
["group", groupField], ["position", positionField], ["activity", activityField]]);
|
|
910
|
+
const shift = shiftField;
|
|
911
|
+
const group = groupField;
|
|
912
|
+
const who = resource.field;
|
|
913
|
+
const whoOf = resourceValue;
|
|
914
|
+
const parts = kindParts(slot, part, formOver([startField, endField, who, shift, group, positionField, activityField]));
|
|
915
|
+
const Roles = ScheduleRosterRolesType;
|
|
916
|
+
// A row with the Roster's roles written from `roles`, the resource field from `value`, and every other field
|
|
917
|
+
// from `source`: the row as it was, or a new row's defaults. A kind with no `position` writes none.
|
|
918
|
+
const rosterRow = (source, roles, value) => East.value(Object.fromEntries(Object.keys(fields).map((f) => [f,
|
|
919
|
+
f === startField ? roles.start
|
|
920
|
+
: f === endField ? roles.end
|
|
921
|
+
: f === who ? value
|
|
922
|
+
: f === shift ? roles.shift
|
|
923
|
+
: f === group ? roles.group
|
|
924
|
+
: f === positionField ? roles.position.match({ some: (_$, held) => held, none: () => fieldOf(source, f) })
|
|
925
|
+
: f === activityField ? roles.activity
|
|
926
|
+
: fieldOf(source, f)])), rowType);
|
|
927
|
+
// A duty's roles, from its row and its key: its times and who, its shift and group, its position and
|
|
928
|
+
// activity, and the hours it counts.
|
|
929
|
+
const rolesOf = East.function([rowType, StringType], Roles, ($, row, key) => {
|
|
930
|
+
const ref = $.const(refOf);
|
|
931
|
+
const start = $.const(fieldOf(row, startField));
|
|
932
|
+
const end = $.const(fieldOf(row, endField));
|
|
933
|
+
let hours;
|
|
934
|
+
if (hoursOf === undefined) {
|
|
935
|
+
// Its length.
|
|
936
|
+
hours = $.const(start.durationMinutes(end).divide(60.0));
|
|
937
|
+
}
|
|
938
|
+
else {
|
|
939
|
+
const count = $.const(hoursOf);
|
|
940
|
+
hours = $.const(count(row, key));
|
|
941
|
+
}
|
|
942
|
+
return East.value({
|
|
943
|
+
start, end, resource: ref(row), shift: fieldOf(row, shift), group: fieldOf(row, group),
|
|
944
|
+
position: positionField === undefined ? none : some(fieldOf(row, positionField)),
|
|
945
|
+
activity: activityField === undefined ? none : fieldOf(row, activityField),
|
|
946
|
+
hours,
|
|
947
|
+
}, Roles);
|
|
948
|
+
});
|
|
949
|
+
// A drafted duty's roles, from its bytes: what `rows` gives a stored one in the pass that reads it.
|
|
950
|
+
const read = East.function([BlobType, StringType], Roles, ($, bytes, key) => {
|
|
951
|
+
const of = $.const(rolesOf);
|
|
952
|
+
return of(bytes.decodeBeast(rowType, "v2"), key);
|
|
953
|
+
});
|
|
954
|
+
// The row with its roles written, and every other field as it was (B1); `none` for a resource the kind refuses.
|
|
955
|
+
const write = East.function([BlobType, Roles], OptionType(BlobType), ($, bytes, roles) => {
|
|
956
|
+
const row = $.const(bytes.decodeBeast(rowType, "v2"));
|
|
957
|
+
const resolve = $.const(whoOf);
|
|
958
|
+
const result = $.let(East.value(none, OptionType(BlobType)), OptionType(BlobType));
|
|
959
|
+
$.match(resolve(roles.resource), {
|
|
960
|
+
some: ($2, value) => { $2.assign(result, East.value(some(East.Blob.encodeBeast(rosterRow(row, roles, value), "v2")), OptionType(BlobType))); },
|
|
961
|
+
});
|
|
962
|
+
return result;
|
|
963
|
+
});
|
|
964
|
+
// A new duty: its roles written, and every other field its type's default.
|
|
965
|
+
const blank = East.value(defaultValue(rowType), rowType);
|
|
966
|
+
const create = East.function([Roles], OptionType(BlobType), ($, roles) => {
|
|
967
|
+
const row = $.const(blank);
|
|
968
|
+
const resolve = $.const(whoOf);
|
|
969
|
+
const result = $.let(East.value(none, OptionType(BlobType)), OptionType(BlobType));
|
|
970
|
+
$.match(resolve(roles.resource), {
|
|
971
|
+
some: ($2, value) => { $2.assign(result, East.value(some(East.Blob.encodeBeast(rosterRow(row, roles, value), "v2")), OptionType(BlobType))); },
|
|
972
|
+
});
|
|
973
|
+
return result;
|
|
974
|
+
});
|
|
975
|
+
return East.value({
|
|
976
|
+
kind: East.value(parts.fields, ScheduleKindType),
|
|
977
|
+
rows: storedRows(parts.reads, ScheduleRosterEntryType, rolesOf),
|
|
978
|
+
read,
|
|
979
|
+
write,
|
|
980
|
+
create,
|
|
981
|
+
roles: { position: positionField !== undefined, activity: activityField !== undefined },
|
|
982
|
+
rowType: toEastTypeValue(rowType),
|
|
983
|
+
}, ScheduleRosterKindType);
|
|
984
|
+
},
|
|
985
|
+
buildAllocation(slot, part) {
|
|
986
|
+
// A bin is one instant, keyed by String, in one lane, booking an arrival, its quantity on its parts for its hold.
|
|
987
|
+
if (!instantKind) {
|
|
988
|
+
throw new Error(`${where}: the Allocation's bins are an instant kind: give \`at\` in place of \`start\` and \`end\``);
|
|
989
|
+
}
|
|
990
|
+
if (keyType.type !== "String") {
|
|
991
|
+
throw new Error(`${where}: the Allocation's bins are keyed by String — a bin is named by its key, and this record is keyed by ${printType(keyType)}`);
|
|
992
|
+
}
|
|
993
|
+
if (resource === undefined)
|
|
994
|
+
throw new Error(`${where}: the Allocation books a bin into a lane, its \`resource\` — give it`);
|
|
995
|
+
if (resource.shape !== "key" || resource.optional) {
|
|
996
|
+
throw new Error(`${where}: the Allocation books each bin into one lane — \`resource\` names a String field, a key of the lanes' kind, ` +
|
|
997
|
+
`and "${resource.field}" holds ${typeText(fields[resource.field])}`);
|
|
998
|
+
}
|
|
999
|
+
if (arrivalField === undefined)
|
|
1000
|
+
throw new Error(`${where}: the Allocation books a bin's \`arrival\` — give it`);
|
|
1001
|
+
if (quantityField === undefined)
|
|
1002
|
+
throw new Error(`${where}: the Allocation reads a bin's \`quantity\` — give it`);
|
|
1003
|
+
if (partsField === undefined || config.parts === undefined)
|
|
1004
|
+
throw new Error(`${where}: the Allocation allocates a bin's \`parts\` — give it`);
|
|
1005
|
+
if (holdField === undefined)
|
|
1006
|
+
throw new Error(`${where}: the Allocation holds a bin for its \`hold\` — give it`);
|
|
1007
|
+
oneFieldEach("Allocation", [["at", startField], ["resource.field", resource.field], ["arrival", arrivalField], ["quantity.field", quantityField],
|
|
1008
|
+
["parts.field", partsField], ["hold", holdField], ["kind", kindField]]);
|
|
1009
|
+
const lane = resource.field;
|
|
1010
|
+
const arrival = arrivalField;
|
|
1011
|
+
const quantity = quantityField;
|
|
1012
|
+
const shares = partsField;
|
|
1013
|
+
const hold = holdField;
|
|
1014
|
+
// The fields no role maps (`allocationValues`): what an arrival's values give a booked bin, a reservation's their type's default.
|
|
1015
|
+
const mapped = allocationMapped;
|
|
1016
|
+
const ValuesType = allocationValues;
|
|
1017
|
+
const parts = kindParts(slot, part, formOver([...mapped]));
|
|
1018
|
+
const Roles = ScheduleAllocationRolesType;
|
|
1019
|
+
// A row with the Allocation's roles written from `roles`, and every other field from `source`: the row as it
|
|
1020
|
+
// was, or a booked bin's values. A kind with no `kind` writes none.
|
|
1021
|
+
const binRow = (source, roles) => East.value(Object.fromEntries(Object.keys(fields).map((f) => [f,
|
|
1022
|
+
f === startField ? roles.at
|
|
1023
|
+
: f === lane ? roles.lane
|
|
1024
|
+
: f === arrival ? roles.arrival
|
|
1025
|
+
: f === quantity ? roles.quantity
|
|
1026
|
+
: f === shares ? roles.parts
|
|
1027
|
+
: f === hold ? roles.hold
|
|
1028
|
+
: f === kindField ? roles.kind
|
|
1029
|
+
: fieldOf(source, f)])), rowType);
|
|
1030
|
+
// A bin's roles, from its row: its time and lane, the arrival it books, its quantity and parts, its hold and kind.
|
|
1031
|
+
const rolesOf = East.function([rowType, StringType], Roles, (_$, row, _key) => East.value({
|
|
1032
|
+
at: fieldOf(row, startField), lane: fieldOf(row, lane), arrival: fieldOf(row, arrival), quantity: fieldOf(row, quantity),
|
|
1033
|
+
parts: fieldOf(row, shares), hold: fieldOf(row, hold), kind: kindField === undefined ? none : fieldOf(row, kindField),
|
|
1034
|
+
}, Roles));
|
|
1035
|
+
// A drafted bin's roles, from its bytes: what `rows` gives a stored one in the pass that reads it.
|
|
1036
|
+
const read = East.function([BlobType], Roles, ($, bytes) => {
|
|
1037
|
+
const of = $.const(rolesOf);
|
|
1038
|
+
return of(bytes.decodeBeast(rowType, "v2"), "");
|
|
1039
|
+
});
|
|
1040
|
+
// The row with its roles written, and every other field as it was (B1).
|
|
1041
|
+
const write = East.function([BlobType, Roles], BlobType, ($, bytes, roles) => {
|
|
1042
|
+
const row = $.const(bytes.decodeBeast(rowType, "v2"));
|
|
1043
|
+
return East.Blob.encodeBeast(binRow(row, roles), "v2");
|
|
1044
|
+
});
|
|
1045
|
+
// A new bin: its roles written, and every other field the arrival's values' — or, with none, its type's default (B13).
|
|
1046
|
+
const blank = East.value(defaultValue(ValuesType), ValuesType);
|
|
1047
|
+
const create = East.function([Roles, OptionType(BlobType)], BlobType, ($, roles, values) => {
|
|
1048
|
+
const given = $.const(values.match({
|
|
1049
|
+
some: (_$2, bytes) => bytes.decodeBeast(ValuesType, "v2"),
|
|
1050
|
+
none: (_$2) => blank,
|
|
1051
|
+
}));
|
|
1052
|
+
return East.Blob.encodeBeast(binRow(given, roles), "v2");
|
|
1053
|
+
});
|
|
1054
|
+
return East.value({
|
|
1055
|
+
kind: East.value(parts.fields, ScheduleKindType),
|
|
1056
|
+
rows: storedRows(parts.reads, ScheduleAllocationEntryType, rolesOf),
|
|
1057
|
+
read,
|
|
1058
|
+
write,
|
|
1059
|
+
create,
|
|
1060
|
+
lanes: resource.of,
|
|
1061
|
+
parts: config.parts.of,
|
|
1062
|
+
kinded: kindField !== undefined,
|
|
1063
|
+
unit: config.quantity?.unit === undefined ? none : some(config.quantity.unit),
|
|
1064
|
+
values: toEastTypeValue(ValuesType),
|
|
1065
|
+
rowType: toEastTypeValue(rowType),
|
|
1066
|
+
}, ScheduleAllocationKindType);
|
|
807
1067
|
},
|
|
808
|
-
buildPlan(slot) {
|
|
809
|
-
const parts = kindParts(slot);
|
|
1068
|
+
buildPlan(slot, part) {
|
|
1069
|
+
const parts = kindParts(slot, part, formSpecs);
|
|
810
1070
|
const quantity = config.quantity;
|
|
811
1071
|
const format = quantity?.format === undefined ? undefined : East.value(quantity.format, TickFormatType);
|
|
812
1072
|
// One event as Plan draws it: what every view draws, with its roles read from their fields.
|
|
@@ -832,7 +1092,7 @@ export function scheduleEvents(record, input) {
|
|
|
832
1092
|
// is the record's: read whole, or for a kind read a window at a time (#1199) looked for first among the
|
|
833
1093
|
// rows its windows hold over [from, to) and its backlog's, where a gesture's event is drawn, then read
|
|
834
1094
|
// by its key.
|
|
835
|
-
const planEvent = readEvent(planItemOf, PlanEventReadType);
|
|
1095
|
+
const planEvent = readEvent(planItemOf, PlanEventReadType, parts.reads);
|
|
836
1096
|
const name = (field) => (field === undefined ? none : some(field));
|
|
837
1097
|
return East.value({
|
|
838
1098
|
...parts.fields,
|
|
@@ -840,8 +1100,8 @@ export function scheduleEvents(record, input) {
|
|
|
840
1100
|
instant: instantKind,
|
|
841
1101
|
overlaps: variant(overlaps, null),
|
|
842
1102
|
roles: { state: name(stateField), quantity: name(quantityField), lane: name(laneField) },
|
|
843
|
-
planItems: windowOf(PlanEventItemType, planItemOf),
|
|
844
|
-
planUnscheduled: backlogOf(PlanEventItemType, planItemOf),
|
|
1103
|
+
planItems: windowOf(PlanEventItemType, planItemOf, parts.reads),
|
|
1104
|
+
planUnscheduled: backlogOf(PlanEventItemType, planItemOf, parts.reads),
|
|
845
1105
|
planEvent,
|
|
846
1106
|
inspector: inspector === undefined ? East.value(none, OptionType(RowInspectorType)) : East.value(some(inspector), OptionType(RowInspectorType)),
|
|
847
1107
|
}, PlanEventKindType);
|