@almadar/std 16.187.0 → 16.189.0
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/behaviors/lolo/ui/core/.hand-authored.json +4 -4
- package/behaviors/lolo/ui/core/atoms/std-board.lolo +138 -4
- package/behaviors/lolo/ui/core/atoms/std-browse.lolo +148 -8
- package/behaviors/lolo/ui/core/atoms/std-calendar.lolo +161 -11
- package/behaviors/lolo/ui/core/atoms/std-event-log.lolo +255 -2
- package/behaviors/lolo/ui/core/atoms/std-gallery.lolo +148 -1
- package/behaviors/lolo/ui/core/atoms/std-list.lolo +193 -1
- package/behaviors/lolo/ui/core/atoms/std-record-detail.lolo +731 -0
- package/behaviors/lolo/ui/core/atoms/std-related.lolo +5 -1
- package/behaviors/lolo/ui/core/atoms/std-selection.lolo +182 -1
- package/behaviors/lolo/ui/core/atoms/std-tree.lolo +113 -3
- package/behaviors/lolo/ui/core/atoms/std-version-history.lolo +1 -1
- package/behaviors/lolo/ui/core/molecules/ui-document-details.lolo +80 -0
- package/behaviors/lolo/ui/core/molecules/ui-document-panel.lolo +213 -0
- package/behaviors/lolo/ui/core/molecules/{ui-rich-block-editor.lolo → ui-rich-text-editor.lolo} +25 -25
- package/behaviors/lolo/ui/game/atoms/std-area-fill.lolo +93 -0
- package/behaviors/lolo/ui/game/atoms/std-choice-gate.lolo +100 -0
- package/behaviors/lolo/ui/game/atoms/std-coef-pad.lolo +114 -0
- package/behaviors/lolo/ui/game/atoms/std-curve-fog.lolo +50 -0
- package/behaviors/lolo/ui/game/atoms/std-loop-lock.lolo +79 -0
- package/behaviors/lolo/ui/game/atoms/std-pad-lock.lolo +97 -0
- package/behaviors/lolo/ui/game/atoms/std-patrol-hazard.lolo +14 -7
- package/behaviors/lolo/ui/game/atoms/std-platformer-body.lolo +48 -5
- package/behaviors/lolo/ui/game/atoms/std-velocity-gate.lolo +101 -0
- package/behaviors/lolo/ui/game/atoms/std-zone-card.lolo +95 -0
- package/behaviors/lolo/ui/game/organisms/std-platformer-board-2d.lolo +9 -0
- package/behaviors/registry/infra/atoms/std-approval-gate.orb +16 -8
- package/behaviors/registry/infra/atoms/std-cache-aside.orb +62 -31
- package/behaviors/registry/infra/atoms/std-circuit-breaker.orb +32 -16
- package/behaviors/registry/infra/atoms/std-data-erasure.orb +16 -8
- package/behaviors/registry/infra/atoms/std-mod-queue.orb +16 -8
- package/behaviors/registry/infra/atoms/std-rate-limiter.orb +28 -14
- package/behaviors/registry/infra/organisms/std-status-lifecycle-control.orb +2 -1
- package/behaviors/registry/ml/organisms/std-escalating-decision.orb +10 -5
- package/behaviors/registry/ml/organisms/std-knowledge-tracing.orb +4 -2
- package/behaviors/registry/ui/core/atoms/std-billable-hour.orb +2 -1
- package/behaviors/registry/ui/core/atoms/std-board.orb +355 -2
- package/behaviors/registry/ui/core/atoms/std-browse.orb +304 -31
- package/behaviors/registry/ui/core/atoms/std-calendar.orb +393 -25
- package/behaviors/registry/ui/core/atoms/std-dashboard-grid-embedded.orb +2 -1
- package/behaviors/registry/ui/core/atoms/std-esign-flow.orb +4 -2
- package/behaviors/registry/ui/core/atoms/std-esign-request.orb +6 -3
- package/behaviors/registry/ui/core/atoms/std-event-log.orb +773 -0
- package/behaviors/registry/ui/core/atoms/std-export.orb +4 -2
- package/behaviors/registry/ui/core/atoms/std-gallery.orb +390 -0
- package/behaviors/registry/ui/core/atoms/std-import.orb +4 -2
- package/behaviors/registry/ui/core/atoms/std-list.orb +451 -0
- package/behaviors/registry/ui/core/atoms/std-record-detail.orb +3360 -0
- package/behaviors/registry/ui/core/atoms/std-related.orb +23 -1
- package/behaviors/registry/ui/core/atoms/std-selection.orb +436 -0
- package/behaviors/registry/ui/core/atoms/std-tree.orb +292 -1
- package/behaviors/registry/ui/core/atoms/std-version-history.orb +1 -1
- package/behaviors/registry/ui/core/molecules/ui-document-details.orb +342 -0
- package/behaviors/registry/ui/core/molecules/ui-document-panel.orb +655 -0
- package/behaviors/registry/ui/core/molecules/{ui-rich-block-editor.orb → ui-rich-text-editor.orb} +84 -97
- package/behaviors/registry/ui/game/atoms/std-area-fill.orb +955 -0
- package/behaviors/registry/ui/game/atoms/std-choice-gate.orb +855 -0
- package/behaviors/registry/ui/game/atoms/std-coef-pad.orb +928 -0
- package/behaviors/registry/ui/game/atoms/std-curve-fog.orb +337 -0
- package/behaviors/registry/ui/game/atoms/std-fx-trail.orb +1 -1
- package/behaviors/registry/ui/game/atoms/std-gate-lock.orb +1 -1
- package/behaviors/registry/ui/game/atoms/std-lives.orb +1 -1
- package/behaviors/registry/ui/game/atoms/std-loop-lock.orb +785 -0
- package/behaviors/registry/ui/game/atoms/std-pad-lock.orb +933 -0
- package/behaviors/registry/ui/game/atoms/std-patrol-hazard.orb +190 -44
- package/behaviors/registry/ui/game/atoms/std-platformer-body.orb +1330 -653
- package/behaviors/registry/ui/game/atoms/std-velocity-gate.orb +1040 -0
- package/behaviors/registry/ui/game/atoms/std-zone-card.orb +642 -0
- package/behaviors/registry/ui/game/organisms/std-arcade-board-3d.orb +8 -4
- package/behaviors/registry/ui/game/organisms/std-crew-board-2d.orb +6 -3
- package/behaviors/registry/ui/game/organisms/std-dungeon-board-2d.orb +10 -5
- package/behaviors/registry/ui/game/organisms/std-market-board-3d.orb +8 -4
- package/behaviors/registry/ui/game/organisms/std-objective-board-3d.orb +8 -4
- package/behaviors/registry/ui/game/organisms/std-platformer-board-2d.orb +36 -1
- package/behaviors/registry/ui/game/organisms/std-survival-board-3d.orb +8 -4
- package/behaviors/registry/ui/game/organisms/std-tactics-board-2d.orb +12 -6
- package/behaviors/registry/ui/game/organisms/std-tactics-board-3d.orb +8 -4
- package/behaviors/registry/ui/game/organisms/std-worldmap-board-2d.orb +6 -3
- package/behaviors/registry/ui/learning/atoms/std-learn-slope-probe.orb +1 -1
- package/behaviors/registry/ui/marketing/atoms/std-marketing-article.orb +2 -1
- package/behaviors/registry/ui/marketing/atoms/std-marketing-footer.orb +2 -1
- package/behaviors/registry/ui/marketing/atoms/std-marketing-split.orb +2 -1
- package/behaviors/registry/ui/marketing/atoms/std-marketing-stats.orb +2 -1
- package/behaviors/registry/ui/marketing/atoms/std-marketing-steps.orb +2 -1
- package/behaviors/registry/ui/marketing/atoms/std-marketing-team.orb +2 -1
- package/dist/behaviors/exports-reader.js +10971 -6255
- package/dist/behaviors/functions/index.d.ts +1205 -256
- package/dist/behaviors/functions/index.js +10932 -6245
- package/dist/behaviors/index.d.ts +1 -1
- package/dist/behaviors/index.js +10972 -6256
- package/dist/behaviors/query.js +10971 -6255
- package/dist/behaviors-embeddings.hash.json +3 -3
- package/dist/behaviors-embeddings.json +485 -469
- package/dist/behaviors-registry.json +6125 -2940
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10972 -6256
- package/dist/knob-embeddings.hash.json +3 -3
- package/dist/knob-embeddings.json +1 -1
- package/dist/registry/factory-signatures.json +1 -1
- package/package.json +4 -4
- package/behaviors/lolo/ui/core/atoms/std-rich-editor.lolo +0 -790
- package/behaviors/registry/ui/core/atoms/std-rich-editor.orb +0 -2225
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
app std-calendar "1.4.0"
|
|
2
2
|
"std-calendar as a Function — owns the fetch + SELECT_DAY state machine; default bodyContent renders the month-grid + upcoming-events tree. `config.calendarLook` switches the body between the default month-grid ('month'), a day-grouped agenda list ('agenda-list'), and a 7-column week timeline ('week-timeline') while inheriting the same trait, state machine, emits, and listens."
|
|
3
3
|
type ItemAction = { label : string!, event : string, navigatesTo : string, variant : primary | secondary | ghost | danger, icon : string }
|
|
4
|
+
type FilterSpec = { field : string!, label : string, options : [string] }
|
|
4
5
|
orbital CalendarEventOrbital {
|
|
5
6
|
type CalendarEventLoaded = Event { data : [CalendarEvent] } "Fired when CalendarEvent finishes loading; payload.data holds the events"
|
|
6
7
|
|
|
@@ -27,6 +28,7 @@ orbital CalendarEventOrbital {
|
|
|
27
28
|
(set @entity.weekAnchor (time/now))
|
|
28
29
|
(fetch CalendarEvent {
|
|
29
30
|
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
31
|
+
include: @config.include
|
|
30
32
|
})
|
|
31
33
|
(render-ui main {
|
|
32
34
|
align: center
|
|
@@ -81,6 +83,7 @@ orbital CalendarEventOrbital {
|
|
|
81
83
|
INIT -> loading
|
|
82
84
|
(fetch CalendarEvent {
|
|
83
85
|
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
86
|
+
include: @config.include
|
|
84
87
|
})
|
|
85
88
|
(render-ui main { type: spinner })
|
|
86
89
|
SELECT_DAY -> loading
|
|
@@ -89,17 +92,36 @@ orbital CalendarEventOrbital {
|
|
|
89
92
|
;; hardcoded `date`, which retargeted consumers (startField=startTime) lack
|
|
90
93
|
(fetch CalendarEvent {
|
|
91
94
|
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
95
|
+
include: @config.include
|
|
92
96
|
filter: (time/isAfter (time/parse (object/get @entity @config.startField)) (if ["=", ?value, week] (time/subtract (time/now) 1 week) (if ["=", ?value, "3months"] (time/subtract (time/now) 3 month) (if ["=", ?value, year] (time/subtract (time/now) 1 year) (time/subtract (time/now) 1 month)))))
|
|
93
97
|
})
|
|
94
98
|
CALENDAR_PREV_WEEK -> loading
|
|
95
99
|
(set @entity.weekAnchor (time/subtract @entity.weekAnchor 1 week))
|
|
96
100
|
(fetch CalendarEvent {
|
|
97
101
|
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
102
|
+
include: @config.include
|
|
98
103
|
})
|
|
99
104
|
CALENDAR_NEXT_WEEK -> loading
|
|
100
105
|
(set @entity.weekAnchor (time/add @entity.weekAnchor 1 week))
|
|
101
106
|
(fetch CalendarEvent {
|
|
102
107
|
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
108
|
+
include: @config.include
|
|
109
|
+
})
|
|
110
|
+
;; Same no-render-ui shape as SELECT_DAY/CALENDAR_*_WEEK above: transition
|
|
111
|
+
;; to `loading` without repainting, so the current grid/agenda/timeline
|
|
112
|
+
;; stays mounted until CalendarEventLoaded's own render-ui fires — a
|
|
113
|
+
;; repaint here would flicker the toolbar's search-input every keystroke.
|
|
114
|
+
REFETCH_QUERY -> loading
|
|
115
|
+
(fetch CalendarEvent {
|
|
116
|
+
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
117
|
+
include: @config.include
|
|
118
|
+
filter: (or ["=", ?searchTerm, ""] (str/includes (object/get @entity name) ?searchTerm))
|
|
119
|
+
})
|
|
120
|
+
REFETCH_FILTER -> loading
|
|
121
|
+
(fetch CalendarEvent {
|
|
122
|
+
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
123
|
+
include: @config.include
|
|
124
|
+
filter: (or ["=", ?value, ""] ["=", (object/get @entity ?field), ?value])
|
|
103
125
|
})
|
|
104
126
|
}
|
|
105
127
|
|
|
@@ -107,6 +129,7 @@ orbital CalendarEventOrbital {
|
|
|
107
129
|
INIT -> loading
|
|
108
130
|
(fetch CalendarEvent {
|
|
109
131
|
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
132
|
+
include: @config.include
|
|
110
133
|
})
|
|
111
134
|
(render-ui main { type: spinner })
|
|
112
135
|
;; the error screen's Retry button: INIT is lifecycle-only and the bus never
|
|
@@ -114,6 +137,7 @@ orbital CalendarEventOrbital {
|
|
|
114
137
|
RETRY -> loading
|
|
115
138
|
(fetch CalendarEvent {
|
|
116
139
|
emit: { failure: CalendarEventLoadFailed, success: CalendarEventLoaded }
|
|
140
|
+
include: @config.include
|
|
117
141
|
})
|
|
118
142
|
(render-ui main { type: spinner })
|
|
119
143
|
}
|
|
@@ -128,9 +152,11 @@ orbital CalendarEventOrbital {
|
|
|
128
152
|
@synonyms "error, failed, problem, loading issue"
|
|
129
153
|
@tier "internal"
|
|
130
154
|
@config.onEventClick -> external {
|
|
131
|
-
event :
|
|
155
|
+
event : @entity
|
|
156
|
+
id : string
|
|
157
|
+
row : @entity
|
|
132
158
|
}
|
|
133
|
-
@description "Emitted when a calendar chip is clicked
|
|
159
|
+
@description "Emitted when a calendar chip is clicked ({ event } carries the clicked row) or an agenda/upcoming row action fires ({ id, row }). Consumers routing it should read the row from ?event or ?row, whichever the payload carries."
|
|
134
160
|
@tier "presentation"
|
|
135
161
|
}
|
|
136
162
|
|
|
@@ -162,6 +188,19 @@ orbital CalendarEventOrbital {
|
|
|
162
188
|
@description "Move the week timeline one week later."
|
|
163
189
|
@synonyms "next week, forward a week, later week, following week"
|
|
164
190
|
@tier "domain"
|
|
191
|
+
REFETCH_QUERY {
|
|
192
|
+
searchTerm : string!
|
|
193
|
+
}
|
|
194
|
+
@description "Triggers a data refresh based on the current query."
|
|
195
|
+
@synonyms "refresh, reload, update, re-query"
|
|
196
|
+
@tier "domain"
|
|
197
|
+
REFETCH_FILTER {
|
|
198
|
+
field : string!
|
|
199
|
+
value : string!
|
|
200
|
+
}
|
|
201
|
+
@description "Triggers a data refresh based on current filter criteria."
|
|
202
|
+
@synonyms "refresh, filter, update, reload"
|
|
203
|
+
@tier "domain"
|
|
165
204
|
}
|
|
166
205
|
|
|
167
206
|
config {
|
|
@@ -185,6 +224,11 @@ orbital CalendarEventOrbital {
|
|
|
185
224
|
@label "Description binding"
|
|
186
225
|
@description "Per-row binding for the event description slot."
|
|
187
226
|
@tier "presentation"
|
|
227
|
+
include : [string] = []
|
|
228
|
+
@label "Which relation fields to hydrate?"
|
|
229
|
+
@description "Entity relation field names to hydrate on fetch (e.g. a `category : Category` field named `category`), so chip bindings can use dot-paths like @item.category.name. Empty = no hydration, the default."
|
|
230
|
+
@synonyms "relation hydration, populate relations, joined fields, hydrate relations"
|
|
231
|
+
@tier "internal"
|
|
188
232
|
startField : string = "date"
|
|
189
233
|
@label "Start field"
|
|
190
234
|
@description "Row column holding the timestamp the calendar grid places each chip by. Rebound hosts point this at their own column (e.g. startTime, startsAt, dueAt); the chip's LABEL comes from titleBinding, not from here."
|
|
@@ -203,7 +247,7 @@ orbital CalendarEventOrbital {
|
|
|
203
247
|
@label "Title"
|
|
204
248
|
@description "Header text shown above the calendar body."
|
|
205
249
|
@tier "presentation"
|
|
206
|
-
agendaItemActions : [ItemAction] = [
|
|
250
|
+
agendaItemActions : [ItemAction] = []
|
|
207
251
|
@label "Agenda item actions"
|
|
208
252
|
@description "Per-item action buttons on agenda-list rows — data-list itemActions descriptors (label/event/icon/variant). Consumers override to wire their own row actions (View/Edit/Delete) so agenda hosts never need a second table for actions."
|
|
209
253
|
@synonyms "agenda actions, row actions, event actions, list actions"
|
|
@@ -213,6 +257,26 @@ orbital CalendarEventOrbital {
|
|
|
213
257
|
@description "Row field the agenda list groups its day sections by. Rebound hosts point this at their own timestamp column (e.g. startTime, scheduledAt)."
|
|
214
258
|
@synonyms "group field, section field, day field"
|
|
215
259
|
@tier "presentation"
|
|
260
|
+
bodySearch : boolean = false
|
|
261
|
+
@label "Show the calendar's own search box?"
|
|
262
|
+
@description "Embeds a title search box in the toolbar above the calendar body (all three calendarLook trees). Defaults false: std-calendar has never had a search box, so an untouched consumer's surface is unchanged; the primary path is composing std-search beside this atom and wiring XSearch.SEARCH -> REFETCH_QUERY. Set true only for a standalone calendar with no page-level search affordance."
|
|
263
|
+
@synonyms "inline search, calendar search, built-in search, show search, duplicate search"
|
|
264
|
+
@tier "presentation"
|
|
265
|
+
searchPlaceholder : string = "Search…"
|
|
266
|
+
@label "Search box placeholder text"
|
|
267
|
+
@description "Hint text inside the calendar's search box (e.g. 'Search events…')."
|
|
268
|
+
@synonyms "search hint, placeholder, search box text, search label"
|
|
269
|
+
@tier "presentation"
|
|
270
|
+
filters : [FilterSpec] = []
|
|
271
|
+
@label "Which filters should appear above the calendar?"
|
|
272
|
+
@description "Dropdown filter facets by field, rendered as an embedded filter bar above the calendar body (all three calendarLook trees); each selection fires REFETCH_FILTER on this trait. Empty (the default) = no filter bar, which is the right setting whenever the page already composes std-filter beside this calendar and routes XFilter.FILTER -> REFETCH_FILTER — that is the wired owner and remains the primary path. Use this knob only for a standalone calendar with no page-level filter affordance."
|
|
273
|
+
@synonyms "filter bar, faceted filters, field filters, dropdowns"
|
|
274
|
+
@tier "presentation"
|
|
275
|
+
filterBarLook : "toolbar" | "chips" | "pills" | "popover-trigger" | "inline-column-header" = toolbar
|
|
276
|
+
@label "Filter bar look"
|
|
277
|
+
@description "Visual treatment for the embedded filter bar, mirroring std-filter's own enum. Only applies when `filters` is non-empty."
|
|
278
|
+
@synonyms "filter bar style, facet style, chips, pills"
|
|
279
|
+
@tier "presentation"
|
|
216
280
|
bodyContent : render-ui = {
|
|
217
281
|
children: [{
|
|
218
282
|
align: center
|
|
@@ -235,7 +299,37 @@ orbital CalendarEventOrbital {
|
|
|
235
299
|
gap: md
|
|
236
300
|
justify: between
|
|
237
301
|
type: stack
|
|
238
|
-
},
|
|
302
|
+
}, (if @config.bodySearch {
|
|
303
|
+
children: [{
|
|
304
|
+
className: "w-full max-w-md"
|
|
305
|
+
clearable: true
|
|
306
|
+
event: REFETCH_QUERY
|
|
307
|
+
placeholder: @config.searchPlaceholder
|
|
308
|
+
type: search-input
|
|
309
|
+
}]
|
|
310
|
+
direction: horizontal
|
|
311
|
+
gap: sm
|
|
312
|
+
type: stack
|
|
313
|
+
} {
|
|
314
|
+
children: []
|
|
315
|
+
gap: none
|
|
316
|
+
type: stack
|
|
317
|
+
}), (if [">", (array/len @config.filters), 0] {
|
|
318
|
+
children: [{
|
|
319
|
+
entity: CalendarEvent
|
|
320
|
+
event: REFETCH_FILTER
|
|
321
|
+
filters: @config.filters
|
|
322
|
+
look: @config.filterBarLook
|
|
323
|
+
type: filter-group
|
|
324
|
+
}]
|
|
325
|
+
direction: horizontal
|
|
326
|
+
gap: sm
|
|
327
|
+
type: stack
|
|
328
|
+
} {
|
|
329
|
+
children: []
|
|
330
|
+
gap: none
|
|
331
|
+
type: stack
|
|
332
|
+
}), { type: divider }, {
|
|
239
333
|
events: ?data
|
|
240
334
|
onEventClick: @config.onEventClick
|
|
241
335
|
renderItem: (fn item {
|
|
@@ -270,11 +364,7 @@ orbital CalendarEventOrbital {
|
|
|
270
364
|
name: status
|
|
271
365
|
variant: badge
|
|
272
366
|
}]
|
|
273
|
-
itemActions:
|
|
274
|
-
event: SELECT_DAY
|
|
275
|
-
icon: eye
|
|
276
|
-
label: View
|
|
277
|
-
}]
|
|
367
|
+
itemActions: @config.agendaItemActions
|
|
278
368
|
look: @config.tableLook
|
|
279
369
|
type: data-list
|
|
280
370
|
}]
|
|
@@ -307,7 +397,37 @@ orbital CalendarEventOrbital {
|
|
|
307
397
|
gap: md
|
|
308
398
|
justify: between
|
|
309
399
|
type: stack
|
|
310
|
-
},
|
|
400
|
+
}, (if @config.bodySearch {
|
|
401
|
+
children: [{
|
|
402
|
+
className: "w-full max-w-md"
|
|
403
|
+
clearable: true
|
|
404
|
+
event: REFETCH_QUERY
|
|
405
|
+
placeholder: @config.searchPlaceholder
|
|
406
|
+
type: search-input
|
|
407
|
+
}]
|
|
408
|
+
direction: horizontal
|
|
409
|
+
gap: sm
|
|
410
|
+
type: stack
|
|
411
|
+
} {
|
|
412
|
+
children: []
|
|
413
|
+
gap: none
|
|
414
|
+
type: stack
|
|
415
|
+
}), (if [">", (array/len @config.filters), 0] {
|
|
416
|
+
children: [{
|
|
417
|
+
entity: CalendarEvent
|
|
418
|
+
event: REFETCH_FILTER
|
|
419
|
+
filters: @config.filters
|
|
420
|
+
look: @config.filterBarLook
|
|
421
|
+
type: filter-group
|
|
422
|
+
}]
|
|
423
|
+
direction: horizontal
|
|
424
|
+
gap: sm
|
|
425
|
+
type: stack
|
|
426
|
+
} {
|
|
427
|
+
children: []
|
|
428
|
+
gap: none
|
|
429
|
+
type: stack
|
|
430
|
+
}), { type: divider }, {
|
|
311
431
|
entity: ?data
|
|
312
432
|
fields: []
|
|
313
433
|
gap: md
|
|
@@ -429,7 +549,37 @@ orbital CalendarEventOrbital {
|
|
|
429
549
|
gap: md
|
|
430
550
|
justify: between
|
|
431
551
|
type: stack
|
|
432
|
-
},
|
|
552
|
+
}, (if @config.bodySearch {
|
|
553
|
+
children: [{
|
|
554
|
+
className: "w-full max-w-md"
|
|
555
|
+
clearable: true
|
|
556
|
+
event: REFETCH_QUERY
|
|
557
|
+
placeholder: @config.searchPlaceholder
|
|
558
|
+
type: search-input
|
|
559
|
+
}]
|
|
560
|
+
direction: horizontal
|
|
561
|
+
gap: sm
|
|
562
|
+
type: stack
|
|
563
|
+
} {
|
|
564
|
+
children: []
|
|
565
|
+
gap: none
|
|
566
|
+
type: stack
|
|
567
|
+
}), (if [">", (array/len @config.filters), 0] {
|
|
568
|
+
children: [{
|
|
569
|
+
entity: CalendarEvent
|
|
570
|
+
event: REFETCH_FILTER
|
|
571
|
+
filters: @config.filters
|
|
572
|
+
look: @config.filterBarLook
|
|
573
|
+
type: filter-group
|
|
574
|
+
}]
|
|
575
|
+
direction: horizontal
|
|
576
|
+
gap: sm
|
|
577
|
+
type: stack
|
|
578
|
+
} {
|
|
579
|
+
children: []
|
|
580
|
+
gap: none
|
|
581
|
+
type: stack
|
|
582
|
+
}), { type: divider }, {
|
|
433
583
|
className: w-full
|
|
434
584
|
dayWindow: 7
|
|
435
585
|
events: ?data
|
|
@@ -2,6 +2,7 @@ app std-event-log "2.1.0"
|
|
|
2
2
|
"std-event-log — generic chronological event feed (Stripe activity log / GitHub PR timeline / Linear event feed style). Renders a vertical `timeline` with type-coded dots, a single horizontal chip-bar of kind filters (All + per-kind), reverse-chronological sort, and an inline form for logging events that weren't auto-captured. `config.kindOptions` maps each kind → status/icon/label so consuming molecules/organisms get type-coded visuals without re-implementing topology. Topology = loading / viewing / backfilling / error."
|
|
3
3
|
type ObjectSpec = { id : string, label : string, value : string }
|
|
4
4
|
type KindOption = { label : string!, value : string! }
|
|
5
|
+
type FilterSpec = { field : string!, label : string, options : [string] }
|
|
5
6
|
orbital EventLogOrbital {
|
|
6
7
|
type LogEntry = { id : string!, title : string!, description : string, date : string, status : "complete" | "active" | "pending" | "error", kind : "created" | "updated" | "approved" | "rejected" }
|
|
7
8
|
|
|
@@ -89,7 +90,37 @@ orbital EventLogOrbital {
|
|
|
89
90
|
direction: horizontal
|
|
90
91
|
gap: sm
|
|
91
92
|
type: stack
|
|
92
|
-
}, {
|
|
93
|
+
}, (if @config.bodySearch {
|
|
94
|
+
children: [{
|
|
95
|
+
className: "w-full max-w-md"
|
|
96
|
+
clearable: true
|
|
97
|
+
event: REFETCH_QUERY
|
|
98
|
+
placeholder: @config.searchPlaceholder
|
|
99
|
+
type: search-input
|
|
100
|
+
}]
|
|
101
|
+
direction: horizontal
|
|
102
|
+
gap: sm
|
|
103
|
+
type: stack
|
|
104
|
+
} {
|
|
105
|
+
children: []
|
|
106
|
+
gap: none
|
|
107
|
+
type: stack
|
|
108
|
+
}), (if [">", (array/len @config.filters), 0] {
|
|
109
|
+
children: [{
|
|
110
|
+
entity: EventLogView
|
|
111
|
+
event: REFETCH_FILTER
|
|
112
|
+
filters: @config.filters
|
|
113
|
+
look: @config.filterBarLook
|
|
114
|
+
type: filter-group
|
|
115
|
+
}]
|
|
116
|
+
direction: horizontal
|
|
117
|
+
gap: sm
|
|
118
|
+
type: stack
|
|
119
|
+
} {
|
|
120
|
+
children: []
|
|
121
|
+
gap: none
|
|
122
|
+
type: stack
|
|
123
|
+
}), {
|
|
93
124
|
activeTab: @entity.filterKind
|
|
94
125
|
tabChangeEvent: APPLY_FILTER
|
|
95
126
|
tabs: @entity.filterChips
|
|
@@ -155,7 +186,150 @@ orbital EventLogOrbital {
|
|
|
155
186
|
direction: horizontal
|
|
156
187
|
gap: sm
|
|
157
188
|
type: stack
|
|
189
|
+
}, (if @config.bodySearch {
|
|
190
|
+
children: [{
|
|
191
|
+
className: "w-full max-w-md"
|
|
192
|
+
clearable: true
|
|
193
|
+
event: REFETCH_QUERY
|
|
194
|
+
placeholder: @config.searchPlaceholder
|
|
195
|
+
type: search-input
|
|
196
|
+
}]
|
|
197
|
+
direction: horizontal
|
|
198
|
+
gap: sm
|
|
199
|
+
type: stack
|
|
200
|
+
} {
|
|
201
|
+
children: []
|
|
202
|
+
gap: none
|
|
203
|
+
type: stack
|
|
204
|
+
}), (if [">", (array/len @config.filters), 0] {
|
|
205
|
+
children: [{
|
|
206
|
+
entity: EventLogView
|
|
207
|
+
event: REFETCH_FILTER
|
|
208
|
+
filters: @config.filters
|
|
209
|
+
look: @config.filterBarLook
|
|
210
|
+
type: filter-group
|
|
211
|
+
}]
|
|
212
|
+
direction: horizontal
|
|
213
|
+
gap: sm
|
|
214
|
+
type: stack
|
|
215
|
+
} {
|
|
216
|
+
children: []
|
|
217
|
+
gap: none
|
|
218
|
+
type: stack
|
|
219
|
+
}), {
|
|
220
|
+
activeTab: @entity.filterKind
|
|
221
|
+
tabChangeEvent: APPLY_FILTER
|
|
222
|
+
tabs: @entity.filterChips
|
|
223
|
+
type: tabs
|
|
158
224
|
}, {
|
|
225
|
+
entity: @entity.entries
|
|
226
|
+
fields: (title description date status)
|
|
227
|
+
look: @config.timelineLook
|
|
228
|
+
type: timeline
|
|
229
|
+
}]
|
|
230
|
+
direction: vertical
|
|
231
|
+
gap: md
|
|
232
|
+
type: stack
|
|
233
|
+
})
|
|
234
|
+
;; REFETCH_* stays in `viewing` and DOES NOT replace the timeline with a
|
|
235
|
+
;; skeleton — same reasoning as std-browse's REFETCH_* arms: a skeleton
|
|
236
|
+
;; on refetch unmounts the timeline and flickers every keystroke. The
|
|
237
|
+
;; fetch fires in the background; the EventLogLoaded arm below re-renders
|
|
238
|
+
;; in place once it lands. Each refetch also honours the current kind
|
|
239
|
+
;; tab (@entity.filterKind) so search/generic-filter compound with it
|
|
240
|
+
;; instead of resetting it.
|
|
241
|
+
REFETCH_QUERY -> viewing
|
|
242
|
+
(fetch EventLogView {
|
|
243
|
+
emit: { failure: EventLogLoadFailed, success: EventLogLoaded }
|
|
244
|
+
filter: (and (or ["=", @entity.filterKind, ""] ["=", (object/get @entity kind), @entity.filterKind]) (or ["=", ?searchTerm, ""] (str/includes (object/get @entity title) ?searchTerm)))
|
|
245
|
+
})
|
|
246
|
+
REFETCH_FILTER -> viewing
|
|
247
|
+
(fetch EventLogView {
|
|
248
|
+
emit: { failure: EventLogLoadFailed, success: EventLogLoaded }
|
|
249
|
+
filter: (and (or ["=", @entity.filterKind, ""] ["=", (object/get @entity kind), @entity.filterKind]) (or ["=", ?value, ""] ["=", (object/get @entity ?field), ?value]))
|
|
250
|
+
})
|
|
251
|
+
;; No filter carried over on REFETCH_PAGE, mirroring std-browse exactly —
|
|
252
|
+
;; the reference page arm does not preserve query/filter either.
|
|
253
|
+
REFETCH_PAGE -> viewing
|
|
254
|
+
(fetch EventLogView {
|
|
255
|
+
emit: { failure: EventLogLoadFailed, success: EventLogLoaded }
|
|
256
|
+
limit: @config.pageSize
|
|
257
|
+
offset: ["*", ["-", ?page, 1], @config.pageSize]
|
|
258
|
+
})
|
|
259
|
+
EventLogLoaded -> viewing
|
|
260
|
+
(set @entity.filterChips (array/prepend (array/map @config.kindOptions (fn k {
|
|
261
|
+
icon: (object/get @k icon circle)
|
|
262
|
+
id: (object/get @k key)
|
|
263
|
+
label: (object/get @k label)
|
|
264
|
+
})) {
|
|
265
|
+
icon: list
|
|
266
|
+
id: ""
|
|
267
|
+
label: All
|
|
268
|
+
}))
|
|
269
|
+
(set @entity.allEntries (array/sort (array/map ?data (fn row {
|
|
270
|
+
date: (object/get @row createdAt (object/get @row date ""))
|
|
271
|
+
description: (object/get @row description "")
|
|
272
|
+
id: (object/get @row id "")
|
|
273
|
+
kind: (object/get @row kind "")
|
|
274
|
+
status: (object/get (or (array/find @config.kindOptions (fn k ["=", (object/get @k key), (object/get @row kind "")])) {}) status pending)
|
|
275
|
+
title: (object/get @row title "")
|
|
276
|
+
})) date desc))
|
|
277
|
+
(set @entity.entries (array/sort (array/map ?data (fn row {
|
|
278
|
+
date: (object/get @row createdAt (object/get @row date ""))
|
|
279
|
+
description: (object/get @row description "")
|
|
280
|
+
id: (object/get @row id "")
|
|
281
|
+
kind: (object/get @row kind "")
|
|
282
|
+
status: (object/get (or (array/find @config.kindOptions (fn k ["=", (object/get @k key), (object/get @row kind "")])) {}) status pending)
|
|
283
|
+
title: (object/get @row title "")
|
|
284
|
+
})) date desc))
|
|
285
|
+
(render-ui main {
|
|
286
|
+
children: [{
|
|
287
|
+
align: center
|
|
288
|
+
children: [{ name: history, type: icon }, {
|
|
289
|
+
content: @config.title
|
|
290
|
+
type: typography
|
|
291
|
+
variant: h3
|
|
292
|
+
}, {
|
|
293
|
+
action: OPEN_BACKFILL
|
|
294
|
+
icon: plus
|
|
295
|
+
label: "Log event"
|
|
296
|
+
type: button
|
|
297
|
+
variant: primary
|
|
298
|
+
}]
|
|
299
|
+
direction: horizontal
|
|
300
|
+
gap: sm
|
|
301
|
+
type: stack
|
|
302
|
+
}, (if @config.bodySearch {
|
|
303
|
+
children: [{
|
|
304
|
+
className: "w-full max-w-md"
|
|
305
|
+
clearable: true
|
|
306
|
+
event: REFETCH_QUERY
|
|
307
|
+
placeholder: @config.searchPlaceholder
|
|
308
|
+
type: search-input
|
|
309
|
+
}]
|
|
310
|
+
direction: horizontal
|
|
311
|
+
gap: sm
|
|
312
|
+
type: stack
|
|
313
|
+
} {
|
|
314
|
+
children: []
|
|
315
|
+
gap: none
|
|
316
|
+
type: stack
|
|
317
|
+
}), (if [">", (array/len @config.filters), 0] {
|
|
318
|
+
children: [{
|
|
319
|
+
entity: EventLogView
|
|
320
|
+
event: REFETCH_FILTER
|
|
321
|
+
filters: @config.filters
|
|
322
|
+
look: @config.filterBarLook
|
|
323
|
+
type: filter-group
|
|
324
|
+
}]
|
|
325
|
+
direction: horizontal
|
|
326
|
+
gap: sm
|
|
327
|
+
type: stack
|
|
328
|
+
} {
|
|
329
|
+
children: []
|
|
330
|
+
gap: none
|
|
331
|
+
type: stack
|
|
332
|
+
}), {
|
|
159
333
|
activeTab: @entity.filterKind
|
|
160
334
|
tabChangeEvent: APPLY_FILTER
|
|
161
335
|
tabs: @entity.filterChips
|
|
@@ -237,7 +411,37 @@ orbital EventLogOrbital {
|
|
|
237
411
|
direction: horizontal
|
|
238
412
|
gap: sm
|
|
239
413
|
type: stack
|
|
240
|
-
}, {
|
|
414
|
+
}, (if @config.bodySearch {
|
|
415
|
+
children: [{
|
|
416
|
+
className: "w-full max-w-md"
|
|
417
|
+
clearable: true
|
|
418
|
+
event: REFETCH_QUERY
|
|
419
|
+
placeholder: @config.searchPlaceholder
|
|
420
|
+
type: search-input
|
|
421
|
+
}]
|
|
422
|
+
direction: horizontal
|
|
423
|
+
gap: sm
|
|
424
|
+
type: stack
|
|
425
|
+
} {
|
|
426
|
+
children: []
|
|
427
|
+
gap: none
|
|
428
|
+
type: stack
|
|
429
|
+
}), (if [">", (array/len @config.filters), 0] {
|
|
430
|
+
children: [{
|
|
431
|
+
entity: EventLogView
|
|
432
|
+
event: REFETCH_FILTER
|
|
433
|
+
filters: @config.filters
|
|
434
|
+
look: @config.filterBarLook
|
|
435
|
+
type: filter-group
|
|
436
|
+
}]
|
|
437
|
+
direction: horizontal
|
|
438
|
+
gap: sm
|
|
439
|
+
type: stack
|
|
440
|
+
} {
|
|
441
|
+
children: []
|
|
442
|
+
gap: none
|
|
443
|
+
type: stack
|
|
444
|
+
}), {
|
|
241
445
|
activeTab: @entity.filterKind
|
|
242
446
|
tabChangeEvent: APPLY_FILTER
|
|
243
447
|
tabs: @entity.filterChips
|
|
@@ -354,6 +558,25 @@ orbital EventLogOrbital {
|
|
|
354
558
|
@description "Indicates an attempt to save an event failed."
|
|
355
559
|
@synonyms "error, failure, save failed"
|
|
356
560
|
@tier "internal"
|
|
561
|
+
REFETCH_QUERY {
|
|
562
|
+
searchTerm : string!
|
|
563
|
+
}
|
|
564
|
+
@description "Triggers an activity feed refresh based on the current search term."
|
|
565
|
+
@synonyms "refresh, reload, update, re-query, search"
|
|
566
|
+
@tier "domain"
|
|
567
|
+
REFETCH_FILTER {
|
|
568
|
+
field : string!
|
|
569
|
+
value : string!
|
|
570
|
+
}
|
|
571
|
+
@description "Triggers an activity feed refresh based on a field/value filter, in addition to the built-in kind tabs."
|
|
572
|
+
@synonyms "refresh, filter, update, reload"
|
|
573
|
+
@tier "domain"
|
|
574
|
+
REFETCH_PAGE {
|
|
575
|
+
page : number!
|
|
576
|
+
}
|
|
577
|
+
@description "Triggers an activity feed page refresh."
|
|
578
|
+
@synonyms "reload, refresh, update, paginate"
|
|
579
|
+
@tier "domain"
|
|
357
580
|
}
|
|
358
581
|
|
|
359
582
|
config {
|
|
@@ -397,6 +620,36 @@ orbital EventLogOrbital {
|
|
|
397
620
|
@label "Timeline look"
|
|
398
621
|
@description "Layer 2 visual treatment for the timeline."
|
|
399
622
|
@tier "presentation"
|
|
623
|
+
bodySearch : boolean = false
|
|
624
|
+
@label "Show the log's own search box?"
|
|
625
|
+
@description "Embeds a search box above the activity feed. Set true only when the page has no other search affordance (e.g. no page-level std-search), so the surface shows one search box instead of two. False is the default — no consumer of this atom has ever had a search box."
|
|
626
|
+
@synonyms "inline search, log search, built-in search, show search"
|
|
627
|
+
@tier "presentation"
|
|
628
|
+
searchPlaceholder : string = "Search activity…"
|
|
629
|
+
@label "Search box placeholder text"
|
|
630
|
+
@description "Hint text inside the log's search box."
|
|
631
|
+
@synonyms "search hint, placeholder, search box text"
|
|
632
|
+
@tier "presentation"
|
|
633
|
+
filters : [FilterSpec] = []
|
|
634
|
+
@label "Which filters should appear above the feed?"
|
|
635
|
+
@description "Dropdown filter facets by field, rendered as an embedded filter bar above the timeline; each selection fires REFETCH_FILTER on this trait, ANDed with the current kind tab. Empty (the default) = no filter bar — the right setting whenever the page already composes std-filter beside this atom and routes XFilter.FILTER -> REFETCH_FILTER, or relies solely on the built-in kind-filter chips (driven by kindOptions, which this knob does not duplicate or replace). Use this knob only for an extra facet beyond kind (e.g. actor, priority)."
|
|
636
|
+
@synonyms "filter bar, faceted filters, field filters, dropdowns"
|
|
637
|
+
@tier "presentation"
|
|
638
|
+
filterBarLook : "toolbar" | "chips" | "pills" | "popover-trigger" | "inline-column-header" = toolbar
|
|
639
|
+
@label "Filter bar look"
|
|
640
|
+
@description "Visual treatment for the embedded filter bar, mirroring std-filter's own enum. Only applies when `filters` is non-empty."
|
|
641
|
+
@synonyms "filter bar style, facet style, chips, pills"
|
|
642
|
+
@tier "presentation"
|
|
643
|
+
pageSize : number = 20
|
|
644
|
+
@label "How many entries per page when paging?"
|
|
645
|
+
@description "Records fetched from the server per REFETCH_PAGE request. The initial load and every search/kind/filter refetch stay unpaginated (load everything that matches) so the default unlimited activity feed is unchanged; only an explicit REFETCH_PAGE from a composed std-pagination control applies this limit."
|
|
646
|
+
@synonyms "fetch limit, records per page, page limit"
|
|
647
|
+
@tier "presentation"
|
|
648
|
+
displayPageSize : number = 20
|
|
649
|
+
@label "How many entries per page should a pager show?"
|
|
650
|
+
@description "Page size a consumer-composed std-pagination control should use to compute total pages (e.g. from totalCount). This atom's own timeline pattern has no built-in pager UI, so this knob is informational for the composed control, not consumed by the timeline itself."
|
|
651
|
+
@synonyms "visible rows, items per page, display limit"
|
|
652
|
+
@tier "presentation"
|
|
400
653
|
}
|
|
401
654
|
}
|
|
402
655
|
|