@ai-matrx/content-ir-react 0.15.2 → 0.16.1
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 +35 -0
- package/dist/{directive-host-DJfF35FD.d.cts → directive-host-C4TcPpxX.d.cts} +19 -2
- package/dist/{directive-host-DJfF35FD.d.ts → directive-host-C4TcPpxX.d.ts} +19 -2
- package/dist/directives.cjs +145 -28
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +85 -41
- package/dist/directives.d.ts +85 -41
- package/dist/directives.js +145 -28
- package/dist/directives.js.map +1 -1
- package/dist/{host-types-9NfBeqrG.d.ts → host-types-CEc86R-v.d.ts} +1 -1
- package/dist/{host-types-DVIaaGR_.d.cts → host-types-a0XEr5b3.d.cts} +1 -1
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts +3 -3
- package/dist/host.d.ts +3 -3
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +151 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -42
- package/dist/index.d.ts +85 -42
- package/dist/index.js +148 -31
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +144 -33
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +141 -30
- package/dist/react.js.map +1 -1
- package/dist/{route-DDbgc-ID.d.ts → route-De9c5YgW.d.ts} +19 -2
- package/dist/{route-BCtPhF7W.d.cts → route-YcoyR3Fj.d.cts} +19 -2
- package/dist/route.d.cts +1 -1
- package/dist/route.d.ts +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.1 — 2026-10-02
|
|
4
|
+
|
|
5
|
+
- **A record's title column reads "Title" everywhere.** `itemChanges(item, current,
|
|
6
|
+
{ titleColumn })` labels the noun's title column "Title" (a note's is stored in
|
|
7
|
+
`label`, and the confirm said "Label" while the form said "Title"); the card's update
|
|
8
|
+
row passes `nounTitleColumn`. Guard: `__tests__/directive-card-g3.test.tsx` ("a
|
|
9
|
+
record's title column…", 2 red on 0.16.0).
|
|
10
|
+
|
|
11
|
+
Consumer action: a host's own confirm passes `{ titleColumn }` to `itemChanges`.
|
|
12
|
+
|
|
13
|
+
## 0.16.0 — 2026-10-02
|
|
14
|
+
|
|
15
|
+
The G3 review of the action cards (nightly clone). Guard: `__tests__/directive-card-g3.test.tsx`
|
|
16
|
+
(7 cases, every one red on 0.15.2).
|
|
17
|
+
|
|
18
|
+
- **An update says old → new.** New host seam `DirectiveHost.readRecord({noun, id})` →
|
|
19
|
+
the record's current fields (or null). `itemChanges(item, current)` now carries `before`
|
|
20
|
+
and `same`; the new `DirectiveChangeList` draws "Label old → new" (old struck through,
|
|
21
|
+
"empty" for a blank field, "(no change)" when it already holds the value). ONE component
|
|
22
|
+
for the card row and a host's confirm dialog. `useRecordValues(read, ref)` reads it.
|
|
23
|
+
- **A Delete card's Apply looks destructive** (`data-apply-tone="destructive"`), not the
|
|
24
|
+
neutral grey of a create's.
|
|
25
|
+
- **Run again shows the copies.** `DirectiveApplyState.copies` (1 + every Run again) and
|
|
26
|
+
`records` = the LATEST copy's. The tally says "2 copies" (create) / "Ran 2 times" and
|
|
27
|
+
links the newest copy; a yes to Run again counts one more.
|
|
28
|
+
- **The card's state belongs to the block, not its slot.** A host that keys blocks by
|
|
29
|
+
position handed one card instance a different directive when a block was inserted
|
|
30
|
+
above it; an applied Update card flipped back to "Apply" until a reload. The Apply
|
|
31
|
+
control now resets and re-reads the ledger whenever the block it draws changes, and an
|
|
32
|
+
apply that finishes after its block moved away never lands on the new one.
|
|
33
|
+
|
|
34
|
+
Consumer action: pass `readRecord` on the directive host for old → new; a host's own
|
|
35
|
+
confirm dialog draws changes through `DirectiveChangeList`; an `applyState` answer passes
|
|
36
|
+
`copies` when its ledger knows it.
|
|
37
|
+
|
|
3
38
|
## 0.15.2 — 2026-10-02
|
|
4
39
|
|
|
5
40
|
- While "Run again" asks, the tally stays on screen (only its own button goes
|
|
@@ -32,8 +32,17 @@ interface DirectiveApplyState {
|
|
|
32
32
|
state: "not_applied" | "in_flight" | "applied";
|
|
33
33
|
/** The ledger row's sentence ("Created task."), never composed client-side. */
|
|
34
34
|
message?: string | null;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* The records the LATEST apply wrote — the tally's doors. After "Run again"
|
|
37
|
+
* that is the newest copy, never the first.
|
|
38
|
+
*/
|
|
36
39
|
records?: DirectiveRecordRef[];
|
|
40
|
+
/**
|
|
41
|
+
* How many times the ledger holds this block as applied: 1 for the original,
|
|
42
|
+
* one more for every "Run again". Absent → 1. A create that ran twice made
|
|
43
|
+
* two records, and the card says so (reviewer, 2026-10-02).
|
|
44
|
+
*/
|
|
45
|
+
copies?: number;
|
|
37
46
|
}
|
|
38
47
|
/** One record a directive names: the noun it is, and its id. */
|
|
39
48
|
interface DirectiveRecordRef {
|
|
@@ -132,6 +141,14 @@ interface DirectiveHost {
|
|
|
132
141
|
* is idempotent. Absent → the card starts at Apply, as before.
|
|
133
142
|
*/
|
|
134
143
|
applyState?: (shell: DirectiveShell) => Promise<DirectiveApplyState>;
|
|
144
|
+
/**
|
|
145
|
+
* Read the CURRENT values of ONE existing record, so an update says what it
|
|
146
|
+
* replaces — "Status open → done", never just "→ done" (reviewer,
|
|
147
|
+
* 2026-10-02). Resolve `null` when the record cannot be read (no access, no
|
|
148
|
+
* such record, a noun the host cannot read); reject only for a real failure.
|
|
149
|
+
* Absent → an update row shows the new values alone, as before.
|
|
150
|
+
*/
|
|
151
|
+
readRecord?: (ref: DirectiveRecordRef) => Promise<Record<string, unknown> | null>;
|
|
135
152
|
/**
|
|
136
153
|
* Draw ONE existing record by its live name, as a way to open it. Used on
|
|
137
154
|
* update/delete rows (the record that will change), in the host's own ask
|
|
@@ -176,4 +193,4 @@ declare function DirectiveHostProvider({ host, children }: DirectiveHostProvider
|
|
|
176
193
|
*/
|
|
177
194
|
declare function useDirectiveHost(): DirectiveHost;
|
|
178
195
|
|
|
179
|
-
export { type
|
|
196
|
+
export { type DirectiveRecordRef as D, type DirectiveApplyResult as a, type DirectiveApplyState as b, type DirectiveAskRequest as c, type DirectiveCopyProps as d, type DirectiveHost as e, DirectiveHostProvider as f, type DirectiveHostProviderProps as g, type DirectiveOpenItemOptions as h, type DirectiveRecordProps as i, type DirectiveScope as j, DirectiveScopeProvider as k, type DirectiveShell as l, useDirectiveScope as m, useDirectiveHost as u };
|
|
@@ -32,8 +32,17 @@ interface DirectiveApplyState {
|
|
|
32
32
|
state: "not_applied" | "in_flight" | "applied";
|
|
33
33
|
/** The ledger row's sentence ("Created task."), never composed client-side. */
|
|
34
34
|
message?: string | null;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* The records the LATEST apply wrote — the tally's doors. After "Run again"
|
|
37
|
+
* that is the newest copy, never the first.
|
|
38
|
+
*/
|
|
36
39
|
records?: DirectiveRecordRef[];
|
|
40
|
+
/**
|
|
41
|
+
* How many times the ledger holds this block as applied: 1 for the original,
|
|
42
|
+
* one more for every "Run again". Absent → 1. A create that ran twice made
|
|
43
|
+
* two records, and the card says so (reviewer, 2026-10-02).
|
|
44
|
+
*/
|
|
45
|
+
copies?: number;
|
|
37
46
|
}
|
|
38
47
|
/** One record a directive names: the noun it is, and its id. */
|
|
39
48
|
interface DirectiveRecordRef {
|
|
@@ -132,6 +141,14 @@ interface DirectiveHost {
|
|
|
132
141
|
* is idempotent. Absent → the card starts at Apply, as before.
|
|
133
142
|
*/
|
|
134
143
|
applyState?: (shell: DirectiveShell) => Promise<DirectiveApplyState>;
|
|
144
|
+
/**
|
|
145
|
+
* Read the CURRENT values of ONE existing record, so an update says what it
|
|
146
|
+
* replaces — "Status open → done", never just "→ done" (reviewer,
|
|
147
|
+
* 2026-10-02). Resolve `null` when the record cannot be read (no access, no
|
|
148
|
+
* such record, a noun the host cannot read); reject only for a real failure.
|
|
149
|
+
* Absent → an update row shows the new values alone, as before.
|
|
150
|
+
*/
|
|
151
|
+
readRecord?: (ref: DirectiveRecordRef) => Promise<Record<string, unknown> | null>;
|
|
135
152
|
/**
|
|
136
153
|
* Draw ONE existing record by its live name, as a way to open it. Used on
|
|
137
154
|
* update/delete rows (the record that will change), in the host's own ask
|
|
@@ -176,4 +193,4 @@ declare function DirectiveHostProvider({ host, children }: DirectiveHostProvider
|
|
|
176
193
|
*/
|
|
177
194
|
declare function useDirectiveHost(): DirectiveHost;
|
|
178
195
|
|
|
179
|
-
export { type
|
|
196
|
+
export { type DirectiveRecordRef as D, type DirectiveApplyResult as a, type DirectiveApplyState as b, type DirectiveAskRequest as c, type DirectiveCopyProps as d, type DirectiveHost as e, DirectiveHostProvider as f, type DirectiveHostProviderProps as g, type DirectiveOpenItemOptions as h, type DirectiveRecordProps as i, type DirectiveScope as j, DirectiveScopeProvider as k, type DirectiveShell as l, useDirectiveScope as m, useDirectiveHost as u };
|
package/dist/directives.cjs
CHANGED
|
@@ -23,6 +23,7 @@ var directives_exports = {};
|
|
|
23
23
|
__export(directives_exports, {
|
|
24
24
|
ApplyDirectiveButton: () => ApplyDirectiveButton,
|
|
25
25
|
CHANGE_VALUE_MAX: () => CHANGE_VALUE_MAX,
|
|
26
|
+
DirectiveChangeList: () => DirectiveChangeList,
|
|
26
27
|
DirectiveFallbackCard: () => DirectiveFallbackCard,
|
|
27
28
|
DirectiveHostProvider: () => DirectiveHostProvider,
|
|
28
29
|
DirectiveProvisionalCard: () => DirectiveProvisionalCard,
|
|
@@ -30,6 +31,7 @@ __export(directives_exports, {
|
|
|
30
31
|
DirectiveScopeProvider: () => DirectiveScopeProvider,
|
|
31
32
|
SideEffectDirectiveCard: () => SideEffectDirectiveCard,
|
|
32
33
|
TARGETING_CLASSES: () => TARGETING_CLASSES,
|
|
34
|
+
describeChangeValue: () => describeChangeValue,
|
|
33
35
|
fieldLabel: () => fieldLabel,
|
|
34
36
|
getDirectiveRenderer: () => getDirectiveRenderer,
|
|
35
37
|
itemChanges: () => itemChanges,
|
|
@@ -39,7 +41,8 @@ __export(directives_exports, {
|
|
|
39
41
|
registerDirectiveRenderer: () => registerDirectiveRenderer,
|
|
40
42
|
resetDirectiveRenderers: () => resetDirectiveRenderers,
|
|
41
43
|
useDirectiveHost: () => useDirectiveHost,
|
|
42
|
-
useDirectiveScope: () => useDirectiveScope
|
|
44
|
+
useDirectiveScope: () => useDirectiveScope,
|
|
45
|
+
useRecordValues: () => useRecordValues
|
|
43
46
|
});
|
|
44
47
|
module.exports = __toCommonJS(directives_exports);
|
|
45
48
|
|
|
@@ -107,6 +110,9 @@ function recordFallbackName(nounLabel3, id) {
|
|
|
107
110
|
const short = (0, import_uuid.isUuidShape)(id) ? id.slice(0, 8) : id.length > 12 ? `${id.slice(0, 12)}\u2026` : id;
|
|
108
111
|
return `${nounLabel3} ${short}`;
|
|
109
112
|
}
|
|
113
|
+
function describeChangeValue(value) {
|
|
114
|
+
return describeValue(value);
|
|
115
|
+
}
|
|
110
116
|
function describeValue(value) {
|
|
111
117
|
if (value === null || value === void 0) return { value: "cleared", full: "cleared", clears: true };
|
|
112
118
|
if (typeof value === "string") {
|
|
@@ -135,11 +141,28 @@ function safeJson(value) {
|
|
|
135
141
|
return String(value);
|
|
136
142
|
}
|
|
137
143
|
}
|
|
138
|
-
function
|
|
144
|
+
function sameValue(a, b) {
|
|
145
|
+
if (a === b) return true;
|
|
146
|
+
if (a === null || a === void 0 || b === null || b === void 0) {
|
|
147
|
+
const emptyA = a === null || a === void 0 || a === "";
|
|
148
|
+
const emptyB = b === null || b === void 0 || b === "";
|
|
149
|
+
return emptyA && emptyB;
|
|
150
|
+
}
|
|
151
|
+
if (typeof a === "object" || typeof b === "object") return safeJson(a) === safeJson(b);
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
function itemChanges(item, current, options = {}) {
|
|
139
155
|
const out = [];
|
|
156
|
+
const titleColumn = options.titleColumn ?? null;
|
|
140
157
|
for (const [key, raw] of Object.entries(item)) {
|
|
141
158
|
if (NOT_A_CHANGE.has(key)) continue;
|
|
142
|
-
|
|
159
|
+
const label = key === titleColumn ? "Title" : fieldLabel(key);
|
|
160
|
+
const change = { key, label, ...describeValue(raw) };
|
|
161
|
+
if (current && Object.prototype.hasOwnProperty.call(current, key)) {
|
|
162
|
+
change.before = describeValue(current[key]);
|
|
163
|
+
change.same = sameValue(current[key], raw);
|
|
164
|
+
}
|
|
165
|
+
out.push(change);
|
|
143
166
|
}
|
|
144
167
|
return out;
|
|
145
168
|
}
|
|
@@ -252,12 +275,23 @@ function ApplyDirectiveButton({
|
|
|
252
275
|
const conversationId = scope.conversationId || void 0;
|
|
253
276
|
const items = directive.items;
|
|
254
277
|
const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
);
|
|
278
|
+
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
279
|
+
const [state, setState] = (0, import_react2.useState)(initial);
|
|
258
280
|
const [elapsed, setElapsed] = (0, import_react2.useState)(0);
|
|
259
281
|
const [askingAgain, setAskingAgain] = (0, import_react2.useState)(false);
|
|
260
282
|
const startedAt = (0, import_react2.useRef)(null);
|
|
283
|
+
const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
|
|
284
|
+
const [stateFor, setStateFor] = (0, import_react2.useState)(identity);
|
|
285
|
+
if (stateFor !== identity) {
|
|
286
|
+
setStateFor(identity);
|
|
287
|
+
setState(initial);
|
|
288
|
+
setAskingAgain(false);
|
|
289
|
+
setElapsed(0);
|
|
290
|
+
}
|
|
291
|
+
const currentIdentity = (0, import_react2.useRef)(identity);
|
|
292
|
+
(0, import_react2.useEffect)(() => {
|
|
293
|
+
currentIdentity.current = identity;
|
|
294
|
+
}, [identity]);
|
|
261
295
|
const nounText = (0, import_content_ir2.nounLabel)(directive.noun, host.nouns);
|
|
262
296
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
263
297
|
const read = host.applyState;
|
|
@@ -280,7 +314,8 @@ function ApplyDirectiveButton({
|
|
|
280
314
|
applied: shellItems.length,
|
|
281
315
|
failed: 0,
|
|
282
316
|
message: answer.message?.trim() ? answer.message.trim() : null,
|
|
283
|
-
records: answer.records ?? []
|
|
317
|
+
records: answer.records ?? [],
|
|
318
|
+
copies: Math.max(1, answer.copies ?? 1)
|
|
284
319
|
} : prev
|
|
285
320
|
);
|
|
286
321
|
} else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
|
|
@@ -320,6 +355,9 @@ function ApplyDirectiveButton({
|
|
|
320
355
|
async function handleApply(again = false) {
|
|
321
356
|
if (!confirm) return;
|
|
322
357
|
const before = state;
|
|
358
|
+
const askedFor = identity;
|
|
359
|
+
const stillHere = () => currentIdentity.current === askedFor;
|
|
360
|
+
const priorCopies = state.status === "applied" ? state.copies : 0;
|
|
323
361
|
if (host.ask) {
|
|
324
362
|
if (again) setAskingAgain(true);
|
|
325
363
|
else setState({ status: "asking" });
|
|
@@ -332,6 +370,7 @@ function ApplyDirectiveButton({
|
|
|
332
370
|
...again ? { again: true } : {}
|
|
333
371
|
});
|
|
334
372
|
} catch (error) {
|
|
373
|
+
if (!stillHere()) return;
|
|
335
374
|
setAskingAgain(false);
|
|
336
375
|
setState({
|
|
337
376
|
status: "error",
|
|
@@ -339,6 +378,7 @@ function ApplyDirectiveButton({
|
|
|
339
378
|
});
|
|
340
379
|
return;
|
|
341
380
|
}
|
|
381
|
+
if (!stillHere()) return;
|
|
342
382
|
setAskingAgain(false);
|
|
343
383
|
if (!ok) {
|
|
344
384
|
setState(again ? before : { status: "idle" });
|
|
@@ -352,15 +392,19 @@ function ApplyDirectiveButton({
|
|
|
352
392
|
if (conversationId) shell.conversationId = conversationId;
|
|
353
393
|
if (again) shell.force = true;
|
|
354
394
|
const result = await confirm(shell);
|
|
395
|
+
if (!stillHere()) return;
|
|
355
396
|
setState({
|
|
356
397
|
status: "applied",
|
|
357
398
|
applied: result.applied,
|
|
358
399
|
failed: result.failed,
|
|
359
400
|
message: result.message?.trim() ? result.message.trim() : null,
|
|
360
|
-
records: result.records ?? []
|
|
401
|
+
records: result.records ?? [],
|
|
402
|
+
// "Run again" made one more; a first apply (or a replay of one) is one.
|
|
403
|
+
copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies)
|
|
361
404
|
});
|
|
362
405
|
onApplied?.();
|
|
363
406
|
} catch (error) {
|
|
407
|
+
if (!stillHere()) return;
|
|
364
408
|
setState({
|
|
365
409
|
status: "error",
|
|
366
410
|
message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
|
|
@@ -385,6 +429,15 @@ function ApplyDirectiveButton({
|
|
|
385
429
|
bad && !state.message ? ` \xB7 ${state.failed} failed` : ""
|
|
386
430
|
] })
|
|
387
431
|
] }),
|
|
432
|
+
state.copies > 1 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
433
|
+
"span",
|
|
434
|
+
{
|
|
435
|
+
className: "shrink-0 text-muted-foreground",
|
|
436
|
+
"data-apply-copies": state.copies,
|
|
437
|
+
title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
|
|
438
|
+
children: directive.directiveClass === "create" ? `${state.copies} copies` : `Ran ${state.copies} times`
|
|
439
|
+
}
|
|
440
|
+
) : null,
|
|
388
441
|
records.map((record) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
389
442
|
...record,
|
|
390
443
|
fallback: recordFallbackName(label2, record.id),
|
|
@@ -435,6 +488,7 @@ function ApplyDirectiveButton({
|
|
|
435
488
|
}
|
|
436
489
|
);
|
|
437
490
|
}
|
|
491
|
+
const destructive = directive.directiveClass === "delete";
|
|
438
492
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
|
|
439
493
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
440
494
|
"button",
|
|
@@ -442,7 +496,8 @@ function ApplyDirectiveButton({
|
|
|
442
496
|
type: "button",
|
|
443
497
|
onClick: () => void handleApply(),
|
|
444
498
|
disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
|
|
445
|
-
|
|
499
|
+
"data-apply-tone": destructive ? "destructive" : "default",
|
|
500
|
+
className: `inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-medium disabled:opacity-50 ${destructive ? "border-destructive/50 bg-background text-destructive hover:bg-destructive/10" : "border-border bg-background hover:bg-accent"}`,
|
|
446
501
|
children: [
|
|
447
502
|
state.status === "applying" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PlayIcon, { className: "h-3.5 w-3.5" }),
|
|
448
503
|
state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
@@ -457,8 +512,41 @@ function ApplyDirectiveButton({
|
|
|
457
512
|
}
|
|
458
513
|
|
|
459
514
|
// directives/SideEffectDirectiveCard.tsx
|
|
460
|
-
var
|
|
515
|
+
var import_react4 = require("react");
|
|
461
516
|
var import_content_ir3 = require("@ai-matrx/content-ir");
|
|
517
|
+
|
|
518
|
+
// directives/record-values.ts
|
|
519
|
+
var import_react3 = require("react");
|
|
520
|
+
function useRecordValues(read, ref) {
|
|
521
|
+
const key = ref && read ? `${ref.noun}:${ref.id}` : "";
|
|
522
|
+
const [result, setResult] = (0, import_react3.useState)({
|
|
523
|
+
key: "",
|
|
524
|
+
values: null,
|
|
525
|
+
status: "idle"
|
|
526
|
+
});
|
|
527
|
+
(0, import_react3.useEffect)(() => {
|
|
528
|
+
if (!key || !read) return;
|
|
529
|
+
const split = key.indexOf(":");
|
|
530
|
+
const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
|
|
531
|
+
let live = true;
|
|
532
|
+
setResult({ key, values: null, status: "loading" });
|
|
533
|
+
read(target).then((values) => {
|
|
534
|
+
if (!live) return;
|
|
535
|
+
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
536
|
+
}).catch(() => {
|
|
537
|
+
if (!live) return;
|
|
538
|
+
setResult({ key, values: null, status: "unavailable" });
|
|
539
|
+
});
|
|
540
|
+
return () => {
|
|
541
|
+
live = false;
|
|
542
|
+
};
|
|
543
|
+
}, [key, read]);
|
|
544
|
+
if (!key) return { values: null, status: "idle" };
|
|
545
|
+
if (result.key !== key) return { values: null, status: "loading" };
|
|
546
|
+
return { values: result.values, status: result.status };
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// directives/SideEffectDirectiveCard.tsx
|
|
462
550
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
463
551
|
var ROWS_BEFORE_FOLD = 3;
|
|
464
552
|
function ItemRow({
|
|
@@ -512,44 +600,73 @@ function ItemRow({
|
|
|
512
600
|
host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
|
|
513
601
|
] });
|
|
514
602
|
}
|
|
515
|
-
function
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
recordId
|
|
603
|
+
function DirectiveChangeList({
|
|
604
|
+
changes,
|
|
605
|
+
className
|
|
519
606
|
}) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
528
|
-
] }),
|
|
529
|
-
directive.directiveClass === "update" ? changes.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "px-1 text-[11px] text-muted-foreground", children: "Sets no fields \u2014 nothing would change." }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "mt-0.5 space-y-0.5 px-1", children: changes.map((change) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
607
|
+
if (changes.length === 0) {
|
|
608
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: `text-[11px] text-muted-foreground${className ? ` ${className}` : ""}`, children: "Sets no fields \u2014 nothing would change." });
|
|
609
|
+
}
|
|
610
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: `space-y-0.5${className ? ` ${className}` : ""}`, "data-directive-changes": "", children: changes.map((change) => {
|
|
611
|
+
const before = change.before && !change.same ? change.before : null;
|
|
612
|
+
const was = before ? before.clears ? "empty" : before.value : null;
|
|
613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
530
614
|
"li",
|
|
531
615
|
{
|
|
532
616
|
className: "flex min-w-0 items-baseline gap-1.5 text-[11px]",
|
|
533
|
-
title: `${change.label} \u2192 ${change.full}`,
|
|
617
|
+
title: before ? `${change.label}: ${before.clears ? "empty" : before.full} \u2192 ${change.full}` : `${change.label} \u2192 ${change.full}`,
|
|
618
|
+
"data-change-key": change.key,
|
|
534
619
|
children: [
|
|
535
620
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "shrink-0 text-muted-foreground", children: change.label }),
|
|
621
|
+
was !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
622
|
+
"span",
|
|
623
|
+
{
|
|
624
|
+
className: "min-w-0 max-w-[40%] shrink truncate text-muted-foreground line-through",
|
|
625
|
+
"data-change-before": "",
|
|
626
|
+
children: was
|
|
627
|
+
}
|
|
628
|
+
) : null,
|
|
536
629
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": true, className: "shrink-0 text-muted-foreground", children: "\u2192" }),
|
|
537
630
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
538
631
|
"span",
|
|
539
632
|
{
|
|
540
633
|
className: `min-w-0 truncate ${change.clears ? "italic text-muted-foreground" : "text-foreground"}`,
|
|
634
|
+
"data-change-after": "",
|
|
541
635
|
children: change.value
|
|
542
636
|
}
|
|
543
|
-
)
|
|
637
|
+
),
|
|
638
|
+
change.same ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "shrink-0 text-muted-foreground", children: "(no change)" }) : null
|
|
544
639
|
]
|
|
545
640
|
},
|
|
546
641
|
change.key
|
|
547
|
-
)
|
|
642
|
+
);
|
|
643
|
+
}) });
|
|
644
|
+
}
|
|
645
|
+
function TargetRow({
|
|
646
|
+
directive,
|
|
647
|
+
item,
|
|
648
|
+
recordId
|
|
649
|
+
}) {
|
|
650
|
+
const host = useDirectiveHost();
|
|
651
|
+
const fallback = recordFallbackName((0, import_content_ir3.nounLabel)(directive.noun, host.nouns), recordId);
|
|
652
|
+
const isUpdate = directive.directiveClass === "update";
|
|
653
|
+
const current = useRecordValues(
|
|
654
|
+
isUpdate ? host.readRecord : void 0,
|
|
655
|
+
isUpdate ? { noun: directive.noun, id: recordId } : null
|
|
656
|
+
);
|
|
657
|
+
const changes = isUpdate ? itemChanges(item, current.values, { titleColumn: (0, import_content_ir3.nounTitleColumn)(directive.noun, host.nouns) }) : [];
|
|
658
|
+
const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate font-medium text-foreground", children: fallback });
|
|
659
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
|
|
660
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
661
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
|
|
662
|
+
host.renderCopy?.({ label: fallback, value: item, size: "xs" })
|
|
663
|
+
] }),
|
|
664
|
+
isUpdate ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DirectiveChangeList, { changes, className: "mt-0.5 px-1" }) : null
|
|
548
665
|
] });
|
|
549
666
|
}
|
|
550
667
|
function SideEffectDirectiveCard({ directive }) {
|
|
551
668
|
const host = useDirectiveHost();
|
|
552
|
-
const [expanded, setExpanded] = (0,
|
|
669
|
+
const [expanded, setExpanded] = (0, import_react4.useState)(false);
|
|
553
670
|
const items = directive.items;
|
|
554
671
|
const total = items.length;
|
|
555
672
|
const display = (0, import_content_ir3.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
|