@lv-x-software-house/x_view 1.2.4 → 1.2.5-dev.2
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.js +1684 -815
- package/dist/index.mjs +1691 -816
- package/package.json +52 -43
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import React25, {
|
|
2
|
+
import React25, {
|
|
3
|
+
useCallback as useCallback4,
|
|
4
|
+
useEffect as useEffect22,
|
|
5
|
+
useRef as useRef19,
|
|
6
|
+
useState as useState25,
|
|
7
|
+
useMemo as useMemo12
|
|
8
|
+
} from "react";
|
|
3
9
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
4
10
|
import { useSession } from "next-auth/react";
|
|
5
11
|
import CryptoJS from "crypto-js";
|
|
@@ -402,11 +408,18 @@ function ContextMenu({
|
|
|
402
408
|
))));
|
|
403
409
|
};
|
|
404
410
|
const renderAncestryActionsView = () => {
|
|
411
|
+
var _a2, _b2;
|
|
405
412
|
const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
|
|
406
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
407
|
-
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry);
|
|
413
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: ancestryTitle }, ancestryTitle))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("read", "Ancestry") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
414
|
+
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "full");
|
|
415
|
+
onClose();
|
|
416
|
+
}, className: baseButtonClass, title: "Renderizar Ancestralidade Completa" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ React.createElement("span", null, "Renderizar Ancestralidade")), /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
417
|
+
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "ancestry_only");
|
|
408
418
|
onClose();
|
|
409
|
-
}, className: baseButtonClass, title: "Renderizar Ancestralidade" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("
|
|
419
|
+
}, className: baseButtonClass, title: "Renderizar apenas a \xC1rvore de Ancestralidade (Radial)" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M12 2v3m0 14v3m10-10h-3m-14 0H2m15.66-6.34-2.12 2.12m-9.08 9.08-2.12 2.12m13.32 0-2.12-2.12m-9.08-9.08-2.12-2.12" })), /* @__PURE__ */ React.createElement("span", null, "\xC1rvore de Ancestralidade")), ((_b2 = (_a2 = selectedAncestry == null ? void 0 : selectedAncestry.abstraction_tree) == null ? void 0 : _a2.children) == null ? void 0 : _b2.length) > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
420
|
+
onRenderAncestry == null ? void 0 : onRenderAncestry(selectedAncestry, "abstraction_only");
|
|
421
|
+
onClose();
|
|
422
|
+
}, className: baseButtonClass, title: "Renderizar apenas a \xC1rvore de Abstra\xE7\xE3o (Vertical)" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ React.createElement("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ React.createElement("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ React.createElement("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }), /* @__PURE__ */ React.createElement("path", { d: "M10 6.5h4" }), /* @__PURE__ */ React.createElement("path", { d: "M10 17.5h4" }), /* @__PURE__ */ React.createElement("path", { d: "M6.5 10v4" }), /* @__PURE__ */ React.createElement("path", { d: "M17.5 10v4" })), /* @__PURE__ */ React.createElement("span", null, "\xC1rvore de Abstra\xE7\xE3o"))), ability.can("update", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
410
423
|
onEditAncestry == null ? void 0 : onEditAncestry(selectedAncestry);
|
|
411
424
|
onClose();
|
|
412
425
|
}, className: baseButtonClass, title: "Editar Ancestralidade" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M12 20h9" }), /* @__PURE__ */ React.createElement("path", { d: "M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" })), /* @__PURE__ */ React.createElement("span", null, "Editar Ancestralidade")), (ability.can("update", "Ancestry") || ability.can("delete", "Ancestry")) && /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), ability.can("delete", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
@@ -9890,7 +9903,6 @@ var GroupItem = ({
|
|
|
9890
9903
|
onPlayAncestry,
|
|
9891
9904
|
availableIds,
|
|
9892
9905
|
canEdit
|
|
9893
|
-
// [NOVO] Recebe permissão de edição
|
|
9894
9906
|
}) => {
|
|
9895
9907
|
const canIndent = index > 0;
|
|
9896
9908
|
const isPickingForThisGroup = pickingGroupId === group.id;
|
|
@@ -9905,107 +9917,126 @@ var GroupItem = ({
|
|
|
9905
9917
|
useEffect21(() => {
|
|
9906
9918
|
adjustHeight();
|
|
9907
9919
|
}, [group.text]);
|
|
9908
|
-
return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React24.createElement(
|
|
9920
|
+
return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React24.createElement(
|
|
9921
|
+
"div",
|
|
9922
|
+
{
|
|
9923
|
+
className: `
|
|
9909
9924
|
flex flex-col gap-2 py-2 px-3 transition-all duration-200
|
|
9910
9925
|
${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
|
|
9911
|
-
`
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
|
|
9915
|
-
className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
|
|
9916
|
-
rows: 1,
|
|
9917
|
-
style: {
|
|
9918
|
-
minHeight: "1.5rem",
|
|
9919
|
-
maxHeight: "250px"
|
|
9920
|
-
},
|
|
9921
|
-
placeholder: canEdit ? "Escreva sobre este grupo..." : "",
|
|
9922
|
-
value: group.text,
|
|
9923
|
-
readOnly: !canEdit,
|
|
9924
|
-
onChange: (e) => {
|
|
9925
|
-
if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
|
|
9926
|
-
}
|
|
9927
|
-
}
|
|
9928
|
-
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
|
|
9929
|
-
const isValid = availableIds.has(String(anc.ancestry_id));
|
|
9930
|
-
return /* @__PURE__ */ React24.createElement(
|
|
9931
|
-
"div",
|
|
9926
|
+
`
|
|
9927
|
+
},
|
|
9928
|
+
/* @__PURE__ */ React24.createElement(
|
|
9929
|
+
"textarea",
|
|
9932
9930
|
{
|
|
9933
|
-
|
|
9934
|
-
className: `
|
|
9931
|
+
ref: textareaRef,
|
|
9932
|
+
className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
|
|
9933
|
+
rows: 1,
|
|
9934
|
+
style: {
|
|
9935
|
+
minHeight: "1.5rem",
|
|
9936
|
+
maxHeight: "250px"
|
|
9937
|
+
},
|
|
9938
|
+
placeholder: canEdit ? "Escreva sobre este grupo..." : "",
|
|
9939
|
+
value: group.text,
|
|
9940
|
+
readOnly: !canEdit,
|
|
9941
|
+
onChange: (e) => {
|
|
9942
|
+
if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
|
|
9943
|
+
}
|
|
9944
|
+
}
|
|
9945
|
+
),
|
|
9946
|
+
group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
|
|
9947
|
+
const isValid = availableIds.has(String(anc.ancestry_id));
|
|
9948
|
+
return /* @__PURE__ */ React24.createElement(
|
|
9949
|
+
"div",
|
|
9950
|
+
{
|
|
9951
|
+
key: anc.ancestry_id,
|
|
9952
|
+
className: `
|
|
9935
9953
|
flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
|
|
9936
9954
|
${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
|
|
9937
9955
|
`,
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9956
|
+
title: isValid ? "" : "Esta ancestralidade foi removida ou n\xE3o existe mais."
|
|
9957
|
+
},
|
|
9958
|
+
isValid ? (
|
|
9959
|
+
// [MANTIDO] Botão Play visível para todos
|
|
9960
|
+
/* @__PURE__ */ React24.createElement(
|
|
9961
|
+
"button",
|
|
9962
|
+
{
|
|
9963
|
+
onClick: () => onPlayAncestry(anc.ancestry_id),
|
|
9964
|
+
className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
|
|
9965
|
+
title: "Renderizar no cen\xE1rio"
|
|
9966
|
+
},
|
|
9967
|
+
/* @__PURE__ */ React24.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
|
|
9968
|
+
)
|
|
9969
|
+
) : /* @__PURE__ */ React24.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React24.createElement(FiAlertTriangle, { size: 10 })),
|
|
9942
9970
|
/* @__PURE__ */ React24.createElement(
|
|
9971
|
+
"span",
|
|
9972
|
+
{
|
|
9973
|
+
className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}`
|
|
9974
|
+
},
|
|
9975
|
+
anc.name
|
|
9976
|
+
),
|
|
9977
|
+
canEdit && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
|
|
9978
|
+
"div",
|
|
9979
|
+
{
|
|
9980
|
+
className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}`
|
|
9981
|
+
}
|
|
9982
|
+
), /* @__PURE__ */ React24.createElement(
|
|
9943
9983
|
"button",
|
|
9944
9984
|
{
|
|
9945
|
-
onClick: () =>
|
|
9946
|
-
className: "text-
|
|
9947
|
-
title: "
|
|
9985
|
+
onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
|
|
9986
|
+
className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
|
|
9987
|
+
title: "Remover men\xE7\xE3o"
|
|
9948
9988
|
},
|
|
9949
|
-
/* @__PURE__ */ React24.createElement(
|
|
9950
|
-
)
|
|
9951
|
-
)
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
title: "Remover men\xE7\xE3o"
|
|
9959
|
-
},
|
|
9960
|
-
/* @__PURE__ */ React24.createElement(FiX7, { size: 12 })
|
|
9961
|
-
))
|
|
9962
|
-
);
|
|
9963
|
-
})), canEdit && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
9964
|
-
"button",
|
|
9965
|
-
{
|
|
9966
|
-
onClick: () => onRequestPickAncestry(group.id),
|
|
9967
|
-
className: `
|
|
9989
|
+
/* @__PURE__ */ React24.createElement(FiX7, { size: 12 })
|
|
9990
|
+
))
|
|
9991
|
+
);
|
|
9992
|
+
})),
|
|
9993
|
+
canEdit && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
9994
|
+
"button",
|
|
9995
|
+
{
|
|
9996
|
+
onClick: () => onRequestPickAncestry(group.id),
|
|
9997
|
+
className: `
|
|
9968
9998
|
flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors
|
|
9969
9999
|
${isPickingForThisGroup ? "text-indigo-300 animate-pulse" : "text-slate-500 hover:text-indigo-300 hover:bg-indigo-500/10"}
|
|
9970
10000
|
`,
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
9984
|
-
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
|
|
9988
|
-
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10001
|
+
title: "Adicionar Ancestralidade a este grupo"
|
|
10002
|
+
},
|
|
10003
|
+
isPickingForThisGroup ? /* @__PURE__ */ React24.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React24.createElement(FiSearch4, { size: 12 }),
|
|
10004
|
+
isPickingForThisGroup ? "Selecionando..." : "Adicionar"
|
|
10005
|
+
), /* @__PURE__ */ React24.createElement(
|
|
10006
|
+
"button",
|
|
10007
|
+
{
|
|
10008
|
+
onClick: () => onAddSubgroup(group.id),
|
|
10009
|
+
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
10010
|
+
title: "Criar Subgrupo"
|
|
10011
|
+
},
|
|
10012
|
+
/* @__PURE__ */ React24.createElement(FiPlus9, { size: 14 })
|
|
10013
|
+
)), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
10014
|
+
"button",
|
|
10015
|
+
{
|
|
10016
|
+
onClick: () => onIndent(group.id),
|
|
10017
|
+
disabled: !canIndent,
|
|
10018
|
+
className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
|
|
10019
|
+
title: "Aninhar no grupo acima"
|
|
10020
|
+
},
|
|
10021
|
+
/* @__PURE__ */ React24.createElement(FiArrowRight, { size: 14 })
|
|
10022
|
+
), /* @__PURE__ */ React24.createElement(
|
|
10023
|
+
"button",
|
|
10024
|
+
{
|
|
10025
|
+
onClick: () => onOutdent(group.id),
|
|
10026
|
+
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
10027
|
+
title: "Desaninhar"
|
|
10028
|
+
},
|
|
10029
|
+
/* @__PURE__ */ React24.createElement(FiArrowLeft3, { size: 14 })
|
|
10030
|
+
), /* @__PURE__ */ React24.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement(
|
|
10031
|
+
"button",
|
|
10032
|
+
{
|
|
10033
|
+
onClick: () => onDelete(group.id),
|
|
10034
|
+
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
|
|
10035
|
+
title: "Remover Grupo"
|
|
10036
|
+
},
|
|
10037
|
+
/* @__PURE__ */ React24.createElement(FiTrash23, { size: 14 })
|
|
10038
|
+
)))
|
|
10039
|
+
), group.children && group.children.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React24.createElement(
|
|
10009
10040
|
GroupItem,
|
|
10010
10041
|
{
|
|
10011
10042
|
key: childGroup.id,
|
|
@@ -10214,7 +10245,9 @@ function AncestryBoard({
|
|
|
10214
10245
|
const addRecursive = (list) => {
|
|
10215
10246
|
return list.map((g) => {
|
|
10216
10247
|
if (g.id === pickingGroupId) {
|
|
10217
|
-
const exists = g.ancestries.some(
|
|
10248
|
+
const exists = g.ancestries.some(
|
|
10249
|
+
(a) => a.ancestry_id === ancestry.ancestry_id
|
|
10250
|
+
);
|
|
10218
10251
|
if (exists) return g;
|
|
10219
10252
|
return { ...g, ancestries: [...g.ancestries, ancestry] };
|
|
10220
10253
|
}
|
|
@@ -10225,12 +10258,16 @@ function AncestryBoard({
|
|
|
10225
10258
|
});
|
|
10226
10259
|
setPickingGroupId(null);
|
|
10227
10260
|
} else {
|
|
10228
|
-
const fullAncestry = availableAncestries.find(
|
|
10261
|
+
const fullAncestry = availableAncestries.find(
|
|
10262
|
+
(a) => a.ancestry_id === ancestry.ancestry_id
|
|
10263
|
+
) || ancestry;
|
|
10229
10264
|
onSelect(fullAncestry);
|
|
10230
10265
|
}
|
|
10231
10266
|
};
|
|
10232
10267
|
const handlePlayFromGroup = (ancestryId) => {
|
|
10233
|
-
const fullAncestry = availableAncestries.find(
|
|
10268
|
+
const fullAncestry = availableAncestries.find(
|
|
10269
|
+
(a) => a.ancestry_id === ancestryId
|
|
10270
|
+
);
|
|
10234
10271
|
if (fullAncestry && onSelect) {
|
|
10235
10272
|
onSelect(fullAncestry);
|
|
10236
10273
|
}
|
|
@@ -10240,7 +10277,12 @@ function AncestryBoard({
|
|
|
10240
10277
|
const removeRecursive = (list) => {
|
|
10241
10278
|
return list.map((g) => {
|
|
10242
10279
|
if (g.id === groupId) {
|
|
10243
|
-
return {
|
|
10280
|
+
return {
|
|
10281
|
+
...g,
|
|
10282
|
+
ancestries: g.ancestries.filter(
|
|
10283
|
+
(a) => a.ancestry_id !== ancestryId
|
|
10284
|
+
)
|
|
10285
|
+
};
|
|
10244
10286
|
}
|
|
10245
10287
|
return { ...g, children: removeRecursive(g.children) };
|
|
10246
10288
|
});
|
|
@@ -10261,7 +10303,13 @@ function AncestryBoard({
|
|
|
10261
10303
|
className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
|
|
10262
10304
|
onClick: (e) => e.stopPropagation()
|
|
10263
10305
|
},
|
|
10264
|
-
/* @__PURE__ */ React24.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React24.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React24.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
|
|
10306
|
+
/* @__PURE__ */ React24.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React24.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React24.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(
|
|
10307
|
+
FiLoader5,
|
|
10308
|
+
{
|
|
10309
|
+
className: "animate-spin text-indigo-400",
|
|
10310
|
+
size: 12
|
|
10311
|
+
}
|
|
10312
|
+
), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ React24.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ React24.createElement(
|
|
10265
10313
|
"button",
|
|
10266
10314
|
{
|
|
10267
10315
|
onClick: handleAddRootGroup,
|
|
@@ -10277,57 +10325,75 @@ function AncestryBoard({
|
|
|
10277
10325
|
},
|
|
10278
10326
|
"\xD7"
|
|
10279
10327
|
))),
|
|
10280
|
-
/* @__PURE__ */ React24.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React24.createElement(
|
|
10328
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React24.createElement(
|
|
10329
|
+
"div",
|
|
10330
|
+
{
|
|
10331
|
+
className: `
|
|
10281
10332
|
flex flex-col border-r border-white/10 transition-all duration-300 flex-none
|
|
10282
10333
|
${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
|
|
10283
10334
|
min-w-[280px] max-w-[500px] bg-slate-900
|
|
10284
|
-
`
|
|
10285
|
-
|
|
10286
|
-
{
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
10335
|
+
`
|
|
10336
|
+
},
|
|
10337
|
+
/* @__PURE__ */ React24.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React24.createElement("div", { className: "relative group" }, /* @__PURE__ */ React24.createElement(
|
|
10338
|
+
FiSearch4,
|
|
10339
|
+
{
|
|
10340
|
+
className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}`
|
|
10341
|
+
}
|
|
10342
|
+
), /* @__PURE__ */ React24.createElement(
|
|
10343
|
+
"input",
|
|
10344
|
+
{
|
|
10345
|
+
type: "text",
|
|
10346
|
+
placeholder: pickingGroupId ? "Pesquise para adicionar..." : "Pesquisar ancestralidade...",
|
|
10347
|
+
className: `
|
|
10290
10348
|
w-full rounded-md pl-9 pr-4 py-2 text-sm transition-all focus:outline-none focus:ring-1 focus:ring-indigo-500 border
|
|
10291
10349
|
${pickingGroupId ? "bg-indigo-950/30 border-indigo-500/30 text-white placeholder-indigo-300/50" : "bg-slate-950 border-white/10 text-slate-200 placeholder-slate-600"}
|
|
10292
10350
|
`,
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
|
|
10302
|
-
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
|
|
10307
|
-
|
|
10351
|
+
value: searchTerm,
|
|
10352
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
10353
|
+
autoFocus: !pickingGroupId
|
|
10354
|
+
}
|
|
10355
|
+
))),
|
|
10356
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
|
|
10357
|
+
const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
|
|
10358
|
+
const isPicking = !!pickingGroupId;
|
|
10359
|
+
return /* @__PURE__ */ React24.createElement(
|
|
10360
|
+
"div",
|
|
10361
|
+
{
|
|
10362
|
+
key: anc.ancestry_id,
|
|
10363
|
+
onClick: () => {
|
|
10364
|
+
if (isPicking) handleSelectAncestry(anc);
|
|
10365
|
+
},
|
|
10366
|
+
className: `
|
|
10308
10367
|
group relative flex items-start gap-3 p-3 text-left rounded-lg border transition-all duration-200
|
|
10309
10368
|
${isPicking ? "border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer" : "border-white/5 bg-slate-800/40 hover:bg-indigo-600/10 hover:border-indigo-500/30 cursor-default"}
|
|
10310
10369
|
`
|
|
10311
|
-
|
|
10312
|
-
|
|
10370
|
+
},
|
|
10371
|
+
/* @__PURE__ */ React24.createElement(
|
|
10372
|
+
"div",
|
|
10373
|
+
{
|
|
10374
|
+
className: `
|
|
10313
10375
|
mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
|
|
10314
10376
|
${isPicking ? "bg-indigo-500 text-white border-indigo-400" : "bg-slate-800 text-indigo-400 border-white/5 group-hover:bg-indigo-500 group-hover:text-white"}
|
|
10315
|
-
`
|
|
10316
|
-
/* @__PURE__ */ React24.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React24.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React24.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React24.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React24.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React24.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
|
|
10317
|
-
!isPicking && /* @__PURE__ */ React24.createElement(
|
|
10318
|
-
"button",
|
|
10319
|
-
{
|
|
10320
|
-
onClick: (e) => {
|
|
10321
|
-
e.stopPropagation();
|
|
10322
|
-
handleSelectAncestry(anc);
|
|
10377
|
+
`
|
|
10323
10378
|
},
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
},
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10379
|
+
isPicking ? /* @__PURE__ */ React24.createElement(FiPlus9, { size: 16 }) : /* @__PURE__ */ React24.createElement(FiLayers6, { size: 14 })
|
|
10380
|
+
),
|
|
10381
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React24.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React24.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React24.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React24.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React24.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
|
|
10382
|
+
!isPicking && /* @__PURE__ */ React24.createElement(
|
|
10383
|
+
"button",
|
|
10384
|
+
{
|
|
10385
|
+
onClick: (e) => {
|
|
10386
|
+
e.stopPropagation();
|
|
10387
|
+
handleSelectAncestry(anc);
|
|
10388
|
+
},
|
|
10389
|
+
className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
|
|
10390
|
+
title: "Renderizar Ancestralidade"
|
|
10391
|
+
},
|
|
10392
|
+
/* @__PURE__ */ React24.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React24.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
|
|
10393
|
+
)
|
|
10394
|
+
);
|
|
10395
|
+
}))
|
|
10396
|
+
), /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React24.createElement(FiLayers6, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React24.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React24.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React24.createElement(
|
|
10331
10397
|
GroupItem,
|
|
10332
10398
|
{
|
|
10333
10399
|
key: group.id,
|
|
@@ -10406,7 +10472,10 @@ var findNodePath3 = (tree, targetNodeId, currentPath = []) => {
|
|
|
10406
10472
|
}
|
|
10407
10473
|
if (tree.children) {
|
|
10408
10474
|
for (let i = 0; i < tree.children.length; i++) {
|
|
10409
|
-
const res = findNodePath3(tree.children[i], targetNodeId, [
|
|
10475
|
+
const res = findNodePath3(tree.children[i], targetNodeId, [
|
|
10476
|
+
...currentPath,
|
|
10477
|
+
i
|
|
10478
|
+
]);
|
|
10410
10479
|
if (res) return res;
|
|
10411
10480
|
}
|
|
10412
10481
|
}
|
|
@@ -10499,27 +10568,70 @@ function XViewScene({
|
|
|
10499
10568
|
const [userPermissionRole, setUserPermissionRole] = useState25(null);
|
|
10500
10569
|
const [isInitialized, setIsInitialized] = useState25(false);
|
|
10501
10570
|
const [sceneVersion, setSceneVersion] = useState25(0);
|
|
10502
|
-
const [contextMenu, setContextMenu] = useState25({
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10571
|
+
const [contextMenu, setContextMenu] = useState25({
|
|
10572
|
+
visible: false,
|
|
10573
|
+
x: 0,
|
|
10574
|
+
y: 0,
|
|
10575
|
+
nodeData: null
|
|
10576
|
+
});
|
|
10577
|
+
const [multiContextMenu, setMultiContextMenu] = useState25({
|
|
10578
|
+
visible: false,
|
|
10579
|
+
x: 0,
|
|
10580
|
+
y: 0,
|
|
10581
|
+
nodeIds: null
|
|
10582
|
+
});
|
|
10583
|
+
const [relationshipMenu, setRelationshipMenu] = useState25({
|
|
10584
|
+
visible: false,
|
|
10585
|
+
x: 0,
|
|
10586
|
+
y: 0,
|
|
10587
|
+
linkObject: null
|
|
10588
|
+
});
|
|
10589
|
+
const [creationMode, setCreationMode] = useState25({
|
|
10590
|
+
isActive: false,
|
|
10591
|
+
sourceNodeData: null
|
|
10592
|
+
});
|
|
10593
|
+
const [versionMode, setVersionMode] = useState25({
|
|
10594
|
+
isActive: false,
|
|
10595
|
+
sourceNodeData: null
|
|
10596
|
+
});
|
|
10507
10597
|
const [questMode, setQuestMode] = useState25({ isActive: false });
|
|
10508
10598
|
const [hasFocusedInitial, setHasFocusedInitial] = useState25(false);
|
|
10509
10599
|
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState25(false);
|
|
10510
|
-
const [ancestryMode, setAncestryMode] = useState25({
|
|
10600
|
+
const [ancestryMode, setAncestryMode] = useState25({
|
|
10601
|
+
isActive: false,
|
|
10602
|
+
tree: null,
|
|
10603
|
+
selectedParentId: null,
|
|
10604
|
+
isEditMode: false,
|
|
10605
|
+
currentAncestryId: null,
|
|
10606
|
+
ancestryName: "",
|
|
10607
|
+
ancestryDescription: "",
|
|
10608
|
+
ancestryDescriptionSections: [],
|
|
10609
|
+
isAddingNodes: false
|
|
10610
|
+
});
|
|
10511
10611
|
const [readingMode, setReadingMode] = useState25({
|
|
10512
10612
|
isActive: false,
|
|
10513
10613
|
ancestry: null,
|
|
10514
10614
|
branchStack: [],
|
|
10515
10615
|
autoAbstraction: false
|
|
10516
10616
|
});
|
|
10517
|
-
const [formPosition, setFormPosition] = useState25({
|
|
10617
|
+
const [formPosition, setFormPosition] = useState25({
|
|
10618
|
+
left: 16,
|
|
10619
|
+
top: 16,
|
|
10620
|
+
opacity: 0
|
|
10621
|
+
});
|
|
10518
10622
|
const [detailsNode, setDetailsNode] = useState25(null);
|
|
10519
10623
|
const [detailsLink, setDetailsLink] = useState25(null);
|
|
10520
10624
|
const [ancestryLinkDetails, setAncestryLinkDetails] = useState25(null);
|
|
10521
|
-
const [imageViewer, setImageViewer] = useState25({
|
|
10522
|
-
|
|
10625
|
+
const [imageViewer, setImageViewer] = useState25({
|
|
10626
|
+
visible: false,
|
|
10627
|
+
images: [],
|
|
10628
|
+
startIndex: 0
|
|
10629
|
+
});
|
|
10630
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState25({
|
|
10631
|
+
visible: false,
|
|
10632
|
+
data: null,
|
|
10633
|
+
path: null
|
|
10634
|
+
});
|
|
10523
10635
|
const [isImportModalOpen, setIsImportModalOpen] = useState25(false);
|
|
10524
10636
|
const [importSuccessMessage, setImportSuccessMessage] = useState25("");
|
|
10525
10637
|
const [highlightedNodeId, setHighlightedNodeId] = useState25(null);
|
|
@@ -10559,8 +10671,23 @@ function XViewScene({
|
|
|
10559
10671
|
ghostElements: { node: null, line: null, aura: null },
|
|
10560
10672
|
creation: { isActive: false, sourceNodeData: null },
|
|
10561
10673
|
connection: { isActive: false, sourceNodeData: null, line: null },
|
|
10562
|
-
relink: {
|
|
10563
|
-
|
|
10674
|
+
relink: {
|
|
10675
|
+
isActive: false,
|
|
10676
|
+
end: null,
|
|
10677
|
+
fixedNodeId: null,
|
|
10678
|
+
originalLine: null,
|
|
10679
|
+
line: null
|
|
10680
|
+
},
|
|
10681
|
+
ancestry: {
|
|
10682
|
+
isActive: false,
|
|
10683
|
+
tree: null,
|
|
10684
|
+
selectedParentId: null,
|
|
10685
|
+
isEditMode: false,
|
|
10686
|
+
currentAncestryId: null,
|
|
10687
|
+
ancestryName: "",
|
|
10688
|
+
ancestryDescription: "",
|
|
10689
|
+
isAddingNodes: false
|
|
10690
|
+
},
|
|
10564
10691
|
glowTexture: null,
|
|
10565
10692
|
nodeIdToParentFileMap: null,
|
|
10566
10693
|
maxAncestryRenderIndex: 0,
|
|
@@ -10569,7 +10696,11 @@ function XViewScene({
|
|
|
10569
10696
|
highlightedNodeId: null
|
|
10570
10697
|
});
|
|
10571
10698
|
const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
10572
|
-
const {
|
|
10699
|
+
const {
|
|
10700
|
+
width: readModeWidth,
|
|
10701
|
+
isResizing: isReadModeResizing,
|
|
10702
|
+
handlePointerDown: handleReadModeResize
|
|
10703
|
+
} = useResizablePanel({
|
|
10573
10704
|
initialWidth: 700,
|
|
10574
10705
|
minWidth: 320,
|
|
10575
10706
|
maxWidth: maxReadPanelW
|
|
@@ -10586,7 +10717,9 @@ function XViewScene({
|
|
|
10586
10717
|
for (const parentFileId in allParentData) {
|
|
10587
10718
|
if (allParentData.hasOwnProperty(parentFileId)) {
|
|
10588
10719
|
const parentFile = allParentData[parentFileId];
|
|
10589
|
-
const parentDbInfo = parentDbsArray.find(
|
|
10720
|
+
const parentDbInfo = parentDbsArray.find(
|
|
10721
|
+
(db) => String(db.db_id) === String(parentFileId)
|
|
10722
|
+
);
|
|
10590
10723
|
const ownerId2 = (parentDbInfo == null ? void 0 : parentDbInfo.owner_id) || null;
|
|
10591
10724
|
const datasetName = parentFile.dataset_name || `Dataset #${parentFileId.substring(0, 6)}`;
|
|
10592
10725
|
if (parentFile.nodes && ownerId2) {
|
|
@@ -10622,7 +10755,10 @@ function XViewScene({
|
|
|
10622
10755
|
if (files.length > 0 && get_single_parent_file && save_view_data) {
|
|
10623
10756
|
for (const file of files) {
|
|
10624
10757
|
try {
|
|
10625
|
-
const parentFileData = await get_single_parent_file(
|
|
10758
|
+
const parentFileData = await get_single_parent_file(
|
|
10759
|
+
file.id,
|
|
10760
|
+
session
|
|
10761
|
+
);
|
|
10626
10762
|
if (parentFileData.success && parentFileData.data) {
|
|
10627
10763
|
parentDataRef.current = {
|
|
10628
10764
|
...parentDataRef.current,
|
|
@@ -10633,7 +10769,11 @@ function XViewScene({
|
|
|
10633
10769
|
owner_id: session.user.id
|
|
10634
10770
|
};
|
|
10635
10771
|
updatedParentDbs.push(newParentDbObject);
|
|
10636
|
-
await add_new_parent_file_to_scene_at_firebase_action(
|
|
10772
|
+
await add_new_parent_file_to_scene_at_firebase_action(
|
|
10773
|
+
sceneConfigId,
|
|
10774
|
+
session,
|
|
10775
|
+
file.id
|
|
10776
|
+
);
|
|
10637
10777
|
importedIds.push(file.id);
|
|
10638
10778
|
successCount++;
|
|
10639
10779
|
}
|
|
@@ -10645,7 +10785,10 @@ function XViewScene({
|
|
|
10645
10785
|
if (viewToImport && get_ancestry_file) {
|
|
10646
10786
|
try {
|
|
10647
10787
|
const targetViewOwnerId = ((_b2 = (_a2 = viewToImport.members) == null ? void 0 : _a2.find((m) => m.permission === "owner")) == null ? void 0 : _b2.id) || session.user.id;
|
|
10648
|
-
const ancestryResponse = await get_ancestry_file(
|
|
10788
|
+
const ancestryResponse = await get_ancestry_file(
|
|
10789
|
+
viewToImport.id,
|
|
10790
|
+
targetViewOwnerId
|
|
10791
|
+
);
|
|
10649
10792
|
if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
|
|
10650
10793
|
const viewSpecificAncestries = ancestryResponse.data.filter(
|
|
10651
10794
|
(anc) => anc._source_file_id === viewToImport.id && !anc.is_private
|
|
@@ -10656,14 +10799,21 @@ function XViewScene({
|
|
|
10656
10799
|
_imported_from_view_owner_id: targetViewOwnerId,
|
|
10657
10800
|
_source_file_id: viewToImport.id,
|
|
10658
10801
|
_source_owner_id: targetViewOwnerId,
|
|
10659
|
-
_origin_db_ids: (viewToImport.selected_databases || []).map(
|
|
10802
|
+
_origin_db_ids: (viewToImport.selected_databases || []).map(
|
|
10803
|
+
(db) => db.db_id
|
|
10804
|
+
)
|
|
10660
10805
|
}));
|
|
10661
10806
|
const currentAncestries = ancestryDataRef.current || [];
|
|
10662
10807
|
const newAncestries = processedAncestries.filter(
|
|
10663
|
-
(newAnc) => !currentAncestries.some(
|
|
10808
|
+
(newAnc) => !currentAncestries.some(
|
|
10809
|
+
(curr) => String(curr.ancestry_id) === String(newAnc.ancestry_id)
|
|
10810
|
+
)
|
|
10664
10811
|
);
|
|
10665
10812
|
if (newAncestries.length > 0) {
|
|
10666
|
-
ancestryDataRef.current = [
|
|
10813
|
+
ancestryDataRef.current = [
|
|
10814
|
+
...currentAncestries,
|
|
10815
|
+
...newAncestries
|
|
10816
|
+
];
|
|
10667
10817
|
ancestriesWereImported = true;
|
|
10668
10818
|
}
|
|
10669
10819
|
}
|
|
@@ -10683,7 +10833,9 @@ function XViewScene({
|
|
|
10683
10833
|
if (ancestry_save_url) {
|
|
10684
10834
|
await save_view_data(ancestry_save_url, ancestryDataRef.current);
|
|
10685
10835
|
} else {
|
|
10686
|
-
console.error(
|
|
10836
|
+
console.error(
|
|
10837
|
+
"Erro: URL de salvamento de ancestralidade n\xE3o definida."
|
|
10838
|
+
);
|
|
10687
10839
|
}
|
|
10688
10840
|
}
|
|
10689
10841
|
setSceneVersion((v) => v + 1);
|
|
@@ -10691,113 +10843,136 @@ function XViewScene({
|
|
|
10691
10843
|
setImportSuccessMessage("Importa\xE7\xE3o conclu\xEDda com sucesso.");
|
|
10692
10844
|
setTimeout(() => setImportSuccessMessage(""), 5e3);
|
|
10693
10845
|
} else if (viewToImport && !ancestriesWereImported) {
|
|
10694
|
-
console.warn(
|
|
10846
|
+
console.warn(
|
|
10847
|
+
"Importa\xE7\xE3o finalizada, mas nenhum dado novo foi adicionado."
|
|
10848
|
+
);
|
|
10695
10849
|
}
|
|
10696
10850
|
},
|
|
10697
|
-
[
|
|
10851
|
+
[
|
|
10852
|
+
get_single_parent_file,
|
|
10853
|
+
get_ancestry_file,
|
|
10854
|
+
save_view_data,
|
|
10855
|
+
session,
|
|
10856
|
+
sceneSaveUrl,
|
|
10857
|
+
ancestry_save_url,
|
|
10858
|
+
sceneConfigId,
|
|
10859
|
+
add_new_parent_file_to_scene_at_firebase_action
|
|
10860
|
+
]
|
|
10698
10861
|
);
|
|
10699
10862
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
10700
10863
|
setImageViewer({ visible: true, images, startIndex });
|
|
10701
10864
|
};
|
|
10702
|
-
const tweenToTarget = useCallback4(
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10865
|
+
const tweenToTarget = useCallback4(
|
|
10866
|
+
(target, zoomFactor = 1, forcedDirection = null) => {
|
|
10867
|
+
const { camera, controls, tweenGroup } = stateRef.current;
|
|
10868
|
+
if (!camera || !controls || !tweenGroup) return;
|
|
10869
|
+
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
10870
|
+
const controlsTween = new Tween2(controls.target).to(targetPos, 1500).easing(Easing2.Cubic.Out);
|
|
10871
|
+
tweenGroup.add(controlsTween);
|
|
10872
|
+
controlsTween.start();
|
|
10873
|
+
let offset;
|
|
10874
|
+
if (forcedDirection) {
|
|
10875
|
+
offset = forcedDirection.clone().normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
|
|
10876
|
+
} else {
|
|
10877
|
+
offset = camera.position.clone().sub(controls.target).normalize().multiplyScalar(x_view_config.CAMERA_ZOOM_DISTANCE / zoomFactor);
|
|
10878
|
+
}
|
|
10879
|
+
const targetCameraPos = targetPos.clone().add(offset);
|
|
10880
|
+
const cameraTween = new Tween2(camera.position).to(targetCameraPos, 1500).easing(Easing2.Cubic.Out);
|
|
10881
|
+
tweenGroup.add(cameraTween);
|
|
10882
|
+
cameraTween.start();
|
|
10883
|
+
},
|
|
10884
|
+
[]
|
|
10885
|
+
);
|
|
10720
10886
|
const isFromUiOverlay = (event) => {
|
|
10721
10887
|
const t = event == null ? void 0 : event.target;
|
|
10722
10888
|
if (!t || typeof t.closest !== "function") return false;
|
|
10723
10889
|
return !!t.closest(".ui-overlay");
|
|
10724
10890
|
};
|
|
10725
|
-
const buildFullAncestryTree = useCallback4(
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
};
|
|
10736
|
-
}
|
|
10737
|
-
let nodeId = treeItem.node_id;
|
|
10738
|
-
if (!nodeId && treeItem.node) nodeId = treeItem.node.id;
|
|
10739
|
-
const fullNode = nodeMap.get(String(nodeId));
|
|
10740
|
-
const effectiveNode = fullNode || treeItem.node;
|
|
10741
|
-
let processedBranches = [];
|
|
10742
|
-
if (treeItem.parallel_branches && Array.isArray(treeItem.parallel_branches)) {
|
|
10743
|
-
processedBranches = treeItem.parallel_branches.map((branch) => {
|
|
10744
|
-
if (branch.linked_ancestry_id) {
|
|
10745
|
-
const linkedAncestry = ancestryMap.get(String(branch.linked_ancestry_id));
|
|
10746
|
-
if (linkedAncestry && linkedAncestry.tree) {
|
|
10747
|
-
const graftedTree = recursiveBuild(linkedAncestry.tree);
|
|
10748
|
-
return {
|
|
10749
|
-
...branch,
|
|
10750
|
-
name: linkedAncestry.name,
|
|
10751
|
-
description: linkedAncestry.description,
|
|
10752
|
-
description_sections: linkedAncestry.description_sections,
|
|
10753
|
-
tree: graftedTree,
|
|
10754
|
-
isLinked: true
|
|
10755
|
-
};
|
|
10756
|
-
}
|
|
10757
|
-
}
|
|
10891
|
+
const buildFullAncestryTree = useCallback4(
|
|
10892
|
+
(idTree, nodes, ancestries = []) => {
|
|
10893
|
+
if (!idTree) return null;
|
|
10894
|
+
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
10895
|
+
const ancestryMap = new Map(
|
|
10896
|
+
ancestries.map((a) => [String(a.ancestry_id), a])
|
|
10897
|
+
);
|
|
10898
|
+
const recursiveBuild = (treeItem) => {
|
|
10899
|
+
if (!treeItem) return null;
|
|
10900
|
+
if (treeItem.is_section) {
|
|
10758
10901
|
return {
|
|
10759
|
-
...
|
|
10760
|
-
|
|
10902
|
+
...treeItem,
|
|
10903
|
+
children: (treeItem.children || []).map(recursiveBuild).filter(Boolean)
|
|
10761
10904
|
};
|
|
10762
|
-
}
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
parallel_branches
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
return {
|
|
10786
|
-
...branch,
|
|
10787
|
-
name: linkedAncestry.name,
|
|
10788
|
-
description: linkedAncestry.description,
|
|
10789
|
-
description_sections: linkedAncestry.description_sections,
|
|
10790
|
-
tree: recursiveBuild(linkedAncestry.tree),
|
|
10791
|
-
isLinked: true
|
|
10792
|
-
};
|
|
10905
|
+
}
|
|
10906
|
+
let nodeId = treeItem.node_id;
|
|
10907
|
+
if (!nodeId && treeItem.node) nodeId = treeItem.node.id;
|
|
10908
|
+
const fullNode = nodeMap.get(String(nodeId));
|
|
10909
|
+
const effectiveNode = fullNode || treeItem.node;
|
|
10910
|
+
let processedBranches = [];
|
|
10911
|
+
if (treeItem.parallel_branches && Array.isArray(treeItem.parallel_branches)) {
|
|
10912
|
+
processedBranches = treeItem.parallel_branches.map((branch) => {
|
|
10913
|
+
if (branch.linked_ancestry_id) {
|
|
10914
|
+
const linkedAncestry = ancestryMap.get(
|
|
10915
|
+
String(branch.linked_ancestry_id)
|
|
10916
|
+
);
|
|
10917
|
+
if (linkedAncestry && linkedAncestry.tree) {
|
|
10918
|
+
const graftedTree = recursiveBuild(linkedAncestry.tree);
|
|
10919
|
+
return {
|
|
10920
|
+
...branch,
|
|
10921
|
+
name: linkedAncestry.name,
|
|
10922
|
+
description: linkedAncestry.description,
|
|
10923
|
+
description_sections: linkedAncestry.description_sections,
|
|
10924
|
+
tree: graftedTree,
|
|
10925
|
+
isLinked: true
|
|
10926
|
+
};
|
|
10927
|
+
}
|
|
10793
10928
|
}
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10929
|
+
return {
|
|
10930
|
+
...branch,
|
|
10931
|
+
tree: recursiveBuild(branch.tree)
|
|
10932
|
+
};
|
|
10933
|
+
});
|
|
10934
|
+
}
|
|
10935
|
+
return {
|
|
10936
|
+
...effectiveNode ? { node: effectiveNode } : { node: { id: nodeId, name: "Unknown" } },
|
|
10937
|
+
relationship: treeItem.relationship || {},
|
|
10938
|
+
children: (treeItem.children || []).map(recursiveBuild).filter(Boolean),
|
|
10939
|
+
parallel_branches: processedBranches
|
|
10940
|
+
};
|
|
10797
10941
|
};
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10942
|
+
let rootId = idTree.node_id;
|
|
10943
|
+
if (!rootId && idTree.node) rootId = idTree.node.id;
|
|
10944
|
+
if (rootId) {
|
|
10945
|
+
const rootNode = nodeMap.get(String(rootId));
|
|
10946
|
+
const effectiveRoot = rootNode || idTree.node;
|
|
10947
|
+
if (!effectiveRoot) return null;
|
|
10948
|
+
return {
|
|
10949
|
+
node: effectiveRoot,
|
|
10950
|
+
relationship: idTree.relationship || {},
|
|
10951
|
+
children: (idTree.children || []).map(recursiveBuild).filter(Boolean),
|
|
10952
|
+
parallel_branches: (idTree.parallel_branches || []).map((branch) => {
|
|
10953
|
+
if (branch.linked_ancestry_id) {
|
|
10954
|
+
const linkedAncestry = ancestryMap.get(
|
|
10955
|
+
String(branch.linked_ancestry_id)
|
|
10956
|
+
);
|
|
10957
|
+
if (linkedAncestry && linkedAncestry.tree) {
|
|
10958
|
+
return {
|
|
10959
|
+
...branch,
|
|
10960
|
+
name: linkedAncestry.name,
|
|
10961
|
+
description: linkedAncestry.description,
|
|
10962
|
+
description_sections: linkedAncestry.description_sections,
|
|
10963
|
+
tree: recursiveBuild(linkedAncestry.tree),
|
|
10964
|
+
isLinked: true
|
|
10965
|
+
};
|
|
10966
|
+
}
|
|
10967
|
+
}
|
|
10968
|
+
return { ...branch, tree: recursiveBuild(branch.tree) };
|
|
10969
|
+
})
|
|
10970
|
+
};
|
|
10971
|
+
}
|
|
10972
|
+
return recursiveBuild(idTree);
|
|
10973
|
+
},
|
|
10974
|
+
[]
|
|
10975
|
+
);
|
|
10801
10976
|
const handleActivateTimeline = useCallback4(() => {
|
|
10802
10977
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
10803
10978
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
@@ -10878,10 +11053,12 @@ function XViewScene({
|
|
|
10878
11053
|
if (timelineNodes.length === 0) return;
|
|
10879
11054
|
const sortedTimePoints = Array.from(allTimePoints).sort((a, b) => a - b);
|
|
10880
11055
|
const maxTimeIndex = sortedTimePoints.length - 1;
|
|
10881
|
-
const timeToYMap = new Map(
|
|
10882
|
-
time,
|
|
10883
|
-
|
|
10884
|
-
|
|
11056
|
+
const timeToYMap = new Map(
|
|
11057
|
+
sortedTimePoints.map((time, index) => [
|
|
11058
|
+
time,
|
|
11059
|
+
(index - maxTimeIndex) * TIMELINE_LAYER_SPACING_Y
|
|
11060
|
+
])
|
|
11061
|
+
);
|
|
10885
11062
|
timelineNodes.sort((a, b) => {
|
|
10886
11063
|
if (a.isUndated && b.isUndated) return 0;
|
|
10887
11064
|
if (a.isUndated) return 1;
|
|
@@ -10924,7 +11101,12 @@ function XViewScene({
|
|
|
10924
11101
|
if (type === "interval") {
|
|
10925
11102
|
const endY = timeToYMap.get(endDate.getTime());
|
|
10926
11103
|
if (endY > y) {
|
|
10927
|
-
const barGeometry = new THREE3.CylinderGeometry(
|
|
11104
|
+
const barGeometry = new THREE3.CylinderGeometry(
|
|
11105
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11106
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11107
|
+
1,
|
|
11108
|
+
16
|
|
11109
|
+
);
|
|
10928
11110
|
const barMaterial = new THREE3.MeshStandardMaterial({
|
|
10929
11111
|
color: TIMELINE_GOLD_COLOR,
|
|
10930
11112
|
emissive: 12092939,
|
|
@@ -10953,7 +11135,8 @@ function XViewScene({
|
|
|
10953
11135
|
}, []);
|
|
10954
11136
|
const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
|
|
10955
11137
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
10956
|
-
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
|
|
11138
|
+
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
|
|
11139
|
+
return;
|
|
10957
11140
|
versionMeshes.forEach((mesh) => {
|
|
10958
11141
|
const oldLabel = mesh.getObjectByName("timelineLabel");
|
|
10959
11142
|
if (oldLabel) {
|
|
@@ -10969,7 +11152,8 @@ function XViewScene({
|
|
|
10969
11152
|
}
|
|
10970
11153
|
if (mesh.userData.timelineEndLabel) {
|
|
10971
11154
|
timelineIntervalsGroup.remove(mesh.userData.timelineEndLabel);
|
|
10972
|
-
if (mesh.userData.timelineEndLabel.material.map)
|
|
11155
|
+
if (mesh.userData.timelineEndLabel.material.map)
|
|
11156
|
+
mesh.userData.timelineEndLabel.material.map.dispose();
|
|
10973
11157
|
mesh.userData.timelineEndLabel.material.dispose();
|
|
10974
11158
|
delete mesh.userData.timelineEndLabel;
|
|
10975
11159
|
}
|
|
@@ -11029,8 +11213,15 @@ function XViewScene({
|
|
|
11029
11213
|
});
|
|
11030
11214
|
if (timelineNodes.length === 0) return;
|
|
11031
11215
|
const sortedTimePoints = Array.from(allTimePoints).sort((a, b) => a - b);
|
|
11032
|
-
const timeToYMap = new Map(
|
|
11033
|
-
|
|
11216
|
+
const timeToYMap = new Map(
|
|
11217
|
+
sortedTimePoints.map((time, index) => [
|
|
11218
|
+
time,
|
|
11219
|
+
index * TIMELINE_LAYER_SPACING_Y
|
|
11220
|
+
])
|
|
11221
|
+
);
|
|
11222
|
+
timelineNodes.sort(
|
|
11223
|
+
(a, b) => a.startDate - b.startDate || a.endDate - b.endDate
|
|
11224
|
+
);
|
|
11034
11225
|
const baseX = sourceMesh.position.x + TIMELINE_NODE_SPACING_X;
|
|
11035
11226
|
const baseY = sourceMesh.position.y;
|
|
11036
11227
|
const maxNodeIndex = timelineNodes.length - 1;
|
|
@@ -11048,7 +11239,12 @@ function XViewScene({
|
|
|
11048
11239
|
if (type === "interval") {
|
|
11049
11240
|
const relativeEndY = timeToYMap.get(endDate.getTime()) - timeToYMap.get(startDate.getTime());
|
|
11050
11241
|
if (relativeEndY > 0) {
|
|
11051
|
-
const barGeometry = new THREE3.CylinderGeometry(
|
|
11242
|
+
const barGeometry = new THREE3.CylinderGeometry(
|
|
11243
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11244
|
+
TIMELINE_INTERVAL_BAR_RADIUS,
|
|
11245
|
+
1,
|
|
11246
|
+
16
|
|
11247
|
+
);
|
|
11052
11248
|
const barMaterial = new THREE3.MeshStandardMaterial({
|
|
11053
11249
|
color: TIMELINE_GOLD_COLOR,
|
|
11054
11250
|
emissive: 12092939,
|
|
@@ -11085,15 +11281,31 @@ function XViewScene({
|
|
|
11085
11281
|
try {
|
|
11086
11282
|
const typeStr = (viewParams == null ? void 0 : viewParams.type) || "";
|
|
11087
11283
|
const sceneType = typeStr.toLowerCase().includes("database") ? "database" : "view";
|
|
11088
|
-
const scenePromise = get_scene_view_data(
|
|
11284
|
+
const scenePromise = get_scene_view_data(
|
|
11285
|
+
configPath,
|
|
11286
|
+
ownerId2,
|
|
11287
|
+
typeStr,
|
|
11288
|
+
session,
|
|
11289
|
+
focusNodeId,
|
|
11290
|
+
focusAncestryId
|
|
11291
|
+
);
|
|
11089
11292
|
const boardPromise = get_ancestry_board_action && session ? get_ancestry_board_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
|
|
11090
|
-
const [sceneResponse, boardResponse] = await Promise.all([
|
|
11293
|
+
const [sceneResponse, boardResponse] = await Promise.all([
|
|
11294
|
+
scenePromise,
|
|
11295
|
+
boardPromise
|
|
11296
|
+
]);
|
|
11091
11297
|
if ((sceneResponse == null ? void 0 : sceneResponse.success) && ((_a2 = sceneResponse.data) == null ? void 0 : _a2.scene) && ((_b2 = sceneResponse.data) == null ? void 0 : _b2.parent)) {
|
|
11092
11298
|
if (focusNodeId) {
|
|
11093
|
-
let targetNode = sceneResponse.data.scene.nodes.find(
|
|
11299
|
+
let targetNode = sceneResponse.data.scene.nodes.find(
|
|
11300
|
+
(n) => String(n.id) === String(focusNodeId)
|
|
11301
|
+
);
|
|
11094
11302
|
if (!targetNode) {
|
|
11095
|
-
const allParentNodes = Object.values(
|
|
11096
|
-
|
|
11303
|
+
const allParentNodes = Object.values(
|
|
11304
|
+
sceneResponse.data.parent
|
|
11305
|
+
).flatMap((f) => f.nodes || []);
|
|
11306
|
+
targetNode = allParentNodes.find(
|
|
11307
|
+
(n) => String(n.id) === String(focusNodeId)
|
|
11308
|
+
);
|
|
11097
11309
|
}
|
|
11098
11310
|
if (targetNode) {
|
|
11099
11311
|
sceneResponse.data.scene.nodes = [targetNode];
|
|
@@ -11106,12 +11318,24 @@ function XViewScene({
|
|
|
11106
11318
|
sceneDataRef.current = sceneResponse.data.scene;
|
|
11107
11319
|
parentDataRef.current = sceneResponse.data.parent;
|
|
11108
11320
|
ancestryDataRef.current = sceneResponse.data.ancestry;
|
|
11109
|
-
console.log(
|
|
11110
|
-
|
|
11111
|
-
|
|
11321
|
+
console.log(
|
|
11322
|
+
"Console de sceneResponse.data.scene:",
|
|
11323
|
+
sceneResponse.data.scene
|
|
11324
|
+
);
|
|
11325
|
+
console.log(
|
|
11326
|
+
"Console de sceneResponse.data.parent:",
|
|
11327
|
+
sceneResponse.data.parent
|
|
11328
|
+
);
|
|
11329
|
+
console.log(
|
|
11330
|
+
"Console de sceneResponse.data.ancestry:",
|
|
11331
|
+
sceneResponse.data.ancestry
|
|
11332
|
+
);
|
|
11112
11333
|
setIsInitialized(true);
|
|
11113
11334
|
} else {
|
|
11114
|
-
console.error(
|
|
11335
|
+
console.error(
|
|
11336
|
+
"Falha ao buscar dados da cena:",
|
|
11337
|
+
(sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida."
|
|
11338
|
+
);
|
|
11115
11339
|
}
|
|
11116
11340
|
if (boardResponse == null ? void 0 : boardResponse.success) {
|
|
11117
11341
|
setAncestryBoardData(boardResponse.data);
|
|
@@ -11130,7 +11354,9 @@ function XViewScene({
|
|
|
11130
11354
|
console.error("Usu\xE1rio n\xE3o autenticado. Acesso negado.");
|
|
11131
11355
|
setIsLoading(false);
|
|
11132
11356
|
} else if (!sceneConfigId && status !== "loading") {
|
|
11133
|
-
console.warn(
|
|
11357
|
+
console.warn(
|
|
11358
|
+
"Nenhum par\xE2metro de cena encontrado na URL ou falha na decripta\xE7\xE3o."
|
|
11359
|
+
);
|
|
11134
11360
|
setIsLoading(false);
|
|
11135
11361
|
}
|
|
11136
11362
|
}, [
|
|
@@ -11151,33 +11377,46 @@ function XViewScene({
|
|
|
11151
11377
|
const objs = stateRef.current.nodeObjects || {};
|
|
11152
11378
|
return !!objs[key];
|
|
11153
11379
|
}, []);
|
|
11154
|
-
const addOrUpdateNodeMesh = useCallback4(
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
tweenGroup
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11380
|
+
const addOrUpdateNodeMesh = useCallback4(
|
|
11381
|
+
(nodeData, position, suppressVersionUpdate = false) => {
|
|
11382
|
+
const {
|
|
11383
|
+
graphGroup,
|
|
11384
|
+
nodeObjects,
|
|
11385
|
+
clickableNodes,
|
|
11386
|
+
glowTexture,
|
|
11387
|
+
tweenGroup
|
|
11388
|
+
} = stateRef.current;
|
|
11389
|
+
const nodeId = String(nodeData.id);
|
|
11390
|
+
if (nodeObjects[nodeId]) {
|
|
11391
|
+
const existingMesh = nodeObjects[nodeId];
|
|
11392
|
+
if (position) {
|
|
11393
|
+
const updateTween = new Tween2(existingMesh.position).to(position, 800).easing(Easing2.Cubic.Out);
|
|
11394
|
+
tweenGroup.add(updateTween);
|
|
11395
|
+
updateTween.start();
|
|
11396
|
+
}
|
|
11397
|
+
return existingMesh;
|
|
11398
|
+
}
|
|
11399
|
+
const mesh = createNodeMesh(
|
|
11400
|
+
nodeData,
|
|
11401
|
+
position || new THREE3.Vector3(),
|
|
11402
|
+
glowTexture
|
|
11403
|
+
);
|
|
11404
|
+
graphGroup.add(mesh);
|
|
11405
|
+
if (mesh.userData.labelObject) {
|
|
11406
|
+
if (mesh.userData.labelOffset) {
|
|
11407
|
+
mesh.userData.labelObject.position.copy(mesh.position).add(mesh.userData.labelOffset);
|
|
11408
|
+
}
|
|
11409
|
+
graphGroup.add(mesh.userData.labelObject);
|
|
11171
11410
|
}
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
}
|
|
11179
|
-
|
|
11180
|
-
|
|
11411
|
+
nodeObjects[nodeId] = mesh;
|
|
11412
|
+
clickableNodes.push(mesh);
|
|
11413
|
+
if (!suppressVersionUpdate) {
|
|
11414
|
+
setSceneVersion((v) => v + 1);
|
|
11415
|
+
}
|
|
11416
|
+
return mesh;
|
|
11417
|
+
},
|
|
11418
|
+
[]
|
|
11419
|
+
);
|
|
11181
11420
|
useEffect22(() => {
|
|
11182
11421
|
if (!isInitialized || !sceneDataRef.current) return;
|
|
11183
11422
|
const currentMount = mountRef.current;
|
|
@@ -11192,7 +11431,12 @@ function XViewScene({
|
|
|
11192
11431
|
const scene = new THREE3.Scene();
|
|
11193
11432
|
scene.background = new THREE3.Color(0);
|
|
11194
11433
|
stateRef.current.scene = scene;
|
|
11195
|
-
const camera = new THREE3.PerspectiveCamera(
|
|
11434
|
+
const camera = new THREE3.PerspectiveCamera(
|
|
11435
|
+
75,
|
|
11436
|
+
currentMount.clientWidth / currentMount.clientHeight,
|
|
11437
|
+
0.1,
|
|
11438
|
+
2e3
|
|
11439
|
+
);
|
|
11196
11440
|
camera.position.set(0, 60, 120);
|
|
11197
11441
|
stateRef.current.camera = camera;
|
|
11198
11442
|
const renderer = new THREE3.WebGLRenderer({ antialias: true });
|
|
@@ -11213,7 +11457,12 @@ function XViewScene({
|
|
|
11213
11457
|
directionalLight.position.set(50, 50, 50);
|
|
11214
11458
|
scene.add(directionalLight);
|
|
11215
11459
|
const renderScene = new RenderPass(scene, camera);
|
|
11216
|
-
const bloomPass = new UnrealBloomPass(
|
|
11460
|
+
const bloomPass = new UnrealBloomPass(
|
|
11461
|
+
new THREE3.Vector2(currentMount.clientWidth, currentMount.clientHeight),
|
|
11462
|
+
x_view_config.BLOOM_EFFECT.strength,
|
|
11463
|
+
x_view_config.BLOOM_EFFECT.radius,
|
|
11464
|
+
x_view_config.BLOOM_EFFECT.threshold
|
|
11465
|
+
);
|
|
11217
11466
|
const composer = new EffectComposer(renderer);
|
|
11218
11467
|
composer.addPass(renderScene);
|
|
11219
11468
|
composer.addPass(bloomPass);
|
|
@@ -11256,8 +11505,16 @@ function XViewScene({
|
|
|
11256
11505
|
const sourceNode = nodeObjects[String(linksArray[0].source)];
|
|
11257
11506
|
const targetNode = nodeObjects[String(linksArray[0].target)];
|
|
11258
11507
|
if (sourceNode && targetNode) {
|
|
11259
|
-
const resolution = new THREE3.Vector2(
|
|
11260
|
-
|
|
11508
|
+
const resolution = new THREE3.Vector2(
|
|
11509
|
+
currentMount.clientWidth,
|
|
11510
|
+
currentMount.clientHeight
|
|
11511
|
+
);
|
|
11512
|
+
const newLinks = createMultipleLinkLines(
|
|
11513
|
+
linksArray,
|
|
11514
|
+
sourceNode,
|
|
11515
|
+
targetNode,
|
|
11516
|
+
resolution
|
|
11517
|
+
);
|
|
11261
11518
|
newLinks.forEach((line, idx) => {
|
|
11262
11519
|
const meta = linksArray[idx];
|
|
11263
11520
|
if (meta) {
|
|
@@ -11298,7 +11555,10 @@ function XViewScene({
|
|
|
11298
11555
|
function tryPickNode() {
|
|
11299
11556
|
raycaster.setFromCamera(mouse, camera);
|
|
11300
11557
|
raycaster.layers.enable(GHOST_BLOOM_LAYER);
|
|
11301
|
-
const intersects = raycaster.intersectObjects(
|
|
11558
|
+
const intersects = raycaster.intersectObjects(
|
|
11559
|
+
stateRef.current.clickableNodes,
|
|
11560
|
+
false
|
|
11561
|
+
);
|
|
11302
11562
|
return intersects.length > 0 ? intersects[0].object : null;
|
|
11303
11563
|
}
|
|
11304
11564
|
function findClosestLinkToRay() {
|
|
@@ -11310,7 +11570,10 @@ function XViewScene({
|
|
|
11310
11570
|
x: (mouse.x * 0.5 + 0.5) * clientWidth,
|
|
11311
11571
|
y: (-mouse.y * 0.5 + 0.5) * clientHeight
|
|
11312
11572
|
};
|
|
11313
|
-
const allVisibleLinks = [
|
|
11573
|
+
const allVisibleLinks = [
|
|
11574
|
+
...stateRef.current.allLinks,
|
|
11575
|
+
...stateRef.current.ancestryLinks
|
|
11576
|
+
];
|
|
11314
11577
|
const THRESH = x_view_config.LINE_HOVER_THRESHOLD_PX + 4;
|
|
11315
11578
|
const tmpP1 = new THREE3.Vector3();
|
|
11316
11579
|
const tmpP2 = new THREE3.Vector3();
|
|
@@ -11325,19 +11588,35 @@ function XViewScene({
|
|
|
11325
11588
|
const up = new THREE3.Vector3(0, 1, 0);
|
|
11326
11589
|
const normal = new THREE3.Vector3().crossVectors(dir, up).normalize();
|
|
11327
11590
|
const controlPoint = mid.add(normal.multiplyScalar(curveOffset || 0));
|
|
11328
|
-
const curve = new THREE3.QuadraticBezierCurve3(
|
|
11591
|
+
const curve = new THREE3.QuadraticBezierCurve3(
|
|
11592
|
+
start,
|
|
11593
|
+
controlPoint,
|
|
11594
|
+
end
|
|
11595
|
+
);
|
|
11329
11596
|
const points = curve.getPoints(x_view_config.CURVE_SEGMENTS || 32);
|
|
11330
11597
|
for (let i = 0; i < points.length - 1; i++) {
|
|
11331
11598
|
tmpP1.copy(points[i]).project(camera);
|
|
11332
11599
|
tmpP2.copy(points[i + 1]).project(camera);
|
|
11333
|
-
const p1_px = {
|
|
11334
|
-
|
|
11600
|
+
const p1_px = {
|
|
11601
|
+
x: (tmpP1.x * 0.5 + 0.5) * clientWidth,
|
|
11602
|
+
y: (-tmpP1.y * 0.5 + 0.5) * clientHeight
|
|
11603
|
+
};
|
|
11604
|
+
const p2_px = {
|
|
11605
|
+
x: (tmpP2.x * 0.5 + 0.5) * clientWidth,
|
|
11606
|
+
y: (-tmpP2.y * 0.5 + 0.5) * clientHeight
|
|
11607
|
+
};
|
|
11335
11608
|
const L2 = (p2_px.x - p1_px.x) ** 2 + (p2_px.y - p1_px.y) ** 2;
|
|
11336
11609
|
if (L2 === 0) continue;
|
|
11337
11610
|
let t = ((mousePixels.x - p1_px.x) * (p2_px.x - p1_px.x) + (mousePixels.y - p1_px.y) * (p2_px.y - p1_px.y)) / L2;
|
|
11338
11611
|
t = Math.max(0, Math.min(1, t));
|
|
11339
|
-
const closestPoint = {
|
|
11340
|
-
|
|
11612
|
+
const closestPoint = {
|
|
11613
|
+
x: p1_px.x + t * (p2_px.x - p1_px.x),
|
|
11614
|
+
y: p1_px.y + t * (p2_px.y - p1_px.y)
|
|
11615
|
+
};
|
|
11616
|
+
const dist = Math.hypot(
|
|
11617
|
+
mousePixels.x - closestPoint.x,
|
|
11618
|
+
mousePixels.y - closestPoint.y
|
|
11619
|
+
);
|
|
11341
11620
|
if (dist < THRESH && dist < minDistance) {
|
|
11342
11621
|
minDistance = dist;
|
|
11343
11622
|
closestLink = link;
|
|
@@ -11346,14 +11625,26 @@ function XViewScene({
|
|
|
11346
11625
|
} else {
|
|
11347
11626
|
const p1 = new THREE3.Vector3().copy(sourceNode.position).project(camera);
|
|
11348
11627
|
const p2 = new THREE3.Vector3().copy(targetNode.position).project(camera);
|
|
11349
|
-
const p1_px = {
|
|
11350
|
-
|
|
11628
|
+
const p1_px = {
|
|
11629
|
+
x: (p1.x * 0.5 + 0.5) * clientWidth,
|
|
11630
|
+
y: (-p1.y * 0.5 + 0.5) * clientHeight
|
|
11631
|
+
};
|
|
11632
|
+
const p2_px = {
|
|
11633
|
+
x: (p2.x * 0.5 + 0.5) * clientWidth,
|
|
11634
|
+
y: (-p2.y * 0.5 + 0.5) * clientHeight
|
|
11635
|
+
};
|
|
11351
11636
|
const L2 = (p2_px.x - p1_px.x) ** 2 + (p2_px.y - p1_px.y) ** 2;
|
|
11352
11637
|
if (L2 === 0) return;
|
|
11353
11638
|
let t = ((mousePixels.x - p1_px.x) * (p2_px.x - p1_px.x) + (mousePixels.y - p1_px.y) * (p2_px.y - p1_px.y)) / L2;
|
|
11354
11639
|
t = Math.max(0, Math.min(1, t));
|
|
11355
|
-
const closestPoint = {
|
|
11356
|
-
|
|
11640
|
+
const closestPoint = {
|
|
11641
|
+
x: p1_px.x + t * (p2_px.x - p1_px.x),
|
|
11642
|
+
y: p1_px.y + t * (p2_px.y - p1_px.y)
|
|
11643
|
+
};
|
|
11644
|
+
const dist = Math.hypot(
|
|
11645
|
+
mousePixels.x - closestPoint.x,
|
|
11646
|
+
mousePixels.y - closestPoint.y
|
|
11647
|
+
);
|
|
11357
11648
|
if (dist < THRESH && dist < minDistance) {
|
|
11358
11649
|
minDistance = dist;
|
|
11359
11650
|
closestLink = link;
|
|
@@ -11388,7 +11679,11 @@ function XViewScene({
|
|
|
11388
11679
|
if (picked && !stateRef.current.ancestry.isActive) {
|
|
11389
11680
|
stateRef.current.controls.enabled = false;
|
|
11390
11681
|
}
|
|
11391
|
-
stateRef.current.pointerDown = {
|
|
11682
|
+
stateRef.current.pointerDown = {
|
|
11683
|
+
isDown: true,
|
|
11684
|
+
x: event.clientX,
|
|
11685
|
+
y: event.clientY
|
|
11686
|
+
};
|
|
11392
11687
|
stateRef.current.dragCandidate = picked;
|
|
11393
11688
|
}
|
|
11394
11689
|
function onPointerMove(event) {
|
|
@@ -11399,7 +11694,10 @@ function XViewScene({
|
|
|
11399
11694
|
const raycaster2 = new THREE3.Raycaster();
|
|
11400
11695
|
raycaster2.setFromCamera(mouse, camera);
|
|
11401
11696
|
camera.getWorldDirection(plane.normal);
|
|
11402
|
-
plane.setFromNormalAndCoplanarPoint(
|
|
11697
|
+
plane.setFromNormalAndCoplanarPoint(
|
|
11698
|
+
plane.normal,
|
|
11699
|
+
stateRef.current.draggedNode.position
|
|
11700
|
+
);
|
|
11403
11701
|
if (raycaster2.ray.intersectPlane(plane, intersectionPoint)) {
|
|
11404
11702
|
const draggedNode = stateRef.current.draggedNode;
|
|
11405
11703
|
draggedNode.position.copy(intersectionPoint);
|
|
@@ -11408,7 +11706,8 @@ function XViewScene({
|
|
|
11408
11706
|
}
|
|
11409
11707
|
if (stateRef.current.connection.isActive || stateRef.current.relink.isActive || stateRef.current.ancestry.isActive) {
|
|
11410
11708
|
const newHoveredNode2 = tryPickNode();
|
|
11411
|
-
if (stateRef.current.hoveredNode !== newHoveredNode2)
|
|
11709
|
+
if (stateRef.current.hoveredNode !== newHoveredNode2)
|
|
11710
|
+
stateRef.current.hoveredNode = newHoveredNode2;
|
|
11412
11711
|
if (currentMount) {
|
|
11413
11712
|
let fixedId = null;
|
|
11414
11713
|
if (stateRef.current.connection.isActive) {
|
|
@@ -11439,14 +11738,20 @@ function XViewScene({
|
|
|
11439
11738
|
stateRef.current.controls.enabled = false;
|
|
11440
11739
|
if (currentMount) currentMount.style.cursor = "grabbing";
|
|
11441
11740
|
camera.getWorldDirection(plane.normal);
|
|
11442
|
-
plane.setFromNormalAndCoplanarPoint(
|
|
11741
|
+
plane.setFromNormalAndCoplanarPoint(
|
|
11742
|
+
plane.normal,
|
|
11743
|
+
stateRef.current.draggedNode.position
|
|
11744
|
+
);
|
|
11443
11745
|
}
|
|
11444
11746
|
}
|
|
11445
11747
|
const newHoveredNode = tryPickNode();
|
|
11446
11748
|
const newHoveredLink = !newHoveredNode ? findClosestLinkToRay() : null;
|
|
11447
|
-
if (stateRef.current.hoveredNode !== newHoveredNode)
|
|
11448
|
-
|
|
11449
|
-
if (
|
|
11749
|
+
if (stateRef.current.hoveredNode !== newHoveredNode)
|
|
11750
|
+
stateRef.current.hoveredNode = newHoveredNode;
|
|
11751
|
+
if (stateRef.current.hoveredLink !== newHoveredLink)
|
|
11752
|
+
stateRef.current.hoveredLink = newHoveredLink;
|
|
11753
|
+
if (currentMount)
|
|
11754
|
+
currentMount.style.cursor = newHoveredNode || newHoveredLink ? "pointer" : "grab";
|
|
11450
11755
|
}
|
|
11451
11756
|
const isNodeInTree = (tree, nodeId) => {
|
|
11452
11757
|
if (!tree) return false;
|
|
@@ -11461,7 +11766,10 @@ function XViewScene({
|
|
|
11461
11766
|
const context = actionHandlerContext;
|
|
11462
11767
|
if (connection.isActive) {
|
|
11463
11768
|
if (hoveredNode && String(hoveredNode.userData.id) !== String(connection.sourceNodeData.id)) {
|
|
11464
|
-
await userActionHandlers.handleCompleteConnection(
|
|
11769
|
+
await userActionHandlers.handleCompleteConnection(
|
|
11770
|
+
context,
|
|
11771
|
+
hoveredNode.userData
|
|
11772
|
+
);
|
|
11465
11773
|
} else {
|
|
11466
11774
|
userActionHandlers.handleCancelConnection(context);
|
|
11467
11775
|
}
|
|
@@ -11469,7 +11777,10 @@ function XViewScene({
|
|
|
11469
11777
|
}
|
|
11470
11778
|
if (relink.isActive) {
|
|
11471
11779
|
if (hoveredNode && String(hoveredNode.userData.id) !== String(relink.fixedNodeId)) {
|
|
11472
|
-
await userActionHandlers.handleCompleteRelink(
|
|
11780
|
+
await userActionHandlers.handleCompleteRelink(
|
|
11781
|
+
context,
|
|
11782
|
+
hoveredNode.userData
|
|
11783
|
+
);
|
|
11473
11784
|
} else {
|
|
11474
11785
|
userActionHandlers.handleCancelRelink(context);
|
|
11475
11786
|
}
|
|
@@ -11487,7 +11798,9 @@ function XViewScene({
|
|
|
11487
11798
|
const clickedNodeId = String(clickedNode.userData.id);
|
|
11488
11799
|
const parentId = String(currentSelectedParent);
|
|
11489
11800
|
if (clickedNodeId === parentId) {
|
|
11490
|
-
alert(
|
|
11801
|
+
alert(
|
|
11802
|
+
"Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo."
|
|
11803
|
+
);
|
|
11491
11804
|
return;
|
|
11492
11805
|
}
|
|
11493
11806
|
const parentInfo = stateRef.current.nodeIdToParentFileMap.get(clickedNodeId);
|
|
@@ -11497,16 +11810,33 @@ function XViewScene({
|
|
|
11497
11810
|
const addChildToNode = (current, targetParentId, childNode) => {
|
|
11498
11811
|
const currentId = current.is_section ? current.id || current.section_id : String(current.node.id);
|
|
11499
11812
|
if (String(currentId) === String(targetParentId)) {
|
|
11500
|
-
const alreadyExists = current.children.some(
|
|
11813
|
+
const alreadyExists = current.children.some(
|
|
11814
|
+
(child) => !child.is_section && String(child.node.id) === String(childNode.id)
|
|
11815
|
+
);
|
|
11501
11816
|
if (alreadyExists) return current;
|
|
11502
|
-
return {
|
|
11817
|
+
return {
|
|
11818
|
+
...current,
|
|
11819
|
+
children: [
|
|
11820
|
+
...current.children,
|
|
11821
|
+
{ node: childNode, children: [], relationship: {} }
|
|
11822
|
+
]
|
|
11823
|
+
};
|
|
11503
11824
|
}
|
|
11504
|
-
return {
|
|
11825
|
+
return {
|
|
11826
|
+
...current,
|
|
11827
|
+
children: current.children.map(
|
|
11828
|
+
(c) => addChildToNode(c, targetParentId, childNode)
|
|
11829
|
+
)
|
|
11830
|
+
};
|
|
11505
11831
|
};
|
|
11506
11832
|
setAncestryMode((prev) => {
|
|
11507
11833
|
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
11508
11834
|
if (!prev[treeKey]) return prev;
|
|
11509
|
-
const newTree = addChildToNode(
|
|
11835
|
+
const newTree = addChildToNode(
|
|
11836
|
+
prev[treeKey],
|
|
11837
|
+
parentId,
|
|
11838
|
+
fullNodeData
|
|
11839
|
+
);
|
|
11510
11840
|
return { ...prev, [treeKey]: newTree };
|
|
11511
11841
|
});
|
|
11512
11842
|
}
|
|
@@ -11520,7 +11850,8 @@ function XViewScene({
|
|
|
11520
11850
|
stateRef.current.dragCandidate = null;
|
|
11521
11851
|
stateRef.current.pointerDown.isDown = false;
|
|
11522
11852
|
stateRef.current.controls.enabled = true;
|
|
11523
|
-
if (currentMount)
|
|
11853
|
+
if (currentMount)
|
|
11854
|
+
currentMount.style.cursor = stateRef.current.hoveredNode || stateRef.current.hoveredLink ? "pointer" : "grab";
|
|
11524
11855
|
return;
|
|
11525
11856
|
}
|
|
11526
11857
|
const dragDistance = Math.hypot(
|
|
@@ -11568,16 +11899,21 @@ function XViewScene({
|
|
|
11568
11899
|
}
|
|
11569
11900
|
function handleDoubleClick(event) {
|
|
11570
11901
|
if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
|
|
11571
|
-
if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11572
|
-
|
|
11902
|
+
if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11903
|
+
return;
|
|
11904
|
+
if (stateRef.current.hoveredNode)
|
|
11905
|
+
tweenToTarget(stateRef.current.hoveredNode);
|
|
11573
11906
|
}
|
|
11574
11907
|
function handleContextMenu(event) {
|
|
11575
11908
|
if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
|
|
11576
11909
|
if (isFromUiOverlay(event)) return;
|
|
11577
11910
|
event.preventDefault();
|
|
11578
|
-
if (stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11911
|
+
if (stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive)
|
|
11912
|
+
return;
|
|
11579
11913
|
setMouseFromEvent(event);
|
|
11580
|
-
setContextMenu(
|
|
11914
|
+
setContextMenu(
|
|
11915
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
11916
|
+
);
|
|
11581
11917
|
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
11582
11918
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
11583
11919
|
const pickedNode = tryPickNode();
|
|
@@ -11608,7 +11944,12 @@ function XViewScene({
|
|
|
11608
11944
|
return;
|
|
11609
11945
|
}
|
|
11610
11946
|
stateRef.current.selectedNodes.clear();
|
|
11611
|
-
setRelationshipMenu({
|
|
11947
|
+
setRelationshipMenu({
|
|
11948
|
+
visible: true,
|
|
11949
|
+
x: event.clientX,
|
|
11950
|
+
y: event.clientY,
|
|
11951
|
+
linkObject: pickedLink
|
|
11952
|
+
});
|
|
11612
11953
|
return;
|
|
11613
11954
|
}
|
|
11614
11955
|
stateRef.current.selectedNodes.clear();
|
|
@@ -11640,7 +11981,10 @@ function XViewScene({
|
|
|
11640
11981
|
}
|
|
11641
11982
|
});
|
|
11642
11983
|
}
|
|
11643
|
-
const allRenderedLinks = [
|
|
11984
|
+
const allRenderedLinks = [
|
|
11985
|
+
...stateRef.current.allLinks,
|
|
11986
|
+
...stateRef.current.ancestryLinks
|
|
11987
|
+
];
|
|
11644
11988
|
allRenderedLinks.forEach((line) => {
|
|
11645
11989
|
const { sourceNode, targetNode, isCurved, curveOffset } = line.userData;
|
|
11646
11990
|
if (sourceNode && targetNode) {
|
|
@@ -11652,13 +11996,20 @@ function XViewScene({
|
|
|
11652
11996
|
const up = new THREE3.Vector3(0, 1, 0);
|
|
11653
11997
|
const normal = new THREE3.Vector3().crossVectors(dir, up).normalize();
|
|
11654
11998
|
const controlPoint = mid.add(normal.multiplyScalar(curveOffset));
|
|
11655
|
-
const curve = new THREE3.QuadraticBezierCurve3(
|
|
11999
|
+
const curve = new THREE3.QuadraticBezierCurve3(
|
|
12000
|
+
start,
|
|
12001
|
+
controlPoint,
|
|
12002
|
+
end
|
|
12003
|
+
);
|
|
11656
12004
|
const points = curve.getPoints(x_view_config.CURVE_SEGMENTS);
|
|
11657
12005
|
const positions = [];
|
|
11658
12006
|
points.forEach((p) => positions.push(p.x, p.y, p.z));
|
|
11659
12007
|
line.geometry.setPositions(positions);
|
|
11660
12008
|
} else {
|
|
11661
|
-
line.geometry.setPositions([
|
|
12009
|
+
line.geometry.setPositions([
|
|
12010
|
+
...sourceNode.position.toArray(),
|
|
12011
|
+
...targetNode.position.toArray()
|
|
12012
|
+
]);
|
|
11662
12013
|
}
|
|
11663
12014
|
}
|
|
11664
12015
|
});
|
|
@@ -11671,7 +12022,11 @@ function XViewScene({
|
|
|
11671
12022
|
const startPos = node.position;
|
|
11672
12023
|
const distance = startPos.distanceTo(endPos);
|
|
11673
12024
|
bar.scale.y = distance;
|
|
11674
|
-
const midpoint = new THREE3.Vector3().lerpVectors(
|
|
12025
|
+
const midpoint = new THREE3.Vector3().lerpVectors(
|
|
12026
|
+
startPos,
|
|
12027
|
+
endPos,
|
|
12028
|
+
0.5
|
|
12029
|
+
);
|
|
11675
12030
|
bar.position.copy(midpoint);
|
|
11676
12031
|
const direction = new THREE3.Vector3().subVectors(endPos, startPos).normalize();
|
|
11677
12032
|
const upVector = new THREE3.Vector3(0, 1, 0);
|
|
@@ -11682,7 +12037,11 @@ function XViewScene({
|
|
|
11682
12037
|
const { ghostElements, creation, connection, relink } = stateRef.current;
|
|
11683
12038
|
if (creation.isActive && ghostElements.node && ghostElements.line) {
|
|
11684
12039
|
const srcMesh = stateRef.current.nodeObjects[String(creation.sourceNodeData.id)];
|
|
11685
|
-
if (srcMesh)
|
|
12040
|
+
if (srcMesh)
|
|
12041
|
+
ghostElements.line.geometry.setPositions([
|
|
12042
|
+
...srcMesh.position.toArray(),
|
|
12043
|
+
...ghostElements.node.position.toArray()
|
|
12044
|
+
]);
|
|
11686
12045
|
}
|
|
11687
12046
|
if (connection.isActive && connection.line) {
|
|
11688
12047
|
const srcMesh = stateRef.current.nodeObjects[String(connection.sourceNodeData.id)];
|
|
@@ -11691,7 +12050,11 @@ function XViewScene({
|
|
|
11691
12050
|
raycaster2.setFromCamera(mouse, camera);
|
|
11692
12051
|
camera.getWorldDirection(plane.normal);
|
|
11693
12052
|
plane.setFromNormalAndCoplanarPoint(plane.normal, srcMesh.position);
|
|
11694
|
-
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12053
|
+
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12054
|
+
connection.line.geometry.setPositions([
|
|
12055
|
+
...srcMesh.position.toArray(),
|
|
12056
|
+
...intersectionPoint.toArray()
|
|
12057
|
+
]);
|
|
11695
12058
|
}
|
|
11696
12059
|
}
|
|
11697
12060
|
if (relink.isActive && relink.line) {
|
|
@@ -11701,7 +12064,11 @@ function XViewScene({
|
|
|
11701
12064
|
raycaster2.setFromCamera(mouse, camera);
|
|
11702
12065
|
camera.getWorldDirection(plane.normal);
|
|
11703
12066
|
plane.setFromNormalAndCoplanarPoint(plane.normal, fixedMesh.position);
|
|
11704
|
-
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12067
|
+
if (raycaster2.ray.intersectPlane(plane, intersectionPoint))
|
|
12068
|
+
relink.line.geometry.setPositions([
|
|
12069
|
+
...fixedMesh.position.toArray(),
|
|
12070
|
+
...intersectionPoint.toArray()
|
|
12071
|
+
]);
|
|
11705
12072
|
}
|
|
11706
12073
|
}
|
|
11707
12074
|
Object.values(stateRef.current.nodeObjects).forEach((node) => {
|
|
@@ -11745,11 +12112,18 @@ function XViewScene({
|
|
|
11745
12112
|
renderer.setSize(clientWidth, clientHeight);
|
|
11746
12113
|
composer.setSize(clientWidth, clientHeight);
|
|
11747
12114
|
const resVec = new THREE3.Vector2(clientWidth, clientHeight);
|
|
11748
|
-
stateRef.current.allLinks.forEach(
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
12115
|
+
stateRef.current.allLinks.forEach(
|
|
12116
|
+
(line) => line.material.resolution.copy(resVec)
|
|
12117
|
+
);
|
|
12118
|
+
stateRef.current.ancestryLinks.forEach(
|
|
12119
|
+
(line) => line.material.resolution.copy(resVec)
|
|
12120
|
+
);
|
|
12121
|
+
if (stateRef.current.ghostElements.line)
|
|
12122
|
+
stateRef.current.ghostElements.line.material.resolution.copy(resVec);
|
|
12123
|
+
if (stateRef.current.connection.line)
|
|
12124
|
+
stateRef.current.connection.line.material.resolution.copy(resVec);
|
|
12125
|
+
if (stateRef.current.relink.line)
|
|
12126
|
+
stateRef.current.relink.line.material.resolution.copy(resVec);
|
|
11753
12127
|
}
|
|
11754
12128
|
window.addEventListener("resize", handleResize);
|
|
11755
12129
|
return () => {
|
|
@@ -11769,14 +12143,16 @@ function XViewScene({
|
|
|
11769
12143
|
ancestryGroup.traverse((obj) => {
|
|
11770
12144
|
if (obj.geometry) obj.geometry.dispose();
|
|
11771
12145
|
if (obj.material) {
|
|
11772
|
-
if (Array.isArray(obj.material))
|
|
12146
|
+
if (Array.isArray(obj.material))
|
|
12147
|
+
obj.material.forEach((m) => m.dispose());
|
|
11773
12148
|
else obj.material.dispose();
|
|
11774
12149
|
}
|
|
11775
12150
|
});
|
|
11776
12151
|
graphGroup.traverse((obj) => {
|
|
11777
12152
|
if (obj.geometry) obj.geometry.dispose();
|
|
11778
12153
|
if (obj.material) {
|
|
11779
|
-
if (Array.isArray(obj.material))
|
|
12154
|
+
if (Array.isArray(obj.material))
|
|
12155
|
+
obj.material.forEach((m) => m.dispose());
|
|
11780
12156
|
else obj.material.dispose();
|
|
11781
12157
|
}
|
|
11782
12158
|
});
|
|
@@ -11787,9 +12163,22 @@ function XViewScene({
|
|
|
11787
12163
|
currentMount.removeChild(renderer.domElement);
|
|
11788
12164
|
}
|
|
11789
12165
|
};
|
|
11790
|
-
}, [
|
|
12166
|
+
}, [
|
|
12167
|
+
isInitialized,
|
|
12168
|
+
tweenToTarget,
|
|
12169
|
+
dbSaveUrl,
|
|
12170
|
+
isNodeInView,
|
|
12171
|
+
addOrUpdateNodeMesh,
|
|
12172
|
+
handleActivateTimeline,
|
|
12173
|
+
get_scene_view_data,
|
|
12174
|
+
save_view_data
|
|
12175
|
+
]);
|
|
11791
12176
|
const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
|
|
11792
|
-
const {
|
|
12177
|
+
const {
|
|
12178
|
+
node: ghostNode,
|
|
12179
|
+
line: ghostLine,
|
|
12180
|
+
aura: ghostAura
|
|
12181
|
+
} = stateRef.current.ghostElements;
|
|
11793
12182
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
11794
12183
|
if (!ghostNode || !graphGroup) return;
|
|
11795
12184
|
const currentData = {
|
|
@@ -11800,13 +12189,15 @@ function XViewScene({
|
|
|
11800
12189
|
const position = ghostNode.position.clone();
|
|
11801
12190
|
if (ghostNode.userData.labelObject) {
|
|
11802
12191
|
graphGroup.remove(ghostNode.userData.labelObject);
|
|
11803
|
-
if (ghostNode.userData.labelObject.material.map)
|
|
12192
|
+
if (ghostNode.userData.labelObject.material.map)
|
|
12193
|
+
ghostNode.userData.labelObject.material.map.dispose();
|
|
11804
12194
|
ghostNode.userData.labelObject.material.dispose();
|
|
11805
12195
|
}
|
|
11806
12196
|
graphGroup.remove(ghostNode);
|
|
11807
12197
|
if (ghostNode.geometry) ghostNode.geometry.dispose();
|
|
11808
12198
|
if (ghostNode.material) {
|
|
11809
|
-
if (Array.isArray(ghostNode.material))
|
|
12199
|
+
if (Array.isArray(ghostNode.material))
|
|
12200
|
+
ghostNode.material.forEach((m) => m.dispose());
|
|
11810
12201
|
else ghostNode.material.dispose();
|
|
11811
12202
|
}
|
|
11812
12203
|
const newGhostNode = createNodeMesh(currentData, position, glowTexture);
|
|
@@ -11851,28 +12242,31 @@ function XViewScene({
|
|
|
11851
12242
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
11852
12243
|
}
|
|
11853
12244
|
}, []);
|
|
11854
|
-
const handleDetailNodeIntensityChange = useCallback4(
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
borderMesh.material
|
|
12245
|
+
const handleDetailNodeIntensityChange = useCallback4(
|
|
12246
|
+
(nodeId, newIntensity) => {
|
|
12247
|
+
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
12248
|
+
if (!mesh) return;
|
|
12249
|
+
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
12250
|
+
mesh.userData.intensity = newIntensity;
|
|
12251
|
+
mesh.userData._baseEmissiveIntensity = adjustedIntensity;
|
|
12252
|
+
const isImageNode = mesh.userData.useImageAsTexture === true;
|
|
12253
|
+
if (isImageNode) {
|
|
12254
|
+
const borderMesh = mesh.getObjectByName("borderRing");
|
|
12255
|
+
if (borderMesh && borderMesh.material) {
|
|
12256
|
+
borderMesh.material.emissiveIntensity = adjustedIntensity;
|
|
12257
|
+
}
|
|
12258
|
+
} else {
|
|
12259
|
+
if (mesh.material) {
|
|
12260
|
+
mesh.material.emissiveIntensity = adjustedIntensity;
|
|
12261
|
+
}
|
|
11865
12262
|
}
|
|
11866
|
-
|
|
11867
|
-
if (
|
|
11868
|
-
|
|
12263
|
+
const aura = mesh.getObjectByName("aura");
|
|
12264
|
+
if (aura && aura.material) {
|
|
12265
|
+
aura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
11869
12266
|
}
|
|
11870
|
-
}
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
aura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
11874
|
-
}
|
|
11875
|
-
}, []);
|
|
12267
|
+
},
|
|
12268
|
+
[]
|
|
12269
|
+
);
|
|
11876
12270
|
const handleGhostNodeColorChange = (newColor) => {
|
|
11877
12271
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
11878
12272
|
if (!ghostNode) return;
|
|
@@ -11983,7 +12377,9 @@ function XViewScene({
|
|
|
11983
12377
|
mesh.userData.size = newSize;
|
|
11984
12378
|
};
|
|
11985
12379
|
const handleStartAncestryCreation = (nodeData) => {
|
|
11986
|
-
setContextMenu(
|
|
12380
|
+
setContextMenu(
|
|
12381
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
12382
|
+
);
|
|
11987
12383
|
stateRef.current.maxAncestryRenderIndex = 0;
|
|
11988
12384
|
setAncestryMode({
|
|
11989
12385
|
isActive: true,
|
|
@@ -12008,9 +12404,12 @@ function XViewScene({
|
|
|
12008
12404
|
const newTreeStr = JSON.stringify(newTree);
|
|
12009
12405
|
let metaChanged = false;
|
|
12010
12406
|
if (extraData) {
|
|
12011
|
-
if (extraData.ancestryName !== void 0 && extraData.ancestryName !== prev.ancestryName)
|
|
12012
|
-
|
|
12013
|
-
if (extraData.
|
|
12407
|
+
if (extraData.ancestryName !== void 0 && extraData.ancestryName !== prev.ancestryName)
|
|
12408
|
+
metaChanged = true;
|
|
12409
|
+
if (extraData.ancestryDescription !== void 0 && extraData.ancestryDescription !== prev.ancestryDescription)
|
|
12410
|
+
metaChanged = true;
|
|
12411
|
+
if (extraData.ancestryDescriptionSections !== void 0 && JSON.stringify(extraData.ancestryDescriptionSections) !== JSON.stringify(prev.ancestryDescriptionSections))
|
|
12412
|
+
metaChanged = true;
|
|
12014
12413
|
}
|
|
12015
12414
|
if (prevTreeStr === newTreeStr && !metaChanged) {
|
|
12016
12415
|
return prev;
|
|
@@ -12088,13 +12487,15 @@ function XViewScene({
|
|
|
12088
12487
|
if (ghostElements.node && graphGroup) {
|
|
12089
12488
|
if (ghostElements.node.userData.labelObject) {
|
|
12090
12489
|
graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
12091
|
-
if (ghostElements.node.userData.labelObject.material.map)
|
|
12490
|
+
if (ghostElements.node.userData.labelObject.material.map)
|
|
12491
|
+
ghostElements.node.userData.labelObject.material.map.dispose();
|
|
12092
12492
|
ghostElements.node.userData.labelObject.material.dispose();
|
|
12093
12493
|
}
|
|
12094
12494
|
graphGroup.remove(ghostElements.node);
|
|
12095
12495
|
ghostElements.node.traverse((child) => {
|
|
12096
12496
|
if (child.material) {
|
|
12097
|
-
if (Array.isArray(child.material))
|
|
12497
|
+
if (Array.isArray(child.material))
|
|
12498
|
+
child.material.forEach((m) => m.dispose());
|
|
12098
12499
|
else child.material.dispose();
|
|
12099
12500
|
}
|
|
12100
12501
|
if (child.geometry) child.geometry.dispose();
|
|
@@ -12104,7 +12505,17 @@ function XViewScene({
|
|
|
12104
12505
|
setQuestMode({ isActive: false });
|
|
12105
12506
|
}, []);
|
|
12106
12507
|
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
12107
|
-
const {
|
|
12508
|
+
const {
|
|
12509
|
+
graphDataRef,
|
|
12510
|
+
sceneDataRef: sceneDataRef2,
|
|
12511
|
+
stateRef: stateRef2,
|
|
12512
|
+
setters,
|
|
12513
|
+
actions,
|
|
12514
|
+
sceneSaveUrl: sceneSaveUrl2,
|
|
12515
|
+
viewType,
|
|
12516
|
+
sceneConfigId: sceneConfigId2,
|
|
12517
|
+
ownerId: ownerId2
|
|
12518
|
+
} = context;
|
|
12108
12519
|
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
12109
12520
|
const currentCounter = sceneDataRef2.current.quest_counter || 1;
|
|
12110
12521
|
const newNode = {
|
|
@@ -12137,7 +12548,8 @@ function XViewScene({
|
|
|
12137
12548
|
const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
|
|
12138
12549
|
const { graphGroup, ghostElements } = stateRef2.current;
|
|
12139
12550
|
if (ghostElements.node && graphGroup) {
|
|
12140
|
-
if (ghostElements.node.userData.labelObject)
|
|
12551
|
+
if (ghostElements.node.userData.labelObject)
|
|
12552
|
+
graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
12141
12553
|
graphGroup.remove(ghostElements.node);
|
|
12142
12554
|
}
|
|
12143
12555
|
stateRef2.current.ghostElements = { node: null, line: null, aura: null };
|
|
@@ -12151,14 +12563,33 @@ function XViewScene({
|
|
|
12151
12563
|
}
|
|
12152
12564
|
};
|
|
12153
12565
|
userActionHandlers.handleCompleteConnection = async (context, targetNodeData) => {
|
|
12154
|
-
const {
|
|
12566
|
+
const {
|
|
12567
|
+
stateRef: stateRef2,
|
|
12568
|
+
graphDataRef,
|
|
12569
|
+
sceneDataRef: sceneDataRef2,
|
|
12570
|
+
sceneConfigId: sceneConfigId2,
|
|
12571
|
+
sceneSaveUrl: sceneSaveUrl2,
|
|
12572
|
+
ownerId: ownerId2
|
|
12573
|
+
} = context;
|
|
12155
12574
|
const { sourceNodeData } = stateRef2.current.connection;
|
|
12156
12575
|
if (!graphDataRef.current || !sceneDataRef2.current || !sourceNodeData || !targetNodeData) {
|
|
12157
12576
|
userActionHandlers.handleCancelConnection(context);
|
|
12158
12577
|
return;
|
|
12159
12578
|
}
|
|
12160
|
-
const sourceParentInfo = getParentFileInfoForNode(
|
|
12161
|
-
|
|
12579
|
+
const sourceParentInfo = getParentFileInfoForNode(
|
|
12580
|
+
graphDataRef.current,
|
|
12581
|
+
sceneDataRef2.current,
|
|
12582
|
+
sourceNodeData.id,
|
|
12583
|
+
sceneConfigId2,
|
|
12584
|
+
ownerId2
|
|
12585
|
+
);
|
|
12586
|
+
const targetParentInfo = getParentFileInfoForNode(
|
|
12587
|
+
graphDataRef.current,
|
|
12588
|
+
sceneDataRef2.current,
|
|
12589
|
+
targetNodeData.id,
|
|
12590
|
+
sceneConfigId2,
|
|
12591
|
+
ownerId2
|
|
12592
|
+
);
|
|
12162
12593
|
let parentInfoToSave = sourceParentInfo;
|
|
12163
12594
|
const isSourceQuest = sourceParentInfo.parentFileId === sceneConfigId2;
|
|
12164
12595
|
const isTargetQuest = targetParentInfo.parentFileId === sceneConfigId2;
|
|
@@ -12184,10 +12615,15 @@ function XViewScene({
|
|
|
12184
12615
|
};
|
|
12185
12616
|
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
12186
12617
|
} else {
|
|
12187
|
-
const specificParentData = JSON.parse(
|
|
12618
|
+
const specificParentData = JSON.parse(
|
|
12619
|
+
JSON.stringify(graphDataRef.current[parentFileIdToSave])
|
|
12620
|
+
);
|
|
12188
12621
|
specificParentData.links.push(newLink);
|
|
12189
12622
|
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
12190
|
-
await context.actions.save_view_data(
|
|
12623
|
+
await context.actions.save_view_data(
|
|
12624
|
+
filenameForSpecificParent,
|
|
12625
|
+
specificParentData
|
|
12626
|
+
);
|
|
12191
12627
|
graphDataRef.current[parentFileIdToSave] = specificParentData;
|
|
12192
12628
|
}
|
|
12193
12629
|
addNewLinkToScene(stateRef2.current, newLink);
|
|
@@ -12199,7 +12635,9 @@ function XViewScene({
|
|
|
12199
12635
|
};
|
|
12200
12636
|
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
12201
12637
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
12202
|
-
const renderIndex = renderedAncestries.findIndex(
|
|
12638
|
+
const renderIndex = renderedAncestries.findIndex(
|
|
12639
|
+
(a) => String(a.id) === String(ancestryId)
|
|
12640
|
+
);
|
|
12203
12641
|
if (renderIndex !== -1) {
|
|
12204
12642
|
const toRemove = renderedAncestries[renderIndex];
|
|
12205
12643
|
toRemove.lines.forEach((line) => {
|
|
@@ -12208,12 +12646,16 @@ function XViewScene({
|
|
|
12208
12646
|
if (line.material) line.material.dispose();
|
|
12209
12647
|
});
|
|
12210
12648
|
renderedAncestries.splice(renderIndex, 1);
|
|
12211
|
-
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
12649
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
12650
|
+
(a) => a.lines
|
|
12651
|
+
);
|
|
12212
12652
|
}
|
|
12213
12653
|
}, []);
|
|
12214
12654
|
const handleRenderAncestry = useCallback4(
|
|
12215
12655
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
12216
|
-
setContextMenu(
|
|
12656
|
+
setContextMenu(
|
|
12657
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
12658
|
+
);
|
|
12217
12659
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
12218
12660
|
return;
|
|
12219
12661
|
}
|
|
@@ -12240,14 +12682,16 @@ function XViewScene({
|
|
|
12240
12682
|
if (numId !== void 0 && normalizedAllowedIds.has(numId)) return true;
|
|
12241
12683
|
if (strId && normalizedAllowedIds.has(strId)) return true;
|
|
12242
12684
|
if (strSecId && normalizedAllowedIds.has(strSecId)) return true;
|
|
12243
|
-
if (numId !== void 0 && normalizedAllowedIds.has(String(numId)))
|
|
12685
|
+
if (numId !== void 0 && normalizedAllowedIds.has(String(numId)))
|
|
12686
|
+
return true;
|
|
12244
12687
|
return false;
|
|
12245
12688
|
};
|
|
12246
12689
|
const checkIsActive = (section, targetId) => {
|
|
12247
12690
|
if (targetId === null || targetId === void 0) return false;
|
|
12248
12691
|
const sTarget = String(targetId);
|
|
12249
12692
|
if (section.id && String(section.id) === sTarget) return true;
|
|
12250
|
-
if (section.section_id && String(section.section_id) === sTarget)
|
|
12693
|
+
if (section.section_id && String(section.section_id) === sTarget)
|
|
12694
|
+
return true;
|
|
12251
12695
|
if (section.section_numeric_id !== void 0) {
|
|
12252
12696
|
if (String(section.section_numeric_id) === sTarget) return true;
|
|
12253
12697
|
}
|
|
@@ -12263,7 +12707,9 @@ function XViewScene({
|
|
|
12263
12707
|
traverse(sectionTree);
|
|
12264
12708
|
return ids;
|
|
12265
12709
|
};
|
|
12266
|
-
const existingIndex = renderedAncestries.findIndex(
|
|
12710
|
+
const existingIndex = renderedAncestries.findIndex(
|
|
12711
|
+
(a) => String(a.id) === String(ancestryObject.ancestry_id)
|
|
12712
|
+
);
|
|
12267
12713
|
let skipGeneration = false;
|
|
12268
12714
|
let ancestryEntry = null;
|
|
12269
12715
|
if (existingIndex !== -1) {
|
|
@@ -12318,9 +12764,15 @@ function XViewScene({
|
|
|
12318
12764
|
if (line.material) line.material.dispose();
|
|
12319
12765
|
});
|
|
12320
12766
|
}
|
|
12321
|
-
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
12767
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
12768
|
+
(fileData) => fileData.nodes
|
|
12769
|
+
);
|
|
12322
12770
|
const allAncestries = ancestryDataRef.current || [];
|
|
12323
|
-
const fullTree = buildFullAncestryTree(
|
|
12771
|
+
const fullTree = buildFullAncestryTree(
|
|
12772
|
+
ancestryObject.tree,
|
|
12773
|
+
allParentNodes,
|
|
12774
|
+
allAncestries
|
|
12775
|
+
);
|
|
12324
12776
|
if (!fullTree) return;
|
|
12325
12777
|
const rootNodeId = String(ancestryObject.ancestral_node);
|
|
12326
12778
|
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
@@ -12363,7 +12815,10 @@ function XViewScene({
|
|
|
12363
12815
|
const colorIndex = stateRef.current.ancestryRenderCounter % 3;
|
|
12364
12816
|
colorHex = ANCESTRY_COLORS[colorIndex];
|
|
12365
12817
|
}
|
|
12366
|
-
const resolution = new THREE3.Vector2(
|
|
12818
|
+
const resolution = new THREE3.Vector2(
|
|
12819
|
+
renderer.domElement.clientWidth,
|
|
12820
|
+
renderer.domElement.clientHeight
|
|
12821
|
+
);
|
|
12367
12822
|
const cleanupLinesForNode = (nodeId) => {
|
|
12368
12823
|
if (!ancestryEntry || !ancestryEntry.lines) return;
|
|
12369
12824
|
const linesKeep = [];
|
|
@@ -12403,7 +12858,13 @@ function XViewScene({
|
|
|
12403
12858
|
}
|
|
12404
12859
|
if (originMesh && rootNodeMesh) {
|
|
12405
12860
|
cleanupLinesForNode(rootNodeId);
|
|
12406
|
-
const branchLine = createAncestryLinkLine(
|
|
12861
|
+
const branchLine = createAncestryLinkLine(
|
|
12862
|
+
originMesh,
|
|
12863
|
+
rootNodeMesh,
|
|
12864
|
+
resolution,
|
|
12865
|
+
{},
|
|
12866
|
+
colorHex
|
|
12867
|
+
);
|
|
12407
12868
|
ancestryGroup.add(branchLine);
|
|
12408
12869
|
ancestryEntry.lines.push(branchLine);
|
|
12409
12870
|
}
|
|
@@ -12414,8 +12875,14 @@ function XViewScene({
|
|
|
12414
12875
|
if (!children || children.length === 0) return null;
|
|
12415
12876
|
let lastRenderedMesh = null;
|
|
12416
12877
|
const numChildren = children.length;
|
|
12417
|
-
const forwardVec = new THREE3.Vector3(0, 0, 1).applyAxisAngle(
|
|
12418
|
-
|
|
12878
|
+
const forwardVec = new THREE3.Vector3(0, 0, 1).applyAxisAngle(
|
|
12879
|
+
new THREE3.Vector3(0, 1, 0),
|
|
12880
|
+
currentAngle
|
|
12881
|
+
);
|
|
12882
|
+
const rightVec = new THREE3.Vector3(1, 0, 0).applyAxisAngle(
|
|
12883
|
+
new THREE3.Vector3(0, 1, 0),
|
|
12884
|
+
currentAngle
|
|
12885
|
+
);
|
|
12419
12886
|
const angleRange = numChildren > 3 ? Math.PI : Math.PI / 1.5;
|
|
12420
12887
|
children.forEach((childItem, index) => {
|
|
12421
12888
|
if (childItem.is_section) return;
|
|
@@ -12436,14 +12903,30 @@ function XViewScene({
|
|
|
12436
12903
|
targetPositionsCache.set(sNodeId, childPosition.clone());
|
|
12437
12904
|
cleanupLinesForNode(sNodeId);
|
|
12438
12905
|
}
|
|
12439
|
-
const childMesh = addOrUpdateNodeMesh(
|
|
12906
|
+
const childMesh = addOrUpdateNodeMesh(
|
|
12907
|
+
childItem.node,
|
|
12908
|
+
childPosition,
|
|
12909
|
+
true
|
|
12910
|
+
);
|
|
12440
12911
|
allRenderedNodePositions.push(childPosition);
|
|
12441
|
-
const line = createAncestryLinkLine(
|
|
12912
|
+
const line = createAncestryLinkLine(
|
|
12913
|
+
parentMesh,
|
|
12914
|
+
childMesh,
|
|
12915
|
+
resolution,
|
|
12916
|
+
childItem.relationship,
|
|
12917
|
+
colorHex
|
|
12918
|
+
);
|
|
12442
12919
|
ancestryGroup.add(line);
|
|
12443
12920
|
ancestryEntry.lines.push(line);
|
|
12444
12921
|
lastRenderedMesh = childMesh;
|
|
12445
12922
|
if (childItem.children && childItem.children.length > 0) {
|
|
12446
|
-
const lastDescendant = renderCluster(
|
|
12923
|
+
const lastDescendant = renderCluster(
|
|
12924
|
+
childItem.children,
|
|
12925
|
+
childMesh,
|
|
12926
|
+
childPosition,
|
|
12927
|
+
level + 1,
|
|
12928
|
+
currentAngle
|
|
12929
|
+
);
|
|
12447
12930
|
if (lastDescendant) lastRenderedMesh = lastDescendant;
|
|
12448
12931
|
}
|
|
12449
12932
|
});
|
|
@@ -12457,9 +12940,13 @@ function XViewScene({
|
|
|
12457
12940
|
else looseNodes.push(child);
|
|
12458
12941
|
});
|
|
12459
12942
|
}
|
|
12460
|
-
sections.sort(
|
|
12943
|
+
sections.sort(
|
|
12944
|
+
(a, b) => (a.section_numeric_id || 0) - (b.section_numeric_id || 0)
|
|
12945
|
+
);
|
|
12461
12946
|
let combinedStartNodes = [...looseNodes];
|
|
12462
|
-
let session0Index = sections.findIndex(
|
|
12947
|
+
let session0Index = sections.findIndex(
|
|
12948
|
+
(s) => s.section_numeric_id === 0 || s.name === "Sess\xE3o 0"
|
|
12949
|
+
);
|
|
12463
12950
|
if (session0Index !== -1) {
|
|
12464
12951
|
const session0 = sections[session0Index];
|
|
12465
12952
|
if (checkShouldRender(session0) && session0.children) {
|
|
@@ -12468,7 +12955,13 @@ function XViewScene({
|
|
|
12468
12955
|
sections.splice(session0Index, 1);
|
|
12469
12956
|
}
|
|
12470
12957
|
const rootTargetPos2 = targetPositionsCache.get(rootNodeId) || rootNodeMesh.position;
|
|
12471
|
-
const lastStartMesh = renderCluster(
|
|
12958
|
+
const lastStartMesh = renderCluster(
|
|
12959
|
+
combinedStartNodes,
|
|
12960
|
+
rootNodeMesh,
|
|
12961
|
+
rootTargetPos2,
|
|
12962
|
+
1,
|
|
12963
|
+
baseRotation
|
|
12964
|
+
);
|
|
12472
12965
|
if (lastStartMesh) {
|
|
12473
12966
|
currentAnchorMesh = lastStartMesh;
|
|
12474
12967
|
}
|
|
@@ -12479,10 +12972,18 @@ function XViewScene({
|
|
|
12479
12972
|
const sectionNodes = section.children || [];
|
|
12480
12973
|
if (sectionNodes.length > 0) {
|
|
12481
12974
|
const parentAngle = nodeRotationMap.get(String(currentAnchorMesh.userData.id)) ?? baseRotation;
|
|
12482
|
-
const lastMeshOfThisSection = renderCluster(
|
|
12975
|
+
const lastMeshOfThisSection = renderCluster(
|
|
12976
|
+
sectionNodes,
|
|
12977
|
+
currentAnchorMesh,
|
|
12978
|
+
currentAnchorPosition,
|
|
12979
|
+
1,
|
|
12980
|
+
parentAngle
|
|
12981
|
+
);
|
|
12483
12982
|
if (lastMeshOfThisSection) {
|
|
12484
12983
|
currentAnchorMesh = lastMeshOfThisSection;
|
|
12485
|
-
currentAnchorPosition = targetPositionsCache.get(
|
|
12984
|
+
currentAnchorPosition = targetPositionsCache.get(
|
|
12985
|
+
String(lastMeshOfThisSection.userData.id)
|
|
12986
|
+
) || lastMeshOfThisSection.position;
|
|
12486
12987
|
}
|
|
12487
12988
|
}
|
|
12488
12989
|
}
|
|
@@ -12511,7 +13012,10 @@ function XViewScene({
|
|
|
12511
13012
|
} else {
|
|
12512
13013
|
const directChildren = fullTree.children ? fullTree.children.filter((c) => !c.is_section) : [];
|
|
12513
13014
|
if (directChildren.length > 0) {
|
|
12514
|
-
targetSectionForZone = {
|
|
13015
|
+
targetSectionForZone = {
|
|
13016
|
+
name: "In\xEDcio",
|
|
13017
|
+
children: directChildren
|
|
13018
|
+
};
|
|
12515
13019
|
}
|
|
12516
13020
|
}
|
|
12517
13021
|
} else {
|
|
@@ -12585,7 +13089,10 @@ function XViewScene({
|
|
|
12585
13089
|
stateRef.current.ancestryLinks = stateRef.current.renderedAncestries.flatMap((a) => a.lines);
|
|
12586
13090
|
focusTargetPosition = center;
|
|
12587
13091
|
focusTargetRotation = baseRotation;
|
|
12588
|
-
const desiredDistance = Math.max(
|
|
13092
|
+
const desiredDistance = Math.max(
|
|
13093
|
+
x_view_config.CAMERA_ZOOM_DISTANCE,
|
|
13094
|
+
radius * 2.8
|
|
13095
|
+
);
|
|
12589
13096
|
focusZoomFactor = x_view_config.CAMERA_ZOOM_DISTANCE / desiredDistance;
|
|
12590
13097
|
} else {
|
|
12591
13098
|
const anchorId = String(currentAnchorMesh.userData.id);
|
|
@@ -12600,13 +13107,18 @@ function XViewScene({
|
|
|
12600
13107
|
}
|
|
12601
13108
|
if (!focusTargetPosition && !allowedSectionIds) {
|
|
12602
13109
|
if (allRenderedNodePositions.length > 0) {
|
|
12603
|
-
const boundingBox = new THREE3.Box3().setFromPoints(
|
|
13110
|
+
const boundingBox = new THREE3.Box3().setFromPoints(
|
|
13111
|
+
allRenderedNodePositions
|
|
13112
|
+
);
|
|
12604
13113
|
const center = new THREE3.Vector3();
|
|
12605
13114
|
boundingBox.getCenter(center);
|
|
12606
13115
|
const size = new THREE3.Vector3();
|
|
12607
13116
|
boundingBox.getSize(size);
|
|
12608
13117
|
const maxDim = Math.max(size.x, size.y, size.z);
|
|
12609
|
-
const fitZoom = Math.min(
|
|
13118
|
+
const fitZoom = Math.min(
|
|
13119
|
+
1,
|
|
13120
|
+
x_view_config.CAMERA_ZOOM_DISTANCE / (maxDim * 1.5)
|
|
13121
|
+
);
|
|
12610
13122
|
const defaultBase = new THREE3.Vector3(-50, 40, 20);
|
|
12611
13123
|
const rotatedCinematicAngle = defaultBase.clone().applyAxisAngle(new THREE3.Vector3(0, 1, 0), baseRotation);
|
|
12612
13124
|
tweenToTarget(center, fitZoom, rotatedCinematicAngle);
|
|
@@ -12625,210 +13137,280 @@ function XViewScene({
|
|
|
12625
13137
|
tweenToTarget(targetPos, focusZoomFactor, rotatedCinematicAngle);
|
|
12626
13138
|
}
|
|
12627
13139
|
},
|
|
12628
|
-
[
|
|
13140
|
+
[
|
|
13141
|
+
addOrUpdateNodeMesh,
|
|
13142
|
+
tweenToTarget,
|
|
13143
|
+
buildFullAncestryTree,
|
|
13144
|
+
readingMode.isActive,
|
|
13145
|
+
ancestryMode.isActive
|
|
13146
|
+
]
|
|
12629
13147
|
);
|
|
12630
|
-
const handleRenderAbstractionTree = useCallback4(
|
|
12631
|
-
|
|
12632
|
-
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
13148
|
+
const handleRenderAbstractionTree = useCallback4(
|
|
13149
|
+
(ancestryObject, targetNodeId = null) => {
|
|
13150
|
+
setContextMenu(
|
|
13151
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
13152
|
+
);
|
|
13153
|
+
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
13154
|
+
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
13155
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
13156
|
+
(f) => f.nodes
|
|
13157
|
+
);
|
|
13158
|
+
let fullTree = buildFullAncestryTree(
|
|
13159
|
+
ancestryObject.abstraction_tree,
|
|
13160
|
+
allParentNodes,
|
|
13161
|
+
ancestryDataRef.current
|
|
13162
|
+
);
|
|
13163
|
+
if (!fullTree || !fullTree.node) return;
|
|
13164
|
+
if (targetNodeId) {
|
|
13165
|
+
const pruneTreeToPath = (treeNode, targetId) => {
|
|
13166
|
+
var _a2;
|
|
13167
|
+
if (!treeNode) return null;
|
|
13168
|
+
const currentId = treeNode.is_section ? treeNode.section_id : String((_a2 = treeNode.node) == null ? void 0 : _a2.id);
|
|
13169
|
+
if (String(currentId) === String(targetId)) {
|
|
13170
|
+
return { ...treeNode, children: [] };
|
|
12651
13171
|
}
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
}
|
|
12658
|
-
const absId = ancestryObject.ancestry_id + "_abs";
|
|
12659
|
-
handleClearAncestryVisuals(absId);
|
|
12660
|
-
const colorHex = 9133302;
|
|
12661
|
-
const resolution = new THREE3.Vector2(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
|
|
12662
|
-
const ancestryEntry = { id: absId, lines: [], isFullRender: true };
|
|
12663
|
-
renderedAncestries.push(ancestryEntry);
|
|
12664
|
-
const rootNodeId = String(fullTree.node.id);
|
|
12665
|
-
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
12666
|
-
let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
|
|
12667
|
-
if (!rootNodeMesh) {
|
|
12668
|
-
rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
|
|
12669
|
-
}
|
|
12670
|
-
const SPACING_Y = -40;
|
|
12671
|
-
const SPACING_X = 55;
|
|
12672
|
-
const renderVertical = (treeNode, parentMesh, parentPos, level) => {
|
|
12673
|
-
if (!treeNode.children || treeNode.children.length === 0) return;
|
|
12674
|
-
const totalSiblings = treeNode.children.length;
|
|
12675
|
-
treeNode.children.forEach((childItem, i) => {
|
|
12676
|
-
if (!childItem.node) return;
|
|
12677
|
-
const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
|
|
12678
|
-
const childY = parentPos.y + SPACING_Y;
|
|
12679
|
-
const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
|
|
12680
|
-
const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
|
|
12681
|
-
const line = createAncestryLinkLine(parentMesh, childMesh, resolution, {}, colorHex);
|
|
12682
|
-
ancestryGroup.add(line);
|
|
12683
|
-
ancestryEntry.lines.push(line);
|
|
12684
|
-
renderVertical(childItem, childMesh, childPos, level + 1);
|
|
12685
|
-
});
|
|
12686
|
-
};
|
|
12687
|
-
renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
|
|
12688
|
-
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
12689
|
-
tweenToTarget(rootTargetPos, 0.7);
|
|
12690
|
-
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
12691
|
-
const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
|
|
12692
|
-
const { ancestry, branchStack } = readingMode;
|
|
12693
|
-
if (!ancestry || !ancestry.tree) return;
|
|
12694
|
-
const allAncestries = ancestryDataRef.current || [];
|
|
12695
|
-
const fullTree = buildFullAncestryTree(ancestry.tree, Object.values(parentDataRef.current).flatMap((f) => f.nodes), allAncestries);
|
|
12696
|
-
if (action === "open") {
|
|
12697
|
-
let currentPtr = fullTree;
|
|
12698
|
-
for (const step of branchStack) {
|
|
12699
|
-
const found = findNodePath3(currentPtr, step.nodeId);
|
|
12700
|
-
if (found && found.node.parallel_branches) {
|
|
12701
|
-
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
12702
|
-
if (branch) currentPtr = branch.tree;
|
|
12703
|
-
}
|
|
12704
|
-
}
|
|
12705
|
-
const foundTarget = findNodePath3(currentPtr, nodeId);
|
|
12706
|
-
if (foundTarget && foundTarget.node && foundTarget.node.parallel_branches && foundTarget.node.parallel_branches.length > 0) {
|
|
12707
|
-
const branchToOpen = foundTarget.node.parallel_branches.find((b) => (b.direction || "right") === direction);
|
|
12708
|
-
if (!branchToOpen) return;
|
|
12709
|
-
if (branchToOpen && branchToOpen.tree) {
|
|
12710
|
-
const parentIndexToSave = stateRef.current.readMode.currentMaxIndex;
|
|
12711
|
-
const savedBranchProgress = 0;
|
|
12712
|
-
stateRef.current.readMode.currentMaxIndex = savedBranchProgress;
|
|
12713
|
-
stateRef.current.maxAncestryRenderIndex = savedBranchProgress;
|
|
12714
|
-
const newStack = [...branchStack, {
|
|
12715
|
-
nodeId,
|
|
12716
|
-
branchId: branchToOpen.id,
|
|
12717
|
-
savedMaxIndex: parentIndexToSave,
|
|
12718
|
-
entryDirection: direction
|
|
12719
|
-
}];
|
|
12720
|
-
setReadingMode((prev) => ({ ...prev, branchStack: newStack, initialSectionId: null }));
|
|
12721
|
-
const branchAncestryObj = {
|
|
12722
|
-
ancestry_id: branchToOpen.id,
|
|
12723
|
-
ancestral_node: branchToOpen.tree.node.id,
|
|
12724
|
-
name: branchToOpen.name,
|
|
12725
|
-
description: branchToOpen.description,
|
|
12726
|
-
description_sections: branchToOpen.description_sections,
|
|
12727
|
-
tree: branchToOpen.tree,
|
|
12728
|
-
_originNodeId: nodeId,
|
|
12729
|
-
_branchDirection: direction
|
|
12730
|
-
};
|
|
12731
|
-
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
12732
|
-
const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
|
|
12733
|
-
for (let i = 0; i <= savedBranchProgress; i++) {
|
|
12734
|
-
if (branchSections[i]) {
|
|
12735
|
-
if (branchSections[i].id) allowedIds.add(String(branchSections[i].id));
|
|
12736
|
-
if (branchSections[i].numericId !== void 0 && branchSections[i].numericId !== null) {
|
|
12737
|
-
allowedIds.add(branchSections[i].numericId);
|
|
12738
|
-
allowedIds.add(String(branchSections[i].numericId));
|
|
13172
|
+
if (treeNode.children && treeNode.children.length > 0) {
|
|
13173
|
+
for (let child of treeNode.children) {
|
|
13174
|
+
const prunedChild = pruneTreeToPath(child, targetId);
|
|
13175
|
+
if (prunedChild) {
|
|
13176
|
+
return { ...treeNode, children: [prunedChild] };
|
|
12739
13177
|
}
|
|
12740
13178
|
}
|
|
12741
13179
|
}
|
|
12742
|
-
|
|
12743
|
-
|
|
12744
|
-
|
|
12745
|
-
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12753
|
-
|
|
13180
|
+
return null;
|
|
13181
|
+
};
|
|
13182
|
+
const pruned = pruneTreeToPath(fullTree, targetNodeId);
|
|
13183
|
+
if (pruned) fullTree = pruned;
|
|
13184
|
+
}
|
|
13185
|
+
const absId = ancestryObject.ancestry_id + "_abs";
|
|
13186
|
+
handleClearAncestryVisuals(absId);
|
|
13187
|
+
const colorHex = 9133302;
|
|
13188
|
+
const resolution = new THREE3.Vector2(
|
|
13189
|
+
renderer.domElement.clientWidth,
|
|
13190
|
+
renderer.domElement.clientHeight
|
|
13191
|
+
);
|
|
13192
|
+
const ancestryEntry = { id: absId, lines: [], isFullRender: true };
|
|
13193
|
+
renderedAncestries.push(ancestryEntry);
|
|
13194
|
+
const rootNodeId = String(fullTree.node.id);
|
|
13195
|
+
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
13196
|
+
let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
|
|
13197
|
+
if (!rootNodeMesh) {
|
|
13198
|
+
rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
|
|
12754
13199
|
}
|
|
12755
|
-
|
|
12756
|
-
|
|
12757
|
-
const
|
|
12758
|
-
|
|
12759
|
-
|
|
12760
|
-
|
|
12761
|
-
|
|
12762
|
-
|
|
12763
|
-
|
|
12764
|
-
|
|
12765
|
-
|
|
12766
|
-
|
|
12767
|
-
|
|
12768
|
-
|
|
12769
|
-
|
|
12770
|
-
|
|
13200
|
+
const SPACING_Y = -40;
|
|
13201
|
+
const SPACING_X = 55;
|
|
13202
|
+
const renderVertical = (treeNode, parentMesh, parentPos, level) => {
|
|
13203
|
+
if (!treeNode.children || treeNode.children.length === 0) return;
|
|
13204
|
+
const totalSiblings = treeNode.children.length;
|
|
13205
|
+
treeNode.children.forEach((childItem, i) => {
|
|
13206
|
+
if (!childItem.node) return;
|
|
13207
|
+
const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
|
|
13208
|
+
const childY = parentPos.y + SPACING_Y;
|
|
13209
|
+
const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
|
|
13210
|
+
const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
|
|
13211
|
+
const line = createAncestryLinkLine(
|
|
13212
|
+
parentMesh,
|
|
13213
|
+
childMesh,
|
|
13214
|
+
resolution,
|
|
13215
|
+
{},
|
|
13216
|
+
colorHex
|
|
13217
|
+
);
|
|
13218
|
+
ancestryGroup.add(line);
|
|
13219
|
+
ancestryEntry.lines.push(line);
|
|
13220
|
+
renderVertical(childItem, childMesh, childPos, level + 1);
|
|
13221
|
+
});
|
|
13222
|
+
};
|
|
13223
|
+
renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
|
|
13224
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
13225
|
+
(a) => a.lines
|
|
13226
|
+
);
|
|
13227
|
+
tweenToTarget(rootTargetPos, 0.7);
|
|
13228
|
+
},
|
|
13229
|
+
[
|
|
13230
|
+
addOrUpdateNodeMesh,
|
|
13231
|
+
tweenToTarget,
|
|
13232
|
+
buildFullAncestryTree,
|
|
13233
|
+
handleClearAncestryVisuals
|
|
13234
|
+
]
|
|
13235
|
+
);
|
|
13236
|
+
const handleReadModeBranchNav = useCallback4(
|
|
13237
|
+
(nodeId, action, direction = "right") => {
|
|
13238
|
+
const { ancestry, branchStack } = readingMode;
|
|
13239
|
+
if (!ancestry || !ancestry.tree) return;
|
|
13240
|
+
const allAncestries = ancestryDataRef.current || [];
|
|
13241
|
+
const fullTree = buildFullAncestryTree(
|
|
13242
|
+
ancestry.tree,
|
|
13243
|
+
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
13244
|
+
allAncestries
|
|
13245
|
+
);
|
|
13246
|
+
if (action === "open") {
|
|
13247
|
+
let currentPtr = fullTree;
|
|
13248
|
+
for (const step of branchStack) {
|
|
13249
|
+
const found = findNodePath3(currentPtr, step.nodeId);
|
|
12771
13250
|
if (found && found.node.parallel_branches) {
|
|
12772
|
-
const branch = found.node.parallel_branches.find(
|
|
12773
|
-
|
|
12774
|
-
|
|
12775
|
-
|
|
13251
|
+
const branch = found.node.parallel_branches.find(
|
|
13252
|
+
(b) => b.id === step.branchId
|
|
13253
|
+
);
|
|
13254
|
+
if (branch) currentPtr = branch.tree;
|
|
13255
|
+
}
|
|
13256
|
+
}
|
|
13257
|
+
const foundTarget = findNodePath3(currentPtr, nodeId);
|
|
13258
|
+
if (foundTarget && foundTarget.node && foundTarget.node.parallel_branches && foundTarget.node.parallel_branches.length > 0) {
|
|
13259
|
+
const branchToOpen = foundTarget.node.parallel_branches.find(
|
|
13260
|
+
(b) => (b.direction || "right") === direction
|
|
13261
|
+
);
|
|
13262
|
+
if (!branchToOpen) return;
|
|
13263
|
+
if (branchToOpen && branchToOpen.tree) {
|
|
13264
|
+
const parentIndexToSave = stateRef.current.readMode.currentMaxIndex;
|
|
13265
|
+
const savedBranchProgress = 0;
|
|
13266
|
+
stateRef.current.readMode.currentMaxIndex = savedBranchProgress;
|
|
13267
|
+
stateRef.current.maxAncestryRenderIndex = savedBranchProgress;
|
|
13268
|
+
const newStack = [
|
|
13269
|
+
...branchStack,
|
|
13270
|
+
{
|
|
13271
|
+
nodeId,
|
|
13272
|
+
branchId: branchToOpen.id,
|
|
13273
|
+
savedMaxIndex: parentIndexToSave,
|
|
13274
|
+
entryDirection: direction
|
|
13275
|
+
}
|
|
13276
|
+
];
|
|
13277
|
+
setReadingMode((prev) => ({
|
|
13278
|
+
...prev,
|
|
13279
|
+
branchStack: newStack,
|
|
13280
|
+
initialSectionId: null
|
|
13281
|
+
}));
|
|
13282
|
+
const branchAncestryObj = {
|
|
13283
|
+
ancestry_id: branchToOpen.id,
|
|
13284
|
+
ancestral_node: branchToOpen.tree.node.id,
|
|
13285
|
+
name: branchToOpen.name,
|
|
13286
|
+
description: branchToOpen.description,
|
|
13287
|
+
description_sections: branchToOpen.description_sections,
|
|
13288
|
+
tree: branchToOpen.tree,
|
|
13289
|
+
_originNodeId: nodeId,
|
|
13290
|
+
_branchDirection: direction
|
|
13291
|
+
};
|
|
13292
|
+
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
13293
|
+
const branchSections = parseDescriptionSections(
|
|
13294
|
+
branchToOpen.description || "",
|
|
13295
|
+
branchToOpen.description_sections || []
|
|
13296
|
+
);
|
|
13297
|
+
for (let i = 0; i <= savedBranchProgress; i++) {
|
|
13298
|
+
if (branchSections[i]) {
|
|
13299
|
+
if (branchSections[i].id)
|
|
13300
|
+
allowedIds.add(String(branchSections[i].id));
|
|
13301
|
+
if (branchSections[i].numericId !== void 0 && branchSections[i].numericId !== null) {
|
|
13302
|
+
allowedIds.add(branchSections[i].numericId);
|
|
13303
|
+
allowedIds.add(String(branchSections[i].numericId));
|
|
13304
|
+
}
|
|
13305
|
+
}
|
|
12776
13306
|
}
|
|
13307
|
+
const rotation = newStack.reduce((acc, step) => {
|
|
13308
|
+
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
13309
|
+
}, 0);
|
|
13310
|
+
const initialFocusId = "preamble";
|
|
13311
|
+
handleRenderAncestry(
|
|
13312
|
+
branchAncestryObj,
|
|
13313
|
+
allowedIds,
|
|
13314
|
+
initialFocusId,
|
|
13315
|
+
rotation,
|
|
13316
|
+
false
|
|
13317
|
+
);
|
|
12777
13318
|
}
|
|
12778
13319
|
}
|
|
12779
|
-
|
|
12780
|
-
|
|
12781
|
-
|
|
12782
|
-
|
|
12783
|
-
|
|
12784
|
-
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12788
|
-
|
|
12789
|
-
|
|
12790
|
-
|
|
12791
|
-
|
|
12792
|
-
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12796
|
-
|
|
12797
|
-
|
|
12798
|
-
|
|
13320
|
+
} else if (action === "back") {
|
|
13321
|
+
if (branchStack.length === 0) return;
|
|
13322
|
+
const newStack = [...branchStack];
|
|
13323
|
+
const popped = newStack.pop();
|
|
13324
|
+
if (popped && popped.branchId) {
|
|
13325
|
+
stateRef.current.readMode.progressMap[popped.branchId] = stateRef.current.readMode.currentMaxIndex;
|
|
13326
|
+
}
|
|
13327
|
+
const parentSavedIndex = popped.savedMaxIndex !== void 0 ? popped.savedMaxIndex : 0;
|
|
13328
|
+
stateRef.current.readMode.currentMaxIndex = parentSavedIndex;
|
|
13329
|
+
stateRef.current.maxAncestryRenderIndex = parentSavedIndex;
|
|
13330
|
+
let targetTreeToRender = fullTree;
|
|
13331
|
+
let targetAncestryInfo = ancestry;
|
|
13332
|
+
if (newStack.length > 0) {
|
|
13333
|
+
let ptr = fullTree;
|
|
13334
|
+
for (const step of newStack) {
|
|
13335
|
+
const found = findNodePath3(ptr, step.nodeId);
|
|
13336
|
+
if (found && found.node.parallel_branches) {
|
|
13337
|
+
const branch = found.node.parallel_branches.find(
|
|
13338
|
+
(b) => b.id === step.branchId
|
|
13339
|
+
);
|
|
13340
|
+
if (branch) {
|
|
13341
|
+
ptr = branch.tree;
|
|
13342
|
+
targetAncestryInfo = {
|
|
13343
|
+
...branch,
|
|
13344
|
+
ancestry_id: branch.id,
|
|
13345
|
+
ancestral_node: branch.tree.node.id
|
|
13346
|
+
};
|
|
13347
|
+
}
|
|
13348
|
+
}
|
|
13349
|
+
}
|
|
13350
|
+
targetTreeToRender = ptr;
|
|
13351
|
+
}
|
|
13352
|
+
const activeParentStackItem = newStack.length > 0 ? newStack[newStack.length - 1] : null;
|
|
13353
|
+
const parentAncestryObj = {
|
|
13354
|
+
...targetAncestryInfo,
|
|
13355
|
+
tree: targetTreeToRender,
|
|
13356
|
+
_originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
|
|
13357
|
+
_branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
|
|
13358
|
+
};
|
|
13359
|
+
const descriptionText = targetAncestryInfo.description || "";
|
|
13360
|
+
const savedSections = targetAncestryInfo.description_sections || [];
|
|
13361
|
+
const sections = parseDescriptionSections(
|
|
13362
|
+
descriptionText,
|
|
13363
|
+
savedSections
|
|
13364
|
+
);
|
|
13365
|
+
let focusTargetId = null;
|
|
13366
|
+
if (popped && popped.nodeId) {
|
|
13367
|
+
const mentionTag = `[[MENTION:node:${popped.nodeId}]]`;
|
|
13368
|
+
for (let i = 0; i < sections.length; i++) {
|
|
13369
|
+
if (sections[i].content && sections[i].content.includes(mentionTag)) {
|
|
13370
|
+
const section = sections[i];
|
|
13371
|
+
focusTargetId = section.numericId !== void 0 ? section.numericId : section.id;
|
|
13372
|
+
break;
|
|
13373
|
+
}
|
|
12799
13374
|
}
|
|
12800
13375
|
}
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12806
|
-
|
|
12807
|
-
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
13376
|
+
const allowedIds = /* @__PURE__ */ new Set();
|
|
13377
|
+
allowedIds.add("preamble");
|
|
13378
|
+
allowedIds.add(0);
|
|
13379
|
+
allowedIds.add("0");
|
|
13380
|
+
for (let i = 0; i <= parentSavedIndex; i++) {
|
|
13381
|
+
if (sections[i]) {
|
|
13382
|
+
if (sections[i].id) allowedIds.add(String(sections[i].id));
|
|
13383
|
+
if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
|
|
13384
|
+
allowedIds.add(sections[i].numericId);
|
|
13385
|
+
allowedIds.add(String(sections[i].numericId));
|
|
13386
|
+
}
|
|
12812
13387
|
}
|
|
12813
13388
|
}
|
|
12814
|
-
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
|
|
12821
|
-
|
|
12822
|
-
|
|
13389
|
+
const rotation = newStack.reduce((acc, step) => {
|
|
13390
|
+
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
13391
|
+
}, 0);
|
|
13392
|
+
handleRenderAncestry(
|
|
13393
|
+
parentAncestryObj,
|
|
13394
|
+
allowedIds,
|
|
13395
|
+
focusTargetId,
|
|
13396
|
+
rotation,
|
|
13397
|
+
false
|
|
13398
|
+
);
|
|
13399
|
+
if (popped && popped.nodeId) {
|
|
13400
|
+
const nodeMesh = stateRef.current.nodeObjects[String(popped.nodeId)];
|
|
13401
|
+
if (nodeMesh) {
|
|
13402
|
+
tweenToTarget(nodeMesh);
|
|
13403
|
+
}
|
|
12823
13404
|
}
|
|
13405
|
+
setReadingMode((prev) => ({
|
|
13406
|
+
...prev,
|
|
13407
|
+
branchStack: newStack,
|
|
13408
|
+
initialSectionId: focusTargetId
|
|
13409
|
+
}));
|
|
12824
13410
|
}
|
|
12825
|
-
|
|
12826
|
-
|
|
12827
|
-
|
|
12828
|
-
initialSectionId: focusTargetId
|
|
12829
|
-
}));
|
|
12830
|
-
}
|
|
12831
|
-
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
13411
|
+
},
|
|
13412
|
+
[readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]
|
|
13413
|
+
);
|
|
12832
13414
|
const handleReadModeHighlight = useCallback4((nodeId) => {
|
|
12833
13415
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
12834
13416
|
stateRef.current.highlightedNodeId = nodeId;
|
|
@@ -12836,7 +13418,8 @@ function XViewScene({
|
|
|
12836
13418
|
setHighlightedNodeId(nodeId);
|
|
12837
13419
|
}, []);
|
|
12838
13420
|
const activeNodeBranches = useMemo12(() => {
|
|
12839
|
-
if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
|
|
13421
|
+
if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
|
|
13422
|
+
return null;
|
|
12840
13423
|
const fullTree = buildFullAncestryTree(
|
|
12841
13424
|
readingMode.ancestry.tree,
|
|
12842
13425
|
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
@@ -12871,7 +13454,13 @@ function XViewScene({
|
|
|
12871
13454
|
};
|
|
12872
13455
|
}
|
|
12873
13456
|
return null;
|
|
12874
|
-
}, [
|
|
13457
|
+
}, [
|
|
13458
|
+
highlightedNodeId,
|
|
13459
|
+
readingMode.ancestry,
|
|
13460
|
+
buildFullAncestryTree,
|
|
13461
|
+
readingMode.branchStack,
|
|
13462
|
+
ancestryDataRef.current
|
|
13463
|
+
]);
|
|
12875
13464
|
const backNavigationInfo = useMemo12(() => {
|
|
12876
13465
|
const { branchStack } = readingMode;
|
|
12877
13466
|
if (!branchStack || branchStack.length === 0) return null;
|
|
@@ -12907,7 +13496,9 @@ function XViewScene({
|
|
|
12907
13496
|
for (const step of branchStack) {
|
|
12908
13497
|
const found = findNodePath3(currentPtr, step.nodeId);
|
|
12909
13498
|
if (found && found.node.parallel_branches) {
|
|
12910
|
-
const branch = found.node.parallel_branches.find(
|
|
13499
|
+
const branch = found.node.parallel_branches.find(
|
|
13500
|
+
(b) => b.id === step.branchId
|
|
13501
|
+
);
|
|
12911
13502
|
if (branch) {
|
|
12912
13503
|
currentPtr = branch.tree;
|
|
12913
13504
|
currentMeta = branch;
|
|
@@ -12928,17 +13519,26 @@ function XViewScene({
|
|
|
12928
13519
|
if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
|
|
12929
13520
|
return null;
|
|
12930
13521
|
}
|
|
12931
|
-
const allNodes = Object.values(parentDataRef.current || {}).flatMap(
|
|
13522
|
+
const allNodes = Object.values(parentDataRef.current || {}).flatMap(
|
|
13523
|
+
(f) => f.nodes || []
|
|
13524
|
+
);
|
|
12932
13525
|
const allAncestries = ancestryDataRef.current || [];
|
|
12933
13526
|
return buildFullAncestryTree(
|
|
12934
13527
|
readingMode.ancestry.abstraction_tree,
|
|
12935
13528
|
allNodes,
|
|
12936
13529
|
allAncestries
|
|
12937
13530
|
);
|
|
12938
|
-
}, [
|
|
13531
|
+
}, [
|
|
13532
|
+
readingMode.isActive,
|
|
13533
|
+
readingMode.ancestry,
|
|
13534
|
+
buildFullAncestryTree,
|
|
13535
|
+
sceneVersion
|
|
13536
|
+
]);
|
|
12939
13537
|
const handleStartReadingAncestry = useCallback4(
|
|
12940
|
-
async (ancestryObject) => {
|
|
12941
|
-
setContextMenu(
|
|
13538
|
+
async (ancestryObject, renderMode = "full") => {
|
|
13539
|
+
setContextMenu(
|
|
13540
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
13541
|
+
);
|
|
12942
13542
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
12943
13543
|
console.warn("Ancestralidade inv\xE1lida para leitura.");
|
|
12944
13544
|
return;
|
|
@@ -12951,14 +13551,20 @@ function XViewScene({
|
|
|
12951
13551
|
const hasDescription = ancestryObject.description && ancestryObject.description.trim() !== "";
|
|
12952
13552
|
const hasMainTreeNodes = ancestryObject.tree.children && ancestryObject.tree.children.length > 0;
|
|
12953
13553
|
const hasAbstractionNodes = ancestryObject.abstraction_tree && ancestryObject.abstraction_tree.children && ancestryObject.abstraction_tree.children.length > 0;
|
|
12954
|
-
const
|
|
13554
|
+
const isFull = renderMode === "full";
|
|
13555
|
+
const isAncestryOnly = renderMode === "ancestry_only";
|
|
13556
|
+
const isAbstractionOnly = renderMode === "abstraction_only";
|
|
13557
|
+
let shouldRenderAbstraction = isAbstractionOnly;
|
|
13558
|
+
if (isFull) {
|
|
13559
|
+
shouldRenderAbstraction = !hasDescription && !hasMainTreeNodes && hasAbstractionNodes;
|
|
13560
|
+
}
|
|
12955
13561
|
setReadingMode({
|
|
12956
|
-
isActive:
|
|
13562
|
+
isActive: isFull ? hasDescription : false,
|
|
12957
13563
|
ancestry: ancestryObject,
|
|
12958
13564
|
branchStack: [],
|
|
12959
|
-
autoAbstraction:
|
|
13565
|
+
autoAbstraction: shouldRenderAbstraction
|
|
12960
13566
|
});
|
|
12961
|
-
if (
|
|
13567
|
+
if (shouldRenderAbstraction) {
|
|
12962
13568
|
handleRenderAbstractionTree(ancestryObject, null);
|
|
12963
13569
|
} else {
|
|
12964
13570
|
const initialSections = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
@@ -12971,148 +13577,190 @@ function XViewScene({
|
|
|
12971
13577
|
},
|
|
12972
13578
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
12973
13579
|
);
|
|
12974
|
-
const handleReadModeSectionChange = useCallback4(
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
13580
|
+
const handleReadModeSectionChange = useCallback4(
|
|
13581
|
+
(activeSectionId) => {
|
|
13582
|
+
const { ancestry, branchStack } = readingMode;
|
|
13583
|
+
if (!ancestry || !readingMode.isActive) return;
|
|
13584
|
+
let targetObj = ancestry;
|
|
13585
|
+
let targetTree = ancestry.tree;
|
|
13586
|
+
if (branchStack.length > 0) {
|
|
13587
|
+
const allNodes = Object.values(parentDataRef.current).flatMap(
|
|
13588
|
+
(f) => f.nodes
|
|
13589
|
+
);
|
|
13590
|
+
const fullTree = buildFullAncestryTree(
|
|
13591
|
+
ancestry.tree,
|
|
13592
|
+
allNodes,
|
|
13593
|
+
ancestryDataRef.current
|
|
13594
|
+
);
|
|
13595
|
+
let currentPtr = fullTree;
|
|
13596
|
+
for (const step of branchStack) {
|
|
13597
|
+
const found = findNodePath3(currentPtr, step.nodeId);
|
|
13598
|
+
if (found && found.node && found.node.parallel_branches) {
|
|
13599
|
+
const branch = found.node.parallel_branches.find(
|
|
13600
|
+
(b) => b.id === step.branchId
|
|
13601
|
+
);
|
|
13602
|
+
if (branch) {
|
|
13603
|
+
targetObj = branch;
|
|
13604
|
+
targetTree = branch.tree;
|
|
13605
|
+
currentPtr = branch.tree;
|
|
13606
|
+
}
|
|
12995
13607
|
}
|
|
12996
13608
|
}
|
|
12997
13609
|
}
|
|
12998
|
-
|
|
12999
|
-
|
|
13000
|
-
|
|
13001
|
-
|
|
13002
|
-
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13012
|
-
|
|
13013
|
-
|
|
13014
|
-
|
|
13015
|
-
|
|
13016
|
-
|
|
13017
|
-
|
|
13018
|
-
|
|
13019
|
-
allowedIds.add(String(sections[i].
|
|
13610
|
+
const descriptionText = targetObj.description || "";
|
|
13611
|
+
const savedSections = targetObj.description_sections || [];
|
|
13612
|
+
const sections = parseDescriptionSections(descriptionText, savedSections);
|
|
13613
|
+
let activeIndex = sections.findIndex(
|
|
13614
|
+
(s) => String(s.id) === String(activeSectionId)
|
|
13615
|
+
);
|
|
13616
|
+
if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
|
|
13617
|
+
activeIndex = sections.findIndex(
|
|
13618
|
+
(s) => s.numericId === parseInt(activeSectionId)
|
|
13619
|
+
);
|
|
13620
|
+
}
|
|
13621
|
+
if (activeIndex === -1) activeIndex = 0;
|
|
13622
|
+
stateRef.current.readMode.currentMaxIndex = activeIndex;
|
|
13623
|
+
stateRef.current.maxAncestryRenderIndex = activeIndex;
|
|
13624
|
+
const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
|
|
13625
|
+
const allowedIds = /* @__PURE__ */ new Set();
|
|
13626
|
+
allowedIds.add("preamble");
|
|
13627
|
+
allowedIds.add(0);
|
|
13628
|
+
allowedIds.add("0");
|
|
13629
|
+
for (let i = 0; i <= renderLimitIndex; i++) {
|
|
13630
|
+
if (sections[i]) {
|
|
13631
|
+
if (sections[i].id) allowedIds.add(String(sections[i].id));
|
|
13632
|
+
if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
|
|
13633
|
+
allowedIds.add(sections[i].numericId);
|
|
13634
|
+
allowedIds.add(String(sections[i].numericId));
|
|
13635
|
+
}
|
|
13020
13636
|
}
|
|
13021
13637
|
}
|
|
13022
|
-
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13638
|
+
const activeSection = sections[activeIndex];
|
|
13639
|
+
let focusTargetId = activeSectionId;
|
|
13640
|
+
if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
|
|
13641
|
+
focusTargetId = activeSection.numericId;
|
|
13642
|
+
}
|
|
13643
|
+
const currentStackItem = branchStack.length > 0 ? branchStack[branchStack.length - 1] : null;
|
|
13644
|
+
const renderPayload = {
|
|
13645
|
+
...targetObj,
|
|
13646
|
+
ancestry_id: targetObj.ancestry_id || targetObj.id,
|
|
13647
|
+
ancestral_node: targetTree.node ? targetTree.node.id : targetTree.node_id,
|
|
13648
|
+
tree: targetTree,
|
|
13649
|
+
_originNodeId: currentStackItem ? currentStackItem.nodeId : null,
|
|
13650
|
+
_branchDirection: currentStackItem ? currentStackItem.entryDirection : null,
|
|
13651
|
+
_forceUpdate: true
|
|
13652
|
+
};
|
|
13653
|
+
const rotation = branchStack.reduce((acc, step) => {
|
|
13654
|
+
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
13655
|
+
}, 0);
|
|
13656
|
+
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
13657
|
+
},
|
|
13658
|
+
[
|
|
13659
|
+
readingMode,
|
|
13660
|
+
handleRenderAncestry,
|
|
13661
|
+
buildFullAncestryTree,
|
|
13662
|
+
ancestryDataRef.current
|
|
13663
|
+
]
|
|
13664
|
+
);
|
|
13043
13665
|
const handleCloseReadMode = useCallback4(() => {
|
|
13044
13666
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
13045
13667
|
}, []);
|
|
13046
|
-
const handleAncestrySectionChange = useCallback4(
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13668
|
+
const handleAncestrySectionChange = useCallback4(
|
|
13669
|
+
(activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
13670
|
+
var _a2, _b2;
|
|
13671
|
+
const currentMode = stateRef.current.ancestry;
|
|
13672
|
+
let targetObj = ancestryOverride;
|
|
13673
|
+
if (!targetObj) {
|
|
13674
|
+
const currentAncestryId = currentMode.currentAncestryId;
|
|
13675
|
+
const ancestryObj = (ancestryDataRef.current || []).find(
|
|
13676
|
+
(a) => String(a.ancestry_id) === String(currentAncestryId)
|
|
13677
|
+
);
|
|
13678
|
+
targetObj = ancestryObj || (currentMode.isActive ? {
|
|
13679
|
+
...currentMode,
|
|
13680
|
+
ancestry_id: "temp_creating",
|
|
13681
|
+
ancestral_node: (_b2 = (_a2 = currentMode.tree) == null ? void 0 : _a2.node) == null ? void 0 : _b2.id
|
|
13682
|
+
} : null);
|
|
13683
|
+
}
|
|
13684
|
+
if (!targetObj) return;
|
|
13685
|
+
const targetId = targetObj.ancestry_id || targetObj.id;
|
|
13686
|
+
if (stateRef.current.lastRenderedAncestryId !== targetId) {
|
|
13687
|
+
stateRef.current.maxAncestryRenderIndex = 0;
|
|
13688
|
+
stateRef.current.lastRenderedAncestryId = targetId;
|
|
13689
|
+
}
|
|
13690
|
+
const descriptionText = (ancestryOverride ? targetObj.description : currentMode.ancestryDescription) || targetObj.description || "";
|
|
13691
|
+
const savedSections = (ancestryOverride ? targetObj.description_sections : currentMode.ancestryDescriptionSections) || targetObj.description_sections || [];
|
|
13692
|
+
const sections = parseDescriptionSections(descriptionText, savedSections);
|
|
13693
|
+
let activeIndex = sections.findIndex(
|
|
13694
|
+
(s) => String(s.id) === String(activeSectionId)
|
|
13695
|
+
);
|
|
13696
|
+
if (activeIndex === -1 && !isNaN(parseInt(activeSectionId))) {
|
|
13697
|
+
activeIndex = sections.findIndex(
|
|
13698
|
+
(s) => s.numericId === parseInt(activeSectionId)
|
|
13699
|
+
);
|
|
13700
|
+
}
|
|
13701
|
+
if (activeIndex === -1) activeIndex = 0;
|
|
13702
|
+
if (stateRef.current.maxAncestryRenderIndex === void 0)
|
|
13703
|
+
stateRef.current.maxAncestryRenderIndex = 0;
|
|
13704
|
+
stateRef.current.maxAncestryRenderIndex = activeIndex;
|
|
13705
|
+
const renderLimitIndex = stateRef.current.maxAncestryRenderIndex;
|
|
13706
|
+
const allowedIds = /* @__PURE__ */ new Set();
|
|
13707
|
+
allowedIds.add("preamble");
|
|
13708
|
+
allowedIds.add(0);
|
|
13709
|
+
allowedIds.add("0");
|
|
13710
|
+
for (let i = 0; i <= renderLimitIndex; i++) {
|
|
13711
|
+
if (sections[i]) {
|
|
13712
|
+
if (sections[i].id) allowedIds.add(String(sections[i].id));
|
|
13713
|
+
if (sections[i].numericId !== void 0 && sections[i].numericId !== null) {
|
|
13714
|
+
allowedIds.add(sections[i].numericId);
|
|
13715
|
+
allowedIds.add(String(sections[i].numericId));
|
|
13716
|
+
}
|
|
13086
13717
|
}
|
|
13087
13718
|
}
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13719
|
+
const activeSection = sections[activeIndex];
|
|
13720
|
+
let focusTargetId = activeSectionId;
|
|
13721
|
+
if (activeSection && activeSection.numericId !== void 0 && activeSection.numericId !== null) {
|
|
13722
|
+
focusTargetId = activeSection.numericId;
|
|
13723
|
+
}
|
|
13724
|
+
const treeToRender = ancestryOverride ? ancestryOverride.tree : currentMode.isActive && currentMode.tree ? currentMode.tree : targetObj.tree;
|
|
13725
|
+
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
13726
|
+
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
13727
|
+
},
|
|
13728
|
+
[handleRenderAncestry]
|
|
13729
|
+
);
|
|
13098
13730
|
const handleEditAncestry = useCallback4(
|
|
13099
13731
|
async (ancestryObject) => {
|
|
13100
|
-
setContextMenu(
|
|
13732
|
+
setContextMenu(
|
|
13733
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
13734
|
+
);
|
|
13101
13735
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
13102
|
-
alert(
|
|
13736
|
+
alert(
|
|
13737
|
+
"N\xE3o foi poss\xEDvel carregar os dados desta ancestralidade para edi\xE7\xE3o."
|
|
13738
|
+
);
|
|
13103
13739
|
return;
|
|
13104
13740
|
}
|
|
13105
13741
|
stateRef.current.maxAncestryRenderIndex = 0;
|
|
13106
13742
|
const initialSections = /* @__PURE__ */ new Set(["preamble", 0]);
|
|
13107
13743
|
await handleRenderAncestry(ancestryObject, initialSections);
|
|
13108
|
-
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
13744
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap(
|
|
13745
|
+
(fileData) => fileData.nodes
|
|
13746
|
+
);
|
|
13109
13747
|
const allAncestries = ancestryDataRef.current || [];
|
|
13110
|
-
const fullTree = buildFullAncestryTree(
|
|
13748
|
+
const fullTree = buildFullAncestryTree(
|
|
13749
|
+
ancestryObject.tree,
|
|
13750
|
+
allParentNodes,
|
|
13751
|
+
allAncestries
|
|
13752
|
+
);
|
|
13111
13753
|
if (!fullTree) {
|
|
13112
|
-
alert(
|
|
13754
|
+
alert(
|
|
13755
|
+
"Falha ao reconstruir a \xE1rvore de ancestralidade. Alguns Nodes podem estar faltando."
|
|
13756
|
+
);
|
|
13113
13757
|
return;
|
|
13114
13758
|
}
|
|
13115
|
-
const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(
|
|
13759
|
+
const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(
|
|
13760
|
+
ancestryObject.abstraction_tree,
|
|
13761
|
+
allParentNodes,
|
|
13762
|
+
allAncestries
|
|
13763
|
+
) : { node: fullTree.node, children: [] };
|
|
13116
13764
|
setAncestryMode({
|
|
13117
13765
|
isActive: true,
|
|
13118
13766
|
...ancestryObject,
|
|
@@ -13164,7 +13812,9 @@ function XViewScene({
|
|
|
13164
13812
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
13165
13813
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
13166
13814
|
if (!treeToUse || !treeToUse.node) {
|
|
13167
|
-
alert(
|
|
13815
|
+
alert(
|
|
13816
|
+
"Erro: A estrutura da ancestralidade \xE9 inv\xE1lida (Node raiz ausente)."
|
|
13817
|
+
);
|
|
13168
13818
|
return;
|
|
13169
13819
|
}
|
|
13170
13820
|
if (!save_view_data || !stateRef.current.nodeIdToParentFileMap) return;
|
|
@@ -13197,14 +13847,18 @@ function XViewScene({
|
|
|
13197
13847
|
};
|
|
13198
13848
|
};
|
|
13199
13849
|
const treeWithIds = convertTreeToIds(treeToUse);
|
|
13200
|
-
const abstractionTreeWithIds = convertTreeToIds(
|
|
13850
|
+
const abstractionTreeWithIds = convertTreeToIds(
|
|
13851
|
+
ancestryMode.abstraction_tree
|
|
13852
|
+
);
|
|
13201
13853
|
if (!treeWithIds) {
|
|
13202
13854
|
alert("Erro ao processar a \xE1rvore da ancestralidade.");
|
|
13203
13855
|
return;
|
|
13204
13856
|
}
|
|
13205
13857
|
let originalAncestryObj = null;
|
|
13206
13858
|
if (isEditMode && currentAncestryId) {
|
|
13207
|
-
originalAncestryObj = (ancestryDataRef.current || []).find(
|
|
13859
|
+
originalAncestryObj = (ancestryDataRef.current || []).find(
|
|
13860
|
+
(anc) => String(anc.ancestry_id) === String(currentAncestryId)
|
|
13861
|
+
);
|
|
13208
13862
|
}
|
|
13209
13863
|
const ancestryObjectToSave = {
|
|
13210
13864
|
ancestry_id: isEditMode && currentAncestryId ? currentAncestryId : `${short2.generate()}`,
|
|
@@ -13287,14 +13941,20 @@ function XViewScene({
|
|
|
13287
13941
|
try {
|
|
13288
13942
|
if (isExternalSave) {
|
|
13289
13943
|
try {
|
|
13290
|
-
const remoteResponse = await get_ancestry_file(
|
|
13944
|
+
const remoteResponse = await get_ancestry_file(
|
|
13945
|
+
targetFileIdForCache,
|
|
13946
|
+
targetOwnerIdForCache
|
|
13947
|
+
);
|
|
13291
13948
|
if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
|
|
13292
13949
|
masterAncestryList = remoteResponse.data;
|
|
13293
13950
|
} else {
|
|
13294
13951
|
masterAncestryList = [];
|
|
13295
13952
|
}
|
|
13296
13953
|
} catch (fetchErr) {
|
|
13297
|
-
console.warn(
|
|
13954
|
+
console.warn(
|
|
13955
|
+
"Arquivo de destino n\xE3o existe ou erro ao buscar, criando novo:",
|
|
13956
|
+
fetchErr
|
|
13957
|
+
);
|
|
13298
13958
|
masterAncestryList = [];
|
|
13299
13959
|
}
|
|
13300
13960
|
} else {
|
|
@@ -13314,7 +13974,9 @@ function XViewScene({
|
|
|
13314
13974
|
const result = await save_view_data(finalSaveUrl, masterAncestryList);
|
|
13315
13975
|
if (result.success) {
|
|
13316
13976
|
const localList = [...ancestryDataRef.current || []];
|
|
13317
|
-
const localIndex = localList.findIndex(
|
|
13977
|
+
const localIndex = localList.findIndex(
|
|
13978
|
+
(a) => String(a.ancestry_id) === String(ancestryObjectToSave.ancestry_id)
|
|
13979
|
+
);
|
|
13318
13980
|
if (localIndex !== -1) {
|
|
13319
13981
|
localList[localIndex] = ancestryObjectToSave;
|
|
13320
13982
|
} else {
|
|
@@ -13342,11 +14004,29 @@ function XViewScene({
|
|
|
13342
14004
|
return;
|
|
13343
14005
|
}
|
|
13344
14006
|
if (!keepOpen) {
|
|
13345
|
-
setAncestryMode({
|
|
14007
|
+
setAncestryMode({
|
|
14008
|
+
isActive: false,
|
|
14009
|
+
tree: null,
|
|
14010
|
+
selectedParentId: null,
|
|
14011
|
+
isEditMode: false,
|
|
14012
|
+
currentAncestryId: null,
|
|
14013
|
+
ancestryName: "",
|
|
14014
|
+
ancestryDescription: "",
|
|
14015
|
+
ancestryDescriptionSections: [],
|
|
14016
|
+
isAddingNodes: false
|
|
14017
|
+
});
|
|
13346
14018
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13347
14019
|
}
|
|
13348
14020
|
},
|
|
13349
|
-
[
|
|
14021
|
+
[
|
|
14022
|
+
ancestryMode,
|
|
14023
|
+
ancestry_save_url,
|
|
14024
|
+
handleRenderAncestry,
|
|
14025
|
+
save_view_data,
|
|
14026
|
+
sceneConfigId,
|
|
14027
|
+
ownerId,
|
|
14028
|
+
get_ancestry_file
|
|
14029
|
+
]
|
|
13350
14030
|
);
|
|
13351
14031
|
const handleOpenAncestryRelEditor = (path, currentData) => {
|
|
13352
14032
|
setEditingAncestryRel({ visible: true, data: currentData, path });
|
|
@@ -13376,7 +14056,9 @@ function XViewScene({
|
|
|
13376
14056
|
if (ancestryToDelete && delete_file_action) {
|
|
13377
14057
|
const urls = extractFileUrlsFromProperties(ancestryToDelete);
|
|
13378
14058
|
if (urls.length > 0) {
|
|
13379
|
-
Promise.all(urls.map((url) => delete_file_action(url))).catch(
|
|
14059
|
+
Promise.all(urls.map((url) => delete_file_action(url))).catch(
|
|
14060
|
+
(err) => console.error("Erro ao deletar arquivos da ancestralidade:", err)
|
|
14061
|
+
);
|
|
13380
14062
|
}
|
|
13381
14063
|
}
|
|
13382
14064
|
if (!ancestryToDelete) {
|
|
@@ -13386,7 +14068,9 @@ function XViewScene({
|
|
|
13386
14068
|
const sourceFileId = ancestryToDelete._source_file_id;
|
|
13387
14069
|
const sourceOwnerId = ancestryToDelete._source_owner_id;
|
|
13388
14070
|
if (!sourceFileId || !sourceOwnerId) {
|
|
13389
|
-
alert(
|
|
14071
|
+
alert(
|
|
14072
|
+
"N\xE3o foi poss\xEDvel identificar o arquivo de origem desta ancestralidade."
|
|
14073
|
+
);
|
|
13390
14074
|
return;
|
|
13391
14075
|
}
|
|
13392
14076
|
const finalSaveUrl = `x_view_ancestry/${sourceOwnerId}/${sourceFileId}`;
|
|
@@ -13394,13 +14078,18 @@ function XViewScene({
|
|
|
13394
14078
|
(anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
|
|
13395
14079
|
);
|
|
13396
14080
|
try {
|
|
13397
|
-
const result = await save_view_data(
|
|
14081
|
+
const result = await save_view_data(
|
|
14082
|
+
finalSaveUrl,
|
|
14083
|
+
updatedAncestriesForFile
|
|
14084
|
+
);
|
|
13398
14085
|
if (result.success) {
|
|
13399
14086
|
ancestryDataRef.current = (ancestryDataRef.current || []).filter(
|
|
13400
14087
|
(ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
|
|
13401
14088
|
);
|
|
13402
14089
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
13403
|
-
const renderIndex = renderedAncestries.findIndex(
|
|
14090
|
+
const renderIndex = renderedAncestries.findIndex(
|
|
14091
|
+
(a) => String(a.id) === String(ancestryIdToDelete)
|
|
14092
|
+
);
|
|
13404
14093
|
if (renderIndex !== -1) {
|
|
13405
14094
|
const toRemove = renderedAncestries[renderIndex];
|
|
13406
14095
|
toRemove.lines.forEach((line) => {
|
|
@@ -13409,18 +14098,29 @@ function XViewScene({
|
|
|
13409
14098
|
if (line.material) line.material.dispose();
|
|
13410
14099
|
});
|
|
13411
14100
|
renderedAncestries.splice(renderIndex, 1);
|
|
13412
|
-
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
14101
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap(
|
|
14102
|
+
(a) => a.lines
|
|
14103
|
+
);
|
|
13413
14104
|
}
|
|
13414
14105
|
setSceneVersion((v) => v + 1);
|
|
13415
14106
|
} else {
|
|
13416
|
-
throw new Error(
|
|
14107
|
+
throw new Error(
|
|
14108
|
+
result.error || "Ocorreu um erro desconhecido ao excluir."
|
|
14109
|
+
);
|
|
13417
14110
|
}
|
|
13418
14111
|
} catch (error) {
|
|
13419
14112
|
console.error("Falha ao excluir a ancestralidade:", error);
|
|
13420
14113
|
alert(`Erro ao excluir a ancestralidade: ${error.message}`);
|
|
13421
14114
|
return;
|
|
13422
14115
|
}
|
|
13423
|
-
setAncestryMode({
|
|
14116
|
+
setAncestryMode({
|
|
14117
|
+
isActive: false,
|
|
14118
|
+
tree: null,
|
|
14119
|
+
selectedParentId: null,
|
|
14120
|
+
isEditMode: false,
|
|
14121
|
+
currentAncestryId: null,
|
|
14122
|
+
ancestryName: ""
|
|
14123
|
+
});
|
|
13424
14124
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13425
14125
|
},
|
|
13426
14126
|
[save_view_data, delete_file_action]
|
|
@@ -13428,24 +14128,38 @@ function XViewScene({
|
|
|
13428
14128
|
const handleOpenAncestryBoard = useCallback4(() => {
|
|
13429
14129
|
setIsAncestryBoardOpen(true);
|
|
13430
14130
|
}, []);
|
|
13431
|
-
const handleSelectAncestryFromBoard = useCallback4(
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
14131
|
+
const handleSelectAncestryFromBoard = useCallback4(
|
|
14132
|
+
(ancestry) => {
|
|
14133
|
+
setIsAncestryBoardOpen(false);
|
|
14134
|
+
setIsSidebarOpen(false);
|
|
14135
|
+
handleStartReadingAncestry(ancestry);
|
|
14136
|
+
},
|
|
14137
|
+
[handleStartReadingAncestry]
|
|
14138
|
+
);
|
|
14139
|
+
const handleSaveAncestryBoard = useCallback4(
|
|
14140
|
+
async (groups) => {
|
|
14141
|
+
if (!sceneConfigId || !viewParams || !session) return;
|
|
14142
|
+
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
14143
|
+
await save_ancestry_board_action(
|
|
14144
|
+
sceneConfigId,
|
|
14145
|
+
sceneType,
|
|
14146
|
+
groups,
|
|
14147
|
+
session,
|
|
14148
|
+
ownerId
|
|
14149
|
+
);
|
|
14150
|
+
},
|
|
14151
|
+
[sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]
|
|
14152
|
+
);
|
|
13441
14153
|
const existingNodeTypes = useMemo12(() => {
|
|
13442
14154
|
if (!parentDataRef.current) {
|
|
13443
14155
|
return [];
|
|
13444
14156
|
}
|
|
13445
|
-
const allTypes = Object.values(parentDataRef.current).flatMap(
|
|
13446
|
-
|
|
13447
|
-
|
|
13448
|
-
|
|
14157
|
+
const allTypes = Object.values(parentDataRef.current).flatMap(
|
|
14158
|
+
(fileData) => fileData.nodes.flatMap((node) => {
|
|
14159
|
+
if (Array.isArray(node.type)) return node.type;
|
|
14160
|
+
return [node.type];
|
|
14161
|
+
})
|
|
14162
|
+
).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
|
|
13449
14163
|
return [...new Set(allTypes)];
|
|
13450
14164
|
}, [parentDataRef.current, sceneVersion]);
|
|
13451
14165
|
const searchableDbNodes = useMemo12(() => {
|
|
@@ -13459,7 +14173,10 @@ function XViewScene({
|
|
|
13459
14173
|
}, [parentDataRef.current, sceneVersion]);
|
|
13460
14174
|
const handleAddExistingNode = useCallback4(
|
|
13461
14175
|
(nodeId) => {
|
|
13462
|
-
return userActionHandlers.handleAddExistingNodeById(
|
|
14176
|
+
return userActionHandlers.handleAddExistingNodeById(
|
|
14177
|
+
actionHandlerContext,
|
|
14178
|
+
nodeId
|
|
14179
|
+
);
|
|
13463
14180
|
},
|
|
13464
14181
|
[actionHandlerContext]
|
|
13465
14182
|
);
|
|
@@ -13467,7 +14184,9 @@ function XViewScene({
|
|
|
13467
14184
|
var _a2, _b2, _c2;
|
|
13468
14185
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
13469
14186
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
13470
|
-
console.warn(
|
|
14187
|
+
console.warn(
|
|
14188
|
+
"N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente."
|
|
14189
|
+
);
|
|
13471
14190
|
return;
|
|
13472
14191
|
}
|
|
13473
14192
|
if (!save_view_data) return;
|
|
@@ -13504,48 +14223,68 @@ function XViewScene({
|
|
|
13504
14223
|
}, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
|
|
13505
14224
|
const allAvailableNodes = useMemo12(() => {
|
|
13506
14225
|
if (!parentDataRef.current) return [];
|
|
13507
|
-
return Object.values(parentDataRef.current).flatMap(
|
|
14226
|
+
return Object.values(parentDataRef.current).flatMap(
|
|
14227
|
+
(fileData) => fileData.nodes || []
|
|
14228
|
+
);
|
|
13508
14229
|
}, [sceneVersion, isInitialized]);
|
|
13509
14230
|
const allAvailableAncestries = useMemo12(() => {
|
|
13510
14231
|
return ancestryDataRef.current || [];
|
|
13511
14232
|
}, [sceneVersion, isInitialized]);
|
|
13512
|
-
const handleOpenReference = useCallback4(
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
14233
|
+
const handleOpenReference = useCallback4(
|
|
14234
|
+
(referenceData) => {
|
|
14235
|
+
const { type, id } = referenceData;
|
|
14236
|
+
if (type === "node") {
|
|
14237
|
+
const targetNode = allAvailableNodes.find(
|
|
14238
|
+
(n) => String(n.id) === String(id)
|
|
14239
|
+
);
|
|
14240
|
+
if (targetNode) {
|
|
14241
|
+
setAncestryLinkDetails(null);
|
|
14242
|
+
setDetailsLink(null);
|
|
14243
|
+
setDetailsNode(targetNode);
|
|
14244
|
+
const sceneMesh = stateRef.current.nodeObjects[String(id)];
|
|
14245
|
+
if (sceneMesh) {
|
|
14246
|
+
tweenToTarget(sceneMesh);
|
|
14247
|
+
}
|
|
14248
|
+
} else {
|
|
14249
|
+
alert("Node original n\xE3o encontrado neste contexto.");
|
|
14250
|
+
}
|
|
14251
|
+
} else if (type === "ancestry") {
|
|
14252
|
+
const targetAncestry = allAvailableAncestries.find(
|
|
14253
|
+
(a) => String(a.ancestry_id) === String(id)
|
|
14254
|
+
);
|
|
14255
|
+
if (targetAncestry) {
|
|
14256
|
+
setDetailsNode(null);
|
|
14257
|
+
setDetailsLink(null);
|
|
14258
|
+
setAncestryLinkDetails(null);
|
|
14259
|
+
handleEditAncestry(targetAncestry);
|
|
14260
|
+
} else {
|
|
14261
|
+
alert("Ancestralidade original n\xE3o encontrada neste contexto.");
|
|
13523
14262
|
}
|
|
13524
|
-
} else {
|
|
13525
|
-
alert("Node original n\xE3o encontrado neste contexto.");
|
|
13526
|
-
}
|
|
13527
|
-
} else if (type === "ancestry") {
|
|
13528
|
-
const targetAncestry = allAvailableAncestries.find((a) => String(a.ancestry_id) === String(id));
|
|
13529
|
-
if (targetAncestry) {
|
|
13530
|
-
setDetailsNode(null);
|
|
13531
|
-
setDetailsLink(null);
|
|
13532
|
-
setAncestryLinkDetails(null);
|
|
13533
|
-
handleEditAncestry(targetAncestry);
|
|
13534
|
-
} else {
|
|
13535
|
-
alert("Ancestralidade original n\xE3o encontrada neste contexto.");
|
|
13536
14263
|
}
|
|
13537
|
-
}
|
|
13538
|
-
|
|
14264
|
+
},
|
|
14265
|
+
[
|
|
14266
|
+
allAvailableNodes,
|
|
14267
|
+
allAvailableAncestries,
|
|
14268
|
+
handleEditAncestry,
|
|
14269
|
+
tweenToTarget
|
|
14270
|
+
]
|
|
14271
|
+
);
|
|
13539
14272
|
const handleToggleAncestryAddMode = useCallback4(() => {
|
|
13540
|
-
setAncestryMode((prev) => ({
|
|
14273
|
+
setAncestryMode((prev) => ({
|
|
14274
|
+
...prev,
|
|
14275
|
+
isAddingNodes: !prev.isAddingNodes
|
|
14276
|
+
}));
|
|
13541
14277
|
}, []);
|
|
13542
|
-
const handleFocusNode = useCallback4(
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
14278
|
+
const handleFocusNode = useCallback4(
|
|
14279
|
+
(nodeData) => {
|
|
14280
|
+
if (!nodeData) return;
|
|
14281
|
+
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
14282
|
+
if (nodeMesh) {
|
|
14283
|
+
tweenToTarget(nodeMesh, 1.2);
|
|
14284
|
+
}
|
|
14285
|
+
},
|
|
14286
|
+
[tweenToTarget]
|
|
14287
|
+
);
|
|
13549
14288
|
const availableDatasets = useMemo12(() => {
|
|
13550
14289
|
if (!sceneDataRef.current || !parentDataRef.current) return [];
|
|
13551
14290
|
return sceneDataRef.current.parent_dbs.map((db) => {
|
|
@@ -13556,7 +14295,9 @@ function XViewScene({
|
|
|
13556
14295
|
};
|
|
13557
14296
|
});
|
|
13558
14297
|
}, [sceneVersion, isInitialized]);
|
|
13559
|
-
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
|
|
14298
|
+
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
|
|
14299
|
+
String(creationMode.sourceNodeData.id)
|
|
14300
|
+
)) == null ? void 0 : _b.parentFileId : null;
|
|
13560
14301
|
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
13561
14302
|
useEffect22(() => {
|
|
13562
14303
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
@@ -13571,11 +14312,19 @@ function XViewScene({
|
|
|
13571
14312
|
setHasFocusedInitial(true);
|
|
13572
14313
|
}
|
|
13573
14314
|
}
|
|
13574
|
-
}, [
|
|
14315
|
+
}, [
|
|
14316
|
+
isInitialized,
|
|
14317
|
+
sceneVersion,
|
|
14318
|
+
focusNodeId,
|
|
14319
|
+
hasFocusedInitial,
|
|
14320
|
+
tweenToTarget
|
|
14321
|
+
]);
|
|
13575
14322
|
useEffect22(() => {
|
|
13576
14323
|
if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
|
|
13577
14324
|
const ancestries = ancestryDataRef.current || [];
|
|
13578
|
-
const targetAncestry = ancestries.find(
|
|
14325
|
+
const targetAncestry = ancestries.find(
|
|
14326
|
+
(a) => String(a.ancestry_id) === String(focusAncestryId)
|
|
14327
|
+
);
|
|
13579
14328
|
if (targetAncestry) {
|
|
13580
14329
|
setTimeout(() => {
|
|
13581
14330
|
handleStartReadingAncestry(targetAncestry);
|
|
@@ -13585,18 +14334,38 @@ function XViewScene({
|
|
|
13585
14334
|
setHasOpenedInitialAncestry(true);
|
|
13586
14335
|
}
|
|
13587
14336
|
}
|
|
13588
|
-
}, [
|
|
14337
|
+
}, [
|
|
14338
|
+
isInitialized,
|
|
14339
|
+
sceneVersion,
|
|
14340
|
+
focusAncestryId,
|
|
14341
|
+
hasOpenedInitialAncestry,
|
|
14342
|
+
handleStartReadingAncestry
|
|
14343
|
+
]);
|
|
13589
14344
|
useEffect22(() => {
|
|
13590
14345
|
function handleKeyDown(event) {
|
|
13591
14346
|
var _a2, _b2, _c2;
|
|
13592
14347
|
const context = actionHandlerContext;
|
|
13593
14348
|
if (event.key === "Escape") {
|
|
13594
|
-
if (stateRef.current.connection.isActive)
|
|
13595
|
-
|
|
13596
|
-
if (stateRef.current.
|
|
13597
|
-
|
|
14349
|
+
if (stateRef.current.connection.isActive)
|
|
14350
|
+
userActionHandlers.handleCancelConnection(context);
|
|
14351
|
+
if (stateRef.current.relink.isActive)
|
|
14352
|
+
userActionHandlers.handleCancelRelink(context);
|
|
14353
|
+
if (stateRef.current.creation.isActive)
|
|
14354
|
+
userActionHandlers.handleCancelCreation(context);
|
|
14355
|
+
if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive)
|
|
14356
|
+
userActionHandlers.handleCancelVersioning(context);
|
|
13598
14357
|
if (stateRef.current.ancestry.isActive) {
|
|
13599
|
-
setAncestryMode({
|
|
14358
|
+
setAncestryMode({
|
|
14359
|
+
isActive: false,
|
|
14360
|
+
tree: null,
|
|
14361
|
+
selectedParentId: null,
|
|
14362
|
+
isEditMode: false,
|
|
14363
|
+
currentAncestryId: null,
|
|
14364
|
+
ancestryName: "",
|
|
14365
|
+
ancestryDescription: "",
|
|
14366
|
+
ancestryDescriptionSections: [],
|
|
14367
|
+
isAddingNodes: false
|
|
14368
|
+
});
|
|
13600
14369
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13601
14370
|
}
|
|
13602
14371
|
if (questMode.isActive) {
|
|
@@ -13605,7 +14374,9 @@ function XViewScene({
|
|
|
13605
14374
|
if (stateRef.current.selectedNodes.size > 0) {
|
|
13606
14375
|
stateRef.current.selectedNodes.clear();
|
|
13607
14376
|
}
|
|
13608
|
-
setContextMenu(
|
|
14377
|
+
setContextMenu(
|
|
14378
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
14379
|
+
);
|
|
13609
14380
|
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
13610
14381
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
13611
14382
|
}
|
|
@@ -13624,7 +14395,9 @@ function XViewScene({
|
|
|
13624
14395
|
let attempts = 0;
|
|
13625
14396
|
const MIN_CLEARANCE = 15;
|
|
13626
14397
|
while (isOccupied && attempts < 30) {
|
|
13627
|
-
isOccupied = existingNodes.some(
|
|
14398
|
+
isOccupied = existingNodes.some(
|
|
14399
|
+
(mesh) => mesh.position.distanceTo(ghostPosition) < MIN_CLEARANCE
|
|
14400
|
+
);
|
|
13628
14401
|
if (isOccupied) {
|
|
13629
14402
|
ghostPosition.x = controls.target.x + Math.cos(angle) * radius;
|
|
13630
14403
|
ghostPosition.y = controls.target.y + (Math.random() - 0.5) * 8;
|
|
@@ -13643,7 +14416,11 @@ function XViewScene({
|
|
|
13643
14416
|
intensity: 0,
|
|
13644
14417
|
type: ["quest"]
|
|
13645
14418
|
};
|
|
13646
|
-
const ghostNode = createNodeMesh(
|
|
14419
|
+
const ghostNode = createNodeMesh(
|
|
14420
|
+
ghostData,
|
|
14421
|
+
ghostPosition,
|
|
14422
|
+
glowTexture
|
|
14423
|
+
);
|
|
13647
14424
|
ghostNode.traverse((child) => {
|
|
13648
14425
|
if (child.isMesh) {
|
|
13649
14426
|
child.material.transparent = true;
|
|
@@ -13690,13 +14467,49 @@ function XViewScene({
|
|
|
13690
14467
|
return /* @__PURE__ */ React25.createElement(LoadingScreen, null);
|
|
13691
14468
|
}
|
|
13692
14469
|
if (permissionStatus === "denied") {
|
|
13693
|
-
return /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React25.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React25.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React25.createElement(
|
|
14470
|
+
return /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React25.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React25.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React25.createElement(
|
|
14471
|
+
"svg",
|
|
14472
|
+
{
|
|
14473
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14474
|
+
fill: "none",
|
|
14475
|
+
viewBox: "0 0 24 24",
|
|
14476
|
+
strokeWidth: 1.5,
|
|
14477
|
+
stroke: "currentColor",
|
|
14478
|
+
className: "w-16 h-16 mx-auto"
|
|
14479
|
+
},
|
|
14480
|
+
/* @__PURE__ */ React25.createElement(
|
|
14481
|
+
"path",
|
|
14482
|
+
{
|
|
14483
|
+
strokeLinecap: "round",
|
|
14484
|
+
strokeLinejoin: "round",
|
|
14485
|
+
d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
|
|
14486
|
+
}
|
|
14487
|
+
)
|
|
14488
|
+
)), /* @__PURE__ */ React25.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React25.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React25.createElement(
|
|
13694
14489
|
"button",
|
|
13695
14490
|
{
|
|
13696
14491
|
onClick: () => router.push("/dashboard/scenes"),
|
|
13697
14492
|
className: "flex items-center justify-center gap-2 w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors font-medium"
|
|
13698
14493
|
},
|
|
13699
|
-
/* @__PURE__ */ React25.createElement(
|
|
14494
|
+
/* @__PURE__ */ React25.createElement(
|
|
14495
|
+
"svg",
|
|
14496
|
+
{
|
|
14497
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
14498
|
+
fill: "none",
|
|
14499
|
+
viewBox: "0 0 24 24",
|
|
14500
|
+
strokeWidth: 2,
|
|
14501
|
+
stroke: "currentColor",
|
|
14502
|
+
className: "w-5 h-5"
|
|
14503
|
+
},
|
|
14504
|
+
/* @__PURE__ */ React25.createElement(
|
|
14505
|
+
"path",
|
|
14506
|
+
{
|
|
14507
|
+
strokeLinecap: "round",
|
|
14508
|
+
strokeLinejoin: "round",
|
|
14509
|
+
d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"
|
|
14510
|
+
}
|
|
14511
|
+
)
|
|
14512
|
+
),
|
|
13700
14513
|
"Voltar para Scenes"
|
|
13701
14514
|
)));
|
|
13702
14515
|
}
|
|
@@ -13743,7 +14556,14 @@ function XViewScene({
|
|
|
13743
14556
|
onImageChange: handleGhostNodeImageChange,
|
|
13744
14557
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13745
14558
|
onMentionClick: handleAddExistingNode,
|
|
13746
|
-
style: {
|
|
14559
|
+
style: {
|
|
14560
|
+
position: "absolute",
|
|
14561
|
+
left: `${formPosition.left}px`,
|
|
14562
|
+
top: `${formPosition.top}px`,
|
|
14563
|
+
opacity: formPosition.opacity,
|
|
14564
|
+
zIndex: 20,
|
|
14565
|
+
transition: "opacity 200ms ease-out"
|
|
14566
|
+
},
|
|
13747
14567
|
refEl: formRef,
|
|
13748
14568
|
existingTypes: existingNodeTypes,
|
|
13749
14569
|
initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
|
|
@@ -13767,7 +14587,14 @@ function XViewScene({
|
|
|
13767
14587
|
onImageChange: handleGhostNodeImageChange,
|
|
13768
14588
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13769
14589
|
onMentionClick: handleAddExistingNode,
|
|
13770
|
-
style: {
|
|
14590
|
+
style: {
|
|
14591
|
+
position: "absolute",
|
|
14592
|
+
left: `${formPosition.left}px`,
|
|
14593
|
+
top: `${formPosition.top}px`,
|
|
14594
|
+
opacity: formPosition.opacity,
|
|
14595
|
+
zIndex: 20,
|
|
14596
|
+
transition: "opacity 200ms ease-out"
|
|
14597
|
+
},
|
|
13771
14598
|
refEl: formRef,
|
|
13772
14599
|
fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
|
|
13773
14600
|
fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
|
|
@@ -13784,7 +14611,13 @@ function XViewScene({
|
|
|
13784
14611
|
onNameChange: handleGhostNodeNameChange,
|
|
13785
14612
|
onColorChange: handleGhostNodeColorChange,
|
|
13786
14613
|
onSizeChange: handleGhostNodeSizeChange,
|
|
13787
|
-
style: {
|
|
14614
|
+
style: {
|
|
14615
|
+
position: "absolute",
|
|
14616
|
+
left: `16px`,
|
|
14617
|
+
top: `16px`,
|
|
14618
|
+
zIndex: 20,
|
|
14619
|
+
transition: "opacity 200ms ease-out"
|
|
14620
|
+
},
|
|
13788
14621
|
refEl: formRef,
|
|
13789
14622
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13790
14623
|
onMentionClick: handleAddExistingNode,
|
|
@@ -13799,7 +14632,14 @@ function XViewScene({
|
|
|
13799
14632
|
"div",
|
|
13800
14633
|
{
|
|
13801
14634
|
className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isReadModeResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
13802
|
-
style: {
|
|
14635
|
+
style: {
|
|
14636
|
+
top: 16,
|
|
14637
|
+
right: 16,
|
|
14638
|
+
zIndex: 1100,
|
|
14639
|
+
maxHeight: "calc(100vh - 32px)",
|
|
14640
|
+
width: `${readModeWidth}px`,
|
|
14641
|
+
maxWidth: "92vw"
|
|
14642
|
+
}
|
|
13803
14643
|
},
|
|
13804
14644
|
/* @__PURE__ */ React25.createElement(
|
|
13805
14645
|
"div",
|
|
@@ -13857,7 +14697,16 @@ function XViewScene({
|
|
|
13857
14697
|
onSave: handleSaveAncestry,
|
|
13858
14698
|
onEditRelationship: handleOpenAncestryRelEditor,
|
|
13859
14699
|
onClose: () => {
|
|
13860
|
-
setAncestryMode({
|
|
14700
|
+
setAncestryMode({
|
|
14701
|
+
isActive: false,
|
|
14702
|
+
tree: null,
|
|
14703
|
+
selectedParentId: null,
|
|
14704
|
+
isEditMode: false,
|
|
14705
|
+
currentAncestryId: null,
|
|
14706
|
+
ancestryName: "",
|
|
14707
|
+
ancestryDescription: "",
|
|
14708
|
+
isAddingNodes: false
|
|
14709
|
+
});
|
|
13861
14710
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13862
14711
|
},
|
|
13863
14712
|
availableNodes: allAvailableNodes,
|
|
@@ -13922,7 +14771,12 @@ function XViewScene({
|
|
|
13922
14771
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13923
14772
|
existingTypes: existingNodeTypes,
|
|
13924
14773
|
onImageChange: (useImage, url, currentColorOverride) => {
|
|
13925
|
-
const updatedNode = {
|
|
14774
|
+
const updatedNode = {
|
|
14775
|
+
...detailsNode,
|
|
14776
|
+
useImageAsTexture: useImage,
|
|
14777
|
+
textureImageUrl: url,
|
|
14778
|
+
color: currentColorOverride || detailsNode.color
|
|
14779
|
+
};
|
|
13926
14780
|
updateExistingNodeVisuals(stateRef.current, updatedNode);
|
|
13927
14781
|
setDetailsNode(updatedNode);
|
|
13928
14782
|
},
|
|
@@ -13996,7 +14850,9 @@ function XViewScene({
|
|
|
13996
14850
|
parentData: parentDataRef.current,
|
|
13997
14851
|
sceneData: sceneDataRef.current,
|
|
13998
14852
|
ancestryData: ancestryDataRef.current,
|
|
13999
|
-
onClose: () => setContextMenu(
|
|
14853
|
+
onClose: () => setContextMenu(
|
|
14854
|
+
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
14855
|
+
),
|
|
14000
14856
|
onStartCreation: (data) => userActionHandlers.handleStartCreation(actionHandlerContext, data),
|
|
14001
14857
|
onStartConnection: (data) => userActionHandlers.handleStartConnection(actionHandlerContext, data),
|
|
14002
14858
|
onStartVersioning: handleStartVersioning,
|
|
@@ -14004,7 +14860,11 @@ function XViewScene({
|
|
|
14004
14860
|
onDeleteNode: (data) => userActionHandlers.handleDeleteNode(actionHandlerContext, data),
|
|
14005
14861
|
onDismissNode: (data) => userActionHandlers.handleDismissNode(actionHandlerContext, data),
|
|
14006
14862
|
onDismissOtherNodes: (data) => userActionHandlers.handleDismissOtherNodes(actionHandlerContext, data),
|
|
14007
|
-
onExpandConnections: (sourceNode, links) => userActionHandlers.handleExpandConnections(
|
|
14863
|
+
onExpandConnections: (sourceNode, links) => userActionHandlers.handleExpandConnections(
|
|
14864
|
+
actionHandlerContext,
|
|
14865
|
+
sourceNode,
|
|
14866
|
+
links
|
|
14867
|
+
),
|
|
14008
14868
|
onRenderAncestry: handleStartReadingAncestry,
|
|
14009
14869
|
onEditAncestry: handleEditAncestry,
|
|
14010
14870
|
onDeleteAncestry: (ancestryId) => handleDeleteAncestry(ancestryId),
|
|
@@ -14017,9 +14877,18 @@ function XViewScene({
|
|
|
14017
14877
|
data: multiContextMenu,
|
|
14018
14878
|
userRole: userPermissionRole,
|
|
14019
14879
|
onClose: () => setMultiContextMenu((prev) => ({ ...prev, visible: false })),
|
|
14020
|
-
onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(
|
|
14021
|
-
|
|
14022
|
-
|
|
14880
|
+
onDismissNodes: (ids) => userActionHandlers.handleDismissMultipleNodes(
|
|
14881
|
+
actionHandlerContext,
|
|
14882
|
+
ids
|
|
14883
|
+
),
|
|
14884
|
+
onDismissOtherNodes: (ids) => userActionHandlers.handleDismissOtherMultipleNodes(
|
|
14885
|
+
actionHandlerContext,
|
|
14886
|
+
ids
|
|
14887
|
+
),
|
|
14888
|
+
onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(
|
|
14889
|
+
actionHandlerContext,
|
|
14890
|
+
ids
|
|
14891
|
+
)
|
|
14023
14892
|
}
|
|
14024
14893
|
),
|
|
14025
14894
|
/* @__PURE__ */ React25.createElement(
|
|
@@ -14040,7 +14909,13 @@ function XViewScene({
|
|
|
14040
14909
|
onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
|
|
14041
14910
|
}
|
|
14042
14911
|
),
|
|
14043
|
-
/* @__PURE__ */ React25.createElement(
|
|
14912
|
+
/* @__PURE__ */ React25.createElement(
|
|
14913
|
+
ImageViewer,
|
|
14914
|
+
{
|
|
14915
|
+
data: imageViewer,
|
|
14916
|
+
onClose: () => setImageViewer({ ...imageViewer, visible: false })
|
|
14917
|
+
}
|
|
14918
|
+
),
|
|
14044
14919
|
/* @__PURE__ */ React25.createElement(
|
|
14045
14920
|
AncestryBoard,
|
|
14046
14921
|
{
|