@elaraai/e3-ui 1.0.96 → 1.0.98
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/index.d.ts +258 -7
- package/dist/src/allocation/index.d.ts.map +1 -1
- package/dist/src/allocation/index.js +30 -1
- package/dist/src/allocation/index.js.map +1 -1
- package/dist/src/allocation/types.d.ts +41 -0
- package/dist/src/allocation/types.d.ts.map +1 -1
- package/dist/src/allocation/types.js +35 -0
- package/dist/src/allocation/types.js.map +1 -1
- package/dist/src/bind/data-indexed.d.ts +31 -4
- package/dist/src/bind/data-indexed.d.ts.map +1 -1
- package/dist/src/bind/data-indexed.js +54 -10
- package/dist/src/bind/data-indexed.js.map +1 -1
- package/dist/src/calendar/index.d.ts +540 -14
- package/dist/src/calendar/index.d.ts.map +1 -1
- package/dist/src/calendar/index.js +43 -7
- package/dist/src/calendar/index.js.map +1 -1
- package/dist/src/calendar/paged.d.ts +89 -0
- package/dist/src/calendar/paged.d.ts.map +1 -0
- package/dist/src/calendar/paged.js +148 -0
- package/dist/src/calendar/paged.js.map +1 -0
- package/dist/src/flowchart/payload.d.ts +156 -0
- package/dist/src/flowchart/payload.d.ts.map +1 -1
- package/dist/src/flowchart/window.d.ts +12 -0
- package/dist/src/flowchart/window.d.ts.map +1 -1
- package/dist/src/index.d.ts +11 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +11 -5
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +28 -7
- package/dist/src/internal.js.map +1 -1
- package/dist/src/plan/builders.d.ts +12 -8
- package/dist/src/plan/builders.d.ts.map +1 -1
- package/dist/src/plan/builders.js +12 -8
- package/dist/src/plan/builders.js.map +1 -1
- package/dist/src/plan/event-rows.d.ts +228 -156
- package/dist/src/plan/event-rows.d.ts.map +1 -1
- package/dist/src/plan/event-rows.js +239 -54
- package/dist/src/plan/event-rows.js.map +1 -1
- package/dist/src/plan/index.d.ts +5 -0
- package/dist/src/plan/index.d.ts.map +1 -1
- package/dist/src/plan/index.js +3 -0
- package/dist/src/plan/index.js.map +1 -1
- package/dist/src/plan/ir.d.ts +70 -0
- package/dist/src/plan/ir.d.ts.map +1 -1
- package/dist/src/plan/ordered-source.d.ts +2038 -1
- package/dist/src/plan/ordered-source.d.ts.map +1 -1
- package/dist/src/plan/ordered-source.js +19 -11
- package/dist/src/plan/ordered-source.js.map +1 -1
- package/dist/src/plan/plan.d.ts +513 -32
- package/dist/src/plan/plan.d.ts.map +1 -1
- package/dist/src/plan/plan.js +119 -32
- package/dist/src/plan/plan.js.map +1 -1
- package/dist/src/plan/root.d.ts +4 -2
- package/dist/src/plan/root.d.ts.map +1 -1
- package/dist/src/plan/root.js +6 -4
- package/dist/src/plan/root.js.map +1 -1
- package/dist/src/plan/series.d.ts +13 -0
- package/dist/src/plan/series.d.ts.map +1 -1
- package/dist/src/plan/series.js +61 -7
- package/dist/src/plan/series.js.map +1 -1
- package/dist/src/plan/types.d.ts +14 -0
- package/dist/src/plan/types.d.ts.map +1 -1
- package/dist/src/plan/types.js +8 -0
- package/dist/src/plan/types.js.map +1 -1
- package/dist/src/roster/index.d.ts +608 -20
- package/dist/src/roster/index.d.ts.map +1 -1
- package/dist/src/roster/index.js +103 -29
- package/dist/src/roster/index.js.map +1 -1
- package/dist/src/roster/library.d.ts +12 -2
- package/dist/src/roster/library.d.ts.map +1 -1
- package/dist/src/roster/library.js +8 -0
- package/dist/src/roster/library.js.map +1 -1
- package/dist/src/roster/lists.d.ts +59 -12
- package/dist/src/roster/lists.d.ts.map +1 -1
- package/dist/src/roster/lists.js +51 -58
- package/dist/src/roster/lists.js.map +1 -1
- package/dist/src/roster/times.d.ts +402 -0
- package/dist/src/roster/times.d.ts.map +1 -1
- package/dist/src/roster/types.d.ts +913 -1
- package/dist/src/roster/types.d.ts.map +1 -1
- package/dist/src/roster/types.js +43 -3
- package/dist/src/roster/types.js.map +1 -1
- package/dist/src/schedule/cell-checks.d.ts +85 -0
- package/dist/src/schedule/cell-checks.d.ts.map +1 -0
- package/dist/src/schedule/cell-checks.js +211 -0
- package/dist/src/schedule/cell-checks.js.map +1 -0
- package/dist/src/schedule/events.d.ts +42 -10
- package/dist/src/schedule/events.d.ts.map +1 -1
- package/dist/src/schedule/events.js +349 -155
- package/dist/src/schedule/events.js.map +1 -1
- package/dist/src/schedule/fields.d.ts +134 -0
- package/dist/src/schedule/fields.d.ts.map +1 -0
- package/dist/src/schedule/fields.js +207 -0
- package/dist/src/schedule/fields.js.map +1 -0
- package/dist/src/schedule/library.d.ts +11 -3
- package/dist/src/schedule/library.d.ts.map +1 -1
- package/dist/src/schedule/library.js +9 -6
- package/dist/src/schedule/library.js.map +1 -1
- package/dist/src/schedule/optimise.d.ts +124 -0
- package/dist/src/schedule/optimise.d.ts.map +1 -0
- package/dist/src/schedule/optimise.js +140 -0
- package/dist/src/schedule/optimise.js.map +1 -0
- package/dist/src/schedule/pages.d.ts +76 -0
- package/dist/src/schedule/pages.d.ts.map +1 -0
- package/dist/src/schedule/pages.js +86 -0
- package/dist/src/schedule/pages.js.map +1 -0
- package/dist/src/schedule/record-window.d.ts +119 -6
- package/dist/src/schedule/record-window.d.ts.map +1 -1
- package/dist/src/schedule/record-window.js +139 -60
- package/dist/src/schedule/record-window.js.map +1 -1
- package/dist/src/schedule/resources.d.ts +8 -4
- package/dist/src/schedule/resources.d.ts.map +1 -1
- package/dist/src/schedule/resources.js +35 -15
- package/dist/src/schedule/resources.js.map +1 -1
- package/dist/src/schedule/session.d.ts +14 -0
- package/dist/src/schedule/session.d.ts.map +1 -1
- package/dist/src/schedule/session.js +29 -17
- package/dist/src/schedule/session.js.map +1 -1
- package/dist/src/schedule/types.d.ts +426 -36
- package/dist/src/schedule/types.d.ts.map +1 -1
- package/dist/src/schedule/types.js +63 -17
- package/dist/src/schedule/types.js.map +1 -1
- package/dist/src/schedule/window.d.ts +30 -9
- package/dist/src/schedule/window.d.ts.map +1 -1
- package/dist/src/schedule/window.js +101 -49
- package/dist/src/schedule/window.js.map +1 -1
- package/dist/src/schematic/index.d.ts +277 -0
- package/dist/src/schematic/index.d.ts.map +1 -0
- package/dist/src/schematic/index.js +206 -0
- package/dist/src/schematic/index.js.map +1 -0
- package/dist/src/schematic/kinds.d.ts +501 -0
- package/dist/src/schematic/kinds.d.ts.map +1 -0
- package/dist/src/schematic/kinds.js +1027 -0
- package/dist/src/schematic/kinds.js.map +1 -0
- package/dist/src/schematic/layers.d.ts +74 -0
- package/dist/src/schematic/layers.d.ts.map +1 -0
- package/dist/src/schematic/layers.js +99 -0
- package/dist/src/schematic/layers.js.map +1 -0
- package/dist/src/schematic/library.d.ts +202 -0
- package/dist/src/schematic/library.d.ts.map +1 -0
- package/dist/src/schematic/library.js +244 -0
- package/dist/src/schematic/library.js.map +1 -0
- package/dist/src/schematic/payload.d.ts +8360 -0
- package/dist/src/schematic/payload.d.ts.map +1 -0
- package/dist/src/schematic/payload.js +446 -0
- package/dist/src/schematic/payload.js.map +1 -0
- package/dist/src/schematic/schematic.d.ts +27 -0
- package/dist/src/schematic/schematic.d.ts.map +1 -0
- package/dist/src/schematic/schematic.js +17 -0
- package/dist/src/schematic/schematic.js.map +1 -0
- package/dist/src/schematic/shapes.d.ts +150 -0
- package/dist/src/schematic/shapes.d.ts.map +1 -0
- package/dist/src/schematic/shapes.js +171 -0
- package/dist/src/schematic/shapes.js.map +1 -0
- package/dist/src/schematic/templates.d.ts +96 -0
- package/dist/src/schematic/templates.d.ts.map +1 -0
- package/dist/src/schematic/templates.js +91 -0
- package/dist/src/schematic/templates.js.map +1 -0
- package/dist/src/schematic/types.d.ts +5766 -0
- package/dist/src/schematic/types.d.ts.map +1 -0
- package/dist/src/schematic/types.js +688 -0
- package/dist/src/schematic/types.js.map +1 -0
- package/dist/src/schematic/window.d.ts +212 -0
- package/dist/src/schematic/window.d.ts.map +1 -0
- package/dist/src/schematic/window.js +337 -0
- package/dist/src/schematic/window.js.map +1 -0
- package/dist/src/sheet/editing-bridge.d.ts +4 -2
- package/dist/src/sheet/editing-bridge.d.ts.map +1 -1
- package/dist/src/sheet/editing-bridge.js +8 -2
- package/dist/src/sheet/editing-bridge.js.map +1 -1
- package/dist/src/sheet/editing-types.d.ts +9 -5
- package/dist/src/sheet/editing-types.d.ts.map +1 -1
- package/dist/src/sheet/editing-types.js +9 -5
- package/dist/src/sheet/editing-types.js.map +1 -1
- package/dist/src/sheet/index.d.ts +18 -8
- package/dist/src/sheet/index.d.ts.map +1 -1
- package/dist/src/sheet/index.js +15 -7
- package/dist/src/sheet/index.js.map +1 -1
- package/dist/src/sheet/optimise.d.ts +69 -0
- package/dist/src/sheet/optimise.d.ts.map +1 -0
- package/dist/src/sheet/optimise.js +81 -0
- package/dist/src/sheet/optimise.js.map +1 -0
- package/dist/src/sheet/registers.d.ts +5 -5
- package/dist/src/sheet/registers.js +5 -5
- package/dist/src/sheet/root.d.ts +2 -0
- package/dist/src/sheet/root.d.ts.map +1 -1
- package/dist/src/sheet/root.js +2 -2
- package/dist/src/sheet/root.js.map +1 -1
- package/dist/src/sheet/sheet.d.ts +753 -573
- package/dist/src/sheet/sheet.d.ts.map +1 -1
- package/dist/src/sheet/sheet.js +45 -13
- package/dist/src/sheet/sheet.js.map +1 -1
- package/dist/src/sheet/types.d.ts +92 -12
- package/dist/src/sheet/types.d.ts.map +1 -1
- package/dist/src/sheet/types.js +4 -8
- package/dist/src/sheet/types.js.map +1 -1
- package/dist/src/utils/keyed-rows.d.ts +41 -0
- package/dist/src/utils/keyed-rows.d.ts.map +1 -0
- package/dist/src/utils/keyed-rows.js +64 -0
- package/dist/src/utils/keyed-rows.js.map +1 -0
- package/dist/src/utils/optimise.d.ts +79 -0
- package/dist/src/utils/optimise.d.ts.map +1 -0
- package/dist/src/utils/optimise.js +46 -0
- package/dist/src/utils/optimise.js.map +1 -0
- package/dist/test/allocation/allocation.examples.d.ts +6 -18
- package/dist/test/allocation/allocation.examples.d.ts.map +1 -1
- package/dist/test/allocation/allocation.examples.js +3 -3
- package/dist/test/allocation/allocation.examples.js.map +1 -1
- package/dist/test/allocation/optimise.examples.d.ts +109 -0
- package/dist/test/allocation/optimise.examples.d.ts.map +1 -0
- package/dist/test/allocation/optimise.examples.js +223 -0
- package/dist/test/allocation/optimise.examples.js.map +1 -0
- package/dist/test/bind/data/data.examples.d.ts +540 -36
- package/dist/test/bind/data/data.examples.d.ts.map +1 -1
- package/dist/test/bind/data/data.examples.js +66 -2
- package/dist/test/bind/data/data.examples.js.map +1 -1
- package/dist/test/bind/record/record.examples.d.ts +1 -3
- package/dist/test/bind/record/record.examples.d.ts.map +1 -1
- package/dist/test/calendar/calendar-records.examples.d.ts.map +1 -1
- package/dist/test/calendar/calendar-records.examples.js +3 -3
- package/dist/test/calendar/calendar-records.examples.js.map +1 -1
- package/dist/test/calendar/calendar-windows.examples.d.ts +9 -0
- package/dist/test/calendar/calendar-windows.examples.d.ts.map +1 -0
- package/dist/test/calendar/calendar-windows.examples.js +111 -0
- package/dist/test/calendar/calendar-windows.examples.js.map +1 -0
- package/dist/test/calendar/calendar.examples.d.ts +7 -21
- package/dist/test/calendar/calendar.examples.d.ts.map +1 -1
- package/dist/test/calendar/calendar.examples.js +7 -7
- package/dist/test/calendar/calendar.examples.js.map +1 -1
- package/dist/test/calendar/optimise.examples.d.ts +132 -0
- package/dist/test/calendar/optimise.examples.d.ts.map +1 -0
- package/dist/test/calendar/optimise.examples.js +75 -0
- package/dist/test/calendar/optimise.examples.js.map +1 -0
- package/dist/test/examples-package.d.ts +46 -10
- package/dist/test/examples-package.d.ts.map +1 -1
- package/dist/test/examples-package.js +142 -32
- package/dist/test/examples-package.js.map +1 -1
- package/dist/test/flowchart/flowchart.examples.d.ts +10 -30
- package/dist/test/flowchart/flowchart.examples.d.ts.map +1 -1
- package/dist/test/plan/optimise.examples.d.ts +207 -0
- package/dist/test/plan/optimise.examples.d.ts.map +1 -0
- package/dist/test/plan/optimise.examples.js +98 -0
- package/dist/test/plan/optimise.examples.js.map +1 -0
- package/dist/test/plan/plan-events.examples.d.ts +8 -24
- package/dist/test/plan/plan-events.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-events.examples.js +3 -3
- package/dist/test/plan/plan-events.examples.js.map +1 -1
- package/dist/test/plan/plan-records.examples.d.ts +200 -19
- package/dist/test/plan/plan-records.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-records.examples.js +125 -28
- package/dist/test/plan/plan-records.examples.js.map +1 -1
- package/dist/test/plan/plan-windows.examples.d.ts +853 -36
- package/dist/test/plan/plan-windows.examples.d.ts.map +1 -1
- package/dist/test/plan/plan-windows.examples.js +166 -29
- package/dist/test/plan/plan-windows.examples.js.map +1 -1
- package/dist/test/plan/plan.examples.d.ts +7 -21
- package/dist/test/plan/plan.examples.d.ts.map +1 -1
- package/dist/test/plan/plan.examples.js +11 -9
- package/dist/test/plan/plan.examples.js.map +1 -1
- package/dist/test/roster/domain.examples.d.ts +804 -0
- package/dist/test/roster/domain.examples.d.ts.map +1 -1
- package/dist/test/roster/domain.examples.js +3 -3
- package/dist/test/roster/domain.examples.js.map +1 -1
- package/dist/test/roster/optimise.examples.d.ts +485 -0
- package/dist/test/roster/optimise.examples.d.ts.map +1 -0
- package/dist/test/roster/optimise.examples.js +155 -0
- package/dist/test/roster/optimise.examples.js.map +1 -0
- package/dist/test/roster/roster-records.examples.d.ts +6 -18
- package/dist/test/roster/roster-records.examples.d.ts.map +1 -1
- package/dist/test/roster/roster-records.examples.js +1 -1
- package/dist/test/roster/roster-records.examples.js.map +1 -1
- package/dist/test/roster/roster.examples.d.ts +3391 -21
- package/dist/test/roster/roster.examples.d.ts.map +1 -1
- package/dist/test/roster/roster.examples.js +54 -7
- package/dist/test/roster/roster.examples.js.map +1 -1
- package/dist/test/roster/warehouse.d.ts +150 -7
- package/dist/test/roster/warehouse.d.ts.map +1 -1
- package/dist/test/roster/warehouse.js +36 -11
- package/dist/test/roster/warehouse.js.map +1 -1
- package/dist/test/schedule/schedule.examples.d.ts +1 -3
- package/dist/test/schedule/schedule.examples.d.ts.map +1 -1
- package/dist/test/schematic/schematic-records.examples.d.ts +444 -0
- package/dist/test/schematic/schematic-records.examples.d.ts.map +1 -0
- package/dist/test/schematic/schematic-records.examples.js +205 -0
- package/dist/test/schematic/schematic-records.examples.js.map +1 -0
- package/dist/test/schematic/schematic.examples.d.ts +2289 -0
- package/dist/test/schematic/schematic.examples.d.ts.map +1 -0
- package/dist/test/schematic/schematic.examples.js +453 -0
- package/dist/test/schematic/schematic.examples.js.map +1 -0
- package/dist/test/sheet/optimise.examples.d.ts +177 -0
- package/dist/test/sheet/optimise.examples.d.ts.map +1 -0
- package/dist/test/sheet/optimise.examples.js +75 -0
- package/dist/test/sheet/optimise.examples.js.map +1 -0
- package/dist/test/sheet/sheet-records.examples.d.ts +95 -204
- package/dist/test/sheet/sheet-records.examples.d.ts.map +1 -1
- package/dist/test/sheet/sheet-records.examples.js +42 -17
- package/dist/test/sheet/sheet-records.examples.js.map +1 -1
- package/dist/test/sheet/sheet.examples.d.ts +17 -33
- package/dist/test/sheet/sheet.examples.d.ts.map +1 -1
- package/dist/test/sheet/sheet.examples.js +18 -15
- package/dist/test/sheet/sheet.examples.js.map +1 -1
- package/package.json +11 -11
|
@@ -43,10 +43,22 @@
|
|
|
43
43
|
* part)`, and the kind reads overlap queries through its declared interval
|
|
44
44
|
* indexes (the source's `range` naming the start field). It shares the
|
|
45
45
|
* toolbar's filters and window, counts original events once, and reads backlog
|
|
46
|
-
* through the same choices with an Unset start
|
|
46
|
+
* through the same choices with an Unset start — the Plan's with its window, as
|
|
47
|
+
* one; the Calendar's never, as it pages the backlog through the source itself
|
|
48
|
+
* (#1424), its window reading the window's rows alone. It requires `entries` for
|
|
47
49
|
* original-key inspection and Save. Existing drafts outside a new narrowing
|
|
48
50
|
* remain in the session; Save includes them. A kind narrowed so takes no
|
|
49
|
-
* `window` or `backlogWindow`.
|
|
51
|
+
* `window` or `backlogWindow`. Every kind counts its events before one is read
|
|
52
|
+
* (`count`, #1039) — through its source, the count its window's read asks
|
|
53
|
+
* first; through its day index, the days' entries the search its read asks
|
|
54
|
+
* first answers; its record read whole, in memory — and the Calendar's and the
|
|
55
|
+
* Plan's builds read its window only within `SCHEDULE_EVENT_CAP`, counted
|
|
56
|
+
* first (#1424). A day index files an event under each day it runs on, so its
|
|
57
|
+
* count is an upper bound on the events, never their number (`countExact`).
|
|
58
|
+
* A builder over resources read a window at a time reads a kind placed on them
|
|
59
|
+
* a cell at a time through the shared schedule reader, which hands each read
|
|
60
|
+
* seam — the events over a window, the backlog, one event by key — what it
|
|
61
|
+
* read of the kind's series index's cells (`cellsType`, `seriesKey`).
|
|
50
62
|
*
|
|
51
63
|
* A large record may also be read a window at a time (#1199, `window.ts`): given
|
|
52
64
|
* `window`, a paged read of a day index keyed by `Schedule.days`, the kind's
|
|
@@ -84,30 +96,17 @@ import { EventStateType, TimeStepType } from "@elaraai/east-ui";
|
|
|
84
96
|
import { EditingDraftFieldType, EditingReadinessType, Fields, FieldSpecType, TickFormatType } from "@elaraai/east-ui/internal";
|
|
85
97
|
import { RowInspectorType, rowInspector } from "../utils/row-inspector.js";
|
|
86
98
|
import { scheduleAccessor } from "./accessor.js";
|
|
99
|
+
import { checkKeyField, fieldOf, fieldSetters, keyFieldRef, keyFieldSlots, keyFieldValue } from "./fields.js";
|
|
87
100
|
import { SCHEDULE_TEMPLATES, checkedTemplates } from "./templates.js";
|
|
88
101
|
import { SCHEDULE_DEF } from "./resources.js";
|
|
89
|
-
import { scheduleRecordWindow } from "./record-window.js";
|
|
102
|
+
import { SCHEDULE_EVENT_CAP, scheduleRecordCount, scheduleRecordWindow } from "./record-window.js";
|
|
90
103
|
import { scheduleRecordSession } from "./session.js";
|
|
91
|
-
import { checkEntries, checkIndexWindow, optionOf, scheduleBacklogWindow, scheduleDayWindow, typeText } from "./window.js";
|
|
104
|
+
import { checkEntries, checkIndexWindow, optionOf, scheduleBacklogWindow, scheduleDayCount, scheduleDayWindow, typeText } from "./window.js";
|
|
92
105
|
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
106
|
/** The Roster's roles, as a kind's options name them. */
|
|
94
107
|
const ROSTER_ROLES = ["shift", "group", "position", "activity", "hours"];
|
|
95
108
|
/** The Allocation's roles, as a kind's options name them. */
|
|
96
109
|
const ALLOCATION_ROLES = ["arrival", "parts", "hold", "kind"];
|
|
97
|
-
// ============================================================================
|
|
98
|
-
// Reading East types
|
|
99
|
-
// ============================================================================
|
|
100
|
-
/** A variant's cases, when every one of them holds a String. */
|
|
101
|
-
function stringCases(type) {
|
|
102
|
-
if (type.type !== "Variant" || optionOf(type) !== undefined)
|
|
103
|
-
return undefined;
|
|
104
|
-
const cases = Object.entries(type.cases);
|
|
105
|
-
return cases.length > 0 && cases.every(([, t]) => isTypeEqual(t, StringType)) ? cases.map(([c]) => c) : undefined;
|
|
106
|
-
}
|
|
107
|
-
/** A field of a struct as an East expression, by name. */
|
|
108
|
-
function fieldOf(row, name) {
|
|
109
|
-
return row[name];
|
|
110
|
-
}
|
|
111
110
|
/** The ways a kind draws. */
|
|
112
111
|
const DRAWS = ["span", "buckets", "cards", "marks"];
|
|
113
112
|
export function scheduleEvents(record, input) {
|
|
@@ -183,38 +182,10 @@ export function scheduleEvents(record, input) {
|
|
|
183
182
|
? `${where}: \`backlog\` is a kind's rows with no time, and an instant kind's \`at\` is a plain DateTime field — it has none`
|
|
184
183
|
: `${where}: \`backlog\` is a kind's rows with no time, and its times are plain DateTime fields — make \`start\` and \`end\` Options for a backlog`);
|
|
185
184
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const inner = optionOf(type) ?? type;
|
|
191
|
-
const isOptional = optionOf(type) !== undefined;
|
|
192
|
-
const cases = stringCases(inner);
|
|
193
|
-
if (isTypeEqual(inner, StringType)) {
|
|
194
|
-
if (typeof of !== "string" || of === "") {
|
|
195
|
-
throw new Error(`${where}: \`resource.of\` names the resource slot "${field}" holds keys of — a String field holds one kind's keys`);
|
|
196
|
-
}
|
|
197
|
-
resource = { field, shape: "key", of, optional: isOptional };
|
|
198
|
-
}
|
|
199
|
-
else if (cases !== undefined) {
|
|
200
|
-
if (typeof of !== "object" || of === null) {
|
|
201
|
-
throw new Error(`${where}: "${field}" is a variant — \`resource.of\` names a resource slot per case: { ${cases.map((c) => `${c}: "…"`).join(", ")} }`);
|
|
202
|
-
}
|
|
203
|
-
const named = Object.keys(of);
|
|
204
|
-
if (named.length !== cases.length || !named.every((c) => cases.includes(c))) {
|
|
205
|
-
throw new Error(`${where}: \`resource.of\` names a resource slot for each of "${field}"'s cases (${cases.join(", ")}) — and it names ${named.join(", ") || "none"}`);
|
|
206
|
-
}
|
|
207
|
-
const kinds = Object.values(of);
|
|
208
|
-
if (new Set(kinds).size !== kinds.length) {
|
|
209
|
-
throw new Error(`${where}: \`resource.of\` names each resource slot once — a case per kind of resource — and it names ${kinds.join(", ")}`);
|
|
210
|
-
}
|
|
211
|
-
resource = { field, shape: "cases", of, cases, optional: isOptional, variant: inner };
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
throw new Error(`${where}: \`resource.field\` names a field holding a resource's key — a String, a variant of String cases, or an Option of either — and "${field}" holds ${typeText(type)}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
const takes = resource === undefined ? [] : resource.shape === "key" ? [resource.of] : Object.values(resource.of);
|
|
185
|
+
// The resource: a key of one kind, or a case per kind (`fields.ts`).
|
|
186
|
+
const resource = config.resource === undefined ? undefined
|
|
187
|
+
: checkKeyField(config.resource.field, fieldType("resource.field", config.resource.field), config.resource.of, { where, prop: "resource", noun: "resource" });
|
|
188
|
+
const takes = resource === undefined ? [] : keyFieldSlots(resource);
|
|
218
189
|
// The status: a variant, a Status per case.
|
|
219
190
|
let statusCases;
|
|
220
191
|
let statusTable;
|
|
@@ -348,6 +319,8 @@ export function scheduleEvents(record, input) {
|
|
|
348
319
|
// ── The East the seams share ─────────────────────────────────────────
|
|
349
320
|
const draftType = EditingDraftFieldType(rowType);
|
|
350
321
|
const EntryRowType = StructType({ id: StringType, key: keyType, row: rowType });
|
|
322
|
+
// The stored entries a reader read by a series index's cells (#1039), each its key and its row.
|
|
323
|
+
const CellsType = ArrayType(StructType({ key: keyType, row: rowType }));
|
|
351
324
|
// The entry a draft leaves: the drafted entry, none for one deleted, the held one for a draft it cannot read.
|
|
352
325
|
const drafted = East.function([BlobType, OptionType(rowType)], OptionType(rowType), (_$, bytes, held) => bytes.decodeBeast(draftType, "v2").match({
|
|
353
326
|
value: (_$2, row) => East.value(some(row), OptionType(rowType)),
|
|
@@ -394,6 +367,31 @@ export function scheduleEvents(record, input) {
|
|
|
394
367
|
: East.value(some(fieldOf(row, name)), OptionType(DateTimeType));
|
|
395
368
|
// A time as its field holds it: an Option field holds `some`.
|
|
396
369
|
const placedAt = (t) => (optional ? East.value(some(t), OptionType(DateTimeType)) : t);
|
|
370
|
+
// How many of the record's stored events overlap [from, to), its record read whole, counted in memory (#1039): by the
|
|
371
|
+
// views' rule, an optional missing end an instant at its start, as the views place it.
|
|
372
|
+
const countWhole = East.function([DateTimeType, DateTimeType], OptionType(IntegerType), ($, from, to) => {
|
|
373
|
+
const all = $.const(readAll());
|
|
374
|
+
const n = $.let(0n, IntegerType);
|
|
375
|
+
$.for(all, ($2, row) => {
|
|
376
|
+
const start = $2.const(instant(row, startField));
|
|
377
|
+
const end = $2.const(instant(row, endField).match({
|
|
378
|
+
none: () => start,
|
|
379
|
+
some: (_$3, e) => East.value(some(e), OptionType(DateTimeType)),
|
|
380
|
+
}));
|
|
381
|
+
$2.match(start, {
|
|
382
|
+
some: ($3, s) => {
|
|
383
|
+
$3.match(end, {
|
|
384
|
+
some: ($4, e) => {
|
|
385
|
+
$4.if(East.less(s, to).and(() => East.greater(e, from).or(() => East.greaterEqual(s, from))), ($5) => {
|
|
386
|
+
$5.assign(n, n.add(1n));
|
|
387
|
+
});
|
|
388
|
+
},
|
|
389
|
+
});
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
return East.value(some(n), OptionType(IntegerType));
|
|
394
|
+
});
|
|
397
395
|
// A duration in minutes — a month counts 30 days.
|
|
398
396
|
const minutesOf = East.function([ScheduleDurationType], IntegerType, (_$, step) => East.Float.roundHalf(step.match({
|
|
399
397
|
minutes: (_$2, n) => n,
|
|
@@ -406,53 +404,12 @@ export function scheduleEvents(record, input) {
|
|
|
406
404
|
: East.function([rowType, keyType], ScheduleDurationType, (_$, row, key) => config.backlog.duration(row, key));
|
|
407
405
|
const dueOf = config.backlog?.due === undefined ? undefined
|
|
408
406
|
: East.function([rowType, keyType], OptionType(DateTimeType), (_$, row, key) => config.backlog.due(row, key));
|
|
409
|
-
// The resource a row is on.
|
|
407
|
+
// The resource a row is on (`fields.ts`).
|
|
410
408
|
const RefOption = OptionType(ScheduleResourceRefType);
|
|
411
|
-
const refOf =
|
|
412
|
-
if (resource === undefined)
|
|
413
|
-
return East.value(none, RefOption);
|
|
414
|
-
const value = fieldOf(row, resource.field);
|
|
415
|
-
if (resource.shape === "key") {
|
|
416
|
-
const kind = resource.of;
|
|
417
|
-
const ref = (key) => East.value(some(East.value({ kind, key }, ScheduleResourceRefType)), RefOption);
|
|
418
|
-
return resource.optional
|
|
419
|
-
? value.match({ none: (_$2) => East.value(none, RefOption), some: (_$2, key) => ref(key) })
|
|
420
|
-
: ref(value);
|
|
421
|
-
}
|
|
422
|
-
const of = resource.of;
|
|
423
|
-
const byCase = (v) => v.match(Object.fromEntries(resource.cases.map((c) => [c, (_$2, key) => East.value(some(East.value({ kind: of[c], key }, ScheduleResourceRefType)), RefOption)])));
|
|
424
|
-
return resource.optional
|
|
425
|
-
? value.match({ none: (_$2) => East.value(none, RefOption), some: (_$2, v) => byCase(v) })
|
|
426
|
-
: byCase(value);
|
|
427
|
-
});
|
|
409
|
+
const refOf = keyFieldRef(resource, rowType);
|
|
428
410
|
// The value a resource field takes for a placement's resource; `none` where the kind refuses it: a resource of a
|
|
429
411
|
// kind it does not take, or none for a field that must hold one.
|
|
430
|
-
const resourceValue = resource === undefined ? undefined : (
|
|
431
|
-
const valueType = fields[resource.field];
|
|
432
|
-
return East.function([RefOption], OptionType(valueType), ($, ref) => {
|
|
433
|
-
const result = $.let(East.value(none, OptionType(valueType)), OptionType(valueType));
|
|
434
|
-
$.match(ref, {
|
|
435
|
-
none: ($2) => {
|
|
436
|
-
if (resource.optional)
|
|
437
|
-
$2.assign(result, East.value(some(East.value(none, valueType)), OptionType(valueType)));
|
|
438
|
-
},
|
|
439
|
-
some: ($2, r) => {
|
|
440
|
-
if (resource.shape === "key") {
|
|
441
|
-
const key = resource.optional ? East.value(some(r.key), valueType) : r.key;
|
|
442
|
-
$2.if(East.equal(r.kind, resource.of), ($3) => { $3.assign(result, East.value(some(key), OptionType(valueType))); });
|
|
443
|
-
}
|
|
444
|
-
else {
|
|
445
|
-
for (const c of resource.cases) {
|
|
446
|
-
const caseValue = East.value(variant(c, r.key), resource.variant);
|
|
447
|
-
const held = resource.optional ? East.value(some(caseValue), valueType) : caseValue;
|
|
448
|
-
$2.if(East.equal(r.kind, resource.of[c]), ($3) => { $3.assign(result, East.value(some(held), OptionType(valueType))); });
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
},
|
|
452
|
-
});
|
|
453
|
-
return result;
|
|
454
|
-
});
|
|
455
|
-
})();
|
|
412
|
+
const resourceValue = resource === undefined ? undefined : keyFieldValue(resource, fields[resource.field]);
|
|
456
413
|
// A row of the record's type, field by field: its times and resource from a placement, the rest from `source`.
|
|
457
414
|
// An instant kind's `at` is its start.
|
|
458
415
|
const rowWith = (source, start, end, resourceField) => East.value(Object.fromEntries(Object.keys(fields).map((f) => [f,
|
|
@@ -476,51 +433,45 @@ export function scheduleEvents(record, input) {
|
|
|
476
433
|
return result;
|
|
477
434
|
});
|
|
478
435
|
// A setter for every field, at any depth: an inspector edit writes one (`field`), its value as bytes at the field's type.
|
|
479
|
-
const setters =
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
chain.push({ struct, field: step, at });
|
|
488
|
-
at = fieldOf(at, step);
|
|
489
|
-
struct = struct.fields[step];
|
|
490
|
-
}
|
|
491
|
-
const leaf = struct;
|
|
492
|
-
const leafAt = at;
|
|
493
|
-
let next = East.value(Object.fromEntries(Object.keys(leaf.fields).map((f) => [f, f === name ? value : fieldOf(leafAt, f)])), leaf);
|
|
494
|
-
for (let i = chain.length - 1; i >= 0; i--) {
|
|
495
|
-
const link = chain[i];
|
|
496
|
-
const inner = next;
|
|
497
|
-
next = East.value(Object.fromEntries(Object.keys(link.struct.fields).map((f) => [f, f === link.field ? inner : fieldOf(link.at, f)])), link.struct);
|
|
498
|
-
}
|
|
499
|
-
return next;
|
|
500
|
-
});
|
|
501
|
-
const collect = (struct, prefix) => {
|
|
502
|
-
for (const [name, type] of Object.entries(struct.fields)) {
|
|
503
|
-
setters.push({ path: [...prefix, name], set: setterOf(prefix, name, type) });
|
|
504
|
-
if (type.type === "Struct")
|
|
505
|
-
collect(type, [...prefix, name]);
|
|
506
|
-
}
|
|
507
|
-
};
|
|
508
|
-
collect(rowType, []);
|
|
509
|
-
const readsOf = (slot, part) => {
|
|
436
|
+
const setters = fieldSetters(rowType);
|
|
437
|
+
/**
|
|
438
|
+
* The reads, through the kind's source of its builder's slice when it has one — given `cap` (#1039, #1424), the
|
|
439
|
+
* Calendar's and the Plan's, its window counted first, through the source, through its day index or in memory, and
|
|
440
|
+
* read only within `cap`, its backlog whole. Given `pagedBacklog` (#1424, the Calendar's), a kind with a backlog
|
|
441
|
+
* narrowed through its source reads its window's rows alone: its builder pages the backlog through the source itself.
|
|
442
|
+
*/
|
|
443
|
+
const readsOf = (slot, part, cap, pagedBacklog = false) => {
|
|
510
444
|
if (part === undefined) {
|
|
511
445
|
if (entries !== undefined && dayWindow === undefined) {
|
|
512
446
|
throw new Error(`${where}: \`entries\` reads one event by its key beside \`window\`, or beside the kind's source of its builder's ` +
|
|
513
447
|
`Slice.bindRecords (one named "${slot}") — give one of those with it`);
|
|
514
448
|
}
|
|
515
449
|
const unscheduled = backlogWindow === undefined ? undefined : scheduleBacklogWindow(backlogWindow, keyType, rowType, where);
|
|
450
|
+
// A backlog index's read takes no window: the window is given, and read past.
|
|
451
|
+
const backlog = unscheduled === undefined ? undefined : East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, _from, _to) => {
|
|
452
|
+
const read = $.const(unscheduled);
|
|
453
|
+
return read();
|
|
454
|
+
});
|
|
455
|
+
// A record read whole under a cap (#1039): its window counted in memory first, and drawn only within the cap —
|
|
456
|
+
// past it the window answers none, and none of its events draws.
|
|
457
|
+
const capped = cap === undefined || dayWindow !== undefined ? undefined
|
|
458
|
+
: East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, from, to) => {
|
|
459
|
+
const count = $.const(countWhole);
|
|
460
|
+
const result = $.let(East.value(none, OptionType(HeldType)), OptionType(HeldType));
|
|
461
|
+
$.match(count(from, to), {
|
|
462
|
+
some: ($2, n) => {
|
|
463
|
+
$2.if(n.lessEqual(BigInt(cap)), ($3) => { $3.assign(result, East.value(some(readAll()), OptionType(HeldType))); });
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
return result;
|
|
467
|
+
});
|
|
516
468
|
return {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
backlog
|
|
520
|
-
|
|
521
|
-
return read();
|
|
522
|
-
}),
|
|
469
|
+
// A day index under a cap counts the days' entries first, and past it reads no page (#1039).
|
|
470
|
+
days: dayWindow === undefined ? capped : scheduleDayWindow(dayWindow, keyType, rowType, where, cap),
|
|
471
|
+
backlog,
|
|
472
|
+
alone: backlog,
|
|
523
473
|
withDrafts: withDraftsFor(false),
|
|
474
|
+
pagedBacklog: false,
|
|
524
475
|
};
|
|
525
476
|
}
|
|
526
477
|
if (dayWindow !== undefined || backlogWindow !== undefined) {
|
|
@@ -530,13 +481,20 @@ export function scheduleEvents(record, input) {
|
|
|
530
481
|
throw new Error(`${where}: the builder's source "${slot}" reads only its narrowing — and one event, the inspector's ` +
|
|
531
482
|
"or its editing's, is read by its key: give `entries` beside it, Data.bindPaged(record), the record's own entries");
|
|
532
483
|
}
|
|
533
|
-
const scheduled = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, false, where);
|
|
484
|
+
const scheduled = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, false, where, cap);
|
|
534
485
|
if (!optional)
|
|
535
|
-
return { days: scheduled, backlog: undefined, withDrafts: withDraftsFor(true) };
|
|
486
|
+
return { days: scheduled, backlog: undefined, alone: undefined, withDrafts: withDraftsFor(true), pagedBacklog: false };
|
|
487
|
+
const backlogged = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, true, where);
|
|
488
|
+
if (pagedBacklog) {
|
|
489
|
+
// Its builder pages its backlog through the source itself (#1424): the window is its rows alone, and a draft
|
|
490
|
+
// its host gives draws where it places its event — a backlog event scheduled into the window among them — the
|
|
491
|
+
// host having left out those of events the narrowing does not hold. Its backlog whole is `unscheduled`'s
|
|
492
|
+
// alone, which such a builder never asks.
|
|
493
|
+
return { days: scheduled, backlog: backlogged, alone: backlogged, withDrafts: withDraftsFor(false), pagedBacklog: true };
|
|
494
|
+
}
|
|
536
495
|
// A kind with a backlog reads both through its source as one: what its narrowing holds over the window and in
|
|
537
496
|
// its backlog. A draft then moves an event between the two by its times alone, and a draft the narrowing does
|
|
538
497
|
// not hold never shows in either (#1343).
|
|
539
|
-
const backlogged = scheduleRecordWindow(part, slot, keyType, rowType, startField, endField, optional, true, where);
|
|
540
498
|
const both = East.function([DateTimeType, DateTimeType], OptionType(HeldType), ($, from, to) => {
|
|
541
499
|
const inWindow = $.const(scheduled);
|
|
542
500
|
const inBacklog = $.const(backlogged);
|
|
@@ -554,7 +512,7 @@ export function scheduleEvents(record, input) {
|
|
|
554
512
|
});
|
|
555
513
|
return result;
|
|
556
514
|
});
|
|
557
|
-
return { days: both, backlog: both, withDrafts: withDraftsFor(true) };
|
|
515
|
+
return { days: both, backlog: both, alone: backlogged, withDrafts: withDraftsFor(true), pagedBacklog: false };
|
|
558
516
|
};
|
|
559
517
|
/** An item seam over a window: the events whose items `itemFn` makes that overlap `[from, to)`. */
|
|
560
518
|
const windowOf = (itemType, itemFn, reads) => East.function([DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, from, to, drafts) => {
|
|
@@ -622,6 +580,123 @@ export function scheduleEvents(record, input) {
|
|
|
622
580
|
}
|
|
623
581
|
return result;
|
|
624
582
|
});
|
|
583
|
+
// ── A kind a reader reads by a series index's cells (#1039) ──────────
|
|
584
|
+
// The reader gives the entries it read as one beast2 of `CellsType`; a long event its cells repeat, tile by tile,
|
|
585
|
+
// is one entry, held once by its key. Every draft it gives shows: it gives a draft of an entry it did not read only
|
|
586
|
+
// where its narrowing holds the entry, or the record does not.
|
|
587
|
+
/** The entries a reader read by cells, as the record's rows by key. */
|
|
588
|
+
const cellsHeld = East.function([BlobType], HeldType, ($, bytes) => {
|
|
589
|
+
const entries = $.const(bytes.decodeBeast(CellsType, "v2"));
|
|
590
|
+
const held = $.let(new Map(), HeldType);
|
|
591
|
+
$.for(entries, ($2, entry) => {
|
|
592
|
+
$2(held.insertOrUpdate(entry.key, entry.row, (_$3, _was, now) => now));
|
|
593
|
+
});
|
|
594
|
+
return held;
|
|
595
|
+
});
|
|
596
|
+
/** Every draft given in place over the entries a reader read by cells, as `withDraftsFor` gives them. */
|
|
597
|
+
const cellsInPlace = withDraftsFor(false);
|
|
598
|
+
/** An item seam over the entries a reader read by cells: the events whose items `itemFn` makes that overlap `[from, to)`, by the views' rule. */
|
|
599
|
+
const cellsOf = (itemType, itemFn) => East.function([BlobType, DateTimeType, DateTimeType, ScheduleDraftsType], ArrayType(itemType), ($, bytes, from, to, drafts) => {
|
|
600
|
+
const hold = $.const(cellsHeld);
|
|
601
|
+
const inPlace = $.const(cellsInPlace);
|
|
602
|
+
const item = $.const(itemFn);
|
|
603
|
+
const out = $.let([], ArrayType(itemType));
|
|
604
|
+
$.for(inPlace(hold(bytes), drafts), ($2, entry) => {
|
|
605
|
+
const one = $2.const(item(entry));
|
|
606
|
+
$2.match(one.start, {
|
|
607
|
+
some: ($3, s) => {
|
|
608
|
+
$3.match(one.end, {
|
|
609
|
+
some: ($4, e) => {
|
|
610
|
+
$4.if(East.less(s, to).and(() => East.greater(e, from).or(() => East.greaterEqual(s, from))), ($5) => {
|
|
611
|
+
$5(out.pushLast(one));
|
|
612
|
+
});
|
|
613
|
+
},
|
|
614
|
+
});
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
return out;
|
|
619
|
+
});
|
|
620
|
+
/**
|
|
621
|
+
* A backlog seam beside the entries a reader read by cells: the backlog read alone, never the window, with those
|
|
622
|
+
* entries held beside it — a draft moves an event between them by its times alone — the rows with no time, as
|
|
623
|
+
* `itemFn` makes them.
|
|
624
|
+
*/
|
|
625
|
+
const backlogBeside = (itemType, itemFn, reads) => East.function([BlobType, DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(ArrayType(itemType)), ($, bytes, from, to, drafts) => {
|
|
626
|
+
const result = $.let(East.value(some([]), OptionType(ArrayType(itemType))), OptionType(ArrayType(itemType)));
|
|
627
|
+
if (optional) {
|
|
628
|
+
const hold = $.const(cellsHeld);
|
|
629
|
+
const inPlace = $.const(cellsInPlace);
|
|
630
|
+
const item = $.const(itemFn);
|
|
631
|
+
let read;
|
|
632
|
+
if (reads.alone === undefined) {
|
|
633
|
+
read = $.let(East.value(some(readAll()), OptionType(HeldType)));
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
const alone = $.const(reads.alone);
|
|
637
|
+
read = $.let(alone(from, to));
|
|
638
|
+
}
|
|
639
|
+
$.assign(result, East.value(none, OptionType(ArrayType(itemType))));
|
|
640
|
+
$.match(read, {
|
|
641
|
+
some: ($2, rows) => {
|
|
642
|
+
const all = $2.let(hold(bytes));
|
|
643
|
+
$2(all.unionInPlace(rows, (_$3, held) => held));
|
|
644
|
+
const out = $2.let([], ArrayType(itemType));
|
|
645
|
+
$2.for(inPlace(all, drafts), ($3, entry) => {
|
|
646
|
+
const one = $3.const(item(entry));
|
|
647
|
+
$3.if(one.start.hasTag("none"), ($4) => { $4(out.pushLast(one)); });
|
|
648
|
+
});
|
|
649
|
+
$2.assign(result, East.value(some(out), OptionType(ArrayType(itemType))));
|
|
650
|
+
},
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return result;
|
|
654
|
+
});
|
|
655
|
+
/**
|
|
656
|
+
* One event by its key's text, the drafts in place, of a kind a reader reads by cells: the drafts, then its row as
|
|
657
|
+
* the reader holds it (`held`, none for one it does not), then the backlog read alone — but where its builder pages
|
|
658
|
+
* the backlog itself (#1424) — then its key; never the window.
|
|
659
|
+
*/
|
|
660
|
+
const readBeside = (makeItem, readType, reads) => East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType, OptionType(BlobType)], OptionType(readType), ($, id, drafts, from, to, held) => {
|
|
661
|
+
const parse = $.const(keyOf);
|
|
662
|
+
const make = $.const(makeItem);
|
|
663
|
+
const key = $.const(parse(id));
|
|
664
|
+
const row = $.let(East.value(none, OptionType(rowType)), OptionType(rowType));
|
|
665
|
+
const unread = $.let(true, BooleanType);
|
|
666
|
+
$.if(drafts.has(id), ($2) => {
|
|
667
|
+
$2.match(drafts.get(id).decodeBeast(draftType, "v2"), {
|
|
668
|
+
value: ($3, entry) => {
|
|
669
|
+
$3.assign(row, East.value(some(entry), OptionType(rowType)));
|
|
670
|
+
$3.assign(unread, false);
|
|
671
|
+
},
|
|
672
|
+
missing: ($3) => { $3.assign(unread, false); },
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
$.if(unread, ($2) => {
|
|
676
|
+
$2.match(held, { some: ($3, bytes) => { $3.assign(row, East.value(some(bytes.decodeBeast(rowType, "v2")), OptionType(rowType))); } });
|
|
677
|
+
// A builder that pages the backlog itself never has it read whole (#1424): its key reads one event.
|
|
678
|
+
if (reads.alone !== undefined && !reads.pagedBacklog) {
|
|
679
|
+
const alone = $2.const(reads.alone);
|
|
680
|
+
$2.if(row.hasTag("none"), ($3) => {
|
|
681
|
+
$3.match(alone(from, to), { some: ($4, rows) => { $4.assign(row, rows.tryGet(key)); } });
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
if (byKey === undefined) {
|
|
685
|
+
const all = $2.const(readAll());
|
|
686
|
+
$2.if(row.hasTag("none"), ($3) => { $3.assign(row, all.tryGet(key)); });
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
const find = $2.const(byKey);
|
|
690
|
+
$2.if(row.hasTag("none"), ($3) => {
|
|
691
|
+
$3.match(find(id), { held: ($4, stored) => { $4.assign(row, East.value(some(stored), OptionType(rowType))); } });
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
return row.match({
|
|
696
|
+
some: (_$2, r) => East.value(some({ item: make({ id, key, row: r }), row: East.Blob.encodeBeast(r, "v2") }), OptionType(readType)),
|
|
697
|
+
none: (_$2) => East.value(none, OptionType(readType)),
|
|
698
|
+
});
|
|
699
|
+
});
|
|
625
700
|
const readEvent = (makeItem, readType, reads) => East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType], OptionType(readType), ($, id, drafts, from, to) => {
|
|
626
701
|
const parse = $.const(keyOf);
|
|
627
702
|
const make = $.const(makeItem);
|
|
@@ -645,7 +720,8 @@ export function scheduleEvents(record, input) {
|
|
|
645
720
|
}
|
|
646
721
|
const days = $2.const(reads.days);
|
|
647
722
|
$2.match(days(from, to), { some: ($3, held) => { $3.assign(row, held.tryGet(key)); } });
|
|
648
|
-
|
|
723
|
+
// A builder that pages the backlog itself never has it read whole (#1424): its key reads one event.
|
|
724
|
+
if (reads.backlog !== undefined && !reads.pagedBacklog) {
|
|
649
725
|
const backlog = $2.const(reads.backlog);
|
|
650
726
|
$2.if(row.hasTag("none"), ($3) => {
|
|
651
727
|
$3.match(backlog(from, to), { some: ($4, held) => { $4.assign(row, held.tryGet(key)); } });
|
|
@@ -661,12 +737,114 @@ export function scheduleEvents(record, input) {
|
|
|
661
737
|
none: (_$2) => East.value(none, OptionType(readType)),
|
|
662
738
|
});
|
|
663
739
|
});
|
|
740
|
+
/**
|
|
741
|
+
* A kind's three read seams over its events as `itemFn` makes them (#1039): its events over a window, its backlog,
|
|
742
|
+
* and one event by its key — each from what a reader read by its series index's cells when it is given that, and
|
|
743
|
+
* never the window then; else over the window, as `reads` reads it.
|
|
744
|
+
*/
|
|
745
|
+
const readSeams = (itemType, itemFn, readType, reads) => {
|
|
746
|
+
const window = windowOf(itemType, itemFn, reads);
|
|
747
|
+
const cells = cellsOf(itemType, itemFn);
|
|
748
|
+
const items = East.function([DateTimeType, DateTimeType, ScheduleDraftsType, OptionType(BlobType)], OptionType(ArrayType(itemType)), ($, from, to, drafts, read) => {
|
|
749
|
+
const overWindow = $.const(window);
|
|
750
|
+
const fromCells = $.const(cells);
|
|
751
|
+
return read.match({
|
|
752
|
+
none: (_$2) => overWindow(from, to, drafts),
|
|
753
|
+
some: (_$2, bytes) => East.value(some(fromCells(bytes, from, to, drafts)), OptionType(ArrayType(itemType))),
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
const backlog = backlogOf(itemType, itemFn, reads);
|
|
757
|
+
const besideCells = backlogBeside(itemType, itemFn, reads);
|
|
758
|
+
const unscheduled = East.function([DateTimeType, DateTimeType, ScheduleDraftsType, OptionType(BlobType)], OptionType(ArrayType(itemType)), ($, from, to, drafts, read) => {
|
|
759
|
+
const overWindow = $.const(backlog);
|
|
760
|
+
const beside = $.const(besideCells);
|
|
761
|
+
return read.match({
|
|
762
|
+
none: (_$2) => overWindow(from, to, drafts),
|
|
763
|
+
some: (_$2, bytes) => beside(bytes, from, to, drafts),
|
|
764
|
+
});
|
|
765
|
+
});
|
|
766
|
+
const windowed = readEvent(itemFn, readType, reads);
|
|
767
|
+
const besideRead = readBeside(itemFn, readType, reads);
|
|
768
|
+
const event = East.function([StringType, ScheduleDraftsType, DateTimeType, DateTimeType, OptionType(OptionType(BlobType))], OptionType(readType), ($, id, drafts, from, to, held) => {
|
|
769
|
+
const overWindow = $.const(windowed);
|
|
770
|
+
const byCells = $.const(besideRead);
|
|
771
|
+
return held.match({
|
|
772
|
+
none: (_$2) => overWindow(id, drafts, from, to),
|
|
773
|
+
some: (_$2, row) => byCells(id, drafts, from, to, row),
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
return { items, unscheduled, event };
|
|
777
|
+
};
|
|
778
|
+
/**
|
|
779
|
+
* A kind's events' rows over a window and its backlog's beside them, by key, the drafts in place, read once (#1409,
|
|
780
|
+
* R24): the reads `event` finds one row in — the window's rows, then the backlog's where it is read apart from them —
|
|
781
|
+
* as the record's own Dict's bytes, so a run's request finds every event's row there rather than reading them all
|
|
782
|
+
* again an event. `none` while a read is in flight. It reads the window, never a reader's cells: a kind read by them
|
|
783
|
+
* carries no request.
|
|
784
|
+
*/
|
|
785
|
+
const rowsOver = (reads) => {
|
|
786
|
+
// A backlog read apart from the window's rows — a backlog index's, beside a day index — is read beside them; one
|
|
787
|
+
// read through the kind's source is read with them, and a record read whole holds it already.
|
|
788
|
+
const apart = reads.backlog !== undefined && !Object.is(reads.backlog, reads.days) && !reads.pagedBacklog;
|
|
789
|
+
// The entries held, the drafts in place, as the record's own Dict, by key: its bytes.
|
|
790
|
+
const heldBytes = East.function([ArrayType(EntryRowType)], BlobType, ($, entries) => {
|
|
791
|
+
const out = $.let(new Map(), HeldType);
|
|
792
|
+
$.for(entries, ($2, entry) => { $2(out.insert(entry.key, entry.row)); });
|
|
793
|
+
return East.Blob.encodeBeast(out, "v2");
|
|
794
|
+
});
|
|
795
|
+
return East.function([DateTimeType, DateTimeType, ScheduleDraftsType], OptionType(BlobType), ($, from, to, drafts) => {
|
|
796
|
+
const inPlace = $.const(reads.withDrafts);
|
|
797
|
+
const bytesOf = $.const(heldBytes);
|
|
798
|
+
const result = $.let(East.value(none, OptionType(BlobType)), OptionType(BlobType));
|
|
799
|
+
let read;
|
|
800
|
+
if (reads.days === undefined) {
|
|
801
|
+
read = $.let(East.value(some(readAll()), OptionType(HeldType)));
|
|
802
|
+
}
|
|
803
|
+
else {
|
|
804
|
+
const days = $.const(reads.days);
|
|
805
|
+
read = $.let(days(from, to));
|
|
806
|
+
}
|
|
807
|
+
$.match(read, {
|
|
808
|
+
some: ($2, rows) => {
|
|
809
|
+
if (!apart) {
|
|
810
|
+
$2.assign(result, East.value(some(bytesOf(inPlace(rows, drafts))), OptionType(BlobType)));
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
const backlog = $2.const(reads.backlog);
|
|
814
|
+
$2.match(backlog(from, to), {
|
|
815
|
+
some: ($3, more) => {
|
|
816
|
+
const all = $3.let(rows.copy());
|
|
817
|
+
$3(all.unionInPlace(more, (_$4, held) => held));
|
|
818
|
+
$3.assign(result, East.value(some(bytesOf(inPlace(all, drafts))), OptionType(BlobType)));
|
|
819
|
+
},
|
|
820
|
+
});
|
|
821
|
+
},
|
|
822
|
+
});
|
|
823
|
+
return result;
|
|
824
|
+
});
|
|
825
|
+
};
|
|
826
|
+
// The `.east` text of the value the resource field holds for a resource, or for none: what a series or a summary
|
|
827
|
+
// index of the record files the resource's events under (#1039), the key a reader's cells search for.
|
|
828
|
+
const seriesKey = East.function([RefOption], OptionType(StringType), ($, ref) => {
|
|
829
|
+
const result = $.let(none, OptionType(StringType));
|
|
830
|
+
if (resourceValue !== undefined) {
|
|
831
|
+
const resolve = $.const(resourceValue);
|
|
832
|
+
$.match(resolve(ref), { some: ($2, value) => { $2.assign(result, some(East.print(value))); } });
|
|
833
|
+
}
|
|
834
|
+
return result;
|
|
835
|
+
});
|
|
664
836
|
/**
|
|
665
837
|
* 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.
|
|
838
|
+
* function that makes one of its events. Given `cap`, its window — through its source, through its day index or in
|
|
839
|
+
* memory, its record read whole — is counted first and read only within it (#1039, #1424): the Calendar's and the
|
|
840
|
+
* Plan's. Every kind is counted before one of its events is read (`count`), through its source's interval index —
|
|
841
|
+
* the count its window's read asks first, so none of its own — through its day index, the days' entries the search
|
|
842
|
+
* its window's read asks first answers (an upper bound, never their number: `countExact` false), or in memory. Given
|
|
843
|
+
* `pagedBacklog` (#1424, the Calendar's), a kind with a backlog narrowed through its source reads its window's rows
|
|
844
|
+
* alone, its builder paging the backlog through the source itself.
|
|
667
845
|
*/
|
|
668
|
-
const kindParts = (slot, part, form) => {
|
|
669
|
-
const reads = readsOf(slot, part);
|
|
846
|
+
const kindParts = (slot, part, form, cap, pagedBacklog = false) => {
|
|
847
|
+
const reads = readsOf(slot, part, cap, pagedBacklog);
|
|
670
848
|
// One event, as every view draws it.
|
|
671
849
|
const itemOf = East.function([EntryRowType], ScheduleItemType, ($, entry) => {
|
|
672
850
|
const row = entry.row;
|
|
@@ -711,8 +889,13 @@ export function scheduleEvents(record, input) {
|
|
|
711
889
|
due,
|
|
712
890
|
}, ScheduleItemType);
|
|
713
891
|
});
|
|
714
|
-
const
|
|
715
|
-
|
|
892
|
+
const seams = readSeams(ScheduleItemType, itemOf, ScheduleReadType, reads);
|
|
893
|
+
// How many of its stored events overlap [from, to), counted before one is read (#1039): through its source's
|
|
894
|
+
// interval index — the count its window's read asks first, so none of its own; through its day index, the days'
|
|
895
|
+
// entries the search its window's read asks first answers — an event under each day it runs on, so an upper
|
|
896
|
+
// bound on them, never their number; or, its record read whole, in memory, by the views' rule.
|
|
897
|
+
const count = part !== undefined ? scheduleRecordCount(part, slot, keyType, rowType, startField, endField, optional, where)
|
|
898
|
+
: dayWindow !== undefined ? scheduleDayCount(dayWindow, where) : countWhole;
|
|
716
899
|
// Each template's values, by key, as the templates on the wire carry them.
|
|
717
900
|
const templateRows = boundTemplates ?? East.value(templates.map((t) => ({
|
|
718
901
|
key: t.key, name: t.name, group: t.group === undefined ? none : some(t.group),
|
|
@@ -803,20 +986,25 @@ export function scheduleEvents(record, input) {
|
|
|
803
986
|
templates: templateRows,
|
|
804
987
|
templatesSource: templatesSource === undefined ? none : some(templatesSource),
|
|
805
988
|
fields: East.value(form, ArrayType(FieldSpecType)),
|
|
806
|
-
items,
|
|
807
|
-
unscheduled,
|
|
989
|
+
items: seams.items,
|
|
990
|
+
unscheduled: seams.unscheduled,
|
|
808
991
|
write,
|
|
809
992
|
ready: ready === undefined ? none : some(ready),
|
|
810
993
|
editing,
|
|
811
994
|
entries: entriesSeam,
|
|
812
995
|
history: session.history,
|
|
813
|
-
event:
|
|
996
|
+
event: seams.event,
|
|
814
997
|
// A kind with no title names none: the Calendar and Plan, whose inspectors draw it, refuse one.
|
|
815
998
|
schedule: { title: titleField ?? "", start: startField, end: endField,
|
|
816
999
|
resource: resource === undefined ? none : some(resource.field),
|
|
817
1000
|
status: config.status === undefined ? none : some(config.status.field) },
|
|
818
1001
|
overlaps: variant(overlaps, null),
|
|
819
1002
|
inspector: inspector === undefined ? none : some(inspector),
|
|
1003
|
+
seriesKey,
|
|
1004
|
+
cellsType: toEastTypeValue(CellsType),
|
|
1005
|
+
count,
|
|
1006
|
+
// Every count but a day index's counts the events themselves.
|
|
1007
|
+
countExact: part !== undefined || dayWindow === undefined,
|
|
820
1008
|
};
|
|
821
1009
|
return { fields: fieldsOfKind, itemOf, reads };
|
|
822
1010
|
};
|
|
@@ -886,8 +1074,13 @@ export function scheduleEvents(record, input) {
|
|
|
886
1074
|
roles: [...rosterGiven, ...allocationGiven],
|
|
887
1075
|
partsOf: config.parts?.of,
|
|
888
1076
|
allocationValues,
|
|
1077
|
+
times: { start: startField, end: endField },
|
|
1078
|
+
resourceField: resource?.field,
|
|
1079
|
+
windowed: dayWindow !== undefined,
|
|
889
1080
|
build(slot, part) {
|
|
890
|
-
|
|
1081
|
+
// Its window counted first, and read only within the cap (#1424): past it, no page is read. The Calendar pages
|
|
1082
|
+
// a narrowed kind's backlog through its source itself, so its window reads the window's rows alone.
|
|
1083
|
+
return East.value(kindParts(slot, part, formSpecs, SCHEDULE_EVENT_CAP, true).fields, ScheduleKindType);
|
|
891
1084
|
},
|
|
892
1085
|
buildRoster(slot, part) {
|
|
893
1086
|
// A duty runs from its start to its end, keyed by String, on its slot's shift and group, rostered to someone.
|
|
@@ -1066,7 +1259,8 @@ export function scheduleEvents(record, input) {
|
|
|
1066
1259
|
}, ScheduleAllocationKindType);
|
|
1067
1260
|
},
|
|
1068
1261
|
buildPlan(slot, part) {
|
|
1069
|
-
|
|
1262
|
+
// Its window through its source counted first, and read only within the cap (#1039): past it, no page is read.
|
|
1263
|
+
const parts = kindParts(slot, part, formSpecs, SCHEDULE_EVENT_CAP);
|
|
1070
1264
|
const quantity = config.quantity;
|
|
1071
1265
|
const format = quantity?.format === undefined ? undefined : East.value(quantity.format, TickFormatType);
|
|
1072
1266
|
// One event as Plan draws it: what every view draws, with its roles read from their fields.
|
|
@@ -1087,12 +1281,10 @@ export function scheduleEvents(record, input) {
|
|
|
1087
1281
|
lane: laneField === undefined ? none : some(fieldOf(row, laneField)),
|
|
1088
1282
|
}, PlanEventItemType);
|
|
1089
1283
|
});
|
|
1090
|
-
// One event by its id, the drafts in place
|
|
1091
|
-
//
|
|
1092
|
-
//
|
|
1093
|
-
|
|
1094
|
-
// by its key.
|
|
1095
|
-
const planEvent = readEvent(planItemOf, PlanEventReadType, parts.reads);
|
|
1284
|
+
// One event by its id, the drafts in place, as Plan draws it, and its events and its backlog as Plan draws
|
|
1285
|
+
// them: the kind's three read seams over its own item (`readSeams`) — a kind a reader reads by its series
|
|
1286
|
+
// index's cells (#1039) given what it read, and never reading the window.
|
|
1287
|
+
const plan = readSeams(PlanEventItemType, planItemOf, PlanEventReadType, parts.reads);
|
|
1096
1288
|
const name = (field) => (field === undefined ? none : some(field));
|
|
1097
1289
|
return East.value({
|
|
1098
1290
|
...parts.fields,
|
|
@@ -1100,9 +1292,11 @@ export function scheduleEvents(record, input) {
|
|
|
1100
1292
|
instant: instantKind,
|
|
1101
1293
|
overlaps: variant(overlaps, null),
|
|
1102
1294
|
roles: { state: name(stateField), quantity: name(quantityField), lane: name(laneField) },
|
|
1103
|
-
planItems:
|
|
1104
|
-
planUnscheduled:
|
|
1105
|
-
planEvent,
|
|
1295
|
+
planItems: plan.items,
|
|
1296
|
+
planUnscheduled: plan.unscheduled,
|
|
1297
|
+
planEvent: plan.event,
|
|
1298
|
+
// Every event's row at once, for a run's request (#1409, R24): read once, never once an event.
|
|
1299
|
+
planRows: rowsOver(parts.reads),
|
|
1106
1300
|
inspector: inspector === undefined ? East.value(none, OptionType(RowInspectorType)) : East.value(some(inspector), OptionType(RowInspectorType)),
|
|
1107
1301
|
}, PlanEventKindType);
|
|
1108
1302
|
},
|