@object-ui/plugin-detail 17.5.0 → 17.7.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/CHANGELOG.md +7216 -0
- package/README.md +442 -74
- package/dist/ActivityTimeline.d.ts.map +1 -1
- package/dist/CommentAttachment.d.ts.map +1 -1
- package/dist/ConcurrentUpdateDialog.d.ts +17 -1
- package/dist/ConcurrentUpdateDialog.d.ts.map +1 -1
- package/dist/DetailSection.d.ts.map +1 -1
- package/dist/DetailSectionNode.d.ts +97 -0
- package/dist/DetailSectionNode.d.ts.map +1 -0
- package/dist/DetailView.d.ts.map +1 -1
- package/dist/HeaderHighlight.d.ts.map +1 -1
- package/dist/HistoryTimeline.d.ts +8 -1
- package/dist/HistoryTimeline.d.ts.map +1 -1
- package/dist/InlineEditSaveBar.d.ts +68 -0
- package/dist/InlineEditSaveBar.d.ts.map +1 -1
- package/dist/InlineFieldInput.d.ts +79 -6
- package/dist/InlineFieldInput.d.ts.map +1 -1
- package/dist/ReactionPicker.d.ts.map +1 -1
- package/dist/RecordActivityTimeline.d.ts +19 -4
- package/dist/RecordActivityTimeline.d.ts.map +1 -1
- package/dist/RecordChatterPanel.d.ts +6 -1
- package/dist/RecordChatterPanel.d.ts.map +1 -1
- package/dist/RecordComments.d.ts +1 -0
- package/dist/RecordComments.d.ts.map +1 -1
- package/dist/RecordDetailDrawer.d.ts +20 -6
- package/dist/RecordDetailDrawer.d.ts.map +1 -1
- package/dist/RecordDetailPanel.d.ts +101 -0
- package/dist/RecordDetailPanel.d.ts.map +1 -0
- package/dist/RecordMetaFooter.d.ts +1 -1
- package/dist/RecordMetaFooter.d.ts.map +1 -1
- package/dist/RelatedList.d.ts +94 -10
- package/dist/RelatedList.d.ts.map +1 -1
- package/dist/ThreadedReplies.d.ts +1 -1
- package/dist/ThreadedReplies.d.ts.map +1 -1
- package/dist/emptiness.d.ts +142 -0
- package/dist/emptiness.d.ts.map +1 -0
- package/dist/fieldEnrichment.d.ts +44 -4
- package/dist/fieldEnrichment.d.ts.map +1 -1
- package/dist/headerColor.d.ts +20 -0
- package/dist/headerColor.d.ts.map +1 -0
- package/dist/index.d.ts +181 -76
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5259 -5567
- package/dist/index.umd.cjs +2 -5
- package/dist/renderers/record-activity.d.ts.map +1 -1
- package/dist/renderers/record-alert.d.ts +83 -13
- package/dist/renderers/record-alert.d.ts.map +1 -1
- package/dist/renderers/record-alert.readProps.d.ts +40 -0
- package/dist/renderers/record-alert.readProps.d.ts.map +1 -0
- package/dist/renderers/record-chatter.d.ts.map +1 -1
- package/dist/renderers/record-details.d.ts +2 -0
- package/dist/renderers/record-details.d.ts.map +1 -1
- package/dist/renderers/record-highlights.d.ts.map +1 -1
- package/dist/renderers/record-history.d.ts +1 -1
- package/dist/renderers/record-history.d.ts.map +1 -1
- package/dist/renderers/record-path.d.ts.map +1 -1
- package/dist/renderers/record-quick-actions.d.ts +20 -3
- package/dist/renderers/record-quick-actions.d.ts.map +1 -1
- package/dist/renderers/record-reference-rail.d.ts +42 -17
- package/dist/renderers/record-reference-rail.d.ts.map +1 -1
- package/dist/renderers/record-related-list.d.ts +37 -3
- package/dist/renderers/record-related-list.d.ts.map +1 -1
- package/dist/renderers/recordActivityFeed.d.ts +352 -13
- package/dist/renderers/recordActivityFeed.d.ts.map +1 -1
- package/dist/renderers/recordComponentAria.d.ts +44 -0
- package/dist/renderers/recordComponentAria.d.ts.map +1 -0
- package/dist/renderers/relatedListActions.d.ts +102 -0
- package/dist/renderers/relatedListActions.d.ts.map +1 -0
- package/dist/summaryChipPercent.d.ts +83 -0
- package/dist/summaryChipPercent.d.ts.map +1 -0
- package/dist/summaryChipRenderers.d.ts +83 -0
- package/dist/summaryChipRenderers.d.ts.map +1 -0
- package/dist/synth/buildDefaultPageSchema.d.ts +98 -17
- package/dist/synth/buildDefaultPageSchema.d.ts.map +1 -1
- package/dist/useDetailTranslation.d.ts.map +1 -1
- package/dist/useRecordEditable.d.ts +1 -1
- package/dist/useRecordEditable.d.ts.map +1 -1
- package/package.json +20 -18
- package/dist/CommentInput.d.ts +0 -24
- package/dist/CommentInput.d.ts.map +0 -1
- package/dist/DiffView.d.ts +0 -24
- package/dist/DiffView.d.ts.map +0 -1
- package/dist/InlineCreateRelated.d.ts +0 -32
- package/dist/InlineCreateRelated.d.ts.map +0 -1
- package/dist/MentionAutocomplete.d.ts +0 -43
- package/dist/MentionAutocomplete.d.ts.map +0 -1
- package/dist/PointInTimeRestore.d.ts +0 -28
- package/dist/PointInTimeRestore.d.ts.map +0 -1
- package/dist/RecordNavigationEnhanced.d.ts +0 -18
- package/dist/RecordNavigationEnhanced.d.ts.map +0 -1
- package/dist/RelationshipGraph.d.ts +0 -23
- package/dist/RelationshipGraph.d.ts.map +0 -1
|
@@ -1,25 +1,189 @@
|
|
|
1
1
|
import { FeedItem, FeedItemType } from '@object-ui/types';
|
|
2
|
-
import { FeedFilterMode } from '../RecordActivityTimeline';
|
|
2
|
+
import { FeedFilterMode } from '../RecordActivityTimeline.js';
|
|
3
3
|
/** Spec default for `RecordActivityProps.limit`. */
|
|
4
4
|
export declare const DEFAULT_ACTIVITY_LIMIT = 20;
|
|
5
5
|
/**
|
|
6
6
|
* `sys_activity.type` → `FeedItem.type`.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* into the discussion feed
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
8
|
+
* Meant to be one reading with the map `RecordDetailView` uses when it merges
|
|
9
|
+
* `sys_activity` into the discussion feed. Two renderers that disagree about what a `created` row IS would put
|
|
10
|
+
* the same record's history under two different icons depending on which block
|
|
11
|
+
* an author reached for, so the richer `record_create` / `record_delete` /
|
|
12
|
+
* `sharing` feed types the spec offers are NOT used here — adopting them is a
|
|
13
|
+
* change to that shared map, not to this block.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ That copy is a hand-written literal in `app-shell`, not an import of this
|
|
16
|
+
* one, and nothing fails when the two disagree — so the `scheduled` entry below
|
|
17
|
+
* is currently present here and absent there. Tracked as objectui#5878; fixing
|
|
18
|
+
* it means the second copy reading this export, which is a different package's
|
|
19
|
+
* surface than this card's.
|
|
15
20
|
*
|
|
16
21
|
* `commented` / `mentioned` map to nothing because their content lives in
|
|
17
22
|
* `sys_comment` (with reactions and threading attached) — a host that has both
|
|
18
23
|
* merges the comment rows, and the block on its own has no comment write path
|
|
19
24
|
* to pair them with. `login` / `logout` are account events, not record
|
|
20
25
|
* activity.
|
|
26
|
+
*
|
|
27
|
+
* ## Two vocabularies, not one (objectui#5840)
|
|
28
|
+
*
|
|
29
|
+
* The keys were originally set-equal to plugin-audit's declared
|
|
30
|
+
* `sys_activity.type` select options, and the test pinned exactly that. They no
|
|
31
|
+
* longer are, because those options are **not** what the column stores:
|
|
32
|
+
*
|
|
33
|
+
* - Every field on `sys_activity` is `readonly: true`, and objectql's
|
|
34
|
+
* `validateRecord` skips readonly fields on both the insert and the update
|
|
35
|
+
* branch. The eleven-value enum is therefore documentation, not a contract —
|
|
36
|
+
* an undeclared value is written silently (measured upstream by
|
|
37
|
+
* plugin-audit's own `sys-activity-type-vocabulary.test.ts`).
|
|
38
|
+
* - The platform itself forwards author-declared values into the column:
|
|
39
|
+
* ADR-0052 §5b.2 `activityMilestones[].type` is applied verbatim by
|
|
40
|
+
* plugin-audit's `audit-writers.ts` (`if (milestone.type) activityType =
|
|
41
|
+
* milestone.type`). That is how `completed` is produced, and it is a general
|
|
42
|
+
* door, not a special case.
|
|
43
|
+
*
|
|
44
|
+
* So `scheduled` is a value that is written, stored and queryable while being
|
|
45
|
+
* undeclared upstream. Dropping it was not a decision this map made; it was the
|
|
46
|
+
* absence of one. Its producer is HotCRM's `schedule_meeting` action
|
|
47
|
+
* (`src/actions/global.actions.ts` — `type: EVENT_STATUS === 'held' ?
|
|
48
|
+
* 'completed' : 'scheduled'`), registered for `crm_lead`, `crm_contact`,
|
|
49
|
+
* `crm_account`, `crm_opportunity` and `crm_case`: the held branch reached the
|
|
50
|
+
* timeline, the scheduled branch never did.
|
|
51
|
+
*
|
|
52
|
+
* `scheduled` → `event` is the semantic pairing and it is what makes the
|
|
53
|
+
* declared `event` feed type reachable at all. Note the two branches of that
|
|
54
|
+
* one producer now land at different DEFAULT visibility, which is the intended
|
|
55
|
+
* reading: a held meeting is `completed` → `task`, hidden unless
|
|
56
|
+
* `showCompleted`; a not-yet-held meeting is `scheduled` → `event`, shown,
|
|
57
|
+
* because an upcoming meeting is the part of a timeline you still act on.
|
|
58
|
+
*
|
|
59
|
+
* ## The vocabulary is OPEN — ruled. Do NOT restore set-equality.
|
|
60
|
+
*
|
|
61
|
+
* Maintainer ruling of 2026-08-24 (objectstack `88b9d749a`), **direction 4**:
|
|
62
|
+
* `sys_activity.type` is AUTHOR-EXTENSIBLE. The declared select options are the
|
|
63
|
+
* platform's BUILT-IN set, not the column's domain, and the two facts above are
|
|
64
|
+
* why — readonly fields are never validated on write, and ADR-0052 §5b.2
|
|
65
|
+
* forwards an author's `activityMilestones[].type` into the column verbatim.
|
|
66
|
+
*
|
|
67
|
+
* So the relation this table stands in is a SUPERSET, in one direction only:
|
|
68
|
+
*
|
|
69
|
+
* - **map ⊇ built-ins** — every value the platform declares has an entry here,
|
|
70
|
+
* either a feed type or a deliberate `undefined` exclusion. A new built-in
|
|
71
|
+
* with no entry is a gap, and objectui#5969's pin turns red for it.
|
|
72
|
+
* - **NOT built-ins ⊇ map**, and NOT set-equality in either spelling. An
|
|
73
|
+
* author-extended value legitimately exists outside the declaration, so a
|
|
74
|
+
* pin that required the two sets to match would be false by construction.
|
|
75
|
+
*
|
|
76
|
+
* ⛔ A reader who finds no equality check here is looking at a DECISION, not an
|
|
77
|
+
* omission: objectui#5840 removed the old set-equality pin on purpose, because
|
|
78
|
+
* pinning to the closed declaration meant dropping stored rows, and
|
|
79
|
+
* objectui#5969 replaced it with the two-directional pin under this ruling.
|
|
80
|
+
*
|
|
81
|
+
* (`scheduled` — the value #5840 was about — has since been declared upstream
|
|
82
|
+
* by objectstack#11522, superseding objectstack#11424. That is precisely the
|
|
83
|
+
* drift a hand-maintained equality pin cannot survive, and the reason the pin
|
|
84
|
+
* is a superset assertion plus a fallback rather than a census of two groups.)
|
|
85
|
+
*
|
|
86
|
+
* A value outside this table is NO LONGER DROPPED: it renders through
|
|
87
|
+
* {@link UNMAPPED_ACTIVITY_FEED_TYPE}. See {@link activityRowToFeedItem}.
|
|
21
88
|
*/
|
|
22
89
|
export declare const ACTIVITY_TYPE_TO_FEED_TYPE: Readonly<Record<string, FeedItemType | undefined>>;
|
|
90
|
+
/**
|
|
91
|
+
* The presentation an `sys_activity.type` value outside
|
|
92
|
+
* {@link ACTIVITY_TYPE_TO_FEED_TYPE} renders through.
|
|
93
|
+
*
|
|
94
|
+
* The second half of the direction-4 ruling (2026-08-24, objectstack `88b9d749a`): if
|
|
95
|
+
* the column is author-extensible, then a value this map has never heard of is
|
|
96
|
+
* REAL RECORD ACTIVITY that an author extended the platform with — not a
|
|
97
|
+
* mistake — and dropping it is the objectui#5840 failure mode reappearing for
|
|
98
|
+
* every author who ever writes one. Stored, queryable, invisible.
|
|
99
|
+
*
|
|
100
|
+
* `system` is the generic bucket rather than a new feed type because
|
|
101
|
+
* `FeedItemType` is a CLOSED spec enum owned by `@objectstack/spec` — minting a
|
|
102
|
+
* kind for "we don't know" is a platform change, not this block's.
|
|
103
|
+
*
|
|
104
|
+
* ⚠️ This is a FLOOR under the map, never a substitute for it. objectui#5840
|
|
105
|
+
* rejected a catch-all *offered as the fix* — an unmeasured type rendering as
|
|
106
|
+
* `system` is not the same data as a type someone read and mapped. What makes
|
|
107
|
+
* the catch-all safe here is that it does not stand alone: the superset pin
|
|
108
|
+
* above forces every built-in to keep its OWN presentation, so the fallback can
|
|
109
|
+
* only ever receive values nobody has ruled on yet, and the diagnostic below
|
|
110
|
+
* names each one so somebody can.
|
|
111
|
+
*/
|
|
112
|
+
export declare const UNMAPPED_ACTIVITY_FEED_TYPE: FeedItemType;
|
|
113
|
+
/**
|
|
114
|
+
* Feed kinds an ObjectUI surface produces WITHOUT going through
|
|
115
|
+
* {@link ACTIVITY_TYPE_TO_FEED_TYPE}.
|
|
116
|
+
*
|
|
117
|
+
* Exactly one today: `comment`, built from `sys_comment` rows by app-shell's
|
|
118
|
+
* `RecordDetailView` (the `sys_comment` read, and the two optimistic rows the
|
|
119
|
+
* composer writes) and handed to this block through `DiscussionContext`. It
|
|
120
|
+
* cannot be derived here — app-shell depends on this package, not the other way
|
|
121
|
+
* round — so it is DECLARED, and `feedTypeProducerCensus-5877.test.ts` re-runs
|
|
122
|
+
* the census over the repository so the declaration cannot go stale silently.
|
|
123
|
+
*
|
|
124
|
+
* ## Census, and the pathspec it was taken over (objectui#5877)
|
|
125
|
+
*
|
|
126
|
+
* Every `.ts` / `.tsx` file in the repository that is not a test, at every top
|
|
127
|
+
* level (`packages/`, `apps/`, `examples/`, `scripts/`, `e2e/`), narrowed to the
|
|
128
|
+
* files that mention `FeedItem` at all — you cannot construct one without
|
|
129
|
+
* naming the type — then read for `FeedItemType` literals. 1622 files scanned,
|
|
130
|
+
* 13 mention `FeedItem`, one produces a kind off this map. A census is only as
|
|
131
|
+
* wide as its pathspec, so the pathspec is stated rather than implied, and the
|
|
132
|
+
* test above holds it.
|
|
133
|
+
*
|
|
134
|
+
* ⛔ NOT counted, deliberately: app-shell's `sharedUserFeeds.ts` /
|
|
135
|
+
* `activityItemType.ts` read the same `sys_activity` rows but produce
|
|
136
|
+
* `ActivityItemType` (`create` / `update` / `delete` / `comment` / `system`), a
|
|
137
|
+
* DIFFERENT five-value vocabulary that is not a projection of this one in either
|
|
138
|
+
* direction (objectui#6730 records why converging them costs rows). A row it
|
|
139
|
+
* turns into an `ActivityItem` never becomes a `FeedItem`, so it produces
|
|
140
|
+
* nothing for this feed. `ActivityEntry` in `@object-ui/types` is a third
|
|
141
|
+
* vocabulary again, and has no producer at all.
|
|
142
|
+
*
|
|
143
|
+
* ⚠️ Also NOT counted, and the reason the diagnostic below names it: a HOST can
|
|
144
|
+
* hand this block a feed of its own (`items` on the node, or a
|
|
145
|
+
* `DiscussionContext` it mounts itself). Those items are produced outside this
|
|
146
|
+
* repository, so no census taken here can bound their kinds.
|
|
147
|
+
*/
|
|
148
|
+
export declare const FEED_TYPES_PRODUCED_OFF_MAP: readonly FeedItemType[];
|
|
149
|
+
/**
|
|
150
|
+
* Feed kinds this repository has decided NOT to adopt — as opposed to kinds
|
|
151
|
+
* nothing happens to produce.
|
|
152
|
+
*
|
|
153
|
+
* The distinction matters more than the diagnostic that uses it. Reporting a
|
|
154
|
+
* decision as a defect is how a warning channel gets trained out of an author's
|
|
155
|
+
* attention, and these three are decisions: `created` / `deleted` / `shared`
|
|
156
|
+
* rows are mapped to `field_change` ON PURPOSE, because `RecordDetailView` and
|
|
157
|
+
* this block must agree about what a `created` row IS before either can move to
|
|
158
|
+
* the richer kind. Adopting them is a change to that shared map, not to this
|
|
159
|
+
* block. The reasoning is written out at {@link ACTIVITY_TYPE_TO_FEED_TYPE}.
|
|
160
|
+
*
|
|
161
|
+
* ⚠️ This list is a TRANSCRIPTION of that prose, not a derivation, and there is
|
|
162
|
+
* no way to make it one: the decision exists as a comment, and a comment is not
|
|
163
|
+
* machine-readable. Two consequences, both load-bearing:
|
|
164
|
+
*
|
|
165
|
+
* 1. it is only as true as the prose it was copied from, so it is edited
|
|
166
|
+
* together with that prose and never on its own;
|
|
167
|
+
* 2. a kind that is NOT on this list is not thereby known to be an oversight.
|
|
168
|
+
* It is only known to have no producer. Whether somebody decided against it
|
|
169
|
+
* and did not write it down is not recorded anywhere this code can read, and
|
|
170
|
+
* the message below says so rather than guessing.
|
|
171
|
+
*
|
|
172
|
+
* ⛔ Do not extend it by inference. A kind belongs here when a decision about it
|
|
173
|
+
* is written down, not when its absence looks deliberate.
|
|
174
|
+
*/
|
|
175
|
+
export declare const DELIBERATELY_UNADOPTED_FEED_TYPES: readonly FeedItemType[];
|
|
176
|
+
/**
|
|
177
|
+
* Every feed kind some ObjectUI surface can put on a record feed.
|
|
178
|
+
*
|
|
179
|
+
* DERIVED from the producers themselves — the map's range, its fallback, and
|
|
180
|
+
* the declared off-map producer above — never a second hand-written list of
|
|
181
|
+
* kinds. Giving an unproduced kind a producer (one new entry in
|
|
182
|
+
* {@link ACTIVITY_TYPE_TO_FEED_TYPE}) therefore retires its diagnostic in the
|
|
183
|
+
* same edit, with nothing else to remember. A hand-kept copy would not, and
|
|
184
|
+
* that copy is exactly what this file's header records the cost of.
|
|
185
|
+
*/
|
|
186
|
+
export declare const PRODUCED_FEED_TYPES: ReadonlySet<FeedItemType>;
|
|
23
187
|
/** A row as `sys_activity` returns it. Loose on purpose: the block reads a
|
|
24
188
|
* system table it does not own, and an unknown column is not an error. */
|
|
25
189
|
export interface SysActivityRow {
|
|
@@ -34,6 +198,12 @@ export interface SysActivityRow {
|
|
|
34
198
|
source_id?: string | number | null;
|
|
35
199
|
[k: string]: unknown;
|
|
36
200
|
}
|
|
201
|
+
/** Test seam: forget which `types` entries have already been named. */
|
|
202
|
+
export declare function resetUnrecognisedFeedTypeWarnings(): void;
|
|
203
|
+
/** Test seam: forget which unproduced `types` entries have already been named. */
|
|
204
|
+
export declare function resetUnproducedFeedTypeWarnings(): void;
|
|
205
|
+
/** Test seam: forget which `filterMode` values have already been named. */
|
|
206
|
+
export declare function resetUnrecognisedFilterModeWarnings(): void;
|
|
37
207
|
/**
|
|
38
208
|
* Coerce an authored `filterMode` to a value the timeline understands.
|
|
39
209
|
*
|
|
@@ -41,12 +211,122 @@ export interface SysActivityRow {
|
|
|
41
211
|
* `<Select>` handed a value with no matching item renders blank and the
|
|
42
212
|
* dropdown reads as broken. Same posture as objectui#3151 — an unrecognised
|
|
43
213
|
* filter token is skipped, never turned into a filter that can't match.
|
|
214
|
+
*
|
|
215
|
+
* ## Why that fallback needs a diagnostic (objectui#5891)
|
|
216
|
+
*
|
|
217
|
+
* `'all'` is the WIDEST of the four declared modes — `filterItems` in
|
|
218
|
+
* `RecordActivityTimeline` narrows to ONE feed type for each of the other three
|
|
219
|
+
* and returns the feed untouched for `'all'` — so every unrecognised value
|
|
220
|
+
* lands on the one option that shows the author MORE than they asked for. A
|
|
221
|
+
* near-miss like `comments-only` or `commentsOnly` therefore opens the panel on
|
|
222
|
+
* the unfiltered stream, and the tell is a PLAUSIBLE result (a populated
|
|
223
|
+
* timeline) rather than an empty one that gets investigated. That is the same
|
|
224
|
+
* shape objectui#5841 removed from the sibling `types` sanitiser.
|
|
225
|
+
*
|
|
226
|
+
* The ruling on this card (triage, 2026-08-25) is that the defect is the
|
|
227
|
+
* INVISIBILITY, not the fallback: `filterMode` seeds a control the user can
|
|
228
|
+
* change, and there is no defensible narrower default to fall back to instead.
|
|
229
|
+
* So nothing that renders changes here — what changes is that the fold is now
|
|
230
|
+
* SAID OUT LOUD, once per distinct offending value on each block (see
|
|
231
|
+
* {@link warnOnce}).
|
|
232
|
+
*
|
|
233
|
+
* `block` is the registered name of the block the value was authored on
|
|
234
|
+
* (`record:activity`, `record:chatter`, `record:discussion`). It is REQUIRED,
|
|
235
|
+
* not defaulted: the message is addressed to that block's author, and a default
|
|
236
|
+
* would hand every caller that forgot it some other block's name — the defect
|
|
237
|
+
* objectui#9557 removed.
|
|
238
|
+
*
|
|
239
|
+
* Absent (`undefined` / `null`) is silent: no `filterMode` was authored, which
|
|
240
|
+
* is not a mistake, and a warning about a decision teaches authors to ignore
|
|
241
|
+
* the channel. Only a value the author actually wrote is reported.
|
|
242
|
+
*
|
|
243
|
+
* The declared modes named in the message are read from `@objectstack/spec`'s
|
|
244
|
+
* `FeedFilterMode` at runtime, never re-typed here — see the file header for
|
|
245
|
+
* what a hand copy of a spec enum cost.
|
|
246
|
+
*/
|
|
247
|
+
export declare function normalizeFilterMode(value: unknown, block: string): FeedFilterMode;
|
|
248
|
+
/**
|
|
249
|
+
* Sanitise an authored `types` allow-list. Narrowing or refusal, never widening.
|
|
250
|
+
*
|
|
251
|
+
* Three distinct authored intents used to collapse into one rendering
|
|
252
|
+
* (objectui#5841). They are three again:
|
|
253
|
+
*
|
|
254
|
+
* | authored | returns | rendered |
|
|
255
|
+
* | ----------------------------- | ----------- | ------------------------------ |
|
|
256
|
+
* | absent (`undefined`/`null`) | `undefined` | every kind — no filter authored |
|
|
257
|
+
* | `[]` | `[]` | nothing — the author said "no kinds" |
|
|
258
|
+
* | `['crm_task']` (none known) | `[]` | nothing, plus one diagnostic |
|
|
259
|
+
* | `['task', 'crm_task']` | `['task']` | the recognised members, plus one diagnostic |
|
|
260
|
+
* | `['approval']` (no producer) | `['approval']` | nothing, plus one diagnostic — the kind is declared and honoured, but nothing emits it (objectui#5877) |
|
|
261
|
+
*
|
|
262
|
+
* `undefined` now means "no `types` key was authored" and ONLY that. It used to
|
|
263
|
+
* mean that OR "everything you authored was dropped", and {@link applyFeedConfig}
|
|
264
|
+
* reads it as "apply no filter" — so a single typo served the author every
|
|
265
|
+
* activity on the record with nothing said anywhere, and the tell was a
|
|
266
|
+
* PLAUSIBLE result (a populated timeline) rather than an empty one that gets
|
|
267
|
+
* investigated. That is the principle this function now holds: a sanitiser may
|
|
268
|
+
* narrow an author's request or refuse it, but it must never silently widen it,
|
|
269
|
+
* because widening turns a typo into "show the user everything" — the one
|
|
270
|
+
* outcome no author asked for.
|
|
271
|
+
*
|
|
272
|
+
* `[]` is honoured rather than reinterpreted, and silently: rendering every kind
|
|
273
|
+
* is the maximally wrong answer to "no kinds", and there is nothing to report
|
|
274
|
+
* about a request that was carried out exactly.
|
|
275
|
+
*
|
|
276
|
+
* Membership is read from `@objectstack/spec`'s `FeedItemType` at runtime, never
|
|
277
|
+
* re-typed here — see the file header for what a hand copy of a spec enum cost.
|
|
278
|
+
*
|
|
279
|
+
* NOT pure, on TWO independent channels (see {@link warnOnce}) — the failure
|
|
280
|
+
* being repaired is invisibility in both cases, so the diagnostics are the other
|
|
281
|
+
* half of the fix rather than a nicety:
|
|
282
|
+
*
|
|
283
|
+
* - an entry it cannot recognise logs once (no declared kind matches it);
|
|
284
|
+
* - a RECOGNISED entry that no producer emits logs once as well, on its own
|
|
285
|
+
* channel — see {@link warnUnproducedFeedTypes}. That one changes nothing
|
|
286
|
+
* about the return value: the kind is declared, so it is kept and honoured.
|
|
287
|
+
*
|
|
288
|
+
* Both channels name, and dedupe per, the REQUIRED `block` the list was
|
|
289
|
+
* authored on — see {@link normalizeFilterMode} for why it has no default.
|
|
290
|
+
*/
|
|
291
|
+
export declare function normalizeFeedTypes(value: unknown, block: string): FeedItemType[] | undefined;
|
|
292
|
+
/**
|
|
293
|
+
* The ONE resolver for this block's row cap (objectui#10096, objectui#10145).
|
|
294
|
+
*
|
|
295
|
+
* A refused value is dropped for this block's own default.
|
|
296
|
+
*
|
|
297
|
+
* ⛔ Not `Math.floor`, which objectui#10096 replaced: flooring REPAIRED an
|
|
298
|
+
* authored `2.5` into a two-row window and handed it back as a result, so the
|
|
299
|
+
* author got a silently different number than the one they wrote. Refusing and
|
|
300
|
+
* defaulting is the answer the sibling `record:history` gives through
|
|
301
|
+
* `normalizeHistoryLimit`, and the answer objectui#9925 landed at three further
|
|
302
|
+
* read points (all three test `typeof value === 'number'` first, as this does).
|
|
303
|
+
*
|
|
304
|
+
* `NaN` and both infinities are refused (not integers); `0` and negatives are
|
|
305
|
+
* refused (not positive); `undefined` is the unauthored case and resolves to
|
|
306
|
+
* the default without being a refusal.
|
|
307
|
+
*
|
|
308
|
+
* ⚠️ FAIL-SOFT on purpose: throwing would take out a record page over one
|
|
309
|
+
* declaration. It is NOT silent — the renderers that call this state every
|
|
310
|
+
* refusal through `describeRefusedFeedLimit` (objectui#10097 ruled "always
|
|
311
|
+
* warn" for the family; objectui#10145 extends the refused set to non-numbers).
|
|
312
|
+
* This function stays pure so it can run on every render.
|
|
313
|
+
*
|
|
314
|
+
* ⭐ Shared with `record:chatter` / `record:discussion`, which resolve
|
|
315
|
+
* `feed.limit` through this same function — `RecordChatterProps.feed` is
|
|
316
|
+
* `RecordActivityProps`, so it is the same declared member and the same
|
|
317
|
+
* refusal.
|
|
44
318
|
*/
|
|
45
|
-
export declare function normalizeFilterMode(value: unknown): FeedFilterMode;
|
|
46
|
-
/** Keep only the `types` entries the spec actually defines. */
|
|
47
|
-
export declare function normalizeFeedTypes(value: unknown): FeedItemType[] | undefined;
|
|
48
|
-
/** Coerce `limit` to a positive integer, falling back to the spec default. */
|
|
49
319
|
export declare function normalizeLimit(value: unknown): number;
|
|
320
|
+
/**
|
|
321
|
+
* The diagnostic half of the row-cap refusal for the blocks that resolve
|
|
322
|
+
* through `normalizeLimit` (`record:activity`, `record:chatter`,
|
|
323
|
+
* `record:discussion`). `null` means "nothing to say": an absent `limit`
|
|
324
|
+
* (`undefined` / `null`) is not a mistake, and a usable one is not either.
|
|
325
|
+
*
|
|
326
|
+
* Callers fire it from an effect keyed on the declaration — the channel
|
|
327
|
+
* objectui#9925 uses at its three read points — never from render.
|
|
328
|
+
*/
|
|
329
|
+
export declare function describeRefusedFeedLimit(block: string, authored: unknown): string | null;
|
|
50
330
|
/**
|
|
51
331
|
* Timestamp of a `sys_activity` row.
|
|
52
332
|
*
|
|
@@ -56,9 +336,24 @@ export declare function normalizeLimit(value: unknown): number;
|
|
|
56
336
|
* type map is: same rows, same quirk.
|
|
57
337
|
*/
|
|
58
338
|
export declare function activityTimestamp(row: SysActivityRow): string;
|
|
339
|
+
/** Test seam: forget which unknown types have already been warned about. */
|
|
340
|
+
export declare function resetUnknownActivityTypeWarnings(): void;
|
|
59
341
|
/**
|
|
60
342
|
* One `sys_activity` row → one {@link FeedItem}, or `null` when the row is not
|
|
61
343
|
* record activity (see {@link ACTIVITY_TYPE_TO_FEED_TYPE}).
|
|
344
|
+
*
|
|
345
|
+
* Three outcomes, and the difference between the last two is the whole of the
|
|
346
|
+
* direction-4 ruling (2026-08-24, objectstack `88b9d749a`):
|
|
347
|
+
*
|
|
348
|
+
* - a type mapped to a feed type renders with THAT presentation;
|
|
349
|
+
* - a type the table maps to `undefined` is a DELIBERATE exclusion — `null`,
|
|
350
|
+
* quietly, because a warning about a decision teaches authors to ignore the
|
|
351
|
+
* channel;
|
|
352
|
+
* - a type the table does not contain at all is an AUTHOR-EXTENDED value under
|
|
353
|
+
* the ruled open vocabulary. It renders through
|
|
354
|
+
* {@link UNMAPPED_ACTIVITY_FEED_TYPE} and says so once. It used to return
|
|
355
|
+
* `null` here, which made every extended value invisible — the same outcome
|
|
356
|
+
* objectui#5840 was filed for, reached by a different route.
|
|
62
357
|
*/
|
|
63
358
|
export declare function activityRowToFeedItem(row: SysActivityRow, systemActorLabel: string): FeedItem | null;
|
|
64
359
|
/** The subset of `RecordActivityProps` that decides which items survive. */
|
|
@@ -86,8 +381,52 @@ export interface AppliedFeed {
|
|
|
86
381
|
* `pageSize` is the effective window (`limit` on first render, grown by
|
|
87
382
|
* "Load more"); it is separate from `config.limit` so paging does not have to
|
|
88
383
|
* rewrite the authored config.
|
|
384
|
+
*
|
|
385
|
+
* `block` is the registered name of the block whose config this is; the
|
|
386
|
+
* `types` diagnostics are addressed to it (objectui#9557, see
|
|
387
|
+
* {@link normalizeFilterMode}).
|
|
89
388
|
*/
|
|
90
|
-
export declare function applyFeedConfig(items: readonly FeedItem[], config: FeedConfigFilters, pageSize: number): AppliedFeed;
|
|
389
|
+
export declare function applyFeedConfig(items: readonly FeedItem[], config: FeedConfigFilters, pageSize: number, block: string): AppliedFeed;
|
|
91
390
|
/** Sort a feed chronologically and de-duplicate by id (feeds are append-only). */
|
|
92
391
|
export declare function mergeFeedItems(...groups: readonly FeedItem[][]): FeedItem[];
|
|
392
|
+
/**
|
|
393
|
+
* Whether a rejected feed read — `sys_activity` or `sys_comment` — was REFUSED
|
|
394
|
+
* (objectui#11195): the server answered, and the answer was "not for you".
|
|
395
|
+
*
|
|
396
|
+
* A refused read and an empty read are different answers about the record, and
|
|
397
|
+
* the panel used to give both the same one. Every failure on the feed landed on
|
|
398
|
+
* `No activity recorded` / `No comments yet`, so a member the server refused
|
|
399
|
+
* read a permission wall as a record where nothing had happened. The panel now
|
|
400
|
+
* shows a no-permission state for a refused read instead, and keeps the empty
|
|
401
|
+
* state for a read that answered with zero rows.
|
|
402
|
+
*
|
|
403
|
+
* The verdict is `classifyLoadError`'s (`@object-ui/react`), the read
|
|
404
|
+
* classifier `ListView`'s error panel and `RecordAttachmentsPanel` already
|
|
405
|
+
* share. Nothing here reads a status or a code of its own. Refused means the
|
|
406
|
+
* two kinds that are about the caller:
|
|
407
|
+
*
|
|
408
|
+
* - `forbidden`: 403, or a `PERMISSION_DENIED` / `FORBIDDEN` envelope;
|
|
409
|
+
* - `unauthorized`: 401, or `UNAUTHORIZED` / `UNAUTHENTICATED`.
|
|
410
|
+
*
|
|
411
|
+
* ⚠️ The 401 half is a deliberate difference from `RecordAttachmentsPanel`,
|
|
412
|
+
* whose `denied` state does not claim a 401. The triage on objectui#11195 ruled
|
|
413
|
+
* it for this panel: any refused read (401 / 403, or a permission envelope)
|
|
414
|
+
* shows the no-permission state.
|
|
415
|
+
*
|
|
416
|
+
* NOT refused, so these keep today's empty state:
|
|
417
|
+
*
|
|
418
|
+
* - `api-disabled` (`OBJECT_API_DISABLED` 404 / `OBJECT_API_METHOD_NOT_ALLOWED`
|
|
419
|
+
* 405): a property of the object's metadata, not of the caller, and no
|
|
420
|
+
* permission grant changes it;
|
|
421
|
+
* - a bare 404 (`sys_activity` on a deployment without the audit plugin).
|
|
422
|
+
* The ObjectStack adapter already answers that as zero rows; another
|
|
423
|
+
* adapter's rejection classifies as `network` and lands here;
|
|
424
|
+
* - `rejected` (400) and `network` (a 5xx, an unreachable server). Those are
|
|
425
|
+
* failures, not refusals. The panel has no error state of its own, so they
|
|
426
|
+
* still render the empty state.
|
|
427
|
+
*
|
|
428
|
+
* ⛔ A refusal is not retried. A refused read is the same answer on every
|
|
429
|
+
* retry, so the callers write it into state and do not re-issue the read.
|
|
430
|
+
*/
|
|
431
|
+
export declare function isRefusedFeedRead(err: unknown): boolean;
|
|
93
432
|
//# sourceMappingURL=recordActivityFeed.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recordActivityFeed.d.ts","sourceRoot":"","sources":["../../src/renderers/recordActivityFeed.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"recordActivityFeed.d.ts","sourceRoot":"","sources":["../../src/renderers/recordActivityFeed.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RecordComponentAriaProps } from '@object-ui/types';
|
|
2
|
+
/**
|
|
3
|
+
* The authored `aria` bag as a renderer actually receives it: the declared
|
|
4
|
+
* face, plus the undeclared `label` spelling a stored document may still carry.
|
|
5
|
+
*/
|
|
6
|
+
export type AuthoredRecordAria = RecordComponentAriaProps & {
|
|
7
|
+
/**
|
|
8
|
+
* ⛔ Not a member of the contract. It is the shared ARIA shape's alias entry
|
|
9
|
+
* and is refused on parse. Declared on this type ONLY so the diagnostic can
|
|
10
|
+
* see it without an `as any` cast (a cast is how `record:path` once came to
|
|
11
|
+
* read this spelling and no other).
|
|
12
|
+
*
|
|
13
|
+
* ⚠️ It is never read as a name. objectui#9945 retired the fold that did;
|
|
14
|
+
* a served value is reported, and only for a caller that names its `block`.
|
|
15
|
+
* See this module's header.
|
|
16
|
+
*/
|
|
17
|
+
label?: string;
|
|
18
|
+
};
|
|
19
|
+
/** What {@link useRecordAriaProps} spreads onto a block's container element. */
|
|
20
|
+
export interface RecordAriaDomProps {
|
|
21
|
+
'aria-label'?: string;
|
|
22
|
+
'aria-describedby'?: string;
|
|
23
|
+
role?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The ARIA DOM props for a `record:*` block's own container.
|
|
27
|
+
*
|
|
28
|
+
* @param aria - the authored bag, straight off the node's `aria` key.
|
|
29
|
+
* @param defaultRole - the role this block renders when the author declares
|
|
30
|
+
* none. Omit it and the container stays role-less until an author declares a
|
|
31
|
+
* name, a description or a role — at which point `'region'` carries the name,
|
|
32
|
+
* because an attribute on a `generic` element carries nothing.
|
|
33
|
+
* @param defaultLabel - the block's built-in accessible name, used when the
|
|
34
|
+
* author declared none (or declared an empty one).
|
|
35
|
+
* @param block - the block's registered type (`record:path`), named in the
|
|
36
|
+
* report of a served `aria.label`. Omit it and that spelling is still not
|
|
37
|
+
* read, just not reported. See this module's header for which blocks pass it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function useRecordAriaProps(aria: AuthoredRecordAria | undefined, { defaultRole, defaultLabel, block, }?: {
|
|
40
|
+
defaultRole?: string;
|
|
41
|
+
defaultLabel?: string;
|
|
42
|
+
block?: string;
|
|
43
|
+
}): RecordAriaDomProps;
|
|
44
|
+
//# sourceMappingURL=recordComponentAria.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordComponentAria.d.ts","sourceRoot":"","sources":["../../src/renderers/recordComponentAria.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGG;AAKH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,GAAG;IAC1D;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAwCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,kBAAkB,GAAG,SAAS,EACpC,EACE,WAAW,EACX,YAAY,EACZ,KAAK,GACN,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACtE,kBAAkB,CAapB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* `record:related_list.actions` — where an authored action id lands on the list,
|
|
9
|
+
* or why it is refused (objectui#11163; the maintainer's ENFORCE ruling on
|
|
10
|
+
* objectstack-ai/objectstack#20665).
|
|
11
|
+
*
|
|
12
|
+
* The contract declares the key as `z.array(z.string())`, "Action IDs available
|
|
13
|
+
* for related records". This module is the whole of its meaning, kept apart
|
|
14
|
+
* from the renderer so the file that draws the block keeps exporting
|
|
15
|
+
* components only:
|
|
16
|
+
*
|
|
17
|
+
* - RESOLUTION is `resolveDeclaredActionIds` — the one function
|
|
18
|
+
* `page:header`, `record:quick_actions` and `record:alert` resolve an
|
|
19
|
+
* authored action id through (objectui#7182, objectui#7382) — against the
|
|
20
|
+
* RELATED object's registered `actions`. ⛔ No second lookup: the caller
|
|
21
|
+
* reads that registry through `useMetadataItem('object', …)`, the same
|
|
22
|
+
* entry `record:quick_actions.actionNames` uses.
|
|
23
|
+
* - Only the IDS arm is this key's. The inline-object arm of the shared
|
|
24
|
+
* rule is `page:header`'s transition tolerance (objectstack#11592) and is
|
|
25
|
+
* not inherited here, the choice `record:alert` made for its CTA: an
|
|
26
|
+
* object in this array would widen what a related list can run past what
|
|
27
|
+
* the object declares.
|
|
28
|
+
* - PLACEMENT is each action's own `locations`, read by `actionRendersAt`
|
|
29
|
+
* — the platform's one placement rule, and the rule the host bridge
|
|
30
|
+
* (`RelatedRecordActionsBridge.deriveActions`) already applies to this
|
|
31
|
+
* list: `list_toolbar` draws a header button; `list_item` and
|
|
32
|
+
* `record_related` draw a row-menu item (objectui#11270). This block only
|
|
33
|
+
* ever renders inside a parent record, which is the scope `record_related`
|
|
34
|
+
* names (objectstack-ai/objectstack#20937, triage `5919625056`: row
|
|
35
|
+
* placement, inside a record only). Naming an action here does not bypass
|
|
36
|
+
* location filtering (only a list view's selection bar is placed by
|
|
37
|
+
* naming), so an id whose action declares none of the three is REFUSED
|
|
38
|
+
* rather than drawn somewhere or dropped.
|
|
39
|
+
* - ORDER is the author's, within each surface.
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* An action definition as the registry holds it — the two members read here,
|
|
43
|
+
* typed `unknown` because the definitions arrive straight off the metadata
|
|
44
|
+
* wire (the reason `actionRendersAt` gives for its own parameter).
|
|
45
|
+
*/
|
|
46
|
+
export interface RegisteredRelatedAction {
|
|
47
|
+
readonly name?: unknown;
|
|
48
|
+
readonly locations?: unknown;
|
|
49
|
+
}
|
|
50
|
+
/** One reason an authored entry does not render, stated for the author. */
|
|
51
|
+
export type RelatedListActionRefusal =
|
|
52
|
+
/** The array itself is refused: not an array, or not all action ids. */
|
|
53
|
+
{
|
|
54
|
+
readonly kind: 'array';
|
|
55
|
+
readonly message: string;
|
|
56
|
+
}
|
|
57
|
+
/** An id that names no registered action of the related object. */
|
|
58
|
+
| {
|
|
59
|
+
readonly kind: 'unresolved';
|
|
60
|
+
readonly id: string;
|
|
61
|
+
}
|
|
62
|
+
/** An id that resolves, to an action declaring no location this list renders. */
|
|
63
|
+
| {
|
|
64
|
+
readonly kind: 'unplaced';
|
|
65
|
+
readonly id: string;
|
|
66
|
+
};
|
|
67
|
+
export interface PlacedRelatedListActions<T> {
|
|
68
|
+
/** `list_toolbar` actions, in authored order — the list's header buttons. */
|
|
69
|
+
readonly toolbar: T[];
|
|
70
|
+
/** `list_item` and `record_related` actions, in authored order — each row's menu. */
|
|
71
|
+
readonly row: T[];
|
|
72
|
+
/** Every authored entry that renders nowhere, and why. */
|
|
73
|
+
readonly refused: RelatedListActionRefusal[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Whether an authored value has any id to look up — the registry-independent
|
|
77
|
+
* half of the shared rule, so the caller requests the metadata read only when
|
|
78
|
+
* it can change the answer (a `[]`, an object array or a refused array is
|
|
79
|
+
* decided without it).
|
|
80
|
+
*/
|
|
81
|
+
export declare function relatedListActionsNeedLookup(authored: unknown): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Resolve and place an authored `record:related_list.actions` value.
|
|
84
|
+
*
|
|
85
|
+
* `registered` is the related object's `actions` once the metadata lookup has
|
|
86
|
+
* ANSWERED. The caller does not call this while the lookup is in flight: every
|
|
87
|
+
* id would come back unresolved and the list would refuse an id it is about to
|
|
88
|
+
* resolve.
|
|
89
|
+
*
|
|
90
|
+
* An id authored twice renders once, at its first position — it is drawn, so
|
|
91
|
+
* nothing the author asked for is dropped.
|
|
92
|
+
*/
|
|
93
|
+
export declare function placeAuthoredRelatedListActions<T extends RegisteredRelatedAction>(authored: unknown, registered: readonly T[] | null | undefined): PlacedRelatedListActions<T>;
|
|
94
|
+
/**
|
|
95
|
+
* The refusal notice's text — one sentence per refused entry, naming it and
|
|
96
|
+
* the related object, so the fix is a one-entry edit.
|
|
97
|
+
*
|
|
98
|
+
* `objectKnown` is whether the lookup found the related object at all: an id
|
|
99
|
+
* cannot be "not an action of" an object whose metadata never arrived.
|
|
100
|
+
*/
|
|
101
|
+
export declare function describeRelatedListActionRefusals(refused: readonly RelatedListActionRefusal[], objectName: string, objectKnown: boolean): string;
|
|
102
|
+
//# sourceMappingURL=relatedListActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relatedListActions.d.ts","sourceRoot":"","sources":["../../src/renderers/relatedListActions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,2EAA2E;AAC3E,MAAM,MAAM,wBAAwB;AAClC,wEAAwE;AACtE;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACtD,mEAAmE;GACjE;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AACtD,iFAAiF;GAC/E;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;IACtB,qFAAqF;IACrF,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;IAClB,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,wBAAwB,EAAE,CAAC;CAC9C;AAQD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAIvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAAC,CAAC,SAAS,uBAAuB,EAC/E,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,GAC1C,wBAAwB,CAAC,CAAC,CAAC,CA6C7B;AAED;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,SAAS,wBAAwB,EAAE,EAC5C,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,GACnB,MAAM,CAeR"}
|