pxengine 0.1.115 → 0.1.117
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 +346 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.mjs +346 -35
- package/dist/index.mjs.map +1 -1
- package/dist/registry.json +31 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -3556,6 +3556,10 @@ interface DeckOutlineSlide {
|
|
|
3556
3556
|
n?: number;
|
|
3557
3557
|
type?: string;
|
|
3558
3558
|
message?: string;
|
|
3559
|
+
/** Informational review flag (DEV-194) — never gates Approve & Build. */
|
|
3560
|
+
approved?: boolean;
|
|
3561
|
+
/** Per-slide design template override (DEV-194) — unset means "inherit the deck's template". */
|
|
3562
|
+
template_id?: string;
|
|
3559
3563
|
[key: string]: unknown;
|
|
3560
3564
|
}
|
|
3561
3565
|
/** The planned deck outline (deck_plan) shown for approval before rendering. */
|
|
@@ -3633,6 +3637,30 @@ interface PresentationJobCardProps {
|
|
|
3633
3637
|
* `/api/presentations/{job_id}/approve-outline`. Proceeds to render the deck.
|
|
3634
3638
|
*/
|
|
3635
3639
|
approveOutlineUrl?: string;
|
|
3640
|
+
/**
|
|
3641
|
+
* Reorder-slides endpoint (POST), DEV-194. Defaults to
|
|
3642
|
+
* `/api/presentations/{job_id}/outline/reorder-slides`. Called from the
|
|
3643
|
+
* outline-review phase's move-up/move-down controls.
|
|
3644
|
+
*/
|
|
3645
|
+
reorderSlidesUrl?: string;
|
|
3646
|
+
/**
|
|
3647
|
+
* Approve-slide endpoint (POST), DEV-194. Defaults to
|
|
3648
|
+
* `/api/presentations/{job_id}/outline/approve-slide`. Informational only —
|
|
3649
|
+
* never gates the whole-outline Approve & Build action.
|
|
3650
|
+
*/
|
|
3651
|
+
approveSlideUrl?: string;
|
|
3652
|
+
/**
|
|
3653
|
+
* Set-slide-template endpoint (POST), DEV-194 "slide-level design
|
|
3654
|
+
* templates". Defaults to `/api/presentations/{job_id}/outline/set-slide-template`.
|
|
3655
|
+
* Gives one outline slide its own design template, overriding the deck's
|
|
3656
|
+
* overall template for just that slide.
|
|
3657
|
+
*/
|
|
3658
|
+
setSlideTemplateUrl?: string;
|
|
3659
|
+
/**
|
|
3660
|
+
* Templates list endpoint (GET), used to populate the per-slide template
|
|
3661
|
+
* override <select>. Defaults to `/api/presentations/templates`.
|
|
3662
|
+
*/
|
|
3663
|
+
templatesUrl?: string;
|
|
3636
3664
|
/** Regenerate endpoint (POST). Defaults to `/api/presentations/{job_id}/regenerate`. */
|
|
3637
3665
|
regenerateUrl?: string;
|
|
3638
3666
|
/**
|
|
@@ -3671,6 +3699,8 @@ interface ReportOutlineSection {
|
|
|
3671
3699
|
heading?: string;
|
|
3672
3700
|
body?: string;
|
|
3673
3701
|
takeaway?: string;
|
|
3702
|
+
/** Informational review flag (DEV-194) — never gates Approve & Build. */
|
|
3703
|
+
approved?: boolean;
|
|
3674
3704
|
[key: string]: unknown;
|
|
3675
3705
|
}
|
|
3676
3706
|
/** The planned report outline (report_data) shown for approval. */
|
|
@@ -3765,6 +3795,18 @@ interface ResearchReportJobCardProps {
|
|
|
3765
3795
|
* phase to proceed to rendering the full report.
|
|
3766
3796
|
*/
|
|
3767
3797
|
approveOutlineUrl?: string;
|
|
3798
|
+
/**
|
|
3799
|
+
* Reorder-sections endpoint (POST), DEV-194. Defaults to
|
|
3800
|
+
* `/api/reports/{job_id}/outline/reorder-sections`. Called from the
|
|
3801
|
+
* outline-review phase's move-up/move-down controls.
|
|
3802
|
+
*/
|
|
3803
|
+
reorderSectionsUrl?: string;
|
|
3804
|
+
/**
|
|
3805
|
+
* Approve-section endpoint (POST), DEV-194. Defaults to
|
|
3806
|
+
* `/api/reports/{job_id}/outline/approve-section`. Informational only —
|
|
3807
|
+
* never gates the whole-outline Approve & Build action.
|
|
3808
|
+
*/
|
|
3809
|
+
approveSectionUrl?: string;
|
|
3768
3810
|
/** Regenerate endpoint (POST). Defaults to `/api/reports/{job_id}/regenerate`. */
|
|
3769
3811
|
regenerateUrl?: string;
|
|
3770
3812
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -3556,6 +3556,10 @@ interface DeckOutlineSlide {
|
|
|
3556
3556
|
n?: number;
|
|
3557
3557
|
type?: string;
|
|
3558
3558
|
message?: string;
|
|
3559
|
+
/** Informational review flag (DEV-194) — never gates Approve & Build. */
|
|
3560
|
+
approved?: boolean;
|
|
3561
|
+
/** Per-slide design template override (DEV-194) — unset means "inherit the deck's template". */
|
|
3562
|
+
template_id?: string;
|
|
3559
3563
|
[key: string]: unknown;
|
|
3560
3564
|
}
|
|
3561
3565
|
/** The planned deck outline (deck_plan) shown for approval before rendering. */
|
|
@@ -3633,6 +3637,30 @@ interface PresentationJobCardProps {
|
|
|
3633
3637
|
* `/api/presentations/{job_id}/approve-outline`. Proceeds to render the deck.
|
|
3634
3638
|
*/
|
|
3635
3639
|
approveOutlineUrl?: string;
|
|
3640
|
+
/**
|
|
3641
|
+
* Reorder-slides endpoint (POST), DEV-194. Defaults to
|
|
3642
|
+
* `/api/presentations/{job_id}/outline/reorder-slides`. Called from the
|
|
3643
|
+
* outline-review phase's move-up/move-down controls.
|
|
3644
|
+
*/
|
|
3645
|
+
reorderSlidesUrl?: string;
|
|
3646
|
+
/**
|
|
3647
|
+
* Approve-slide endpoint (POST), DEV-194. Defaults to
|
|
3648
|
+
* `/api/presentations/{job_id}/outline/approve-slide`. Informational only —
|
|
3649
|
+
* never gates the whole-outline Approve & Build action.
|
|
3650
|
+
*/
|
|
3651
|
+
approveSlideUrl?: string;
|
|
3652
|
+
/**
|
|
3653
|
+
* Set-slide-template endpoint (POST), DEV-194 "slide-level design
|
|
3654
|
+
* templates". Defaults to `/api/presentations/{job_id}/outline/set-slide-template`.
|
|
3655
|
+
* Gives one outline slide its own design template, overriding the deck's
|
|
3656
|
+
* overall template for just that slide.
|
|
3657
|
+
*/
|
|
3658
|
+
setSlideTemplateUrl?: string;
|
|
3659
|
+
/**
|
|
3660
|
+
* Templates list endpoint (GET), used to populate the per-slide template
|
|
3661
|
+
* override <select>. Defaults to `/api/presentations/templates`.
|
|
3662
|
+
*/
|
|
3663
|
+
templatesUrl?: string;
|
|
3636
3664
|
/** Regenerate endpoint (POST). Defaults to `/api/presentations/{job_id}/regenerate`. */
|
|
3637
3665
|
regenerateUrl?: string;
|
|
3638
3666
|
/**
|
|
@@ -3671,6 +3699,8 @@ interface ReportOutlineSection {
|
|
|
3671
3699
|
heading?: string;
|
|
3672
3700
|
body?: string;
|
|
3673
3701
|
takeaway?: string;
|
|
3702
|
+
/** Informational review flag (DEV-194) — never gates Approve & Build. */
|
|
3703
|
+
approved?: boolean;
|
|
3674
3704
|
[key: string]: unknown;
|
|
3675
3705
|
}
|
|
3676
3706
|
/** The planned report outline (report_data) shown for approval. */
|
|
@@ -3765,6 +3795,18 @@ interface ResearchReportJobCardProps {
|
|
|
3765
3795
|
* phase to proceed to rendering the full report.
|
|
3766
3796
|
*/
|
|
3767
3797
|
approveOutlineUrl?: string;
|
|
3798
|
+
/**
|
|
3799
|
+
* Reorder-sections endpoint (POST), DEV-194. Defaults to
|
|
3800
|
+
* `/api/reports/{job_id}/outline/reorder-sections`. Called from the
|
|
3801
|
+
* outline-review phase's move-up/move-down controls.
|
|
3802
|
+
*/
|
|
3803
|
+
reorderSectionsUrl?: string;
|
|
3804
|
+
/**
|
|
3805
|
+
* Approve-section endpoint (POST), DEV-194. Defaults to
|
|
3806
|
+
* `/api/reports/{job_id}/outline/approve-section`. Informational only —
|
|
3807
|
+
* never gates the whole-outline Approve & Build action.
|
|
3808
|
+
*/
|
|
3809
|
+
approveSectionUrl?: string;
|
|
3768
3810
|
/** Regenerate endpoint (POST). Defaults to `/api/reports/{job_id}/regenerate`. */
|
|
3769
3811
|
regenerateUrl?: string;
|
|
3770
3812
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -15801,6 +15801,8 @@ var SlideTypeIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "14", height:
|
|
|
15801
15801
|
/* @__PURE__ */ jsx147("rect", { x: "3", y: "4", width: "18", height: "14", rx: "2" }),
|
|
15802
15802
|
/* @__PURE__ */ jsx147("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
|
|
15803
15803
|
] });
|
|
15804
|
+
var ChevronUpIcon = () => /* @__PURE__ */ jsx147("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx147("polyline", { points: "18 15 12 9 6 15" }) });
|
|
15805
|
+
var ChevronDownIcon = () => /* @__PURE__ */ jsx147("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx147("polyline", { points: "6 9 12 15 18 9" }) });
|
|
15804
15806
|
function formatTemplateLabel(templateId) {
|
|
15805
15807
|
if (!templateId) return null;
|
|
15806
15808
|
return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
@@ -16026,6 +16028,10 @@ var PresentationJobCard = ({
|
|
|
16026
16028
|
shareUrl,
|
|
16027
16029
|
approveUrl,
|
|
16028
16030
|
approveOutlineUrl,
|
|
16031
|
+
reorderSlidesUrl,
|
|
16032
|
+
approveSlideUrl,
|
|
16033
|
+
setSlideTemplateUrl,
|
|
16034
|
+
templatesUrl,
|
|
16029
16035
|
regenerateUrl,
|
|
16030
16036
|
hideApproval = false,
|
|
16031
16037
|
className,
|
|
@@ -16048,6 +16054,7 @@ var PresentationJobCard = ({
|
|
|
16048
16054
|
const [, setTemplateVersionId] = useState10(initialTemplateVersionId || "");
|
|
16049
16055
|
const [reviewStatus, setReviewStatus] = useState10(initialReviewStatus || "");
|
|
16050
16056
|
const [outline, setOutline] = useState10(initialOutline);
|
|
16057
|
+
const [slideTemplateOptions, setSlideTemplateOptions] = useState10(null);
|
|
16051
16058
|
const [showExport, setShowExport] = useState10(false);
|
|
16052
16059
|
const [showFullscreen, setShowFullscreen] = useState10(false);
|
|
16053
16060
|
const [copied, setCopied] = useState10(false);
|
|
@@ -16057,6 +16064,8 @@ var PresentationJobCard = ({
|
|
|
16057
16064
|
const [messageEdits, setMessageEdits] = useState10({});
|
|
16058
16065
|
const [approvingOutline, setApprovingOutline] = useState10(false);
|
|
16059
16066
|
const [outlineWritePollUrl, setOutlineWritePollUrl] = useState10(null);
|
|
16067
|
+
const [rowBusyIndex, setRowBusyIndex] = useState10(null);
|
|
16068
|
+
const [rowError, setRowError] = useState10(null);
|
|
16060
16069
|
const [regenPollUrl, setRegenPollUrl] = useState10(null);
|
|
16061
16070
|
const [currentSlide, setCurrentSlide] = useState10(1);
|
|
16062
16071
|
const [previewScale, setPreviewScale] = useState10(1);
|
|
@@ -16100,6 +16109,33 @@ var PresentationJobCard = ({
|
|
|
16100
16109
|
useEffect7(() => {
|
|
16101
16110
|
if (initialOutline) setOutline(initialOutline);
|
|
16102
16111
|
}, [initialOutlineSlideCount]);
|
|
16112
|
+
useEffect7(() => {
|
|
16113
|
+
if (reviewStatus !== "pending_outline_approval" || slideTemplateOptions !== null) return;
|
|
16114
|
+
let cancelled = false;
|
|
16115
|
+
(async () => {
|
|
16116
|
+
try {
|
|
16117
|
+
const endpoint = templatesUrl || "/api/presentations/templates";
|
|
16118
|
+
const headers = {};
|
|
16119
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
16120
|
+
const res = await fetch(endpoint, { headers });
|
|
16121
|
+
if (!res.ok) throw new Error(`Templates fetch failed (${res.status})`);
|
|
16122
|
+
const list = await res.json();
|
|
16123
|
+
if (!cancelled && Array.isArray(list)) {
|
|
16124
|
+
setSlideTemplateOptions(
|
|
16125
|
+
list.map((t2) => ({
|
|
16126
|
+
id: t2.template_id || t2.id || "",
|
|
16127
|
+
name: t2.name || t2.template_id || t2.id || ""
|
|
16128
|
+
}))
|
|
16129
|
+
);
|
|
16130
|
+
}
|
|
16131
|
+
} catch {
|
|
16132
|
+
if (!cancelled) setSlideTemplateOptions([]);
|
|
16133
|
+
}
|
|
16134
|
+
})();
|
|
16135
|
+
return () => {
|
|
16136
|
+
cancelled = true;
|
|
16137
|
+
};
|
|
16138
|
+
}, [reviewStatus, slideTemplateOptions, templatesUrl, authToken]);
|
|
16103
16139
|
const updateScale = useCallback4(() => {
|
|
16104
16140
|
if (previewRef.current) setPreviewScale(previewRef.current.offsetWidth / 1280);
|
|
16105
16141
|
}, []);
|
|
@@ -16289,6 +16325,111 @@ var PresentationJobCard = ({
|
|
|
16289
16325
|
});
|
|
16290
16326
|
return changed ? { ...outline, slides } : void 0;
|
|
16291
16327
|
};
|
|
16328
|
+
const moveOutlineSlide = async (index, delta) => {
|
|
16329
|
+
if (!outline || !Array.isArray(outline.slides) || rowBusyIndex !== null) return;
|
|
16330
|
+
const slides = outline.slides;
|
|
16331
|
+
const target = index + delta;
|
|
16332
|
+
if (target < 0 || target >= slides.length) return;
|
|
16333
|
+
const order = slides.map((_, i) => i);
|
|
16334
|
+
[order[index], order[target]] = [order[target], order[index]];
|
|
16335
|
+
const reordered = order.map((i, newIndex) => ({ ...slides[i], n: newIndex + 1 }));
|
|
16336
|
+
const previousOutline = outline;
|
|
16337
|
+
const previousEdits = messageEdits;
|
|
16338
|
+
setOutline({ ...outline, slides: reordered });
|
|
16339
|
+
setMessageEdits((prev) => {
|
|
16340
|
+
const remapped = {};
|
|
16341
|
+
order.forEach((originalIndex, newIndex) => {
|
|
16342
|
+
if (prev[originalIndex] !== void 0) remapped[newIndex] = prev[originalIndex];
|
|
16343
|
+
});
|
|
16344
|
+
return remapped;
|
|
16345
|
+
});
|
|
16346
|
+
setRowBusyIndex(index);
|
|
16347
|
+
setRowError(null);
|
|
16348
|
+
try {
|
|
16349
|
+
const endpoint = reorderSlidesUrl || `/api/presentations/${_job_id}/outline/reorder-slides`;
|
|
16350
|
+
const headers = { "Content-Type": "application/json" };
|
|
16351
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
16352
|
+
const res = await fetch(endpoint, {
|
|
16353
|
+
method: "POST",
|
|
16354
|
+
headers,
|
|
16355
|
+
body: JSON.stringify({ order })
|
|
16356
|
+
});
|
|
16357
|
+
if (!res.ok) {
|
|
16358
|
+
const err = await res.json().catch(() => ({}));
|
|
16359
|
+
throw new Error(err.detail || err.error || `Reorder failed (${res.status})`);
|
|
16360
|
+
}
|
|
16361
|
+
} catch (e) {
|
|
16362
|
+
setOutline(previousOutline);
|
|
16363
|
+
setMessageEdits(previousEdits);
|
|
16364
|
+
setRowError(e instanceof Error ? e.message : "Could not reorder slides");
|
|
16365
|
+
} finally {
|
|
16366
|
+
setRowBusyIndex(null);
|
|
16367
|
+
}
|
|
16368
|
+
};
|
|
16369
|
+
const toggleSlideApproved = async (index) => {
|
|
16370
|
+
if (!outline || !Array.isArray(outline.slides) || rowBusyIndex !== null) return;
|
|
16371
|
+
const slides = outline.slides;
|
|
16372
|
+
const nextApproved = !slides[index]?.approved;
|
|
16373
|
+
const previousOutline = outline;
|
|
16374
|
+
const updated = slides.map((s, i) => i === index ? { ...s, approved: nextApproved } : s);
|
|
16375
|
+
setOutline({ ...outline, slides: updated });
|
|
16376
|
+
setRowBusyIndex(index);
|
|
16377
|
+
setRowError(null);
|
|
16378
|
+
try {
|
|
16379
|
+
const endpoint = approveSlideUrl || `/api/presentations/${_job_id}/outline/approve-slide`;
|
|
16380
|
+
const headers = { "Content-Type": "application/json" };
|
|
16381
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
16382
|
+
const res = await fetch(endpoint, {
|
|
16383
|
+
method: "POST",
|
|
16384
|
+
headers,
|
|
16385
|
+
body: JSON.stringify({ slide_index: index, approved: nextApproved })
|
|
16386
|
+
});
|
|
16387
|
+
if (!res.ok) {
|
|
16388
|
+
const err = await res.json().catch(() => ({}));
|
|
16389
|
+
throw new Error(err.detail || err.error || `Approve failed (${res.status})`);
|
|
16390
|
+
}
|
|
16391
|
+
} catch (e) {
|
|
16392
|
+
setOutline(previousOutline);
|
|
16393
|
+
setRowError(e instanceof Error ? e.message : "Could not update slide");
|
|
16394
|
+
} finally {
|
|
16395
|
+
setRowBusyIndex(null);
|
|
16396
|
+
}
|
|
16397
|
+
};
|
|
16398
|
+
const setSlideTemplate = async (index, templateId2) => {
|
|
16399
|
+
if (!outline || !Array.isArray(outline.slides) || rowBusyIndex !== null) return;
|
|
16400
|
+
const slides = outline.slides;
|
|
16401
|
+
const previousOutline = outline;
|
|
16402
|
+
const updated = slides.map((s, i) => {
|
|
16403
|
+
if (i !== index) return s;
|
|
16404
|
+
if (!templateId2) {
|
|
16405
|
+
const { template_id: _drop, ...rest } = s;
|
|
16406
|
+
return rest;
|
|
16407
|
+
}
|
|
16408
|
+
return { ...s, template_id: templateId2 };
|
|
16409
|
+
});
|
|
16410
|
+
setOutline({ ...outline, slides: updated });
|
|
16411
|
+
setRowBusyIndex(index);
|
|
16412
|
+
setRowError(null);
|
|
16413
|
+
try {
|
|
16414
|
+
const endpoint = setSlideTemplateUrl || `/api/presentations/${_job_id}/outline/set-slide-template`;
|
|
16415
|
+
const headers = { "Content-Type": "application/json" };
|
|
16416
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
16417
|
+
const res = await fetch(endpoint, {
|
|
16418
|
+
method: "POST",
|
|
16419
|
+
headers,
|
|
16420
|
+
body: JSON.stringify({ slide_index: index, template_id: templateId2 || null })
|
|
16421
|
+
});
|
|
16422
|
+
if (!res.ok) {
|
|
16423
|
+
const err = await res.json().catch(() => ({}));
|
|
16424
|
+
throw new Error(err.detail || err.error || `Template update failed (${res.status})`);
|
|
16425
|
+
}
|
|
16426
|
+
} catch (e) {
|
|
16427
|
+
setOutline(previousOutline);
|
|
16428
|
+
setRowError(e instanceof Error ? e.message : "Could not update slide's template");
|
|
16429
|
+
} finally {
|
|
16430
|
+
setRowBusyIndex(null);
|
|
16431
|
+
}
|
|
16432
|
+
};
|
|
16292
16433
|
const handleApproveOutline = async () => {
|
|
16293
16434
|
if (!_job_id || approvingOutline) return;
|
|
16294
16435
|
const endpoint = approveOutlineUrl || `/api/presentations/${_job_id}/approve-outline`;
|
|
@@ -16526,31 +16667,85 @@ var PresentationJobCard = ({
|
|
|
16526
16667
|
] })
|
|
16527
16668
|
] }),
|
|
16528
16669
|
/* @__PURE__ */ jsxs108("div", { className: "mt-4 space-y-2", children: [
|
|
16529
|
-
slides.map((s, i) =>
|
|
16530
|
-
|
|
16531
|
-
/* @__PURE__ */ jsxs108(
|
|
16532
|
-
"span",
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16545
|
-
|
|
16546
|
-
|
|
16547
|
-
|
|
16548
|
-
|
|
16549
|
-
|
|
16550
|
-
|
|
16551
|
-
|
|
16670
|
+
slides.map((s, i) => {
|
|
16671
|
+
const rowBusy = building || rowBusyIndex === i;
|
|
16672
|
+
return /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-1.5", children: [
|
|
16673
|
+
/* @__PURE__ */ jsx147("span", { className: "text-xs text-zinc-600 w-5 text-right tabular-nums flex-shrink-0", children: s.n ?? i + 1 }),
|
|
16674
|
+
/* @__PURE__ */ jsxs108(
|
|
16675
|
+
"span",
|
|
16676
|
+
{
|
|
16677
|
+
className: "flex items-center gap-1 text-[10px] uppercase tracking-wide text-zinc-500 w-20 flex-shrink-0 truncate",
|
|
16678
|
+
title: s.type,
|
|
16679
|
+
children: [
|
|
16680
|
+
/* @__PURE__ */ jsx147(SlideTypeIcon, {}),
|
|
16681
|
+
s.type || "slide"
|
|
16682
|
+
]
|
|
16683
|
+
}
|
|
16684
|
+
),
|
|
16685
|
+
slideTemplateOptions && slideTemplateOptions.length > 0 && /* @__PURE__ */ jsxs108(
|
|
16686
|
+
"select",
|
|
16687
|
+
{
|
|
16688
|
+
value: s.template_id || "",
|
|
16689
|
+
onChange: (e) => setSlideTemplate(i, e.target.value),
|
|
16690
|
+
disabled: rowBusy,
|
|
16691
|
+
title: "Design template for this slide only (default: deck's template)",
|
|
16692
|
+
className: "w-24 flex-shrink-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-1.5 h-8 text-[10px] text-zinc-300 focus:border-indigo-500 outline-none disabled:opacity-60",
|
|
16693
|
+
children: [
|
|
16694
|
+
/* @__PURE__ */ jsx147("option", { value: "", children: "Deck default" }),
|
|
16695
|
+
slideTemplateOptions.map((opt) => /* @__PURE__ */ jsx147("option", { value: opt.id, children: opt.name }, opt.id))
|
|
16696
|
+
]
|
|
16697
|
+
}
|
|
16698
|
+
),
|
|
16699
|
+
/* @__PURE__ */ jsx147(
|
|
16700
|
+
"input",
|
|
16701
|
+
{
|
|
16702
|
+
value: messageEdits[i] ?? s.message ?? "",
|
|
16703
|
+
onChange: (e) => setMessageEdits((prev) => ({ ...prev, [i]: e.target.value })),
|
|
16704
|
+
disabled: building,
|
|
16705
|
+
className: "flex-1 min-w-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-3 h-8 text-xs text-zinc-200 focus:border-indigo-500 outline-none disabled:opacity-60"
|
|
16706
|
+
}
|
|
16707
|
+
),
|
|
16708
|
+
/* @__PURE__ */ jsx147(
|
|
16709
|
+
"button",
|
|
16710
|
+
{
|
|
16711
|
+
type: "button",
|
|
16712
|
+
onClick: () => moveOutlineSlide(i, -1),
|
|
16713
|
+
disabled: rowBusy || i === 0,
|
|
16714
|
+
title: "Move up",
|
|
16715
|
+
className: "w-7 h-7 flex items-center justify-center rounded-md border border-zinc-700 text-zinc-400 hover:text-zinc-100 hover:border-zinc-500 disabled:opacity-30 disabled:hover:text-zinc-400 disabled:hover:border-zinc-700 flex-shrink-0",
|
|
16716
|
+
children: /* @__PURE__ */ jsx147(ChevronUpIcon, {})
|
|
16717
|
+
}
|
|
16718
|
+
),
|
|
16719
|
+
/* @__PURE__ */ jsx147(
|
|
16720
|
+
"button",
|
|
16721
|
+
{
|
|
16722
|
+
type: "button",
|
|
16723
|
+
onClick: () => moveOutlineSlide(i, 1),
|
|
16724
|
+
disabled: rowBusy || i === slides.length - 1,
|
|
16725
|
+
title: "Move down",
|
|
16726
|
+
className: "w-7 h-7 flex items-center justify-center rounded-md border border-zinc-700 text-zinc-400 hover:text-zinc-100 hover:border-zinc-500 disabled:opacity-30 disabled:hover:text-zinc-400 disabled:hover:border-zinc-700 flex-shrink-0",
|
|
16727
|
+
children: /* @__PURE__ */ jsx147(ChevronDownIcon, {})
|
|
16728
|
+
}
|
|
16729
|
+
),
|
|
16730
|
+
/* @__PURE__ */ jsx147(
|
|
16731
|
+
"button",
|
|
16732
|
+
{
|
|
16733
|
+
type: "button",
|
|
16734
|
+
onClick: () => toggleSlideApproved(i),
|
|
16735
|
+
disabled: rowBusy,
|
|
16736
|
+
title: s.approved ? "Marked reviewed" : "Mark as reviewed",
|
|
16737
|
+
className: cn(
|
|
16738
|
+
"w-7 h-7 flex items-center justify-center rounded-md border flex-shrink-0 disabled:opacity-40",
|
|
16739
|
+
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"
|
|
16740
|
+
),
|
|
16741
|
+
children: /* @__PURE__ */ jsx147(CheckIcon, {})
|
|
16742
|
+
}
|
|
16743
|
+
)
|
|
16744
|
+
] }, i);
|
|
16745
|
+
}),
|
|
16552
16746
|
slides.length === 0 && /* @__PURE__ */ jsx147("p", { className: "text-xs text-zinc-500", children: "No outline slides were returned; you can still build the deck." })
|
|
16553
16747
|
] }),
|
|
16748
|
+
rowError && /* @__PURE__ */ jsx147("p", { className: "mt-2 text-xs text-red-400/90", children: rowError }),
|
|
16554
16749
|
approveError && /* @__PURE__ */ jsx147("p", { className: "mt-3 text-xs text-red-400/90", children: approveError }),
|
|
16555
16750
|
/* @__PURE__ */ jsx147("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs108(
|
|
16556
16751
|
"button",
|
|
@@ -16800,6 +16995,8 @@ var ShareIcon2 = () => /* @__PURE__ */ jsxs109("svg", { width: "14", height: "14
|
|
|
16800
16995
|
/* @__PURE__ */ jsx148("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
16801
16996
|
] });
|
|
16802
16997
|
var CheckIcon2 = () => /* @__PURE__ */ jsx148("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx148("polyline", { points: "20 6 9 17 4 12" }) });
|
|
16998
|
+
var ChevronUpIcon2 = () => /* @__PURE__ */ jsx148("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx148("polyline", { points: "18 15 12 9 6 15" }) });
|
|
16999
|
+
var ChevronDownIcon2 = () => /* @__PURE__ */ jsx148("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx148("polyline", { points: "6 9 12 15 18 9" }) });
|
|
16803
17000
|
var RefreshIcon2 = () => /* @__PURE__ */ jsxs109("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
16804
17001
|
/* @__PURE__ */ jsx148("polyline", { points: "23 4 23 10 17 10" }),
|
|
16805
17002
|
/* @__PURE__ */ jsx148("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
|
|
@@ -16882,6 +17079,8 @@ var ResearchReportJobCard = (props) => {
|
|
|
16882
17079
|
shareUrl,
|
|
16883
17080
|
approveUrl,
|
|
16884
17081
|
approveOutlineUrl,
|
|
17082
|
+
reorderSectionsUrl,
|
|
17083
|
+
approveSectionUrl,
|
|
16885
17084
|
regenerateUrl,
|
|
16886
17085
|
hideApproval = false,
|
|
16887
17086
|
className,
|
|
@@ -16919,6 +17118,8 @@ var ResearchReportJobCard = (props) => {
|
|
|
16919
17118
|
const [approveError, setApproveError] = useState11(null);
|
|
16920
17119
|
const [headingEdits, setHeadingEdits] = useState11({});
|
|
16921
17120
|
const [approvingOutline, setApprovingOutline] = useState11(false);
|
|
17121
|
+
const [rowBusyIndex, setRowBusyIndex] = useState11(null);
|
|
17122
|
+
const [rowError, setRowError] = useState11(null);
|
|
16922
17123
|
const [outlineWritePollUrl, setOutlineWritePollUrl] = useState11(null);
|
|
16923
17124
|
const [regenPollUrl, setRegenPollUrl] = useState11(null);
|
|
16924
17125
|
const previewRef = useRef7(null);
|
|
@@ -17174,6 +17375,76 @@ var ResearchReportJobCard = (props) => {
|
|
|
17174
17375
|
});
|
|
17175
17376
|
return changed ? { ...outline, sections } : void 0;
|
|
17176
17377
|
};
|
|
17378
|
+
const moveOutlineSection = async (index, delta) => {
|
|
17379
|
+
if (!outline || !Array.isArray(outline.sections) || rowBusyIndex !== null) return;
|
|
17380
|
+
const sections = outline.sections;
|
|
17381
|
+
const target = index + delta;
|
|
17382
|
+
if (target < 0 || target >= sections.length) return;
|
|
17383
|
+
const order = sections.map((_, i) => i);
|
|
17384
|
+
[order[index], order[target]] = [order[target], order[index]];
|
|
17385
|
+
const reordered = order.map((i) => sections[i]);
|
|
17386
|
+
const previousOutline = outline;
|
|
17387
|
+
const previousEdits = headingEdits;
|
|
17388
|
+
setOutline({ ...outline, sections: reordered });
|
|
17389
|
+
setHeadingEdits((prev) => {
|
|
17390
|
+
const remapped = {};
|
|
17391
|
+
order.forEach((originalIndex, newIndex) => {
|
|
17392
|
+
if (prev[originalIndex] !== void 0) remapped[newIndex] = prev[originalIndex];
|
|
17393
|
+
});
|
|
17394
|
+
return remapped;
|
|
17395
|
+
});
|
|
17396
|
+
setRowBusyIndex(index);
|
|
17397
|
+
setRowError(null);
|
|
17398
|
+
try {
|
|
17399
|
+
const endpoint = reorderSectionsUrl || `/api/reports/${job_id}/outline/reorder-sections`;
|
|
17400
|
+
const headers = { "Content-Type": "application/json" };
|
|
17401
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
17402
|
+
const res = await fetch(endpoint, {
|
|
17403
|
+
method: "POST",
|
|
17404
|
+
headers,
|
|
17405
|
+
body: JSON.stringify({ order })
|
|
17406
|
+
});
|
|
17407
|
+
if (!res.ok) {
|
|
17408
|
+
const err = await res.json().catch(() => ({}));
|
|
17409
|
+
throw new Error(err.detail || err.error || `Reorder failed (${res.status})`);
|
|
17410
|
+
}
|
|
17411
|
+
} catch (e) {
|
|
17412
|
+
setOutline(previousOutline);
|
|
17413
|
+
setHeadingEdits(previousEdits);
|
|
17414
|
+
setRowError(e instanceof Error ? e.message : "Could not reorder sections");
|
|
17415
|
+
} finally {
|
|
17416
|
+
setRowBusyIndex(null);
|
|
17417
|
+
}
|
|
17418
|
+
};
|
|
17419
|
+
const toggleSectionApproved = async (index) => {
|
|
17420
|
+
if (!outline || !Array.isArray(outline.sections) || rowBusyIndex !== null) return;
|
|
17421
|
+
const sections = outline.sections;
|
|
17422
|
+
const nextApproved = !sections[index]?.approved;
|
|
17423
|
+
const previousOutline = outline;
|
|
17424
|
+
const updated = sections.map((s, i) => i === index ? { ...s, approved: nextApproved } : s);
|
|
17425
|
+
setOutline({ ...outline, sections: updated });
|
|
17426
|
+
setRowBusyIndex(index);
|
|
17427
|
+
setRowError(null);
|
|
17428
|
+
try {
|
|
17429
|
+
const endpoint = approveSectionUrl || `/api/reports/${job_id}/outline/approve-section`;
|
|
17430
|
+
const headers = { "Content-Type": "application/json" };
|
|
17431
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
17432
|
+
const res = await fetch(endpoint, {
|
|
17433
|
+
method: "POST",
|
|
17434
|
+
headers,
|
|
17435
|
+
body: JSON.stringify({ section_index: index, approved: nextApproved })
|
|
17436
|
+
});
|
|
17437
|
+
if (!res.ok) {
|
|
17438
|
+
const err = await res.json().catch(() => ({}));
|
|
17439
|
+
throw new Error(err.detail || err.error || `Approve failed (${res.status})`);
|
|
17440
|
+
}
|
|
17441
|
+
} catch (e) {
|
|
17442
|
+
setOutline(previousOutline);
|
|
17443
|
+
setRowError(e instanceof Error ? e.message : "Could not update section");
|
|
17444
|
+
} finally {
|
|
17445
|
+
setRowBusyIndex(null);
|
|
17446
|
+
}
|
|
17447
|
+
};
|
|
17177
17448
|
const handleApproveOutline = async () => {
|
|
17178
17449
|
if (!job_id || approvingOutline) return;
|
|
17179
17450
|
const endpoint = approveOutlineUrl || `/api/reports/${job_id}/approve-outline`;
|
|
@@ -17333,20 +17604,60 @@ var ResearchReportJobCard = (props) => {
|
|
|
17333
17604
|
] })
|
|
17334
17605
|
] }),
|
|
17335
17606
|
/* @__PURE__ */ jsxs109("div", { className: "mt-4 space-y-2", children: [
|
|
17336
|
-
sections.map((s, i) =>
|
|
17337
|
-
|
|
17338
|
-
/* @__PURE__ */
|
|
17339
|
-
"
|
|
17340
|
-
|
|
17341
|
-
|
|
17342
|
-
|
|
17343
|
-
|
|
17344
|
-
|
|
17345
|
-
|
|
17346
|
-
|
|
17347
|
-
|
|
17607
|
+
sections.map((s, i) => {
|
|
17608
|
+
const rowBusy = building || rowBusyIndex === i;
|
|
17609
|
+
return /* @__PURE__ */ jsxs109("div", { className: "flex items-center gap-1.5", children: [
|
|
17610
|
+
/* @__PURE__ */ jsx148("span", { className: "text-xs text-zinc-600 w-5 text-right tabular-nums flex-shrink-0", children: i + 1 }),
|
|
17611
|
+
/* @__PURE__ */ jsx148(
|
|
17612
|
+
"input",
|
|
17613
|
+
{
|
|
17614
|
+
value: headingEdits[i] ?? s.heading ?? "",
|
|
17615
|
+
onChange: (e) => setHeadingEdits((prev) => ({ ...prev, [i]: e.target.value })),
|
|
17616
|
+
disabled: building,
|
|
17617
|
+
className: "flex-1 min-w-0 bg-zinc-800/60 border border-zinc-700 rounded-lg px-3 h-8 text-xs text-zinc-200 focus:border-violet-500 outline-none disabled:opacity-60"
|
|
17618
|
+
}
|
|
17619
|
+
),
|
|
17620
|
+
/* @__PURE__ */ jsx148(
|
|
17621
|
+
"button",
|
|
17622
|
+
{
|
|
17623
|
+
type: "button",
|
|
17624
|
+
onClick: () => moveOutlineSection(i, -1),
|
|
17625
|
+
disabled: rowBusy || i === 0,
|
|
17626
|
+
title: "Move up",
|
|
17627
|
+
className: "w-7 h-7 flex items-center justify-center rounded-md border border-zinc-700 text-zinc-400 hover:text-zinc-100 hover:border-zinc-500 disabled:opacity-30 disabled:hover:text-zinc-400 disabled:hover:border-zinc-700 flex-shrink-0",
|
|
17628
|
+
children: /* @__PURE__ */ jsx148(ChevronUpIcon2, {})
|
|
17629
|
+
}
|
|
17630
|
+
),
|
|
17631
|
+
/* @__PURE__ */ jsx148(
|
|
17632
|
+
"button",
|
|
17633
|
+
{
|
|
17634
|
+
type: "button",
|
|
17635
|
+
onClick: () => moveOutlineSection(i, 1),
|
|
17636
|
+
disabled: rowBusy || i === sections.length - 1,
|
|
17637
|
+
title: "Move down",
|
|
17638
|
+
className: "w-7 h-7 flex items-center justify-center rounded-md border border-zinc-700 text-zinc-400 hover:text-zinc-100 hover:border-zinc-500 disabled:opacity-30 disabled:hover:text-zinc-400 disabled:hover:border-zinc-700 flex-shrink-0",
|
|
17639
|
+
children: /* @__PURE__ */ jsx148(ChevronDownIcon2, {})
|
|
17640
|
+
}
|
|
17641
|
+
),
|
|
17642
|
+
/* @__PURE__ */ jsx148(
|
|
17643
|
+
"button",
|
|
17644
|
+
{
|
|
17645
|
+
type: "button",
|
|
17646
|
+
onClick: () => toggleSectionApproved(i),
|
|
17647
|
+
disabled: rowBusy,
|
|
17648
|
+
title: s.approved ? "Marked reviewed" : "Mark as reviewed",
|
|
17649
|
+
className: cn(
|
|
17650
|
+
"w-7 h-7 flex items-center justify-center rounded-md border flex-shrink-0 disabled:opacity-40",
|
|
17651
|
+
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"
|
|
17652
|
+
),
|
|
17653
|
+
children: /* @__PURE__ */ jsx148(CheckIcon2, {})
|
|
17654
|
+
}
|
|
17655
|
+
)
|
|
17656
|
+
] }, i);
|
|
17657
|
+
}),
|
|
17348
17658
|
sections.length === 0 && /* @__PURE__ */ jsx148("p", { className: "text-xs text-zinc-500", children: "No outline sections were returned; you can still build the report." })
|
|
17349
17659
|
] }),
|
|
17660
|
+
rowError && /* @__PURE__ */ jsx148("p", { className: "mt-2 text-xs text-red-400/90", children: rowError }),
|
|
17350
17661
|
approveError && /* @__PURE__ */ jsx148("p", { className: "mt-3 text-xs text-red-400/90", children: approveError }),
|
|
17351
17662
|
/* @__PURE__ */ jsx148("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs109(
|
|
17352
17663
|
"button",
|