@ai-matrx/content-ir-react 0.13.17 → 0.14.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/dist/react.cjs CHANGED
@@ -274,6 +274,8 @@ function classIcon(directiveClass, noun) {
274
274
 
275
275
  // directives/ApplyDirectiveButton.tsx
276
276
  var import_jsx_runtime4 = require("react/jsx-runtime");
277
+ var FINISH_POLL_MS = 2e3;
278
+ var FINISH_POLLS_MAX = 30;
277
279
  function ApplyDirectiveButton({
278
280
  directive,
279
281
  label = "Apply",
@@ -281,9 +283,58 @@ function ApplyDirectiveButton({
281
283
  onApplied
282
284
  }) {
283
285
  const host = useDirectiveHost();
284
- const [state, setState] = (0, import_react4.useState)({ status: "idle" });
286
+ const items = directive.items;
287
+ const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
288
+ const [state, setState] = (0, import_react4.useState)(
289
+ readsLedger ? { status: "checking" } : { status: "idle" }
290
+ );
285
291
  const [elapsed, setElapsed] = (0, import_react4.useState)(0);
286
292
  const startedAt = (0, import_react4.useRef)(null);
293
+ const nounText = (0, import_content_ir.nounLabel)(directive.noun, host.nouns);
294
+ const shellKey = readsLedger ? JSON.stringify([directive.slug, items]) : "";
295
+ const read = host.applyState;
296
+ const report = host.reportError;
297
+ (0, import_react4.useEffect)(() => {
298
+ if (!shellKey || !read) return;
299
+ const [slug, shellItems] = JSON.parse(shellKey);
300
+ let live = true;
301
+ let polls = 0;
302
+ let timer = null;
303
+ const ask = () => {
304
+ read({ __kind: slug, items: shellItems }).then((answer) => {
305
+ if (!live) return;
306
+ if (answer.state === "applied") {
307
+ setState(
308
+ (prev) => prev.status === "checking" || prev.status === "finishing" ? {
309
+ status: "applied",
310
+ applied: shellItems.length,
311
+ failed: 0,
312
+ message: answer.message?.trim() ? answer.message.trim() : null,
313
+ records: answer.records ?? []
314
+ } : prev
315
+ );
316
+ } else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
317
+ polls += 1;
318
+ setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "finishing" } : prev);
319
+ timer = setTimeout(ask, FINISH_POLL_MS);
320
+ } else {
321
+ setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "idle" } : prev);
322
+ }
323
+ }).catch((error) => {
324
+ if (!live) return;
325
+ const why = error instanceof Error && error.message ? error.message : String(error);
326
+ (report ?? console.error)(
327
+ `[kind-directives] Could not read whether ${slug} was already applied: ${why}`
328
+ );
329
+ setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "idle" } : prev);
330
+ });
331
+ };
332
+ ask();
333
+ return () => {
334
+ live = false;
335
+ if (timer) clearTimeout(timer);
336
+ };
337
+ }, [shellKey, read, report]);
287
338
  (0, import_react4.useEffect)(() => {
288
339
  if (state.status !== "applying") return;
289
340
  startedAt.current = Date.now();
@@ -296,7 +347,6 @@ function ApplyDirectiveButton({
296
347
  if (!directive.parsed.executes) return null;
297
348
  const confirm = host.confirm;
298
349
  if (!confirm) return null;
299
- const items = directive.items;
300
350
  async function handleApply() {
301
351
  if (!confirm) return;
302
352
  if (host.ask) {
@@ -306,7 +356,7 @@ function ApplyDirectiveButton({
306
356
  ok = await host.ask({
307
357
  directive,
308
358
  items,
309
- nounLabel: (0, import_content_ir.nounLabel)(directive.noun, host.nouns)
359
+ nounLabel: nounText
310
360
  });
311
361
  } catch (error) {
312
362
  setState({
@@ -342,7 +392,7 @@ function ApplyDirectiveButton({
342
392
  if (state.status === "applied") {
343
393
  const bad = state.failed > 0;
344
394
  const trashed = directive.directiveClass === "delete";
345
- const label2 = (0, import_content_ir.nounLabel)(directive.noun, host.nouns);
395
+ const label2 = nounText;
346
396
  const records = host.renderRecord ? state.records : [];
347
397
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
348
398
  "span",
@@ -365,6 +415,32 @@ function ApplyDirectiveButton({
365
415
  }
366
416
  );
367
417
  }
418
+ if (state.status === "checking") {
419
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
420
+ "span",
421
+ {
422
+ className: "inline-flex h-6 w-6 items-center justify-center text-muted-foreground",
423
+ role: "status",
424
+ "aria-label": "Checking whether this already ran",
425
+ "data-apply-state": "checking",
426
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" })
427
+ }
428
+ );
429
+ }
430
+ if (state.status === "finishing") {
431
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
432
+ "span",
433
+ {
434
+ className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
435
+ role: "status",
436
+ "data-apply-state": "finishing",
437
+ children: [
438
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }),
439
+ "Finishing\u2026"
440
+ ]
441
+ }
442
+ );
443
+ }
368
444
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
369
445
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
370
446
  "button",