@lv-x-software-house/x_view 1.1.8 → 1.1.9-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 +215 -94
- package/dist/index.mjs +251 -130
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5019,8 +5019,12 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
|
|
|
5019
5019
|
};
|
|
5020
5020
|
function CreateAncestryPanel({
|
|
5021
5021
|
ancestryMode,
|
|
5022
|
+
setAncestryMode,
|
|
5023
|
+
// <--- Nova prop necessária para as novas funções manipuladoras
|
|
5022
5024
|
onSelectParent,
|
|
5025
|
+
// Mantido para compatibilidade, mas as novas funções usam setAncestryMode
|
|
5023
5026
|
onRemoveNode,
|
|
5027
|
+
// Mantido para compatibilidade
|
|
5024
5028
|
onSave,
|
|
5025
5029
|
onClose,
|
|
5026
5030
|
onEditRelationship,
|
|
@@ -5031,12 +5035,14 @@ function CreateAncestryPanel({
|
|
|
5031
5035
|
onUpdateTree,
|
|
5032
5036
|
onAncestrySectionChange,
|
|
5033
5037
|
onToggleAddNodes,
|
|
5038
|
+
// Mantido para compatibilidade
|
|
5034
5039
|
onRenderFullAncestry,
|
|
5035
5040
|
onHighlightNode,
|
|
5036
5041
|
onClearAncestryVisuals,
|
|
5037
5042
|
onUploadFile,
|
|
5038
|
-
onOpenImageViewer
|
|
5039
|
-
|
|
5043
|
+
onOpenImageViewer,
|
|
5044
|
+
onRenderAbstractionTree
|
|
5045
|
+
// <--- Nova prop recebida
|
|
5040
5046
|
}) {
|
|
5041
5047
|
const {
|
|
5042
5048
|
tree: rootTree,
|
|
@@ -5072,6 +5078,91 @@ function CreateAncestryPanel({
|
|
|
5072
5078
|
console.warn("onOpenImageViewer n\xE3o foi passado para CreateAncestryPanel");
|
|
5073
5079
|
}
|
|
5074
5080
|
};
|
|
5081
|
+
const handleSelectAncestryParent = (nodeId, isAbstraction = false) => {
|
|
5082
|
+
setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
|
|
5083
|
+
};
|
|
5084
|
+
const handleToggleAddMode = (isAbstraction = false) => {
|
|
5085
|
+
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
5086
|
+
};
|
|
5087
|
+
const handleRemoveNode = (0, import_react10.useCallback)((pathToRemove, isAbstraction = false) => {
|
|
5088
|
+
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
5089
|
+
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5090
|
+
setAncestryMode((prev) => {
|
|
5091
|
+
if (!prev[treeKey]) return prev;
|
|
5092
|
+
const newTree = JSON.parse(JSON.stringify(prev[treeKey]));
|
|
5093
|
+
let currentParent = newTree;
|
|
5094
|
+
for (let i = 0; i < pathToRemove.length - 1; i++) {
|
|
5095
|
+
const childIndex = pathToRemove[i];
|
|
5096
|
+
if (currentParent.children && currentParent.children[childIndex]) {
|
|
5097
|
+
currentParent = currentParent.children[childIndex];
|
|
5098
|
+
} else return prev;
|
|
5099
|
+
}
|
|
5100
|
+
const indexToRemove = pathToRemove[pathToRemove.length - 1];
|
|
5101
|
+
if (currentParent.children && currentParent.children.length > indexToRemove) {
|
|
5102
|
+
currentParent.children.splice(indexToRemove, 1);
|
|
5103
|
+
}
|
|
5104
|
+
return { ...prev, [treeKey]: newTree };
|
|
5105
|
+
});
|
|
5106
|
+
}, [setAncestryMode]);
|
|
5107
|
+
const handleMoveNode = (sourceId, targetId, isAbstraction = false) => {
|
|
5108
|
+
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5109
|
+
const activeTreeContext = ancestryMode[treeKey];
|
|
5110
|
+
if (!activeTreeContext) return;
|
|
5111
|
+
const rootTreeClone = JSON.parse(JSON.stringify(ancestryMode[treeKey]));
|
|
5112
|
+
let targetTreeContext = rootTreeClone;
|
|
5113
|
+
if (!isAbstraction && branchStack.length > 0) {
|
|
5114
|
+
let ptr = rootTreeClone;
|
|
5115
|
+
for (const step of branchStack) {
|
|
5116
|
+
const found = findNodePath(ptr, step.nodeId);
|
|
5117
|
+
if (found && found.node.parallel_branches) {
|
|
5118
|
+
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
5119
|
+
if (branch) ptr = branch.tree;
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
targetTreeContext = ptr;
|
|
5123
|
+
}
|
|
5124
|
+
let movedNodeData = null;
|
|
5125
|
+
const removeSourceNode = (node) => {
|
|
5126
|
+
if (!node.children) return false;
|
|
5127
|
+
const idx = node.children.findIndex((child) => {
|
|
5128
|
+
var _a;
|
|
5129
|
+
return String(child.is_section ? child.id : (_a = child.node) == null ? void 0 : _a.id) === String(sourceId);
|
|
5130
|
+
});
|
|
5131
|
+
if (idx !== -1) {
|
|
5132
|
+
movedNodeData = node.children[idx];
|
|
5133
|
+
node.children.splice(idx, 1);
|
|
5134
|
+
return true;
|
|
5135
|
+
}
|
|
5136
|
+
for (const child of node.children) {
|
|
5137
|
+
if (removeSourceNode(child)) return true;
|
|
5138
|
+
}
|
|
5139
|
+
return false;
|
|
5140
|
+
};
|
|
5141
|
+
const insertTargetNode = (node) => {
|
|
5142
|
+
var _a;
|
|
5143
|
+
if (String(node.is_section ? node.id : (_a = node.node) == null ? void 0 : _a.id) === String(targetId)) {
|
|
5144
|
+
if (!node.children) node.children = [];
|
|
5145
|
+
node.children.push(movedNodeData);
|
|
5146
|
+
return true;
|
|
5147
|
+
}
|
|
5148
|
+
if (node.children) {
|
|
5149
|
+
for (const child of node.children) {
|
|
5150
|
+
if (insertTargetNode(child)) return true;
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
5153
|
+
return false;
|
|
5154
|
+
};
|
|
5155
|
+
if (removeSourceNode(targetTreeContext) && movedNodeData) {
|
|
5156
|
+
if (insertTargetNode(targetTreeContext)) {
|
|
5157
|
+
if (!isAbstraction) {
|
|
5158
|
+
updateGlobalTree(rootTreeClone);
|
|
5159
|
+
}
|
|
5160
|
+
setAncestryMode((prev) => ({ ...prev, [treeKey]: rootTreeClone }));
|
|
5161
|
+
} else {
|
|
5162
|
+
alert("N\xE3o \xE9 poss\xEDvel mover um node para dentro de seus pr\xF3prios descendentes.");
|
|
5163
|
+
}
|
|
5164
|
+
}
|
|
5165
|
+
};
|
|
5075
5166
|
const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal) => {
|
|
5076
5167
|
return {
|
|
5077
5168
|
tree: JSON.stringify(tree),
|
|
@@ -5842,66 +5933,6 @@ function CreateAncestryPanel({
|
|
|
5842
5933
|
updateGlobalTree(newRootTree);
|
|
5843
5934
|
}
|
|
5844
5935
|
}, [description, existingSections]);
|
|
5845
|
-
const handleMoveNode = (sourceId, targetId) => {
|
|
5846
|
-
if (!activeTree) return;
|
|
5847
|
-
const rootTreeClone = JSON.parse(JSON.stringify(ancestryMode.tree));
|
|
5848
|
-
let targetTreeContext = rootTreeClone;
|
|
5849
|
-
if (branchStack.length > 0) {
|
|
5850
|
-
let ptr = rootTreeClone;
|
|
5851
|
-
for (const step of branchStack) {
|
|
5852
|
-
const found = findNodePath(ptr, step.nodeId);
|
|
5853
|
-
if (found && found.node.parallel_branches) {
|
|
5854
|
-
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
5855
|
-
if (branch) ptr = branch.tree;
|
|
5856
|
-
}
|
|
5857
|
-
}
|
|
5858
|
-
targetTreeContext = ptr;
|
|
5859
|
-
}
|
|
5860
|
-
let movedNodeData = null;
|
|
5861
|
-
const removeSourceNode = (node) => {
|
|
5862
|
-
if (!node.children) return;
|
|
5863
|
-
const idx = node.children.findIndex((child) => {
|
|
5864
|
-
var _a;
|
|
5865
|
-
const cId = child.is_section ? child.id : String((_a = child.node) == null ? void 0 : _a.id);
|
|
5866
|
-
return String(cId) === String(sourceId);
|
|
5867
|
-
});
|
|
5868
|
-
if (idx !== -1) {
|
|
5869
|
-
movedNodeData = node.children[idx];
|
|
5870
|
-
node.children.splice(idx, 1);
|
|
5871
|
-
return true;
|
|
5872
|
-
}
|
|
5873
|
-
for (const child of node.children) {
|
|
5874
|
-
if (removeSourceNode(child)) return true;
|
|
5875
|
-
}
|
|
5876
|
-
return false;
|
|
5877
|
-
};
|
|
5878
|
-
const insertTargetNode = (node) => {
|
|
5879
|
-
var _a;
|
|
5880
|
-
const nodeId = node.is_section ? node.id : String((_a = node.node) == null ? void 0 : _a.id);
|
|
5881
|
-
if (String(nodeId) === String(targetId)) {
|
|
5882
|
-
if (!node.children) node.children = [];
|
|
5883
|
-
node.children.push(movedNodeData);
|
|
5884
|
-
return true;
|
|
5885
|
-
}
|
|
5886
|
-
if (node.children) {
|
|
5887
|
-
for (const child of node.children) {
|
|
5888
|
-
if (insertTargetNode(child)) return true;
|
|
5889
|
-
}
|
|
5890
|
-
}
|
|
5891
|
-
return false;
|
|
5892
|
-
};
|
|
5893
|
-
const foundAndRemoved = removeSourceNode(targetTreeContext);
|
|
5894
|
-
if (!foundAndRemoved || !movedNodeData) {
|
|
5895
|
-
console.error("Node de origem n\xE3o encontrado na \xE1rvore.");
|
|
5896
|
-
return;
|
|
5897
|
-
}
|
|
5898
|
-
const inserted = insertTargetNode(targetTreeContext);
|
|
5899
|
-
if (!inserted) {
|
|
5900
|
-
alert("N\xE3o \xE9 poss\xEDvel mover um node para dentro de seus pr\xF3prios descendentes.");
|
|
5901
|
-
return;
|
|
5902
|
-
}
|
|
5903
|
-
updateGlobalTree(rootTreeClone);
|
|
5904
|
-
};
|
|
5905
5936
|
const handleTriggerFullRender = () => {
|
|
5906
5937
|
var _a;
|
|
5907
5938
|
if (onRenderFullAncestry && activeTree) {
|
|
@@ -6153,7 +6184,7 @@ function CreateAncestryPanel({
|
|
|
6153
6184
|
), /* @__PURE__ */ import_react10.default.createElement(
|
|
6154
6185
|
"button",
|
|
6155
6186
|
{
|
|
6156
|
-
onClick:
|
|
6187
|
+
onClick: () => handleToggleAddMode(false),
|
|
6157
6188
|
className: `p-1.5 rounded-md transition-colors ${isAddingNodes ? "bg-cyan-500 text-white shadow-lg shadow-cyan-500/30" : "bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600"}`,
|
|
6158
6189
|
title: isAddingNodes ? "Concluir edi\xE7\xE3o da estrutura" : "Editar estrutura e adicionar nodes"
|
|
6159
6190
|
},
|
|
@@ -6162,17 +6193,54 @@ function CreateAncestryPanel({
|
|
|
6162
6193
|
NodeItem,
|
|
6163
6194
|
{
|
|
6164
6195
|
nodeData: activeTree,
|
|
6165
|
-
onSelectParent,
|
|
6166
|
-
onRemoveNode,
|
|
6196
|
+
onSelectParent: (id) => handleSelectAncestryParent(id, false),
|
|
6197
|
+
onRemoveNode: (path) => handleRemoveNode(path, false),
|
|
6167
6198
|
onEditRelationship,
|
|
6168
|
-
onMoveNode: handleMoveNode,
|
|
6199
|
+
onMoveNode: (s, t) => handleMoveNode(s, t, false),
|
|
6169
6200
|
selectedParentId,
|
|
6170
6201
|
level: 0,
|
|
6171
6202
|
isLast: true,
|
|
6172
6203
|
path: [],
|
|
6173
6204
|
isEditable: isAddingNodes
|
|
6174
6205
|
}
|
|
6175
|
-
), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center py-4 text-xs text-slate-500 italic" }, "A estrutura est\xE1 vazia. Clique no l\xE1pis acima para adicionar nodes."))), branchStack.length === 0 && /* @__PURE__ */ import_react10.default.createElement("div", { className:
|
|
6206
|
+
), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ import_react10.default.createElement("div", { className: "text-center py-4 text-xs text-slate-500 italic" }, "A estrutura est\xE1 vazia. Clique no l\xE1pis acima para adicionar nodes."))), branchStack.length === 0 && ancestryMode.abstraction_tree && /* @__PURE__ */ import_react10.default.createElement("div", { className: `mt-6 rounded-lg border transition-all duration-300 overflow-hidden ${ancestryMode.isAddingAbstractionNodes ? "border-purple-500/40 bg-slate-900/60 ring-1 ring-purple-500/20" : "border-white/10 bg-slate-800/60"}` }, /* @__PURE__ */ import_react10.default.createElement("div", { className: `flex items-center justify-between px-3 py-2 border-b ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-900/20 border-purple-500/20" : "bg-white/5 border-white/5"}` }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react10.default.createElement("span", { className: `text-xs font-semibold uppercase tracking-wider ${ancestryMode.isAddingAbstractionNodes ? "text-purple-300" : "text-slate-400"}` }, "Estrutura de Abstra\xE7\xE3o"), ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ import_react10.default.createElement("span", { className: "text-[10px] bg-purple-500/20 text-purple-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
6207
|
+
"button",
|
|
6208
|
+
{
|
|
6209
|
+
type: "button",
|
|
6210
|
+
onClick: () => {
|
|
6211
|
+
const tempPayload = {
|
|
6212
|
+
ancestry_id: currentAncestryId || "temp_rendering",
|
|
6213
|
+
abstraction_tree: ancestryMode.abstraction_tree
|
|
6214
|
+
};
|
|
6215
|
+
if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
|
|
6216
|
+
},
|
|
6217
|
+
className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
|
|
6218
|
+
title: "Renderizar Verticalmente no Cen\xE1rio"
|
|
6219
|
+
},
|
|
6220
|
+
/* @__PURE__ */ import_react10.default.createElement(import_fi9.FiLayers, { size: 14 })
|
|
6221
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
6222
|
+
"button",
|
|
6223
|
+
{
|
|
6224
|
+
onClick: () => handleToggleAddMode(true),
|
|
6225
|
+
className: `p-1.5 rounded-md transition-colors ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-500 text-white shadow-lg shadow-purple-500/30" : "bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600"}`,
|
|
6226
|
+
title: "Editar estrutura da abstra\xE7\xE3o"
|
|
6227
|
+
},
|
|
6228
|
+
ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 14 }) : /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiEdit2, { size: 14 })
|
|
6229
|
+
))), /* @__PURE__ */ import_react10.default.createElement("div", { className: "p-4 space-y-2" }, ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mb-3 p-2 rounded bg-purple-900/20 border border-purple-500/20 text-xs text-purple-200 flex items-start gap-2" }, /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiMousePointer, { className: "mt-0.5 flex-shrink-0" }), /* @__PURE__ */ import_react10.default.createElement("span", null, "Clique nos nodes do cen\xE1rio para adicion\xE1-los. Arraste e solte para organizar a hierarquia.")), /* @__PURE__ */ import_react10.default.createElement(
|
|
6230
|
+
NodeItem,
|
|
6231
|
+
{
|
|
6232
|
+
nodeData: ancestryMode.abstraction_tree,
|
|
6233
|
+
onSelectParent: (id) => handleSelectAncestryParent(id, true),
|
|
6234
|
+
onRemoveNode: (path) => handleRemoveNode(path, true),
|
|
6235
|
+
onEditRelationship,
|
|
6236
|
+
onMoveNode: (s, t) => handleMoveNode(s, t, true),
|
|
6237
|
+
selectedParentId: ancestryMode.selectedAbstractionParentId,
|
|
6238
|
+
level: 0,
|
|
6239
|
+
isLast: true,
|
|
6240
|
+
path: [],
|
|
6241
|
+
isEditable: ancestryMode.isAddingAbstractionNodes
|
|
6242
|
+
}
|
|
6243
|
+
))), branchStack.length === 0 && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-3 flex items-center justify-end px-1" }, /* @__PURE__ */ import_react10.default.createElement("label", { className: "flex items-center gap-2 cursor-pointer group select-none" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: `w-4 h-4 rounded border flex items-center justify-center transition-colors ${isPrivate ? "bg-indigo-500 border-indigo-500" : "border-slate-500 bg-transparent"}` }, isPrivate && /* @__PURE__ */ import_react10.default.createElement(import_fi9.FiCheck, { size: 12, className: "text-white" })), /* @__PURE__ */ import_react10.default.createElement(
|
|
6176
6244
|
"input",
|
|
6177
6245
|
{
|
|
6178
6246
|
type: "checkbox",
|
|
@@ -9740,43 +9808,38 @@ function XViewScene({
|
|
|
9740
9808
|
return;
|
|
9741
9809
|
}
|
|
9742
9810
|
if (ancestry.isActive) {
|
|
9743
|
-
if (ancestry.isAddingNodes) {
|
|
9811
|
+
if (ancestry.isAddingNodes || ancestry.isAddingAbstractionNodes) {
|
|
9744
9812
|
const clickedNode = stateRef.current.dragCandidate || tryPickNode();
|
|
9745
9813
|
stateRef.current.dragCandidate = null;
|
|
9746
9814
|
stateRef.current.pointerDown.isDown = false;
|
|
9747
9815
|
stateRef.current.controls.enabled = true;
|
|
9748
|
-
|
|
9816
|
+
const isAbstraction = ancestry.isAddingAbstractionNodes;
|
|
9817
|
+
const currentSelectedParent = isAbstraction ? ancestry.selectedAbstractionParentId : ancestry.selectedParentId;
|
|
9818
|
+
if (clickedNode && currentSelectedParent) {
|
|
9749
9819
|
const clickedNodeId = String(clickedNode.userData.id);
|
|
9750
|
-
const parentId = String(
|
|
9820
|
+
const parentId = String(currentSelectedParent);
|
|
9751
9821
|
if (clickedNodeId === parentId) {
|
|
9752
9822
|
alert("Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo.");
|
|
9753
9823
|
return;
|
|
9754
9824
|
}
|
|
9755
9825
|
const parentInfo = stateRef.current.nodeIdToParentFileMap.get(clickedNodeId);
|
|
9756
|
-
if (!parentInfo)
|
|
9757
|
-
console.warn(`Node ${clickedNodeId} n\xE3o encontrado em nenhum arquivo pai.`);
|
|
9758
|
-
return;
|
|
9759
|
-
}
|
|
9826
|
+
if (!parentInfo) return;
|
|
9760
9827
|
const fullNodeData = (_a2 = parentDataRef.current[parentInfo.parentFileId]) == null ? void 0 : _a2.nodes.find((n) => String(n.id) === clickedNodeId);
|
|
9761
|
-
if (!fullNodeData)
|
|
9762
|
-
console.error(`Falha ao encontrar dados completos do Node ${clickedNodeId} mesmo com parentInfo.`);
|
|
9763
|
-
return;
|
|
9764
|
-
}
|
|
9828
|
+
if (!fullNodeData) return;
|
|
9765
9829
|
const addChildToNode = (current, targetParentId, childNode) => {
|
|
9766
9830
|
const currentId = current.is_section ? current.id || current.section_id : String(current.node.id);
|
|
9767
9831
|
if (String(currentId) === String(targetParentId)) {
|
|
9768
9832
|
const alreadyExists = current.children.some((child) => !child.is_section && String(child.node.id) === String(childNode.id));
|
|
9769
9833
|
if (alreadyExists) return current;
|
|
9770
|
-
|
|
9771
|
-
return { ...current, children: newChildren };
|
|
9834
|
+
return { ...current, children: [...current.children, { node: childNode, children: [], relationship: {} }] };
|
|
9772
9835
|
}
|
|
9773
|
-
|
|
9774
|
-
return { ...current, children: updatedChildren };
|
|
9836
|
+
return { ...current, children: current.children.map((c) => addChildToNode(c, targetParentId, childNode)) };
|
|
9775
9837
|
};
|
|
9776
9838
|
setAncestryMode((prev) => {
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9839
|
+
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
9840
|
+
if (!prev[treeKey]) return prev;
|
|
9841
|
+
const newTree = addChildToNode(prev[treeKey], parentId, fullNodeData);
|
|
9842
|
+
return { ...prev, [treeKey]: newTree };
|
|
9780
9843
|
});
|
|
9781
9844
|
}
|
|
9782
9845
|
return;
|
|
@@ -10259,12 +10322,15 @@ function XViewScene({
|
|
|
10259
10322
|
setAncestryMode({
|
|
10260
10323
|
isActive: true,
|
|
10261
10324
|
tree: { node: nodeData, children: [] },
|
|
10325
|
+
abstraction_tree: { node: nodeData, children: [] },
|
|
10262
10326
|
selectedParentId: nodeData.id,
|
|
10327
|
+
selectedAbstractionParentId: nodeData.id,
|
|
10263
10328
|
isEditMode: false,
|
|
10264
10329
|
currentAncestryId: null,
|
|
10265
10330
|
ancestryName: `Ancestralidade ${nodeData.name}`,
|
|
10266
10331
|
ancestryDescription: "",
|
|
10267
|
-
isAddingNodes: false
|
|
10332
|
+
isAddingNodes: false,
|
|
10333
|
+
isAddingAbstractionNodes: false
|
|
10268
10334
|
});
|
|
10269
10335
|
if (mountRef.current) {
|
|
10270
10336
|
mountRef.current.style.cursor = "default";
|
|
@@ -10770,6 +10836,46 @@ function XViewScene({
|
|
|
10770
10836
|
},
|
|
10771
10837
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
10772
10838
|
);
|
|
10839
|
+
const handleRenderAbstractionTree = (0, import_react23.useCallback)((ancestryObject) => {
|
|
10840
|
+
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
10841
|
+
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
10842
|
+
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
10843
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
|
|
10844
|
+
const fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
|
|
10845
|
+
if (!fullTree || !fullTree.node) return;
|
|
10846
|
+
const absId = ancestryObject.ancestry_id + "_abs";
|
|
10847
|
+
handleClearAncestryVisuals(absId);
|
|
10848
|
+
const colorHex = 9133302;
|
|
10849
|
+
const resolution = new THREE3.Vector2(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
|
|
10850
|
+
const ancestryEntry = { id: absId, lines: [], isFullRender: true };
|
|
10851
|
+
renderedAncestries.push(ancestryEntry);
|
|
10852
|
+
const rootNodeId = String(fullTree.node.id);
|
|
10853
|
+
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
10854
|
+
let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
|
|
10855
|
+
if (!rootNodeMesh) {
|
|
10856
|
+
rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
|
|
10857
|
+
}
|
|
10858
|
+
const SPACING_Y = -40;
|
|
10859
|
+
const SPACING_X = 55;
|
|
10860
|
+
const renderVertical = (treeNode, parentMesh, parentPos, level) => {
|
|
10861
|
+
if (!treeNode.children || treeNode.children.length === 0) return;
|
|
10862
|
+
const totalSiblings = treeNode.children.length;
|
|
10863
|
+
treeNode.children.forEach((childItem, i) => {
|
|
10864
|
+
if (!childItem.node) return;
|
|
10865
|
+
const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
|
|
10866
|
+
const childY = parentPos.y + SPACING_Y;
|
|
10867
|
+
const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
|
|
10868
|
+
const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
|
|
10869
|
+
const line = createAncestryLinkLine(parentMesh, childMesh, resolution, {}, colorHex);
|
|
10870
|
+
ancestryGroup.add(line);
|
|
10871
|
+
ancestryEntry.lines.push(line);
|
|
10872
|
+
renderVertical(childItem, childMesh, childPos, level + 1);
|
|
10873
|
+
});
|
|
10874
|
+
};
|
|
10875
|
+
renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
|
|
10876
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
10877
|
+
tweenToTarget(rootTargetPos, 0.7);
|
|
10878
|
+
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
10773
10879
|
const handleReadModeBranchNav = (0, import_react23.useCallback)((nodeId, action, direction = "right") => {
|
|
10774
10880
|
const { ancestry, branchStack } = readingMode;
|
|
10775
10881
|
if (!ancestry || !ancestry.tree) return;
|
|
@@ -11179,22 +11285,24 @@ function XViewScene({
|
|
|
11179
11285
|
alert("Falha ao reconstruir a \xE1rvore de ancestralidade. Alguns Nodes podem estar faltando.");
|
|
11180
11286
|
return;
|
|
11181
11287
|
}
|
|
11288
|
+
const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, allAncestries) : { node: fullTree.node, children: [] };
|
|
11182
11289
|
setAncestryMode({
|
|
11183
11290
|
isActive: true,
|
|
11184
|
-
// --- CORREÇÃO AQUI ---
|
|
11185
|
-
// 1. Espalhamos as propriedades do objeto (custom props, ids, etc) PRIMEIRO.
|
|
11186
11291
|
...ancestryObject,
|
|
11187
|
-
// 2. Definimos a 'tree' DEPOIS. Isso garante que a árvore 'fullTree' (hidratada com os nodes reais)
|
|
11188
|
-
// prevaleça sobre a árvore 'crua' (apenas IDs) que veio dentro de 'ancestryObject'.
|
|
11189
11292
|
tree: fullTree,
|
|
11190
|
-
|
|
11293
|
+
abstraction_tree: fullAbstractionTree,
|
|
11294
|
+
// NOVO
|
|
11191
11295
|
selectedParentId: ancestryObject.ancestral_node,
|
|
11296
|
+
selectedAbstractionParentId: ancestryObject.ancestral_node,
|
|
11297
|
+
// NOVO
|
|
11192
11298
|
isEditMode: true,
|
|
11193
11299
|
currentAncestryId: ancestryObject.ancestry_id,
|
|
11194
11300
|
ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
|
|
11195
11301
|
ancestryDescription: ancestryObject.description || "",
|
|
11196
11302
|
ancestryDescriptionSections: ancestryObject.description_sections || [],
|
|
11197
|
-
isAddingNodes: false
|
|
11303
|
+
isAddingNodes: false,
|
|
11304
|
+
isAddingAbstractionNodes: false
|
|
11305
|
+
// NOVO
|
|
11198
11306
|
});
|
|
11199
11307
|
},
|
|
11200
11308
|
[handleRenderAncestry, buildFullAncestryTree]
|
|
@@ -11265,6 +11373,7 @@ function XViewScene({
|
|
|
11265
11373
|
};
|
|
11266
11374
|
};
|
|
11267
11375
|
const treeWithIds = convertTreeToIds(treeToUse);
|
|
11376
|
+
const abstractionTreeWithIds = convertTreeToIds(ancestryMode.abstraction_tree);
|
|
11268
11377
|
if (!treeWithIds) {
|
|
11269
11378
|
alert("Erro ao processar a \xE1rvore da ancestralidade.");
|
|
11270
11379
|
return;
|
|
@@ -11280,6 +11389,7 @@ function XViewScene({
|
|
|
11280
11389
|
description: ancestryDescription,
|
|
11281
11390
|
description_sections: ancestrySections,
|
|
11282
11391
|
tree: treeWithIds,
|
|
11392
|
+
abstraction_tree: abstractionTreeWithIds,
|
|
11283
11393
|
_imported_from_view_id: originalAncestryObj == null ? void 0 : originalAncestryObj._imported_from_view_id,
|
|
11284
11394
|
_imported_from_view_owner_id: originalAncestryObj == null ? void 0 : originalAncestryObj._imported_from_view_owner_id,
|
|
11285
11395
|
_origin_db_ids: originalAncestryObj == null ? void 0 : originalAncestryObj._origin_db_ids,
|
|
@@ -11724,6 +11834,7 @@ function XViewScene({
|
|
|
11724
11834
|
CreateAncestryPanel,
|
|
11725
11835
|
{
|
|
11726
11836
|
ancestryMode,
|
|
11837
|
+
setAncestryMode,
|
|
11727
11838
|
onSelectParent: handleSelectAncestryParent,
|
|
11728
11839
|
onRemoveNode: handleRemoveFromAncestry,
|
|
11729
11840
|
onSave: handleSaveAncestry,
|
|
@@ -11742,7 +11853,8 @@ function XViewScene({
|
|
|
11742
11853
|
onRenderFullAncestry: (data, allowed, focus, rot) => handleRenderAncestry(data, allowed, focus, rot),
|
|
11743
11854
|
onClearAncestryVisuals: handleClearAncestryVisuals,
|
|
11744
11855
|
onUploadFile: upload_file_action,
|
|
11745
|
-
onOpenImageViewer: handleOpenImageViewer
|
|
11856
|
+
onOpenImageViewer: handleOpenImageViewer,
|
|
11857
|
+
onRenderAbstractionTree: (data) => handleRenderAbstractionTree(data)
|
|
11746
11858
|
}
|
|
11747
11859
|
),
|
|
11748
11860
|
editingAncestryRel.visible && /* @__PURE__ */ import_react23.default.createElement(
|
|
@@ -12112,7 +12224,16 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
|
|
|
12112
12224
|
if (!parentNodeIds.has(String(ancestry.ancestral_node))) return null;
|
|
12113
12225
|
const cleanedTree = pruneTree(ancestry.tree);
|
|
12114
12226
|
if (!cleanedTree) return null;
|
|
12115
|
-
|
|
12227
|
+
let cleanedAbstraction = null;
|
|
12228
|
+
if (ancestry.abstraction_tree) {
|
|
12229
|
+
cleanedAbstraction = pruneTree(ancestry.abstraction_tree);
|
|
12230
|
+
}
|
|
12231
|
+
return {
|
|
12232
|
+
...ancestry,
|
|
12233
|
+
tree: cleanedTree,
|
|
12234
|
+
abstraction_tree: cleanedAbstraction
|
|
12235
|
+
// Salva a árvore limpa
|
|
12236
|
+
};
|
|
12116
12237
|
}).filter(Boolean);
|
|
12117
12238
|
if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
|
|
12118
12239
|
ancestryData = cleanedAncestryData;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import React23, { useCallback as
|
|
2
|
+
import React23, { useCallback as useCallback3, useEffect as useEffect20, useRef as useRef17, useState as useState22, useMemo as useMemo12 } from "react";
|
|
3
3
|
import { useRouter } from "next/navigation";
|
|
4
4
|
import { useSession } from "next-auth/react";
|
|
5
5
|
import CryptoJS from "crypto-js";
|
|
@@ -4757,7 +4757,7 @@ function AncestryRelationshipPanel({
|
|
|
4757
4757
|
}
|
|
4758
4758
|
|
|
4759
4759
|
// src/components/CreateAncestryPanel.jsx
|
|
4760
|
-
import React10, { useState as useState10, useEffect as useEffect9, useMemo as useMemo8, useRef as useRef8 } from "react";
|
|
4760
|
+
import React10, { useState as useState10, useEffect as useEffect9, useMemo as useMemo8, useRef as useRef8, useCallback } from "react";
|
|
4761
4761
|
import {
|
|
4762
4762
|
FiEdit2 as FiEdit23,
|
|
4763
4763
|
FiBookOpen as FiBookOpen2,
|
|
@@ -5000,8 +5000,12 @@ var NodeItem = ({ nodeData, onSelectParent, onRemoveNode, onEditRelationship, on
|
|
|
5000
5000
|
};
|
|
5001
5001
|
function CreateAncestryPanel({
|
|
5002
5002
|
ancestryMode,
|
|
5003
|
+
setAncestryMode,
|
|
5004
|
+
// <--- Nova prop necessária para as novas funções manipuladoras
|
|
5003
5005
|
onSelectParent,
|
|
5006
|
+
// Mantido para compatibilidade, mas as novas funções usam setAncestryMode
|
|
5004
5007
|
onRemoveNode,
|
|
5008
|
+
// Mantido para compatibilidade
|
|
5005
5009
|
onSave,
|
|
5006
5010
|
onClose,
|
|
5007
5011
|
onEditRelationship,
|
|
@@ -5012,12 +5016,14 @@ function CreateAncestryPanel({
|
|
|
5012
5016
|
onUpdateTree,
|
|
5013
5017
|
onAncestrySectionChange,
|
|
5014
5018
|
onToggleAddNodes,
|
|
5019
|
+
// Mantido para compatibilidade
|
|
5015
5020
|
onRenderFullAncestry,
|
|
5016
5021
|
onHighlightNode,
|
|
5017
5022
|
onClearAncestryVisuals,
|
|
5018
5023
|
onUploadFile,
|
|
5019
|
-
onOpenImageViewer
|
|
5020
|
-
|
|
5024
|
+
onOpenImageViewer,
|
|
5025
|
+
onRenderAbstractionTree
|
|
5026
|
+
// <--- Nova prop recebida
|
|
5021
5027
|
}) {
|
|
5022
5028
|
const {
|
|
5023
5029
|
tree: rootTree,
|
|
@@ -5053,6 +5059,91 @@ function CreateAncestryPanel({
|
|
|
5053
5059
|
console.warn("onOpenImageViewer n\xE3o foi passado para CreateAncestryPanel");
|
|
5054
5060
|
}
|
|
5055
5061
|
};
|
|
5062
|
+
const handleSelectAncestryParent = (nodeId, isAbstraction = false) => {
|
|
5063
|
+
setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
|
|
5064
|
+
};
|
|
5065
|
+
const handleToggleAddMode = (isAbstraction = false) => {
|
|
5066
|
+
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
5067
|
+
};
|
|
5068
|
+
const handleRemoveNode = useCallback((pathToRemove, isAbstraction = false) => {
|
|
5069
|
+
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
5070
|
+
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5071
|
+
setAncestryMode((prev) => {
|
|
5072
|
+
if (!prev[treeKey]) return prev;
|
|
5073
|
+
const newTree = JSON.parse(JSON.stringify(prev[treeKey]));
|
|
5074
|
+
let currentParent = newTree;
|
|
5075
|
+
for (let i = 0; i < pathToRemove.length - 1; i++) {
|
|
5076
|
+
const childIndex = pathToRemove[i];
|
|
5077
|
+
if (currentParent.children && currentParent.children[childIndex]) {
|
|
5078
|
+
currentParent = currentParent.children[childIndex];
|
|
5079
|
+
} else return prev;
|
|
5080
|
+
}
|
|
5081
|
+
const indexToRemove = pathToRemove[pathToRemove.length - 1];
|
|
5082
|
+
if (currentParent.children && currentParent.children.length > indexToRemove) {
|
|
5083
|
+
currentParent.children.splice(indexToRemove, 1);
|
|
5084
|
+
}
|
|
5085
|
+
return { ...prev, [treeKey]: newTree };
|
|
5086
|
+
});
|
|
5087
|
+
}, [setAncestryMode]);
|
|
5088
|
+
const handleMoveNode = (sourceId, targetId, isAbstraction = false) => {
|
|
5089
|
+
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5090
|
+
const activeTreeContext = ancestryMode[treeKey];
|
|
5091
|
+
if (!activeTreeContext) return;
|
|
5092
|
+
const rootTreeClone = JSON.parse(JSON.stringify(ancestryMode[treeKey]));
|
|
5093
|
+
let targetTreeContext = rootTreeClone;
|
|
5094
|
+
if (!isAbstraction && branchStack.length > 0) {
|
|
5095
|
+
let ptr = rootTreeClone;
|
|
5096
|
+
for (const step of branchStack) {
|
|
5097
|
+
const found = findNodePath(ptr, step.nodeId);
|
|
5098
|
+
if (found && found.node.parallel_branches) {
|
|
5099
|
+
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
5100
|
+
if (branch) ptr = branch.tree;
|
|
5101
|
+
}
|
|
5102
|
+
}
|
|
5103
|
+
targetTreeContext = ptr;
|
|
5104
|
+
}
|
|
5105
|
+
let movedNodeData = null;
|
|
5106
|
+
const removeSourceNode = (node) => {
|
|
5107
|
+
if (!node.children) return false;
|
|
5108
|
+
const idx = node.children.findIndex((child) => {
|
|
5109
|
+
var _a;
|
|
5110
|
+
return String(child.is_section ? child.id : (_a = child.node) == null ? void 0 : _a.id) === String(sourceId);
|
|
5111
|
+
});
|
|
5112
|
+
if (idx !== -1) {
|
|
5113
|
+
movedNodeData = node.children[idx];
|
|
5114
|
+
node.children.splice(idx, 1);
|
|
5115
|
+
return true;
|
|
5116
|
+
}
|
|
5117
|
+
for (const child of node.children) {
|
|
5118
|
+
if (removeSourceNode(child)) return true;
|
|
5119
|
+
}
|
|
5120
|
+
return false;
|
|
5121
|
+
};
|
|
5122
|
+
const insertTargetNode = (node) => {
|
|
5123
|
+
var _a;
|
|
5124
|
+
if (String(node.is_section ? node.id : (_a = node.node) == null ? void 0 : _a.id) === String(targetId)) {
|
|
5125
|
+
if (!node.children) node.children = [];
|
|
5126
|
+
node.children.push(movedNodeData);
|
|
5127
|
+
return true;
|
|
5128
|
+
}
|
|
5129
|
+
if (node.children) {
|
|
5130
|
+
for (const child of node.children) {
|
|
5131
|
+
if (insertTargetNode(child)) return true;
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
return false;
|
|
5135
|
+
};
|
|
5136
|
+
if (removeSourceNode(targetTreeContext) && movedNodeData) {
|
|
5137
|
+
if (insertTargetNode(targetTreeContext)) {
|
|
5138
|
+
if (!isAbstraction) {
|
|
5139
|
+
updateGlobalTree(rootTreeClone);
|
|
5140
|
+
}
|
|
5141
|
+
setAncestryMode((prev) => ({ ...prev, [treeKey]: rootTreeClone }));
|
|
5142
|
+
} else {
|
|
5143
|
+
alert("N\xE3o \xE9 poss\xEDvel mover um node para dentro de seus pr\xF3prios descendentes.");
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
};
|
|
5056
5147
|
const takeSnapshot = (tree, name, desc, sections, customProps2, isPrivateVal) => {
|
|
5057
5148
|
return {
|
|
5058
5149
|
tree: JSON.stringify(tree),
|
|
@@ -5823,66 +5914,6 @@ function CreateAncestryPanel({
|
|
|
5823
5914
|
updateGlobalTree(newRootTree);
|
|
5824
5915
|
}
|
|
5825
5916
|
}, [description, existingSections]);
|
|
5826
|
-
const handleMoveNode = (sourceId, targetId) => {
|
|
5827
|
-
if (!activeTree) return;
|
|
5828
|
-
const rootTreeClone = JSON.parse(JSON.stringify(ancestryMode.tree));
|
|
5829
|
-
let targetTreeContext = rootTreeClone;
|
|
5830
|
-
if (branchStack.length > 0) {
|
|
5831
|
-
let ptr = rootTreeClone;
|
|
5832
|
-
for (const step of branchStack) {
|
|
5833
|
-
const found = findNodePath(ptr, step.nodeId);
|
|
5834
|
-
if (found && found.node.parallel_branches) {
|
|
5835
|
-
const branch = found.node.parallel_branches.find((b) => b.id === step.branchId);
|
|
5836
|
-
if (branch) ptr = branch.tree;
|
|
5837
|
-
}
|
|
5838
|
-
}
|
|
5839
|
-
targetTreeContext = ptr;
|
|
5840
|
-
}
|
|
5841
|
-
let movedNodeData = null;
|
|
5842
|
-
const removeSourceNode = (node) => {
|
|
5843
|
-
if (!node.children) return;
|
|
5844
|
-
const idx = node.children.findIndex((child) => {
|
|
5845
|
-
var _a;
|
|
5846
|
-
const cId = child.is_section ? child.id : String((_a = child.node) == null ? void 0 : _a.id);
|
|
5847
|
-
return String(cId) === String(sourceId);
|
|
5848
|
-
});
|
|
5849
|
-
if (idx !== -1) {
|
|
5850
|
-
movedNodeData = node.children[idx];
|
|
5851
|
-
node.children.splice(idx, 1);
|
|
5852
|
-
return true;
|
|
5853
|
-
}
|
|
5854
|
-
for (const child of node.children) {
|
|
5855
|
-
if (removeSourceNode(child)) return true;
|
|
5856
|
-
}
|
|
5857
|
-
return false;
|
|
5858
|
-
};
|
|
5859
|
-
const insertTargetNode = (node) => {
|
|
5860
|
-
var _a;
|
|
5861
|
-
const nodeId = node.is_section ? node.id : String((_a = node.node) == null ? void 0 : _a.id);
|
|
5862
|
-
if (String(nodeId) === String(targetId)) {
|
|
5863
|
-
if (!node.children) node.children = [];
|
|
5864
|
-
node.children.push(movedNodeData);
|
|
5865
|
-
return true;
|
|
5866
|
-
}
|
|
5867
|
-
if (node.children) {
|
|
5868
|
-
for (const child of node.children) {
|
|
5869
|
-
if (insertTargetNode(child)) return true;
|
|
5870
|
-
}
|
|
5871
|
-
}
|
|
5872
|
-
return false;
|
|
5873
|
-
};
|
|
5874
|
-
const foundAndRemoved = removeSourceNode(targetTreeContext);
|
|
5875
|
-
if (!foundAndRemoved || !movedNodeData) {
|
|
5876
|
-
console.error("Node de origem n\xE3o encontrado na \xE1rvore.");
|
|
5877
|
-
return;
|
|
5878
|
-
}
|
|
5879
|
-
const inserted = insertTargetNode(targetTreeContext);
|
|
5880
|
-
if (!inserted) {
|
|
5881
|
-
alert("N\xE3o \xE9 poss\xEDvel mover um node para dentro de seus pr\xF3prios descendentes.");
|
|
5882
|
-
return;
|
|
5883
|
-
}
|
|
5884
|
-
updateGlobalTree(rootTreeClone);
|
|
5885
|
-
};
|
|
5886
5917
|
const handleTriggerFullRender = () => {
|
|
5887
5918
|
var _a;
|
|
5888
5919
|
if (onRenderFullAncestry && activeTree) {
|
|
@@ -6134,7 +6165,7 @@ function CreateAncestryPanel({
|
|
|
6134
6165
|
), /* @__PURE__ */ React10.createElement(
|
|
6135
6166
|
"button",
|
|
6136
6167
|
{
|
|
6137
|
-
onClick:
|
|
6168
|
+
onClick: () => handleToggleAddMode(false),
|
|
6138
6169
|
className: `p-1.5 rounded-md transition-colors ${isAddingNodes ? "bg-cyan-500 text-white shadow-lg shadow-cyan-500/30" : "bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600"}`,
|
|
6139
6170
|
title: isAddingNodes ? "Concluir edi\xE7\xE3o da estrutura" : "Editar estrutura e adicionar nodes"
|
|
6140
6171
|
},
|
|
@@ -6143,17 +6174,54 @@ function CreateAncestryPanel({
|
|
|
6143
6174
|
NodeItem,
|
|
6144
6175
|
{
|
|
6145
6176
|
nodeData: activeTree,
|
|
6146
|
-
onSelectParent,
|
|
6147
|
-
onRemoveNode,
|
|
6177
|
+
onSelectParent: (id) => handleSelectAncestryParent(id, false),
|
|
6178
|
+
onRemoveNode: (path) => handleRemoveNode(path, false),
|
|
6148
6179
|
onEditRelationship,
|
|
6149
|
-
onMoveNode: handleMoveNode,
|
|
6180
|
+
onMoveNode: (s, t) => handleMoveNode(s, t, false),
|
|
6150
6181
|
selectedParentId,
|
|
6151
6182
|
level: 0,
|
|
6152
6183
|
isLast: true,
|
|
6153
6184
|
path: [],
|
|
6154
6185
|
isEditable: isAddingNodes
|
|
6155
6186
|
}
|
|
6156
|
-
), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ React10.createElement("div", { className: "text-center py-4 text-xs text-slate-500 italic" }, "A estrutura est\xE1 vazia. Clique no l\xE1pis acima para adicionar nodes."))), branchStack.length === 0 && /* @__PURE__ */ React10.createElement("div", { className:
|
|
6187
|
+
), (!activeTree || activeTree.children.length === 0) && !isAddingNodes && /* @__PURE__ */ React10.createElement("div", { className: "text-center py-4 text-xs text-slate-500 italic" }, "A estrutura est\xE1 vazia. Clique no l\xE1pis acima para adicionar nodes."))), branchStack.length === 0 && ancestryMode.abstraction_tree && /* @__PURE__ */ React10.createElement("div", { className: `mt-6 rounded-lg border transition-all duration-300 overflow-hidden ${ancestryMode.isAddingAbstractionNodes ? "border-purple-500/40 bg-slate-900/60 ring-1 ring-purple-500/20" : "border-white/10 bg-slate-800/60"}` }, /* @__PURE__ */ React10.createElement("div", { className: `flex items-center justify-between px-3 py-2 border-b ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-900/20 border-purple-500/20" : "bg-white/5 border-white/5"}` }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React10.createElement("span", { className: `text-xs font-semibold uppercase tracking-wider ${ancestryMode.isAddingAbstractionNodes ? "text-purple-300" : "text-slate-400"}` }, "Estrutura de Abstra\xE7\xE3o"), ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement("span", { className: "text-[10px] bg-purple-500/20 text-purple-300 px-1.5 py-0.5 rounded animate-pulse" }, "Editando")), /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React10.createElement(
|
|
6188
|
+
"button",
|
|
6189
|
+
{
|
|
6190
|
+
type: "button",
|
|
6191
|
+
onClick: () => {
|
|
6192
|
+
const tempPayload = {
|
|
6193
|
+
ancestry_id: currentAncestryId || "temp_rendering",
|
|
6194
|
+
abstraction_tree: ancestryMode.abstraction_tree
|
|
6195
|
+
};
|
|
6196
|
+
if (onRenderAbstractionTree) onRenderAbstractionTree(tempPayload);
|
|
6197
|
+
},
|
|
6198
|
+
className: "p-1.5 rounded-md bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600 transition-colors",
|
|
6199
|
+
title: "Renderizar Verticalmente no Cen\xE1rio"
|
|
6200
|
+
},
|
|
6201
|
+
/* @__PURE__ */ React10.createElement(FiLayers5, { size: 14 })
|
|
6202
|
+
), /* @__PURE__ */ React10.createElement(
|
|
6203
|
+
"button",
|
|
6204
|
+
{
|
|
6205
|
+
onClick: () => handleToggleAddMode(true),
|
|
6206
|
+
className: `p-1.5 rounded-md transition-colors ${ancestryMode.isAddingAbstractionNodes ? "bg-purple-500 text-white shadow-lg shadow-purple-500/30" : "bg-slate-700 text-slate-400 hover:text-white hover:bg-slate-600"}`,
|
|
6207
|
+
title: "Editar estrutura da abstra\xE7\xE3o"
|
|
6208
|
+
},
|
|
6209
|
+
ancestryMode.isAddingAbstractionNodes ? /* @__PURE__ */ React10.createElement(FiCheck4, { size: 14 }) : /* @__PURE__ */ React10.createElement(FiEdit23, { size: 14 })
|
|
6210
|
+
))), /* @__PURE__ */ React10.createElement("div", { className: "p-4 space-y-2" }, ancestryMode.isAddingAbstractionNodes && /* @__PURE__ */ React10.createElement("div", { className: "mb-3 p-2 rounded bg-purple-900/20 border border-purple-500/20 text-xs text-purple-200 flex items-start gap-2" }, /* @__PURE__ */ React10.createElement(FiMousePointer, { className: "mt-0.5 flex-shrink-0" }), /* @__PURE__ */ React10.createElement("span", null, "Clique nos nodes do cen\xE1rio para adicion\xE1-los. Arraste e solte para organizar a hierarquia.")), /* @__PURE__ */ React10.createElement(
|
|
6211
|
+
NodeItem,
|
|
6212
|
+
{
|
|
6213
|
+
nodeData: ancestryMode.abstraction_tree,
|
|
6214
|
+
onSelectParent: (id) => handleSelectAncestryParent(id, true),
|
|
6215
|
+
onRemoveNode: (path) => handleRemoveNode(path, true),
|
|
6216
|
+
onEditRelationship,
|
|
6217
|
+
onMoveNode: (s, t) => handleMoveNode(s, t, true),
|
|
6218
|
+
selectedParentId: ancestryMode.selectedAbstractionParentId,
|
|
6219
|
+
level: 0,
|
|
6220
|
+
isLast: true,
|
|
6221
|
+
path: [],
|
|
6222
|
+
isEditable: ancestryMode.isAddingAbstractionNodes
|
|
6223
|
+
}
|
|
6224
|
+
))), branchStack.length === 0 && /* @__PURE__ */ React10.createElement("div", { className: "mt-3 flex items-center justify-end px-1" }, /* @__PURE__ */ React10.createElement("label", { className: "flex items-center gap-2 cursor-pointer group select-none" }, /* @__PURE__ */ React10.createElement("div", { className: `w-4 h-4 rounded border flex items-center justify-center transition-colors ${isPrivate ? "bg-indigo-500 border-indigo-500" : "border-slate-500 bg-transparent"}` }, isPrivate && /* @__PURE__ */ React10.createElement(FiCheck4, { size: 12, className: "text-white" })), /* @__PURE__ */ React10.createElement(
|
|
6157
6225
|
"input",
|
|
6158
6226
|
{
|
|
6159
6227
|
type: "checkbox",
|
|
@@ -6201,7 +6269,7 @@ function CreateAncestryPanel({
|
|
|
6201
6269
|
}
|
|
6202
6270
|
|
|
6203
6271
|
// src/components/ImageViewer.jsx
|
|
6204
|
-
import React11, { useState as useState11, useEffect as useEffect10, useLayoutEffect as useLayoutEffect2, useCallback } from "react";
|
|
6272
|
+
import React11, { useState as useState11, useEffect as useEffect10, useLayoutEffect as useLayoutEffect2, useCallback as useCallback2 } from "react";
|
|
6205
6273
|
import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
|
|
6206
6274
|
function ImageViewer({ data, onClose }) {
|
|
6207
6275
|
var _a;
|
|
@@ -6214,12 +6282,12 @@ function ImageViewer({ data, onClose }) {
|
|
|
6214
6282
|
setCurrentIndex(startIndex);
|
|
6215
6283
|
}
|
|
6216
6284
|
}, [visible, startIndex]);
|
|
6217
|
-
const handleNext =
|
|
6285
|
+
const handleNext = useCallback2(() => {
|
|
6218
6286
|
if (images.length > 1) {
|
|
6219
6287
|
setCurrentIndex((prev) => (prev + 1) % images.length);
|
|
6220
6288
|
}
|
|
6221
6289
|
}, [images.length]);
|
|
6222
|
-
const handlePrev =
|
|
6290
|
+
const handlePrev = useCallback2(() => {
|
|
6223
6291
|
if (images.length > 1) {
|
|
6224
6292
|
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
|
|
6225
6293
|
}
|
|
@@ -8865,10 +8933,10 @@ function XViewScene({
|
|
|
8865
8933
|
}
|
|
8866
8934
|
stateRef.current.nodeIdToParentFileMap = map;
|
|
8867
8935
|
}, [isInitialized, sceneVersion]);
|
|
8868
|
-
const handleNavigateBack =
|
|
8936
|
+
const handleNavigateBack = useCallback3(() => {
|
|
8869
8937
|
router.push("/dashboard/scenes");
|
|
8870
8938
|
}, [router]);
|
|
8871
|
-
const handleConfirmImport =
|
|
8939
|
+
const handleConfirmImport = useCallback3(
|
|
8872
8940
|
async (importPayload) => {
|
|
8873
8941
|
var _a2, _b2;
|
|
8874
8942
|
let files = [];
|
|
@@ -8967,7 +9035,7 @@ function XViewScene({
|
|
|
8967
9035
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
8968
9036
|
setImageViewer({ visible: true, images, startIndex });
|
|
8969
9037
|
};
|
|
8970
|
-
const tweenToTarget =
|
|
9038
|
+
const tweenToTarget = useCallback3((target, zoomFactor = 1, forcedDirection = null) => {
|
|
8971
9039
|
const { camera, controls, tweenGroup } = stateRef.current;
|
|
8972
9040
|
if (!camera || !controls || !tweenGroup) return;
|
|
8973
9041
|
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
@@ -8990,7 +9058,7 @@ function XViewScene({
|
|
|
8990
9058
|
if (!t || typeof t.closest !== "function") return false;
|
|
8991
9059
|
return !!t.closest(".ui-overlay");
|
|
8992
9060
|
};
|
|
8993
|
-
const buildFullAncestryTree =
|
|
9061
|
+
const buildFullAncestryTree = useCallback3((idTree, nodes, ancestries = []) => {
|
|
8994
9062
|
if (!idTree) return null;
|
|
8995
9063
|
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
8996
9064
|
const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
|
|
@@ -9070,7 +9138,7 @@ function XViewScene({
|
|
|
9070
9138
|
}
|
|
9071
9139
|
return recursiveBuild(idTree);
|
|
9072
9140
|
}, []);
|
|
9073
|
-
const handleActivateTimeline =
|
|
9141
|
+
const handleActivateTimeline = useCallback3(() => {
|
|
9074
9142
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9075
9143
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
9076
9144
|
while (timelineIntervalsGroup.children.length > 0) {
|
|
@@ -9223,7 +9291,7 @@ function XViewScene({
|
|
|
9223
9291
|
}
|
|
9224
9292
|
});
|
|
9225
9293
|
}, []);
|
|
9226
|
-
const handleVersionTimeline =
|
|
9294
|
+
const handleVersionTimeline = useCallback3((sourceMesh, versionMeshes) => {
|
|
9227
9295
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9228
9296
|
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
|
|
9229
9297
|
versionMeshes.forEach((mesh) => {
|
|
@@ -9404,12 +9472,12 @@ function XViewScene({
|
|
|
9404
9472
|
isInitialized,
|
|
9405
9473
|
permissionStatus
|
|
9406
9474
|
]);
|
|
9407
|
-
const isNodeInView =
|
|
9475
|
+
const isNodeInView = useCallback3((id) => {
|
|
9408
9476
|
const key = String(id);
|
|
9409
9477
|
const objs = stateRef.current.nodeObjects || {};
|
|
9410
9478
|
return !!objs[key];
|
|
9411
9479
|
}, []);
|
|
9412
|
-
const addOrUpdateNodeMesh =
|
|
9480
|
+
const addOrUpdateNodeMesh = useCallback3((nodeData, position, suppressVersionUpdate = false) => {
|
|
9413
9481
|
const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
|
|
9414
9482
|
const nodeId = String(nodeData.id);
|
|
9415
9483
|
if (nodeObjects[nodeId]) {
|
|
@@ -9734,43 +9802,38 @@ function XViewScene({
|
|
|
9734
9802
|
return;
|
|
9735
9803
|
}
|
|
9736
9804
|
if (ancestry.isActive) {
|
|
9737
|
-
if (ancestry.isAddingNodes) {
|
|
9805
|
+
if (ancestry.isAddingNodes || ancestry.isAddingAbstractionNodes) {
|
|
9738
9806
|
const clickedNode = stateRef.current.dragCandidate || tryPickNode();
|
|
9739
9807
|
stateRef.current.dragCandidate = null;
|
|
9740
9808
|
stateRef.current.pointerDown.isDown = false;
|
|
9741
9809
|
stateRef.current.controls.enabled = true;
|
|
9742
|
-
|
|
9810
|
+
const isAbstraction = ancestry.isAddingAbstractionNodes;
|
|
9811
|
+
const currentSelectedParent = isAbstraction ? ancestry.selectedAbstractionParentId : ancestry.selectedParentId;
|
|
9812
|
+
if (clickedNode && currentSelectedParent) {
|
|
9743
9813
|
const clickedNodeId = String(clickedNode.userData.id);
|
|
9744
|
-
const parentId = String(
|
|
9814
|
+
const parentId = String(currentSelectedParent);
|
|
9745
9815
|
if (clickedNodeId === parentId) {
|
|
9746
9816
|
alert("Erro: N\xE3o \xE9 poss\xEDvel adicionar um Node como filho dele mesmo.");
|
|
9747
9817
|
return;
|
|
9748
9818
|
}
|
|
9749
9819
|
const parentInfo = stateRef.current.nodeIdToParentFileMap.get(clickedNodeId);
|
|
9750
|
-
if (!parentInfo)
|
|
9751
|
-
console.warn(`Node ${clickedNodeId} n\xE3o encontrado em nenhum arquivo pai.`);
|
|
9752
|
-
return;
|
|
9753
|
-
}
|
|
9820
|
+
if (!parentInfo) return;
|
|
9754
9821
|
const fullNodeData = (_a2 = parentDataRef.current[parentInfo.parentFileId]) == null ? void 0 : _a2.nodes.find((n) => String(n.id) === clickedNodeId);
|
|
9755
|
-
if (!fullNodeData)
|
|
9756
|
-
console.error(`Falha ao encontrar dados completos do Node ${clickedNodeId} mesmo com parentInfo.`);
|
|
9757
|
-
return;
|
|
9758
|
-
}
|
|
9822
|
+
if (!fullNodeData) return;
|
|
9759
9823
|
const addChildToNode = (current, targetParentId, childNode) => {
|
|
9760
9824
|
const currentId = current.is_section ? current.id || current.section_id : String(current.node.id);
|
|
9761
9825
|
if (String(currentId) === String(targetParentId)) {
|
|
9762
9826
|
const alreadyExists = current.children.some((child) => !child.is_section && String(child.node.id) === String(childNode.id));
|
|
9763
9827
|
if (alreadyExists) return current;
|
|
9764
|
-
|
|
9765
|
-
return { ...current, children: newChildren };
|
|
9828
|
+
return { ...current, children: [...current.children, { node: childNode, children: [], relationship: {} }] };
|
|
9766
9829
|
}
|
|
9767
|
-
|
|
9768
|
-
return { ...current, children: updatedChildren };
|
|
9830
|
+
return { ...current, children: current.children.map((c) => addChildToNode(c, targetParentId, childNode)) };
|
|
9769
9831
|
};
|
|
9770
9832
|
setAncestryMode((prev) => {
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
9833
|
+
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
9834
|
+
if (!prev[treeKey]) return prev;
|
|
9835
|
+
const newTree = addChildToNode(prev[treeKey], parentId, fullNodeData);
|
|
9836
|
+
return { ...prev, [treeKey]: newTree };
|
|
9774
9837
|
});
|
|
9775
9838
|
}
|
|
9776
9839
|
return;
|
|
@@ -10063,7 +10126,7 @@ function XViewScene({
|
|
|
10063
10126
|
}
|
|
10064
10127
|
};
|
|
10065
10128
|
}, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
|
|
10066
|
-
const handleGhostNodeImageChange =
|
|
10129
|
+
const handleGhostNodeImageChange = useCallback3((useImage, imageUrl) => {
|
|
10067
10130
|
const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10068
10131
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
10069
10132
|
if (!ghostNode || !graphGroup) return;
|
|
@@ -10105,7 +10168,7 @@ function XViewScene({
|
|
|
10105
10168
|
aura: newGhostNode.getObjectByName("aura")
|
|
10106
10169
|
};
|
|
10107
10170
|
}, []);
|
|
10108
|
-
const handleGhostNodeIntensityChange =
|
|
10171
|
+
const handleGhostNodeIntensityChange = useCallback3((newIntensity) => {
|
|
10109
10172
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10110
10173
|
if (!ghostNode) return;
|
|
10111
10174
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10126,7 +10189,7 @@ function XViewScene({
|
|
|
10126
10189
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
10127
10190
|
}
|
|
10128
10191
|
}, []);
|
|
10129
|
-
const handleDetailNodeIntensityChange =
|
|
10192
|
+
const handleDetailNodeIntensityChange = useCallback3((nodeId, newIntensity) => {
|
|
10130
10193
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
10131
10194
|
if (!mesh) return;
|
|
10132
10195
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10253,18 +10316,21 @@ function XViewScene({
|
|
|
10253
10316
|
setAncestryMode({
|
|
10254
10317
|
isActive: true,
|
|
10255
10318
|
tree: { node: nodeData, children: [] },
|
|
10319
|
+
abstraction_tree: { node: nodeData, children: [] },
|
|
10256
10320
|
selectedParentId: nodeData.id,
|
|
10321
|
+
selectedAbstractionParentId: nodeData.id,
|
|
10257
10322
|
isEditMode: false,
|
|
10258
10323
|
currentAncestryId: null,
|
|
10259
10324
|
ancestryName: `Ancestralidade ${nodeData.name}`,
|
|
10260
10325
|
ancestryDescription: "",
|
|
10261
|
-
isAddingNodes: false
|
|
10326
|
+
isAddingNodes: false,
|
|
10327
|
+
isAddingAbstractionNodes: false
|
|
10262
10328
|
});
|
|
10263
10329
|
if (mountRef.current) {
|
|
10264
10330
|
mountRef.current.style.cursor = "default";
|
|
10265
10331
|
}
|
|
10266
10332
|
};
|
|
10267
|
-
const handleAncestryTreeUpdate =
|
|
10333
|
+
const handleAncestryTreeUpdate = useCallback3((newTree, extraData = null) => {
|
|
10268
10334
|
setAncestryMode((prev) => {
|
|
10269
10335
|
const prevTreeStr = JSON.stringify(prev.tree);
|
|
10270
10336
|
const newTreeStr = JSON.stringify(newTree);
|
|
@@ -10334,7 +10400,7 @@ function XViewScene({
|
|
|
10334
10400
|
const handleStartVersioning = (nodeData) => {
|
|
10335
10401
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
10336
10402
|
};
|
|
10337
|
-
const handleClearAncestryVisuals =
|
|
10403
|
+
const handleClearAncestryVisuals = useCallback3((ancestryId) => {
|
|
10338
10404
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
10339
10405
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
10340
10406
|
if (renderIndex !== -1) {
|
|
@@ -10348,7 +10414,7 @@ function XViewScene({
|
|
|
10348
10414
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
10349
10415
|
}
|
|
10350
10416
|
}, []);
|
|
10351
|
-
const handleRenderAncestry =
|
|
10417
|
+
const handleRenderAncestry = useCallback3(
|
|
10352
10418
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
10353
10419
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
10354
10420
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -10764,7 +10830,47 @@ function XViewScene({
|
|
|
10764
10830
|
},
|
|
10765
10831
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
10766
10832
|
);
|
|
10767
|
-
const
|
|
10833
|
+
const handleRenderAbstractionTree = useCallback3((ancestryObject) => {
|
|
10834
|
+
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
10835
|
+
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
10836
|
+
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
10837
|
+
const allParentNodes = Object.values(parentDataRef.current).flatMap((f) => f.nodes);
|
|
10838
|
+
const fullTree = buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, ancestryDataRef.current);
|
|
10839
|
+
if (!fullTree || !fullTree.node) return;
|
|
10840
|
+
const absId = ancestryObject.ancestry_id + "_abs";
|
|
10841
|
+
handleClearAncestryVisuals(absId);
|
|
10842
|
+
const colorHex = 9133302;
|
|
10843
|
+
const resolution = new THREE3.Vector2(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
|
|
10844
|
+
const ancestryEntry = { id: absId, lines: [], isFullRender: true };
|
|
10845
|
+
renderedAncestries.push(ancestryEntry);
|
|
10846
|
+
const rootNodeId = String(fullTree.node.id);
|
|
10847
|
+
let rootNodeMesh = nodeObjects[rootNodeId];
|
|
10848
|
+
let rootTargetPos = rootNodeMesh ? rootNodeMesh.position.clone() : new THREE3.Vector3(0, 0, 0);
|
|
10849
|
+
if (!rootNodeMesh) {
|
|
10850
|
+
rootNodeMesh = addOrUpdateNodeMesh(fullTree.node, rootTargetPos, true);
|
|
10851
|
+
}
|
|
10852
|
+
const SPACING_Y = -40;
|
|
10853
|
+
const SPACING_X = 55;
|
|
10854
|
+
const renderVertical = (treeNode, parentMesh, parentPos, level) => {
|
|
10855
|
+
if (!treeNode.children || treeNode.children.length === 0) return;
|
|
10856
|
+
const totalSiblings = treeNode.children.length;
|
|
10857
|
+
treeNode.children.forEach((childItem, i) => {
|
|
10858
|
+
if (!childItem.node) return;
|
|
10859
|
+
const childX = parentPos.x + (i - (totalSiblings - 1) / 2) * (SPACING_X / Math.max(1, level * 0.4));
|
|
10860
|
+
const childY = parentPos.y + SPACING_Y;
|
|
10861
|
+
const childPos = new THREE3.Vector3(childX, childY, parentPos.z);
|
|
10862
|
+
const childMesh = addOrUpdateNodeMesh(childItem.node, childPos, true);
|
|
10863
|
+
const line = createAncestryLinkLine(parentMesh, childMesh, resolution, {}, colorHex);
|
|
10864
|
+
ancestryGroup.add(line);
|
|
10865
|
+
ancestryEntry.lines.push(line);
|
|
10866
|
+
renderVertical(childItem, childMesh, childPos, level + 1);
|
|
10867
|
+
});
|
|
10868
|
+
};
|
|
10869
|
+
renderVertical(fullTree, rootNodeMesh, rootTargetPos, 1);
|
|
10870
|
+
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
10871
|
+
tweenToTarget(rootTargetPos, 0.7);
|
|
10872
|
+
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
10873
|
+
const handleReadModeBranchNav = useCallback3((nodeId, action, direction = "right") => {
|
|
10768
10874
|
const { ancestry, branchStack } = readingMode;
|
|
10769
10875
|
if (!ancestry || !ancestry.tree) return;
|
|
10770
10876
|
const allAncestries = ancestryDataRef.current || [];
|
|
@@ -10908,7 +11014,7 @@ function XViewScene({
|
|
|
10908
11014
|
}));
|
|
10909
11015
|
}
|
|
10910
11016
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
10911
|
-
const handleReadModeHighlight =
|
|
11017
|
+
const handleReadModeHighlight = useCallback3((nodeId) => {
|
|
10912
11018
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
10913
11019
|
stateRef.current.highlightedNodeId = nodeId;
|
|
10914
11020
|
}
|
|
@@ -11006,7 +11112,7 @@ function XViewScene({
|
|
|
11006
11112
|
// <--- ADICIONADO
|
|
11007
11113
|
};
|
|
11008
11114
|
}, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11009
|
-
const handleStartReadingAncestry =
|
|
11115
|
+
const handleStartReadingAncestry = useCallback3(
|
|
11010
11116
|
async (ancestryObject) => {
|
|
11011
11117
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11012
11118
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11032,7 +11138,7 @@ function XViewScene({
|
|
|
11032
11138
|
},
|
|
11033
11139
|
[handleRenderAncestry]
|
|
11034
11140
|
);
|
|
11035
|
-
const handleReadModeSectionChange =
|
|
11141
|
+
const handleReadModeSectionChange = useCallback3((activeSectionId) => {
|
|
11036
11142
|
const { ancestry, branchStack } = readingMode;
|
|
11037
11143
|
if (!ancestry || !readingMode.isActive) return;
|
|
11038
11144
|
let targetObj = ancestry;
|
|
@@ -11101,10 +11207,10 @@ function XViewScene({
|
|
|
11101
11207
|
}, 0);
|
|
11102
11208
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11103
11209
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11104
|
-
const handleCloseReadMode =
|
|
11210
|
+
const handleCloseReadMode = useCallback3(() => {
|
|
11105
11211
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
11106
11212
|
}, []);
|
|
11107
|
-
const handleAncestrySectionChange =
|
|
11213
|
+
const handleAncestrySectionChange = useCallback3((activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
11108
11214
|
var _a2, _b2;
|
|
11109
11215
|
const currentMode = stateRef.current.ancestry;
|
|
11110
11216
|
let targetObj = ancestryOverride;
|
|
@@ -11156,7 +11262,7 @@ function XViewScene({
|
|
|
11156
11262
|
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
11157
11263
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11158
11264
|
}, [handleRenderAncestry]);
|
|
11159
|
-
const handleEditAncestry =
|
|
11265
|
+
const handleEditAncestry = useCallback3(
|
|
11160
11266
|
async (ancestryObject) => {
|
|
11161
11267
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11162
11268
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11173,22 +11279,24 @@ function XViewScene({
|
|
|
11173
11279
|
alert("Falha ao reconstruir a \xE1rvore de ancestralidade. Alguns Nodes podem estar faltando.");
|
|
11174
11280
|
return;
|
|
11175
11281
|
}
|
|
11282
|
+
const fullAbstractionTree = ancestryObject.abstraction_tree ? buildFullAncestryTree(ancestryObject.abstraction_tree, allParentNodes, allAncestries) : { node: fullTree.node, children: [] };
|
|
11176
11283
|
setAncestryMode({
|
|
11177
11284
|
isActive: true,
|
|
11178
|
-
// --- CORREÇÃO AQUI ---
|
|
11179
|
-
// 1. Espalhamos as propriedades do objeto (custom props, ids, etc) PRIMEIRO.
|
|
11180
11285
|
...ancestryObject,
|
|
11181
|
-
// 2. Definimos a 'tree' DEPOIS. Isso garante que a árvore 'fullTree' (hidratada com os nodes reais)
|
|
11182
|
-
// prevaleça sobre a árvore 'crua' (apenas IDs) que veio dentro de 'ancestryObject'.
|
|
11183
11286
|
tree: fullTree,
|
|
11184
|
-
|
|
11287
|
+
abstraction_tree: fullAbstractionTree,
|
|
11288
|
+
// NOVO
|
|
11185
11289
|
selectedParentId: ancestryObject.ancestral_node,
|
|
11290
|
+
selectedAbstractionParentId: ancestryObject.ancestral_node,
|
|
11291
|
+
// NOVO
|
|
11186
11292
|
isEditMode: true,
|
|
11187
11293
|
currentAncestryId: ancestryObject.ancestry_id,
|
|
11188
11294
|
ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
|
|
11189
11295
|
ancestryDescription: ancestryObject.description || "",
|
|
11190
11296
|
ancestryDescriptionSections: ancestryObject.description_sections || [],
|
|
11191
|
-
isAddingNodes: false
|
|
11297
|
+
isAddingNodes: false,
|
|
11298
|
+
isAddingAbstractionNodes: false
|
|
11299
|
+
// NOVO
|
|
11192
11300
|
});
|
|
11193
11301
|
},
|
|
11194
11302
|
[handleRenderAncestry, buildFullAncestryTree]
|
|
@@ -11196,7 +11304,7 @@ function XViewScene({
|
|
|
11196
11304
|
const handleSelectAncestryParent = (nodeId) => {
|
|
11197
11305
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
11198
11306
|
};
|
|
11199
|
-
const handleRemoveFromAncestry =
|
|
11307
|
+
const handleRemoveFromAncestry = useCallback3((pathToRemove) => {
|
|
11200
11308
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
11201
11309
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
11202
11310
|
return;
|
|
@@ -11221,7 +11329,7 @@ function XViewScene({
|
|
|
11221
11329
|
return { ...prev, tree: newTree };
|
|
11222
11330
|
});
|
|
11223
11331
|
}, []);
|
|
11224
|
-
const handleSaveAncestry =
|
|
11332
|
+
const handleSaveAncestry = useCallback3(
|
|
11225
11333
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
11226
11334
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
11227
11335
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -11259,6 +11367,7 @@ function XViewScene({
|
|
|
11259
11367
|
};
|
|
11260
11368
|
};
|
|
11261
11369
|
const treeWithIds = convertTreeToIds(treeToUse);
|
|
11370
|
+
const abstractionTreeWithIds = convertTreeToIds(ancestryMode.abstraction_tree);
|
|
11262
11371
|
if (!treeWithIds) {
|
|
11263
11372
|
alert("Erro ao processar a \xE1rvore da ancestralidade.");
|
|
11264
11373
|
return;
|
|
@@ -11274,6 +11383,7 @@ function XViewScene({
|
|
|
11274
11383
|
description: ancestryDescription,
|
|
11275
11384
|
description_sections: ancestrySections,
|
|
11276
11385
|
tree: treeWithIds,
|
|
11386
|
+
abstraction_tree: abstractionTreeWithIds,
|
|
11277
11387
|
_imported_from_view_id: originalAncestryObj == null ? void 0 : originalAncestryObj._imported_from_view_id,
|
|
11278
11388
|
_imported_from_view_owner_id: originalAncestryObj == null ? void 0 : originalAncestryObj._imported_from_view_owner_id,
|
|
11279
11389
|
_origin_db_ids: originalAncestryObj == null ? void 0 : originalAncestryObj._origin_db_ids,
|
|
@@ -11423,7 +11533,7 @@ function XViewScene({
|
|
|
11423
11533
|
});
|
|
11424
11534
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
11425
11535
|
};
|
|
11426
|
-
const handleDeleteAncestry =
|
|
11536
|
+
const handleDeleteAncestry = useCallback3(
|
|
11427
11537
|
async (ancestryIdToDelete) => {
|
|
11428
11538
|
if (!ancestryIdToDelete) {
|
|
11429
11539
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -11485,15 +11595,15 @@ function XViewScene({
|
|
|
11485
11595
|
},
|
|
11486
11596
|
[save_view_data, delete_file_action]
|
|
11487
11597
|
);
|
|
11488
|
-
const handleOpenAncestryBoard =
|
|
11598
|
+
const handleOpenAncestryBoard = useCallback3(() => {
|
|
11489
11599
|
setIsAncestryBoardOpen(true);
|
|
11490
11600
|
}, []);
|
|
11491
|
-
const handleSelectAncestryFromBoard =
|
|
11601
|
+
const handleSelectAncestryFromBoard = useCallback3((ancestry) => {
|
|
11492
11602
|
setIsAncestryBoardOpen(false);
|
|
11493
11603
|
setIsSidebarOpen(false);
|
|
11494
11604
|
handleStartReadingAncestry(ancestry);
|
|
11495
11605
|
}, [handleStartReadingAncestry]);
|
|
11496
|
-
const handleSaveAncestryBoard =
|
|
11606
|
+
const handleSaveAncestryBoard = useCallback3(async (groups) => {
|
|
11497
11607
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
11498
11608
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
11499
11609
|
await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
|
|
@@ -11517,13 +11627,13 @@ function XViewScene({
|
|
|
11517
11627
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
11518
11628
|
});
|
|
11519
11629
|
}, [parentDataRef.current, sceneVersion]);
|
|
11520
|
-
const handleAddExistingNode =
|
|
11630
|
+
const handleAddExistingNode = useCallback3(
|
|
11521
11631
|
(nodeId) => {
|
|
11522
11632
|
return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
|
|
11523
11633
|
},
|
|
11524
11634
|
[actionHandlerContext]
|
|
11525
11635
|
);
|
|
11526
|
-
const handleSaveCurrentView =
|
|
11636
|
+
const handleSaveCurrentView = useCallback3(async () => {
|
|
11527
11637
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
11528
11638
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
11529
11639
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -11563,7 +11673,7 @@ function XViewScene({
|
|
|
11563
11673
|
const allAvailableAncestries = useMemo12(() => {
|
|
11564
11674
|
return ancestryDataRef.current || [];
|
|
11565
11675
|
}, [sceneVersion, isInitialized]);
|
|
11566
|
-
const handleOpenReference =
|
|
11676
|
+
const handleOpenReference = useCallback3((referenceData) => {
|
|
11567
11677
|
const { type, id } = referenceData;
|
|
11568
11678
|
if (type === "node") {
|
|
11569
11679
|
const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
|
|
@@ -11590,7 +11700,7 @@ function XViewScene({
|
|
|
11590
11700
|
}
|
|
11591
11701
|
}
|
|
11592
11702
|
}, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
|
|
11593
|
-
const handleToggleAncestryAddMode =
|
|
11703
|
+
const handleToggleAncestryAddMode = useCallback3(() => {
|
|
11594
11704
|
setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
|
|
11595
11705
|
}, []);
|
|
11596
11706
|
if (isLoading || status === "loading" || permissionStatus === "loading") {
|
|
@@ -11718,6 +11828,7 @@ function XViewScene({
|
|
|
11718
11828
|
CreateAncestryPanel,
|
|
11719
11829
|
{
|
|
11720
11830
|
ancestryMode,
|
|
11831
|
+
setAncestryMode,
|
|
11721
11832
|
onSelectParent: handleSelectAncestryParent,
|
|
11722
11833
|
onRemoveNode: handleRemoveFromAncestry,
|
|
11723
11834
|
onSave: handleSaveAncestry,
|
|
@@ -11736,7 +11847,8 @@ function XViewScene({
|
|
|
11736
11847
|
onRenderFullAncestry: (data, allowed, focus, rot) => handleRenderAncestry(data, allowed, focus, rot),
|
|
11737
11848
|
onClearAncestryVisuals: handleClearAncestryVisuals,
|
|
11738
11849
|
onUploadFile: upload_file_action,
|
|
11739
|
-
onOpenImageViewer: handleOpenImageViewer
|
|
11850
|
+
onOpenImageViewer: handleOpenImageViewer,
|
|
11851
|
+
onRenderAbstractionTree: (data) => handleRenderAbstractionTree(data)
|
|
11740
11852
|
}
|
|
11741
11853
|
),
|
|
11742
11854
|
editingAncestryRel.visible && /* @__PURE__ */ React23.createElement(
|
|
@@ -12106,7 +12218,16 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id) {
|
|
|
12106
12218
|
if (!parentNodeIds.has(String(ancestry.ancestral_node))) return null;
|
|
12107
12219
|
const cleanedTree = pruneTree(ancestry.tree);
|
|
12108
12220
|
if (!cleanedTree) return null;
|
|
12109
|
-
|
|
12221
|
+
let cleanedAbstraction = null;
|
|
12222
|
+
if (ancestry.abstraction_tree) {
|
|
12223
|
+
cleanedAbstraction = pruneTree(ancestry.abstraction_tree);
|
|
12224
|
+
}
|
|
12225
|
+
return {
|
|
12226
|
+
...ancestry,
|
|
12227
|
+
tree: cleanedTree,
|
|
12228
|
+
abstraction_tree: cleanedAbstraction
|
|
12229
|
+
// Salva a árvore limpa
|
|
12230
|
+
};
|
|
12110
12231
|
}).filter(Boolean);
|
|
12111
12232
|
if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
|
|
12112
12233
|
ancestryData = cleanedAncestryData;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lv-x-software-house/x_view",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9-dev.2",
|
|
4
4
|
"description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
|
|
5
5
|
"author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
|
|
6
6
|
"license": "UNLICENSED",
|