pxengine 0.1.147 → 0.1.148

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/index.cjs CHANGED
@@ -18333,7 +18333,14 @@ var PresentationJobCard = ({
18333
18333
  // src/molecules/generic/ResearchReportJobCard/ResearchReportJobCard.tsx
18334
18334
  var import_react83 = require("react");
18335
18335
  var import_react_dom2 = require("react-dom");
18336
+ var import_core = require("@dnd-kit/core");
18337
+ var import_sortable = require("@dnd-kit/sortable");
18338
+ var import_utilities = require("@dnd-kit/utilities");
18336
18339
  var import_jsx_runtime154 = require("react/jsx-runtime");
18340
+ var outlineCollisionDetection = (args) => {
18341
+ const pointerHits = (0, import_core.pointerWithin)(args);
18342
+ return pointerHits.length > 0 ? pointerHits : (0, import_core.closestCenter)(args);
18343
+ };
18337
18344
  var DEFAULT_THEME = {
18338
18345
  primary: "#C0AE82",
18339
18346
  secondary: "#C4AD7C",
@@ -18577,6 +18584,90 @@ function deriveJobStatusUrl2(newJobId, pollUrl, regenerateUrl) {
18577
18584
  const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/reports\/[^/]+\/regenerate.*$/, "") ?? "";
18578
18585
  return `${base}/api/jobs/${newJobId}/status`;
18579
18586
  }
18587
+ var OutlineSectionRow = ({
18588
+ index,
18589
+ section,
18590
+ headingValue,
18591
+ subHeadingValue,
18592
+ onHeadingChange,
18593
+ onSubHeadingChange,
18594
+ onToggleApproved,
18595
+ disabled,
18596
+ rowBusy
18597
+ }) => {
18598
+ const { attributes, listeners: listeners2, setNodeRef, transform, transition, isDragging } = (0, import_sortable.useSortable)({
18599
+ id: String(index),
18600
+ disabled
18601
+ });
18602
+ return /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
18603
+ "div",
18604
+ {
18605
+ ref: setNodeRef,
18606
+ style: { transform: import_utilities.CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1 },
18607
+ className: cn(
18608
+ "rounded-xl border bg-zinc-800/40 p-3 transition-colors",
18609
+ section.approved ? "border-emerald-700/40" : "border-zinc-700/60"
18610
+ ),
18611
+ children: /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { className: "flex items-start gap-2.5", children: [
18612
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
18613
+ "span",
18614
+ {
18615
+ ...attributes,
18616
+ ...listeners2,
18617
+ className: "flex-shrink-0 mt-1.5 cursor-grab text-zinc-600 hover:text-zinc-400 active:cursor-grabbing touch-none",
18618
+ children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(GripVertical, { size: 14 })
18619
+ }
18620
+ ),
18621
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
18622
+ "span",
18623
+ {
18624
+ className: cn(
18625
+ "flex-shrink-0 mt-1 w-5 h-5 rounded-full flex items-center justify-center text-[10px] font-semibold tabular-nums",
18626
+ section.approved ? "bg-emerald-500/15 text-emerald-300" : "bg-zinc-700/70 text-zinc-400"
18627
+ ),
18628
+ children: index + 1
18629
+ }
18630
+ ),
18631
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { className: "flex-1 min-w-0", children: [
18632
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
18633
+ "input",
18634
+ {
18635
+ value: headingValue,
18636
+ onChange: (e) => onHeadingChange(e.target.value),
18637
+ disabled,
18638
+ placeholder: "Section heading",
18639
+ className: "w-full bg-transparent text-sm text-zinc-100 placeholder:text-zinc-600 outline-none disabled:opacity-60"
18640
+ }
18641
+ ),
18642
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
18643
+ "input",
18644
+ {
18645
+ value: subHeadingValue,
18646
+ onChange: (e) => onSubHeadingChange(e.target.value),
18647
+ disabled,
18648
+ placeholder: "One-line summary",
18649
+ className: "mt-0.5 w-full bg-transparent text-xs text-zinc-500 placeholder:text-zinc-700 outline-none disabled:opacity-60"
18650
+ }
18651
+ )
18652
+ ] }),
18653
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
18654
+ "button",
18655
+ {
18656
+ type: "button",
18657
+ onClick: onToggleApproved,
18658
+ disabled: rowBusy,
18659
+ title: section.approved ? "Marked reviewed" : "Mark as reviewed",
18660
+ className: cn(
18661
+ "w-7 h-7 flex-shrink-0 flex items-center justify-center rounded-md border disabled:opacity-40",
18662
+ section.approved ? "border-emerald-600/50 bg-emerald-950/40 text-emerald-300" : "border-zinc-700 text-zinc-500 hover:text-zinc-300 hover:border-zinc-500"
18663
+ ),
18664
+ children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(CheckIcon, {})
18665
+ }
18666
+ )
18667
+ ] })
18668
+ }
18669
+ );
18670
+ };
18580
18671
  var ResearchReportJobCard = (props) => {
18581
18672
  const {
18582
18673
  job_id,
@@ -18642,9 +18733,12 @@ var ResearchReportJobCard = (props) => {
18642
18733
  const [regenerating, setRegenerating] = (0, import_react83.useState)(false);
18643
18734
  const [approveError, setApproveError] = (0, import_react83.useState)(null);
18644
18735
  const [headingEdits, setHeadingEdits] = (0, import_react83.useState)({});
18736
+ const [subHeadingEdits, setSubHeadingEdits] = (0, import_react83.useState)({});
18645
18737
  const [approvingOutline, setApprovingOutline] = (0, import_react83.useState)(false);
18646
18738
  const [rowBusyIndex, setRowBusyIndex] = (0, import_react83.useState)(null);
18647
18739
  const [rowError, setRowError] = (0, import_react83.useState)(null);
18740
+ const [reordering, setReordering] = (0, import_react83.useState)(false);
18741
+ const sensors = (0, import_core.useSensors)((0, import_core.useSensor)(import_core.PointerSensor, { activationConstraint: { distance: 4 } }));
18648
18742
  const [outlineWritePollUrl, setOutlineWritePollUrl] = (0, import_react83.useState)(null);
18649
18743
  const [regenPollUrl, setRegenPollUrl] = (0, import_react83.useState)(null);
18650
18744
  const onCompleteRef = (0, import_react83.useRef)(onComplete);
@@ -18906,34 +19000,39 @@ var ResearchReportJobCard = (props) => {
18906
19000
  if (!outline || !Array.isArray(outline.sections)) return void 0;
18907
19001
  let changed = false;
18908
19002
  const sections = outline.sections.map((s, i) => {
18909
- const edited = headingEdits[i];
18910
- if (edited !== void 0 && edited !== s.heading) {
19003
+ const editedHeading = headingEdits[i];
19004
+ const editedSubHeading = subHeadingEdits[i];
19005
+ let next = s;
19006
+ if (editedHeading !== void 0 && editedHeading !== s.heading) {
19007
+ next = { ...next, heading: editedHeading };
18911
19008
  changed = true;
18912
- return { ...s, heading: edited };
18913
19009
  }
18914
- return s;
19010
+ if (editedSubHeading !== void 0 && editedSubHeading !== s.sub_heading) {
19011
+ next = { ...next, sub_heading: editedSubHeading };
19012
+ changed = true;
19013
+ }
19014
+ return next;
18915
19015
  });
18916
19016
  return changed ? { ...outline, sections } : void 0;
18917
19017
  };
18918
- const moveOutlineSection = async (index, delta) => {
18919
- if (!outline || !Array.isArray(outline.sections) || rowBusyIndex !== null) return;
19018
+ const reorderOutlineSections = async (order) => {
19019
+ if (!outline || !Array.isArray(outline.sections) || reordering) return;
18920
19020
  const sections = outline.sections;
18921
- const target = index + delta;
18922
- if (target < 0 || target >= sections.length) return;
18923
- const order = sections.map((_, i) => i);
18924
- [order[index], order[target]] = [order[target], order[index]];
18925
19021
  const reordered = order.map((i) => sections[i]);
18926
19022
  const previousOutline = outline;
18927
- const previousEdits = headingEdits;
18928
- setOutline({ ...outline, sections: reordered });
18929
- setHeadingEdits((prev) => {
19023
+ const previousHeadingEdits = headingEdits;
19024
+ const previousSubHeadingEdits = subHeadingEdits;
19025
+ const remap = (prev) => {
18930
19026
  const remapped = {};
18931
19027
  order.forEach((originalIndex, newIndex) => {
18932
19028
  if (prev[originalIndex] !== void 0) remapped[newIndex] = prev[originalIndex];
18933
19029
  });
18934
19030
  return remapped;
18935
- });
18936
- setRowBusyIndex(index);
19031
+ };
19032
+ setOutline({ ...outline, sections: reordered });
19033
+ setHeadingEdits(remap(previousHeadingEdits));
19034
+ setSubHeadingEdits(remap(previousSubHeadingEdits));
19035
+ setReordering(true);
18937
19036
  setRowError(null);
18938
19037
  try {
18939
19038
  const endpoint = reorderSectionsUrl || `/api/reports/${job_id}/outline/reorder-sections`;
@@ -18950,12 +19049,26 @@ var ResearchReportJobCard = (props) => {
18950
19049
  }
18951
19050
  } catch (e) {
18952
19051
  setOutline(previousOutline);
18953
- setHeadingEdits(previousEdits);
19052
+ setHeadingEdits(previousHeadingEdits);
19053
+ setSubHeadingEdits(previousSubHeadingEdits);
18954
19054
  setRowError(e instanceof Error ? e.message : "Could not reorder sections");
18955
19055
  } finally {
18956
- setRowBusyIndex(null);
19056
+ setReordering(false);
18957
19057
  }
18958
19058
  };
19059
+ const handleOutlineDragEnd = (event) => {
19060
+ const { active, over } = event;
19061
+ if (!over || active.id === over.id || !outline?.sections) return;
19062
+ const oldIndex = Number(active.id);
19063
+ const newIndex = Number(over.id);
19064
+ if (Number.isNaN(oldIndex) || Number.isNaN(newIndex)) return;
19065
+ const order = (0, import_sortable.arrayMove)(
19066
+ outline.sections.map((_, i) => i),
19067
+ oldIndex,
19068
+ newIndex
19069
+ );
19070
+ void reorderOutlineSections(order);
19071
+ };
18959
19072
  const toggleSectionApproved = async (index) => {
18960
19073
  if (!outline || !Array.isArray(outline.sections) || rowBusyIndex !== null) return;
18961
19074
  const sections = outline.sections;
@@ -19150,87 +19263,42 @@ var ResearchReportJobCard = (props) => {
19150
19263
  /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", children: title || "Report outline" }),
19151
19264
  /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("p", { className: "text-xs text-amber-400/90 mt-0.5", children: [
19152
19265
  "Review the outline",
19153
- sections.length > 0 ? " \u2014 edit any heading" : "",
19266
+ sections.length > 0 ? " \u2014 edit any heading, drag to reorder" : "",
19154
19267
  ", then build the full report."
19155
19268
  ] })
19156
19269
  ] })
19157
19270
  ] }),
19158
19271
  /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { className: "mt-4 space-y-2", children: [
19159
- sections.map((s, i) => {
19160
- const rowBusy = building || rowBusyIndex === i;
19161
- return /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)(
19162
- "div",
19163
- {
19164
- className: cn(
19165
- "rounded-xl border bg-zinc-800/40 p-3 transition-colors",
19166
- s.approved ? "border-emerald-700/40" : "border-zinc-700/60"
19167
- ),
19168
- children: [
19169
- /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { className: "flex items-start gap-2.5", children: [
19170
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19171
- "span",
19172
- {
19173
- className: cn(
19174
- "flex-shrink-0 mt-1 w-5 h-5 rounded-full flex items-center justify-center text-[10px] font-semibold tabular-nums",
19175
- s.approved ? "bg-emerald-500/15 text-emerald-300" : "bg-zinc-700/70 text-zinc-400"
19176
- ),
19177
- children: i + 1
19178
- }
19179
- ),
19180
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19181
- "input",
19182
- {
19183
- value: headingEdits[i] ?? s.heading ?? "",
19184
- onChange: (e) => setHeadingEdits((prev) => ({ ...prev, [i]: e.target.value })),
19185
- disabled: building,
19186
- placeholder: "Section heading",
19187
- className: "flex-1 min-w-0 bg-transparent text-sm text-zinc-100 placeholder:text-zinc-600 outline-none disabled:opacity-60"
19188
- }
19189
- ),
19190
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19191
- "button",
19192
- {
19193
- type: "button",
19194
- onClick: () => toggleSectionApproved(i),
19195
- disabled: rowBusy,
19196
- title: s.approved ? "Marked reviewed" : "Mark as reviewed",
19197
- className: cn(
19198
- "w-7 h-7 flex-shrink-0 flex items-center justify-center rounded-md border disabled:opacity-40",
19199
- s.approved ? "border-emerald-600/50 bg-emerald-950/40 text-emerald-300" : "border-zinc-700 text-zinc-500 hover:text-zinc-300 hover:border-zinc-500"
19200
- ),
19201
- children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(CheckIcon, {})
19202
- }
19203
- )
19204
- ] }),
19205
- /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { className: "flex items-center justify-end gap-1 mt-2 pl-[30px]", children: [
19206
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19207
- "button",
19208
- {
19209
- type: "button",
19210
- onClick: () => moveOutlineSection(i, -1),
19211
- disabled: rowBusy || i === 0,
19212
- title: "Move up",
19213
- className: "w-6 h-6 flex items-center justify-center rounded-md text-zinc-500 hover:text-zinc-200 hover:bg-zinc-700/60 disabled:opacity-30 disabled:hover:bg-transparent",
19214
- children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(ChevronUpIcon, {})
19215
- }
19216
- ),
19217
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19218
- "button",
19219
- {
19220
- type: "button",
19221
- onClick: () => moveOutlineSection(i, 1),
19222
- disabled: rowBusy || i === sections.length - 1,
19223
- title: "Move down",
19224
- className: "w-6 h-6 flex items-center justify-center rounded-md text-zinc-500 hover:text-zinc-200 hover:bg-zinc-700/60 disabled:opacity-30 disabled:hover:bg-transparent",
19225
- children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(ChevronDownIcon, {})
19226
- }
19227
- )
19228
- ] })
19229
- ]
19230
- },
19231
- i
19232
- );
19233
- }),
19272
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19273
+ import_core.DndContext,
19274
+ {
19275
+ sensors,
19276
+ collisionDetection: outlineCollisionDetection,
19277
+ onDragEnd: handleOutlineDragEnd,
19278
+ children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19279
+ import_sortable.SortableContext,
19280
+ {
19281
+ items: sections.map((_, i) => String(i)),
19282
+ strategy: import_sortable.verticalListSortingStrategy,
19283
+ children: sections.map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
19284
+ OutlineSectionRow,
19285
+ {
19286
+ index: i,
19287
+ section: s,
19288
+ headingValue: headingEdits[i] ?? s.heading ?? "",
19289
+ subHeadingValue: subHeadingEdits[i] ?? s.sub_heading ?? "",
19290
+ onHeadingChange: (v) => setHeadingEdits((prev) => ({ ...prev, [i]: v })),
19291
+ onSubHeadingChange: (v) => setSubHeadingEdits((prev) => ({ ...prev, [i]: v })),
19292
+ onToggleApproved: () => toggleSectionApproved(i),
19293
+ disabled: building || reordering,
19294
+ rowBusy: building || rowBusyIndex === i
19295
+ },
19296
+ i
19297
+ ))
19298
+ }
19299
+ )
19300
+ }
19301
+ ),
19234
19302
  sections.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("p", { className: "text-xs text-zinc-500", children: "No outline sections were returned; you can still build the report." })
19235
19303
  ] }),
19236
19304
  rowError && /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("p", { className: "mt-2 text-xs text-red-400/90", children: rowError }),