pxengine 0.1.113 → 0.1.114
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 +529 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -1
- package/dist/index.d.ts +76 -1
- package/dist/index.mjs +529 -16
- package/dist/index.mjs.map +1 -1
- package/dist/registry.json +62 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -15793,6 +15793,22 @@ var ShareIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "14", height: "14"
|
|
|
15793
15793
|
/* @__PURE__ */ jsx147("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
15794
15794
|
] });
|
|
15795
15795
|
var CheckIcon = () => /* @__PURE__ */ jsx147("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx147("polyline", { points: "20 6 9 17 4 12" }) });
|
|
15796
|
+
var RefreshIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
15797
|
+
/* @__PURE__ */ jsx147("polyline", { points: "23 4 23 10 17 10" }),
|
|
15798
|
+
/* @__PURE__ */ jsx147("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
|
|
15799
|
+
] });
|
|
15800
|
+
var SlideTypeIcon = () => /* @__PURE__ */ jsxs108("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
15801
|
+
/* @__PURE__ */ jsx147("rect", { x: "3", y: "4", width: "18", height: "14", rx: "2" }),
|
|
15802
|
+
/* @__PURE__ */ jsx147("line", { x1: "3", y1: "10", x2: "21", y2: "10" })
|
|
15803
|
+
] });
|
|
15804
|
+
function formatTemplateLabel(templateId) {
|
|
15805
|
+
if (!templateId) return null;
|
|
15806
|
+
return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
15807
|
+
}
|
|
15808
|
+
function deriveJobStatusUrl(newJobId, pollUrl, regenerateUrl) {
|
|
15809
|
+
const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/presentations\/[^/]+\/regenerate.*$/, "") ?? "";
|
|
15810
|
+
return `${base}/api/jobs/${newJobId}/status`;
|
|
15811
|
+
}
|
|
15796
15812
|
var FORMATS = [
|
|
15797
15813
|
{
|
|
15798
15814
|
key: "pptx_url",
|
|
@@ -15998,11 +16014,20 @@ var PresentationJobCard = ({
|
|
|
15998
16014
|
status: initialStatus,
|
|
15999
16015
|
slide_count: initialSlideCount,
|
|
16000
16016
|
formats: initialFormats = {},
|
|
16017
|
+
generation_mode: initialGenerationMode,
|
|
16018
|
+
template_id: initialTemplateId,
|
|
16019
|
+
template_version_id: initialTemplateVersionId,
|
|
16020
|
+
review_status: initialReviewStatus,
|
|
16021
|
+
outline: initialOutline,
|
|
16001
16022
|
error: initialError,
|
|
16002
16023
|
progress: initialProgress,
|
|
16003
16024
|
pollUrl,
|
|
16004
16025
|
authToken,
|
|
16005
16026
|
shareUrl,
|
|
16027
|
+
approveUrl,
|
|
16028
|
+
approveOutlineUrl,
|
|
16029
|
+
regenerateUrl,
|
|
16030
|
+
hideApproval = false,
|
|
16006
16031
|
className,
|
|
16007
16032
|
theme,
|
|
16008
16033
|
onComplete,
|
|
@@ -16016,9 +16041,23 @@ var PresentationJobCard = ({
|
|
|
16016
16041
|
const [formats, setFormats] = useState10(initialFormats);
|
|
16017
16042
|
const [error, setError] = useState10(initialError);
|
|
16018
16043
|
const [progress, setProgress] = useState10(initialProgress);
|
|
16044
|
+
const [generationMode, setGenerationMode] = useState10(
|
|
16045
|
+
initialGenerationMode || (initialFormats?.html_url ? "template" : "")
|
|
16046
|
+
);
|
|
16047
|
+
const [templateId, setTemplateId] = useState10(initialTemplateId || "");
|
|
16048
|
+
const [, setTemplateVersionId] = useState10(initialTemplateVersionId || "");
|
|
16049
|
+
const [reviewStatus, setReviewStatus] = useState10(initialReviewStatus || "");
|
|
16050
|
+
const [outline, setOutline] = useState10(initialOutline);
|
|
16019
16051
|
const [showExport, setShowExport] = useState10(false);
|
|
16020
16052
|
const [showFullscreen, setShowFullscreen] = useState10(false);
|
|
16021
16053
|
const [copied, setCopied] = useState10(false);
|
|
16054
|
+
const [approving, setApproving] = useState10(false);
|
|
16055
|
+
const [regenerating, setRegenerating] = useState10(false);
|
|
16056
|
+
const [approveError, setApproveError] = useState10(null);
|
|
16057
|
+
const [messageEdits, setMessageEdits] = useState10({});
|
|
16058
|
+
const [approvingOutline, setApprovingOutline] = useState10(false);
|
|
16059
|
+
const [outlineWritePollUrl, setOutlineWritePollUrl] = useState10(null);
|
|
16060
|
+
const [regenPollUrl, setRegenPollUrl] = useState10(null);
|
|
16022
16061
|
const [currentSlide, setCurrentSlide] = useState10(1);
|
|
16023
16062
|
const [previewScale, setPreviewScale] = useState10(1);
|
|
16024
16063
|
const [iframeReady, setIframeReady] = useState10(false);
|
|
@@ -16045,6 +16084,22 @@ var PresentationJobCard = ({
|
|
|
16045
16084
|
useEffect7(() => {
|
|
16046
16085
|
if (initialTitle) setTitle(initialTitle);
|
|
16047
16086
|
}, [initialTitle]);
|
|
16087
|
+
useEffect7(() => {
|
|
16088
|
+
if (initialGenerationMode) setGenerationMode(initialGenerationMode);
|
|
16089
|
+
}, [initialGenerationMode]);
|
|
16090
|
+
useEffect7(() => {
|
|
16091
|
+
if (initialTemplateId) setTemplateId(initialTemplateId);
|
|
16092
|
+
}, [initialTemplateId]);
|
|
16093
|
+
useEffect7(() => {
|
|
16094
|
+
if (initialTemplateVersionId) setTemplateVersionId(initialTemplateVersionId);
|
|
16095
|
+
}, [initialTemplateVersionId]);
|
|
16096
|
+
useEffect7(() => {
|
|
16097
|
+
if (initialReviewStatus) setReviewStatus(initialReviewStatus);
|
|
16098
|
+
}, [initialReviewStatus]);
|
|
16099
|
+
const initialOutlineSlideCount = initialOutline?.slides?.length;
|
|
16100
|
+
useEffect7(() => {
|
|
16101
|
+
if (initialOutline) setOutline(initialOutline);
|
|
16102
|
+
}, [initialOutlineSlideCount]);
|
|
16048
16103
|
const updateScale = useCallback4(() => {
|
|
16049
16104
|
if (previewRef.current) setPreviewScale(previewRef.current.offsetWidth / 1280);
|
|
16050
16105
|
}, []);
|
|
@@ -16108,13 +16163,21 @@ var PresentationJobCard = ({
|
|
|
16108
16163
|
setProgress(data.progress);
|
|
16109
16164
|
}
|
|
16110
16165
|
if (newStatus === "complete" && data.output) {
|
|
16111
|
-
const
|
|
16112
|
-
const
|
|
16113
|
-
const
|
|
16166
|
+
const output = data.output;
|
|
16167
|
+
const isOutlinePhase = output.review_status === "pending_outline_approval" || output.type === "presentation-outline";
|
|
16168
|
+
const newTitle = output.title || initialTitle;
|
|
16169
|
+
const newSlideCount = output.slide_count || 0;
|
|
16170
|
+
const newFormats = output.formats || {};
|
|
16114
16171
|
setTitle(newTitle);
|
|
16115
16172
|
setSlideCount(newSlideCount);
|
|
16116
16173
|
setFormats(newFormats);
|
|
16117
|
-
if (
|
|
16174
|
+
if (output.generation_mode) setGenerationMode(output.generation_mode);
|
|
16175
|
+
if (output.template_id) setTemplateId(output.template_id);
|
|
16176
|
+
if (output.template_version_id) setTemplateVersionId(output.template_version_id);
|
|
16177
|
+
if (output.review_status) setReviewStatus(output.review_status);
|
|
16178
|
+
if (output.outline) setOutline(output.outline);
|
|
16179
|
+
else if (output.deck_plan) setOutline(output.deck_plan);
|
|
16180
|
+
if (!isOutlinePhase && !hasNotifiedRef.current && onCompleteRef.current) {
|
|
16118
16181
|
hasNotifiedRef.current = true;
|
|
16119
16182
|
onCompleteRef.current({
|
|
16120
16183
|
title: newTitle,
|
|
@@ -16134,6 +16197,184 @@ var PresentationJobCard = ({
|
|
|
16134
16197
|
}
|
|
16135
16198
|
// Transient fetch errors are ignored — the shared loop retries next tick.
|
|
16136
16199
|
);
|
|
16200
|
+
const applyDeckOutput = useCallback4((out, opts) => {
|
|
16201
|
+
if (out.title) setTitle(out.title);
|
|
16202
|
+
if (out.slide_count !== void 0) setSlideCount(out.slide_count);
|
|
16203
|
+
if (out.formats) setFormats(out.formats);
|
|
16204
|
+
if (out.generation_mode) setGenerationMode(out.generation_mode);
|
|
16205
|
+
if (out.template_id) setTemplateId(out.template_id);
|
|
16206
|
+
setReviewStatus(out.review_status || "pending_review");
|
|
16207
|
+
setTemplateVersionId(opts?.regenerated ? "" : out.template_version_id || "");
|
|
16208
|
+
if (!opts?.regenerated && !hasNotifiedRef.current && onCompleteRef.current) {
|
|
16209
|
+
hasNotifiedRef.current = true;
|
|
16210
|
+
onCompleteRef.current({
|
|
16211
|
+
title: out.title ?? title,
|
|
16212
|
+
slide_count: out.slide_count ?? slideCount,
|
|
16213
|
+
formats: out.formats ?? formats
|
|
16214
|
+
});
|
|
16215
|
+
}
|
|
16216
|
+
}, [title, slideCount, formats]);
|
|
16217
|
+
const refetchSourceAndApply = useCallback4(async () => {
|
|
16218
|
+
if (!pollUrl) return;
|
|
16219
|
+
try {
|
|
16220
|
+
const headers = {};
|
|
16221
|
+
if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
|
|
16222
|
+
const res = await fetch(pollUrl, { headers });
|
|
16223
|
+
if (!res.ok) return;
|
|
16224
|
+
const data = await res.json();
|
|
16225
|
+
if (data.output) applyDeckOutput(data.output);
|
|
16226
|
+
} catch {
|
|
16227
|
+
}
|
|
16228
|
+
}, [pollUrl, authToken, applyDeckOutput]);
|
|
16229
|
+
useSharedPoll(
|
|
16230
|
+
{
|
|
16231
|
+
key: outlineWritePollUrl,
|
|
16232
|
+
intervalMs: 3e3,
|
|
16233
|
+
fetcher: async () => {
|
|
16234
|
+
const headers = {};
|
|
16235
|
+
if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
|
|
16236
|
+
const res = await fetch(outlineWritePollUrl, { headers });
|
|
16237
|
+
if (!res.ok) throw new Error(`poll ${res.status}`);
|
|
16238
|
+
return res.json();
|
|
16239
|
+
},
|
|
16240
|
+
shouldContinue: (data) => data.status !== "complete" && data.status !== "failed"
|
|
16241
|
+
},
|
|
16242
|
+
(data) => {
|
|
16243
|
+
if (data.status === "complete") {
|
|
16244
|
+
setOutlineWritePollUrl(null);
|
|
16245
|
+
setApprovingOutline(false);
|
|
16246
|
+
void refetchSourceAndApply();
|
|
16247
|
+
} else if (data.status === "failed") {
|
|
16248
|
+
setApproveError(data.error || "Could not build the presentation");
|
|
16249
|
+
setOutlineWritePollUrl(null);
|
|
16250
|
+
setApprovingOutline(false);
|
|
16251
|
+
}
|
|
16252
|
+
}
|
|
16253
|
+
);
|
|
16254
|
+
useSharedPoll(
|
|
16255
|
+
{
|
|
16256
|
+
key: regenPollUrl,
|
|
16257
|
+
intervalMs: 3e3,
|
|
16258
|
+
fetcher: async () => {
|
|
16259
|
+
const headers = {};
|
|
16260
|
+
if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
|
|
16261
|
+
const res = await fetch(regenPollUrl, { headers });
|
|
16262
|
+
if (!res.ok) throw new Error(`poll ${res.status}`);
|
|
16263
|
+
return res.json();
|
|
16264
|
+
},
|
|
16265
|
+
shouldContinue: (data) => data.status !== "complete" && data.status !== "failed"
|
|
16266
|
+
},
|
|
16267
|
+
(data) => {
|
|
16268
|
+
if (data.status === "complete") {
|
|
16269
|
+
if (data.output) applyDeckOutput(data.output, { regenerated: true });
|
|
16270
|
+
setRegenPollUrl(null);
|
|
16271
|
+
setRegenerating(false);
|
|
16272
|
+
} else if (data.status === "failed") {
|
|
16273
|
+
setApproveError(data.error || "Could not switch template");
|
|
16274
|
+
setRegenPollUrl(null);
|
|
16275
|
+
setRegenerating(false);
|
|
16276
|
+
}
|
|
16277
|
+
}
|
|
16278
|
+
);
|
|
16279
|
+
const buildEditedOutline = () => {
|
|
16280
|
+
if (!outline || !Array.isArray(outline.slides)) return void 0;
|
|
16281
|
+
let changed = false;
|
|
16282
|
+
const slides = outline.slides.map((s, i) => {
|
|
16283
|
+
const edited = messageEdits[i];
|
|
16284
|
+
if (edited !== void 0 && edited !== s.message) {
|
|
16285
|
+
changed = true;
|
|
16286
|
+
return { ...s, message: edited };
|
|
16287
|
+
}
|
|
16288
|
+
return s;
|
|
16289
|
+
});
|
|
16290
|
+
return changed ? { ...outline, slides } : void 0;
|
|
16291
|
+
};
|
|
16292
|
+
const handleApproveOutline = async () => {
|
|
16293
|
+
if (!_job_id || approvingOutline) return;
|
|
16294
|
+
const endpoint = approveOutlineUrl || `/api/presentations/${_job_id}/approve-outline`;
|
|
16295
|
+
setApprovingOutline(true);
|
|
16296
|
+
setApproveError(null);
|
|
16297
|
+
try {
|
|
16298
|
+
const headers = { "Content-Type": "application/json" };
|
|
16299
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
16300
|
+
const editedOutline = buildEditedOutline();
|
|
16301
|
+
const res = await fetch(endpoint, {
|
|
16302
|
+
method: "POST",
|
|
16303
|
+
headers,
|
|
16304
|
+
body: JSON.stringify(editedOutline ? { outline: editedOutline } : {})
|
|
16305
|
+
});
|
|
16306
|
+
if (!res.ok) {
|
|
16307
|
+
const err = await res.json().catch(() => ({}));
|
|
16308
|
+
throw new Error(err.detail || err.error || `Approve failed (${res.status})`);
|
|
16309
|
+
}
|
|
16310
|
+
const data = await res.json();
|
|
16311
|
+
if (typeof data.job_id === "string" && data.job_id !== _job_id) {
|
|
16312
|
+
setOutlineWritePollUrl(deriveJobStatusUrl(data.job_id, pollUrl, regenerateUrl));
|
|
16313
|
+
return;
|
|
16314
|
+
}
|
|
16315
|
+
setApprovingOutline(false);
|
|
16316
|
+
void refetchSourceAndApply();
|
|
16317
|
+
} catch (e) {
|
|
16318
|
+
setApproveError(e instanceof Error ? e.message : "Could not build the presentation");
|
|
16319
|
+
setApprovingOutline(false);
|
|
16320
|
+
}
|
|
16321
|
+
};
|
|
16322
|
+
const handleApprove = async () => {
|
|
16323
|
+
if (!_job_id || approving) return;
|
|
16324
|
+
const endpoint = approveUrl || `/api/presentations/${_job_id}/approve-standard`;
|
|
16325
|
+
setApproving(true);
|
|
16326
|
+
setApproveError(null);
|
|
16327
|
+
try {
|
|
16328
|
+
const headers = { "Content-Type": "application/json" };
|
|
16329
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
16330
|
+
const res = await fetch(endpoint, {
|
|
16331
|
+
method: "POST",
|
|
16332
|
+
headers,
|
|
16333
|
+
body: JSON.stringify({ label: title })
|
|
16334
|
+
});
|
|
16335
|
+
if (!res.ok) {
|
|
16336
|
+
const err = await res.json().catch(() => ({}));
|
|
16337
|
+
throw new Error(err.detail || err.error || `Approve failed (${res.status})`);
|
|
16338
|
+
}
|
|
16339
|
+
const data = await res.json();
|
|
16340
|
+
setReviewStatus(data.review_status || "approved");
|
|
16341
|
+
if (data.template_version_id) setTemplateVersionId(data.template_version_id);
|
|
16342
|
+
if (data.template_id) setTemplateId(data.template_id);
|
|
16343
|
+
} catch (e) {
|
|
16344
|
+
setApproveError(e instanceof Error ? e.message : "Could not save the format");
|
|
16345
|
+
} finally {
|
|
16346
|
+
setApproving(false);
|
|
16347
|
+
}
|
|
16348
|
+
};
|
|
16349
|
+
const handleRegenerate = async () => {
|
|
16350
|
+
if (!_job_id || regenerating) return;
|
|
16351
|
+
const endpoint = regenerateUrl || `/api/presentations/${_job_id}/regenerate`;
|
|
16352
|
+
setRegenerating(true);
|
|
16353
|
+
setApproveError(null);
|
|
16354
|
+
try {
|
|
16355
|
+
const headers = { "Content-Type": "application/json" };
|
|
16356
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
16357
|
+
const res = await fetch(endpoint, {
|
|
16358
|
+
method: "POST",
|
|
16359
|
+
headers,
|
|
16360
|
+
body: JSON.stringify({})
|
|
16361
|
+
});
|
|
16362
|
+
if (!res.ok) {
|
|
16363
|
+
const err = await res.json().catch(() => ({}));
|
|
16364
|
+
throw new Error(err.detail || err.error || `Regenerate failed (${res.status})`);
|
|
16365
|
+
}
|
|
16366
|
+
const data = await res.json();
|
|
16367
|
+
if (typeof data.job_id === "string" && data.job_id !== _job_id) {
|
|
16368
|
+
setRegenPollUrl(deriveJobStatusUrl(data.job_id, pollUrl, regenerateUrl));
|
|
16369
|
+
return;
|
|
16370
|
+
}
|
|
16371
|
+
applyDeckOutput(data.output || data, { regenerated: true });
|
|
16372
|
+
setRegenerating(false);
|
|
16373
|
+
} catch (e) {
|
|
16374
|
+
setApproveError(e instanceof Error ? e.message : "Could not switch template");
|
|
16375
|
+
setRegenerating(false);
|
|
16376
|
+
}
|
|
16377
|
+
};
|
|
16137
16378
|
const handleShare = async () => {
|
|
16138
16379
|
const link = shareUrl ?? (typeof window !== "undefined" && _job_id ? `${window.location.origin}/p/${_job_id}` : formats.html_url);
|
|
16139
16380
|
if (!link) return;
|
|
@@ -16254,8 +16495,85 @@ var PresentationJobCard = ({
|
|
|
16254
16495
|
] })
|
|
16255
16496
|
] }) }) });
|
|
16256
16497
|
}
|
|
16498
|
+
if (status === "complete" && reviewStatus === "pending_outline_approval") {
|
|
16499
|
+
const slides = Array.isArray(outline?.slides) ? outline.slides : [];
|
|
16500
|
+
const building = Boolean(outlineWritePollUrl) || approvingOutline;
|
|
16501
|
+
return /* @__PURE__ */ jsx147("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsxs108("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", style: t.root, children: [
|
|
16502
|
+
/* @__PURE__ */ jsx147(
|
|
16503
|
+
"div",
|
|
16504
|
+
{
|
|
16505
|
+
className: "h-[3px]",
|
|
16506
|
+
style: { background: accentGradient || "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)" }
|
|
16507
|
+
}
|
|
16508
|
+
),
|
|
16509
|
+
/* @__PURE__ */ jsxs108("div", { className: "p-5", children: [
|
|
16510
|
+
/* @__PURE__ */ jsxs108("div", { className: "flex items-start gap-3", children: [
|
|
16511
|
+
/* @__PURE__ */ jsx147(
|
|
16512
|
+
"div",
|
|
16513
|
+
{
|
|
16514
|
+
className: "w-10 h-10 rounded-xl bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center flex-shrink-0 text-indigo-400",
|
|
16515
|
+
style: { ...t.accentSubtle(0.1), ...t.accentBorder, ...t.accent },
|
|
16516
|
+
children: /* @__PURE__ */ jsx147(SlidesIcon, {})
|
|
16517
|
+
}
|
|
16518
|
+
),
|
|
16519
|
+
/* @__PURE__ */ jsxs108("div", { className: "flex-1 min-w-0", children: [
|
|
16520
|
+
/* @__PURE__ */ jsx147("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", style: t.text, children: title || "Presentation outline" }),
|
|
16521
|
+
/* @__PURE__ */ jsxs108("p", { className: "text-xs text-amber-400/90 mt-0.5", children: [
|
|
16522
|
+
"Review the slide outline",
|
|
16523
|
+
slides.length > 0 ? " \u2014 edit any slide message" : "",
|
|
16524
|
+
", then build the deck."
|
|
16525
|
+
] })
|
|
16526
|
+
] })
|
|
16527
|
+
] }),
|
|
16528
|
+
/* @__PURE__ */ jsxs108("div", { className: "mt-4 space-y-2", children: [
|
|
16529
|
+
slides.map((s, i) => /* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-2", children: [
|
|
16530
|
+
/* @__PURE__ */ jsx147("span", { className: "text-xs text-zinc-600 w-5 text-right tabular-nums flex-shrink-0", children: s.n ?? i + 1 }),
|
|
16531
|
+
/* @__PURE__ */ jsxs108(
|
|
16532
|
+
"span",
|
|
16533
|
+
{
|
|
16534
|
+
className: "flex items-center gap-1 text-[10px] uppercase tracking-wide text-zinc-500 w-20 flex-shrink-0 truncate",
|
|
16535
|
+
title: s.type,
|
|
16536
|
+
children: [
|
|
16537
|
+
/* @__PURE__ */ jsx147(SlideTypeIcon, {}),
|
|
16538
|
+
s.type || "slide"
|
|
16539
|
+
]
|
|
16540
|
+
}
|
|
16541
|
+
),
|
|
16542
|
+
/* @__PURE__ */ jsx147(
|
|
16543
|
+
"input",
|
|
16544
|
+
{
|
|
16545
|
+
value: messageEdits[i] ?? s.message ?? "",
|
|
16546
|
+
onChange: (e) => setMessageEdits((prev) => ({ ...prev, [i]: e.target.value })),
|
|
16547
|
+
disabled: building,
|
|
16548
|
+
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"
|
|
16549
|
+
}
|
|
16550
|
+
)
|
|
16551
|
+
] }, i)),
|
|
16552
|
+
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
|
+
] }),
|
|
16554
|
+
approveError && /* @__PURE__ */ jsx147("p", { className: "mt-3 text-xs text-red-400/90", children: approveError }),
|
|
16555
|
+
/* @__PURE__ */ jsx147("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs108(
|
|
16556
|
+
"button",
|
|
16557
|
+
{
|
|
16558
|
+
onClick: handleApproveOutline,
|
|
16559
|
+
disabled: building,
|
|
16560
|
+
title: "Approve this outline and build the full deck",
|
|
16561
|
+
className: "flex items-center gap-1.5 px-3 h-8 rounded-lg border border-emerald-700/50 bg-emerald-950/40 hover:border-emerald-500 text-emerald-300 text-xs font-medium transition-colors disabled:opacity-50",
|
|
16562
|
+
children: [
|
|
16563
|
+
/* @__PURE__ */ jsx147(CheckIcon, {}),
|
|
16564
|
+
/* @__PURE__ */ jsx147("span", { children: building ? "Building deck..." : "Approve & Build" })
|
|
16565
|
+
]
|
|
16566
|
+
}
|
|
16567
|
+
) })
|
|
16568
|
+
] })
|
|
16569
|
+
] }) });
|
|
16570
|
+
}
|
|
16257
16571
|
const total = slideCount || 1;
|
|
16258
16572
|
const hasHtml = Boolean(formats.html_url);
|
|
16573
|
+
const templateLabel = formatTemplateLabel(templateId);
|
|
16574
|
+
const isApproved = reviewStatus === "approved";
|
|
16575
|
+
const canApprove = !hideApproval && generationMode === "template" && reviewStatus === "pending_review" && Boolean(_job_id);
|
|
16576
|
+
const canRegenerate = canApprove;
|
|
16259
16577
|
return /* @__PURE__ */ jsxs108(Fragment5, { children: [
|
|
16260
16578
|
/* @__PURE__ */ jsx147("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsxs108("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", style: t.root, children: [
|
|
16261
16579
|
/* @__PURE__ */ jsx147("div", { className: "h-[3px]", style: { background: accentGradient || "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)" } }),
|
|
@@ -16273,10 +16591,39 @@ var PresentationJobCard = ({
|
|
|
16273
16591
|
/* @__PURE__ */ jsx147("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", style: t.text, children: title }),
|
|
16274
16592
|
/* @__PURE__ */ jsxs108("p", { className: "text-xs text-zinc-500 mt-0.5", style: t.muted, children: [
|
|
16275
16593
|
slideCount ? `${slideCount} slides` : "Presentation",
|
|
16276
|
-
" \xB7 Ready to export"
|
|
16277
|
-
|
|
16594
|
+
" \xB7 Ready to export",
|
|
16595
|
+
templateLabel && ` \xB7 ${templateLabel}`
|
|
16596
|
+
] }),
|
|
16597
|
+
generationMode === "template" && /* @__PURE__ */ jsx147("p", { className: "text-xs mt-1", children: isApproved ? /* @__PURE__ */ jsx147("span", { className: "text-emerald-400/90", children: "Approved \u2014 future decks use this format" }) : reviewStatus === "pending_review" ? /* @__PURE__ */ jsx147("span", { className: "text-amber-400/90", children: "Review this deck, then approve to lock the format" }) : null })
|
|
16278
16598
|
] }),
|
|
16279
|
-
/* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: [
|
|
16599
|
+
/* @__PURE__ */ jsxs108("div", { className: "flex items-center gap-1.5 flex-shrink-0 flex-wrap justify-end", children: [
|
|
16600
|
+
canRegenerate && /* @__PURE__ */ jsxs108(
|
|
16601
|
+
"button",
|
|
16602
|
+
{
|
|
16603
|
+
onClick: handleRegenerate,
|
|
16604
|
+
disabled: regenerating || approving,
|
|
16605
|
+
title: "Try another design template with the same content",
|
|
16606
|
+
className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-300 text-xs font-medium transition-colors disabled:opacity-50",
|
|
16607
|
+
children: [
|
|
16608
|
+
/* @__PURE__ */ jsx147(RefreshIcon, {}),
|
|
16609
|
+
/* @__PURE__ */ jsx147("span", { children: regenerating ? "Switching..." : "Regenerate" })
|
|
16610
|
+
]
|
|
16611
|
+
}
|
|
16612
|
+
),
|
|
16613
|
+
canApprove && /* @__PURE__ */ jsxs108(
|
|
16614
|
+
"button",
|
|
16615
|
+
{
|
|
16616
|
+
onClick: handleApprove,
|
|
16617
|
+
disabled: approving,
|
|
16618
|
+
title: "Approve and save this deck format for future runs",
|
|
16619
|
+
className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-emerald-700/50 bg-emerald-950/40 hover:border-emerald-500 text-emerald-300 text-xs font-medium transition-colors disabled:opacity-50",
|
|
16620
|
+
children: [
|
|
16621
|
+
/* @__PURE__ */ jsx147(CheckIcon, {}),
|
|
16622
|
+
/* @__PURE__ */ jsx147("span", { children: approving ? "Saving..." : "Approve" })
|
|
16623
|
+
]
|
|
16624
|
+
}
|
|
16625
|
+
),
|
|
16626
|
+
isApproved && /* @__PURE__ */ jsx147("span", { className: "flex items-center justify-center w-7 h-7 rounded-lg border border-emerald-500/40 bg-emerald-500/10 text-emerald-400", title: "Format saved", children: /* @__PURE__ */ jsx147(CheckIcon, {}) }),
|
|
16280
16627
|
/* @__PURE__ */ jsx147(
|
|
16281
16628
|
"button",
|
|
16282
16629
|
{
|
|
@@ -16318,6 +16665,7 @@ var PresentationJobCard = ({
|
|
|
16318
16665
|
)
|
|
16319
16666
|
] })
|
|
16320
16667
|
] }),
|
|
16668
|
+
approveError && /* @__PURE__ */ jsx147("p", { className: "mt-3 text-xs text-red-400/90", children: approveError }),
|
|
16321
16669
|
hasHtml && /* @__PURE__ */ jsxs108("div", { className: "mt-4", children: [
|
|
16322
16670
|
/* @__PURE__ */ jsxs108(
|
|
16323
16671
|
"div",
|
|
@@ -16452,11 +16800,11 @@ var ShareIcon2 = () => /* @__PURE__ */ jsxs109("svg", { width: "14", height: "14
|
|
|
16452
16800
|
/* @__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" })
|
|
16453
16801
|
] });
|
|
16454
16802
|
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" }) });
|
|
16455
|
-
var
|
|
16803
|
+
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: [
|
|
16456
16804
|
/* @__PURE__ */ jsx148("polyline", { points: "23 4 23 10 17 10" }),
|
|
16457
16805
|
/* @__PURE__ */ jsx148("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
|
|
16458
16806
|
] });
|
|
16459
|
-
function
|
|
16807
|
+
function formatTemplateLabel2(templateId) {
|
|
16460
16808
|
if (!templateId) return null;
|
|
16461
16809
|
return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
16462
16810
|
}
|
|
@@ -16503,7 +16851,7 @@ var FullscreenPreviewModal = ({ url, title, onClose }) => {
|
|
|
16503
16851
|
) })
|
|
16504
16852
|
] });
|
|
16505
16853
|
};
|
|
16506
|
-
function
|
|
16854
|
+
function deriveJobStatusUrl2(newJobId, pollUrl, regenerateUrl) {
|
|
16507
16855
|
const base = pollUrl?.replace(/\/api\/jobs\/[^/]+\/status.*$/, "") ?? regenerateUrl?.replace(/\/api\/reports\/[^/]+\/regenerate.*$/, "") ?? "";
|
|
16508
16856
|
return `${base}/api/jobs/${newJobId}/status`;
|
|
16509
16857
|
}
|
|
@@ -16524,6 +16872,7 @@ var ResearchReportJobCard = (props) => {
|
|
|
16524
16872
|
template_id: initialTemplateId,
|
|
16525
16873
|
template_version_id: initialTemplateVersionId,
|
|
16526
16874
|
review_status: initialReviewStatus,
|
|
16875
|
+
outline: initialOutline,
|
|
16527
16876
|
theme: initialTheme,
|
|
16528
16877
|
error: initialError,
|
|
16529
16878
|
progress: initialProgress,
|
|
@@ -16531,7 +16880,9 @@ var ResearchReportJobCard = (props) => {
|
|
|
16531
16880
|
authToken,
|
|
16532
16881
|
shareUrl,
|
|
16533
16882
|
approveUrl,
|
|
16883
|
+
approveOutlineUrl,
|
|
16534
16884
|
regenerateUrl,
|
|
16885
|
+
hideApproval = false,
|
|
16535
16886
|
className,
|
|
16536
16887
|
onComplete,
|
|
16537
16888
|
onFailed,
|
|
@@ -16554,6 +16905,7 @@ var ResearchReportJobCard = (props) => {
|
|
|
16554
16905
|
const [reviewStatus, setReviewStatus] = useState11(
|
|
16555
16906
|
initialReviewStatus || (initialHtmlUrl ? "pending_review" : "")
|
|
16556
16907
|
);
|
|
16908
|
+
const [outline, setOutline] = useState11(initialOutline);
|
|
16557
16909
|
const [theme, setTheme] = useState11(initialTheme || DEFAULT_THEME);
|
|
16558
16910
|
const [error, setError] = useState11(initialError);
|
|
16559
16911
|
const [progress, setProgress] = useState11(initialProgress);
|
|
@@ -16563,6 +16915,9 @@ var ResearchReportJobCard = (props) => {
|
|
|
16563
16915
|
const [approving, setApproving] = useState11(false);
|
|
16564
16916
|
const [regenerating, setRegenerating] = useState11(false);
|
|
16565
16917
|
const [approveError, setApproveError] = useState11(null);
|
|
16918
|
+
const [headingEdits, setHeadingEdits] = useState11({});
|
|
16919
|
+
const [approvingOutline, setApprovingOutline] = useState11(false);
|
|
16920
|
+
const [outlineWritePollUrl, setOutlineWritePollUrl] = useState11(null);
|
|
16566
16921
|
const [regenPollUrl, setRegenPollUrl] = useState11(null);
|
|
16567
16922
|
const previewRef = useRef7(null);
|
|
16568
16923
|
const onCompleteRef = useRef7(onComplete);
|
|
@@ -16592,6 +16947,10 @@ var ResearchReportJobCard = (props) => {
|
|
|
16592
16947
|
useEffect8(() => {
|
|
16593
16948
|
if (initialReviewStatus) setReviewStatus(initialReviewStatus);
|
|
16594
16949
|
}, [initialReviewStatus]);
|
|
16950
|
+
const initialOutlineSectionCount = initialOutline?.sections?.length;
|
|
16951
|
+
useEffect8(() => {
|
|
16952
|
+
if (initialOutline) setOutline(initialOutline);
|
|
16953
|
+
}, [initialOutlineSectionCount]);
|
|
16595
16954
|
useEffect8(() => {
|
|
16596
16955
|
if (initialDepth) setDepth(initialDepth);
|
|
16597
16956
|
}, [initialDepth]);
|
|
@@ -16657,6 +17016,7 @@ var ResearchReportJobCard = (props) => {
|
|
|
16657
17016
|
}
|
|
16658
17017
|
if (newStatus === "complete" && data.output) {
|
|
16659
17018
|
const output = data.output;
|
|
17019
|
+
const isOutlinePhase = output.review_status === "pending_outline_approval" || output.type === "research-report-outline";
|
|
16660
17020
|
setTitle(output.title || initialTitle);
|
|
16661
17021
|
setDepth(output.depth || "");
|
|
16662
17022
|
setSectionCount(output.section_count || 0);
|
|
@@ -16668,10 +17028,11 @@ var ResearchReportJobCard = (props) => {
|
|
|
16668
17028
|
if (output.template_id) setTemplateId(output.template_id);
|
|
16669
17029
|
if (output.template_version_id) setTemplateVersionId(output.template_version_id);
|
|
16670
17030
|
if (output.review_status) setReviewStatus(output.review_status);
|
|
17031
|
+
if (output.outline) setOutline(output.outline);
|
|
16671
17032
|
if (output.theme) {
|
|
16672
17033
|
setTheme(output.theme);
|
|
16673
17034
|
}
|
|
16674
|
-
if (!hasNotifiedRef.current && onCompleteRef.current) {
|
|
17035
|
+
if (!isOutlinePhase && !hasNotifiedRef.current && onCompleteRef.current) {
|
|
16675
17036
|
hasNotifiedRef.current = true;
|
|
16676
17037
|
onCompleteRef.current(output);
|
|
16677
17038
|
}
|
|
@@ -16740,6 +17101,103 @@ var ResearchReportJobCard = (props) => {
|
|
|
16740
17101
|
}
|
|
16741
17102
|
}
|
|
16742
17103
|
);
|
|
17104
|
+
const refetchSourceAndApply = useCallback5(async () => {
|
|
17105
|
+
if (!pollUrl) return;
|
|
17106
|
+
try {
|
|
17107
|
+
const headers = {};
|
|
17108
|
+
if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
|
|
17109
|
+
const res = await fetch(pollUrl, { headers });
|
|
17110
|
+
if (!res.ok) return;
|
|
17111
|
+
const data = await res.json();
|
|
17112
|
+
const out = data.output;
|
|
17113
|
+
if (!out) return;
|
|
17114
|
+
if (out.title) setTitle(out.title);
|
|
17115
|
+
if (out.depth) setDepth(out.depth);
|
|
17116
|
+
if (out.section_count !== void 0) setSectionCount(out.section_count);
|
|
17117
|
+
if (out.source_count !== void 0) setSourceCount(out.source_count);
|
|
17118
|
+
if (out.word_count !== void 0) setWordCount(out.word_count);
|
|
17119
|
+
if (out.executive_summary) setSummary(out.executive_summary);
|
|
17120
|
+
if (out.html_url) setHtmlUrl(out.html_url);
|
|
17121
|
+
if (out.generation_mode) setGenerationMode(out.generation_mode);
|
|
17122
|
+
if (out.template_id) setTemplateId(out.template_id);
|
|
17123
|
+
setTemplateVersionId(out.template_version_id || "");
|
|
17124
|
+
setReviewStatus(out.review_status || "pending_review");
|
|
17125
|
+
if (out.theme) setTheme(out.theme);
|
|
17126
|
+
if (!hasNotifiedRef.current && onCompleteRef.current) {
|
|
17127
|
+
hasNotifiedRef.current = true;
|
|
17128
|
+
onCompleteRef.current(out);
|
|
17129
|
+
}
|
|
17130
|
+
} catch {
|
|
17131
|
+
}
|
|
17132
|
+
}, [pollUrl, authToken]);
|
|
17133
|
+
useSharedPoll(
|
|
17134
|
+
{
|
|
17135
|
+
key: outlineWritePollUrl,
|
|
17136
|
+
intervalMs: 3e3,
|
|
17137
|
+
fetcher: async () => {
|
|
17138
|
+
const headers = {};
|
|
17139
|
+
if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
|
|
17140
|
+
const res = await fetch(outlineWritePollUrl, { headers });
|
|
17141
|
+
if (!res.ok) throw new Error(`poll ${res.status}`);
|
|
17142
|
+
return res.json();
|
|
17143
|
+
},
|
|
17144
|
+
shouldContinue: (data) => data.status !== "complete" && data.status !== "failed"
|
|
17145
|
+
},
|
|
17146
|
+
(data) => {
|
|
17147
|
+
if (data.status === "complete") {
|
|
17148
|
+
setOutlineWritePollUrl(null);
|
|
17149
|
+
setApprovingOutline(false);
|
|
17150
|
+
void refetchSourceAndApply();
|
|
17151
|
+
} else if (data.status === "failed") {
|
|
17152
|
+
setApproveError(data.error || "Could not build the report");
|
|
17153
|
+
setOutlineWritePollUrl(null);
|
|
17154
|
+
setApprovingOutline(false);
|
|
17155
|
+
}
|
|
17156
|
+
}
|
|
17157
|
+
);
|
|
17158
|
+
const buildEditedOutline = () => {
|
|
17159
|
+
if (!outline || !Array.isArray(outline.sections)) return void 0;
|
|
17160
|
+
let changed = false;
|
|
17161
|
+
const sections = outline.sections.map((s, i) => {
|
|
17162
|
+
const edited = headingEdits[i];
|
|
17163
|
+
if (edited !== void 0 && edited !== s.heading) {
|
|
17164
|
+
changed = true;
|
|
17165
|
+
return { ...s, heading: edited };
|
|
17166
|
+
}
|
|
17167
|
+
return s;
|
|
17168
|
+
});
|
|
17169
|
+
return changed ? { ...outline, sections } : void 0;
|
|
17170
|
+
};
|
|
17171
|
+
const handleApproveOutline = async () => {
|
|
17172
|
+
if (!job_id || approvingOutline) return;
|
|
17173
|
+
const endpoint = approveOutlineUrl || `/api/reports/${job_id}/approve-outline`;
|
|
17174
|
+
setApprovingOutline(true);
|
|
17175
|
+
setApproveError(null);
|
|
17176
|
+
try {
|
|
17177
|
+
const headers = { "Content-Type": "application/json" };
|
|
17178
|
+
if (authToken) headers.Authorization = `Bearer ${authToken}`;
|
|
17179
|
+
const editedOutline = buildEditedOutline();
|
|
17180
|
+
const res = await fetch(endpoint, {
|
|
17181
|
+
method: "POST",
|
|
17182
|
+
headers,
|
|
17183
|
+
body: JSON.stringify(editedOutline ? { outline: editedOutline } : {})
|
|
17184
|
+
});
|
|
17185
|
+
if (!res.ok) {
|
|
17186
|
+
const err = await res.json().catch(() => ({}));
|
|
17187
|
+
throw new Error(err.detail || err.error || `Approve failed (${res.status})`);
|
|
17188
|
+
}
|
|
17189
|
+
const data = await res.json();
|
|
17190
|
+
if (typeof data.job_id === "string" && data.job_id !== job_id) {
|
|
17191
|
+
setOutlineWritePollUrl(deriveJobStatusUrl2(data.job_id, pollUrl, regenerateUrl));
|
|
17192
|
+
return;
|
|
17193
|
+
}
|
|
17194
|
+
setApprovingOutline(false);
|
|
17195
|
+
void refetchSourceAndApply();
|
|
17196
|
+
} catch (e) {
|
|
17197
|
+
setApproveError(e instanceof Error ? e.message : "Could not build the report");
|
|
17198
|
+
setApprovingOutline(false);
|
|
17199
|
+
}
|
|
17200
|
+
};
|
|
16743
17201
|
const formatWordCount = (count) => {
|
|
16744
17202
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
|
|
16745
17203
|
return count.toString();
|
|
@@ -16845,6 +17303,61 @@ var ResearchReportJobCard = (props) => {
|
|
|
16845
17303
|
] })
|
|
16846
17304
|
] }) }) });
|
|
16847
17305
|
}
|
|
17306
|
+
if (status === "complete" && reviewStatus === "pending_outline_approval") {
|
|
17307
|
+
const sections = Array.isArray(outline?.sections) ? outline.sections : [];
|
|
17308
|
+
const building = Boolean(outlineWritePollUrl) || approvingOutline;
|
|
17309
|
+
return /* @__PURE__ */ jsx148("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsxs109("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", children: [
|
|
17310
|
+
/* @__PURE__ */ jsx148(
|
|
17311
|
+
"div",
|
|
17312
|
+
{
|
|
17313
|
+
className: "h-[3px]",
|
|
17314
|
+
style: { background: "linear-gradient(90deg, #8B7D5E, #C0AE82, #DCC99B)" }
|
|
17315
|
+
}
|
|
17316
|
+
),
|
|
17317
|
+
/* @__PURE__ */ jsxs109("div", { className: "p-5", children: [
|
|
17318
|
+
/* @__PURE__ */ jsxs109("div", { className: "flex items-start gap-3", children: [
|
|
17319
|
+
/* @__PURE__ */ jsx148("div", { className: "w-10 h-10 rounded-xl bg-violet-500/10 border border-violet-500/20 flex items-center justify-center flex-shrink-0 text-violet-300", children: /* @__PURE__ */ jsx148(DocumentIcon, {}) }),
|
|
17320
|
+
/* @__PURE__ */ jsxs109("div", { className: "flex-1 min-w-0", children: [
|
|
17321
|
+
/* @__PURE__ */ jsx148("h3", { className: "text-sm font-semibold text-zinc-100 truncate leading-tight", children: title || "Report outline" }),
|
|
17322
|
+
/* @__PURE__ */ jsxs109("p", { className: "text-xs text-amber-400/90 mt-0.5", children: [
|
|
17323
|
+
"Review the outline",
|
|
17324
|
+
sections.length > 0 ? " \u2014 edit any heading" : "",
|
|
17325
|
+
", then build the full report."
|
|
17326
|
+
] })
|
|
17327
|
+
] })
|
|
17328
|
+
] }),
|
|
17329
|
+
/* @__PURE__ */ jsxs109("div", { className: "mt-4 space-y-2", children: [
|
|
17330
|
+
sections.map((s, i) => /* @__PURE__ */ jsxs109("div", { className: "flex items-center gap-2", children: [
|
|
17331
|
+
/* @__PURE__ */ jsx148("span", { className: "text-xs text-zinc-600 w-5 text-right tabular-nums flex-shrink-0", children: i + 1 }),
|
|
17332
|
+
/* @__PURE__ */ jsx148(
|
|
17333
|
+
"input",
|
|
17334
|
+
{
|
|
17335
|
+
value: headingEdits[i] ?? s.heading ?? "",
|
|
17336
|
+
onChange: (e) => setHeadingEdits((prev) => ({ ...prev, [i]: e.target.value })),
|
|
17337
|
+
disabled: building,
|
|
17338
|
+
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"
|
|
17339
|
+
}
|
|
17340
|
+
)
|
|
17341
|
+
] }, i)),
|
|
17342
|
+
sections.length === 0 && /* @__PURE__ */ jsx148("p", { className: "text-xs text-zinc-500", children: "No outline sections were returned; you can still build the report." })
|
|
17343
|
+
] }),
|
|
17344
|
+
approveError && /* @__PURE__ */ jsx148("p", { className: "mt-3 text-xs text-red-400/90", children: approveError }),
|
|
17345
|
+
/* @__PURE__ */ jsx148("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs109(
|
|
17346
|
+
"button",
|
|
17347
|
+
{
|
|
17348
|
+
onClick: handleApproveOutline,
|
|
17349
|
+
disabled: building,
|
|
17350
|
+
title: "Approve this outline and build the full report",
|
|
17351
|
+
className: "flex items-center gap-1.5 px-3 h-8 rounded-lg border border-emerald-700/50 bg-emerald-950/40 hover:border-emerald-500 text-emerald-300 text-xs font-medium transition-colors disabled:opacity-50",
|
|
17352
|
+
children: [
|
|
17353
|
+
/* @__PURE__ */ jsx148(CheckIcon2, {}),
|
|
17354
|
+
/* @__PURE__ */ jsx148("span", { children: building ? "Building report..." : "Approve & Build" })
|
|
17355
|
+
]
|
|
17356
|
+
}
|
|
17357
|
+
) })
|
|
17358
|
+
] })
|
|
17359
|
+
] }) });
|
|
17360
|
+
}
|
|
16848
17361
|
if (status === "complete" && !hasHTML) {
|
|
16849
17362
|
return /* @__PURE__ */ jsx148("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsxs109("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", children: [
|
|
16850
17363
|
/* @__PURE__ */ jsx148(
|
|
@@ -16908,8 +17421,8 @@ var ResearchReportJobCard = (props) => {
|
|
|
16908
17421
|
window.open(link, "_blank", "noopener,noreferrer");
|
|
16909
17422
|
}
|
|
16910
17423
|
};
|
|
16911
|
-
const canApprove = generationMode === "template" && reviewStatus === "pending_review" && Boolean(job_id);
|
|
16912
|
-
const canRegenerate = generationMode === "template" && reviewStatus === "pending_review" && Boolean(job_id);
|
|
17424
|
+
const canApprove = !hideApproval && generationMode === "template" && reviewStatus === "pending_review" && Boolean(job_id);
|
|
17425
|
+
const canRegenerate = !hideApproval && generationMode === "template" && reviewStatus === "pending_review" && Boolean(job_id);
|
|
16913
17426
|
const canShare = Boolean(hasHTML || job_id) && (generationMode !== "template" || reviewStatus !== "pending_review");
|
|
16914
17427
|
const handleApprove = async () => {
|
|
16915
17428
|
if (!job_id || approving) return;
|
|
@@ -16974,7 +17487,7 @@ var ResearchReportJobCard = (props) => {
|
|
|
16974
17487
|
}
|
|
16975
17488
|
const data = await res.json();
|
|
16976
17489
|
if (typeof data.job_id === "string" && data.job_id !== job_id) {
|
|
16977
|
-
setRegenPollUrl(
|
|
17490
|
+
setRegenPollUrl(deriveJobStatusUrl2(data.job_id, pollUrl, regenerateUrl));
|
|
16978
17491
|
return;
|
|
16979
17492
|
}
|
|
16980
17493
|
applyRegeneratedOutput(data.output || data);
|
|
@@ -16984,7 +17497,7 @@ var ResearchReportJobCard = (props) => {
|
|
|
16984
17497
|
setRegenerating(false);
|
|
16985
17498
|
}
|
|
16986
17499
|
};
|
|
16987
|
-
const templateLabel =
|
|
17500
|
+
const templateLabel = formatTemplateLabel2(templateId);
|
|
16988
17501
|
const isApproved = reviewStatus === "approved";
|
|
16989
17502
|
return /* @__PURE__ */ jsxs109(Fragment6, { children: [
|
|
16990
17503
|
/* @__PURE__ */ jsx148("div", { className: cn("w-full", className), children: /* @__PURE__ */ jsxs109("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", children: [
|
|
@@ -17033,7 +17546,7 @@ var ResearchReportJobCard = (props) => {
|
|
|
17033
17546
|
title: "Try another report template with the same data",
|
|
17034
17547
|
className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-300 text-xs font-medium transition-colors disabled:opacity-50",
|
|
17035
17548
|
children: [
|
|
17036
|
-
/* @__PURE__ */ jsx148(
|
|
17549
|
+
/* @__PURE__ */ jsx148(RefreshIcon2, {}),
|
|
17037
17550
|
/* @__PURE__ */ jsx148("span", { children: regenerating ? "Switching..." : "Regenerate" })
|
|
17038
17551
|
]
|
|
17039
17552
|
}
|