@lv-x-software-house/x_view 1.2.2-dev.2 → 1.2.2-dev.21
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 +1328 -888
- package/dist/index.mjs +787 -347
- 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) {
|
|
@@ -3847,6 +3977,70 @@ function DescriptionEditModal({
|
|
|
3847
3977
|
setIsMentionModalOpen(true);
|
|
3848
3978
|
}
|
|
3849
3979
|
};
|
|
3980
|
+
const handleKeyDownTextarea = (e) => {
|
|
3981
|
+
const el = textareaRef.current;
|
|
3982
|
+
if (!el) return;
|
|
3983
|
+
if (e.key === "Enter") {
|
|
3984
|
+
const cursorPosition = el.selectionStart;
|
|
3985
|
+
const textBeforeCursor = text.substring(0, cursorPosition);
|
|
3986
|
+
const linesBeforeCursor = textBeforeCursor.split("\n");
|
|
3987
|
+
const currentLine = linesBeforeCursor[linesBeforeCursor.length - 1];
|
|
3988
|
+
const numberMatch = currentLine.match(/^(\s*)(\d+)\.\s(.*)/);
|
|
3989
|
+
if (numberMatch) {
|
|
3990
|
+
e.preventDefault();
|
|
3991
|
+
const space = numberMatch[1];
|
|
3992
|
+
const number = parseInt(numberMatch[2], 10);
|
|
3993
|
+
const content = numberMatch[3];
|
|
3994
|
+
if (content.trim() === "") {
|
|
3995
|
+
const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
|
|
3996
|
+
const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
|
|
3997
|
+
el.value = newText;
|
|
3998
|
+
el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
|
|
3999
|
+
setText(newText);
|
|
4000
|
+
return;
|
|
4001
|
+
}
|
|
4002
|
+
const nextNumber = number + 1;
|
|
4003
|
+
insertAtCursor(`
|
|
4004
|
+
${space}${nextNumber}. `);
|
|
4005
|
+
return;
|
|
4006
|
+
}
|
|
4007
|
+
const checklistMatch = currentLine.match(/^(\s*)- \[[ xX]\]\s(.*)/);
|
|
4008
|
+
if (checklistMatch) {
|
|
4009
|
+
e.preventDefault();
|
|
4010
|
+
const space = checklistMatch[1];
|
|
4011
|
+
const content = checklistMatch[2];
|
|
4012
|
+
if (content.trim() === "") {
|
|
4013
|
+
const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
|
|
4014
|
+
const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
|
|
4015
|
+
el.value = newText;
|
|
4016
|
+
el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
|
|
4017
|
+
setText(newText);
|
|
4018
|
+
return;
|
|
4019
|
+
}
|
|
4020
|
+
insertAtCursor(`
|
|
4021
|
+
${space}- [ ] `);
|
|
4022
|
+
return;
|
|
4023
|
+
}
|
|
4024
|
+
const bulletMatch = currentLine.match(/^(\s*)([-*])\s(.*)/);
|
|
4025
|
+
if (bulletMatch) {
|
|
4026
|
+
e.preventDefault();
|
|
4027
|
+
const space = bulletMatch[1];
|
|
4028
|
+
const bullet = bulletMatch[2];
|
|
4029
|
+
const content = bulletMatch[3];
|
|
4030
|
+
if (content.trim() === "") {
|
|
4031
|
+
const newTextBeforeCursor = textBeforeCursor.substring(0, textBeforeCursor.length - currentLine.length);
|
|
4032
|
+
const newText = newTextBeforeCursor + "\n" + text.substring(el.selectionEnd);
|
|
4033
|
+
el.value = newText;
|
|
4034
|
+
el.setSelectionRange(newTextBeforeCursor.length + 1, newTextBeforeCursor.length + 1);
|
|
4035
|
+
setText(newText);
|
|
4036
|
+
return;
|
|
4037
|
+
}
|
|
4038
|
+
insertAtCursor(`
|
|
4039
|
+
${space}${bullet} `);
|
|
4040
|
+
return;
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
};
|
|
3850
4044
|
const openMentionModalViaButton = () => {
|
|
3851
4045
|
setMentionTriggerIndex(null);
|
|
3852
4046
|
setIsMentionModalOpen(true);
|
|
@@ -3856,7 +4050,8 @@ function DescriptionEditModal({
|
|
|
3856
4050
|
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
4051
|
"div",
|
|
3858
4052
|
{
|
|
3859
|
-
className:
|
|
4053
|
+
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"}`,
|
|
4054
|
+
style: { width: `${panelWidth}px`, maxWidth: "90vw" },
|
|
3860
4055
|
onClick: swallow,
|
|
3861
4056
|
onPointerDown: swallow,
|
|
3862
4057
|
onPointerMove: swallow,
|
|
@@ -3865,9 +4060,20 @@ function DescriptionEditModal({
|
|
|
3865
4060
|
onContextMenu: swallow,
|
|
3866
4061
|
onDoubleClick: swallow
|
|
3867
4062
|
},
|
|
4063
|
+
/* @__PURE__ */ React5.createElement(
|
|
4064
|
+
"div",
|
|
4065
|
+
{
|
|
4066
|
+
onPointerDown: (e) => {
|
|
4067
|
+
e.stopPropagation();
|
|
4068
|
+
handleResize(e);
|
|
4069
|
+
},
|
|
4070
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
4071
|
+
title: "Arraste para redimensionar"
|
|
4072
|
+
}
|
|
4073
|
+
),
|
|
3868
4074
|
/* @__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
4075
|
/* @__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
|
-
/* @__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
|
|
4076
|
+
/* @__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 flex-wrap" }, /* @__PURE__ */ React5.createElement(
|
|
3871
4077
|
"button",
|
|
3872
4078
|
{
|
|
3873
4079
|
onClick: () => insertAtCursor("# "),
|
|
@@ -3894,6 +4100,24 @@ function DescriptionEditModal({
|
|
|
3894
4100
|
},
|
|
3895
4101
|
/* @__PURE__ */ React5.createElement(FiList, { size: 12 }),
|
|
3896
4102
|
" Lista"
|
|
4103
|
+
), /* @__PURE__ */ React5.createElement(
|
|
4104
|
+
"button",
|
|
4105
|
+
{
|
|
4106
|
+
onClick: () => insertAtCursor("1. "),
|
|
4107
|
+
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",
|
|
4108
|
+
title: "Lista Numerada"
|
|
4109
|
+
},
|
|
4110
|
+
/* @__PURE__ */ React5.createElement("span", { className: "text-[10px] font-bold" }, "1."),
|
|
4111
|
+
" Numerada"
|
|
4112
|
+
), /* @__PURE__ */ React5.createElement(
|
|
4113
|
+
"button",
|
|
4114
|
+
{
|
|
4115
|
+
onClick: () => insertAtCursor("- [ ] "),
|
|
4116
|
+
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",
|
|
4117
|
+
title: "Checklist (Checkbox)"
|
|
4118
|
+
},
|
|
4119
|
+
/* @__PURE__ */ React5.createElement(FiCheckSquare, { size: 12 }),
|
|
4120
|
+
" Checklist"
|
|
3897
4121
|
), /* @__PURE__ */ React5.createElement(
|
|
3898
4122
|
"button",
|
|
3899
4123
|
{
|
|
@@ -3921,7 +4145,7 @@ function DescriptionEditModal({
|
|
|
3921
4145
|
},
|
|
3922
4146
|
/* @__PURE__ */ React5.createElement(FiImage, { size: 12 }),
|
|
3923
4147
|
" Imagem"
|
|
3924
|
-
)), /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2
|
|
4148
|
+
)), /* @__PURE__ */ React5.createElement("div", { className: "flex items-center gap-2 flex-wrap" }, /* @__PURE__ */ React5.createElement(
|
|
3925
4149
|
"button",
|
|
3926
4150
|
{
|
|
3927
4151
|
onClick: openMentionModalViaButton,
|
|
@@ -3954,6 +4178,7 @@ function DescriptionEditModal({
|
|
|
3954
4178
|
ref: textareaRef,
|
|
3955
4179
|
value: text,
|
|
3956
4180
|
onChange: handleTextChange,
|
|
4181
|
+
onKeyDown: handleKeyDownTextarea,
|
|
3957
4182
|
placeholder: "Escreva aqui... Use *// para dividir o texto em 'Sess\xF5es'... Digite @ para mencionar...",
|
|
3958
4183
|
autoFocus: true,
|
|
3959
4184
|
className: "w-full flex-1 h-full bg-slate-800/70 p-4 text-sm leading-relaxed rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 custom-scrollbar font-mono resize-none"
|
|
@@ -4029,7 +4254,7 @@ function DescriptionEditModal({
|
|
|
4029
4254
|
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
4255
|
},
|
|
4031
4256
|
"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"))))
|
|
4257
|
+
))), /* @__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
4258
|
/* @__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
4259
|
)), tooltipData && /* @__PURE__ */ React5.createElement(
|
|
4035
4260
|
"div",
|
|
@@ -4056,11 +4281,11 @@ function DescriptionEditModal({
|
|
|
4056
4281
|
}
|
|
4057
4282
|
|
|
4058
4283
|
// 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";
|
|
4284
|
+
import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
|
|
4285
|
+
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
4286
|
var CodeBlock2 = ({ content, isActive, onClick }) => {
|
|
4062
|
-
const [isExpanded, setIsExpanded] =
|
|
4063
|
-
const [copied, setCopied] =
|
|
4287
|
+
const [isExpanded, setIsExpanded] = useState7(false);
|
|
4288
|
+
const [copied, setCopied] = useState7(false);
|
|
4064
4289
|
const cleanContent = content.replace(/^```|```$/g, "").trim();
|
|
4065
4290
|
const isLongCode = cleanContent.split("\n").length > 4;
|
|
4066
4291
|
const handleCopy = (e) => {
|
|
@@ -4200,7 +4425,7 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
|
|
|
4200
4425
|
);
|
|
4201
4426
|
});
|
|
4202
4427
|
};
|
|
4203
|
-
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
|
|
4428
|
+
var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
|
|
4204
4429
|
const trimmedLine = line.replace(/\r$/, "");
|
|
4205
4430
|
const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
|
|
4206
4431
|
if (line.startsWith("# ")) {
|
|
@@ -4211,9 +4436,46 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
|
|
|
4211
4436
|
const content = line.replace("## ", "");
|
|
4212
4437
|
return /* @__PURE__ */ React6.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
|
|
4213
4438
|
}
|
|
4439
|
+
const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
|
|
4440
|
+
if (checkboxMatch) {
|
|
4441
|
+
const [_, space, state, content] = checkboxMatch;
|
|
4442
|
+
const isChecked = state.toLowerCase() === "x";
|
|
4443
|
+
const currentIdx = globalCheckboxCounterRef.current;
|
|
4444
|
+
globalCheckboxCounterRef.current += 1;
|
|
4445
|
+
return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1 group/checkbox" }, /* @__PURE__ */ React6.createElement(
|
|
4446
|
+
"div",
|
|
4447
|
+
{
|
|
4448
|
+
onClick: (e) => {
|
|
4449
|
+
e.stopPropagation();
|
|
4450
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4451
|
+
},
|
|
4452
|
+
className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
|
|
4453
|
+
${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"}
|
|
4454
|
+
`
|
|
4455
|
+
},
|
|
4456
|
+
isChecked && /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-white" })
|
|
4457
|
+
), /* @__PURE__ */ React6.createElement(
|
|
4458
|
+
"span",
|
|
4459
|
+
{
|
|
4460
|
+
className: `transition-all duration-200 cursor-pointer pt-[1px]
|
|
4461
|
+
${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
|
|
4462
|
+
`,
|
|
4463
|
+
onClick: (e) => {
|
|
4464
|
+
e.stopPropagation();
|
|
4465
|
+
if (onToggleCheckbox) onToggleCheckbox(currentIdx);
|
|
4466
|
+
}
|
|
4467
|
+
},
|
|
4468
|
+
processContent(content)
|
|
4469
|
+
));
|
|
4470
|
+
}
|
|
4471
|
+
const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
|
|
4472
|
+
if (numberMatch) {
|
|
4473
|
+
const [_, space, numberStr, content] = numberMatch;
|
|
4474
|
+
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)));
|
|
4475
|
+
}
|
|
4214
4476
|
if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
|
|
4215
4477
|
const content = trimmedLine.trim().substring(2);
|
|
4216
|
-
return /* @__PURE__ */ React6.createElement("span", { className: "
|
|
4478
|
+
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
4479
|
}
|
|
4218
4480
|
return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
|
|
4219
4481
|
};
|
|
@@ -4225,14 +4487,31 @@ function DescriptionDisplay({
|
|
|
4225
4487
|
onOpenReference,
|
|
4226
4488
|
onMentionClick,
|
|
4227
4489
|
onImageClick,
|
|
4228
|
-
// <--- NOVA PROP RECEBIDA
|
|
4229
4490
|
onSectionChange,
|
|
4230
4491
|
onBranchNav,
|
|
4231
4492
|
onHighlightNode,
|
|
4232
4493
|
initialSectionId,
|
|
4233
|
-
currentBranchDirection = null
|
|
4494
|
+
currentBranchDirection = null,
|
|
4495
|
+
onSaveDescription
|
|
4234
4496
|
}) {
|
|
4235
|
-
const
|
|
4497
|
+
const [localDescription, setLocalDescription] = useState7(description || "");
|
|
4498
|
+
useEffect6(() => {
|
|
4499
|
+
setLocalDescription(description || "");
|
|
4500
|
+
}, [description]);
|
|
4501
|
+
const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
|
|
4502
|
+
const globalCheckboxCounterRef = useRef6(0);
|
|
4503
|
+
const handleToggleCheckbox = (targetIndex) => {
|
|
4504
|
+
let currentIndex = 0;
|
|
4505
|
+
const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
|
|
4506
|
+
if (currentIndex === targetIndex) {
|
|
4507
|
+
currentIndex++;
|
|
4508
|
+
return state === " " ? `${space}- [x]` : `${space}- [ ]`;
|
|
4509
|
+
}
|
|
4510
|
+
currentIndex++;
|
|
4511
|
+
return match;
|
|
4512
|
+
});
|
|
4513
|
+
setLocalDescription(newDesc);
|
|
4514
|
+
};
|
|
4236
4515
|
const flatNavigation = useMemo5(() => {
|
|
4237
4516
|
const navItems = [];
|
|
4238
4517
|
sections.forEach((section, sIdx) => {
|
|
@@ -4259,7 +4538,7 @@ function DescriptionDisplay({
|
|
|
4259
4538
|
});
|
|
4260
4539
|
return navItems;
|
|
4261
4540
|
}, [sections]);
|
|
4262
|
-
const [currentStepIndex, setCurrentStepIndex] =
|
|
4541
|
+
const [currentStepIndex, setCurrentStepIndex] = useState7(0);
|
|
4263
4542
|
const activeRef = useRef6(null);
|
|
4264
4543
|
const lastNotifiedSectionId = useRef6(null);
|
|
4265
4544
|
const isInitialMount = useRef6(true);
|
|
@@ -4373,26 +4652,27 @@ function DescriptionDisplay({
|
|
|
4373
4652
|
}
|
|
4374
4653
|
const lines = part.replace(/\n$/, "").split("\n");
|
|
4375
4654
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
|
|
4376
|
-
const isLastLine = lineIndex === lines.length - 1;
|
|
4377
4655
|
const isEmptyLine = line.trim() === "";
|
|
4378
4656
|
if (isEmptyLine) {
|
|
4379
4657
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
|
|
4380
4658
|
}
|
|
4381
4659
|
return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
|
|
4382
|
-
"
|
|
4660
|
+
"div",
|
|
4383
4661
|
{
|
|
4384
4662
|
ref: isActiveSection && activeMentionIndex === -1 && partIndex === 0 && lineIndex === 0 ? setRef : null,
|
|
4385
|
-
onClick: () => {
|
|
4386
|
-
|
|
4387
|
-
|
|
4663
|
+
onClick: (e) => {
|
|
4664
|
+
if (e.target.type !== "checkbox") {
|
|
4665
|
+
const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
|
|
4666
|
+
if (idx !== -1) setCurrentStepIndex(idx);
|
|
4667
|
+
}
|
|
4388
4668
|
},
|
|
4389
4669
|
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/
|
|
4670
|
+
transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
|
|
4671
|
+
${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
|
|
4392
4672
|
`
|
|
4393
4673
|
},
|
|
4394
|
-
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
|
|
4395
|
-
)
|
|
4674
|
+
formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
|
|
4675
|
+
));
|
|
4396
4676
|
}));
|
|
4397
4677
|
});
|
|
4398
4678
|
};
|
|
@@ -4420,7 +4700,9 @@ function DescriptionDisplay({
|
|
|
4420
4700
|
${isActiveSection ? "opacity-100" : "opacity-90"}
|
|
4421
4701
|
` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
|
|
4422
4702
|
};
|
|
4423
|
-
|
|
4703
|
+
globalCheckboxCounterRef.current = 0;
|
|
4704
|
+
const hasUnsavedChanges = localDescription !== (description || "");
|
|
4705
|
+
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
4706
|
const currentNavItem = flatNavigation[currentStepIndex];
|
|
4425
4707
|
const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
|
|
4426
4708
|
const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
|
|
@@ -4436,11 +4718,22 @@ function DescriptionDisplay({
|
|
|
4436
4718
|
if (index === 0) leadingSpace = "";
|
|
4437
4719
|
const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
|
|
4438
4720
|
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
|
-
}))
|
|
4721
|
+
})), 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(
|
|
4722
|
+
"button",
|
|
4723
|
+
{
|
|
4724
|
+
onClick: (e) => {
|
|
4725
|
+
e.stopPropagation();
|
|
4726
|
+
onSaveDescription(localDescription);
|
|
4727
|
+
},
|
|
4728
|
+
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"
|
|
4729
|
+
},
|
|
4730
|
+
/* @__PURE__ */ React6.createElement(FiSave, { size: 12 }),
|
|
4731
|
+
" Salvar Checklist"
|
|
4732
|
+
)));
|
|
4440
4733
|
}
|
|
4441
4734
|
|
|
4442
4735
|
// src/components/DescriptionReadModePanel.jsx
|
|
4443
|
-
import React7, { useState as
|
|
4736
|
+
import React7, { useState as useState8, useMemo as useMemo6, useEffect as useEffect7 } from "react";
|
|
4444
4737
|
import {
|
|
4445
4738
|
FiArrowLeft,
|
|
4446
4739
|
FiEdit2,
|
|
@@ -4519,7 +4812,6 @@ function DescriptionReadModePanel({
|
|
|
4519
4812
|
title,
|
|
4520
4813
|
description,
|
|
4521
4814
|
ancestryId,
|
|
4522
|
-
// <-- NOVO: Prop recebida do XViewScene
|
|
4523
4815
|
savedSections,
|
|
4524
4816
|
onBack,
|
|
4525
4817
|
onEdit,
|
|
@@ -4541,12 +4833,13 @@ function DescriptionReadModePanel({
|
|
|
4541
4833
|
userRole,
|
|
4542
4834
|
abstractionTree = null,
|
|
4543
4835
|
onRenderAbstractionTree = null,
|
|
4544
|
-
initialShowAbstraction = false
|
|
4836
|
+
initialShowAbstraction = false,
|
|
4837
|
+
onSaveDescription
|
|
4545
4838
|
}) {
|
|
4546
|
-
const [showProperties, setShowProperties] =
|
|
4547
|
-
const [showAbstraction, setShowAbstraction] =
|
|
4548
|
-
const [targetRenderNodeId, setTargetRenderNodeId] =
|
|
4549
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
4839
|
+
const [showProperties, setShowProperties] = useState8(false);
|
|
4840
|
+
const [showAbstraction, setShowAbstraction] = useState8(false);
|
|
4841
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState8(null);
|
|
4842
|
+
const [isLinkCopied, setIsLinkCopied] = useState8(false);
|
|
4550
4843
|
const handleCopyLink = (e) => {
|
|
4551
4844
|
e.stopPropagation();
|
|
4552
4845
|
if (!ancestryId) return;
|
|
@@ -4628,7 +4921,7 @@ function DescriptionReadModePanel({
|
|
|
4628
4921
|
return /* @__PURE__ */ React7.createElement(
|
|
4629
4922
|
"div",
|
|
4630
4923
|
{
|
|
4631
|
-
className: "flex flex-col h-full w-full bg-slate-950/50 relative overflow-hidden group",
|
|
4924
|
+
className: "flex flex-col h-full max-h-full w-full bg-slate-950/50 relative overflow-hidden group min-h-0",
|
|
4632
4925
|
onPointerDown: swallow,
|
|
4633
4926
|
onClick: swallow
|
|
4634
4927
|
},
|
|
@@ -4700,7 +4993,7 @@ function DescriptionReadModePanel({
|
|
|
4700
4993
|
},
|
|
4701
4994
|
"\xD7"
|
|
4702
4995
|
))),
|
|
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(
|
|
4996
|
+
/* @__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
4997
|
"button",
|
|
4705
4998
|
{
|
|
4706
4999
|
onClick: (e) => {
|
|
@@ -4759,7 +5052,8 @@ function DescriptionReadModePanel({
|
|
|
4759
5052
|
onHighlightNode,
|
|
4760
5053
|
initialSectionId,
|
|
4761
5054
|
currentBranchDirection,
|
|
4762
|
-
onImageClick
|
|
5055
|
+
onImageClick,
|
|
5056
|
+
onSaveDescription
|
|
4763
5057
|
}
|
|
4764
5058
|
)),
|
|
4765
5059
|
leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
|
|
@@ -4801,11 +5095,11 @@ function AncestryRelationshipPanel({
|
|
|
4801
5095
|
onMentionClick,
|
|
4802
5096
|
onUploadFile
|
|
4803
5097
|
}) {
|
|
4804
|
-
const [description, setDescription] =
|
|
4805
|
-
const [customProps, setCustomProps] =
|
|
4806
|
-
const [existingSections, setExistingSections] =
|
|
4807
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
4808
|
-
const [isReadMode, setIsReadMode] =
|
|
5098
|
+
const [description, setDescription] = useState9((data == null ? void 0 : data.description) ?? "");
|
|
5099
|
+
const [customProps, setCustomProps] = useState9(() => extractCustomPropsFromNode(data || {}));
|
|
5100
|
+
const [existingSections, setExistingSections] = useState9((data == null ? void 0 : data.description_sections) || []);
|
|
5101
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState9(false);
|
|
5102
|
+
const [isReadMode, setIsReadMode] = useState9(false);
|
|
4809
5103
|
const propsEndRef = useRef7(null);
|
|
4810
5104
|
useEffect8(() => {
|
|
4811
5105
|
setDescription((data == null ? void 0 : data.description) ?? "");
|
|
@@ -4829,6 +5123,17 @@ function AncestryRelationshipPanel({
|
|
|
4829
5123
|
return newProps;
|
|
4830
5124
|
});
|
|
4831
5125
|
};
|
|
5126
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
5127
|
+
setDescription(newDescription);
|
|
5128
|
+
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
5129
|
+
const processedSections = processDescriptionForSave(newDescription, existingSections);
|
|
5130
|
+
const dataToSave = {
|
|
5131
|
+
description: newDescription,
|
|
5132
|
+
description_sections: processedSections,
|
|
5133
|
+
...extrasObj
|
|
5134
|
+
};
|
|
5135
|
+
onSave(dataToSave);
|
|
5136
|
+
};
|
|
4832
5137
|
const handleSave = () => {
|
|
4833
5138
|
const extrasObj = toObjectFromCustomProps(customProps.filter((p) => !p.isEditing));
|
|
4834
5139
|
const processedSections = processDescriptionForSave(description, existingSections);
|
|
@@ -4878,7 +5183,8 @@ function AncestryRelationshipPanel({
|
|
|
4878
5183
|
availableAncestries,
|
|
4879
5184
|
onOpenReference,
|
|
4880
5185
|
onMentionClick,
|
|
4881
|
-
onImageClick: handleImageClickFromText
|
|
5186
|
+
onImageClick: handleImageClickFromText,
|
|
5187
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4882
5188
|
}
|
|
4883
5189
|
) : /* @__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
5190
|
DescriptionDisplay,
|
|
@@ -4889,7 +5195,8 @@ function AncestryRelationshipPanel({
|
|
|
4889
5195
|
availableAncestries,
|
|
4890
5196
|
onOpenReference,
|
|
4891
5197
|
onMentionClick,
|
|
4892
|
-
onImageClick: handleImageClickFromText
|
|
5198
|
+
onImageClick: handleImageClickFromText,
|
|
5199
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
4893
5200
|
}
|
|
4894
5201
|
), /* @__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
5202
|
"button",
|
|
@@ -4947,7 +5254,7 @@ function AncestryRelationshipPanel({
|
|
|
4947
5254
|
}
|
|
4948
5255
|
|
|
4949
5256
|
// src/components/CreateAncestryPanel.jsx
|
|
4950
|
-
import React10, { useState as
|
|
5257
|
+
import React10, { useState as useState11, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef8, useCallback as useCallback2 } from "react";
|
|
4951
5258
|
import {
|
|
4952
5259
|
FiEdit2 as FiEdit23,
|
|
4953
5260
|
FiBookOpen as FiBookOpen2,
|
|
@@ -4967,7 +5274,7 @@ import {
|
|
|
4967
5274
|
} from "react-icons/fi";
|
|
4968
5275
|
|
|
4969
5276
|
// src/components/AncestryPickerModal.jsx
|
|
4970
|
-
import React9, { useState as
|
|
5277
|
+
import React9, { useState as useState10, useMemo as useMemo7, useEffect as useEffect9 } from "react";
|
|
4971
5278
|
import { FiSearch as FiSearch3, FiLayers as FiLayers4, FiCornerUpRight as FiCornerUpRight2 } from "react-icons/fi";
|
|
4972
5279
|
function AncestryPickerModal({
|
|
4973
5280
|
isOpen,
|
|
@@ -4977,7 +5284,7 @@ function AncestryPickerModal({
|
|
|
4977
5284
|
availableNodes = [],
|
|
4978
5285
|
currentAncestryId
|
|
4979
5286
|
}) {
|
|
4980
|
-
const [searchTerm, setSearchTerm] =
|
|
5287
|
+
const [searchTerm, setSearchTerm] = useState10("");
|
|
4981
5288
|
useEffect9(() => {
|
|
4982
5289
|
if (!isOpen) return;
|
|
4983
5290
|
const handleKeyDown = (e) => {
|
|
@@ -5062,7 +5369,7 @@ var NodeItem = ({ nodeData, onSelectParent, onViewSelect, highlightedPathIds = [
|
|
|
5062
5369
|
var _a, _b;
|
|
5063
5370
|
const itemId = nodeData.is_section ? nodeData.id : (_a = nodeData.node) == null ? void 0 : _a.id;
|
|
5064
5371
|
const itemName = nodeData.is_section ? nodeData.name : (_b = nodeData.node) == null ? void 0 : _b.name;
|
|
5065
|
-
const [isDragOver, setIsDragOver] =
|
|
5372
|
+
const [isDragOver, setIsDragOver] = useState11(false);
|
|
5066
5373
|
const isSelectedParent = String(selectedParentId) === String(itemId);
|
|
5067
5374
|
const isTargetViewNode = String(targetRenderNodeId) === String(itemId);
|
|
5068
5375
|
const isHighlightedPath = highlightedPathIds.includes(String(itemId));
|
|
@@ -5198,8 +5505,8 @@ function CreateAncestryPanel({
|
|
|
5198
5505
|
isAddingNodes,
|
|
5199
5506
|
currentAncestryId
|
|
5200
5507
|
} = ancestryMode;
|
|
5201
|
-
const [isSaving, setIsSaving] =
|
|
5202
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
5508
|
+
const [isSaving, setIsSaving] = useState11(false);
|
|
5509
|
+
const [isLinkCopied, setIsLinkCopied] = useState11(false);
|
|
5203
5510
|
const handleCopyLink = (e) => {
|
|
5204
5511
|
e.stopPropagation();
|
|
5205
5512
|
if (!currentAncestryId || currentAncestryId === "temp_root" || currentAncestryId === "temp_creating") {
|
|
@@ -5213,11 +5520,11 @@ function CreateAncestryPanel({
|
|
|
5213
5520
|
setTimeout(() => setIsLinkCopied(false), 2e3);
|
|
5214
5521
|
}).catch((err) => console.error("Erro ao copiar link:", err));
|
|
5215
5522
|
};
|
|
5216
|
-
const [isPickerOpen, setIsPickerOpen] =
|
|
5217
|
-
const [customProps, setCustomProps] =
|
|
5523
|
+
const [isPickerOpen, setIsPickerOpen] = useState11(false);
|
|
5524
|
+
const [customProps, setCustomProps] = useState11([]);
|
|
5218
5525
|
const propsEndRef = useRef8(null);
|
|
5219
|
-
const [branchStack, setBranchStack] =
|
|
5220
|
-
const [targetRenderNodeId, setTargetRenderNodeId] =
|
|
5526
|
+
const [branchStack, setBranchStack] = useState11([]);
|
|
5527
|
+
const [targetRenderNodeId, setTargetRenderNodeId] = useState11(null);
|
|
5221
5528
|
const highlightedPathIds = useMemo8(() => {
|
|
5222
5529
|
var _a, _b;
|
|
5223
5530
|
if (!targetRenderNodeId || !ancestryMode.abstraction_tree) return [];
|
|
@@ -5231,17 +5538,27 @@ function CreateAncestryPanel({
|
|
|
5231
5538
|
}
|
|
5232
5539
|
return ids;
|
|
5233
5540
|
}, [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] =
|
|
5541
|
+
const [targetScrollSectionId, setTargetScrollSectionId] = useState11(null);
|
|
5542
|
+
const [internalHighlightedNodeId, setInternalHighlightedNodeId] = useState11(null);
|
|
5543
|
+
const [ancestryName, setAncestryName] = useState11(initialName);
|
|
5544
|
+
const [description, setDescription] = useState11(initialDescription || "");
|
|
5545
|
+
const [existingSections, setExistingSections] = useState11(initialSections || []);
|
|
5546
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState11(false);
|
|
5547
|
+
const [isReadMode, setIsReadMode] = useState11(false);
|
|
5548
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
5549
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
5550
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
5551
|
+
minWidth: 320,
|
|
5552
|
+
maxWidth: maxPanelW
|
|
5553
|
+
});
|
|
5554
|
+
useEffect10(() => {
|
|
5555
|
+
setWidth(isReadMode ? 700 : 440);
|
|
5556
|
+
}, [isReadMode, setWidth]);
|
|
5241
5557
|
const currentMaxRenderIndexRef = useRef8(0);
|
|
5242
5558
|
const branchProgressMapRef = useRef8({});
|
|
5243
|
-
const [lastSavedSnapshot, setLastSavedSnapshot] =
|
|
5244
|
-
const [isPrivate, setIsPrivate] =
|
|
5559
|
+
const [lastSavedSnapshot, setLastSavedSnapshot] = useState11(null);
|
|
5560
|
+
const [isPrivate, setIsPrivate] = useState11(ancestryMode.is_private || false);
|
|
5561
|
+
const initializedContextIdRef = useRef8(null);
|
|
5245
5562
|
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
5246
5563
|
const handleImageClickFromText = (url, name) => {
|
|
5247
5564
|
if (onOpenImageViewer) {
|
|
@@ -5259,7 +5576,7 @@ function CreateAncestryPanel({
|
|
|
5259
5576
|
}
|
|
5260
5577
|
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
5261
5578
|
};
|
|
5262
|
-
const handleRemoveNode =
|
|
5579
|
+
const handleRemoveNode = useCallback2((pathToRemove, isAbstraction = false) => {
|
|
5263
5580
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
5264
5581
|
const treeKey = isAbstraction ? "abstraction_tree" : "tree";
|
|
5265
5582
|
setAncestryMode((prev) => {
|
|
@@ -5440,6 +5757,11 @@ function CreateAncestryPanel({
|
|
|
5440
5757
|
}, [isContextLinked, branchStack]);
|
|
5441
5758
|
useEffect10(() => {
|
|
5442
5759
|
const ctx = getCurrentContext();
|
|
5760
|
+
const currentContextId = branchStack.length > 0 ? branchStack[branchStack.length - 1].branchId : ancestryMode.currentAncestryId || `new_${ancestryMode.ancestral_node}`;
|
|
5761
|
+
if (initializedContextIdRef.current === currentContextId) {
|
|
5762
|
+
return;
|
|
5763
|
+
}
|
|
5764
|
+
initializedContextIdRef.current = currentContextId;
|
|
5443
5765
|
let sourceObject = {};
|
|
5444
5766
|
if (ctx) {
|
|
5445
5767
|
sourceObject = ctx;
|
|
@@ -5790,7 +6112,7 @@ function CreateAncestryPanel({
|
|
|
5790
6112
|
const currentAbsTreeStr = JSON.stringify(ancestryMode.abstraction_tree);
|
|
5791
6113
|
abstractionTreeChanged = currentAbsTreeStr !== lastSavedSnapshot.abstractionTree;
|
|
5792
6114
|
}
|
|
5793
|
-
return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged;
|
|
6115
|
+
return treeChanged || nameChanged || descChanged || sectionsChanged || propsChanged || privateChanged || abstractionTreeChanged;
|
|
5794
6116
|
}, [
|
|
5795
6117
|
ancestryName,
|
|
5796
6118
|
description,
|
|
@@ -6138,6 +6460,10 @@ function CreateAncestryPanel({
|
|
|
6138
6460
|
setInternalHighlightedNodeId(id);
|
|
6139
6461
|
if (onHighlightNode) onHighlightNode(id);
|
|
6140
6462
|
};
|
|
6463
|
+
const handleSaveDescriptionInline = (newDesc) => {
|
|
6464
|
+
setDescription(newDesc);
|
|
6465
|
+
handleLocalSave(true, { description: newDesc });
|
|
6466
|
+
};
|
|
6141
6467
|
const swallow = (e) => e.stopPropagation();
|
|
6142
6468
|
const getSelectedParentName = () => {
|
|
6143
6469
|
if (!activeTree || !selectedParentId) return "";
|
|
@@ -6210,10 +6536,8 @@ function CreateAncestryPanel({
|
|
|
6210
6536
|
return /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(
|
|
6211
6537
|
"div",
|
|
6212
6538
|
{
|
|
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)" },
|
|
6539
|
+
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"}`,
|
|
6540
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
6217
6541
|
onPointerDown: swallow,
|
|
6218
6542
|
onPointerMove: swallow,
|
|
6219
6543
|
onPointerUp: swallow,
|
|
@@ -6222,6 +6546,17 @@ function CreateAncestryPanel({
|
|
|
6222
6546
|
onContextMenu: swallow,
|
|
6223
6547
|
onDoubleClick: swallow
|
|
6224
6548
|
},
|
|
6549
|
+
/* @__PURE__ */ React10.createElement(
|
|
6550
|
+
"div",
|
|
6551
|
+
{
|
|
6552
|
+
onPointerDown: (e) => {
|
|
6553
|
+
e.stopPropagation();
|
|
6554
|
+
handleResize(e);
|
|
6555
|
+
},
|
|
6556
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
6557
|
+
title: "Arraste para redimensionar"
|
|
6558
|
+
}
|
|
6559
|
+
),
|
|
6225
6560
|
isReadMode ? /* @__PURE__ */ React10.createElement(
|
|
6226
6561
|
DescriptionReadModePanel,
|
|
6227
6562
|
{
|
|
@@ -6240,7 +6575,8 @@ function CreateAncestryPanel({
|
|
|
6240
6575
|
onMentionClick,
|
|
6241
6576
|
onSectionChange: handleSectionChangeWrapper,
|
|
6242
6577
|
onHighlightNode,
|
|
6243
|
-
onImageClick: handleImageClickFromText
|
|
6578
|
+
onImageClick: handleImageClickFromText,
|
|
6579
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
6244
6580
|
}
|
|
6245
6581
|
) : /* @__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
6582
|
"button",
|
|
@@ -6297,7 +6633,8 @@ function CreateAncestryPanel({
|
|
|
6297
6633
|
onHighlightNode: handleHighlightWrapper,
|
|
6298
6634
|
initialSectionId: targetScrollSectionId,
|
|
6299
6635
|
currentBranchDirection: currentContext ? currentContext.direction : null,
|
|
6300
|
-
onImageClick: handleImageClickFromText
|
|
6636
|
+
onImageClick: handleImageClickFromText,
|
|
6637
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
6301
6638
|
}
|
|
6302
6639
|
), /* @__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
6640
|
"button",
|
|
@@ -6518,25 +6855,25 @@ function CreateAncestryPanel({
|
|
|
6518
6855
|
}
|
|
6519
6856
|
|
|
6520
6857
|
// src/components/ImageViewer.jsx
|
|
6521
|
-
import React11, { useState as
|
|
6858
|
+
import React11, { useState as useState12, useEffect as useEffect11, useLayoutEffect as useLayoutEffect2, useCallback as useCallback3 } from "react";
|
|
6522
6859
|
import { FiX as FiX2, FiChevronLeft as FiChevronLeft3, FiChevronRight as FiChevronRight5 } from "react-icons/fi";
|
|
6523
6860
|
function ImageViewer({ data, onClose }) {
|
|
6524
6861
|
var _a;
|
|
6525
6862
|
const { images = [], startIndex = 0, visible } = data;
|
|
6526
|
-
const [currentIndex, setCurrentIndex] =
|
|
6527
|
-
const [isLoading, setIsLoading] =
|
|
6528
|
-
const [loadedSrc, setLoadedSrc] =
|
|
6863
|
+
const [currentIndex, setCurrentIndex] = useState12(startIndex);
|
|
6864
|
+
const [isLoading, setIsLoading] = useState12(false);
|
|
6865
|
+
const [loadedSrc, setLoadedSrc] = useState12(null);
|
|
6529
6866
|
useLayoutEffect2(() => {
|
|
6530
6867
|
if (visible) {
|
|
6531
6868
|
setCurrentIndex(startIndex);
|
|
6532
6869
|
}
|
|
6533
6870
|
}, [visible, startIndex]);
|
|
6534
|
-
const handleNext =
|
|
6871
|
+
const handleNext = useCallback3(() => {
|
|
6535
6872
|
if (images.length > 1) {
|
|
6536
6873
|
setCurrentIndex((prev) => (prev + 1) % images.length);
|
|
6537
6874
|
}
|
|
6538
6875
|
}, [images.length]);
|
|
6539
|
-
const handlePrev =
|
|
6876
|
+
const handlePrev = useCallback3(() => {
|
|
6540
6877
|
if (images.length > 1) {
|
|
6541
6878
|
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
|
|
6542
6879
|
}
|
|
@@ -6641,10 +6978,10 @@ function ImageViewer({ data, onClose }) {
|
|
|
6641
6978
|
}
|
|
6642
6979
|
|
|
6643
6980
|
// src/components/InSceneCreationForm.jsx
|
|
6644
|
-
import React13, { useState as
|
|
6981
|
+
import React13, { useState as useState14, useEffect as useEffect13, useRef as useRef10 } from "react";
|
|
6645
6982
|
|
|
6646
6983
|
// src/components/ColorPicker.jsx
|
|
6647
|
-
import React12, { useState as
|
|
6984
|
+
import React12, { useState as useState13, useEffect as useEffect12, useRef as useRef9 } from "react";
|
|
6648
6985
|
import { HexColorPicker } from "react-colorful";
|
|
6649
6986
|
import { FiHash, FiCheck as FiCheck6 } from "react-icons/fi";
|
|
6650
6987
|
var PRESET_COLORS = [
|
|
@@ -6665,7 +7002,7 @@ var PRESET_COLORS = [
|
|
|
6665
7002
|
"#000000"
|
|
6666
7003
|
];
|
|
6667
7004
|
function ColorPicker({ color, onChange, disabled }) {
|
|
6668
|
-
const [isOpen, setIsOpen] =
|
|
7005
|
+
const [isOpen, setIsOpen] = useState13(false);
|
|
6669
7006
|
const popoverRef = useRef9(null);
|
|
6670
7007
|
useEffect12(() => {
|
|
6671
7008
|
const handleClickOutside = (event) => {
|
|
@@ -6740,7 +7077,7 @@ function ColorPicker({ color, onChange, disabled }) {
|
|
|
6740
7077
|
}
|
|
6741
7078
|
|
|
6742
7079
|
// src/components/InSceneCreationForm.jsx
|
|
6743
|
-
import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun } from "react-icons/fi";
|
|
7080
|
+
import { FiPlus as FiPlus3, FiMaximize2, FiX as FiX3, FiCheck as FiCheck7, FiEdit2 as FiEdit24, FiSun, FiChevronDown as FiChevronDown4 } from "react-icons/fi";
|
|
6744
7081
|
function InSceneCreationForm({
|
|
6745
7082
|
onSave,
|
|
6746
7083
|
onCancel,
|
|
@@ -6758,21 +7095,44 @@ function InSceneCreationForm({
|
|
|
6758
7095
|
availableAncestries = [],
|
|
6759
7096
|
onMentionClick,
|
|
6760
7097
|
sourceTypes,
|
|
6761
|
-
onUploadFile
|
|
7098
|
+
onUploadFile,
|
|
7099
|
+
availableDatasets = [],
|
|
7100
|
+
sourceNodeDatasetId,
|
|
7101
|
+
viewType
|
|
6762
7102
|
}) {
|
|
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 [
|
|
7103
|
+
var _a;
|
|
7104
|
+
const [name, setName] = useState14("");
|
|
7105
|
+
const [types, setTypes] = useState14([]);
|
|
7106
|
+
const [typeInput, setTypeInput] = useState14("");
|
|
7107
|
+
const [color, setColor] = useState14(initialColor || "#cccccc");
|
|
7108
|
+
const [size, setSize] = useState14("medium");
|
|
7109
|
+
const [intensity, setIntensity] = useState14(0);
|
|
7110
|
+
const [description, setDescription] = useState14("");
|
|
7111
|
+
const [customProps, setCustomProps] = useState14([]);
|
|
7112
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState14(false);
|
|
7113
|
+
const [filteredTypes, setFilteredTypes] = useState14([]);
|
|
7114
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState14(false);
|
|
7115
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState14(false);
|
|
7116
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState14(null);
|
|
7117
|
+
const [targetDatasetId, setTargetDatasetId] = useState14(sourceNodeDatasetId || "");
|
|
7118
|
+
const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
|
|
7119
|
+
const datasetDropdownRef = useRef10(null);
|
|
7120
|
+
useEffect13(() => {
|
|
7121
|
+
if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
|
|
7122
|
+
}, [sourceNodeDatasetId]);
|
|
7123
|
+
useEffect13(() => {
|
|
7124
|
+
function handleClickOutside(event) {
|
|
7125
|
+
if (datasetDropdownRef.current && !datasetDropdownRef.current.contains(event.target)) {
|
|
7126
|
+
setIsDatasetDropdownOpen(false);
|
|
7127
|
+
}
|
|
7128
|
+
}
|
|
7129
|
+
if (isDatasetDropdownOpen) {
|
|
7130
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
7131
|
+
}
|
|
7132
|
+
return () => {
|
|
7133
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
7134
|
+
};
|
|
7135
|
+
}, [isDatasetDropdownOpen]);
|
|
6776
7136
|
const propsEndRef = useRef10(null);
|
|
6777
7137
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
6778
7138
|
useEffect13(() => {
|
|
@@ -6818,8 +7178,8 @@ function InSceneCreationForm({
|
|
|
6818
7178
|
const newProp = createNewCustomProperty(customProps);
|
|
6819
7179
|
setCustomProps([...customProps, newProp]);
|
|
6820
7180
|
setTimeout(() => {
|
|
6821
|
-
var
|
|
6822
|
-
(
|
|
7181
|
+
var _a2;
|
|
7182
|
+
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
6823
7183
|
}, 100);
|
|
6824
7184
|
};
|
|
6825
7185
|
const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
|
|
@@ -6852,12 +7212,12 @@ function InSceneCreationForm({
|
|
|
6852
7212
|
onSizeChange == null ? void 0 : onSizeChange(newSize);
|
|
6853
7213
|
};
|
|
6854
7214
|
const handleToggleImageMode = () => {
|
|
6855
|
-
var
|
|
7215
|
+
var _a2, _b;
|
|
6856
7216
|
const newValue = !useImageAsTexture;
|
|
6857
7217
|
setUseImageAsTexture(newValue);
|
|
6858
7218
|
if (newValue) {
|
|
6859
7219
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
6860
|
-
if (firstImageProp && ((_b = (
|
|
7220
|
+
if (firstImageProp && ((_b = (_a2 = firstImageProp.value) == null ? void 0 : _a2[0]) == null ? void 0 : _b.value)) {
|
|
6861
7221
|
const url = firstImageProp.value[0].value;
|
|
6862
7222
|
setSelectedImageUrl(url);
|
|
6863
7223
|
onImageChange == null ? void 0 : onImageChange(true, url);
|
|
@@ -6890,6 +7250,7 @@ function InSceneCreationForm({
|
|
|
6890
7250
|
description_sections: processedSections,
|
|
6891
7251
|
useImageAsTexture,
|
|
6892
7252
|
textureImageUrl: useImageAsTexture ? selectedImageUrl : null,
|
|
7253
|
+
targetDatasetId,
|
|
6893
7254
|
...additionalData
|
|
6894
7255
|
});
|
|
6895
7256
|
};
|
|
@@ -6910,6 +7271,7 @@ function InSceneCreationForm({
|
|
|
6910
7271
|
onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
|
|
6911
7272
|
}
|
|
6912
7273
|
};
|
|
7274
|
+
const selectedDatasetName = ((_a = availableDatasets.find((ds) => ds.id === targetDatasetId)) == null ? void 0 : _a.name) || "Selecione um Dataset...";
|
|
6913
7275
|
return /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(
|
|
6914
7276
|
"div",
|
|
6915
7277
|
{
|
|
@@ -6967,7 +7329,27 @@ function InSceneCreationForm({
|
|
|
6967
7329
|
}
|
|
6968
7330
|
},
|
|
6969
7331
|
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" }, "
|
|
7332
|
+
))))), /* @__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(
|
|
7333
|
+
"button",
|
|
7334
|
+
{
|
|
7335
|
+
type: "button",
|
|
7336
|
+
onClick: () => setIsDatasetDropdownOpen(!isDatasetDropdownOpen),
|
|
7337
|
+
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"
|
|
7338
|
+
},
|
|
7339
|
+
/* @__PURE__ */ React13.createElement("span", { className: "truncate pr-2" }, selectedDatasetName),
|
|
7340
|
+
/* @__PURE__ */ React13.createElement(FiChevronDown4, { className: `flex-shrink-0 text-slate-400 transition-transform ${isDatasetDropdownOpen ? "rotate-180" : ""}` })
|
|
7341
|
+
), 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(
|
|
7342
|
+
"li",
|
|
7343
|
+
{
|
|
7344
|
+
key: ds.id,
|
|
7345
|
+
onClick: () => {
|
|
7346
|
+
setTargetDatasetId(ds.id);
|
|
7347
|
+
setIsDatasetDropdownOpen(false);
|
|
7348
|
+
},
|
|
7349
|
+
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"}`
|
|
7350
|
+
},
|
|
7351
|
+
ds.name
|
|
7352
|
+
)))), /* @__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
7353
|
DescriptionDisplay,
|
|
6972
7354
|
{
|
|
6973
7355
|
description,
|
|
@@ -6975,7 +7357,8 @@ function InSceneCreationForm({
|
|
|
6975
7357
|
availableNodes,
|
|
6976
7358
|
availableAncestries,
|
|
6977
7359
|
onMentionClick,
|
|
6978
|
-
onImageClick: handleImageClickFromText
|
|
7360
|
+
onImageClick: handleImageClickFromText,
|
|
7361
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
6979
7362
|
}
|
|
6980
7363
|
), /* @__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
7364
|
"button",
|
|
@@ -7066,7 +7449,7 @@ function InSceneCreationForm({
|
|
|
7066
7449
|
}
|
|
7067
7450
|
|
|
7068
7451
|
// src/components/InSceneVersionForm.jsx
|
|
7069
|
-
import React14, { useState as
|
|
7452
|
+
import React14, { useState as useState15, useEffect as useEffect14, useRef as useRef11 } from "react";
|
|
7070
7453
|
import { FiPlus as FiPlus4, FiMaximize2 as FiMaximize22, FiCheck as FiCheck8, FiEdit2 as FiEdit25 } from "react-icons/fi";
|
|
7071
7454
|
function InSceneVersionForm({
|
|
7072
7455
|
onSave,
|
|
@@ -7084,14 +7467,14 @@ function InSceneVersionForm({
|
|
|
7084
7467
|
onMentionClick,
|
|
7085
7468
|
onUploadFile
|
|
7086
7469
|
}) {
|
|
7087
|
-
const [name, setName] =
|
|
7088
|
-
const [size, setSize] =
|
|
7089
|
-
const [description, setDescription] =
|
|
7090
|
-
const [customProps, setCustomProps] =
|
|
7091
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7470
|
+
const [name, setName] = useState15("");
|
|
7471
|
+
const [size, setSize] = useState15("medium");
|
|
7472
|
+
const [description, setDescription] = useState15("");
|
|
7473
|
+
const [customProps, setCustomProps] = useState15([{ id: v4_default(), key: "Date", type: "date", value: { type: "Data", value: "" }, isEditing: true }]);
|
|
7474
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState15(false);
|
|
7092
7475
|
const propsEndRef = useRef11(null);
|
|
7093
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
7094
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7476
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState15(false);
|
|
7477
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState15(null);
|
|
7095
7478
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
7096
7479
|
useEffect14(() => {
|
|
7097
7480
|
if (!hasImages && useImageAsTexture) {
|
|
@@ -7212,7 +7595,8 @@ function InSceneVersionForm({
|
|
|
7212
7595
|
availableNodes,
|
|
7213
7596
|
availableAncestries,
|
|
7214
7597
|
onMentionClick,
|
|
7215
|
-
onImageClick: handleImageClickFromText
|
|
7598
|
+
onImageClick: handleImageClickFromText,
|
|
7599
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
7216
7600
|
}
|
|
7217
7601
|
), /* @__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
7602
|
"button",
|
|
@@ -7284,8 +7668,8 @@ function InSceneVersionForm({
|
|
|
7284
7668
|
}
|
|
7285
7669
|
|
|
7286
7670
|
// 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";
|
|
7671
|
+
import React15, { useState as useState16, useEffect as useEffect15, useRef as useRef12 } from "react";
|
|
7672
|
+
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
7673
|
function NodeDetailsPanel({
|
|
7290
7674
|
node,
|
|
7291
7675
|
onClose,
|
|
@@ -7303,29 +7687,39 @@ function NodeDetailsPanel({
|
|
|
7303
7687
|
onMentionClick,
|
|
7304
7688
|
onIntensityChange,
|
|
7305
7689
|
onUploadFile,
|
|
7306
|
-
userRole
|
|
7690
|
+
userRole,
|
|
7691
|
+
currentDatasetName
|
|
7307
7692
|
}) {
|
|
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] =
|
|
7693
|
+
const [name, setName] = useState16((node == null ? void 0 : node.name) ?? "");
|
|
7694
|
+
const [types, setTypes] = useState16([]);
|
|
7695
|
+
const [typeInput, setTypeInput] = useState16("");
|
|
7696
|
+
const [color, setColor] = useState16((node == null ? void 0 : node.color) ?? "#8b5cf6");
|
|
7697
|
+
const [size, setSize] = useState16((node == null ? void 0 : node.size) ?? "medium");
|
|
7698
|
+
const [description, setDescription] = useState16((node == null ? void 0 : node.description) ?? "");
|
|
7699
|
+
const [intensity, setIntensity] = useState16((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
7700
|
+
const [customProps, setCustomProps] = useState16(() => extractCustomPropsFromNode(node || {}));
|
|
7701
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState16(false);
|
|
7702
|
+
const [filteredTypes, setFilteredTypes] = useState16([]);
|
|
7703
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
|
|
7704
|
+
const [isReadMode, setIsReadMode] = useState16(false);
|
|
7705
|
+
const [existingSections, setExistingSections] = useState16((node == null ? void 0 : node.description_sections) || []);
|
|
7706
|
+
const [isSaving, setIsSaving] = useState16(false);
|
|
7707
|
+
const [isLinkCopied, setIsLinkCopied] = useState16(false);
|
|
7708
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState16(() => {
|
|
7324
7709
|
if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
|
|
7325
7710
|
if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
|
|
7326
7711
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
7327
7712
|
});
|
|
7328
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
7713
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState16((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
7714
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
7715
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
7716
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
7717
|
+
minWidth: 320,
|
|
7718
|
+
maxWidth: maxPanelW
|
|
7719
|
+
});
|
|
7720
|
+
useEffect15(() => {
|
|
7721
|
+
setWidth(isReadMode ? 700 : 440);
|
|
7722
|
+
}, [isReadMode, setWidth]);
|
|
7329
7723
|
const prevNodeIdRef = useRef12(null);
|
|
7330
7724
|
const propsEndRef = useRef12(null);
|
|
7331
7725
|
const canEdit = userRole !== "viewer";
|
|
@@ -7478,6 +7872,11 @@ function NodeDetailsPanel({
|
|
|
7478
7872
|
textureImageUrl: url
|
|
7479
7873
|
});
|
|
7480
7874
|
};
|
|
7875
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
7876
|
+
setDescription(newDescription);
|
|
7877
|
+
onDataUpdate({ ...node, description: newDescription });
|
|
7878
|
+
triggerAutoSave({ description: newDescription });
|
|
7879
|
+
};
|
|
7481
7880
|
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
7482
7881
|
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
7483
7882
|
const currentTypes = overrides.types !== void 0 ? overrides.types : types;
|
|
@@ -7533,10 +7932,8 @@ function NodeDetailsPanel({
|
|
|
7533
7932
|
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
7534
7933
|
"div",
|
|
7535
7934
|
{
|
|
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 },
|
|
7935
|
+
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"}`,
|
|
7936
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
7540
7937
|
onPointerDown: swallow,
|
|
7541
7938
|
onPointerMove: swallow,
|
|
7542
7939
|
onPointerUp: swallow,
|
|
@@ -7545,6 +7942,17 @@ function NodeDetailsPanel({
|
|
|
7545
7942
|
onContextMenu: swallow,
|
|
7546
7943
|
onDoubleClick: swallow
|
|
7547
7944
|
},
|
|
7945
|
+
/* @__PURE__ */ React15.createElement(
|
|
7946
|
+
"div",
|
|
7947
|
+
{
|
|
7948
|
+
onPointerDown: (e) => {
|
|
7949
|
+
e.stopPropagation();
|
|
7950
|
+
handleResize(e);
|
|
7951
|
+
},
|
|
7952
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
7953
|
+
title: "Arraste para redimensionar"
|
|
7954
|
+
}
|
|
7955
|
+
),
|
|
7548
7956
|
isReadMode ? /* @__PURE__ */ React15.createElement(
|
|
7549
7957
|
DescriptionReadModePanel,
|
|
7550
7958
|
{
|
|
@@ -7563,7 +7971,8 @@ function NodeDetailsPanel({
|
|
|
7563
7971
|
availableAncestries,
|
|
7564
7972
|
onOpenReference,
|
|
7565
7973
|
onMentionClick,
|
|
7566
|
-
onImageClick: handleImageClickFromText
|
|
7974
|
+
onImageClick: handleImageClickFromText,
|
|
7975
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7567
7976
|
}
|
|
7568
7977
|
) : /* @__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
7978
|
"button",
|
|
@@ -7631,7 +8040,8 @@ function NodeDetailsPanel({
|
|
|
7631
8040
|
availableAncestries,
|
|
7632
8041
|
onOpenReference,
|
|
7633
8042
|
onMentionClick,
|
|
7634
|
-
onImageClick: handleImageClickFromText
|
|
8043
|
+
onImageClick: handleImageClickFromText,
|
|
8044
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7635
8045
|
}
|
|
7636
8046
|
), /* @__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
8047
|
"button",
|
|
@@ -7714,7 +8124,7 @@ function NodeDetailsPanel({
|
|
|
7714
8124
|
onUploadFile: canEdit ? onUploadFile : void 0,
|
|
7715
8125
|
readOnly: !canEdit
|
|
7716
8126
|
}
|
|
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(
|
|
8127
|
+
)), /* @__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
8128
|
"button",
|
|
7719
8129
|
{
|
|
7720
8130
|
onClick: () => handleSave(false),
|
|
@@ -7746,7 +8156,7 @@ function NodeDetailsPanel({
|
|
|
7746
8156
|
}
|
|
7747
8157
|
|
|
7748
8158
|
// src/components/MultiNodeContextMenu.jsx
|
|
7749
|
-
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as
|
|
8159
|
+
import React16, { useLayoutEffect as useLayoutEffect3, useRef as useRef13, useState as useState17, useEffect as useEffect16 } from "react";
|
|
7750
8160
|
function MultiNodeContextMenu({
|
|
7751
8161
|
data,
|
|
7752
8162
|
userRole,
|
|
@@ -7757,7 +8167,7 @@ function MultiNodeContextMenu({
|
|
|
7757
8167
|
onDeleteNodes
|
|
7758
8168
|
}) {
|
|
7759
8169
|
const menuRef = useRef13(null);
|
|
7760
|
-
const [menuPos, setMenuPos] =
|
|
8170
|
+
const [menuPos, setMenuPos] = useState17({ left: 0, top: 0 });
|
|
7761
8171
|
const ability = defineAbilityFor(userRole);
|
|
7762
8172
|
const canDelete = ability.can("delete", "Node");
|
|
7763
8173
|
useLayoutEffect3(() => {
|
|
@@ -7806,7 +8216,7 @@ function MultiNodeContextMenu({
|
|
|
7806
8216
|
}
|
|
7807
8217
|
|
|
7808
8218
|
// src/components/RelationshipDetailsPanel.jsx
|
|
7809
|
-
import React17, { useState as
|
|
8219
|
+
import React17, { useState as useState18, useEffect as useEffect17, useRef as useRef14, useMemo as useMemo9 } from "react";
|
|
7810
8220
|
import { FiPlus as FiPlus6, FiEdit2 as FiEdit27, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
|
|
7811
8221
|
function RelationshipDetailsPanel({
|
|
7812
8222
|
link,
|
|
@@ -7820,15 +8230,14 @@ function RelationshipDetailsPanel({
|
|
|
7820
8230
|
onMentionClick,
|
|
7821
8231
|
onUploadFile,
|
|
7822
8232
|
userRole
|
|
7823
|
-
// Recebendo userRole via props
|
|
7824
8233
|
}) {
|
|
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] =
|
|
8234
|
+
const [name, setName] = useState18((link == null ? void 0 : link.name) ?? "");
|
|
8235
|
+
const [description, setDescription] = useState18((link == null ? void 0 : link.description) ?? "");
|
|
8236
|
+
const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(link || {}));
|
|
8237
|
+
const [existingSections, setExistingSections] = useState18((link == null ? void 0 : link.description_sections) || []);
|
|
8238
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
|
|
8239
|
+
const [isSaving, setIsSaving] = useState18(false);
|
|
8240
|
+
const [isReadMode, setIsReadMode] = useState18(false);
|
|
7832
8241
|
const propsEndRef = useRef14(null);
|
|
7833
8242
|
const canEdit = useMemo9(() => {
|
|
7834
8243
|
const ability = defineAbilityFor(userRole);
|
|
@@ -7883,6 +8292,12 @@ function RelationshipDetailsPanel({
|
|
|
7883
8292
|
const triggerAutoSave = (overrides = {}) => {
|
|
7884
8293
|
if (canEdit) handleSave(true, overrides);
|
|
7885
8294
|
};
|
|
8295
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
8296
|
+
if (!canEdit) return;
|
|
8297
|
+
setDescription(newDescription);
|
|
8298
|
+
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
8299
|
+
triggerAutoSave({ description: newDescription });
|
|
8300
|
+
};
|
|
7886
8301
|
const handleRemoveProp = (i) => {
|
|
7887
8302
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
7888
8303
|
setCustomProps(newProps);
|
|
@@ -7936,7 +8351,8 @@ function RelationshipDetailsPanel({
|
|
|
7936
8351
|
availableAncestries,
|
|
7937
8352
|
onOpenReference,
|
|
7938
8353
|
onMentionClick,
|
|
7939
|
-
onImageClick: handleImageClickFromText
|
|
8354
|
+
onImageClick: handleImageClickFromText,
|
|
8355
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7940
8356
|
}
|
|
7941
8357
|
) : /* @__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
8358
|
"input",
|
|
@@ -7959,7 +8375,8 @@ function RelationshipDetailsPanel({
|
|
|
7959
8375
|
availableAncestries,
|
|
7960
8376
|
onOpenReference,
|
|
7961
8377
|
onMentionClick,
|
|
7962
|
-
onImageClick: handleImageClickFromText
|
|
8378
|
+
onImageClick: handleImageClickFromText,
|
|
8379
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
7963
8380
|
}
|
|
7964
8381
|
), /* @__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
8382
|
"button",
|
|
@@ -8031,7 +8448,7 @@ function RelationshipDetailsPanel({
|
|
|
8031
8448
|
}
|
|
8032
8449
|
|
|
8033
8450
|
// src/components/RelationshipContextMenu.jsx
|
|
8034
|
-
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as
|
|
8451
|
+
import React18, { useLayoutEffect as useLayoutEffect4, useRef as useRef15, useState as useState19, useEffect as useEffect18, useMemo as useMemo10 } from "react";
|
|
8035
8452
|
function RelationshipContextMenu({
|
|
8036
8453
|
data,
|
|
8037
8454
|
userRole,
|
|
@@ -8043,7 +8460,7 @@ function RelationshipContextMenu({
|
|
|
8043
8460
|
onClose
|
|
8044
8461
|
}) {
|
|
8045
8462
|
const menuRef = useRef15(null);
|
|
8046
|
-
const [menuPos, setMenuPos] =
|
|
8463
|
+
const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
|
|
8047
8464
|
const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
|
|
8048
8465
|
const sourceName = useMemo10(
|
|
8049
8466
|
() => {
|
|
@@ -8245,7 +8662,7 @@ function LoadingScreen() {
|
|
|
8245
8662
|
}
|
|
8246
8663
|
|
|
8247
8664
|
// src/components/ImportParentFileModal.jsx
|
|
8248
|
-
import React20, { useEffect as useEffect19, useState as
|
|
8665
|
+
import React20, { useEffect as useEffect19, useState as useState20 } from "react";
|
|
8249
8666
|
function ImportParentFileModal({
|
|
8250
8667
|
isOpen,
|
|
8251
8668
|
onClose,
|
|
@@ -8256,11 +8673,11 @@ function ImportParentFileModal({
|
|
|
8256
8673
|
onFetchAvailableFiles,
|
|
8257
8674
|
currentViewName
|
|
8258
8675
|
}) {
|
|
8259
|
-
const [activeTab, setActiveTab] =
|
|
8260
|
-
const [availableDbs, setAvailableDbs] =
|
|
8261
|
-
const [availableViews, setAvailableViews] =
|
|
8262
|
-
const [selectedItem, setSelectedItem] =
|
|
8263
|
-
const [isLoading, setIsLoading] =
|
|
8676
|
+
const [activeTab, setActiveTab] = useState20("databases");
|
|
8677
|
+
const [availableDbs, setAvailableDbs] = useState20([]);
|
|
8678
|
+
const [availableViews, setAvailableViews] = useState20([]);
|
|
8679
|
+
const [selectedItem, setSelectedItem] = useState20(null);
|
|
8680
|
+
const [isLoading, setIsLoading] = useState20(false);
|
|
8264
8681
|
useEffect19(() => {
|
|
8265
8682
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
8266
8683
|
const fetchData = async () => {
|
|
@@ -8406,7 +8823,7 @@ function ImportParentFileModal({
|
|
|
8406
8823
|
}
|
|
8407
8824
|
|
|
8408
8825
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
8409
|
-
import React21, { useState as
|
|
8826
|
+
import React21, { useState as useState21 } from "react";
|
|
8410
8827
|
import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
|
|
8411
8828
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
8412
8829
|
var _a, _b, _c, _d;
|
|
@@ -8416,7 +8833,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8416
8833
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
8417
8834
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
8418
8835
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
8419
|
-
const [isReadMode, setIsReadMode] =
|
|
8836
|
+
const [isReadMode, setIsReadMode] = useState21(false);
|
|
8420
8837
|
const swallow = (e) => e.stopPropagation();
|
|
8421
8838
|
const handleImageClickFromText = (url, name) => {
|
|
8422
8839
|
if (onOpenImageViewer) {
|
|
@@ -8482,7 +8899,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
8482
8899
|
}
|
|
8483
8900
|
|
|
8484
8901
|
// src/components/AncestryBoard.jsx
|
|
8485
|
-
import React22, { useState as
|
|
8902
|
+
import React22, { useState as useState22, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef16 } from "react";
|
|
8486
8903
|
import {
|
|
8487
8904
|
FiSearch as FiSearch4,
|
|
8488
8905
|
FiLayers as FiLayers6,
|
|
@@ -8659,11 +9076,11 @@ function AncestryBoard({
|
|
|
8659
9076
|
userRole
|
|
8660
9077
|
// [NOVO] Recebe a role do usuário
|
|
8661
9078
|
}) {
|
|
8662
|
-
const [searchTerm, setSearchTerm] =
|
|
8663
|
-
const [groups, setGroups] =
|
|
8664
|
-
const [isLoaded, setIsLoaded] =
|
|
8665
|
-
const [pickingGroupId, setPickingGroupId] =
|
|
8666
|
-
const [saveStatus, setSaveStatus] =
|
|
9079
|
+
const [searchTerm, setSearchTerm] = useState22("");
|
|
9080
|
+
const [groups, setGroups] = useState22([]);
|
|
9081
|
+
const [isLoaded, setIsLoaded] = useState22(false);
|
|
9082
|
+
const [pickingGroupId, setPickingGroupId] = useState22(null);
|
|
9083
|
+
const [saveStatus, setSaveStatus] = useState22("idle");
|
|
8667
9084
|
const canEdit = useMemo11(() => {
|
|
8668
9085
|
return userRole !== "viewer";
|
|
8669
9086
|
}, [userRole]);
|
|
@@ -9048,7 +9465,7 @@ function XViewScene({
|
|
|
9048
9465
|
delete_file_action,
|
|
9049
9466
|
check_user_permission
|
|
9050
9467
|
}) {
|
|
9051
|
-
var _a, _b, _c, _d, _e, _f;
|
|
9468
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
9052
9469
|
const { data: session, status } = useSession();
|
|
9053
9470
|
const router = useRouter();
|
|
9054
9471
|
const searchParams = useSearchParams();
|
|
@@ -9113,37 +9530,37 @@ function XViewScene({
|
|
|
9113
9530
|
const sceneDataRef = useRef17(null);
|
|
9114
9531
|
const parentDataRef = useRef17(null);
|
|
9115
9532
|
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] =
|
|
9533
|
+
const [isLoading, setIsLoading] = useState23(true);
|
|
9534
|
+
const [permissionStatus, setPermissionStatus] = useState23("loading");
|
|
9535
|
+
const [userPermissionRole, setUserPermissionRole] = useState23(null);
|
|
9536
|
+
const [isInitialized, setIsInitialized] = useState23(false);
|
|
9537
|
+
const [sceneVersion, setSceneVersion] = useState23(0);
|
|
9538
|
+
const [contextMenu, setContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeData: null });
|
|
9539
|
+
const [multiContextMenu, setMultiContextMenu] = useState23({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
9540
|
+
const [relationshipMenu, setRelationshipMenu] = useState23({ visible: false, x: 0, y: 0, linkObject: null });
|
|
9541
|
+
const [creationMode, setCreationMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9542
|
+
const [versionMode, setVersionMode] = useState23({ isActive: false, sourceNodeData: null });
|
|
9543
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState23(false);
|
|
9544
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState23(false);
|
|
9545
|
+
const [ancestryMode, setAncestryMode] = useState23({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
9546
|
+
const [readingMode, setReadingMode] = useState23({
|
|
9130
9547
|
isActive: false,
|
|
9131
9548
|
ancestry: null,
|
|
9132
9549
|
branchStack: [],
|
|
9133
9550
|
autoAbstraction: false
|
|
9134
9551
|
});
|
|
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] =
|
|
9552
|
+
const [formPosition, setFormPosition] = useState23({ left: 16, top: 16, opacity: 0 });
|
|
9553
|
+
const [detailsNode, setDetailsNode] = useState23(null);
|
|
9554
|
+
const [detailsLink, setDetailsLink] = useState23(null);
|
|
9555
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState23(null);
|
|
9556
|
+
const [imageViewer, setImageViewer] = useState23({ visible: false, images: [], startIndex: 0 });
|
|
9557
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState23({ visible: false, data: null, path: null });
|
|
9558
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState23(false);
|
|
9559
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState23("");
|
|
9560
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState23(null);
|
|
9561
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState23(false);
|
|
9562
|
+
const [ancestryBoardData, setAncestryBoardData] = useState23([]);
|
|
9563
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState23(false);
|
|
9147
9564
|
const mountRef = useRef17(null);
|
|
9148
9565
|
const tooltipRef = useRef17(null);
|
|
9149
9566
|
const formRef = useRef17(null);
|
|
@@ -9186,6 +9603,12 @@ function XViewScene({
|
|
|
9186
9603
|
lastDescriptionLength: 0,
|
|
9187
9604
|
highlightedNodeId: null
|
|
9188
9605
|
});
|
|
9606
|
+
const maxReadPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
9607
|
+
const { width: readModeWidth, isResizing: isReadModeResizing, handlePointerDown: handleReadModeResize } = useResizablePanel({
|
|
9608
|
+
initialWidth: 700,
|
|
9609
|
+
minWidth: 320,
|
|
9610
|
+
maxWidth: maxReadPanelW
|
|
9611
|
+
});
|
|
9189
9612
|
useEffect21(() => {
|
|
9190
9613
|
stateRef.current.ancestry = ancestryMode;
|
|
9191
9614
|
}, [ancestryMode]);
|
|
@@ -9200,19 +9623,20 @@ function XViewScene({
|
|
|
9200
9623
|
const parentFile = allParentData[parentFileId];
|
|
9201
9624
|
const parentDbInfo = parentDbsArray.find((db) => String(db.db_id) === String(parentFileId));
|
|
9202
9625
|
const ownerId2 = (parentDbInfo == null ? void 0 : parentDbInfo.owner_id) || null;
|
|
9626
|
+
const datasetName = parentFile.dataset_name || `Dataset #${parentFileId.substring(0, 6)}`;
|
|
9203
9627
|
if (parentFile.nodes && ownerId2) {
|
|
9204
9628
|
for (const node of parentFile.nodes) {
|
|
9205
|
-
map.set(String(node.id), { parentFileId, ownerId: ownerId2 });
|
|
9629
|
+
map.set(String(node.id), { parentFileId, ownerId: ownerId2, datasetName });
|
|
9206
9630
|
}
|
|
9207
9631
|
}
|
|
9208
9632
|
}
|
|
9209
9633
|
}
|
|
9210
9634
|
stateRef.current.nodeIdToParentFileMap = map;
|
|
9211
9635
|
}, [isInitialized, sceneVersion]);
|
|
9212
|
-
const handleNavigateBack =
|
|
9636
|
+
const handleNavigateBack = useCallback4(() => {
|
|
9213
9637
|
router.push("/dashboard/scenes");
|
|
9214
9638
|
}, [router]);
|
|
9215
|
-
const handleConfirmImport =
|
|
9639
|
+
const handleConfirmImport = useCallback4(
|
|
9216
9640
|
async (importPayload) => {
|
|
9217
9641
|
var _a2, _b2;
|
|
9218
9642
|
let files = [];
|
|
@@ -9260,7 +9684,6 @@ function XViewScene({
|
|
|
9260
9684
|
if (ancestryResponse.success && Array.isArray(ancestryResponse.data)) {
|
|
9261
9685
|
const viewSpecificAncestries = ancestryResponse.data.filter(
|
|
9262
9686
|
(anc) => anc._source_file_id === viewToImport.id && !anc.is_private
|
|
9263
|
-
// <--- AQUI ESTÁ A TRAVA DE SEGURANÇA
|
|
9264
9687
|
);
|
|
9265
9688
|
const processedAncestries = viewSpecificAncestries.map((anc) => ({
|
|
9266
9689
|
...anc,
|
|
@@ -9311,7 +9734,7 @@ function XViewScene({
|
|
|
9311
9734
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
9312
9735
|
setImageViewer({ visible: true, images, startIndex });
|
|
9313
9736
|
};
|
|
9314
|
-
const tweenToTarget =
|
|
9737
|
+
const tweenToTarget = useCallback4((target, zoomFactor = 1, forcedDirection = null) => {
|
|
9315
9738
|
const { camera, controls, tweenGroup } = stateRef.current;
|
|
9316
9739
|
if (!camera || !controls || !tweenGroup) return;
|
|
9317
9740
|
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
@@ -9334,7 +9757,7 @@ function XViewScene({
|
|
|
9334
9757
|
if (!t || typeof t.closest !== "function") return false;
|
|
9335
9758
|
return !!t.closest(".ui-overlay");
|
|
9336
9759
|
};
|
|
9337
|
-
const buildFullAncestryTree =
|
|
9760
|
+
const buildFullAncestryTree = useCallback4((idTree, nodes, ancestries = []) => {
|
|
9338
9761
|
if (!idTree) return null;
|
|
9339
9762
|
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
9340
9763
|
const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
|
|
@@ -9360,14 +9783,10 @@ function XViewScene({
|
|
|
9360
9783
|
return {
|
|
9361
9784
|
...branch,
|
|
9362
9785
|
name: linkedAncestry.name,
|
|
9363
|
-
// Sobrescreve nome para exibição
|
|
9364
9786
|
description: linkedAncestry.description,
|
|
9365
|
-
// Sobrescreve descrição
|
|
9366
9787
|
description_sections: linkedAncestry.description_sections,
|
|
9367
9788
|
tree: graftedTree,
|
|
9368
|
-
// ENXERTA A ÁRVORE AQUI
|
|
9369
9789
|
isLinked: true
|
|
9370
|
-
// Flag útil
|
|
9371
9790
|
};
|
|
9372
9791
|
}
|
|
9373
9792
|
}
|
|
@@ -9414,7 +9833,7 @@ function XViewScene({
|
|
|
9414
9833
|
}
|
|
9415
9834
|
return recursiveBuild(idTree);
|
|
9416
9835
|
}, []);
|
|
9417
|
-
const handleActivateTimeline =
|
|
9836
|
+
const handleActivateTimeline = useCallback4(() => {
|
|
9418
9837
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9419
9838
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
9420
9839
|
while (timelineIntervalsGroup.children.length > 0) {
|
|
@@ -9567,7 +9986,7 @@ function XViewScene({
|
|
|
9567
9986
|
}
|
|
9568
9987
|
});
|
|
9569
9988
|
}, []);
|
|
9570
|
-
const handleVersionTimeline =
|
|
9989
|
+
const handleVersionTimeline = useCallback4((sourceMesh, versionMeshes) => {
|
|
9571
9990
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
9572
9991
|
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
|
|
9573
9992
|
versionMeshes.forEach((mesh) => {
|
|
@@ -9722,6 +10141,9 @@ function XViewScene({
|
|
|
9722
10141
|
sceneDataRef.current = sceneResponse.data.scene;
|
|
9723
10142
|
parentDataRef.current = sceneResponse.data.parent;
|
|
9724
10143
|
ancestryDataRef.current = sceneResponse.data.ancestry;
|
|
10144
|
+
console.log("Console de sceneResponse.data.scene:", sceneResponse.data.scene);
|
|
10145
|
+
console.log("Console de sceneResponse.data.parent:", sceneResponse.data.parent);
|
|
10146
|
+
console.log("Console de sceneResponse.data.ancestry:", sceneResponse.data.ancestry);
|
|
9725
10147
|
setIsInitialized(true);
|
|
9726
10148
|
} else {
|
|
9727
10149
|
console.error("Falha ao buscar dados da cena:", (sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida.");
|
|
@@ -9757,16 +10179,14 @@ function XViewScene({
|
|
|
9757
10179
|
isInitialized,
|
|
9758
10180
|
permissionStatus,
|
|
9759
10181
|
focusNodeId,
|
|
9760
|
-
// <-- MANTIDO
|
|
9761
10182
|
focusAncestryId
|
|
9762
|
-
// <-- ADICIONADO O focusAncestryId NAS DEPENDÊNCIAS
|
|
9763
10183
|
]);
|
|
9764
|
-
const isNodeInView =
|
|
10184
|
+
const isNodeInView = useCallback4((id) => {
|
|
9765
10185
|
const key = String(id);
|
|
9766
10186
|
const objs = stateRef.current.nodeObjects || {};
|
|
9767
10187
|
return !!objs[key];
|
|
9768
10188
|
}, []);
|
|
9769
|
-
const addOrUpdateNodeMesh =
|
|
10189
|
+
const addOrUpdateNodeMesh = useCallback4((nodeData, position, suppressVersionUpdate = false) => {
|
|
9770
10190
|
const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
|
|
9771
10191
|
const nodeId = String(nodeData.id);
|
|
9772
10192
|
if (nodeObjects[nodeId]) {
|
|
@@ -10415,7 +10835,7 @@ function XViewScene({
|
|
|
10415
10835
|
}
|
|
10416
10836
|
};
|
|
10417
10837
|
}, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
|
|
10418
|
-
const handleGhostNodeImageChange =
|
|
10838
|
+
const handleGhostNodeImageChange = useCallback4((useImage, imageUrl) => {
|
|
10419
10839
|
const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10420
10840
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
10421
10841
|
if (!ghostNode || !graphGroup) return;
|
|
@@ -10457,7 +10877,7 @@ function XViewScene({
|
|
|
10457
10877
|
aura: newGhostNode.getObjectByName("aura")
|
|
10458
10878
|
};
|
|
10459
10879
|
}, []);
|
|
10460
|
-
const handleGhostNodeIntensityChange =
|
|
10880
|
+
const handleGhostNodeIntensityChange = useCallback4((newIntensity) => {
|
|
10461
10881
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10462
10882
|
if (!ghostNode) return;
|
|
10463
10883
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10478,7 +10898,7 @@ function XViewScene({
|
|
|
10478
10898
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
10479
10899
|
}
|
|
10480
10900
|
}, []);
|
|
10481
|
-
const handleDetailNodeIntensityChange =
|
|
10901
|
+
const handleDetailNodeIntensityChange = useCallback4((nodeId, newIntensity) => {
|
|
10482
10902
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
10483
10903
|
if (!mesh) return;
|
|
10484
10904
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -10503,32 +10923,33 @@ function XViewScene({
|
|
|
10503
10923
|
const handleGhostNodeColorChange = (newColor) => {
|
|
10504
10924
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
10505
10925
|
if (!ghostNode) return;
|
|
10506
|
-
const {
|
|
10507
|
-
const
|
|
10926
|
+
const { color, emissive } = computeNodeMaterialProps(newColor);
|
|
10927
|
+
const currentIntensity = ghostNode.userData.intensity !== void 0 ? Number(ghostNode.userData.intensity) : 0;
|
|
10928
|
+
const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
|
|
10508
10929
|
const isImageNode = ghostNode.userData.useImageAsTexture === true || String(ghostNode.userData.useImageAsTexture) === "true";
|
|
10509
10930
|
if (isImageNode) {
|
|
10510
10931
|
const borderMesh = ghostNode.getObjectByName("borderRing");
|
|
10511
10932
|
if (borderMesh && borderMesh.material) {
|
|
10512
|
-
borderMesh.material.color.copy(
|
|
10933
|
+
borderMesh.material.color.copy(color);
|
|
10513
10934
|
if (borderMesh.material.emissive) {
|
|
10514
|
-
borderMesh.material.emissive.copy(
|
|
10515
|
-
borderMesh.material.emissiveIntensity =
|
|
10935
|
+
borderMesh.material.emissive.copy(emissive);
|
|
10936
|
+
borderMesh.material.emissiveIntensity = finalIntensity;
|
|
10516
10937
|
}
|
|
10517
10938
|
}
|
|
10518
10939
|
} else {
|
|
10519
10940
|
if (ghostNode.material) {
|
|
10520
|
-
ghostNode.material.color.copy(
|
|
10941
|
+
ghostNode.material.color.copy(color);
|
|
10521
10942
|
if (ghostNode.material.emissive) {
|
|
10522
|
-
ghostNode.material.emissive.copy(
|
|
10523
|
-
ghostNode.material.emissiveIntensity =
|
|
10943
|
+
ghostNode.material.emissive.copy(emissive);
|
|
10944
|
+
ghostNode.material.emissiveIntensity = finalIntensity;
|
|
10524
10945
|
}
|
|
10525
10946
|
}
|
|
10526
10947
|
}
|
|
10527
10948
|
if (ghostAura && ghostAura.material) {
|
|
10528
|
-
ghostAura.material.color.
|
|
10949
|
+
ghostAura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
|
|
10529
10950
|
}
|
|
10530
10951
|
ghostNode.userData.color = newColor;
|
|
10531
|
-
ghostNode.userData._baseEmissiveIntensity =
|
|
10952
|
+
ghostNode.userData._baseEmissiveIntensity = finalIntensity;
|
|
10532
10953
|
};
|
|
10533
10954
|
const handleGhostNodeSizeChange = (sizeKey) => {
|
|
10534
10955
|
const { node: ghostNode } = stateRef.current.ghostElements;
|
|
@@ -10569,7 +10990,9 @@ function XViewScene({
|
|
|
10569
10990
|
var _a2;
|
|
10570
10991
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
10571
10992
|
if (!mesh) return;
|
|
10572
|
-
const { color, emissive
|
|
10993
|
+
const { color, emissive } = computeNodeMaterialProps(newColor);
|
|
10994
|
+
const currentIntensity = mesh.userData.intensity !== void 0 ? Number(mesh.userData.intensity) : 0;
|
|
10995
|
+
const finalIntensity = currentIntensity + MIN_VISIBILITY_INTENSITY;
|
|
10573
10996
|
const isImageNode = mesh.userData.useImageAsTexture === true || String(mesh.userData.useImageAsTexture) === "true";
|
|
10574
10997
|
if (isImageNode) {
|
|
10575
10998
|
const borderMesh = mesh.getObjectByName("borderRing");
|
|
@@ -10577,20 +11000,22 @@ function XViewScene({
|
|
|
10577
11000
|
borderMesh.material.color.copy(color);
|
|
10578
11001
|
if (borderMesh.material.emissive) {
|
|
10579
11002
|
borderMesh.material.emissive.copy(emissive);
|
|
10580
|
-
borderMesh.material.emissiveIntensity =
|
|
11003
|
+
borderMesh.material.emissiveIntensity = finalIntensity;
|
|
10581
11004
|
}
|
|
10582
11005
|
}
|
|
10583
11006
|
} else {
|
|
10584
11007
|
if (mesh.material) {
|
|
10585
11008
|
mesh.material.color.copy(color);
|
|
10586
11009
|
mesh.material.emissive.copy(emissive);
|
|
10587
|
-
mesh.material.emissiveIntensity =
|
|
11010
|
+
mesh.material.emissiveIntensity = finalIntensity;
|
|
10588
11011
|
}
|
|
10589
11012
|
}
|
|
10590
11013
|
const aura = mesh.getObjectByName("aura");
|
|
10591
|
-
if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color)
|
|
11014
|
+
if ((_a2 = aura == null ? void 0 : aura.material) == null ? void 0 : _a2.color) {
|
|
11015
|
+
aura.material.color.copy(color).lerp(new THREE3.Color("#ffffff"), 0.25);
|
|
11016
|
+
}
|
|
10592
11017
|
mesh.userData.color = newColor;
|
|
10593
|
-
mesh.userData._baseEmissiveIntensity =
|
|
11018
|
+
mesh.userData._baseEmissiveIntensity = finalIntensity;
|
|
10594
11019
|
};
|
|
10595
11020
|
const handleDetailNodeSizeChange = (nodeId, newSize) => {
|
|
10596
11021
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
@@ -10619,7 +11044,7 @@ function XViewScene({
|
|
|
10619
11044
|
mountRef.current.style.cursor = "default";
|
|
10620
11045
|
}
|
|
10621
11046
|
};
|
|
10622
|
-
const handleAncestryTreeUpdate =
|
|
11047
|
+
const handleAncestryTreeUpdate = useCallback4((newTree, extraData = null) => {
|
|
10623
11048
|
setAncestryMode((prev) => {
|
|
10624
11049
|
const prevTreeStr = JSON.stringify(prev.tree);
|
|
10625
11050
|
const newTreeStr = JSON.stringify(newTree);
|
|
@@ -10689,7 +11114,7 @@ function XViewScene({
|
|
|
10689
11114
|
const handleStartVersioning = (nodeData) => {
|
|
10690
11115
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
10691
11116
|
};
|
|
10692
|
-
const handleClearAncestryVisuals =
|
|
11117
|
+
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
10693
11118
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
10694
11119
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
10695
11120
|
if (renderIndex !== -1) {
|
|
@@ -10703,7 +11128,7 @@ function XViewScene({
|
|
|
10703
11128
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
10704
11129
|
}
|
|
10705
11130
|
}, []);
|
|
10706
|
-
const handleRenderAncestry =
|
|
11131
|
+
const handleRenderAncestry = useCallback4(
|
|
10707
11132
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
10708
11133
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
10709
11134
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11119,7 +11544,7 @@ function XViewScene({
|
|
|
11119
11544
|
},
|
|
11120
11545
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
11121
11546
|
);
|
|
11122
|
-
const handleRenderAbstractionTree =
|
|
11547
|
+
const handleRenderAbstractionTree = useCallback4((ancestryObject, targetNodeId = null) => {
|
|
11123
11548
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11124
11549
|
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
11125
11550
|
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
@@ -11180,7 +11605,7 @@ function XViewScene({
|
|
|
11180
11605
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
11181
11606
|
tweenToTarget(rootTargetPos, 0.7);
|
|
11182
11607
|
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
11183
|
-
const handleReadModeBranchNav =
|
|
11608
|
+
const handleReadModeBranchNav = useCallback4((nodeId, action, direction = "right") => {
|
|
11184
11609
|
const { ancestry, branchStack } = readingMode;
|
|
11185
11610
|
if (!ancestry || !ancestry.tree) return;
|
|
11186
11611
|
const allAncestries = ancestryDataRef.current || [];
|
|
@@ -11218,9 +11643,7 @@ function XViewScene({
|
|
|
11218
11643
|
description_sections: branchToOpen.description_sections,
|
|
11219
11644
|
tree: branchToOpen.tree,
|
|
11220
11645
|
_originNodeId: nodeId,
|
|
11221
|
-
// <--- ID do node pai (link visual)
|
|
11222
11646
|
_branchDirection: direction
|
|
11223
|
-
// <--- Direção para cálculo de posição
|
|
11224
11647
|
};
|
|
11225
11648
|
const allowedIds = /* @__PURE__ */ new Set(["preamble", 0, "0"]);
|
|
11226
11649
|
const branchSections = parseDescriptionSections(branchToOpen.description || "", branchToOpen.description_sections || []);
|
|
@@ -11276,7 +11699,6 @@ function XViewScene({
|
|
|
11276
11699
|
const parentAncestryObj = {
|
|
11277
11700
|
...targetAncestryInfo,
|
|
11278
11701
|
tree: targetTreeToRender,
|
|
11279
|
-
// Re-injeta a origem se o pai também for uma branch aninhada
|
|
11280
11702
|
_originNodeId: activeParentStackItem ? activeParentStackItem.nodeId : null,
|
|
11281
11703
|
_branchDirection: activeParentStackItem ? activeParentStackItem.entryDirection : null
|
|
11282
11704
|
};
|
|
@@ -11324,7 +11746,7 @@ function XViewScene({
|
|
|
11324
11746
|
}));
|
|
11325
11747
|
}
|
|
11326
11748
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
11327
|
-
const handleReadModeHighlight =
|
|
11749
|
+
const handleReadModeHighlight = useCallback4((nodeId) => {
|
|
11328
11750
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
11329
11751
|
stateRef.current.highlightedNodeId = nodeId;
|
|
11330
11752
|
}
|
|
@@ -11336,7 +11758,6 @@ function XViewScene({
|
|
|
11336
11758
|
readingMode.ancestry.tree,
|
|
11337
11759
|
Object.values(parentDataRef.current).flatMap((f) => f.nodes),
|
|
11338
11760
|
ancestryDataRef.current
|
|
11339
|
-
// <--- Adicionar
|
|
11340
11761
|
);
|
|
11341
11762
|
const findNodeInTree = (tree, targetId) => {
|
|
11342
11763
|
if (!tree) return null;
|
|
@@ -11390,7 +11811,6 @@ function XViewScene({
|
|
|
11390
11811
|
description_sections: ancestry.description_sections,
|
|
11391
11812
|
direction: null,
|
|
11392
11813
|
customProperties: rootProps
|
|
11393
|
-
// <--- ADICIONADO
|
|
11394
11814
|
};
|
|
11395
11815
|
}
|
|
11396
11816
|
const fullTree = buildFullAncestryTree(
|
|
@@ -11419,7 +11839,6 @@ function XViewScene({
|
|
|
11419
11839
|
description_sections: currentMeta.description_sections,
|
|
11420
11840
|
direction: currentDirection,
|
|
11421
11841
|
customProperties: branchProps
|
|
11422
|
-
// <--- ADICIONADO
|
|
11423
11842
|
};
|
|
11424
11843
|
}, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11425
11844
|
const readModeAbstractionTree = useMemo12(() => {
|
|
@@ -11434,7 +11853,7 @@ function XViewScene({
|
|
|
11434
11853
|
allAncestries
|
|
11435
11854
|
);
|
|
11436
11855
|
}, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
|
|
11437
|
-
const handleStartReadingAncestry =
|
|
11856
|
+
const handleStartReadingAncestry = useCallback4(
|
|
11438
11857
|
async (ancestryObject) => {
|
|
11439
11858
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11440
11859
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11455,7 +11874,6 @@ function XViewScene({
|
|
|
11455
11874
|
ancestry: ancestryObject,
|
|
11456
11875
|
branchStack: [],
|
|
11457
11876
|
autoAbstraction: shouldAutoRenderAbstraction
|
|
11458
|
-
// <--- FLAG ENVIADA PARA A UI
|
|
11459
11877
|
});
|
|
11460
11878
|
if (shouldAutoRenderAbstraction) {
|
|
11461
11879
|
handleRenderAbstractionTree(ancestryObject, null);
|
|
@@ -11469,9 +11887,8 @@ function XViewScene({
|
|
|
11469
11887
|
}
|
|
11470
11888
|
},
|
|
11471
11889
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
11472
|
-
// <--- DEPENDÊNCIA ADICIONADA
|
|
11473
11890
|
);
|
|
11474
|
-
const handleReadModeSectionChange =
|
|
11891
|
+
const handleReadModeSectionChange = useCallback4((activeSectionId) => {
|
|
11475
11892
|
const { ancestry, branchStack } = readingMode;
|
|
11476
11893
|
if (!ancestry || !readingMode.isActive) return;
|
|
11477
11894
|
let targetObj = ancestry;
|
|
@@ -11540,10 +11957,10 @@ function XViewScene({
|
|
|
11540
11957
|
}, 0);
|
|
11541
11958
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11542
11959
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
|
|
11543
|
-
const handleCloseReadMode =
|
|
11960
|
+
const handleCloseReadMode = useCallback4(() => {
|
|
11544
11961
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
11545
11962
|
}, []);
|
|
11546
|
-
const handleAncestrySectionChange =
|
|
11963
|
+
const handleAncestrySectionChange = useCallback4((activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
11547
11964
|
var _a2, _b2;
|
|
11548
11965
|
const currentMode = stateRef.current.ancestry;
|
|
11549
11966
|
let targetObj = ancestryOverride;
|
|
@@ -11595,7 +12012,7 @@ function XViewScene({
|
|
|
11595
12012
|
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
11596
12013
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
11597
12014
|
}, [handleRenderAncestry]);
|
|
11598
|
-
const handleEditAncestry =
|
|
12015
|
+
const handleEditAncestry = useCallback4(
|
|
11599
12016
|
async (ancestryObject) => {
|
|
11600
12017
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11601
12018
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -11618,10 +12035,8 @@ function XViewScene({
|
|
|
11618
12035
|
...ancestryObject,
|
|
11619
12036
|
tree: fullTree,
|
|
11620
12037
|
abstraction_tree: fullAbstractionTree,
|
|
11621
|
-
// NOVO
|
|
11622
12038
|
selectedParentId: ancestryObject.ancestral_node,
|
|
11623
12039
|
selectedAbstractionParentId: ancestryObject.ancestral_node,
|
|
11624
|
-
// NOVO
|
|
11625
12040
|
isEditMode: true,
|
|
11626
12041
|
currentAncestryId: ancestryObject.ancestry_id,
|
|
11627
12042
|
ancestryName: ancestryObject.name || `Ancestralidade ${fullTree.node.name}`,
|
|
@@ -11629,7 +12044,6 @@ function XViewScene({
|
|
|
11629
12044
|
ancestryDescriptionSections: ancestryObject.description_sections || [],
|
|
11630
12045
|
isAddingNodes: false,
|
|
11631
12046
|
isAddingAbstractionNodes: false
|
|
11632
|
-
// NOVO
|
|
11633
12047
|
});
|
|
11634
12048
|
},
|
|
11635
12049
|
[handleRenderAncestry, buildFullAncestryTree]
|
|
@@ -11637,7 +12051,7 @@ function XViewScene({
|
|
|
11637
12051
|
const handleSelectAncestryParent = (nodeId) => {
|
|
11638
12052
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
11639
12053
|
};
|
|
11640
|
-
const handleRemoveFromAncestry =
|
|
12054
|
+
const handleRemoveFromAncestry = useCallback4((pathToRemove) => {
|
|
11641
12055
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
11642
12056
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
11643
12057
|
return;
|
|
@@ -11662,7 +12076,7 @@ function XViewScene({
|
|
|
11662
12076
|
return { ...prev, tree: newTree };
|
|
11663
12077
|
});
|
|
11664
12078
|
}, []);
|
|
11665
|
-
const handleSaveAncestry =
|
|
12079
|
+
const handleSaveAncestry = useCallback4(
|
|
11666
12080
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
11667
12081
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
11668
12082
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -11866,7 +12280,7 @@ function XViewScene({
|
|
|
11866
12280
|
});
|
|
11867
12281
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
11868
12282
|
};
|
|
11869
|
-
const handleDeleteAncestry =
|
|
12283
|
+
const handleDeleteAncestry = useCallback4(
|
|
11870
12284
|
async (ancestryIdToDelete) => {
|
|
11871
12285
|
if (!ancestryIdToDelete) {
|
|
11872
12286
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -11928,15 +12342,15 @@ function XViewScene({
|
|
|
11928
12342
|
},
|
|
11929
12343
|
[save_view_data, delete_file_action]
|
|
11930
12344
|
);
|
|
11931
|
-
const handleOpenAncestryBoard =
|
|
12345
|
+
const handleOpenAncestryBoard = useCallback4(() => {
|
|
11932
12346
|
setIsAncestryBoardOpen(true);
|
|
11933
12347
|
}, []);
|
|
11934
|
-
const handleSelectAncestryFromBoard =
|
|
12348
|
+
const handleSelectAncestryFromBoard = useCallback4((ancestry) => {
|
|
11935
12349
|
setIsAncestryBoardOpen(false);
|
|
11936
12350
|
setIsSidebarOpen(false);
|
|
11937
12351
|
handleStartReadingAncestry(ancestry);
|
|
11938
12352
|
}, [handleStartReadingAncestry]);
|
|
11939
|
-
const handleSaveAncestryBoard =
|
|
12353
|
+
const handleSaveAncestryBoard = useCallback4(async (groups) => {
|
|
11940
12354
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
11941
12355
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
11942
12356
|
await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
|
|
@@ -11960,13 +12374,13 @@ function XViewScene({
|
|
|
11960
12374
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
11961
12375
|
});
|
|
11962
12376
|
}, [parentDataRef.current, sceneVersion]);
|
|
11963
|
-
const handleAddExistingNode =
|
|
12377
|
+
const handleAddExistingNode = useCallback4(
|
|
11964
12378
|
(nodeId) => {
|
|
11965
12379
|
return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
|
|
11966
12380
|
},
|
|
11967
12381
|
[actionHandlerContext]
|
|
11968
12382
|
);
|
|
11969
|
-
const handleSaveCurrentView =
|
|
12383
|
+
const handleSaveCurrentView = useCallback4(async () => {
|
|
11970
12384
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
11971
12385
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
11972
12386
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12006,7 +12420,7 @@ function XViewScene({
|
|
|
12006
12420
|
const allAvailableAncestries = useMemo12(() => {
|
|
12007
12421
|
return ancestryDataRef.current || [];
|
|
12008
12422
|
}, [sceneVersion, isInitialized]);
|
|
12009
|
-
const handleOpenReference =
|
|
12423
|
+
const handleOpenReference = useCallback4((referenceData) => {
|
|
12010
12424
|
const { type, id } = referenceData;
|
|
12011
12425
|
if (type === "node") {
|
|
12012
12426
|
const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
|
|
@@ -12033,16 +12447,28 @@ function XViewScene({
|
|
|
12033
12447
|
}
|
|
12034
12448
|
}
|
|
12035
12449
|
}, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
|
|
12036
|
-
const handleToggleAncestryAddMode =
|
|
12450
|
+
const handleToggleAncestryAddMode = useCallback4(() => {
|
|
12037
12451
|
setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
|
|
12038
12452
|
}, []);
|
|
12039
|
-
const handleFocusNode =
|
|
12453
|
+
const handleFocusNode = useCallback4((nodeData) => {
|
|
12040
12454
|
if (!nodeData) return;
|
|
12041
12455
|
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
12042
12456
|
if (nodeMesh) {
|
|
12043
12457
|
tweenToTarget(nodeMesh, 1.2);
|
|
12044
12458
|
}
|
|
12045
12459
|
}, [tweenToTarget]);
|
|
12460
|
+
const availableDatasets = useMemo12(() => {
|
|
12461
|
+
if (!sceneDataRef.current || !parentDataRef.current) return [];
|
|
12462
|
+
return sceneDataRef.current.parent_dbs.map((db) => {
|
|
12463
|
+
var _a2;
|
|
12464
|
+
return {
|
|
12465
|
+
id: db.db_id,
|
|
12466
|
+
name: ((_a2 = parentDataRef.current[db.db_id]) == null ? void 0 : _a2.dataset_name) || `Dataset #${db.db_id.substring(0, 6)}`
|
|
12467
|
+
};
|
|
12468
|
+
});
|
|
12469
|
+
}, [sceneVersion, isInitialized]);
|
|
12470
|
+
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
|
|
12471
|
+
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
12046
12472
|
useEffect21(() => {
|
|
12047
12473
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
12048
12474
|
const nodeObjects = stateRef.current.nodeObjects || {};
|
|
@@ -12094,7 +12520,6 @@ function XViewScene({
|
|
|
12094
12520
|
height: "100vh",
|
|
12095
12521
|
position: "relative",
|
|
12096
12522
|
overflow: "hidden",
|
|
12097
|
-
// <--- ADICIONE ESTA LINHA
|
|
12098
12523
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
12099
12524
|
}
|
|
12100
12525
|
},
|
|
@@ -12132,10 +12557,13 @@ function XViewScene({
|
|
|
12132
12557
|
style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
12133
12558
|
refEl: formRef,
|
|
12134
12559
|
existingTypes: existingNodeTypes,
|
|
12135
|
-
initialColor: (
|
|
12136
|
-
sourceTypes: (
|
|
12560
|
+
initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
|
|
12561
|
+
sourceTypes: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.type,
|
|
12137
12562
|
onIntensityChange: handleGhostNodeIntensityChange,
|
|
12138
|
-
onUploadFile: upload_file_action
|
|
12563
|
+
onUploadFile: upload_file_action,
|
|
12564
|
+
availableDatasets,
|
|
12565
|
+
sourceNodeDatasetId,
|
|
12566
|
+
viewType: viewParams == null ? void 0 : viewParams.type
|
|
12139
12567
|
}
|
|
12140
12568
|
),
|
|
12141
12569
|
versionMode.isActive && /* @__PURE__ */ React23.createElement(
|
|
@@ -12150,17 +12578,28 @@ function XViewScene({
|
|
|
12150
12578
|
onMentionClick: handleAddExistingNode,
|
|
12151
12579
|
style: { position: "absolute", left: `${formPosition.left}px`, top: `${formPosition.top}px`, opacity: formPosition.opacity, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
12152
12580
|
refEl: formRef,
|
|
12153
|
-
fixedType: (
|
|
12154
|
-
fixedColor: (
|
|
12581
|
+
fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
|
|
12582
|
+
fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
|
|
12155
12583
|
onUploadFile: upload_file_action
|
|
12156
12584
|
}
|
|
12157
12585
|
),
|
|
12158
12586
|
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React23.createElement(
|
|
12159
12587
|
"div",
|
|
12160
12588
|
{
|
|
12161
|
-
className:
|
|
12162
|
-
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)" }
|
|
12589
|
+
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"}`,
|
|
12590
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
12163
12591
|
},
|
|
12592
|
+
/* @__PURE__ */ React23.createElement(
|
|
12593
|
+
"div",
|
|
12594
|
+
{
|
|
12595
|
+
onPointerDown: (e) => {
|
|
12596
|
+
e.stopPropagation();
|
|
12597
|
+
handleReadModeResize(e);
|
|
12598
|
+
},
|
|
12599
|
+
className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors",
|
|
12600
|
+
title: "Arraste para redimensionar"
|
|
12601
|
+
}
|
|
12602
|
+
),
|
|
12164
12603
|
/* @__PURE__ */ React23.createElement(
|
|
12165
12604
|
DescriptionReadModePanel,
|
|
12166
12605
|
{
|
|
@@ -12260,7 +12699,8 @@ function XViewScene({
|
|
|
12260
12699
|
onMentionClick: handleAddExistingNode,
|
|
12261
12700
|
onIntensityChange: handleDetailNodeIntensityChange,
|
|
12262
12701
|
onUploadFile: upload_file_action,
|
|
12263
|
-
userRole: userPermissionRole
|
|
12702
|
+
userRole: userPermissionRole,
|
|
12703
|
+
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
12264
12704
|
}
|
|
12265
12705
|
),
|
|
12266
12706
|
detailsLink && /* @__PURE__ */ React23.createElement(
|
|
@@ -12388,7 +12828,7 @@ function XViewScene({
|
|
|
12388
12828
|
onClose: () => setIsImportModalOpen(false),
|
|
12389
12829
|
onConfirm: handleConfirmImport,
|
|
12390
12830
|
session,
|
|
12391
|
-
parentDbs: ((
|
|
12831
|
+
parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
|
|
12392
12832
|
onFetchAvailableFiles: import_parent_file_modal_get,
|
|
12393
12833
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
12394
12834
|
currentAncestries: ancestryDataRef.current || []
|