@lv-x-software-house/x_view 1.2.2-dev.2 → 1.2.2-dev.20
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 +1263 -888
- package/dist/index.mjs +720 -345
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import React23, { useCallback as
|
|
2
|
+
import React23, { useCallback as useCallback4, useEffect as useEffect21, useRef as useRef17, useState as useState23, useMemo as useMemo12 } from "react";
|
|
3
3
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
4
4
|
import { useSession } from "next-auth/react";
|
|
5
5
|
import CryptoJS from "crypto-js";
|
|
@@ -735,7 +735,7 @@ function XViewSidebar({
|
|
|
735
735
|
}
|
|
736
736
|
|
|
737
737
|
// src/components/AncestryRelationshipPanel.jsx
|
|
738
|
-
import React8, { useState as
|
|
738
|
+
import React8, { useState as useState9, useEffect as useEffect8, useRef as useRef7 } from "react";
|
|
739
739
|
|
|
740
740
|
// node_modules/uuid/dist/esm-node/rng.js
|
|
741
741
|
import crypto from "crypto";
|
|
@@ -785,6 +785,7 @@ function v4(options, buf, offset) {
|
|
|
785
785
|
var v4_default = v4;
|
|
786
786
|
|
|
787
787
|
// src/logic/x_view_utils.js
|
|
788
|
+
import { useState as useState3, useCallback } from "react";
|
|
788
789
|
import * as THREE2 from "three";
|
|
789
790
|
|
|
790
791
|
// src/logic/x_view_config.js
|
|
@@ -811,7 +812,6 @@ var x_view_config = {
|
|
|
811
812
|
ANCESTOR_HIGHLIGHT_COLOR: "#FFD700",
|
|
812
813
|
BLOOM_EFFECT: { strength: 1.35, radius: 0.6, threshold: 0.52 },
|
|
813
814
|
EMISSIVE_MULTIPLIER: {
|
|
814
|
-
// AJUSTE: Valores agora representam ADIÇÃO de intensidade, não multiplicação
|
|
815
815
|
BASE: 0,
|
|
816
816
|
HOVER: 2,
|
|
817
817
|
SELECTED: 1.5,
|
|
@@ -863,7 +863,6 @@ var computeNodeMaterialProps = (colorHex) => {
|
|
|
863
863
|
return {
|
|
864
864
|
color: srgb,
|
|
865
865
|
emissive: emissiveColor
|
|
866
|
-
// Intensity é controlada externamente
|
|
867
866
|
};
|
|
868
867
|
};
|
|
869
868
|
var createNodeMesh = (nodeData, position, glowTexture) => {
|
|
@@ -1154,6 +1153,7 @@ var createMultipleLinkLines = (linksArray, sourceNodeMesh, targetNodeMesh, resol
|
|
|
1154
1153
|
resolution,
|
|
1155
1154
|
isCurved,
|
|
1156
1155
|
isCurved,
|
|
1156
|
+
isCurved,
|
|
1157
1157
|
curveOffset
|
|
1158
1158
|
);
|
|
1159
1159
|
line.userData = {
|
|
@@ -1530,12 +1530,12 @@ var userActionHandlers = {
|
|
|
1530
1530
|
stateRef.current.creation = { isActive: true, sourceNodeData };
|
|
1531
1531
|
const ghostGeometry = new THREE.SphereGeometry(1.5, 32, 32);
|
|
1532
1532
|
const sourceColor = sourceNodeData.color || "#cccccc";
|
|
1533
|
-
const {
|
|
1534
|
-
const ghostColor = new THREE.Color(sourceColor);
|
|
1533
|
+
const { color: ghostColor, emissive: ghostEmissive } = computeNodeMaterialProps(sourceColor);
|
|
1535
1534
|
const ghostMaterial = new THREE.MeshStandardMaterial({
|
|
1536
1535
|
color: ghostColor,
|
|
1537
|
-
emissive:
|
|
1538
|
-
emissiveIntensity,
|
|
1536
|
+
emissive: ghostEmissive,
|
|
1537
|
+
emissiveIntensity: MIN_VISIBILITY_INTENSITY,
|
|
1538
|
+
// <-- Forçamos o brilho mínimo
|
|
1539
1539
|
roughness: 0.6,
|
|
1540
1540
|
metalness: 0,
|
|
1541
1541
|
transparent: true,
|
|
@@ -1606,27 +1606,50 @@ var userActionHandlers = {
|
|
|
1606
1606
|
setters.setFormPosition((p) => ({ ...p, opacity: 0 }));
|
|
1607
1607
|
},
|
|
1608
1608
|
handleSaveNode: async (context, newNodeData) => {
|
|
1609
|
-
const { graphDataRef, sceneDataRef, stateRef, creationMode, setters } = context;
|
|
1609
|
+
const { graphDataRef, sceneDataRef, stateRef, creationMode, setters, actions } = context;
|
|
1610
1610
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
1611
1611
|
const { sourceNodeData } = creationMode;
|
|
1612
|
-
const
|
|
1612
|
+
const { targetDatasetId, ...nodeDataToSave } = newNodeData;
|
|
1613
|
+
const newNode = { id: short.generate(), ...nodeDataToSave };
|
|
1613
1614
|
const newLink = { id: `link_${short.generate()}`, source: sourceNodeData.id, target: newNode.id };
|
|
1614
|
-
const
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1615
|
+
const sourceParentInfo = stateRef.current.nodeIdToParentFileMap.get(String(sourceNodeData.id));
|
|
1616
|
+
const finalTargetDatasetId = targetDatasetId || sourceParentInfo.parentFileId;
|
|
1617
|
+
const targetParentInfo = sceneDataRef.current.parent_dbs.find((db) => String(db.db_id) === String(finalTargetDatasetId));
|
|
1618
|
+
if (!sourceParentInfo || !targetParentInfo) {
|
|
1619
|
+
alert("Erro ao identificar os datasets de origem ou destino.");
|
|
1618
1620
|
return;
|
|
1619
1621
|
}
|
|
1620
|
-
const
|
|
1621
|
-
const
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1622
|
+
const isCrossDataset = String(sourceParentInfo.parentFileId) !== String(finalTargetDatasetId);
|
|
1623
|
+
const sourceDataToUpdate = JSON.parse(JSON.stringify(graphDataRef.current[sourceParentInfo.parentFileId]));
|
|
1624
|
+
let targetDataToUpdate = isCrossDataset ? JSON.parse(JSON.stringify(graphDataRef.current[finalTargetDatasetId])) : sourceDataToUpdate;
|
|
1625
|
+
targetDataToUpdate.nodes.push(newNode);
|
|
1626
|
+
sourceDataToUpdate.links.push(newLink);
|
|
1627
|
+
const savePromises = [];
|
|
1628
|
+
if (isCrossDataset) {
|
|
1629
|
+
savePromises.push(
|
|
1630
|
+
actions.save_view_data(`x_view_dbs/${sourceParentInfo.ownerId}/${sourceParentInfo.parentFileId}`, sourceDataToUpdate)
|
|
1631
|
+
);
|
|
1632
|
+
savePromises.push(
|
|
1633
|
+
actions.save_view_data(`x_view_dbs/${targetParentInfo.owner_id}/${finalTargetDatasetId}`, targetDataToUpdate)
|
|
1634
|
+
);
|
|
1635
|
+
} else {
|
|
1636
|
+
savePromises.push(
|
|
1637
|
+
actions.save_view_data(`x_view_dbs/${sourceParentInfo.ownerId}/${sourceParentInfo.parentFileId}`, sourceDataToUpdate)
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1625
1640
|
try {
|
|
1626
|
-
await
|
|
1627
|
-
graphDataRef.current[parentFileId] =
|
|
1641
|
+
await Promise.all(savePromises);
|
|
1642
|
+
graphDataRef.current[sourceParentInfo.parentFileId] = sourceDataToUpdate;
|
|
1643
|
+
if (isCrossDataset) {
|
|
1644
|
+
graphDataRef.current[finalTargetDatasetId] = targetDataToUpdate;
|
|
1645
|
+
}
|
|
1628
1646
|
const finalPosition = stateRef.current.ghostElements.node.position.clone();
|
|
1629
1647
|
addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
|
|
1648
|
+
stateRef.current.nodeIdToParentFileMap.set(String(newNode.id), {
|
|
1649
|
+
parentFileId: finalTargetDatasetId,
|
|
1650
|
+
ownerId: targetParentInfo.owner_id,
|
|
1651
|
+
datasetName: targetDataToUpdate.dataset_name || "Dataset Desconhecido"
|
|
1652
|
+
});
|
|
1630
1653
|
setters.setSceneVersion((v) => v + 1);
|
|
1631
1654
|
} catch (error) {
|
|
1632
1655
|
console.error("Falha ao salvar os dados do grafo:", error);
|
|
@@ -1664,12 +1687,12 @@ var userActionHandlers = {
|
|
|
1664
1687
|
stateRef.current.creation = { isActive: true, sourceNodeData };
|
|
1665
1688
|
const ghostGeometry = new THREE.SphereGeometry(1.5, 32, 32);
|
|
1666
1689
|
const sourceColor = sourceNodeData.color || "#cccccc";
|
|
1667
|
-
const {
|
|
1668
|
-
const ghostColor = new THREE.Color(sourceColor);
|
|
1690
|
+
const { color: ghostColor, emissive: ghostEmissive } = computeNodeMaterialProps(sourceColor);
|
|
1669
1691
|
const ghostMaterial = new THREE.MeshStandardMaterial({
|
|
1670
1692
|
color: ghostColor,
|
|
1671
|
-
emissive:
|
|
1672
|
-
emissiveIntensity,
|
|
1693
|
+
emissive: ghostEmissive,
|
|
1694
|
+
emissiveIntensity: MIN_VISIBILITY_INTENSITY,
|
|
1695
|
+
// <-- Forçamos o brilho mínimo
|
|
1673
1696
|
roughness: 0.6,
|
|
1674
1697
|
metalness: 0,
|
|
1675
1698
|
transparent: true,
|
|
@@ -2977,9 +3000,36 @@ var extractFileUrlsFromProperties = (dataObject) => {
|
|
|
2977
3000
|
});
|
|
2978
3001
|
return urlsToDelete;
|
|
2979
3002
|
};
|
|
3003
|
+
function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
|
|
3004
|
+
const [width, setWidth] = useState3(initialWidth);
|
|
3005
|
+
const [isResizing, setIsResizing] = useState3(false);
|
|
3006
|
+
const handlePointerDown = useCallback((e) => {
|
|
3007
|
+
e.preventDefault();
|
|
3008
|
+
e.stopPropagation();
|
|
3009
|
+
setIsResizing(true);
|
|
3010
|
+
const startX = e.clientX;
|
|
3011
|
+
const startWidth = width;
|
|
3012
|
+
const originalUserSelect = document.body.style.userSelect;
|
|
3013
|
+
document.body.style.userSelect = "none";
|
|
3014
|
+
const handlePointerMove = (moveEvent) => {
|
|
3015
|
+
const deltaX = startX - moveEvent.clientX;
|
|
3016
|
+
const newWidth = Math.min(Math.max(startWidth + deltaX, minWidth), maxWidth);
|
|
3017
|
+
setWidth(newWidth);
|
|
3018
|
+
};
|
|
3019
|
+
const handlePointerUp = () => {
|
|
3020
|
+
setIsResizing(false);
|
|
3021
|
+
document.body.style.userSelect = originalUserSelect;
|
|
3022
|
+
document.removeEventListener("pointermove", handlePointerMove);
|
|
3023
|
+
document.removeEventListener("pointerup", handlePointerUp);
|
|
3024
|
+
};
|
|
3025
|
+
document.addEventListener("pointermove", handlePointerMove);
|
|
3026
|
+
document.addEventListener("pointerup", handlePointerUp);
|
|
3027
|
+
}, [width, minWidth, maxWidth]);
|
|
3028
|
+
return { width, isResizing, handlePointerDown, setWidth };
|
|
3029
|
+
}
|
|
2980
3030
|
|
|
2981
3031
|
// src/components/CustomPropertyDisplay.jsx
|
|
2982
|
-
import React3, { useState as
|
|
3032
|
+
import React3, { useState as useState4, useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
2983
3033
|
import { FiCheck, FiX, FiEdit3, FiTrash2, FiExternalLink, FiFileText, FiChevronDown, FiUpload, FiLoader } from "react-icons/fi";
|
|
2984
3034
|
function CustomPropertyDisplay({
|
|
2985
3035
|
prop,
|
|
@@ -2994,12 +3044,12 @@ function CustomPropertyDisplay({
|
|
|
2994
3044
|
},
|
|
2995
3045
|
onUploadFile
|
|
2996
3046
|
}) {
|
|
2997
|
-
const [isEditing, setIsEditing] =
|
|
2998
|
-
const [tempProp, setTempProp] =
|
|
2999
|
-
const [isHovered, setIsHovered] =
|
|
3000
|
-
const [isTypeDropdownOpen, setIsTypeDropdownOpen] =
|
|
3047
|
+
const [isEditing, setIsEditing] = useState4(prop.isEditing ?? false);
|
|
3048
|
+
const [tempProp, setTempProp] = useState4(prop);
|
|
3049
|
+
const [isHovered, setIsHovered] = useState4(false);
|
|
3050
|
+
const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState4(false);
|
|
3001
3051
|
const dropdownRef = useRef3(null);
|
|
3002
|
-
const [uploadingItemIndex, setUploadingItemIndex] =
|
|
3052
|
+
const [uploadingItemIndex, setUploadingItemIndex] = useState4(null);
|
|
3003
3053
|
const fileInputRef = useRef3(null);
|
|
3004
3054
|
const currentUploadTargetRef = useRef3(null);
|
|
3005
3055
|
useEffect3(() => {
|
|
@@ -3122,8 +3172,8 @@ function CustomPropertyDisplay({
|
|
|
3122
3172
|
const availableOptions = [
|
|
3123
3173
|
{ value: "links", label: "Links", unique: true },
|
|
3124
3174
|
{ value: "images", label: "Images", unique: true },
|
|
3125
|
-
{ value: "documents", label: "Documents", unique: true },
|
|
3126
3175
|
{ value: "date", label: "Data", unique: true },
|
|
3176
|
+
{ value: "documents", label: "Documents", unique: true },
|
|
3127
3177
|
{ value: "text", label: "Texto", unique: false },
|
|
3128
3178
|
{ value: "number", label: "N\xFAmero", unique: false },
|
|
3129
3179
|
{ value: "list", label: "Lista", unique: false }
|
|
@@ -3345,15 +3395,15 @@ function CustomPropertyDisplay({
|
|
|
3345
3395
|
import { FiPlus, FiEdit2 as FiEdit22, FiBookOpen } from "react-icons/fi";
|
|
3346
3396
|
|
|
3347
3397
|
// src/components/DescriptionEditModal.jsx
|
|
3348
|
-
import React5, { useState as
|
|
3349
|
-
import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage } from "react-icons/fi";
|
|
3398
|
+
import React5, { useState as useState6, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
|
|
3399
|
+
import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage, FiCheckSquare } from "react-icons/fi";
|
|
3350
3400
|
|
|
3351
3401
|
// src/components/SectionImportModal.jsx
|
|
3352
|
-
import React4, { useState as
|
|
3402
|
+
import React4, { useState as useState5, useMemo as useMemo3, useRef as useRef4, useEffect as useEffect4 } from "react";
|
|
3353
3403
|
import { FiSearch, FiLayers as FiLayers2, FiHexagon, FiClock, FiCheck as FiCheck2, FiCopy, FiTerminal, FiChevronDown as FiChevronDown2, FiChevronRight, FiDownload, FiLink } from "react-icons/fi";
|
|
3354
3404
|
var CodeBlock = ({ content, isActive, onClick }) => {
|
|
3355
|
-
const [isExpanded, setIsExpanded] =
|
|
3356
|
-
const [copied, setCopied] =
|
|
3405
|
+
const [isExpanded, setIsExpanded] = useState5(false);
|
|
3406
|
+
const [copied, setCopied] = useState5(false);
|
|
3357
3407
|
const cleanContent = content.replace(/^```|```$/g, "").trim();
|
|
3358
3408
|
const isLongCode = cleanContent.split("\n").length > 4;
|
|
3359
3409
|
const handleCopy = (e) => {
|
|
@@ -3416,12 +3466,14 @@ var formatLineContent = (line) => {
|
|
|
3416
3466
|
return /* @__PURE__ */ React4.createElement("span", { className: "break-words" }, line);
|
|
3417
3467
|
};
|
|
3418
3468
|
function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], availableAncestries = [] }) {
|
|
3419
|
-
const [searchTerm, setSearchTerm] =
|
|
3420
|
-
const [selectedItem, setSelectedItem] =
|
|
3421
|
-
const [searchHistory, setSearchHistory] =
|
|
3422
|
-
const [activeIndex, setActiveIndex] =
|
|
3469
|
+
const [searchTerm, setSearchTerm] = useState5("");
|
|
3470
|
+
const [selectedItem, setSelectedItem] = useState5(null);
|
|
3471
|
+
const [searchHistory, setSearchHistory] = useState5([]);
|
|
3472
|
+
const [activeIndex, setActiveIndex] = useState5(0);
|
|
3473
|
+
const [selectedIndices, setSelectedIndices] = useState5(/* @__PURE__ */ new Set([0]));
|
|
3474
|
+
const [lastSelectedIndex, setLastSelectedIndex] = useState5(0);
|
|
3423
3475
|
const sectionRefs = useRef4([]);
|
|
3424
|
-
const [isDropdownOpen, setIsDropdownOpen] =
|
|
3476
|
+
const [isDropdownOpen, setIsDropdownOpen] = useState5(false);
|
|
3425
3477
|
const inputRef = useRef4(null);
|
|
3426
3478
|
useEffect4(() => {
|
|
3427
3479
|
if (!selectedItem) return;
|
|
@@ -3468,6 +3520,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3468
3520
|
}, [selectedItem]);
|
|
3469
3521
|
useEffect4(() => {
|
|
3470
3522
|
setActiveIndex(0);
|
|
3523
|
+
setSelectedIndices(/* @__PURE__ */ new Set([0]));
|
|
3524
|
+
setLastSelectedIndex(0);
|
|
3471
3525
|
}, [selectedItem]);
|
|
3472
3526
|
useEffect4(() => {
|
|
3473
3527
|
if (selectedItem && sectionRefs.current[activeIndex]) {
|
|
@@ -3484,22 +3538,64 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3484
3538
|
if (document.activeElement === inputRef.current) return;
|
|
3485
3539
|
if (e.key === "ArrowDown" || e.key === "ArrowRight") {
|
|
3486
3540
|
e.preventDefault();
|
|
3487
|
-
setActiveIndex((prev) =>
|
|
3541
|
+
setActiveIndex((prev) => {
|
|
3542
|
+
const next = Math.min(prev + 1, itemSections.length - 1);
|
|
3543
|
+
if (e.shiftKey) {
|
|
3544
|
+
setSelectedIndices((old) => /* @__PURE__ */ new Set([...old, next]));
|
|
3545
|
+
} else if (!e.ctrlKey && !e.metaKey) {
|
|
3546
|
+
setSelectedIndices(/* @__PURE__ */ new Set([next]));
|
|
3547
|
+
setLastSelectedIndex(next);
|
|
3548
|
+
}
|
|
3549
|
+
return next;
|
|
3550
|
+
});
|
|
3488
3551
|
}
|
|
3489
3552
|
if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
|
|
3490
3553
|
e.preventDefault();
|
|
3491
|
-
setActiveIndex((prev) =>
|
|
3554
|
+
setActiveIndex((prev) => {
|
|
3555
|
+
const next = Math.max(prev - 1, 0);
|
|
3556
|
+
if (e.shiftKey) {
|
|
3557
|
+
setSelectedIndices((old) => /* @__PURE__ */ new Set([...old, next]));
|
|
3558
|
+
} else if (!e.ctrlKey && !e.metaKey) {
|
|
3559
|
+
setSelectedIndices(/* @__PURE__ */ new Set([next]));
|
|
3560
|
+
setLastSelectedIndex(next);
|
|
3561
|
+
}
|
|
3562
|
+
return next;
|
|
3563
|
+
});
|
|
3492
3564
|
}
|
|
3493
3565
|
if (e.key === "Enter") {
|
|
3494
3566
|
e.preventDefault();
|
|
3495
|
-
|
|
3496
|
-
handleConfirmImport(itemSections[activeIndex]);
|
|
3497
|
-
}
|
|
3567
|
+
handleConfirmImport();
|
|
3498
3568
|
}
|
|
3499
3569
|
};
|
|
3500
3570
|
window.addEventListener("keydown", handleKeyDown);
|
|
3501
3571
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
3502
|
-
}, [itemSections,
|
|
3572
|
+
}, [itemSections, selectedItem]);
|
|
3573
|
+
const handleSectionClick = (index, e) => {
|
|
3574
|
+
e.stopPropagation();
|
|
3575
|
+
if (e.shiftKey && lastSelectedIndex !== null) {
|
|
3576
|
+
const start = Math.min(lastSelectedIndex, index);
|
|
3577
|
+
const end = Math.max(lastSelectedIndex, index);
|
|
3578
|
+
const newSelection = new Set(selectedIndices);
|
|
3579
|
+
for (let i = start; i <= end; i++) {
|
|
3580
|
+
newSelection.add(i);
|
|
3581
|
+
}
|
|
3582
|
+
setSelectedIndices(newSelection);
|
|
3583
|
+
} else if (e.ctrlKey || e.metaKey) {
|
|
3584
|
+
const newSelection = new Set(selectedIndices);
|
|
3585
|
+
if (newSelection.has(index)) {
|
|
3586
|
+
newSelection.delete(index);
|
|
3587
|
+
if (newSelection.size === 0) newSelection.add(index);
|
|
3588
|
+
} else {
|
|
3589
|
+
newSelection.add(index);
|
|
3590
|
+
}
|
|
3591
|
+
setSelectedIndices(newSelection);
|
|
3592
|
+
setLastSelectedIndex(index);
|
|
3593
|
+
} else {
|
|
3594
|
+
setSelectedIndices(/* @__PURE__ */ new Set([index]));
|
|
3595
|
+
setLastSelectedIndex(index);
|
|
3596
|
+
}
|
|
3597
|
+
setActiveIndex(index);
|
|
3598
|
+
};
|
|
3503
3599
|
const handleSelectItem = (item) => {
|
|
3504
3600
|
setSelectedItem(item);
|
|
3505
3601
|
setSearchHistory((prev) => {
|
|
@@ -3513,16 +3609,22 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3513
3609
|
setSearchTerm("");
|
|
3514
3610
|
setIsDropdownOpen(false);
|
|
3515
3611
|
};
|
|
3516
|
-
const handleConfirmImport = (
|
|
3517
|
-
|
|
3518
|
-
if (!section) return;
|
|
3612
|
+
const handleConfirmImport = () => {
|
|
3613
|
+
if (selectedIndices.size === 0) return;
|
|
3519
3614
|
const type = selectedItem._type;
|
|
3520
3615
|
const itemId = selectedItem.id || selectedItem.ancestry_id;
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3616
|
+
const indicesToImport = Array.from(selectedIndices).sort((a, b) => a - b);
|
|
3617
|
+
const tagsToImport = [];
|
|
3618
|
+
indicesToImport.forEach((idx) => {
|
|
3619
|
+
const section = itemSections[idx];
|
|
3620
|
+
if (section && section.id) {
|
|
3621
|
+
tagsToImport.push(`[[REF:${type}:${itemId}:${section.id}]]`);
|
|
3622
|
+
}
|
|
3623
|
+
});
|
|
3624
|
+
if (tagsToImport.length > 0) {
|
|
3625
|
+
onSelect(tagsToImport);
|
|
3524
3626
|
} else {
|
|
3525
|
-
alert("
|
|
3627
|
+
alert("Nenhuma se\xE7\xE3o v\xE1lida selecionada.");
|
|
3526
3628
|
}
|
|
3527
3629
|
};
|
|
3528
3630
|
const renderSectionContent = (content) => {
|
|
@@ -3593,7 +3695,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3593
3695
|
/* @__PURE__ */ React4.createElement("div", { className: "truncate" }, /* @__PURE__ */ React4.createElement("div", { className: "text-sm font-medium text-slate-200 truncate" }, item.name), /* @__PURE__ */ React4.createElement("div", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, isNode ? ((_a = item.version_node) == null ? void 0 : _a.is_version) ? "Vers\xE3o" : "Node" : "Ancestralidade"))
|
|
3594
3696
|
);
|
|
3595
3697
|
}))), /* @__PURE__ */ React4.createElement("div", { className: "flex-1 flex flex-col bg-black/20 relative z-10" }, selectedItem ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 pr-8" }, /* @__PURE__ */ React4.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap" }, itemSections.map((section, index) => {
|
|
3596
|
-
const
|
|
3698
|
+
const isSelected = selectedIndices.has(index);
|
|
3699
|
+
const isFocused = index === activeIndex;
|
|
3597
3700
|
const match = section.content.match(/^(\s*)([\s\S]*?)(\s*)$/);
|
|
3598
3701
|
let leadingSpace = match ? match[1] : "";
|
|
3599
3702
|
const bodyText = match ? match[2] : section.content;
|
|
@@ -3611,10 +3714,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3611
3714
|
refAssigned = true;
|
|
3612
3715
|
}
|
|
3613
3716
|
},
|
|
3614
|
-
onClick: () =>
|
|
3717
|
+
onClick: (e) => handleSectionClick(index, e),
|
|
3615
3718
|
className: `
|
|
3616
3719
|
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
|
|
3617
|
-
${
|
|
3720
|
+
${isSelected ? "bg-indigo-500/30 ring-1 ring-indigo-500/50" : "hover:bg-white/5"}
|
|
3721
|
+
${isFocused && !isSelected ? "ring-1 ring-white/20" : ""}
|
|
3618
3722
|
`
|
|
3619
3723
|
},
|
|
3620
3724
|
renderSectionContent(bodyText)
|
|
@@ -3635,8 +3739,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3635
3739
|
CodeBlock,
|
|
3636
3740
|
{
|
|
3637
3741
|
content: part,
|
|
3638
|
-
isActive,
|
|
3639
|
-
onClick: () =>
|
|
3742
|
+
isActive: isSelected,
|
|
3743
|
+
onClick: (e) => handleSectionClick(index, e)
|
|
3640
3744
|
}
|
|
3641
3745
|
)
|
|
3642
3746
|
);
|
|
@@ -3646,7 +3750,7 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3646
3750
|
const isLastLine = lineIndex === lines.length - 1;
|
|
3647
3751
|
const isEmptyLine = line.trim() === "";
|
|
3648
3752
|
if (isEmptyLine) {
|
|
3649
|
-
return /* @__PURE__ */ React4.createElement(
|
|
3753
|
+
return /* @__PURE__ */ React4.createElement("br", { key: `${index}-${partIndex}-${lineIndex}` });
|
|
3650
3754
|
}
|
|
3651
3755
|
return /* @__PURE__ */ React4.createElement(React4.Fragment, { key: `${index}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React4.createElement(
|
|
3652
3756
|
"span",
|
|
@@ -3657,10 +3761,11 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3657
3761
|
refAssigned = true;
|
|
3658
3762
|
}
|
|
3659
3763
|
},
|
|
3660
|
-
onClick: () =>
|
|
3764
|
+
onClick: (e) => handleSectionClick(index, e),
|
|
3661
3765
|
className: `
|
|
3662
|
-
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
|
|
3663
|
-
${
|
|
3766
|
+
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone select-none
|
|
3767
|
+
${isSelected ? "bg-indigo-500/30 text-white ring-1 ring-indigo-500/50 shadow-sm" : "hover:bg-white/5 hover:text-slate-200"}
|
|
3768
|
+
${isFocused && !isSelected ? "ring-1 ring-white/20" : ""}
|
|
3664
3769
|
`
|
|
3665
3770
|
},
|
|
3666
3771
|
formatLineContent(line)
|
|
@@ -3674,7 +3779,8 @@ function SectionImportModal({ isOpen, onClose, onSelect, availableNodes = [], av
|
|
|
3674
3779
|
className: "flex items-center gap-2 px-6 py-2.5 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-semibold rounded-lg shadow-lg shadow-indigo-500/20 transition-all transform active:scale-95"
|
|
3675
3780
|
},
|
|
3676
3781
|
/* @__PURE__ */ React4.createElement(FiDownload, { className: "text-indigo-200" }),
|
|
3677
|
-
"Importar
|
|
3782
|
+
"Importar ",
|
|
3783
|
+
selectedIndices.size > 1 ? `${selectedIndices.size} Se\xE7\xF5es` : "Se\xE7\xE3o"
|
|
3678
3784
|
))) : /* @__PURE__ */ React4.createElement("div", { className: "flex-1 flex flex-col items-center justify-center text-slate-500" }, /* @__PURE__ */ React4.createElement("div", { className: "w-16 h-16 rounded-full bg-white/5 flex items-center justify-center mb-4" }, /* @__PURE__ */ React4.createElement(FiSearch, { size: 24, className: "opacity-50" })), /* @__PURE__ */ React4.createElement("p", null, "Selecione um item \xE0 esquerda para visualizar suas se\xE7\xF5es."))))
|
|
3679
3785
|
));
|
|
3680
3786
|
}
|
|
@@ -3706,16 +3812,22 @@ function DescriptionEditModal({
|
|
|
3706
3812
|
availableAncestries = [],
|
|
3707
3813
|
availableImages = []
|
|
3708
3814
|
}) {
|
|
3709
|
-
const
|
|
3815
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.9 : 1200;
|
|
3816
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize } = useResizablePanel({
|
|
3817
|
+
initialWidth: 700,
|
|
3818
|
+
minWidth: 400,
|
|
3819
|
+
maxWidth: maxPanelW
|
|
3820
|
+
});
|
|
3821
|
+
const [text, setText] = useState6(initialValue || "");
|
|
3710
3822
|
const textareaRef = useRef5(null);
|
|
3711
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
3712
|
-
const [isMentionModalOpen, setIsMentionModalOpen] =
|
|
3713
|
-
const [mentionSearch, setMentionSearch] =
|
|
3714
|
-
const [mentionTriggerIndex, setMentionTriggerIndex] =
|
|
3715
|
-
const [isImageModalOpen, setIsImageModalOpen] =
|
|
3716
|
-
const [manualImageUrl, setManualImageUrl] =
|
|
3823
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState6(false);
|
|
3824
|
+
const [isMentionModalOpen, setIsMentionModalOpen] = useState6(false);
|
|
3825
|
+
const [mentionSearch, setMentionSearch] = useState6("");
|
|
3826
|
+
const [mentionTriggerIndex, setMentionTriggerIndex] = useState6(null);
|
|
3827
|
+
const [isImageModalOpen, setIsImageModalOpen] = useState6(false);
|
|
3828
|
+
const [manualImageUrl, setManualImageUrl] = useState6("");
|
|
3717
3829
|
const hoverTimeoutRef = useRef5(null);
|
|
3718
|
-
const [tooltipData, setTooltipData] =
|
|
3830
|
+
const [tooltipData, setTooltipData] = useState6(null);
|
|
3719
3831
|
useEffect5(() => {
|
|
3720
3832
|
const handleKeyDown = (e) => {
|
|
3721
3833
|
if (e.key === "Escape") {
|
|
@@ -3723,6 +3835,7 @@ function DescriptionEditModal({
|
|
|
3723
3835
|
e.preventDefault();
|
|
3724
3836
|
e.stopPropagation();
|
|
3725
3837
|
e.stopImmediatePropagation();
|
|
3838
|
+
if (hoverTimeoutRef.current) clearTimeout(hoverTimeoutRef.current);
|
|
3726
3839
|
setIsMentionModalOpen(false);
|
|
3727
3840
|
setMentionTriggerIndex(null);
|
|
3728
3841
|
setTooltipData(null);
|
|
@@ -3807,15 +3920,32 @@ function DescriptionEditModal({
|
|
|
3807
3920
|
const uniqueSuffix = v4_default().slice(0, 4);
|
|
3808
3921
|
insertAtCursor(`*/${nextNum}:${uniqueSuffix}/ `);
|
|
3809
3922
|
};
|
|
3810
|
-
const handleImportSelect = (
|
|
3811
|
-
const
|
|
3812
|
-
const
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3923
|
+
const handleImportSelect = (tags) => {
|
|
3924
|
+
const tagsArray = Array.isArray(tags) ? tags : [tags];
|
|
3925
|
+
const el = textareaRef.current;
|
|
3926
|
+
if (!el) return;
|
|
3927
|
+
let currentText = text;
|
|
3928
|
+
let currentNum = getNextSectionNumber(currentText);
|
|
3929
|
+
let blockToInsert = "";
|
|
3930
|
+
tagsArray.forEach((tag) => {
|
|
3931
|
+
const uniqueSuffix = v4_default().slice(0, 4);
|
|
3932
|
+
blockToInsert += `
|
|
3933
|
+
*/${currentNum}:${uniqueSuffix}/ ${tag}
|
|
3934
|
+
`;
|
|
3935
|
+
currentNum++;
|
|
3936
|
+
});
|
|
3937
|
+
const start = el.selectionStart;
|
|
3938
|
+
const end = el.selectionEnd;
|
|
3939
|
+
const newText = currentText.substring(0, start) + blockToInsert + currentText.substring(end);
|
|
3940
|
+
el.value = newText;
|
|
3941
|
+
el.setSelectionRange(start + blockToInsert.length, start + blockToInsert.length);
|
|
3942
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3943
|
+
el.focus();
|
|
3944
|
+
setText(newText);
|
|
3816
3945
|
setIsImportModalOpen(false);
|
|
3817
3946
|
};
|
|
3818
3947
|
const handleMentionSelect = (node) => {
|
|
3948
|
+
if (hoverTimeoutRef.current) clearTimeout(hoverTimeoutRef.current);
|
|
3819
3949
|
const tag = `[[MENTION:node:${node.id}]]`;
|
|
3820
3950
|
const el = textareaRef.current;
|
|
3821
3951
|
if (mentionTriggerIndex !== null && el) {
|
|
@@ -3856,7 +3986,8 @@ function DescriptionEditModal({
|
|
|
3856
3986
|
return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement("div", { className: "fixed inset-0 z-[2000] flex justify-end pointer-events-none bg-transparent" }, /* @__PURE__ */ React5.createElement(
|
|
3857
3987
|
"div",
|
|
3858
3988
|
{
|
|
3859
|
-
className:
|
|
3989
|
+
className: `ui-overlay pointer-events-auto relative group h-full border-l border-white/10 bg-slate-950/95 shadow-2xl text-white flex flex-col ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
3990
|
+
style: { width: `${panelWidth}px`, maxWidth: "90vw" },
|
|
3860
3991
|
onClick: swallow,
|
|
3861
3992
|
onPointerDown: swallow,
|
|
3862
3993
|
onPointerMove: swallow,
|
|
@@ -3865,6 +3996,17 @@ function DescriptionEditModal({
|
|
|
3865
3996
|
onContextMenu: swallow,
|
|
3866
3997
|
onDoubleClick: swallow
|
|
3867
3998
|
},
|
|
3999
|
+
/* @__PURE__ */ React5.createElement(
|
|
4000
|
+
"div",
|
|
4001
|
+
{
|
|
4002
|
+
onPointerDown: (e) => {
|
|
4003
|
+
e.stopPropagation();
|
|
4004
|
+
handleResize(e);
|
|
4005
|
+
},
|
|
4006
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
4007
|
+
title: "Arraste para redimensionar"
|
|
4008
|
+
}
|
|
4009
|
+
),
|
|
3868
4010
|
/* @__PURE__ */ React5.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 shrink-0" }),
|
|
3869
4011
|
/* @__PURE__ */ React5.createElement("div", { className: "px-6 pt-5 pb-3 flex items-center justify-between gap-4 shrink-0" }, /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React5.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80" }), /* @__PURE__ */ React5.createElement("p", { className: "text-sm font-medium text-slate-200" }, title || "Editar Descri\xE7\xE3o")), /* @__PURE__ */ React5.createElement("button", { onClick: handleClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")),
|
|
3870
4012
|
/* @__PURE__ */ React5.createElement("div", { className: "px-6 py-3 flex flex-col gap-3 border-b border-white/5 bg-white/5 shrink-0" }, /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2 overflow-x-auto custom-scrollbar" }, /* @__PURE__ */ React5.createElement(
|
|
@@ -3894,6 +4036,24 @@ function DescriptionEditModal({
|
|
|
3894
4036
|
},
|
|
3895
4037
|
/* @__PURE__ */ React5.createElement(FiList, { size: 12 }),
|
|
3896
4038
|
" Lista"
|
|
4039
|
+
), /* @__PURE__ */ React5.createElement(
|
|
4040
|
+
"button",
|
|
4041
|
+
{
|
|
4042
|
+
onClick: () => insertAtCursor("1. "),
|
|
4043
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
|
|
4044
|
+
title: "Lista Numerada"
|
|
4045
|
+
},
|
|
4046
|
+
/* @__PURE__ */ React5.createElement("span", { className: "text-[10px] font-bold" }, "1."),
|
|
4047
|
+
" Numerada"
|
|
4048
|
+
), /* @__PURE__ */ React5.createElement(
|
|
4049
|
+
"button",
|
|
4050
|
+
{
|
|
4051
|
+
onClick: () => insertAtCursor("- [ ] "),
|
|
4052
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
|
|
4053
|
+
title: "Checklist (Checkbox)"
|
|
4054
|
+
},
|
|
4055
|
+
/* @__PURE__ */ React5.createElement(FiCheckSquare, { size: 12 }),
|
|
4056
|
+
" Checklist"
|
|
3897
4057
|
), /* @__PURE__ */ React5.createElement(
|
|
3898
4058
|
"button",
|
|
3899
4059
|
{
|
|
@@ -4029,7 +4189,7 @@ function DescriptionEditModal({
|
|
|
4029
4189
|
className: "px-3 py-1.5 bg-indigo-600/30 hover:bg-indigo-600 text-indigo-200 text-xs rounded-lg transition-colors disabled:opacity-50"
|
|
4030
4190
|
},
|
|
4031
4191
|
"OK"
|
|
4032
|
-
))), /* @__PURE__ */ React5.createElement("div", { className: "p-2 border-t border-white/10 bg-slate-950/50 flex justify-end" }, /* @__PURE__ */ React5.createElement("button", { onClick: () => setIsImageModalOpen(false), className: "px-3 py-1.5 text-xs text-slate-400 hover:text-white transition-colors" }, "Cancelar"))))
|
|
4192
|
+
))), /* @__PURE__ */ React5.createElement("div", { className: "p-2 border-t border-white/10 bg-slate-950/50 flex justify-end" }, /* @__PURE__ */ React5.createElement("button", { onClick: () => setIsImageModalOpen(false), className: "px-3 py-1.5 text-xs text-slate-400 hover:text-white transition-colors" }, "Cancelar"))))),
|
|
4033
4193
|
/* @__PURE__ */ React5.createElement("div", { className: "sticky bottom-0 z-10 bg-slate-950/95 border-t border-white/10 px-6 py-4 flex justify-end gap-3 shrink-0" }, /* @__PURE__ */ React5.createElement("button", { onClick: handleSave, className: "px-6 py-2 rounded-lg bg-gradient-to-tr from-indigo-600 to-indigo-400 hover:from-indigo-500 hover:to-indigo-300 transition-colors font-semibold text-sm shadow-[0_8px_24px_rgba(99,102,241,0.35)]" }, "Salvar"))
|
|
4034
4194
|
)), tooltipData && /* @__PURE__ */ React5.createElement(
|
|
4035
4195
|
"div",
|
|
@@ -4056,11 +4216,11 @@ function DescriptionEditModal({
|
|
|
4056
4216
|
}
|
|
4057
4217
|
|
|
4058
4218
|
// src/components/DescriptionDisplay.jsx
|
|
4059
|
-
import React6, { useMemo as useMemo5, useState as
|
|
4060
|
-
import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2 } from "react-icons/fi";
|
|
4219
|
+
import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
|
|
4220
|
+
import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2, FiSave } from "react-icons/fi";
|
|
4061
4221
|
var CodeBlock2 = ({ content, isActive, onClick }) => {
|
|
4062
|
-
const [isExpanded, setIsExpanded] =
|
|
4063
|
-
const [copied, setCopied] =
|
|
4222
|
+
const [isExpanded, setIsExpanded] = useState7(false);
|
|
4223
|
+
const [copied, setCopied] = useState7(false);
|
|
4064
4224
|
const cleanContent = content.replace(/^```|```$/g, "").trim();
|
|
4065
4225
|
const isLongCode = cleanContent.split("\n").length > 4;
|
|
4066
4226
|
const handleCopy = (e) => {
|
|
@@ -4200,7 +4360,7 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
|
|
|
4200
4360
|
);
|
|
4201
4361
|
});
|
|
4202
4362
|
};
|
|
4203
|
-
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
|
|
4363
|
+
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
|
|
4204
4364
|
const trimmedLine = line.replace(/\r$/, "");
|
|
4205
4365
|
const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
|
|
4206
4366
|
if (line.startsWith("# ")) {
|
|
@@ -4211,9 +4371,46 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
|
|
|
4211
4371
|
const content = line.replace("## ", "");
|
|
4212
4372
|
return /* @__PURE__ */ React6.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
|
|
4213
4373
|
}
|
|
4374
|
+
const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
|
|
4375
|
+
if (checkboxMatch) {
|
|
4376
|
+
const [_, space, state, content] = checkboxMatch;
|
|
4377
|
+
const isChecked = state.toLowerCase() === "x";
|
|
4378
|
+
const currentIdx = globalCheckboxCounterRef.current;
|
|
4379
|
+
globalCheckboxCounterRef.current += 1;
|
|
4380
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1 group/checkbox" }, /* @__PURE__ */ React6.createElement(
|
|
4381
|
+
"div",
|
|
4382
|
+
{
|
|
4383
|
+
onClick: (e) => {
|
|
4384
|
+
e.stopPropagation();
|
|
4385
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4386
|
+
},
|
|
4387
|
+
className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
|
|
4388
|
+
${isChecked ? "bg-indigo-500 border-indigo-500 shadow-[0_0_8px_rgba(99,102,241,0.4)]" : "border-slate-500 bg-slate-900/50 hover:border-slate-400 group-hover/checkbox:border-slate-400"}
|
|
4389
|
+
`
|
|
4390
|
+
},
|
|
4391
|
+
isChecked && /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-white" })
|
|
4392
|
+
), /* @__PURE__ */ React6.createElement(
|
|
4393
|
+
"span",
|
|
4394
|
+
{
|
|
4395
|
+
className: `transition-all duration-200 cursor-pointer pt-[1px]
|
|
4396
|
+
${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
|
|
4397
|
+
`,
|
|
4398
|
+
onClick: (e) => {
|
|
4399
|
+
e.stopPropagation();
|
|
4400
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4401
|
+
}
|
|
4402
|
+
},
|
|
4403
|
+
processContent(content)
|
|
4404
|
+
));
|
|
4405
|
+
}
|
|
4406
|
+
const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
|
|
4407
|
+
if (numberMatch) {
|
|
4408
|
+
const [_, space, numberStr, content] = numberMatch;
|
|
4409
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-mono font-bold text-xs mt-[3px] shrink-0" }, numberStr), /* @__PURE__ */ React6.createElement("span", { className: "text-slate-200" }, processContent(content)));
|
|
4410
|
+
}
|
|
4214
4411
|
if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
|
|
4215
4412
|
const content = trimmedLine.trim().substring(2);
|
|
4216
|
-
return /* @__PURE__ */ React6.createElement("span", { className: "
|
|
4413
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1 text-slate-200" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-bold shrink-0 mt-[2px] text-xs" }, "\u2022"), /* @__PURE__ */ React6.createElement("span", null, processContent(content)));
|
|
4217
4414
|
}
|
|
4218
4415
|
return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
|
|
4219
4416
|
};
|
|
@@ -4225,14 +4422,31 @@ function DescriptionDisplay({
|
|
|
4225
4422
|
onOpenReference,
|
|
4226
4423
|
onMentionClick,
|
|
4227
4424
|
onImageClick,
|
|
4228
|
-
// <--- NOVA PROP RECEBIDA
|
|
4229
4425
|
onSectionChange,
|
|
4230
4426
|
onBranchNav,
|
|
4231
4427
|
onHighlightNode,
|
|
4232
4428
|
initialSectionId,
|
|
4233
|
-
currentBranchDirection = null
|
|
4429
|
+
currentBranchDirection = null,
|
|
4430
|
+
onSaveDescription
|
|
4234
4431
|
}) {
|
|
4235
|
-
const
|
|
4432
|
+
const [localDescription, setLocalDescription] = useState7(description || "");
|
|
4433
|
+
useEffect6(() => {
|
|
4434
|
+
setLocalDescription(description || "");
|
|
4435
|
+
}, [description]);
|
|
4436
|
+
const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
|
|
4437
|
+
const globalCheckboxCounterRef = useRef6(0);
|
|
4438
|
+
const handleToggleCheckbox = (targetIndex) => {
|
|
4439
|
+
let currentIndex = 0;
|
|
4440
|
+
const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
|
|
4441
|
+
if (currentIndex === targetIndex) {
|
|
4442
|
+
currentIndex++;
|
|
4443
|
+
return state === " " ? `${space}- [x]` : `${space}- [ ]`;
|
|
4444
|
+
}
|
|
4445
|
+
currentIndex++;
|
|
4446
|
+
return match;
|
|
4447
|
+
});
|
|
4448
|
+
setLocalDescription(newDesc);
|
|
4449
|
+
};
|
|
4236
4450
|
const flatNavigation = useMemo5(() => {
|
|
4237
4451
|
const navItems = [];
|
|
4238
4452
|
sections.forEach((section, sIdx) => {
|
|
@@ -4259,7 +4473,7 @@ function DescriptionDisplay({
|
|
|
4259
4473
|
});
|
|
4260
4474
|
return navItems;
|
|
4261
4475
|
}, [sections]);
|
|
4262
|
-
const [currentStepIndex, setCurrentStepIndex] =
|
|
4476
|
+
const [currentStepIndex, setCurrentStepIndex] = useState7(0);
|
|
4263
4477
|
const activeRef = useRef6(null);
|
|
4264
4478
|
const lastNotifiedSectionId = useRef6(null);
|
|
4265
4479
|
const isInitialMount = useRef6(true);
|
|
@@ -4373,26 +4587,27 @@ function DescriptionDisplay({
|
|
|
4373
4587
|
}
|
|
4374
4588
|
const lines = part.replace(/\n$/, "").split("\n");
|
|
4375
4589
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
|
|
4376
|
-
const isLastLine = lineIndex === lines.length - 1;
|
|
4377
4590
|
const isEmptyLine = line.trim() === "";
|
|
4378
4591
|
if (isEmptyLine) {
|
|
4379
4592
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
|
|
4380
4593
|
}
|
|
4381
4594
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
|
|
4382
|
-
"
|
|
4595
|
+
"div",
|
|
4383
4596
|
{
|
|
4384
4597
|
ref: isActiveSection && activeMentionIndex === -1 && partIndex === 0 && lineIndex === 0 ? setRef : null,
|
|
4385
|
-
onClick: () => {
|
|
4386
|
-
|
|
4387
|
-
|
|
4598
|
+
onClick: (e) => {
|
|
4599
|
+
if (e.target.type !== "checkbox") {
|
|
4600
|
+
const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
|
|
4601
|
+
if (idx !== -1) setCurrentStepIndex(idx);
|
|
4602
|
+
}
|
|
4388
4603
|
},
|
|
4389
4604
|
className: `
|
|
4390
|
-
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
|
|
4391
|
-
${isActiveSection ? "bg-indigo-500/
|
|
4605
|
+
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
|
|
4606
|
+
${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
|
|
4392
4607
|
`
|
|
4393
4608
|
},
|
|
4394
|
-
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
|
|
4395
|
-
)
|
|
4609
|
+
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
|
|
4610
|
+
));
|
|
4396
4611
|
}));
|
|
4397
4612
|
});
|
|
4398
4613
|
};
|
|
@@ -4420,7 +4635,9 @@ function DescriptionDisplay({
|
|
|
4420
4635
|
${isActiveSection ? "opacity-100" : "opacity-90"}
|
|
4421
4636
|
` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
|
|
4422
4637
|
};
|
|
4423
|
-
|
|
4638
|
+
globalCheckboxCounterRef.current = 0;
|
|
4639
|
+
const hasUnsavedChanges = localDescription !== (description || "");
|
|
4640
|
+
return /* @__PURE__ */ React6.createElement("div", { className: "relative w-full h-full min-h-[100px]" }, /* @__PURE__ */ React6.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-16 pr-9" }, sections.map((section, index) => {
|
|
4424
4641
|
const currentNavItem = flatNavigation[currentStepIndex];
|
|
4425
4642
|
const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
|
|
4426
4643
|
const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
|
|
@@ -4436,11 +4653,22 @@ function DescriptionDisplay({
|
|
|
4436
4653
|
if (index === 0) leadingSpace = "";
|
|
4437
4654
|
const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
|
|
4438
4655
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: index }, /* @__PURE__ */ React6.createElement("span", null, leadingSpace), isRef ? renderReferenceSection(bodyText, index, isSectionContextActive, setRef) : renderMixedContent(bodyText, index, isSectionContextActive, activeMentionIndex, setRef), /* @__PURE__ */ React6.createElement("span", null, trailingSpace));
|
|
4439
|
-
}))
|
|
4656
|
+
})), hasUnsavedChanges && onSaveDescription && /* @__PURE__ */ React6.createElement("div", { className: "absolute bottom-2 left-2 z-[100] animate-in slide-in-from-bottom-2 fade-in duration-300" }, /* @__PURE__ */ React6.createElement(
|
|
4657
|
+
"button",
|
|
4658
|
+
{
|
|
4659
|
+
onClick: (e) => {
|
|
4660
|
+
e.stopPropagation();
|
|
4661
|
+
onSaveDescription(localDescription);
|
|
4662
|
+
},
|
|
4663
|
+
className: "flex items-center gap-1.5 px-3 py-1.5 bg-indigo-600/90 hover:bg-indigo-500 text-white rounded-md shadow-[0_4px_12px_rgba(99,102,241,0.3)] text-xs font-medium transition-all hover:scale-105 active:scale-95 border border-indigo-400/20 backdrop-blur-sm"
|
|
4664
|
+
},
|
|
4665
|
+
/* @__PURE__ */ React6.createElement(FiSave, { size: 12 }),
|
|
4666
|
+
" Salvar Checklist"
|
|
4667
|
+
)));
|
|
4440
4668
|
}
|
|
4441
4669
|
|
|
4442
4670
|
// src/components/DescriptionReadModePanel.jsx
|
|
4443
|
-
import React7, { useState as
|
|
4671
|
+
import React7, { useState as useState8, useMemo as useMemo6, useEffect as useEffect7 } from "react";
|
|
4444
4672
|
import {
|
|
4445
4673
|
FiArrowLeft,
|
|
4446
4674
|
FiEdit2,
|
|
@@ -4519,7 +4747,6 @@ function DescriptionReadModePanel({
|
|
|
4519
4747
|
title,
|
|
4520
4748
|
description,
|
|
4521
4749
|
ancestryId,
|
|
4522
|
-
// <-- NOVO: Prop recebida do XViewScene
|
|
4523
4750
|
savedSections,
|
|
4524
4751
|
onBack,
|
|
4525
4752
|
onEdit,
|
|
@@ -4541,12 +4768,13 @@ function DescriptionReadModePanel({
|
|
|
4541
4768
|
userRole,
|
|
4542
4769
|
abstractionTree = null,
|
|
4543
4770
|
onRenderAbstractionTree = null,
|
|
4544
|
-
initialShowAbstraction = false
|
|
4771
|
+
initialShowAbstraction = false,
|
|
4772
|
+
onSaveDescription
|
|
4545
4773
|
}) {
|
|
4546
|
-
const [showProperties, setShowProperties] =
|
|
4547
|
-
const [showAbstraction, setShowAbstraction] =
|
|
4548
|
-
const [targetRenderNodeId, setTargetRenderNodeId] =
|
|
4549
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
4774
|
+
const [showProperties, setShowProperties] = useState8(false);
|
|
4775
|
+
const [showAbstraction, setShowAbstraction] = useState8(false);
|
|
4776
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState8(null);
|
|
4777
|
+
const [isLinkCopied, setIsLinkCopied] = useState8(false);
|
|
4550
4778
|
const handleCopyLink = (e) => {
|
|
4551
4779
|
e.stopPropagation();
|
|
4552
4780
|
if (!ancestryId) return;
|
|
@@ -4628,7 +4856,7 @@ function DescriptionReadModePanel({
|
|
|
4628
4856
|
return /* @__PURE__ */ React7.createElement(
|
|
4629
4857
|
"div",
|
|
4630
4858
|
{
|
|
4631
|
-
className: "flex flex-col h-full w-full bg-slate-950/50 relative overflow-hidden group",
|
|
4859
|
+
className: "flex flex-col h-full max-h-full w-full bg-slate-950/50 relative overflow-hidden group min-h-0",
|
|
4632
4860
|
onPointerDown: swallow,
|
|
4633
4861
|
onClick: swallow
|
|
4634
4862
|
},
|
|
@@ -4700,7 +4928,7 @@ function DescriptionReadModePanel({
|
|
|
4700
4928
|
},
|
|
4701
4929
|
"\xD7"
|
|
4702
4930
|
))),
|
|
4703
|
-
/* @__PURE__ */ React7.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 bg-slate-900/20 relative z-10", onClick: () => setTargetRenderNodeId(null) }, showAbstraction ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4" }, /* @__PURE__ */ React7.createElement("h3", { className: "text-sm font-semibold text-purple-300 uppercase tracking-wider" }, "Explorar Hierarquia"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-wrap gap-2" }, targetRenderNodeId && onRenderAbstractionTree && /* @__PURE__ */ React7.createElement(
|
|
4931
|
+
/* @__PURE__ */ React7.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 bg-slate-900/20 relative z-10 min-h-0", onClick: () => setTargetRenderNodeId(null) }, showAbstraction ? /* @__PURE__ */ React7.createElement("div", { className: "space-y-4 animate-in fade-in slide-in-from-bottom-2 duration-300", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React7.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 mb-4" }, /* @__PURE__ */ React7.createElement("h3", { className: "text-sm font-semibold text-purple-300 uppercase tracking-wider" }, "Explorar Hierarquia"), /* @__PURE__ */ React7.createElement("div", { className: "flex flex-wrap gap-2" }, targetRenderNodeId && onRenderAbstractionTree && /* @__PURE__ */ React7.createElement(
|
|
4704
4932
|
"button",
|
|
4705
4933
|
{
|
|
4706
4934
|
onClick: (e) => {
|
|
@@ -4759,7 +4987,8 @@ function DescriptionReadModePanel({
|
|
|
4759
4987
|
onHighlightNode,
|
|
4760
4988
|
initialSectionId,
|
|
4761
4989
|
currentBranchDirection,
|
|
4762
|
-
onImageClick
|
|
4990
|
+
onImageClick,
|
|
4991
|
+
onSaveDescription
|
|
4763
4992
|
}
|
|
4764
4993
|
)),
|
|
4765
4994
|
leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
|
|
@@ -4801,11 +5030,11 @@ function AncestryRelationshipPanel({
|
|
|
4801
5030
|
onMentionClick,
|
|
4802
5031
|
onUploadFile
|
|
4803
5032
|
}) {
|
|
4804
|
-
const [description, setDescription] =
|
|
4805
|
-
const [customProps, setCustomProps] =
|
|
4806
|
-
const [existingSections, setExistingSections] =
|
|
4807
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
4808
|
-
const [isReadMode, setIsReadMode] =
|
|
5033
|
+
const [description, setDescription] = useState9((data == null ? void 0 : data.description) ?? "");
|
|
5034
|
+
const [customProps, setCustomProps] = useState9(() => extractCustomPropsFromNode(data || {}));
|
|
5035
|
+
const [existingSections, setExistingSections] = useState9((data == null ? void 0 : data.description_sections) || []);
|
|
5036
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState9(false);
|
|
5037
|
+
const [isReadMode, setIsReadMode] = useState9(false);
|
|
4809
5038
|
const propsEndRef = useRef7(null);
|
|
4810
5039
|
useEffect8(() => {
|
|
4811
5040
|
setDescription((data == null ? void 0 : data.description) ?? "");
|
|
@@ -4829,6 +5058,17 @@ function AncestryRelationshipPanel({
|
|
|
4829
5058
|
return newProps;
|
|
4830
5059
|
});
|
|
4831
5060
|
};
|
|
5061
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
5062
|
+
setDescription(newDescription);
|
|
5063
|
+
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
5064
|
+
const processedSections = processDescriptionForSave(newDescription, existingSections);
|
|
5065
|
+
const dataToSave = {
|
|
5066
|
+
description: newDescription,
|
|
5067
|
+
description_sections: processedSections,
|
|
5068
|
+
...extrasObj
|
|
5069
|
+
};
|
|
5070
|
+
onSave(dataToSave);
|
|
5071
|
+
};
|
|
4832
5072
|
const handleSave = () => {
|
|
4833
5073
|
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
4834
5074
|
const processedSections = processDescriptionForSave(description, existingSections);
|
|
@@ -4878,7 +5118,8 @@ function AncestryRelationshipPanel({
|
|
|
4878
5118
|
availableAncestries,
|
|
4879
5119
|
onOpenReference,
|
|
4880
5120
|
onMentionClick,
|
|
4881
|
-
onImageClick: handleImageClickFromText
|
|
5121
|
+
onImageClick: handleImageClickFromText,
|
|
5122
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4882
5123
|
}
|
|
4883
5124
|
) : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement("div", { className: "h-[2px] bg-gradient-to-r from-cyan-400/0 via-cyan-400/70 to-cyan-400/0" }), /* @__PURE__ */ React8.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React8.createElement("div", null, /* @__PURE__ */ React8.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React8.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-cyan-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ React8.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o de Ancestralidade")), /* @__PURE__ */ React8.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Editar Rela\xE7\xE3o")), /* @__PURE__ */ React8.createElement("button", { onClick: onClose, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")), /* @__PURE__ */ React8.createElement("div", { className: "px-6 pb-4 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React8.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React8.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o da Rela\xE7\xE3o"), /* @__PURE__ */ React8.createElement("div", { className: "relative group min-h-[60px] bg-slate-800/40 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React8.createElement(
|
|
4884
5125
|
DescriptionDisplay,
|
|
@@ -4889,7 +5130,8 @@ function AncestryRelationshipPanel({
|
|
|
4889
5130
|
availableAncestries,
|
|
4890
5131
|
onOpenReference,
|
|
4891
5132
|
onMentionClick,
|
|
4892
|
-
onImageClick: handleImageClickFromText
|
|
5133
|
+
onImageClick: handleImageClickFromText,
|
|
5134
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4893
5135
|
}
|
|
4894
5136
|
), /* @__PURE__ */ React8.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React8.createElement(
|
|
4895
5137
|
"button",
|
|
@@ -4947,7 +5189,7 @@ function AncestryRelationshipPanel({
|
|
|
4947
5189
|
}
|
|
4948
5190
|
|
|
4949
5191
|
// src/components/CreateAncestryPanel.jsx
|
|
4950
|
-
import React10, { useState as
|
|
5192
|
+
import React10, { useState as useState11, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback as useCallback2 } from "react";
|
|
4951
5193
|
import {
|
|
4952
5194
|
FiEdit2 as FiEdit23,
|
|
4953
5195
|
FiBookOpen as FiBookOpen2,
|
|
@@ -4967,7 +5209,7 @@ import {
|
|
|
4967
5209
|
} from "react-icons/fi";
|
|
4968
5210
|
|
|
4969
5211
|
// src/components/AncestryPickerModal.jsx
|
|
4970
|
-
import React9, { useState as
|
|
5212
|
+
import React9, { useState as useState10, useMemo as useMemo7, useEffect as useEffect9 } from "react";
|
|
4971
5213
|
import { FiSearch as FiSearch3, FiLayers as FiLayers4, FiCornerUpRight as FiCornerUpRight2 } from "react-icons/fi";
|
|
4972
5214
|
function AncestryPickerModal({
|
|
4973
5215
|
isOpen,
|
|
@@ -4977,7 +5219,7 @@ function AncestryPickerModal({
|
|
|
4977
5219
|
availableNodes = [],
|
|
4978
5220
|
currentAncestryId
|
|
4979
5221
|
}) {
|
|
4980
|
-
const [searchTerm, setSearchTerm] =
|
|
5222
|
+
const [searchTerm, setSearchTerm] = useState10("");
|
|
4981
5223
|
useEffect9(() => {
|
|
4982
5224
|
if (!isOpen) return;
|
|
4983
5225
|
const handleKeyDown = (e) => {
|
|
@@ -5062,7 +5304,7 @@ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [
|
|
|
5062
5304
|
var _a, _b;
|
|
5063
5305
|
const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
|
|
5064
5306
|
const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
|
|
5065
|
-
const [isDragOver, setIsDragOver] =
|
|
5307
|
+
const [isDragOver, setIsDragOver] = useState11(false);
|
|
5066
5308
|
const isSelectedParent = String(selectedParentId) === String(itemId);
|
|
5067
5309
|
const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
|
|
5068
5310
|
const isHighlightedPath = highlightedPathIds.includes(String(itemId));
|
|
@@ -5198,8 +5440,8 @@ function CreateAncestryPanel({
|
|
|
5198
5440
|
isAddingNodes,
|
|
5199
5441
|
currentAncestryId
|
|
5200
5442
|
} = ancestryMode;
|
|
5201
|
-
const [isSaving, setIsSaving] =
|
|
5202
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
5443
|
+
const [isSaving, setIsSaving] = useState11(false);
|
|
5444
|
+
const [isLinkCopied, setIsLinkCopied] = useState11(false);
|
|
5203
5445
|
const handleCopyLink = (e) => {
|
|
5204
5446
|
e.stopPropagation();
|
|
5205
5447
|
if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
|
|
@@ -5213,11 +5455,11 @@ function CreateAncestryPanel({
|
|
|
5213
5455
|
setTimeout(() => setIsLinkCopied(false), 2e3);
|
|
5214
5456
|
}).catch((err) => console.error("Erro ao copiar link:", err));
|
|
5215
5457
|
};
|
|
5216
|
-
const [isPickerOpen, setIsPickerOpen] =
|
|
5217
|
-
const [customProps, setCustomProps] =
|
|
5458
|
+
const [isPickerOpen, setIsPickerOpen] = useState11(false);
|
|
5459
|
+
const [customProps, setCustomProps] = useState11([]);
|
|
5218
5460
|
const propsEndRef = useRef8(null);
|
|
5219
|
-
const [branchStack, setBranchStack] =
|
|
5220
|
-
const [targetRenderNodeId, setTargetRenderNodeId] =
|
|
5461
|
+
const [branchStack, setBranchStack] = useState11([]);
|
|
5462
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState11(null);
|
|
5221
5463
|
const highlightedPathIds = useMemo8(() => {
|
|
5222
5464
|
var _a, _b;
|
|
5223
5465
|
if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
|
|
@@ -5231,17 +5473,27 @@ function CreateAncestryPanel({
|
|
|
5231
5473
|
}
|
|
5232
5474
|
return ids;
|
|
5233
5475
|
}, [targetRenderNodeId, ancestryMode.abstraction_tree]);
|
|
5234
|
-
const [targetScrollSectionId, setTargetScrollSectionId] =
|
|
5235
|
-
const [internalHighlightedNodeId, setInternalHighlightedNodeId] =
|
|
5236
|
-
const [ancestryName, setAncestryName] =
|
|
5237
|
-
const [description, setDescription] =
|
|
5238
|
-
const [existingSections, setExistingSections] =
|
|
5239
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
5240
|
-
const [isReadMode, setIsReadMode] =
|
|
5476
|
+
const [targetScrollSectionId, setTargetScrollSectionId] = useState11(null);
|
|
5477
|
+
const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState11(null);
|
|
5478
|
+
const [ancestryName, setAncestryName] = useState11(initialName);
|
|
5479
|
+
const [description, setDescription] = useState11(initialDescription || "");
|
|
5480
|
+
const [existingSections, setExistingSections] = useState11(initialSections || []);
|
|
5481
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState11(false);
|
|
5482
|
+
const [isReadMode, setIsReadMode] = useState11(false);
|
|
5483
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
5484
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
5485
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
5486
|
+
minWidth: 320,
|
|
5487
|
+
maxWidth: maxPanelW
|
|
5488
|
+
});
|
|
5489
|
+
useEffect10(() => {
|
|
5490
|
+
setWidth(isReadMode ? 700 : 440);
|
|
5491
|
+
}, [isReadMode, setWidth]);
|
|
5241
5492
|
const currentMaxRenderIndexRef = useRef8(0);
|
|
5242
5493
|
const branchProgressMapRef = useRef8({});
|
|
5243
|
-
const [lastSavedSnapshot, setLastSavedSnapshot] =
|
|
5244
|
-
const [isPrivate, setIsPrivate] =
|
|
5494
|
+
const [lastSavedSnapshot, setLastSavedSnapshot] = useState11(null);
|
|
5495
|
+
const [isPrivate, setIsPrivate] = useState11(ancestryMode.is_private || false);
|
|
5496
|
+
const initializedContextIdRef = useRef8(null);
|
|
5245
5497
|
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
5246
5498
|
const handleImageClickFromText = (url, name) => {
|
|
5247
5499
|
if (onOpenImageViewer) {
|
|
@@ -5259,7 +5511,7 @@ function CreateAncestryPanel({
|
|
|
5259
5511
|
}
|
|
5260
5512
|
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
5261
5513
|
};
|
|
5262
|
-
const handleRemoveNode =
|
|
5514
|
+
const handleRemoveNode = useCallback2((pathToRemove, isAbstraction = false) => {
|
|
5263
5515
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
5264
5516
|
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5265
5517
|
setAncestryMode((prev) => {
|
|
@@ -5440,6 +5692,11 @@ function CreateAncestryPanel({
|
|
|
5440
5692
|
}, [isContextLinked, branchStack]);
|
|
5441
5693
|
useEffect10(() => {
|
|
5442
5694
|
const ctx = getCurrentContext();
|
|
5695
|
+
const currentContextId = branchStack.length > 0 ? branchStack[branchStack.length - 1].branchId : ancestryMode.currentAncestryId || `new_${ancestryMode.ancestral_node}`;
|
|
5696
|
+
if (initializedContextIdRef.current === currentContextId) {
|
|
5697
|
+
return;
|
|
5698
|
+
}
|
|
5699
|
+
initializedContextIdRef.current = currentContextId;
|
|
5443
5700
|
let sourceObject = {};
|
|
5444
5701
|
if (ctx) {
|
|
5445
5702
|
sourceObject = ctx;
|
|
@@ -5790,7 +6047,7 @@ function CreateAncestryPanel({
|
|
|
5790
6047
|
const currentAbsTreeStr = JSON.stringify(ancestryMode.abstraction_tree);
|
|
5791
6048
|
abstractionTreeChanged = currentAbsTreeStr !== lastSavedSnapshot.abstractionTree;
|
|
5792
6049
|
}
|
|
5793
|
-
return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged;
|
|
6050
|
+
return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged || abstractionTreeChanged;
|
|
5794
6051
|
}, [
|
|
5795
6052
|
ancestryName,
|
|
5796
6053
|
description,
|
|
@@ -6138,6 +6395,10 @@ function CreateAncestryPanel({
|
|
|
6138
6395
|
setInternalHighlightedNodeId(id);
|
|
6139
6396
|
if (onHighlightNode) onHighlightNode(id);
|
|
6140
6397
|
};
|
|
6398
|
+
const handleSaveDescriptionInline = (newDesc) => {
|
|
6399
|
+
setDescription(newDesc);
|
|
6400
|
+
handleLocalSave(true, { description: newDesc });
|
|
6401
|
+
};
|
|
6141
6402
|
const swallow = (e) => e.stopPropagation();
|
|
6142
6403
|
const getSelectedParentName = () => {
|
|
6143
6404
|
if (!activeTree || !selectedParentId) return "";
|
|
@@ -6210,10 +6471,8 @@ function CreateAncestryPanel({
|
|
|
6210
6471
|
return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
|
|
6211
6472
|
"div",
|
|
6212
6473
|
{
|
|
6213
|
-
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 transition-all duration-300 ease-out
|
|
6214
|
-
|
|
6215
|
-
`,
|
|
6216
|
-
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" },
|
|
6474
|
+
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 ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
6475
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
6217
6476
|
onPointerDown: swallow,
|
|
6218
6477
|
onPointerMove: swallow,
|
|
6219
6478
|
onPointerUp: swallow,
|
|
@@ -6222,6 +6481,17 @@ function CreateAncestryPanel({
|
|
|
6222
6481
|
onContextMenu: swallow,
|
|
6223
6482
|
onDoubleClick: swallow
|
|
6224
6483
|
},
|
|
6484
|
+
/* @__PURE__ */ React10.createElement(
|
|
6485
|
+
"div",
|
|
6486
|
+
{
|
|
6487
|
+
onPointerDown: (e) => {
|
|
6488
|
+
e.stopPropagation();
|
|
6489
|
+
handleResize(e);
|
|
6490
|
+
},
|
|
6491
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
6492
|
+
title: "Arraste para redimensionar"
|
|
6493
|
+
}
|
|
6494
|
+
),
|
|
6225
6495
|
isReadMode ? /* @__PURE__ */ React10.createElement(
|
|
6226
6496
|
DescriptionReadModePanel,
|
|
6227
6497
|
{
|
|
@@ -6240,7 +6510,8 @@ function CreateAncestryPanel({
|
|
|
6240
6510
|
onMentionClick,
|
|
6241
6511
|
onSectionChange: handleSectionChangeWrapper,
|
|
6242
6512
|
onHighlightNode,
|
|
6243
|
-
onImageClick: handleImageClickFromText
|
|
6513
|
+
onImageClick: handleImageClickFromText,
|
|
6514
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
6244
6515
|
}
|
|
6245
6516
|
) : /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 flex-shrink-0" }), /* @__PURE__ */ React10.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4 flex-shrink-0" }, /* @__PURE__ */ React10.createElement("div", { className: "w-full" }, /* @__PURE__ */ React10.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React10.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ React10.createElement("p", { className: "text-xs/relaxed text-slate-300" }, branchStack.length > 0 ? `Ramifica\xE7\xE3o (N\xEDvel ${branchStack.length})` : isEditMode ? "Editar Ancestralidade" : "Criar Ancestralidade"), currentAncestryId && currentAncestryId !== "temp_creating" && currentAncestryId !== "temp_root" && /* @__PURE__ */ React10.createElement(
|
|
6246
6517
|
"button",
|
|
@@ -6297,7 +6568,8 @@ function CreateAncestryPanel({
|
|
|
6297
6568
|
onHighlightNode: handleHighlightWrapper,
|
|
6298
6569
|
initialSectionId: targetScrollSectionId,
|
|
6299
6570
|
currentBranchDirection: currentContext ? currentContext.direction : null,
|
|
6300
|
-
onImageClick: handleImageClickFromText
|
|
6571
|
+
onImageClick: handleImageClickFromText,
|
|
6572
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
6301
6573
|
}
|
|
6302
6574
|
), /* @__PURE__ */ React10.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5 z-30" }, /* @__PURE__ */ React10.createElement(
|
|
6303
6575
|
"button",
|
|
@@ -6518,25 +6790,25 @@ function CreateAncestryPanel({
|
|
|
6518
6790
|
}
|
|
6519
6791
|
|
|
6520
6792
|
// src/components/ImageViewer.jsx
|
|
6521
|
-
import React11, { useState as
|
|
6793
|
+
import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
|
|
6522
6794
|
import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
|
|
6523
6795
|
function ImageViewer({ data, onClose }) {
|
|
6524
6796
|
var _a;
|
|
6525
6797
|
const { images = [], startIndex = 0, visible } = data;
|
|
6526
|
-
const [currentIndex, setCurrentIndex] =
|
|
6527
|
-
const [isLoading, setIsLoading] =
|
|
6528
|
-
const [loadedSrc, setLoadedSrc] =
|
|
6798
|
+
const [currentIndex, setCurrentIndex] = useState12(startIndex);
|
|
6799
|
+
const [isLoading, setIsLoading] = useState12(false);
|
|
6800
|
+
const [loadedSrc, setLoadedSrc] = useState12(null);
|
|
6529
6801
|
useLayoutEffect2(() => {
|
|
6530
6802
|
if (visible) {
|
|
6531
6803
|
setCurrentIndex(startIndex);
|
|
6532
6804
|
}
|
|
6533
6805
|
}, [visible, startIndex]);
|
|
6534
|
-
const handleNext =
|
|
6806
|
+
const handleNext = useCallback3(() => {
|
|
6535
6807
|
if (images.length > 1) {
|
|
6536
6808
|
setCurrentIndex((prev) => (prev + 1) % images.length);
|
|
6537
6809
|
}
|
|
6538
6810
|
}, [images.length]);
|
|
6539
|
-
const handlePrev =
|
|
6811
|
+
const handlePrev = useCallback3(() => {
|
|
6540
6812
|
if (images.length > 1) {
|
|
6541
6813
|
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
|
|
6542
6814
|
}
|
|
@@ -6641,10 +6913,10 @@ function ImageViewer({ data, onClose }) {
|
|
|
6641
6913
|
}
|
|
6642
6914
|
|
|
6643
6915
|
// src/components/InSceneCreationForm.jsx
|
|
6644
|
-
import React13, { useState as
|
|
6916
|
+
import React13, { useState as useState14, useEffect as useEffect13, useRef as useRef10 } from "react";
|
|
6645
6917
|
|
|
6646
6918
|
// src/components/ColorPicker.jsx
|
|
6647
|
-
import React12, { useState as
|
|
6919
|
+
import React12, { useState as useState13, useEffect as useEffect12, useRef as useRef9 } from "react";
|
|
6648
6920
|
import { HexColorPicker } from "react-colorful";
|
|
6649
6921
|
import { FiHash, FiCheck as FiCheck6 } from "react-icons/fi";
|
|
6650
6922
|
var PRESET_COLORS = [
|
|
@@ -6665,7 +6937,7 @@ var PRESET_COLORS = [
|
|
|
6665
6937
|
"#000000"
|
|
6666
6938
|
];
|
|
6667
6939
|
function ColorPicker({ color, onChange, disabled }) {
|
|
6668
|
-
const [isOpen, setIsOpen] =
|
|
6940
|
+
const [isOpen, setIsOpen] = useState13(false);
|
|
6669
6941
|
const popoverRef = useRef9(null);
|
|
6670
6942
|
useEffect12(() => {
|
|
6671
6943
|
const handleClickOutside = (event) => {
|
|
@@ -6740,7 +7012,7 @@ function ColorPicker({ color, onChange, disabled }) {
|
|
|
6740
7012
|
}
|
|
6741
7013
|
|
|
6742
7014
|
// src/components/InSceneCreationForm.jsx
|
|
6743
|
-
import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun } from "react-icons/fi";
|
|
7015
|
+
import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun, FiChevronDown as FiChevronDown4 } from "react-icons/fi";
|
|
6744
7016
|
function InSceneCreationForm({
|
|
6745
7017
|
onSave,
|
|
6746
7018
|
onCancel,
|
|
@@ -6758,21 +7030,44 @@ function InSceneCreationForm({
|
|
|
6758
7030
|
availableAncestries = [],
|
|
6759
7031
|
onMentionClick,
|
|
6760
7032
|
sourceTypes,
|
|
6761
|
-
onUploadFile
|
|
7033
|
+
onUploadFile,
|
|
7034
|
+
availableDatasets = [],
|
|
7035
|
+
sourceNodeDatasetId,
|
|
7036
|
+
viewType
|
|
6762
7037
|
}) {
|
|
6763
|
-
|
|
6764
|
-
const [
|
|
6765
|
-
const [
|
|
6766
|
-
const [
|
|
6767
|
-
const [
|
|
6768
|
-
const [
|
|
6769
|
-
const [
|
|
6770
|
-
const [
|
|
6771
|
-
const [
|
|
6772
|
-
const [
|
|
6773
|
-
const [
|
|
6774
|
-
const [
|
|
6775
|
-
const [
|
|
7038
|
+
var _a;
|
|
7039
|
+
const [name, setName] = useState14("");
|
|
7040
|
+
const [types, setTypes] = useState14([]);
|
|
7041
|
+
const [typeInput, setTypeInput] = useState14("");
|
|
7042
|
+
const [color, setColor] = useState14(initialColor || "#cccccc");
|
|
7043
|
+
const [size, setSize] = useState14("medium");
|
|
7044
|
+
const [intensity, setIntensity] = useState14(0);
|
|
7045
|
+
const [description, setDescription] = useState14("");
|
|
7046
|
+
const [customProps, setCustomProps] = useState14([]);
|
|
7047
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState14(false);
|
|
7048
|
+
const [filteredTypes, setFilteredTypes] = useState14([]);
|
|
7049
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
|
|
7050
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
|
|
7051
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
|
|
7052
|
+
const [targetDatasetId, setTargetDatasetId] = useState14(sourceNodeDatasetId || "");
|
|
7053
|
+
const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
|
|
7054
|
+
const datasetDropdownRef = useRef10(null);
|
|
7055
|
+
useEffect13(() => {
|
|
7056
|
+
if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
|
|
7057
|
+
}, [sourceNodeDatasetId]);
|
|
7058
|
+
useEffect13(() => {
|
|
7059
|
+
function handleClickOutside(event) {
|
|
7060
|
+
if (datasetDropdownRef.current && !datasetDropdownRef.current.contains(event.target)) {
|
|
7061
|
+
setIsDatasetDropdownOpen(false);
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
if (isDatasetDropdownOpen) {
|
|
7065
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
7066
|
+
}
|
|
7067
|
+
return () => {
|
|
7068
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
7069
|
+
};
|
|
7070
|
+
}, [isDatasetDropdownOpen]);
|
|
6776
7071
|
const propsEndRef = useRef10(null);
|
|
6777
7072
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
6778
7073
|
useEffect13(() => {
|
|
@@ -6818,8 +7113,8 @@ function InSceneCreationForm({
|
|
|
6818
7113
|
const newProp = createNewCustomProperty(customProps);
|
|
6819
7114
|
setCustomProps([...customProps, newProp]);
|
|
6820
7115
|
setTimeout(() => {
|
|
6821
|
-
var
|
|
6822
|
-
(
|
|
7116
|
+
var _a2;
|
|
7117
|
+
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
6823
7118
|
}, 100);
|
|
6824
7119
|
};
|
|
6825
7120
|
const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
|
|
@@ -6852,12 +7147,12 @@ function InSceneCreationForm({
|
|
|
6852
7147
|
onSizeChange == null ? void 0 : onSizeChange(newSize);
|
|
6853
7148
|
};
|
|
6854
7149
|
const handleToggleImageMode = () => {
|
|
6855
|
-
var
|
|
7150
|
+
var _a2, _b;
|
|
6856
7151
|
const newValue = !useImageAsTexture;
|
|
6857
7152
|
setUseImageAsTexture(newValue);
|
|
6858
7153
|
if (newValue) {
|
|
6859
7154
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
6860
|
-
if (firstImageProp && ((_b = (
|
|
7155
|
+
if (firstImageProp && ((_b = (_a2 = firstImageProp.value) == null ? void 0 : _a2[0]) == null ? void 0 : _b.value)) {
|
|
6861
7156
|
const url = firstImageProp.value[0].value;
|
|
6862
7157
|
setSelectedImageUrl(url);
|
|
6863
7158
|
onImageChange == null ? void 0 : onImageChange(true, url);
|
|
@@ -6890,6 +7185,7 @@ function InSceneCreationForm({
|
|
|
6890
7185
|
description_sections: processedSections,
|
|
6891
7186
|
useImageAsTexture,
|
|
6892
7187
|
textureImageUrl: useImageAsTexture ? selectedImageUrl : null,
|
|
7188
|
+
targetDatasetId,
|
|
6893
7189
|
...additionalData
|
|
6894
7190
|
});
|
|
6895
7191
|
};
|
|
@@ -6910,6 +7206,7 @@ function InSceneCreationForm({
|
|
|
6910
7206
|
onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
|
|
6911
7207
|
}
|
|
6912
7208
|
};
|
|
7209
|
+
const selectedDatasetName = ((_a = availableDatasets.find((ds) => ds.id === targetDatasetId)) == null ? void 0 : _a.name) || "Selecione um Dataset...";
|
|
6913
7210
|
return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
|
|
6914
7211
|
"div",
|
|
6915
7212
|
{
|
|
@@ -6967,7 +7264,27 @@ function InSceneCreationForm({
|
|
|
6967
7264
|
}
|
|
6968
7265
|
},
|
|
6969
7266
|
suggestedType
|
|
6970
|
-
))))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Nome do Node"), /* @__PURE__ */ React13.createElement("input", { required: true, type: "text", placeholder: "Ex.: Cliente XPTO", value: name, onChange: handleNameInputChange, className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60" })), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "
|
|
7267
|
+
))))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Nome do Node"), /* @__PURE__ */ React13.createElement("input", { required: true, type: "text", placeholder: "Ex.: Cliente XPTO", value: name, onChange: handleNameInputChange, className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60" })), viewType === "view" && availableDatasets.length > 0 && /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative", ref: datasetDropdownRef }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Criar Node no Dataset:"), /* @__PURE__ */ React13.createElement(
|
|
7268
|
+
"button",
|
|
7269
|
+
{
|
|
7270
|
+
type: "button",
|
|
7271
|
+
onClick: () => setIsDatasetDropdownOpen(!isDatasetDropdownOpen),
|
|
7272
|
+
className: "w-full flex items-center justify-between bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 hover:bg-slate-700/70 transition-colors text-slate-200 text-left"
|
|
7273
|
+
},
|
|
7274
|
+
/* @__PURE__ */ React13.createElement("span", { className: "truncate pr-2" }, selectedDatasetName),
|
|
7275
|
+
/* @__PURE__ */ React13.createElement(FiChevronDown4, { className: `flex-shrink-0 text-slate-400 transition-transform ${isDatasetDropdownOpen ? "rotate-180" : ""}` })
|
|
7276
|
+
), isDatasetDropdownOpen && /* @__PURE__ */ React13.createElement("ul", { className: "custom-scrollbar absolute top-[66px] left-0 z-20 w-full max-h-48 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-xl py-1" }, availableDatasets.map((ds) => /* @__PURE__ */ React13.createElement(
|
|
7277
|
+
"li",
|
|
7278
|
+
{
|
|
7279
|
+
key: ds.id,
|
|
7280
|
+
onClick: () => {
|
|
7281
|
+
setTargetDatasetId(ds.id);
|
|
7282
|
+
setIsDatasetDropdownOpen(false);
|
|
7283
|
+
},
|
|
7284
|
+
className: `px-3 py-2 text-sm cursor-pointer transition-colors ${targetDatasetId === ds.id ? "bg-indigo-600/40 text-indigo-200 font-medium" : "text-slate-300 hover:bg-white/5"}`
|
|
7285
|
+
},
|
|
7286
|
+
ds.name
|
|
7287
|
+
)))), /* @__PURE__ */ React13.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React13.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o (Opcional)"), /* @__PURE__ */ React13.createElement("div", { className: "relative group min-h-[80px] bg-slate-800/70 p-2.5 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React13.createElement(
|
|
6971
7288
|
DescriptionDisplay,
|
|
6972
7289
|
{
|
|
6973
7290
|
description,
|
|
@@ -6975,7 +7292,8 @@ function InSceneCreationForm({
|
|
|
6975
7292
|
availableNodes,
|
|
6976
7293
|
availableAncestries,
|
|
6977
7294
|
onMentionClick,
|
|
6978
|
-
onImageClick: handleImageClickFromText
|
|
7295
|
+
onImageClick: handleImageClickFromText,
|
|
7296
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
6979
7297
|
}
|
|
6980
7298
|
), /* @__PURE__ */ React13.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React13.createElement(
|
|
6981
7299
|
"button",
|
|
@@ -7066,7 +7384,7 @@ function InSceneCreationForm({
|
|
|
7066
7384
|
}
|
|
7067
7385
|
|
|
7068
7386
|
// src/components/InSceneVersionForm.jsx
|
|
7069
|
-
import React14, { useState as
|
|
7387
|
+
import React14, { useState as useState15, useEffect as useEffect14, useRef as useRef11 } from "react";
|
|
7070
7388
|
import { FiPlus as FiPlus4, FiMaximize2 as FiMaximize22, FiCheck as FiCheck8, FiEdit2 as FiEdit25 } from "react-icons/fi";
|
|
7071
7389
|
function InSceneVersionForm({
|
|
7072
7390
|
onSave,
|
|
@@ -7084,14 +7402,14 @@ function InSceneVersionForm({
|
|
|
7084
7402
|
onMentionClick,
|
|
7085
7403
|
onUploadFile
|
|
7086
7404
|
}) {
|
|
7087
|
-
const [name, setName] =
|
|
7088
|
-
const [size, setSize] =
|
|
7089
|
-
const [description, setDescription] =
|
|
7090
|
-
const [customProps, setCustomProps] =
|
|
7091
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7405
|
+
const [name, setName] = useState15("");
|
|
7406
|
+
const [size, setSize] = useState15("medium");
|
|
7407
|
+
const [description, setDescription] = useState15("");
|
|
7408
|
+
const [customProps, setCustomProps] = useState15([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
|
|
7409
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
|
|
7092
7410
|
const propsEndRef = useRef11(null);
|
|
7093
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
7094
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7411
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState15(false);
|
|
7412
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState15(null);
|
|
7095
7413
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
7096
7414
|
useEffect14(() => {
|
|
7097
7415
|
if (!hasImages && useImageAsTexture) {
|
|
@@ -7212,7 +7530,8 @@ function InSceneVersionForm({
|
|
|
7212
7530
|
availableNodes,
|
|
7213
7531
|
availableAncestries,
|
|
7214
7532
|
onMentionClick,
|
|
7215
|
-
onImageClick: handleImageClickFromText
|
|
7533
|
+
onImageClick: handleImageClickFromText,
|
|
7534
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
7216
7535
|
}
|
|
7217
7536
|
), /* @__PURE__ */ React14.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React14.createElement(
|
|
7218
7537
|
"button",
|
|
@@ -7284,8 +7603,8 @@ function InSceneVersionForm({
|
|
|
7284
7603
|
}
|
|
7285
7604
|
|
|
7286
7605
|
// src/components/NodeDetailsPanel.jsx
|
|
7287
|
-
import React15, { useState as
|
|
7288
|
-
import { FiPlus as FiPlus5, FiMaximize2 as FiMaximize23, FiX as FiX4, FiCheck as FiCheck9, FiImage as FiImage3, FiEdit2 as FiEdit26, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5 } from "react-icons/fi";
|
|
7606
|
+
import React15, { useState as useState16, useEffect as useEffect15, useRef as useRef12 } from "react";
|
|
7607
|
+
import { FiPlus as FiPlus5, FiMaximize2 as FiMaximize23, FiX as FiX4, FiCheck as FiCheck9, FiImage as FiImage3, FiEdit2 as FiEdit26, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
|
|
7289
7608
|
function NodeDetailsPanel({
|
|
7290
7609
|
node,
|
|
7291
7610
|
onClose,
|
|
@@ -7303,29 +7622,39 @@ function NodeDetailsPanel({
|
|
|
7303
7622
|
onMentionClick,
|
|
7304
7623
|
onIntensityChange,
|
|
7305
7624
|
onUploadFile,
|
|
7306
|
-
userRole
|
|
7625
|
+
userRole,
|
|
7626
|
+
currentDatasetName
|
|
7307
7627
|
}) {
|
|
7308
|
-
const [name, setName] =
|
|
7309
|
-
const [types, setTypes] =
|
|
7310
|
-
const [typeInput, setTypeInput] =
|
|
7311
|
-
const [color, setColor] =
|
|
7312
|
-
const [size, setSize] =
|
|
7313
|
-
const [description, setDescription] =
|
|
7314
|
-
const [intensity, setIntensity] =
|
|
7315
|
-
const [customProps, setCustomProps] =
|
|
7316
|
-
const [showTypeSuggestions, setShowTypeSuggestions] =
|
|
7317
|
-
const [filteredTypes, setFilteredTypes] =
|
|
7318
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7319
|
-
const [isReadMode, setIsReadMode] =
|
|
7320
|
-
const [existingSections, setExistingSections] =
|
|
7321
|
-
const [isSaving, setIsSaving] =
|
|
7322
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
7323
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
7628
|
+
const [name, setName] = useState16((node == null ? void 0 : node.name) ?? "");
|
|
7629
|
+
const [types, setTypes] = useState16([]);
|
|
7630
|
+
const [typeInput, setTypeInput] = useState16("");
|
|
7631
|
+
const [color, setColor] = useState16((node == null ? void 0 : node.color) ?? "#8b5cf6");
|
|
7632
|
+
const [size, setSize] = useState16((node == null ? void 0 : node.size) ?? "medium");
|
|
7633
|
+
const [description, setDescription] = useState16((node == null ? void 0 : node.description) ?? "");
|
|
7634
|
+
const [intensity, setIntensity] = useState16((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
7635
|
+
const [customProps, setCustomProps] = useState16(() => extractCustomPropsFromNode(node || {}));
|
|
7636
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState16(false);
|
|
7637
|
+
const [filteredTypes, setFilteredTypes] = useState16([]);
|
|
7638
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
|
|
7639
|
+
const [isReadMode, setIsReadMode] = useState16(false);
|
|
7640
|
+
const [existingSections, setExistingSections] = useState16((node == null ? void 0 : node.description_sections) || []);
|
|
7641
|
+
const [isSaving, setIsSaving] = useState16(false);
|
|
7642
|
+
const [isLinkCopied, setIsLinkCopied] = useState16(false);
|
|
7643
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState16(() => {
|
|
7324
7644
|
if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
|
|
7325
7645
|
if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
|
|
7326
7646
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
7327
7647
|
});
|
|
7328
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7648
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState16((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
7649
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
7650
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
7651
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
7652
|
+
minWidth: 320,
|
|
7653
|
+
maxWidth: maxPanelW
|
|
7654
|
+
});
|
|
7655
|
+
useEffect15(() => {
|
|
7656
|
+
setWidth(isReadMode ? 700 : 440);
|
|
7657
|
+
}, [isReadMode, setWidth]);
|
|
7329
7658
|
const prevNodeIdRef = useRef12(null);
|
|
7330
7659
|
const propsEndRef = useRef12(null);
|
|
7331
7660
|
const canEdit = userRole !== "viewer";
|
|
@@ -7478,6 +7807,11 @@ function NodeDetailsPanel({
|
|
|
7478
7807
|
textureImageUrl: url
|
|
7479
7808
|
});
|
|
7480
7809
|
};
|
|
7810
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
7811
|
+
setDescription(newDescription);
|
|
7812
|
+
onDataUpdate({ ...node, description: newDescription });
|
|
7813
|
+
triggerAutoSave({ description: newDescription });
|
|
7814
|
+
};
|
|
7481
7815
|
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
7482
7816
|
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
7483
7817
|
const currentTypes = overrides.types !== void 0 ? overrides.types : types;
|
|
@@ -7533,10 +7867,8 @@ function NodeDetailsPanel({
|
|
|
7533
7867
|
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
7534
7868
|
"div",
|
|
7535
7869
|
{
|
|
7536
|
-
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 transition-all duration-300 ease-out
|
|
7537
|
-
|
|
7538
|
-
`,
|
|
7539
|
-
style: { top: 16, right: 16, zIndex: 1100 },
|
|
7870
|
+
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 ${isResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
|
|
7871
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
7540
7872
|
onPointerDown: swallow,
|
|
7541
7873
|
onPointerMove: swallow,
|
|
7542
7874
|
onPointerUp: swallow,
|
|
@@ -7545,6 +7877,17 @@ function NodeDetailsPanel({
|
|
|
7545
7877
|
onContextMenu: swallow,
|
|
7546
7878
|
onDoubleClick: swallow
|
|
7547
7879
|
},
|
|
7880
|
+
/* @__PURE__ */ React15.createElement(
|
|
7881
|
+
"div",
|
|
7882
|
+
{
|
|
7883
|
+
onPointerDown: (e) => {
|
|
7884
|
+
e.stopPropagation();
|
|
7885
|
+
handleResize(e);
|
|
7886
|
+
},
|
|
7887
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
7888
|
+
title: "Arraste para redimensionar"
|
|
7889
|
+
}
|
|
7890
|
+
),
|
|
7548
7891
|
isReadMode ? /* @__PURE__ */ React15.createElement(
|
|
7549
7892
|
DescriptionReadModePanel,
|
|
7550
7893
|
{
|
|
@@ -7563,7 +7906,8 @@ function NodeDetailsPanel({
|
|
|
7563
7906
|
availableAncestries,
|
|
7564
7907
|
onOpenReference,
|
|
7565
7908
|
onMentionClick,
|
|
7566
|
-
onImageClick: handleImageClickFromText
|
|
7909
|
+
onImageClick: handleImageClickFromText,
|
|
7910
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7567
7911
|
}
|
|
7568
7912
|
) : /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ React15.createElement(
|
|
7569
7913
|
"button",
|
|
@@ -7631,7 +7975,8 @@ function NodeDetailsPanel({
|
|
|
7631
7975
|
availableAncestries,
|
|
7632
7976
|
onOpenReference,
|
|
7633
7977
|
onMentionClick,
|
|
7634
|
-
onImageClick: handleImageClickFromText
|
|
7978
|
+
onImageClick: handleImageClickFromText,
|
|
7979
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7635
7980
|
}
|
|
7636
7981
|
), /* @__PURE__ */ React15.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement(
|
|
7637
7982
|
"button",
|
|
@@ -7714,7 +8059,7 @@ function NodeDetailsPanel({
|
|
|
7714
8059
|
onUploadFile: canEdit ? onUploadFile : void 0,
|
|
7715
8060
|
readOnly: !canEdit
|
|
7716
8061
|
}
|
|
7717
|
-
)), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ React15.createElement("div", { className: "sticky bottom-0 z-10 bg-gradient-to-t from-slate-950/80 via-slate-950/50 to-transparent px-6 py-4 border-t border-white/10 flex justify-end gap-3" }, /* @__PURE__ */ React15.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm disabled:opacity-50" }, canEdit ? "Cancelar" : "Fechar"), canEdit && /* @__PURE__ */ React15.createElement(
|
|
8062
|
+
)), /* @__PURE__ */ React15.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React15.createElement("div", { className: "pt-3 mt-4 border-t border-white/10 flex items-center justify-end gap-2 text-xs text-slate-400" }, /* @__PURE__ */ React15.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ React15.createElement("div", { className: "sticky bottom-0 z-10 bg-gradient-to-t from-slate-950/80 via-slate-950/50 to-transparent px-6 py-4 border-t border-white/10 flex justify-end gap-3" }, /* @__PURE__ */ React15.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm disabled:opacity-50" }, canEdit ? "Cancelar" : "Fechar"), canEdit && /* @__PURE__ */ React15.createElement(
|
|
7718
8063
|
"button",
|
|
7719
8064
|
{
|
|
7720
8065
|
onClick: () => handleSave(false),
|
|
@@ -7746,7 +8091,7 @@ function NodeDetailsPanel({
|
|
|
7746
8091
|
}
|
|
7747
8092
|
|
|
7748
8093
|
// src/components/MultiNodeContextMenu.jsx
|
|
7749
|
-
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as
|
|
8094
|
+
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState17, useEffect as useEffect16 } from "react";
|
|
7750
8095
|
function MultiNodeContextMenu({
|
|
7751
8096
|
data,
|
|
7752
8097
|
userRole,
|
|
@@ -7757,7 +8102,7 @@ function MultiNodeContextMenu({
|
|
|
7757
8102
|
onDeleteNodes
|
|
7758
8103
|
}) {
|
|
7759
8104
|
const menuRef = useRef13(null);
|
|
7760
|
-
const [menuPos, setMenuPos] =
|
|
8105
|
+
const [menuPos, setMenuPos] = useState17({ left: 0, top: 0 });
|
|
7761
8106
|
const ability = defineAbilityFor(userRole);
|
|
7762
8107
|
const canDelete = ability.can("delete", "Node");
|
|
7763
8108
|
useLayoutEffect3(() => {
|
|
@@ -7806,7 +8151,7 @@ function MultiNodeContextMenu({
|
|
|
7806
8151
|
}
|
|
7807
8152
|
|
|
7808
8153
|
// src/components/RelationshipDetailsPanel.jsx
|
|
7809
|
-
import React17, { useState as
|
|
8154
|
+
import React17, { useState as useState18, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
|
|
7810
8155
|
import { FiPlus as FiPlus6, FiEdit2 as FiEdit27, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
|
|
7811
8156
|
function RelationshipDetailsPanel({
|
|
7812
8157
|
link,
|
|
@@ -7820,15 +8165,14 @@ function RelationshipDetailsPanel({
|
|
|
7820
8165
|
onMentionClick,
|
|
7821
8166
|
onUploadFile,
|
|
7822
8167
|
userRole
|
|
7823
|
-
// Recebendo userRole via props
|
|
7824
8168
|
}) {
|
|
7825
|
-
const [name, setName] =
|
|
7826
|
-
const [description, setDescription] =
|
|
7827
|
-
const [customProps, setCustomProps] =
|
|
7828
|
-
const [existingSections, setExistingSections] =
|
|
7829
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7830
|
-
const [isSaving, setIsSaving] =
|
|
7831
|
-
const [isReadMode, setIsReadMode] =
|
|
8169
|
+
const [name, setName] = useState18((link == null ? void 0 : link.name) ?? "");
|
|
8170
|
+
const [description, setDescription] = useState18((link == null ? void 0 : link.description) ?? "");
|
|
8171
|
+
const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(link || {}));
|
|
8172
|
+
const [existingSections, setExistingSections] = useState18((link == null ? void 0 : link.description_sections) || []);
|
|
8173
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
|
|
8174
|
+
const [isSaving, setIsSaving] = useState18(false);
|
|
8175
|
+
const [isReadMode, setIsReadMode] = useState18(false);
|
|
7832
8176
|
const propsEndRef = useRef14(null);
|
|
7833
8177
|
const canEdit = useMemo9(() => {
|
|
7834
8178
|
const ability = defineAbilityFor(userRole);
|
|
@@ -7883,6 +8227,12 @@ function RelationshipDetailsPanel({
|
|
|
7883
8227
|
const triggerAutoSave = (overrides = {}) => {
|
|
7884
8228
|
if (canEdit) handleSave(true, overrides);
|
|
7885
8229
|
};
|
|
8230
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
8231
|
+
if (!canEdit) return;
|
|
8232
|
+
setDescription(newDescription);
|
|
8233
|
+
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
8234
|
+
triggerAutoSave({ description: newDescription });
|
|
8235
|
+
};
|
|
7886
8236
|
const handleRemoveProp = (i) => {
|
|
7887
8237
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
7888
8238
|
setCustomProps(newProps);
|
|
@@ -7936,7 +8286,8 @@ function RelationshipDetailsPanel({
|
|
|
7936
8286
|
availableAncestries,
|
|
7937
8287
|
onOpenReference,
|
|
7938
8288
|
onMentionClick,
|
|
7939
|
-
onImageClick: handleImageClickFromText
|
|
8289
|
+
onImageClick: handleImageClickFromText,
|
|
8290
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7940
8291
|
}
|
|
7941
8292
|
) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React17.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-teal-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ React17.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ React17.createElement("button", { onClick: onClose, disabled: isSaving, className: "w-9 h-9 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl disabled:opacity-50", title: "Fechar" }, "\xD7")), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ React17.createElement(
|
|
7942
8293
|
"input",
|
|
@@ -7959,7 +8310,8 @@ function RelationshipDetailsPanel({
|
|
|
7959
8310
|
availableAncestries,
|
|
7960
8311
|
onOpenReference,
|
|
7961
8312
|
onMentionClick,
|
|
7962
|
-
onImageClick: handleImageClickFromText
|
|
8313
|
+
onImageClick: handleImageClickFromText,
|
|
8314
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7963
8315
|
}
|
|
7964
8316
|
), /* @__PURE__ */ React17.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React17.createElement(
|
|
7965
8317
|
"button",
|
|
@@ -8031,7 +8383,7 @@ function RelationshipDetailsPanel({
|
|
|
8031
8383
|
}
|
|
8032
8384
|
|
|
8033
8385
|
// src/components/RelationshipContextMenu.jsx
|
|
8034
|
-
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as
|
|
8386
|
+
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState19, useEffect as useEffect18, useMemo as useMemo10 } from "react";
|
|
8035
8387
|
function RelationshipContextMenu({
|
|
8036
8388
|
data,
|
|
8037
8389
|
userRole,
|
|
@@ -8043,7 +8395,7 @@ function RelationshipContextMenu({
|
|
|
8043
8395
|
onClose
|
|
8044
8396
|
}) {
|
|
8045
8397
|
const menuRef = useRef15(null);
|
|
8046
|
-
const [menuPos, setMenuPos] =
|
|
8398
|
+
const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
|
|
8047
8399
|
const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
|
|
8048
8400
|
const sourceName = useMemo10(
|
|
8049
8401
|
() => {
|
|
@@ -8245,7 +8597,7 @@ function LoadingScreen() {
|
|
|
8245
8597
|
}
|
|
8246
8598
|
|
|
8247
8599
|
// src/components/ImportParentFileModal.jsx
|
|
8248
|
-
import React20, { useEffect as useEffect19, useState as
|
|
8600
|
+
import React20, { useEffect as useEffect19, useState as useState20 } from "react";
|
|
8249
8601
|
function ImportParentFileModal({
|
|
8250
8602
|
isOpen,
|
|
8251
8603
|
onClose,
|
|
@@ -8256,11 +8608,11 @@ function ImportParentFileModal({
|
|
|
8256
8608
|
onFetchAvailableFiles,
|
|
8257
8609
|
currentViewName
|
|
8258
8610
|
}) {
|
|
8259
|
-
const [activeTab, setActiveTab] =
|
|
8260
|
-
const [availableDbs, setAvailableDbs] =
|
|
8261
|
-
const [availableViews, setAvailableViews] =
|
|
8262
|
-
const [selectedItem, setSelectedItem] =
|
|
8263
|
-
const [isLoading, setIsLoading] =
|
|
8611
|
+
const [activeTab, setActiveTab] = useState20("databases");
|
|
8612
|
+
const [availableDbs, setAvailableDbs] = useState20([]);
|
|
8613
|
+
const [availableViews, setAvailableViews] = useState20([]);
|
|
8614
|
+
const [selectedItem, setSelectedItem] = useState20(null);
|
|
8615
|
+
const [isLoading, setIsLoading] = useState20(false);
|
|
8264
8616
|
useEffect19(() => {
|
|
8265
8617
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
8266
8618
|
const fetchData = async () => {
|
|
@@ -8406,7 +8758,7 @@ function ImportParentFileModal({
|
|
|
8406
8758
|
}
|
|
8407
8759
|
|
|
8408
8760
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
8409
|
-
import React21, { useState as
|
|
8761
|
+
import React21, { useState as useState21 } from "react";
|
|
8410
8762
|
import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
|
|
8411
8763
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
8412
8764
|
var _a, _b, _c, _d;
|
|
@@ -8416,7 +8768,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8416
8768
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
8417
8769
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
8418
8770
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
8419
|
-
const [isReadMode, setIsReadMode] =
|
|
8771
|
+
const [isReadMode, setIsReadMode] = useState21(false);
|
|
8420
8772
|
const swallow = (e) => e.stopPropagation();
|
|
8421
8773
|
const handleImageClickFromText = (url, name) => {
|
|
8422
8774
|
if (onOpenImageViewer) {
|
|
@@ -8482,7 +8834,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8482
8834
|
}
|
|
8483
8835
|
|
|
8484
8836
|
// src/components/AncestryBoard.jsx
|
|
8485
|
-
import React22, { useState as
|
|
8837
|
+
import React22, { useState as useState22, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
|
|
8486
8838
|
import {
|
|
8487
8839
|
FiSearch as FiSearch4,
|
|
8488
8840
|
FiLayers as FiLayers6,
|
|
@@ -8659,11 +9011,11 @@ function AncestryBoard({
|
|
|
8659
9011
|
userRole
|
|
8660
9012
|
// [NOVO] Recebe a role do usuário
|
|
8661
9013
|
}) {
|
|
8662
|
-
const [searchTerm, setSearchTerm] =
|
|
8663
|
-
const [groups, setGroups] =
|
|
8664
|
-
const [isLoaded, setIsLoaded] =
|
|
8665
|
-
const [pickingGroupId, setPickingGroupId] =
|
|
8666
|
-
const [saveStatus, setSaveStatus] =
|
|
9014
|
+
const [searchTerm, setSearchTerm] = useState22("");
|
|
9015
|
+
const [groups, setGroups] = useState22([]);
|
|
9016
|
+
const [isLoaded, setIsLoaded] = useState22(false);
|
|
9017
|
+
const [pickingGroupId, setPickingGroupId] = useState22(null);
|
|
9018
|
+
const [saveStatus, setSaveStatus] = useState22("idle");
|
|
8667
9019
|
const canEdit = useMemo11(() => {
|
|
8668
9020
|
return userRole !== "viewer";
|
|
8669
9021
|
}, [userRole]);
|
|
@@ -9048,7 +9400,7 @@ function XViewScene({
|
|
|
9048
9400
|
delete_file_action,
|
|
9049
9401
|
check_user_permission
|
|
9050
9402
|
}) {
|
|
9051
|
-
var _a, _b, _c, _d, _e, _f;
|
|
9403
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
9052
9404
|
const { data: session, status } = useSession();
|
|
9053
9405
|
const router = useRouter();
|
|
9054
9406
|
const searchParams = useSearchParams();
|
|
@@ -9113,37 +9465,37 @@ function XViewScene({
|
|
|
9113
9465
|
const sceneDataRef = useRef17(null);
|
|
9114
9466
|
const parentDataRef = useRef17(null);
|
|
9115
9467
|
const ancestryDataRef = useRef17(null);
|
|
9116
|
-
const [isLoading, setIsLoading] =
|
|
9117
|
-
const [permissionStatus, setPermissionStatus] =
|
|
9118
|
-
const [userPermissionRole, setUserPermissionRole] =
|
|
9119
|
-
const [isInitialized, setIsInitialized] =
|
|
9120
|
-
const [sceneVersion, setSceneVersion] =
|
|
9121
|
-
const [contextMenu, setContextMenu] =
|
|
9122
|
-
const [multiContextMenu, setMultiContextMenu] =
|
|
9123
|
-
const [relationshipMenu, setRelationshipMenu] =
|
|
9124
|
-
const [creationMode, setCreationMode] =
|
|
9125
|
-
const [versionMode, setVersionMode] =
|
|
9126
|
-
const [hasFocusedInitial, setHasFocusedInitial] =
|
|
9127
|
-
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] =
|
|
9128
|
-
const [ancestryMode, setAncestryMode] =
|
|
9129
|
-
const [readingMode, setReadingMode] =
|
|
9468
|
+
const [isLoading, setIsLoading] = useState23(true);
|
|
9469
|
+
const [permissionStatus, setPermissionStatus] = useState23("loading");
|
|
9470
|
+
const [userPermissionRole, setUserPermissionRole] = useState23(null);
|
|
9471
|
+
const [isInitialized, setIsInitialized] = useState23(false);
|
|
9472
|
+
const [sceneVersion, setSceneVersion] = useState23(0);
|
|
9473
|
+
const [contextMenu, setContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeData: null });
|
|
9474
|
+
const [multiContextMenu, setMultiContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
9475
|
+
const [relationshipMenu, setRelationshipMenu] = useState23({ visible: false, x: 0, y: 0, linkObject: null });
|
|
9476
|
+
const [creationMode, setCreationMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9477
|
+
const [versionMode, setVersionMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9478
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState23(false);
|
|
9479
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState23(false);
|
|
9480
|
+
const [ancestryMode, setAncestryMode] = useState23({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
9481
|
+
const [readingMode, setReadingMode] = useState23({
|
|
9130
9482
|
isActive: false,
|
|
9131
9483
|
ancestry: null,
|
|
9132
9484
|
branchStack: [],
|
|
9133
9485
|
autoAbstraction: false
|
|
9134
9486
|
});
|
|
9135
|
-
const [formPosition, setFormPosition] =
|
|
9136
|
-
const [detailsNode, setDetailsNode] =
|
|
9137
|
-
const [detailsLink, setDetailsLink] =
|
|
9138
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] =
|
|
9139
|
-
const [imageViewer, setImageViewer] =
|
|
9140
|
-
const [editingAncestryRel, setEditingAncestryRel] =
|
|
9141
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
9142
|
-
const [importSuccessMessage, setImportSuccessMessage] =
|
|
9143
|
-
const [highlightedNodeId, setHighlightedNodeId] =
|
|
9144
|
-
const [isAncestryBoardOpen, setIsAncestryBoardOpen] =
|
|
9145
|
-
const [ancestryBoardData, setAncestryBoardData] =
|
|
9146
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
9487
|
+
const [formPosition, setFormPosition] = useState23({ left: 16, top: 16, opacity: 0 });
|
|
9488
|
+
const [detailsNode, setDetailsNode] = useState23(null);
|
|
9489
|
+
const [detailsLink, setDetailsLink] = useState23(null);
|
|
9490
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState23(null);
|
|
9491
|
+
const [imageViewer, setImageViewer] = useState23({ visible: false, images: [], startIndex: 0 });
|
|
9492
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState23({ visible: false, data: null, path: null });
|
|
9493
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState23(false);
|
|
9494
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState23("");
|
|
9495
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState23(null);
|
|
9496
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState23(false);
|
|
9497
|
+
const [ancestryBoardData, setAncestryBoardData] = useState23([]);
|
|
9498
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState23(false);
|
|
9147
9499
|
const mountRef = useRef17(null);
|
|
9148
9500
|
const tooltipRef = useRef17(null);
|
|
9149
9501
|
const formRef = useRef17(null);
|
|
@@ -9186,6 +9538,12 @@ function XViewScene({
|
|
|
9186
9538
|
lastDescriptionLength: 0,
|
|
9187
9539
|
highlightedNodeId: null
|
|
9188
9540
|
});
|
|
9541
|
+
const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9542
|
+
const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
|
|
9543
|
+
initialWidth: 700,
|
|
9544
|
+
minWidth: 320,
|
|
9545
|
+
maxWidth: maxReadPanelW
|
|
9546
|
+
});
|
|
9189
9547
|
useEffect21(() => {
|
|
9190
9548
|
stateRef.current.ancestry = ancestryMode;
|
|
9191
9549
|
}, [ancestryMode]);
|
|
@@ -9200,19 +9558,20 @@ function XViewScene({
|
|
|
9200
9558
|
const parentFile = allParentData[parentFileId];
|
|
9201
9559
|
const parentDbInfo = parentDbsArray.find((db) => String(db.db_id) === String(parentFileId));
|
|
9202
9560
|
const ownerId2 = (parentDbInfo == null ? void 0 : parentDbInfo.owner_id) || null;
|
|
9561
|
+
const datasetName = parentFile.dataset_name || `Dataset #${parentFileId.substring(0, 6)}`;
|
|
9203
9562
|
if (parentFile.nodes && ownerId2) {
|
|
9204
9563
|
for (const node of parentFile.nodes) {
|
|
9205
|
-
map.set(String(node.id), { parentFileId, ownerId: ownerId2 });
|
|
9564
|
+
map.set(String(node.id), { parentFileId, ownerId: ownerId2, datasetName });
|
|
9206
9565
|
}
|
|
9207
9566
|
}
|
|
9208
9567
|
}
|
|
9209
9568
|
}
|
|
9210
9569
|
stateRef.current.nodeIdToParentFileMap = map;
|
|
9211
9570
|
}, [isInitialized, sceneVersion]);
|
|
9212
|
-
const handleNavigateBack =
|
|
9571
|
+
const handleNavigateBack = useCallback4(() => {
|
|
9213
9572
|
router.push("/dashboard/scenes");
|
|
9214
9573
|
}, [router]);
|
|
9215
|
-
const handleConfirmImport =
|
|
9574
|
+
const handleConfirmImport = useCallback4(
|
|
9216
9575
|
async (importPayload) => {
|
|
9217
9576
|
var _a2, _b2;
|
|
9218
9577
|
let files = [];
|
|
@@ -9260,7 +9619,6 @@ function XViewScene({
|
|
|
9260
9619
|
if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
|
|
9261
9620
|
const viewSpecificAncestries = ancestryResponse.data.filter(
|
|
9262
9621
|
(anc) => anc._source_file_id === viewToImport.id && !anc.is_private
|
|
9263
|
-
// <--- AQUI ESTÁ A TRAVA DE SEGURANÇA
|
|
9264
9622
|
);
|
|
9265
9623
|
const processedAncestries = viewSpecificAncestries.map((anc) => ({
|
|
9266
9624
|
...anc,
|
|
@@ -9311,7 +9669,7 @@ function XViewScene({
|
|
|
9311
9669
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
9312
9670
|
setImageViewer({ visible: true, images, startIndex });
|
|
9313
9671
|
};
|
|
9314
|
-
const tweenToTarget =
|
|
9672
|
+
const tweenToTarget = useCallback4((target, zoomFactor = 1, forcedDirection = null) => {
|
|
9315
9673
|
const { camera, controls, tweenGroup } = stateRef.current;
|
|
9316
9674
|
if (!camera || !controls || !tweenGroup) return;
|
|
9317
9675
|
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
@@ -9334,7 +9692,7 @@ function XViewScene({
|
|
|
9334
9692
|
if (!t || typeof t.closest !== "function") return false;
|
|
9335
9693
|
return !!t.closest(".ui-overlay");
|
|
9336
9694
|
};
|
|
9337
|
-
const buildFullAncestryTree =
|
|
9695
|
+
const buildFullAncestryTree = useCallback4((idTree, nodes, ancestries = []) => {
|
|
9338
9696
|
if (!idTree) return null;
|
|
9339
9697
|
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
9340
9698
|
const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
|
|
@@ -9360,14 +9718,10 @@ function XViewScene({
|
|
|
9360
9718
|
return {
|
|
9361
9719
|
...branch,
|
|
9362
9720
|
name: linkedAncestry.name,
|
|
9363
|
-
// Sobrescreve nome para exibição
|
|
9364
9721
|
description: linkedAncestry.description,
|
|
9365
|
-
// Sobrescreve descrição
|
|
9366
9722
|
description_sections: linkedAncestry.description_sections,
|
|
9367
9723
|
tree: graftedTree,
|
|
9368
|
-
// ENXERTA A ÁRVORE AQUI
|
|
9369
9724
|
isLinked: true
|
|
9370
|
-
// Flag útil
|
|
9371
9725
|
};
|
|
9372
9726
|
}
|
|
9373
9727
|
}
|
|
@@ -9414,7 +9768,7 @@ function XViewScene({
|
|
|
9414
9768
|
}
|
|
9415
9769
|
return recursiveBuild(idTree);
|
|
9416
9770
|
}, []);
|
|
9417
|
-
const handleActivateTimeline =
|
|
9771
|
+
const handleActivateTimeline = useCallback4(() => {
|
|
9418
9772
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9419
9773
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
9420
9774
|
while (timelineIntervalsGroup.children.length > 0) {
|
|
@@ -9567,7 +9921,7 @@ function XViewScene({
|
|
|
9567
9921
|
}
|
|
9568
9922
|
});
|
|
9569
9923
|
}, []);
|
|
9570
|
-
const handleVersionTimeline =
|
|
9924
|
+
const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
|
|
9571
9925
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9572
9926
|
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
|
|
9573
9927
|
versionMeshes.forEach((mesh) => {
|
|
@@ -9722,6 +10076,9 @@ function XViewScene({
|
|
|
9722
10076
|
sceneDataRef.current = sceneResponse.data.scene;
|
|
9723
10077
|
parentDataRef.current = sceneResponse.data.parent;
|
|
9724
10078
|
ancestryDataRef.current = sceneResponse.data.ancestry;
|
|
10079
|
+
console.log("Console de sceneResponse.data.scene:", sceneResponse.data.scene);
|
|
10080
|
+
console.log("Console de sceneResponse.data.parent:", sceneResponse.data.parent);
|
|
10081
|
+
console.log("Console de sceneResponse.data.ancestry:", sceneResponse.data.ancestry);
|
|
9725
10082
|
setIsInitialized(true);
|
|
9726
10083
|
} else {
|
|
9727
10084
|
console.error("Falha ao buscar dados da cena:", (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida.");
|
|
@@ -9757,16 +10114,14 @@ function XViewScene({
|
|
|
9757
10114
|
isInitialized,
|
|
9758
10115
|
permissionStatus,
|
|
9759
10116
|
focusNodeId,
|
|
9760
|
-
// <-- MANTIDO
|
|
9761
10117
|
focusAncestryId
|
|
9762
|
-
// <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
|
|
9763
10118
|
]);
|
|
9764
|
-
const isNodeInView =
|
|
10119
|
+
const isNodeInView = useCallback4((id) => {
|
|
9765
10120
|
const key = String(id);
|
|
9766
10121
|
const objs = stateRef.current.nodeObjects || {};
|
|
9767
10122
|
return !!objs[key];
|
|
9768
10123
|
}, []);
|
|
9769
|
-
const addOrUpdateNodeMesh =
|
|
10124
|
+
const addOrUpdateNodeMesh = useCallback4((nodeData, position, suppressVersionUpdate = false) => {
|
|
9770
10125
|
const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
|
|
9771
10126
|
const nodeId = String(nodeData.id);
|
|
9772
10127
|
if (nodeObjects[nodeId]) {
|
|
@@ -10415,7 +10770,7 @@ function XViewScene({
|
|
|
10415
10770
|
}
|
|
10416
10771
|
};
|
|
10417
10772
|
}, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
|
|
10418
|
-
const handleGhostNodeImageChange =
|
|
10773
|
+
const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
|
|
10419
10774
|
const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10420
10775
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
10421
10776
|
if (!ghostNode || !graphGroup) return;
|
|
@@ -10457,7 +10812,7 @@ function XViewScene({
|
|
|
10457
10812
|
aura: newGhostNode.getObjectByName("aura")
|
|
10458
10813
|
};
|
|
10459
10814
|
}, []);
|
|
10460
|
-
const handleGhostNodeIntensityChange =
|
|
10815
|
+
const handleGhostNodeIntensityChange = useCallback4((newIntensity) => {
|
|
10461
10816
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10462
10817
|
if (!ghostNode) return;
|
|
10463
10818
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10478,7 +10833,7 @@ function XViewScene({
|
|
|
10478
10833
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
10479
10834
|
}
|
|
10480
10835
|
}, []);
|
|
10481
|
-
const handleDetailNodeIntensityChange =
|
|
10836
|
+
const handleDetailNodeIntensityChange = useCallback4((nodeId, newIntensity) => {
|
|
10482
10837
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
10483
10838
|
if (!mesh) return;
|
|
10484
10839
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10503,32 +10858,33 @@ function XViewScene({
|
|
|
10503
10858
|
const handleGhostNodeColorChange = (newColor) => {
|
|
10504
10859
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10505
10860
|
if (!ghostNode) return;
|
|
10506
|
-
const {
|
|
10507
|
-
const
|
|
10861
|
+
const { color, emissive } = computeNodeMaterialProps(newColor);
|
|
10862
|
+
const currentIntensity = ghostNode.userData.intensity !== void 0 ? Number(ghostNode.userData.intensity) : 0;
|
|
10863
|
+
const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
|
|
10508
10864
|
const isImageNode = ghostNode.userData.useImageAsTexture === true || String(ghostNode.userData.useImageAsTexture) === "true";
|
|
10509
10865
|
if (isImageNode) {
|
|
10510
10866
|
const borderMesh = ghostNode.getObjectByName("borderRing");
|
|
10511
10867
|
if (borderMesh && borderMesh.material) {
|
|
10512
|
-
borderMesh.material.color.copy(
|
|
10868
|
+
borderMesh.material.color.copy(color);
|
|
10513
10869
|
if (borderMesh.material.emissive) {
|
|
10514
|
-
borderMesh.material.emissive.copy(
|
|
10515
|
-
borderMesh.material.emissiveIntensity =
|
|
10870
|
+
borderMesh.material.emissive.copy(emissive);
|
|
10871
|
+
borderMesh.material.emissiveIntensity = finalIntensity;
|
|
10516
10872
|
}
|
|
10517
10873
|
}
|
|
10518
10874
|
} else {
|
|
10519
10875
|
if (ghostNode.material) {
|
|
10520
|
-
ghostNode.material.color.copy(
|
|
10876
|
+
ghostNode.material.color.copy(color);
|
|
10521
10877
|
if (ghostNode.material.emissive) {
|
|
10522
|
-
ghostNode.material.emissive.copy(
|
|
10523
|
-
ghostNode.material.emissiveIntensity =
|
|
10878
|
+
ghostNode.material.emissive.copy(emissive);
|
|
10879
|
+
ghostNode.material.emissiveIntensity = finalIntensity;
|
|
10524
10880
|
}
|
|
10525
10881
|
}
|
|
10526
10882
|
}
|
|
10527
10883
|
if (ghostAura && ghostAura.material) {
|
|
10528
|
-
ghostAura.material.color.
|
|
10884
|
+
ghostAura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
|
|
10529
10885
|
}
|
|
10530
10886
|
ghostNode.userData.color = newColor;
|
|
10531
|
-
ghostNode.userData._baseEmissiveIntensity =
|
|
10887
|
+
ghostNode.userData._baseEmissiveIntensity = finalIntensity;
|
|
10532
10888
|
};
|
|
10533
10889
|
const handleGhostNodeSizeChange = (sizeKey) => {
|
|
10534
10890
|
const { node: ghostNode } = stateRef.current.ghostElements;
|
|
@@ -10569,7 +10925,9 @@ function XViewScene({
|
|
|
10569
10925
|
var _a2;
|
|
10570
10926
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
10571
10927
|
if (!mesh) return;
|
|
10572
|
-
const { color, emissive
|
|
10928
|
+
const { color, emissive } = computeNodeMaterialProps(newColor);
|
|
10929
|
+
const currentIntensity = mesh.userData.intensity !== void 0 ? Number(mesh.userData.intensity) : 0;
|
|
10930
|
+
const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
|
|
10573
10931
|
const isImageNode = mesh.userData.useImageAsTexture === true || String(mesh.userData.useImageAsTexture) === "true";
|
|
10574
10932
|
if (isImageNode) {
|
|
10575
10933
|
const borderMesh = mesh.getObjectByName("borderRing");
|
|
@@ -10577,20 +10935,22 @@ function XViewScene({
|
|
|
10577
10935
|
borderMesh.material.color.copy(color);
|
|
10578
10936
|
if (borderMesh.material.emissive) {
|
|
10579
10937
|
borderMesh.material.emissive.copy(emissive);
|
|
10580
|
-
borderMesh.material.emissiveIntensity =
|
|
10938
|
+
borderMesh.material.emissiveIntensity = finalIntensity;
|
|
10581
10939
|
}
|
|
10582
10940
|
}
|
|
10583
10941
|
} else {
|
|
10584
10942
|
if (mesh.material) {
|
|
10585
10943
|
mesh.material.color.copy(color);
|
|
10586
10944
|
mesh.material.emissive.copy(emissive);
|
|
10587
|
-
mesh.material.emissiveIntensity =
|
|
10945
|
+
mesh.material.emissiveIntensity = finalIntensity;
|
|
10588
10946
|
}
|
|
10589
10947
|
}
|
|
10590
10948
|
const aura = mesh.getObjectByName("aura");
|
|
10591
|
-
if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color)
|
|
10949
|
+
if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color) {
|
|
10950
|
+
aura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
|
|
10951
|
+
}
|
|
10592
10952
|
mesh.userData.color = newColor;
|
|
10593
|
-
mesh.userData._baseEmissiveIntensity =
|
|
10953
|
+
mesh.userData._baseEmissiveIntensity = finalIntensity;
|
|
10594
10954
|
};
|
|
10595
10955
|
const handleDetailNodeSizeChange = (nodeId, newSize) => {
|
|
10596
10956
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
@@ -10619,7 +10979,7 @@ function XViewScene({
|
|
|
10619
10979
|
mountRef.current.style.cursor = "default";
|
|
10620
10980
|
}
|
|
10621
10981
|
};
|
|
10622
|
-
const handleAncestryTreeUpdate =
|
|
10982
|
+
const handleAncestryTreeUpdate = useCallback4((newTree, extraData = null) => {
|
|
10623
10983
|
setAncestryMode((prev) => {
|
|
10624
10984
|
const prevTreeStr = JSON.stringify(prev.tree);
|
|
10625
10985
|
const newTreeStr = JSON.stringify(newTree);
|
|
@@ -10689,7 +11049,7 @@ function XViewScene({
|
|
|
10689
11049
|
const handleStartVersioning = (nodeData) => {
|
|
10690
11050
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
10691
11051
|
};
|
|
10692
|
-
const handleClearAncestryVisuals =
|
|
11052
|
+
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
10693
11053
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
10694
11054
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
10695
11055
|
if (renderIndex !== -1) {
|
|
@@ -10703,7 +11063,7 @@ function XViewScene({
|
|
|
10703
11063
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
10704
11064
|
}
|
|
10705
11065
|
}, []);
|
|
10706
|
-
const handleRenderAncestry =
|
|
11066
|
+
const handleRenderAncestry = useCallback4(
|
|
10707
11067
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
10708
11068
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
10709
11069
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11119,7 +11479,7 @@ function XViewScene({
|
|
|
11119
11479
|
},
|
|
11120
11480
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
11121
11481
|
);
|
|
11122
|
-
const handleRenderAbstractionTree =
|
|
11482
|
+
const handleRenderAbstractionTree = useCallback4((ancestryObject, targetNodeId = null) => {
|
|
11123
11483
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11124
11484
|
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
11125
11485
|
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
@@ -11180,7 +11540,7 @@ function XViewScene({
|
|
|
11180
11540
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
11181
11541
|
tweenToTarget(rootTargetPos, 0.7);
|
|
11182
11542
|
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
11183
|
-
const handleReadModeBranchNav =
|
|
11543
|
+
const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
|
|
11184
11544
|
const { ancestry, branchStack } = readingMode;
|
|
11185
11545
|
if (!ancestry || !ancestry.tree) return;
|
|
11186
11546
|
const allAncestries = ancestryDataRef.current || [];
|
|
@@ -11218,9 +11578,7 @@ function XViewScene({
|
|
|
11218
11578
|
description_sections: branchToOpen.description_sections,
|
|
11219
11579
|
tree: branchToOpen.tree,
|
|
11220
11580
|
_originNodeId: nodeId,
|
|
11221
|
-
// <--- ID do node pai (link visual)
|
|
11222
11581
|
_branchDirection: direction
|
|
11223
|
-
// <--- Direção para cálculo de posição
|
|
11224
11582
|
};
|
|
11225
11583
|
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
11226
11584
|
const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
|
|
@@ -11276,7 +11634,6 @@ function XViewScene({
|
|
|
11276
11634
|
const parentAncestryObj = {
|
|
11277
11635
|
...targetAncestryInfo,
|
|
11278
11636
|
tree: targetTreeToRender,
|
|
11279
|
-
// Re-injeta a origem se o pai também for uma branch aninhada
|
|
11280
11637
|
_originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
|
|
11281
11638
|
_branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
|
|
11282
11639
|
};
|
|
@@ -11324,7 +11681,7 @@ function XViewScene({
|
|
|
11324
11681
|
}));
|
|
11325
11682
|
}
|
|
11326
11683
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
11327
|
-
const handleReadModeHighlight =
|
|
11684
|
+
const handleReadModeHighlight = useCallback4((nodeId) => {
|
|
11328
11685
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
11329
11686
|
stateRef.current.highlightedNodeId = nodeId;
|
|
11330
11687
|
}
|
|
@@ -11336,7 +11693,6 @@ function XViewScene({
|
|
|
11336
11693
|
readingMode.ancestry.tree,
|
|
11337
11694
|
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
11338
11695
|
ancestryDataRef.current
|
|
11339
|
-
// <--- Adicionar
|
|
11340
11696
|
);
|
|
11341
11697
|
const findNodeInTree = (tree, targetId) => {
|
|
11342
11698
|
if (!tree) return null;
|
|
@@ -11390,7 +11746,6 @@ function XViewScene({
|
|
|
11390
11746
|
description_sections: ancestry.description_sections,
|
|
11391
11747
|
direction: null,
|
|
11392
11748
|
customProperties: rootProps
|
|
11393
|
-
// <--- ADICIONADO
|
|
11394
11749
|
};
|
|
11395
11750
|
}
|
|
11396
11751
|
const fullTree = buildFullAncestryTree(
|
|
@@ -11419,7 +11774,6 @@ function XViewScene({
|
|
|
11419
11774
|
description_sections: currentMeta.description_sections,
|
|
11420
11775
|
direction: currentDirection,
|
|
11421
11776
|
customProperties: branchProps
|
|
11422
|
-
// <--- ADICIONADO
|
|
11423
11777
|
};
|
|
11424
11778
|
}, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11425
11779
|
const readModeAbstractionTree = useMemo12(() => {
|
|
@@ -11434,7 +11788,7 @@ function XViewScene({
|
|
|
11434
11788
|
allAncestries
|
|
11435
11789
|
);
|
|
11436
11790
|
}, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
|
|
11437
|
-
const handleStartReadingAncestry =
|
|
11791
|
+
const handleStartReadingAncestry = useCallback4(
|
|
11438
11792
|
async (ancestryObject) => {
|
|
11439
11793
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11440
11794
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11455,7 +11809,6 @@ function XViewScene({
|
|
|
11455
11809
|
ancestry: ancestryObject,
|
|
11456
11810
|
branchStack: [],
|
|
11457
11811
|
autoAbstraction: shouldAutoRenderAbstraction
|
|
11458
|
-
// <--- FLAG ENVIADA PARA A UI
|
|
11459
11812
|
});
|
|
11460
11813
|
if (shouldAutoRenderAbstraction) {
|
|
11461
11814
|
handleRenderAbstractionTree(ancestryObject, null);
|
|
@@ -11469,9 +11822,8 @@ function XViewScene({
|
|
|
11469
11822
|
}
|
|
11470
11823
|
},
|
|
11471
11824
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
11472
|
-
// <--- DEPENDÊNCIA ADICIONADA
|
|
11473
11825
|
);
|
|
11474
|
-
const handleReadModeSectionChange =
|
|
11826
|
+
const handleReadModeSectionChange = useCallback4((activeSectionId) => {
|
|
11475
11827
|
const { ancestry, branchStack } = readingMode;
|
|
11476
11828
|
if (!ancestry || !readingMode.isActive) return;
|
|
11477
11829
|
let targetObj = ancestry;
|
|
@@ -11540,10 +11892,10 @@ function XViewScene({
|
|
|
11540
11892
|
}, 0);
|
|
11541
11893
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11542
11894
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11543
|
-
const handleCloseReadMode =
|
|
11895
|
+
const handleCloseReadMode = useCallback4(() => {
|
|
11544
11896
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
11545
11897
|
}, []);
|
|
11546
|
-
const handleAncestrySectionChange =
|
|
11898
|
+
const handleAncestrySectionChange = useCallback4((activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
11547
11899
|
var _a2, _b2;
|
|
11548
11900
|
const currentMode = stateRef.current.ancestry;
|
|
11549
11901
|
let targetObj = ancestryOverride;
|
|
@@ -11595,7 +11947,7 @@ function XViewScene({
|
|
|
11595
11947
|
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
11596
11948
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11597
11949
|
}, [handleRenderAncestry]);
|
|
11598
|
-
const handleEditAncestry =
|
|
11950
|
+
const handleEditAncestry = useCallback4(
|
|
11599
11951
|
async (ancestryObject) => {
|
|
11600
11952
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11601
11953
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11618,10 +11970,8 @@ function XViewScene({
|
|
|
11618
11970
|
...ancestryObject,
|
|
11619
11971
|
tree: fullTree,
|
|
11620
11972
|
abstraction_tree: fullAbstractionTree,
|
|
11621
|
-
// NOVO
|
|
11622
11973
|
selectedParentId: ancestryObject.ancestral_node,
|
|
11623
11974
|
selectedAbstractionParentId: ancestryObject.ancestral_node,
|
|
11624
|
-
// NOVO
|
|
11625
11975
|
isEditMode: true,
|
|
11626
11976
|
currentAncestryId: ancestryObject.ancestry_id,
|
|
11627
11977
|
ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
|
|
@@ -11629,7 +11979,6 @@ function XViewScene({
|
|
|
11629
11979
|
ancestryDescriptionSections: ancestryObject.description_sections || [],
|
|
11630
11980
|
isAddingNodes: false,
|
|
11631
11981
|
isAddingAbstractionNodes: false
|
|
11632
|
-
// NOVO
|
|
11633
11982
|
});
|
|
11634
11983
|
},
|
|
11635
11984
|
[handleRenderAncestry, buildFullAncestryTree]
|
|
@@ -11637,7 +11986,7 @@ function XViewScene({
|
|
|
11637
11986
|
const handleSelectAncestryParent = (nodeId) => {
|
|
11638
11987
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
11639
11988
|
};
|
|
11640
|
-
const handleRemoveFromAncestry =
|
|
11989
|
+
const handleRemoveFromAncestry = useCallback4((pathToRemove) => {
|
|
11641
11990
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
11642
11991
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
11643
11992
|
return;
|
|
@@ -11662,7 +12011,7 @@ function XViewScene({
|
|
|
11662
12011
|
return { ...prev, tree: newTree };
|
|
11663
12012
|
});
|
|
11664
12013
|
}, []);
|
|
11665
|
-
const handleSaveAncestry =
|
|
12014
|
+
const handleSaveAncestry = useCallback4(
|
|
11666
12015
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
11667
12016
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
11668
12017
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -11866,7 +12215,7 @@ function XViewScene({
|
|
|
11866
12215
|
});
|
|
11867
12216
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
11868
12217
|
};
|
|
11869
|
-
const handleDeleteAncestry =
|
|
12218
|
+
const handleDeleteAncestry = useCallback4(
|
|
11870
12219
|
async (ancestryIdToDelete) => {
|
|
11871
12220
|
if (!ancestryIdToDelete) {
|
|
11872
12221
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -11928,15 +12277,15 @@ function XViewScene({
|
|
|
11928
12277
|
},
|
|
11929
12278
|
[save_view_data, delete_file_action]
|
|
11930
12279
|
);
|
|
11931
|
-
const handleOpenAncestryBoard =
|
|
12280
|
+
const handleOpenAncestryBoard = useCallback4(() => {
|
|
11932
12281
|
setIsAncestryBoardOpen(true);
|
|
11933
12282
|
}, []);
|
|
11934
|
-
const handleSelectAncestryFromBoard =
|
|
12283
|
+
const handleSelectAncestryFromBoard = useCallback4((ancestry) => {
|
|
11935
12284
|
setIsAncestryBoardOpen(false);
|
|
11936
12285
|
setIsSidebarOpen(false);
|
|
11937
12286
|
handleStartReadingAncestry(ancestry);
|
|
11938
12287
|
}, [handleStartReadingAncestry]);
|
|
11939
|
-
const handleSaveAncestryBoard =
|
|
12288
|
+
const handleSaveAncestryBoard = useCallback4(async (groups) => {
|
|
11940
12289
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
11941
12290
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
11942
12291
|
await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
|
|
@@ -11960,13 +12309,13 @@ function XViewScene({
|
|
|
11960
12309
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
11961
12310
|
});
|
|
11962
12311
|
}, [parentDataRef.current, sceneVersion]);
|
|
11963
|
-
const handleAddExistingNode =
|
|
12312
|
+
const handleAddExistingNode = useCallback4(
|
|
11964
12313
|
(nodeId) => {
|
|
11965
12314
|
return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
|
|
11966
12315
|
},
|
|
11967
12316
|
[actionHandlerContext]
|
|
11968
12317
|
);
|
|
11969
|
-
const handleSaveCurrentView =
|
|
12318
|
+
const handleSaveCurrentView = useCallback4(async () => {
|
|
11970
12319
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
11971
12320
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
11972
12321
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12006,7 +12355,7 @@ function XViewScene({
|
|
|
12006
12355
|
const allAvailableAncestries = useMemo12(() => {
|
|
12007
12356
|
return ancestryDataRef.current || [];
|
|
12008
12357
|
}, [sceneVersion, isInitialized]);
|
|
12009
|
-
const handleOpenReference =
|
|
12358
|
+
const handleOpenReference = useCallback4((referenceData) => {
|
|
12010
12359
|
const { type, id } = referenceData;
|
|
12011
12360
|
if (type === "node") {
|
|
12012
12361
|
const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
|
|
@@ -12033,16 +12382,28 @@ function XViewScene({
|
|
|
12033
12382
|
}
|
|
12034
12383
|
}
|
|
12035
12384
|
}, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
|
|
12036
|
-
const handleToggleAncestryAddMode =
|
|
12385
|
+
const handleToggleAncestryAddMode = useCallback4(() => {
|
|
12037
12386
|
setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
|
|
12038
12387
|
}, []);
|
|
12039
|
-
const handleFocusNode =
|
|
12388
|
+
const handleFocusNode = useCallback4((nodeData) => {
|
|
12040
12389
|
if (!nodeData) return;
|
|
12041
12390
|
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
12042
12391
|
if (nodeMesh) {
|
|
12043
12392
|
tweenToTarget(nodeMesh, 1.2);
|
|
12044
12393
|
}
|
|
12045
12394
|
}, [tweenToTarget]);
|
|
12395
|
+
const availableDatasets = useMemo12(() => {
|
|
12396
|
+
if (!sceneDataRef.current || !parentDataRef.current) return [];
|
|
12397
|
+
return sceneDataRef.current.parent_dbs.map((db) => {
|
|
12398
|
+
var _a2;
|
|
12399
|
+
return {
|
|
12400
|
+
id: db.db_id,
|
|
12401
|
+
name: ((_a2 = parentDataRef.current[db.db_id]) == null ? void 0 : _a2.dataset_name) || `Dataset #${db.db_id.substring(0, 6)}`
|
|
12402
|
+
};
|
|
12403
|
+
});
|
|
12404
|
+
}, [sceneVersion, isInitialized]);
|
|
12405
|
+
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
|
|
12406
|
+
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
12046
12407
|
useEffect21(() => {
|
|
12047
12408
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
12048
12409
|
const nodeObjects = stateRef.current.nodeObjects || {};
|
|
@@ -12094,7 +12455,6 @@ function XViewScene({
|
|
|
12094
12455
|
height: "100vh",
|
|
12095
12456
|
position: "relative",
|
|
12096
12457
|
overflow: "hidden",
|
|
12097
|
-
// <--- ADICIONE ESTA LINHA
|
|
12098
12458
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
12099
12459
|
}
|
|
12100
12460
|
},
|
|
@@ -12132,10 +12492,13 @@ function XViewScene({
|
|
|
12132
12492
|
style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
12133
12493
|
refEl: formRef,
|
|
12134
12494
|
existingTypes: existingNodeTypes,
|
|
12135
|
-
initialColor: (
|
|
12136
|
-
sourceTypes: (
|
|
12495
|
+
initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
|
|
12496
|
+
sourceTypes: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.type,
|
|
12137
12497
|
onIntensityChange: handleGhostNodeIntensityChange,
|
|
12138
|
-
onUploadFile: upload_file_action
|
|
12498
|
+
onUploadFile: upload_file_action,
|
|
12499
|
+
availableDatasets,
|
|
12500
|
+
sourceNodeDatasetId,
|
|
12501
|
+
viewType: viewParams == null ? void 0 : viewParams.type
|
|
12139
12502
|
}
|
|
12140
12503
|
),
|
|
12141
12504
|
versionMode.isActive && /* @__PURE__ */ React23.createElement(
|
|
@@ -12150,17 +12513,28 @@ function XViewScene({
|
|
|
12150
12513
|
onMentionClick: handleAddExistingNode,
|
|
12151
12514
|
style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
12152
12515
|
refEl: formRef,
|
|
12153
|
-
fixedType: (
|
|
12154
|
-
fixedColor: (
|
|
12516
|
+
fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
|
|
12517
|
+
fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
|
|
12155
12518
|
onUploadFile: upload_file_action
|
|
12156
12519
|
}
|
|
12157
12520
|
),
|
|
12158
12521
|
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React23.createElement(
|
|
12159
12522
|
"div",
|
|
12160
12523
|
{
|
|
12161
|
-
className:
|
|
12162
|
-
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" }
|
|
12524
|
+
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"}`,
|
|
12525
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
12163
12526
|
},
|
|
12527
|
+
/* @__PURE__ */ React23.createElement(
|
|
12528
|
+
"div",
|
|
12529
|
+
{
|
|
12530
|
+
onPointerDown: (e) => {
|
|
12531
|
+
e.stopPropagation();
|
|
12532
|
+
handleReadModeResize(e);
|
|
12533
|
+
},
|
|
12534
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
12535
|
+
title: "Arraste para redimensionar"
|
|
12536
|
+
}
|
|
12537
|
+
),
|
|
12164
12538
|
/* @__PURE__ */ React23.createElement(
|
|
12165
12539
|
DescriptionReadModePanel,
|
|
12166
12540
|
{
|
|
@@ -12260,7 +12634,8 @@ function XViewScene({
|
|
|
12260
12634
|
onMentionClick: handleAddExistingNode,
|
|
12261
12635
|
onIntensityChange: handleDetailNodeIntensityChange,
|
|
12262
12636
|
onUploadFile: upload_file_action,
|
|
12263
|
-
userRole: userPermissionRole
|
|
12637
|
+
userRole: userPermissionRole,
|
|
12638
|
+
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
12264
12639
|
}
|
|
12265
12640
|
),
|
|
12266
12641
|
detailsLink && /* @__PURE__ */ React23.createElement(
|
|
@@ -12388,7 +12763,7 @@ function XViewScene({
|
|
|
12388
12763
|
onClose: () => setIsImportModalOpen(false),
|
|
12389
12764
|
onConfirm: handleConfirmImport,
|
|
12390
12765
|
session,
|
|
12391
|
-
parentDbs: ((
|
|
12766
|
+
parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
|
|
12392
12767
|
onFetchAvailableFiles: import_parent_file_modal_get,
|
|
12393
12768
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
12394
12769
|
currentAncestries: ancestryDataRef.current || []
|