@lv-x-software-house/x_view 1.2.4-dev.1 → 1.2.4-dev.11
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 +824 -373
- package/dist/index.mjs +744 -293
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import
|
|
2
|
+
import React24, { useCallback as useCallback4, useEffect as useEffect21, useRef as useRef18, useState as useState24, 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";
|
|
@@ -904,7 +904,7 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
|
|
|
904
904
|
if (useImage && nodeData.textureImageUrl) {
|
|
905
905
|
geometry = new THREE.CircleGeometry(1.5, 48);
|
|
906
906
|
const texture = getTexture(nodeData.textureImageUrl);
|
|
907
|
-
material = new
|
|
907
|
+
material = new MeshBasicMaterial({
|
|
908
908
|
map: texture,
|
|
909
909
|
color: 16777215,
|
|
910
910
|
side: THREE.DoubleSide,
|
|
@@ -1515,7 +1515,7 @@ var addStandaloneNodeToScene = (state, nodeData, position) => {
|
|
|
1515
1515
|
scaleTween.start();
|
|
1516
1516
|
}
|
|
1517
1517
|
};
|
|
1518
|
-
var getParentFileInfoForNode = (allParentData, sceneData, nodeId) => {
|
|
1518
|
+
var getParentFileInfoForNode = (allParentData, sceneData, nodeId, sceneConfigId = null, sceneOwnerId = null) => {
|
|
1519
1519
|
const parentDbsArray = (sceneData == null ? void 0 : sceneData.parent_dbs) || [];
|
|
1520
1520
|
for (const parentFileId in allParentData) {
|
|
1521
1521
|
if (allParentData.hasOwnProperty(parentFileId)) {
|
|
@@ -1524,6 +1524,8 @@ var getParentFileInfoForNode = (allParentData, sceneData, nodeId) => {
|
|
|
1524
1524
|
const parentDbInfo = parentDbsArray.find((db) => String(db.db_id) === String(parentFileId));
|
|
1525
1525
|
if (parentDbInfo) {
|
|
1526
1526
|
return { parentFileId, ownerId: parentDbInfo.owner_id };
|
|
1527
|
+
} else if (sceneConfigId && String(parentFileId) === String(sceneConfigId)) {
|
|
1528
|
+
return { parentFileId, ownerId: sceneOwnerId };
|
|
1527
1529
|
} else {
|
|
1528
1530
|
console.warn(`Owner ID n\xE3o encontrado em sceneData.parent_dbs para o parentFileId: ${parentFileId}`);
|
|
1529
1531
|
return { parentFileId, ownerId: null };
|
|
@@ -1793,6 +1795,7 @@ var userActionHandlers = {
|
|
|
1793
1795
|
setters.setFormPosition((p) => ({ ...p, opacity: 0 }));
|
|
1794
1796
|
},
|
|
1795
1797
|
handleSaveVersionNode: async (context, newNodeData) => {
|
|
1798
|
+
var _a;
|
|
1796
1799
|
const { graphDataRef, sceneDataRef, stateRef, versionMode, setters } = context;
|
|
1797
1800
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
1798
1801
|
const { sourceNodeData } = versionMode;
|
|
@@ -1802,7 +1805,7 @@ var userActionHandlers = {
|
|
|
1802
1805
|
version_node: { is_version: true, parent_node: sourceNodeData.id }
|
|
1803
1806
|
};
|
|
1804
1807
|
const newLink = { id: `link_${short.generate()}`, source: sourceNodeData.id, target: newNode.id };
|
|
1805
|
-
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, sourceNodeData.id);
|
|
1808
|
+
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, sourceNodeData.id, context.sceneConfigId, context.ownerId);
|
|
1806
1809
|
if (!parentInfo || !parentInfo.ownerId) {
|
|
1807
1810
|
console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o Node de origem:", sourceNodeData.id);
|
|
1808
1811
|
alert("Ocorreu um erro ao identificar o arquivo pai ou seu propriet\xE1rio.");
|
|
@@ -1812,9 +1815,21 @@ var userActionHandlers = {
|
|
|
1812
1815
|
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
|
|
1813
1816
|
specificParentData.nodes.push(newNode);
|
|
1814
1817
|
specificParentData.links.push(newLink);
|
|
1815
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
1816
1818
|
try {
|
|
1817
|
-
|
|
1819
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
1820
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
1821
|
+
const viewFilePayload = {
|
|
1822
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
1823
|
+
nodes: sceneDataRef.current.nodes,
|
|
1824
|
+
links: sceneDataRef.current.links,
|
|
1825
|
+
quest_nodes: specificParentData.nodes,
|
|
1826
|
+
quest_links: specificParentData.links
|
|
1827
|
+
};
|
|
1828
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
1829
|
+
} else {
|
|
1830
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
1831
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
1832
|
+
}
|
|
1818
1833
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
1819
1834
|
const finalPosition = stateRef.current.ghostElements.node.position.clone();
|
|
1820
1835
|
addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
|
|
@@ -1971,6 +1986,7 @@ var userActionHandlers = {
|
|
|
1971
1986
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
1972
1987
|
},
|
|
1973
1988
|
handleCompleteConnection: async (context, targetNodeData) => {
|
|
1989
|
+
var _a;
|
|
1974
1990
|
const { stateRef, graphDataRef, sceneDataRef } = context;
|
|
1975
1991
|
const { sourceNodeData } = stateRef.current.connection;
|
|
1976
1992
|
if (!graphDataRef.current || !sceneDataRef.current || !sourceNodeData || !targetNodeData) {
|
|
@@ -1978,7 +1994,7 @@ var userActionHandlers = {
|
|
|
1978
1994
|
userActionHandlers.handleCancelConnection(context);
|
|
1979
1995
|
return;
|
|
1980
1996
|
}
|
|
1981
|
-
const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, sourceNodeData.id);
|
|
1997
|
+
const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, sourceNodeData.id, context.sceneConfigId, context.ownerId);
|
|
1982
1998
|
if (!sourceParentInfo || !sourceParentInfo.ownerId) {
|
|
1983
1999
|
console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o Node de origem:", sourceNodeData.id);
|
|
1984
2000
|
alert("Ocorreu um erro ao identificar o arquivo pai ou seu propriet\xE1rio.");
|
|
@@ -1993,12 +2009,26 @@ var userActionHandlers = {
|
|
|
1993
2009
|
source: sourceNodeData.id,
|
|
1994
2010
|
target: targetNodeData.id
|
|
1995
2011
|
};
|
|
1996
|
-
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
1997
|
-
specificParentData.links.push(newLink);
|
|
1998
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
1999
2012
|
try {
|
|
2000
|
-
|
|
2001
|
-
|
|
2013
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2014
|
+
if (isView && parentFileIdToSave === context.sceneConfigId) {
|
|
2015
|
+
const specificParentData = graphDataRef.current[context.sceneConfigId];
|
|
2016
|
+
specificParentData.links.push(newLink);
|
|
2017
|
+
const viewFilePayload = {
|
|
2018
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2019
|
+
nodes: sceneDataRef.current.nodes,
|
|
2020
|
+
links: sceneDataRef.current.links,
|
|
2021
|
+
quest_nodes: specificParentData.nodes,
|
|
2022
|
+
quest_links: specificParentData.links
|
|
2023
|
+
};
|
|
2024
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2025
|
+
} else {
|
|
2026
|
+
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
2027
|
+
specificParentData.links.push(newLink);
|
|
2028
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
2029
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2030
|
+
graphDataRef.current[parentFileIdToSave] = specificParentData;
|
|
2031
|
+
}
|
|
2002
2032
|
addNewLinkToScene(stateRef.current, newLink);
|
|
2003
2033
|
} catch (error) {
|
|
2004
2034
|
console.error("Falha ao salvar a nova conex\xE3o:", error);
|
|
@@ -2067,8 +2097,8 @@ var userActionHandlers = {
|
|
|
2067
2097
|
} else {
|
|
2068
2098
|
newTargetId = newEndNodeData.id;
|
|
2069
2099
|
}
|
|
2070
|
-
const originalParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldSourceId);
|
|
2071
|
-
const newParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newSourceId);
|
|
2100
|
+
const originalParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldSourceId, context.sceneConfigId, context.ownerId);
|
|
2101
|
+
const newParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newSourceId, context.sceneConfigId, context.ownerId);
|
|
2072
2102
|
if (!originalParentInfo || !newParentInfo || !originalParentInfo.ownerId || !newParentInfo.ownerId) {
|
|
2073
2103
|
console.error("N\xE3o foi poss\xEDvel encontrar informa\xE7\xF5es dos arquivos pai para o relink.");
|
|
2074
2104
|
alert("Ocorreu um erro ao identificar os arquivos pai para salvar a altera\xE7\xE3o.");
|
|
@@ -2082,6 +2112,22 @@ var userActionHandlers = {
|
|
|
2082
2112
|
target: newTargetId,
|
|
2083
2113
|
id: linkId
|
|
2084
2114
|
};
|
|
2115
|
+
const saveParentData = async (fileId, fileOwnerId, data) => {
|
|
2116
|
+
var _a;
|
|
2117
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2118
|
+
if (isView && fileId === context.sceneConfigId) {
|
|
2119
|
+
const viewFilePayload = {
|
|
2120
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2121
|
+
nodes: sceneDataRef.current.nodes,
|
|
2122
|
+
links: sceneDataRef.current.links,
|
|
2123
|
+
quest_nodes: data.nodes,
|
|
2124
|
+
quest_links: data.links
|
|
2125
|
+
};
|
|
2126
|
+
return context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2127
|
+
} else {
|
|
2128
|
+
return context.actions.save_view_data(`x_view_dbs/${fileOwnerId}/${fileId}`, data);
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2085
2131
|
const savePromises = [];
|
|
2086
2132
|
const filesToUpdate = {};
|
|
2087
2133
|
if (originalParentInfo.parentFileId !== newParentInfo.parentFileId) {
|
|
@@ -2090,16 +2136,12 @@ var userActionHandlers = {
|
|
|
2090
2136
|
(l) => String(l.id) !== String(linkId)
|
|
2091
2137
|
);
|
|
2092
2138
|
filesToUpdate[originalParentInfo.parentFileId] = updatedOriginalParentData;
|
|
2093
|
-
savePromises.push(
|
|
2094
|
-
context.actions.save_view_data(`x_view_dbs/${originalParentInfo.ownerId}/${originalParentInfo.parentFileId}`, updatedOriginalParentData)
|
|
2095
|
-
);
|
|
2139
|
+
savePromises.push(saveParentData(originalParentInfo.parentFileId, originalParentInfo.ownerId, updatedOriginalParentData));
|
|
2096
2140
|
const updatedNewParentData = JSON.parse(JSON.stringify(graphDataRef.current[newParentInfo.parentFileId]));
|
|
2097
2141
|
if (!updatedNewParentData.links) updatedNewParentData.links = [];
|
|
2098
2142
|
updatedNewParentData.links.push(newLinkData);
|
|
2099
2143
|
filesToUpdate[newParentInfo.parentFileId] = updatedNewParentData;
|
|
2100
|
-
savePromises.push(
|
|
2101
|
-
context.actions.save_view_data(`x_view_dbs/${newParentInfo.ownerId}/${newParentInfo.parentFileId}`, updatedNewParentData)
|
|
2102
|
-
);
|
|
2144
|
+
savePromises.push(saveParentData(newParentInfo.parentFileId, newParentInfo.ownerId, updatedNewParentData));
|
|
2103
2145
|
} else {
|
|
2104
2146
|
const updatedParentData = JSON.parse(JSON.stringify(graphDataRef.current[originalParentInfo.parentFileId]));
|
|
2105
2147
|
updatedParentData.links = updatedParentData.links.filter(
|
|
@@ -2107,9 +2149,7 @@ var userActionHandlers = {
|
|
|
2107
2149
|
);
|
|
2108
2150
|
updatedParentData.links.push(newLinkData);
|
|
2109
2151
|
filesToUpdate[originalParentInfo.parentFileId] = updatedParentData;
|
|
2110
|
-
savePromises.push(
|
|
2111
|
-
context.actions.save_view_data(`x_view_dbs/${originalParentInfo.ownerId}/${originalParentInfo.parentFileId}`, updatedParentData)
|
|
2112
|
-
);
|
|
2152
|
+
savePromises.push(saveParentData(originalParentInfo.parentFileId, originalParentInfo.ownerId, updatedParentData));
|
|
2113
2153
|
}
|
|
2114
2154
|
try {
|
|
2115
2155
|
await Promise.all(savePromises);
|
|
@@ -2127,7 +2167,7 @@ var userActionHandlers = {
|
|
|
2127
2167
|
}
|
|
2128
2168
|
},
|
|
2129
2169
|
handleDeleteLink: async (context, linkObject) => {
|
|
2130
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2170
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2131
2171
|
const { stateRef, graphDataRef, sceneDataRef, setters } = context;
|
|
2132
2172
|
setters.setRelationshipMenu({ visible: false });
|
|
2133
2173
|
if (!(linkObject == null ? void 0 : linkObject.userData) || !graphDataRef.current || !sceneDataRef.current) return;
|
|
@@ -2136,7 +2176,7 @@ var userActionHandlers = {
|
|
|
2136
2176
|
console.error("Tentativa de deletar um link sem ID.", linkObject.userData);
|
|
2137
2177
|
return;
|
|
2138
2178
|
}
|
|
2139
|
-
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, linkObject.userData.source);
|
|
2179
|
+
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, linkObject.userData.source, context.sceneConfigId, context.ownerId);
|
|
2140
2180
|
if (!parentInfo || !parentInfo.ownerId) {
|
|
2141
2181
|
console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o link:", linkIdToDelete);
|
|
2142
2182
|
alert("Ocorreu um erro ao identificar o arquivo pai da rela\xE7\xE3o para exclus\xE3o.");
|
|
@@ -2148,9 +2188,25 @@ var userActionHandlers = {
|
|
|
2148
2188
|
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
|
|
2149
2189
|
const newLinks = (specificParentData.links || []).filter((l) => String(l.id) !== String(linkIdToDelete));
|
|
2150
2190
|
specificParentData.links = newLinks;
|
|
2151
|
-
|
|
2191
|
+
let filenameToSave;
|
|
2192
|
+
let payloadToSave;
|
|
2193
|
+
const isView = ((_g = context.viewType) == null ? void 0 : _g.toLowerCase()) === "view";
|
|
2194
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2195
|
+
filenameToSave = context.sceneSaveUrl;
|
|
2196
|
+
sceneDataRef.current.links = sceneDataRef.current.links.filter((l) => String(l.id) !== String(linkIdToDelete));
|
|
2197
|
+
payloadToSave = {
|
|
2198
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2199
|
+
nodes: sceneDataRef.current.nodes,
|
|
2200
|
+
links: sceneDataRef.current.links,
|
|
2201
|
+
quest_nodes: specificParentData.nodes,
|
|
2202
|
+
quest_links: specificParentData.links
|
|
2203
|
+
};
|
|
2204
|
+
} else {
|
|
2205
|
+
filenameToSave = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2206
|
+
payloadToSave = specificParentData;
|
|
2207
|
+
}
|
|
2152
2208
|
try {
|
|
2153
|
-
await context.actions.save_view_data(
|
|
2209
|
+
await context.actions.save_view_data(filenameToSave, payloadToSave);
|
|
2154
2210
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2155
2211
|
setters.setDetailsLink((prev) => String(prev == null ? void 0 : prev.id) === String(linkIdToDelete) ? null : prev);
|
|
2156
2212
|
if (stateRef.current.hoveredLink === linkObject) {
|
|
@@ -2295,6 +2351,7 @@ var userActionHandlers = {
|
|
|
2295
2351
|
stateRef.current.selectedNodes.clear();
|
|
2296
2352
|
},
|
|
2297
2353
|
handleDeleteMultipleNodes: async (context, nodeIds) => {
|
|
2354
|
+
var _a;
|
|
2298
2355
|
const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
|
|
2299
2356
|
setters.setMultiContextMenu({ visible: false });
|
|
2300
2357
|
if (!nodeIds || nodeIds.size === 0 || !graphDataRef.current || !sceneDataRef.current) return;
|
|
@@ -2313,7 +2370,7 @@ var userActionHandlers = {
|
|
|
2313
2370
|
}
|
|
2314
2371
|
const changesByParentFile = {};
|
|
2315
2372
|
for (const nodeId of strNodeIdsToDelete) {
|
|
2316
|
-
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeId);
|
|
2373
|
+
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeId, context.sceneConfigId, context.ownerId);
|
|
2317
2374
|
if (!parentInfo || !parentInfo.ownerId) {
|
|
2318
2375
|
console.warn(`Node com ID ${nodeId} n\xE3o encontrado ou sem ownerId. Ignorando.`);
|
|
2319
2376
|
continue;
|
|
@@ -2347,8 +2404,27 @@ var userActionHandlers = {
|
|
|
2347
2404
|
originalData.links = (originalData.links || []).filter(
|
|
2348
2405
|
(l) => !linksToDelete.has(String(l.id))
|
|
2349
2406
|
);
|
|
2350
|
-
|
|
2351
|
-
|
|
2407
|
+
let filenameToSave;
|
|
2408
|
+
let payloadToSave;
|
|
2409
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2410
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2411
|
+
filenameToSave = context.sceneSaveUrl;
|
|
2412
|
+
const strNodesToDelete = Array.from(nodesToDelete).map(String);
|
|
2413
|
+
const strLinksToDelete = Array.from(linksToDelete).map(String);
|
|
2414
|
+
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter((n) => !strNodesToDelete.includes(String(n.id)));
|
|
2415
|
+
sceneDataRef.current.links = sceneDataRef.current.links.filter((l) => !strLinksToDelete.includes(String(l.id)));
|
|
2416
|
+
payloadToSave = {
|
|
2417
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2418
|
+
nodes: sceneDataRef.current.nodes,
|
|
2419
|
+
links: sceneDataRef.current.links,
|
|
2420
|
+
quest_nodes: originalData.nodes,
|
|
2421
|
+
quest_links: originalData.links
|
|
2422
|
+
};
|
|
2423
|
+
} else {
|
|
2424
|
+
filenameToSave = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2425
|
+
payloadToSave = originalData;
|
|
2426
|
+
}
|
|
2427
|
+
savePromises.push(context.actions.save_view_data(filenameToSave, payloadToSave));
|
|
2352
2428
|
updatedParentDataCache[parentFileId] = originalData;
|
|
2353
2429
|
}
|
|
2354
2430
|
}
|
|
@@ -2369,6 +2445,7 @@ var userActionHandlers = {
|
|
|
2369
2445
|
}
|
|
2370
2446
|
},
|
|
2371
2447
|
handleDeleteNode: async (context, nodeData) => {
|
|
2448
|
+
var _a;
|
|
2372
2449
|
const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
|
|
2373
2450
|
if (actions.delete_file && nodeData) {
|
|
2374
2451
|
const urls = extractFileUrlsFromProperties(nodeData);
|
|
@@ -2380,7 +2457,7 @@ var userActionHandlers = {
|
|
|
2380
2457
|
if (!nodeData || !graphDataRef.current || !sceneDataRef.current) return;
|
|
2381
2458
|
const nodeIdToDelete = nodeData.id;
|
|
2382
2459
|
const strNodeId = String(nodeIdToDelete);
|
|
2383
|
-
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeIdToDelete);
|
|
2460
|
+
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeIdToDelete, context.sceneConfigId, context.ownerId);
|
|
2384
2461
|
if (!parentInfo || !parentInfo.ownerId) {
|
|
2385
2462
|
console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o Node a ser exclu\xEDdo:", nodeIdToDelete);
|
|
2386
2463
|
alert("Ocorreu um erro ao identificar o arquivo pai ou seu propriet\xE1rio para exclus\xE3o.");
|
|
@@ -2392,9 +2469,28 @@ var userActionHandlers = {
|
|
|
2392
2469
|
const newLinks = (specificParentData.links || []).filter((l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId);
|
|
2393
2470
|
specificParentData.nodes = newNodes;
|
|
2394
2471
|
specificParentData.links = newLinks;
|
|
2395
|
-
|
|
2472
|
+
let filenameToSave;
|
|
2473
|
+
let payloadToSave;
|
|
2474
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2475
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2476
|
+
filenameToSave = context.sceneSaveUrl;
|
|
2477
|
+
const newVisualNodes = sceneDataRef.current.nodes.filter((n) => String(n.id) !== strNodeId);
|
|
2478
|
+
const newVisualLinks = sceneDataRef.current.links.filter((l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId);
|
|
2479
|
+
sceneDataRef.current.nodes = newVisualNodes;
|
|
2480
|
+
sceneDataRef.current.links = newVisualLinks;
|
|
2481
|
+
payloadToSave = {
|
|
2482
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2483
|
+
nodes: newVisualNodes,
|
|
2484
|
+
links: newVisualLinks,
|
|
2485
|
+
quest_nodes: specificParentData.nodes,
|
|
2486
|
+
quest_links: specificParentData.links
|
|
2487
|
+
};
|
|
2488
|
+
} else {
|
|
2489
|
+
filenameToSave = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2490
|
+
payloadToSave = specificParentData;
|
|
2491
|
+
}
|
|
2396
2492
|
try {
|
|
2397
|
-
await context.actions.save_view_data(
|
|
2493
|
+
await context.actions.save_view_data(filenameToSave, payloadToSave);
|
|
2398
2494
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2399
2495
|
setters.setDetailsNode((prev) => String(prev == null ? void 0 : prev.id) === String(nodeIdToDelete) ? null : prev);
|
|
2400
2496
|
removeNodeFromScene(stateRef.current, nodeIdToDelete);
|
|
@@ -2405,10 +2501,11 @@ var userActionHandlers = {
|
|
|
2405
2501
|
}
|
|
2406
2502
|
},
|
|
2407
2503
|
handleSaveNodeDetails: async (context, updatedNode, keepOpen = false) => {
|
|
2504
|
+
var _a;
|
|
2408
2505
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2409
2506
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2410
2507
|
const { _baseEmissiveIntensity: ignored, ...nodeToSave } = updatedNode;
|
|
2411
|
-
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeToSave.id);
|
|
2508
|
+
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeToSave.id, context.sceneConfigId, context.ownerId);
|
|
2412
2509
|
if (!parentInfo || !parentInfo.ownerId) {
|
|
2413
2510
|
console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o Node a ser atualizado:", nodeToSave.id);
|
|
2414
2511
|
alert("Ocorreu um erro ao identificar o arquivo pai ou seu propriet\xE1rio para atualiza\xE7\xE3o.");
|
|
@@ -2424,9 +2521,21 @@ var userActionHandlers = {
|
|
|
2424
2521
|
alert("Erro interno: Node n\xE3o encontrado para salvar.");
|
|
2425
2522
|
return;
|
|
2426
2523
|
}
|
|
2427
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2428
2524
|
try {
|
|
2429
|
-
|
|
2525
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2526
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2527
|
+
const viewFilePayload = {
|
|
2528
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2529
|
+
nodes: sceneDataRef.current.nodes,
|
|
2530
|
+
links: sceneDataRef.current.links,
|
|
2531
|
+
quest_nodes: specificParentData.nodes,
|
|
2532
|
+
quest_links: specificParentData.links
|
|
2533
|
+
};
|
|
2534
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2535
|
+
} else {
|
|
2536
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2537
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2538
|
+
}
|
|
2430
2539
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2431
2540
|
updateExistingNodeVisuals(stateRef.current, nodeToSave);
|
|
2432
2541
|
setters.setSceneVersion((v) => v + 1);
|
|
@@ -2439,10 +2548,11 @@ var userActionHandlers = {
|
|
|
2439
2548
|
}
|
|
2440
2549
|
},
|
|
2441
2550
|
handleSaveLinkDetails: async (context, updatedLink, keepOpen = false) => {
|
|
2551
|
+
var _a;
|
|
2442
2552
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2443
2553
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2444
2554
|
const { sourceNode, targetNode, ...linkToSave } = updatedLink;
|
|
2445
|
-
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, linkToSave.source);
|
|
2555
|
+
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, linkToSave.source, context.sceneConfigId, context.ownerId);
|
|
2446
2556
|
if (!parentInfo || !parentInfo.ownerId) {
|
|
2447
2557
|
console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o link a ser atualizado:", linkToSave.id);
|
|
2448
2558
|
alert("Ocorreu um erro ao identificar o arquivo pai ou seu propriet\xE1rio para atualiza\xE7\xE3o.");
|
|
@@ -2458,9 +2568,21 @@ var userActionHandlers = {
|
|
|
2458
2568
|
alert("Erro interno: link n\xE3o encontrado para salvar.");
|
|
2459
2569
|
return;
|
|
2460
2570
|
}
|
|
2461
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2462
2571
|
try {
|
|
2463
|
-
|
|
2572
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2573
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2574
|
+
const viewFilePayload = {
|
|
2575
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2576
|
+
nodes: sceneDataRef.current.nodes,
|
|
2577
|
+
links: sceneDataRef.current.links,
|
|
2578
|
+
quest_nodes: specificParentData.nodes,
|
|
2579
|
+
quest_links: specificParentData.links
|
|
2580
|
+
};
|
|
2581
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2582
|
+
} else {
|
|
2583
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2584
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2585
|
+
}
|
|
2464
2586
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2465
2587
|
const lineObject = stateRef.current.allLinks.find(
|
|
2466
2588
|
(l) => String(l.userData.id) === String(linkToSave.id)
|
|
@@ -7835,9 +7957,180 @@ function InSceneVersionForm({
|
|
|
7835
7957
|
));
|
|
7836
7958
|
}
|
|
7837
7959
|
|
|
7960
|
+
// src/components/InSceneQuestForm.jsx
|
|
7961
|
+
import React15, { useState as useState16, useRef as useRef12 } from "react";
|
|
7962
|
+
import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4 } from "react-icons/fi";
|
|
7963
|
+
var QUEST_STATUS_COLORS = {
|
|
7964
|
+
"Backlog": "#64748b",
|
|
7965
|
+
// Slate (Cinza azulado)
|
|
7966
|
+
"In Progress": "#eab308",
|
|
7967
|
+
// Yellow (Amarelo)
|
|
7968
|
+
"Review": "#a855f7",
|
|
7969
|
+
// Purple (Roxo)
|
|
7970
|
+
"Done": "#22c55e"
|
|
7971
|
+
// Green (Verde)
|
|
7972
|
+
};
|
|
7973
|
+
function InSceneQuestForm({
|
|
7974
|
+
onSave,
|
|
7975
|
+
onCancel,
|
|
7976
|
+
style,
|
|
7977
|
+
refEl,
|
|
7978
|
+
onOpenImageViewer,
|
|
7979
|
+
availableNodes = [],
|
|
7980
|
+
availableAncestries = [],
|
|
7981
|
+
onMentionClick,
|
|
7982
|
+
onUploadFile
|
|
7983
|
+
}) {
|
|
7984
|
+
const [name, setName] = useState16("");
|
|
7985
|
+
const [types, setTypes] = useState16(["quest"]);
|
|
7986
|
+
const [typeInput, setTypeInput] = useState16("");
|
|
7987
|
+
const [status, setStatus] = useState16("Backlog");
|
|
7988
|
+
const [size, setSize] = useState16("medium");
|
|
7989
|
+
const [intensity, setIntensity] = useState16(0);
|
|
7990
|
+
const [description, setDescription] = useState16("");
|
|
7991
|
+
const [customProps, setCustomProps] = useState16([]);
|
|
7992
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
|
|
7993
|
+
const propsEndRef = useRef12(null);
|
|
7994
|
+
const handleAddProp = () => {
|
|
7995
|
+
const newProp = createNewCustomProperty(customProps);
|
|
7996
|
+
setCustomProps([...customProps, newProp]);
|
|
7997
|
+
setTimeout(() => {
|
|
7998
|
+
var _a;
|
|
7999
|
+
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
8000
|
+
}, 100);
|
|
8001
|
+
};
|
|
8002
|
+
const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
|
|
8003
|
+
const handleUpdateProp = (index, updatedProp) => {
|
|
8004
|
+
const newProps = [...customProps];
|
|
8005
|
+
newProps[index] = updatedProp;
|
|
8006
|
+
setCustomProps(newProps);
|
|
8007
|
+
};
|
|
8008
|
+
const handleAddType = (newType) => {
|
|
8009
|
+
const trimmed = newType.trim();
|
|
8010
|
+
if (trimmed && !types.includes(trimmed)) {
|
|
8011
|
+
setTypes([...types, trimmed]);
|
|
8012
|
+
setTypeInput("");
|
|
8013
|
+
}
|
|
8014
|
+
};
|
|
8015
|
+
const handleRemoveType = (indexToRemove) => {
|
|
8016
|
+
if (types[indexToRemove] === "quest") return;
|
|
8017
|
+
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
8018
|
+
};
|
|
8019
|
+
const handleTypeInputKeyDown = (e) => {
|
|
8020
|
+
if (e.key === "Enter") {
|
|
8021
|
+
e.preventDefault();
|
|
8022
|
+
handleAddType(typeInput);
|
|
8023
|
+
} else if (e.key === "Backspace" && typeInput === "" && types.length > 1) {
|
|
8024
|
+
handleRemoveType(types.length - 1);
|
|
8025
|
+
}
|
|
8026
|
+
};
|
|
8027
|
+
const handleSubmit = (e) => {
|
|
8028
|
+
e.preventDefault();
|
|
8029
|
+
if (!name.trim()) {
|
|
8030
|
+
alert("O campo 'Nome' \xE9 obrigat\xF3rio.");
|
|
8031
|
+
return;
|
|
8032
|
+
}
|
|
8033
|
+
const additionalData = toObjectFromCustomProps(
|
|
8034
|
+
customProps.filter((prop) => prop.key.trim() && !prop.isEditing)
|
|
8035
|
+
);
|
|
8036
|
+
const processedSections = processDescriptionForSave(description, []);
|
|
8037
|
+
onSave({
|
|
8038
|
+
name: name.trim(),
|
|
8039
|
+
type: types,
|
|
8040
|
+
color: QUEST_STATUS_COLORS[status],
|
|
8041
|
+
// Cor atrelada ao status
|
|
8042
|
+
status,
|
|
8043
|
+
size,
|
|
8044
|
+
intensity,
|
|
8045
|
+
description: description.trim(),
|
|
8046
|
+
description_sections: processedSections,
|
|
8047
|
+
useImageAsTexture: false,
|
|
8048
|
+
textureImageUrl: null,
|
|
8049
|
+
...additionalData
|
|
8050
|
+
});
|
|
8051
|
+
};
|
|
8052
|
+
const swallow = (e) => e.stopPropagation();
|
|
8053
|
+
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
8054
|
+
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
8055
|
+
return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
|
|
8056
|
+
"div",
|
|
8057
|
+
{
|
|
8058
|
+
ref: refEl,
|
|
8059
|
+
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 w-[min(92vw,440px)] overflow-hidden",
|
|
8060
|
+
style,
|
|
8061
|
+
onPointerDown: swallow,
|
|
8062
|
+
onClick: swallow,
|
|
8063
|
+
onWheel: swallow,
|
|
8064
|
+
onContextMenu: swallow,
|
|
8065
|
+
onDoubleClick: swallow
|
|
8066
|
+
},
|
|
8067
|
+
/* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS[status]}, transparent)` } }),
|
|
8068
|
+
/* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3" }, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement(FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova Tarefa / Objetivo")), /* @__PURE__ */ React15.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")),
|
|
8069
|
+
/* @__PURE__ */ React15.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ React15.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React15.createElement(
|
|
8070
|
+
"select",
|
|
8071
|
+
{
|
|
8072
|
+
value: status,
|
|
8073
|
+
onChange: (e) => setStatus(e.target.value),
|
|
8074
|
+
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 appearance-none cursor-pointer",
|
|
8075
|
+
style: { borderLeft: `4px solid ${QUEST_STATUS_COLORS[status]}` }
|
|
8076
|
+
},
|
|
8077
|
+
/* @__PURE__ */ React15.createElement("option", { value: "Backlog" }, "Backlog"),
|
|
8078
|
+
/* @__PURE__ */ React15.createElement("option", { value: "In Progress" }, "In Progress"),
|
|
8079
|
+
/* @__PURE__ */ React15.createElement("option", { value: "Review" }, "Review"),
|
|
8080
|
+
/* @__PURE__ */ React15.createElement("option", { value: "Done" }, "Done")
|
|
8081
|
+
)), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ React15.createElement("input", { required: true, type: "text", placeholder: "Ex.: Refatorar M\xF3dulo X", value: name, onChange: (e) => setName(e.target.value), 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__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
|
|
8082
|
+
"input",
|
|
8083
|
+
{
|
|
8084
|
+
type: "text",
|
|
8085
|
+
value: typeInput,
|
|
8086
|
+
onChange: (e) => setTypeInput(e.target.value),
|
|
8087
|
+
onKeyDown: handleTypeInputKeyDown,
|
|
8088
|
+
onBlur: () => {
|
|
8089
|
+
if (typeInput.trim()) handleAddType(typeInput);
|
|
8090
|
+
},
|
|
8091
|
+
className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200",
|
|
8092
|
+
autoComplete: "off"
|
|
8093
|
+
}
|
|
8094
|
+
))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o (Opcional)"), /* @__PURE__ */ React15.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__ */ React15.createElement(
|
|
8095
|
+
DescriptionDisplay,
|
|
8096
|
+
{
|
|
8097
|
+
description,
|
|
8098
|
+
savedSections: [],
|
|
8099
|
+
availableNodes,
|
|
8100
|
+
availableAncestries,
|
|
8101
|
+
onMentionClick,
|
|
8102
|
+
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
8103
|
+
}
|
|
8104
|
+
), /* @__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 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiEdit26, { size: 14 }))), !description && /* @__PURE__ */ React15.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Cen\xE1rio (Size)"), /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ React15.createElement("button", { key: s, type: "button", onClick: () => setSize(s), className: "flex items-center gap-2 group cursor-pointer focus:outline-none" }, /* @__PURE__ */ React15.createElement("div", { className: `w-4 h-4 rounded-[4px] border flex items-center justify-center transition-all duration-200 ${size === s ? "bg-indigo-500 border-indigo-500" : "border-slate-600 bg-transparent group-hover:border-slate-500"}` }, size === s && /* @__PURE__ */ React15.createElement(FiCheck9, { size: 12, className: "text-white" })), /* @__PURE__ */ React15.createElement("span", { className: `text-sm capitalize transition-colors ${size === s ? "text-white font-medium" : "text-slate-400 group-hover:text-slate-300"}` }, s))))), /* @__PURE__ */ React15.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React15.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React15.createElement(FiPlus5, { size: 14 }), " Adicionar")), /* @__PURE__ */ React15.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React15.createElement(
|
|
8105
|
+
CustomPropertyDisplay,
|
|
8106
|
+
{
|
|
8107
|
+
key: prop.id,
|
|
8108
|
+
prop,
|
|
8109
|
+
onUpdate: (updatedProp) => handleUpdateProp(index, updatedProp),
|
|
8110
|
+
onRemove: () => handleRemoveProp(index),
|
|
8111
|
+
onOpenImageViewer,
|
|
8112
|
+
unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type),
|
|
8113
|
+
onUploadFile
|
|
8114
|
+
}
|
|
8115
|
+
)), /* @__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", { type: "button", onClick: onCancel, className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm" }, "Cancelar"), /* @__PURE__ */ React15.createElement("button", { type: "submit", className: "px-4 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 Quest")))
|
|
8116
|
+
), isDescriptionModalOpen && /* @__PURE__ */ React15.createElement(
|
|
8117
|
+
DescriptionEditModal,
|
|
8118
|
+
{
|
|
8119
|
+
isOpen: isDescriptionModalOpen,
|
|
8120
|
+
title: "Editar Descri\xE7\xE3o da Quest",
|
|
8121
|
+
initialValue: description,
|
|
8122
|
+
onSave: (newDescription) => setDescription(newDescription),
|
|
8123
|
+
onClose: () => setIsDescriptionModalOpen(false),
|
|
8124
|
+
availableNodes,
|
|
8125
|
+
availableAncestries,
|
|
8126
|
+
availableImages
|
|
8127
|
+
}
|
|
8128
|
+
));
|
|
8129
|
+
}
|
|
8130
|
+
|
|
7838
8131
|
// src/components/NodeDetailsPanel.jsx
|
|
7839
|
-
import
|
|
7840
|
-
import { FiPlus as
|
|
8132
|
+
import React16, { useState as useState17, useEffect as useEffect15, useRef as useRef13 } from "react";
|
|
8133
|
+
import { FiPlus as FiPlus6, FiMaximize2 as FiMaximize23, FiX as FiX5, FiCheck as FiCheck10, FiImage as FiImage3, FiEdit2 as FiEdit27, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
|
|
7841
8134
|
function NodeDetailsPanel({
|
|
7842
8135
|
node,
|
|
7843
8136
|
onClose,
|
|
@@ -7858,27 +8151,27 @@ function NodeDetailsPanel({
|
|
|
7858
8151
|
userRole,
|
|
7859
8152
|
currentDatasetName
|
|
7860
8153
|
}) {
|
|
7861
|
-
const [name, setName] =
|
|
7862
|
-
const [types, setTypes] =
|
|
7863
|
-
const [typeInput, setTypeInput] =
|
|
7864
|
-
const [color, setColor] =
|
|
7865
|
-
const [size, setSize] =
|
|
7866
|
-
const [description, setDescription] =
|
|
7867
|
-
const [intensity, setIntensity] =
|
|
7868
|
-
const [customProps, setCustomProps] =
|
|
7869
|
-
const [showTypeSuggestions, setShowTypeSuggestions] =
|
|
7870
|
-
const [filteredTypes, setFilteredTypes] =
|
|
7871
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
7872
|
-
const [isReadMode, setIsReadMode] =
|
|
7873
|
-
const [existingSections, setExistingSections] =
|
|
7874
|
-
const [isSaving, setIsSaving] =
|
|
7875
|
-
const [isLinkCopied, setIsLinkCopied] =
|
|
7876
|
-
const [useImageAsTexture, setUseImageAsTexture] =
|
|
8154
|
+
const [name, setName] = useState17((node == null ? void 0 : node.name) ?? "");
|
|
8155
|
+
const [types, setTypes] = useState17([]);
|
|
8156
|
+
const [typeInput, setTypeInput] = useState17("");
|
|
8157
|
+
const [color, setColor] = useState17((node == null ? void 0 : node.color) ?? "#8b5cf6");
|
|
8158
|
+
const [size, setSize] = useState17((node == null ? void 0 : node.size) ?? "medium");
|
|
8159
|
+
const [description, setDescription] = useState17((node == null ? void 0 : node.description) ?? "");
|
|
8160
|
+
const [intensity, setIntensity] = useState17((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8161
|
+
const [customProps, setCustomProps] = useState17(() => extractCustomPropsFromNode(node || {}));
|
|
8162
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState17(false);
|
|
8163
|
+
const [filteredTypes, setFilteredTypes] = useState17([]);
|
|
8164
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState17(false);
|
|
8165
|
+
const [isReadMode, setIsReadMode] = useState17(false);
|
|
8166
|
+
const [existingSections, setExistingSections] = useState17((node == null ? void 0 : node.description_sections) || []);
|
|
8167
|
+
const [isSaving, setIsSaving] = useState17(false);
|
|
8168
|
+
const [isLinkCopied, setIsLinkCopied] = useState17(false);
|
|
8169
|
+
const [useImageAsTexture, setUseImageAsTexture] = useState17(() => {
|
|
7877
8170
|
if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
|
|
7878
8171
|
if ((node == null ? void 0 : node.useImageAsTexture) === "false") return false;
|
|
7879
8172
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
7880
8173
|
});
|
|
7881
|
-
const [selectedImageUrl, setSelectedImageUrl] =
|
|
8174
|
+
const [selectedImageUrl, setSelectedImageUrl] = useState17((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
7882
8175
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
7883
8176
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
7884
8177
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -7888,8 +8181,8 @@ function NodeDetailsPanel({
|
|
|
7888
8181
|
useEffect15(() => {
|
|
7889
8182
|
setWidth(isReadMode ? 700 : 440);
|
|
7890
8183
|
}, [isReadMode, setWidth]);
|
|
7891
|
-
const prevNodeIdRef =
|
|
7892
|
-
const propsEndRef =
|
|
8184
|
+
const prevNodeIdRef = useRef13(null);
|
|
8185
|
+
const propsEndRef = useRef13(null);
|
|
7893
8186
|
const canEdit = userRole !== "viewer";
|
|
7894
8187
|
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
7895
8188
|
const handleImageClickFromText = (url, name2) => {
|
|
@@ -8097,7 +8390,7 @@ function NodeDetailsPanel({
|
|
|
8097
8390
|
onClose();
|
|
8098
8391
|
};
|
|
8099
8392
|
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
8100
|
-
return /* @__PURE__ */
|
|
8393
|
+
return /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
|
|
8101
8394
|
"div",
|
|
8102
8395
|
{
|
|
8103
8396
|
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"}`,
|
|
@@ -8110,7 +8403,7 @@ function NodeDetailsPanel({
|
|
|
8110
8403
|
onContextMenu: swallow,
|
|
8111
8404
|
onDoubleClick: swallow
|
|
8112
8405
|
},
|
|
8113
|
-
/* @__PURE__ */
|
|
8406
|
+
/* @__PURE__ */ React16.createElement(
|
|
8114
8407
|
"div",
|
|
8115
8408
|
{
|
|
8116
8409
|
onPointerDown: (e) => {
|
|
@@ -8121,7 +8414,7 @@ function NodeDetailsPanel({
|
|
|
8121
8414
|
title: "Arraste para redimensionar"
|
|
8122
8415
|
}
|
|
8123
8416
|
),
|
|
8124
|
-
isReadMode ? /* @__PURE__ */
|
|
8417
|
+
isReadMode ? /* @__PURE__ */ React16.createElement(
|
|
8125
8418
|
DescriptionReadModePanel,
|
|
8126
8419
|
{
|
|
8127
8420
|
title: name || (node == null ? void 0 : node.name),
|
|
@@ -8142,23 +8435,23 @@ function NodeDetailsPanel({
|
|
|
8142
8435
|
onImageClick: handleImageClickFromText,
|
|
8143
8436
|
onSaveDescription: handleSaveDescriptionInline
|
|
8144
8437
|
}
|
|
8145
|
-
) : /* @__PURE__ */
|
|
8438
|
+
) : /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ React16.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React16.createElement("div", null, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React16.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__ */ React16.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ React16.createElement(
|
|
8146
8439
|
"button",
|
|
8147
8440
|
{
|
|
8148
8441
|
onClick: handleCopyLink,
|
|
8149
8442
|
className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-indigo-400"}`,
|
|
8150
8443
|
title: isLinkCopied ? "Link Copiado!" : "Copiar link para este Node"
|
|
8151
8444
|
},
|
|
8152
|
-
isLinkCopied ? /* @__PURE__ */
|
|
8153
|
-
)), /* @__PURE__ */
|
|
8445
|
+
isLinkCopied ? /* @__PURE__ */ React16.createElement(FiCheck10, { size: 12 }) : /* @__PURE__ */ React16.createElement(FiLink5, { size: 12 })
|
|
8446
|
+
)), /* @__PURE__ */ React16.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ React16.createElement("button", { onClick: handleCancel, 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: "Cancelar" }, "\xD7")), /* @__PURE__ */ React16.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ React16.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ React16.createElement("span", { key: index, className: "flex items-center gap-1 bg-indigo-500/30 text-indigo-100 px-1.5 py-0.5 rounded-md text-xs font-medium border border-indigo-500/20" }, t, canEdit && /* @__PURE__ */ React16.createElement(
|
|
8154
8447
|
"button",
|
|
8155
8448
|
{
|
|
8156
8449
|
type: "button",
|
|
8157
8450
|
onClick: () => handleRemoveType(index),
|
|
8158
8451
|
className: "hover:text-white transition-colors"
|
|
8159
8452
|
},
|
|
8160
|
-
/* @__PURE__ */
|
|
8161
|
-
))), canEdit && /* @__PURE__ */
|
|
8453
|
+
/* @__PURE__ */ React16.createElement(FiX5, { size: 12 })
|
|
8454
|
+
))), canEdit && /* @__PURE__ */ React16.createElement(
|
|
8162
8455
|
"input",
|
|
8163
8456
|
{
|
|
8164
8457
|
type: "text",
|
|
@@ -8179,7 +8472,7 @@ function NodeDetailsPanel({
|
|
|
8179
8472
|
placeholder: types.length === 0 ? "Ex.: Cliente" : "",
|
|
8180
8473
|
autoComplete: "off"
|
|
8181
8474
|
}
|
|
8182
|
-
), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */
|
|
8475
|
+
), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ React16.createElement("ul", { className: "custom-scrollbar absolute top-full left-0 z-10 w-full mt-1 max-h-40 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-lg" }, filteredTypes.map((suggestedType, index) => /* @__PURE__ */ React16.createElement(
|
|
8183
8476
|
"li",
|
|
8184
8477
|
{
|
|
8185
8478
|
key: index,
|
|
@@ -8190,7 +8483,7 @@ function NodeDetailsPanel({
|
|
|
8190
8483
|
}
|
|
8191
8484
|
},
|
|
8192
8485
|
suggestedType
|
|
8193
|
-
))))), /* @__PURE__ */
|
|
8486
|
+
))))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Nome"), /* @__PURE__ */ React16.createElement(
|
|
8194
8487
|
"input",
|
|
8195
8488
|
{
|
|
8196
8489
|
type: "text",
|
|
@@ -8199,7 +8492,7 @@ function NodeDetailsPanel({
|
|
|
8199
8492
|
readOnly: !canEdit,
|
|
8200
8493
|
className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none ${canEdit ? "focus:ring-2 focus:ring-indigo-400/60" : "cursor-default text-slate-400"}`
|
|
8201
8494
|
}
|
|
8202
|
-
)), /* @__PURE__ */
|
|
8495
|
+
)), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React16.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__ */ React16.createElement(
|
|
8203
8496
|
DescriptionDisplay,
|
|
8204
8497
|
{
|
|
8205
8498
|
description,
|
|
@@ -8211,7 +8504,7 @@ function NodeDetailsPanel({
|
|
|
8211
8504
|
onImageClick: handleImageClickFromText,
|
|
8212
8505
|
onSaveDescription: handleSaveDescriptionInline
|
|
8213
8506
|
}
|
|
8214
|
-
), /* @__PURE__ */
|
|
8507
|
+
), /* @__PURE__ */ React16.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__ */ React16.createElement(
|
|
8215
8508
|
"button",
|
|
8216
8509
|
{
|
|
8217
8510
|
type: "button",
|
|
@@ -8219,8 +8512,8 @@ function NodeDetailsPanel({
|
|
|
8219
8512
|
className: `p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors ${canEdit ? "border-r border-white/5" : ""}`,
|
|
8220
8513
|
title: "Modo de Leitura"
|
|
8221
8514
|
},
|
|
8222
|
-
/* @__PURE__ */
|
|
8223
|
-
), canEdit && /* @__PURE__ */
|
|
8515
|
+
/* @__PURE__ */ React16.createElement(FiBookOpen3, { size: 14 })
|
|
8516
|
+
), canEdit && /* @__PURE__ */ React16.createElement(
|
|
8224
8517
|
"button",
|
|
8225
8518
|
{
|
|
8226
8519
|
type: "button",
|
|
@@ -8228,17 +8521,17 @@ function NodeDetailsPanel({
|
|
|
8228
8521
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8229
8522
|
title: "Editar descri\xE7\xE3o (Modo de Escrita)"
|
|
8230
8523
|
},
|
|
8231
|
-
/* @__PURE__ */
|
|
8232
|
-
)), canEdit && !description && /* @__PURE__ */
|
|
8524
|
+
/* @__PURE__ */ React16.createElement(FiEdit27, { size: 14 })
|
|
8525
|
+
)), canEdit && !description && /* @__PURE__ */ React16.createElement(
|
|
8233
8526
|
"div",
|
|
8234
8527
|
{
|
|
8235
8528
|
onClick: () => setIsDescriptionModalOpen(true),
|
|
8236
8529
|
className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
|
|
8237
8530
|
},
|
|
8238
8531
|
"Adicionar descri\xE7\xE3o..."
|
|
8239
|
-
))), /* @__PURE__ */
|
|
8532
|
+
))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Size"), /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
|
|
8240
8533
|
const isSelected = size === s;
|
|
8241
|
-
return /* @__PURE__ */
|
|
8534
|
+
return /* @__PURE__ */ React16.createElement(
|
|
8242
8535
|
"button",
|
|
8243
8536
|
{
|
|
8244
8537
|
key: s,
|
|
@@ -8246,10 +8539,10 @@ function NodeDetailsPanel({
|
|
|
8246
8539
|
onClick: () => canEdit && handleSizeChange(s),
|
|
8247
8540
|
className: `flex items-center gap-2 group focus:outline-none ${canEdit ? "cursor-pointer" : "cursor-default opacity-80"}`
|
|
8248
8541
|
},
|
|
8249
|
-
/* @__PURE__ */
|
|
8250
|
-
/* @__PURE__ */
|
|
8542
|
+
/* @__PURE__ */ React16.createElement("div", { className: `w-4 h-4 rounded-[4px] border flex items-center justify-center transition-all duration-200 ${isSelected ? "bg-indigo-500 border-indigo-500 shadow-[0_0_10px_rgba(99,102,241,0.4)]" : "border-slate-600 bg-transparent " + (canEdit ? "group-hover:border-slate-500" : "")}` }, isSelected && /* @__PURE__ */ React16.createElement(FiCheck10, { size: 12, className: "text-white" })),
|
|
8543
|
+
/* @__PURE__ */ React16.createElement("span", { className: `text-sm capitalize transition-colors ${isSelected ? "text-white font-medium" : "text-slate-400 " + (canEdit ? "group-hover:text-slate-300" : "")}` }, s)
|
|
8251
8544
|
);
|
|
8252
|
-
}))), /* @__PURE__ */
|
|
8545
|
+
}))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300" }, "Cor e Brilho"), canEdit && hasImages && /* @__PURE__ */ React16.createElement("label", { className: "flex items-center gap-2 cursor-pointer group" }, /* @__PURE__ */ React16.createElement("div", { className: `w-4 h-4 rounded border flex items-center justify-center transition-colors ${useImageAsTexture ? "bg-indigo-500 border-indigo-500" : "border-slate-500 bg-transparent"}` }, useImageAsTexture && /* @__PURE__ */ React16.createElement(FiCheck10, { size: 12, className: "text-white" })), /* @__PURE__ */ React16.createElement(
|
|
8253
8546
|
"input",
|
|
8254
8547
|
{
|
|
8255
8548
|
type: "checkbox",
|
|
@@ -8257,14 +8550,14 @@ function NodeDetailsPanel({
|
|
|
8257
8550
|
onChange: handleToggleImageMode,
|
|
8258
8551
|
className: "hidden"
|
|
8259
8552
|
}
|
|
8260
|
-
), /* @__PURE__ */
|
|
8553
|
+
), /* @__PURE__ */ React16.createElement("span", { className: `text-xs ${useImageAsTexture ? "text-indigo-300" : "text-slate-400 group-hover:text-slate-300"}` }, "Usar imagem para representar o node"))), /* @__PURE__ */ React16.createElement(
|
|
8261
8554
|
ColorPicker,
|
|
8262
8555
|
{
|
|
8263
8556
|
color,
|
|
8264
8557
|
onChange: handleColorChange,
|
|
8265
8558
|
disabled: !canEdit || useImageAsTexture
|
|
8266
8559
|
}
|
|
8267
|
-
), /* @__PURE__ */
|
|
8560
|
+
), /* @__PURE__ */ React16.createElement("div", { className: "mt-3 flex items-center gap-3" }, /* @__PURE__ */ React16.createElement(FiSun2, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React16.createElement(
|
|
8268
8561
|
"input",
|
|
8269
8562
|
{
|
|
8270
8563
|
type: "range",
|
|
@@ -8277,7 +8570,7 @@ function NodeDetailsPanel({
|
|
|
8277
8570
|
className: `w-full h-1.5 bg-slate-700 rounded-lg appearance-none ${canEdit ? "cursor-pointer accent-indigo-500 hover:accent-indigo-400" : "cursor-default accent-slate-500"}`,
|
|
8278
8571
|
title: `Intensidade do brilho: ${intensity}`
|
|
8279
8572
|
}
|
|
8280
|
-
), /* @__PURE__ */
|
|
8573
|
+
), /* @__PURE__ */ React16.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ React16.createElement("span", { className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}` }, useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Ajuste a cor e a intensidade do brilho.")), /* @__PURE__ */ React16.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React16.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React16.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React16.createElement(FiPlus6, { size: 14 }), " Adicionar")), /* @__PURE__ */ React16.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React16.createElement(
|
|
8281
8574
|
CustomPropertyDisplay,
|
|
8282
8575
|
{
|
|
8283
8576
|
key: prop.id,
|
|
@@ -8292,7 +8585,7 @@ function NodeDetailsPanel({
|
|
|
8292
8585
|
onUploadFile: canEdit ? onUploadFile : void 0,
|
|
8293
8586
|
readOnly: !canEdit
|
|
8294
8587
|
}
|
|
8295
|
-
)), /* @__PURE__ */
|
|
8588
|
+
)), /* @__PURE__ */ React16.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React16.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__ */ React16.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ React16.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ React16.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__ */ React16.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__ */ React16.createElement(
|
|
8296
8589
|
"button",
|
|
8297
8590
|
{
|
|
8298
8591
|
onClick: () => handleSave(false),
|
|
@@ -8301,10 +8594,10 @@ function NodeDetailsPanel({
|
|
|
8301
8594
|
${isSaving ? "bg-slate-700 text-slate-300 cursor-wait" : "bg-gradient-to-tr from-indigo-600 to-indigo-400 hover:from-indigo-500 hover:to-indigo-300 text-white"}
|
|
8302
8595
|
`
|
|
8303
8596
|
},
|
|
8304
|
-
isSaving && /* @__PURE__ */
|
|
8597
|
+
isSaving && /* @__PURE__ */ React16.createElement(FiLoader2, { className: "animate-spin" }),
|
|
8305
8598
|
isSaving ? "Salvando..." : "Salvar"
|
|
8306
8599
|
)))
|
|
8307
|
-
), isDescriptionModalOpen && canEdit && /* @__PURE__ */
|
|
8600
|
+
), isDescriptionModalOpen && canEdit && /* @__PURE__ */ React16.createElement(
|
|
8308
8601
|
DescriptionEditModal,
|
|
8309
8602
|
{
|
|
8310
8603
|
isOpen: isDescriptionModalOpen,
|
|
@@ -8324,7 +8617,7 @@ function NodeDetailsPanel({
|
|
|
8324
8617
|
}
|
|
8325
8618
|
|
|
8326
8619
|
// src/components/MultiNodeContextMenu.jsx
|
|
8327
|
-
import
|
|
8620
|
+
import React17, { useLayoutEffect as useLayoutEffect3, useRef as useRef14, useState as useState18, useEffect as useEffect16 } from "react";
|
|
8328
8621
|
function MultiNodeContextMenu({
|
|
8329
8622
|
data,
|
|
8330
8623
|
userRole,
|
|
@@ -8333,9 +8626,9 @@ function MultiNodeContextMenu({
|
|
|
8333
8626
|
onDismissOtherNodes,
|
|
8334
8627
|
onDeleteNodes
|
|
8335
8628
|
}) {
|
|
8336
|
-
const menuRef =
|
|
8337
|
-
const [menuPos, setMenuPos] =
|
|
8338
|
-
const [isConfirmingDelete, setIsConfirmingDelete] =
|
|
8629
|
+
const menuRef = useRef14(null);
|
|
8630
|
+
const [menuPos, setMenuPos] = useState18({ left: 0, top: 0 });
|
|
8631
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState18(false);
|
|
8339
8632
|
const ability = defineAbilityFor(userRole);
|
|
8340
8633
|
const canDelete = ability.can("delete", "Node");
|
|
8341
8634
|
useLayoutEffect3(() => {
|
|
@@ -8366,7 +8659,7 @@ function MultiNodeContextMenu({
|
|
|
8366
8659
|
const baseButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-indigo-500/20 text-slate-200 hover:text-white transition-colors duration-150 truncate";
|
|
8367
8660
|
const deleteButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-red-500/25 text-red-400 hover:text-red-300 transition-colors duration-150 truncate";
|
|
8368
8661
|
const nodeCount = data.nodeIds.size;
|
|
8369
|
-
return /* @__PURE__ */
|
|
8662
|
+
return /* @__PURE__ */ React17.createElement(
|
|
8370
8663
|
"div",
|
|
8371
8664
|
{
|
|
8372
8665
|
ref: menuRef,
|
|
@@ -8380,28 +8673,28 @@ function MultiNodeContextMenu({
|
|
|
8380
8673
|
onContextMenu: swallow,
|
|
8381
8674
|
onDoubleClick: swallow
|
|
8382
8675
|
},
|
|
8383
|
-
/* @__PURE__ */
|
|
8384
|
-
/* @__PURE__ */
|
|
8676
|
+
/* @__PURE__ */ React17.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
8677
|
+
/* @__PURE__ */ React17.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React17.createElement("div", { className: "w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 mb-1" }, /* @__PURE__ */ React17.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React17.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React17.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React17.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ React17.createElement("strong", null, nodeCount, " Nodes"), "?"), /* @__PURE__ */ React17.createElement("p", { className: "text-[11px] text-slate-400 leading-tight" }, "Esta a\xE7\xE3o \xE9 irrevers\xEDvel. Todas as conex\xF5es associadas a eles ser\xE3o apagadas.")), /* @__PURE__ */ React17.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React17.createElement(
|
|
8385
8678
|
"button",
|
|
8386
8679
|
{
|
|
8387
8680
|
onClick: () => setIsConfirmingDelete(false),
|
|
8388
8681
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8389
8682
|
},
|
|
8390
8683
|
"Cancelar"
|
|
8391
|
-
), /* @__PURE__ */
|
|
8684
|
+
), /* @__PURE__ */ React17.createElement(
|
|
8392
8685
|
"button",
|
|
8393
8686
|
{
|
|
8394
8687
|
onClick: () => onDeleteNodes(data.nodeIds),
|
|
8395
8688
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
8396
8689
|
},
|
|
8397
8690
|
"Excluir"
|
|
8398
|
-
))) : /* @__PURE__ */
|
|
8691
|
+
))) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React17.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ React17.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es em Grupo (", nodeCount, " Nodes)")), /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React17.createElement("button", { onClick: () => onDismissNodes(data.nodeIds), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React17.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React17.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React17.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ React17.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ React17.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React17.createElement("span", null, "Dismiss (", nodeCount, ")")), /* @__PURE__ */ React17.createElement("button", { onClick: () => onDismissOtherNodes(data.nodeIds), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React17.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React17.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React17.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React17.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React17.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React17.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React17.createElement("span", null, "Dismiss other nodes")), canDelete && /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React17.createElement("button", { onClick: () => setIsConfirmingDelete(true), className: deleteButtonClass, title: "Excluir Nodes" }, /* @__PURE__ */ React17.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React17.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React17.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React17.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React17.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React17.createElement("span", null, "Excluir Nodes (", nodeCount, ")"))))))
|
|
8399
8692
|
);
|
|
8400
8693
|
}
|
|
8401
8694
|
|
|
8402
8695
|
// src/components/RelationshipDetailsPanel.jsx
|
|
8403
|
-
import
|
|
8404
|
-
import { FiPlus as
|
|
8696
|
+
import React18, { useState as useState19, useEffect as useEffect17, useRef as useRef15, useMemo as useMemo9 } from "react";
|
|
8697
|
+
import { FiPlus as FiPlus7, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
|
|
8405
8698
|
function RelationshipDetailsPanel({
|
|
8406
8699
|
link,
|
|
8407
8700
|
onClose,
|
|
@@ -8415,14 +8708,14 @@ function RelationshipDetailsPanel({
|
|
|
8415
8708
|
onUploadFile,
|
|
8416
8709
|
userRole
|
|
8417
8710
|
}) {
|
|
8418
|
-
const [name, setName] =
|
|
8419
|
-
const [description, setDescription] =
|
|
8420
|
-
const [customProps, setCustomProps] =
|
|
8421
|
-
const [existingSections, setExistingSections] =
|
|
8422
|
-
const [isDescriptionModalOpen, setIsDescriptionModalOpen] =
|
|
8423
|
-
const [isSaving, setIsSaving] =
|
|
8424
|
-
const [isReadMode, setIsReadMode] =
|
|
8425
|
-
const propsEndRef =
|
|
8711
|
+
const [name, setName] = useState19((link == null ? void 0 : link.name) ?? "");
|
|
8712
|
+
const [description, setDescription] = useState19((link == null ? void 0 : link.description) ?? "");
|
|
8713
|
+
const [customProps, setCustomProps] = useState19(() => extractCustomPropsFromNode(link || {}));
|
|
8714
|
+
const [existingSections, setExistingSections] = useState19((link == null ? void 0 : link.description_sections) || []);
|
|
8715
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState19(false);
|
|
8716
|
+
const [isSaving, setIsSaving] = useState19(false);
|
|
8717
|
+
const [isReadMode, setIsReadMode] = useState19(false);
|
|
8718
|
+
const propsEndRef = useRef15(null);
|
|
8426
8719
|
const canEdit = useMemo9(() => {
|
|
8427
8720
|
const ability = defineAbilityFor(userRole);
|
|
8428
8721
|
return ability.can("update", "Connection");
|
|
@@ -8502,7 +8795,7 @@ function RelationshipDetailsPanel({
|
|
|
8502
8795
|
onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
|
|
8503
8796
|
}
|
|
8504
8797
|
};
|
|
8505
|
-
return /* @__PURE__ */
|
|
8798
|
+
return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(
|
|
8506
8799
|
"div",
|
|
8507
8800
|
{
|
|
8508
8801
|
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
|
|
@@ -8517,7 +8810,7 @@ function RelationshipDetailsPanel({
|
|
|
8517
8810
|
onContextMenu: swallow,
|
|
8518
8811
|
onDoubleClick: swallow
|
|
8519
8812
|
},
|
|
8520
|
-
isReadMode ? /* @__PURE__ */
|
|
8813
|
+
isReadMode ? /* @__PURE__ */ React18.createElement(
|
|
8521
8814
|
DescriptionReadModePanel,
|
|
8522
8815
|
{
|
|
8523
8816
|
title: name || "Rela\xE7\xE3o",
|
|
@@ -8538,7 +8831,7 @@ function RelationshipDetailsPanel({
|
|
|
8538
8831
|
onImageClick: handleImageClickFromText,
|
|
8539
8832
|
onSaveDescription: handleSaveDescriptionInline
|
|
8540
8833
|
}
|
|
8541
|
-
) : /* @__PURE__ */
|
|
8834
|
+
) : /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ React18.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React18.createElement("div", null, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React18.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__ */ React18.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ React18.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ React18.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__ */ React18.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React18.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React18.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ React18.createElement(
|
|
8542
8835
|
"input",
|
|
8543
8836
|
{
|
|
8544
8837
|
type: "text",
|
|
@@ -8550,7 +8843,7 @@ function RelationshipDetailsPanel({
|
|
|
8550
8843
|
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
8551
8844
|
`
|
|
8552
8845
|
}
|
|
8553
|
-
)), /* @__PURE__ */
|
|
8846
|
+
)), /* @__PURE__ */ React18.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React18.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React18.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__ */ React18.createElement(
|
|
8554
8847
|
DescriptionDisplay,
|
|
8555
8848
|
{
|
|
8556
8849
|
description,
|
|
@@ -8562,7 +8855,7 @@ function RelationshipDetailsPanel({
|
|
|
8562
8855
|
onImageClick: handleImageClickFromText,
|
|
8563
8856
|
onSaveDescription: handleSaveDescriptionInline
|
|
8564
8857
|
}
|
|
8565
|
-
), /* @__PURE__ */
|
|
8858
|
+
), /* @__PURE__ */ React18.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__ */ React18.createElement(
|
|
8566
8859
|
"button",
|
|
8567
8860
|
{
|
|
8568
8861
|
type: "button",
|
|
@@ -8570,8 +8863,8 @@ function RelationshipDetailsPanel({
|
|
|
8570
8863
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors border-r border-white/5",
|
|
8571
8864
|
title: "Modo de Leitura"
|
|
8572
8865
|
},
|
|
8573
|
-
/* @__PURE__ */
|
|
8574
|
-
), canEdit && /* @__PURE__ */
|
|
8866
|
+
/* @__PURE__ */ React18.createElement(FiBookOpen4, { size: 14 })
|
|
8867
|
+
), canEdit && /* @__PURE__ */ React18.createElement(
|
|
8575
8868
|
"button",
|
|
8576
8869
|
{
|
|
8577
8870
|
type: "button",
|
|
@@ -8579,15 +8872,15 @@ function RelationshipDetailsPanel({
|
|
|
8579
8872
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8580
8873
|
title: "Editar descri\xE7\xE3o"
|
|
8581
8874
|
},
|
|
8582
|
-
/* @__PURE__ */
|
|
8583
|
-
)), !description && canEdit && /* @__PURE__ */
|
|
8875
|
+
/* @__PURE__ */ React18.createElement(FiEdit28, { size: 14 })
|
|
8876
|
+
)), !description && canEdit && /* @__PURE__ */ React18.createElement(
|
|
8584
8877
|
"div",
|
|
8585
8878
|
{
|
|
8586
8879
|
onClick: () => setIsDescriptionModalOpen(true),
|
|
8587
8880
|
className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
|
|
8588
8881
|
},
|
|
8589
8882
|
"Adicionar descri\xE7\xE3o..."
|
|
8590
|
-
))), /* @__PURE__ */
|
|
8883
|
+
))), /* @__PURE__ */ React18.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React18.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React18.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React18.createElement(FiPlus7, { size: 14 }), " Adicionar")), /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React18.createElement(
|
|
8591
8884
|
CustomPropertyDisplay,
|
|
8592
8885
|
{
|
|
8593
8886
|
key: prop.id,
|
|
@@ -8599,7 +8892,7 @@ function RelationshipDetailsPanel({
|
|
|
8599
8892
|
onUploadFile,
|
|
8600
8893
|
disabled: !canEdit
|
|
8601
8894
|
}
|
|
8602
|
-
)), /* @__PURE__ */
|
|
8895
|
+
)), /* @__PURE__ */ React18.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ React18.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__ */ React18.createElement("button", { onClick: onClose, 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__ */ React18.createElement(
|
|
8603
8896
|
"button",
|
|
8604
8897
|
{
|
|
8605
8898
|
onClick: () => handleSave(false),
|
|
@@ -8608,10 +8901,10 @@ function RelationshipDetailsPanel({
|
|
|
8608
8901
|
${isSaving ? "bg-slate-700 text-slate-300 cursor-wait" : "bg-gradient-to-tr from-teal-600 to-teal-400 hover:from-teal-500 hover:to-teal-300 text-white"}
|
|
8609
8902
|
`
|
|
8610
8903
|
},
|
|
8611
|
-
isSaving && /* @__PURE__ */
|
|
8904
|
+
isSaving && /* @__PURE__ */ React18.createElement(FiLoader3, { className: "animate-spin" }),
|
|
8612
8905
|
isSaving ? "Salvando..." : "Salvar"
|
|
8613
8906
|
)))
|
|
8614
|
-
), isDescriptionModalOpen && /* @__PURE__ */
|
|
8907
|
+
), isDescriptionModalOpen && /* @__PURE__ */ React18.createElement(
|
|
8615
8908
|
DescriptionEditModal,
|
|
8616
8909
|
{
|
|
8617
8910
|
isOpen: isDescriptionModalOpen,
|
|
@@ -8632,7 +8925,7 @@ function RelationshipDetailsPanel({
|
|
|
8632
8925
|
}
|
|
8633
8926
|
|
|
8634
8927
|
// src/components/RelationshipContextMenu.jsx
|
|
8635
|
-
import
|
|
8928
|
+
import React19, { useLayoutEffect as useLayoutEffect4, useRef as useRef16, useState as useState20, useEffect as useEffect18, useMemo as useMemo10 } from "react";
|
|
8636
8929
|
function RelationshipContextMenu({
|
|
8637
8930
|
data,
|
|
8638
8931
|
userRole,
|
|
@@ -8642,9 +8935,9 @@ function RelationshipContextMenu({
|
|
|
8642
8935
|
onDelete,
|
|
8643
8936
|
onClose
|
|
8644
8937
|
}) {
|
|
8645
|
-
const menuRef =
|
|
8646
|
-
const [menuPos, setMenuPos] =
|
|
8647
|
-
const [isConfirmingDelete, setIsConfirmingDelete] =
|
|
8938
|
+
const menuRef = useRef16(null);
|
|
8939
|
+
const [menuPos, setMenuPos] = useState20({ left: 0, top: 0 });
|
|
8940
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState20(false);
|
|
8648
8941
|
const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
|
|
8649
8942
|
const sourceName = useMemo10(
|
|
8650
8943
|
() => {
|
|
@@ -8689,7 +8982,7 @@ function RelationshipContextMenu({
|
|
|
8689
8982
|
const dangerButtonClass = "w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md hover:bg-rose-500/20 text-rose-300 hover:text-rose-100 transition-colors duration-150 truncate";
|
|
8690
8983
|
const canUpdate = ability.can("update", "Connection");
|
|
8691
8984
|
const canDelete = ability.can("delete", "Connection");
|
|
8692
|
-
return /* @__PURE__ */
|
|
8985
|
+
return /* @__PURE__ */ React19.createElement(
|
|
8693
8986
|
"div",
|
|
8694
8987
|
{
|
|
8695
8988
|
ref: menuRef,
|
|
@@ -8703,29 +8996,29 @@ function RelationshipContextMenu({
|
|
|
8703
8996
|
onContextMenu: swallow,
|
|
8704
8997
|
onDoubleClick: swallow
|
|
8705
8998
|
},
|
|
8706
|
-
/* @__PURE__ */
|
|
8707
|
-
/* @__PURE__ */
|
|
8999
|
+
/* @__PURE__ */ React19.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
|
|
9000
|
+
/* @__PURE__ */ React19.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React19.createElement("div", { className: "w-10 h-10 rounded-full bg-rose-500/20 flex items-center justify-center text-rose-400 mb-1" }, /* @__PURE__ */ React19.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React19.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React19.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), /* @__PURE__ */ React19.createElement("path", { d: "M10 11v6" }), /* @__PURE__ */ React19.createElement("path", { d: "M14 11v6" }), /* @__PURE__ */ React19.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React19.createElement("p", { className: "text-sm text-slate-200" }, "Excluir rela\xE7\xE3o?"), /* @__PURE__ */ React19.createElement("p", { className: "text-[11px] text-slate-400 leading-tight break-words" }, "Desconectar ", /* @__PURE__ */ React19.createElement("strong", null, sourceName), " de ", /* @__PURE__ */ React19.createElement("strong", null, targetName), ".")), /* @__PURE__ */ React19.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React19.createElement(
|
|
8708
9001
|
"button",
|
|
8709
9002
|
{
|
|
8710
9003
|
onClick: () => setIsConfirmingDelete(false),
|
|
8711
9004
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8712
9005
|
},
|
|
8713
9006
|
"Cancelar"
|
|
8714
|
-
), /* @__PURE__ */
|
|
9007
|
+
), /* @__PURE__ */ React19.createElement(
|
|
8715
9008
|
"button",
|
|
8716
9009
|
{
|
|
8717
9010
|
onClick: () => onDelete == null ? void 0 : onDelete(data.linkObject),
|
|
8718
9011
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-rose-600 hover:bg-rose-500 rounded-md text-white transition-colors"
|
|
8719
9012
|
},
|
|
8720
9013
|
"Excluir"
|
|
8721
|
-
))) : /* @__PURE__ */
|
|
9014
|
+
))) : /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React19.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-teal-400/80 shadow-[0_0_12px_1px_rgba(45,212,191,0.5)]" }), /* @__PURE__ */ React19.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Rela\xE7\xE3o")), /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-1" }, canUpdate && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(
|
|
8722
9015
|
"button",
|
|
8723
9016
|
{
|
|
8724
9017
|
onClick: () => onRelinkSource == null ? void 0 : onRelinkSource(data.linkObject),
|
|
8725
9018
|
className: baseButtonClass,
|
|
8726
9019
|
title: "Desconectar ponta ligada ao Source"
|
|
8727
9020
|
},
|
|
8728
|
-
/* @__PURE__ */
|
|
9021
|
+
/* @__PURE__ */ React19.createElement(
|
|
8729
9022
|
"svg",
|
|
8730
9023
|
{
|
|
8731
9024
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8738,18 +9031,18 @@ function RelationshipContextMenu({
|
|
|
8738
9031
|
strokeLinecap: "round",
|
|
8739
9032
|
strokeLinejoin: "round"
|
|
8740
9033
|
},
|
|
8741
|
-
/* @__PURE__ */
|
|
8742
|
-
/* @__PURE__ */
|
|
9034
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }),
|
|
9035
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.72-1.72" })
|
|
8743
9036
|
),
|
|
8744
|
-
/* @__PURE__ */
|
|
8745
|
-
), /* @__PURE__ */
|
|
9037
|
+
/* @__PURE__ */ React19.createElement("span", null, "Desconectar Source (", sourceName, ")")
|
|
9038
|
+
), /* @__PURE__ */ React19.createElement(
|
|
8746
9039
|
"button",
|
|
8747
9040
|
{
|
|
8748
9041
|
onClick: () => onRelinkTarget == null ? void 0 : onRelinkTarget(data.linkObject),
|
|
8749
9042
|
className: baseButtonClass,
|
|
8750
9043
|
title: "Desconectar ponta ligada ao Target"
|
|
8751
9044
|
},
|
|
8752
|
-
/* @__PURE__ */
|
|
9045
|
+
/* @__PURE__ */ React19.createElement(
|
|
8753
9046
|
"svg",
|
|
8754
9047
|
{
|
|
8755
9048
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8762,21 +9055,21 @@ function RelationshipContextMenu({
|
|
|
8762
9055
|
strokeLinecap: "round",
|
|
8763
9056
|
strokeLinejoin: "round"
|
|
8764
9057
|
},
|
|
8765
|
-
/* @__PURE__ */
|
|
8766
|
-
/* @__PURE__ */
|
|
8767
|
-
/* @__PURE__ */
|
|
8768
|
-
/* @__PURE__ */
|
|
8769
|
-
/* @__PURE__ */
|
|
9058
|
+
/* @__PURE__ */ React19.createElement("polyline", { points: "16 3 21 3 21 8" }),
|
|
9059
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "4", y1: "20", x2: "21", y2: "3" }),
|
|
9060
|
+
/* @__PURE__ */ React19.createElement("polyline", { points: "21 16 21 21 16 21" }),
|
|
9061
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "15", y1: "15", x2: "21", y2: "21" }),
|
|
9062
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "4", y1: "4", x2: "9", y2: "9" })
|
|
8770
9063
|
),
|
|
8771
|
-
/* @__PURE__ */
|
|
8772
|
-
), /* @__PURE__ */
|
|
9064
|
+
/* @__PURE__ */ React19.createElement("span", null, "Desconectar Target (", targetName, ")")
|
|
9065
|
+
), /* @__PURE__ */ React19.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" })), /* @__PURE__ */ React19.createElement(
|
|
8773
9066
|
"button",
|
|
8774
9067
|
{
|
|
8775
9068
|
onClick: () => onOpenDetails == null ? void 0 : onOpenDetails(data.linkObject),
|
|
8776
9069
|
className: baseButtonClass,
|
|
8777
9070
|
title: "Abrir detalhes da rela\xE7\xE3o"
|
|
8778
9071
|
},
|
|
8779
|
-
/* @__PURE__ */
|
|
9072
|
+
/* @__PURE__ */ React19.createElement(
|
|
8780
9073
|
"svg",
|
|
8781
9074
|
{
|
|
8782
9075
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8789,19 +9082,19 @@ function RelationshipContextMenu({
|
|
|
8789
9082
|
strokeLinecap: "round",
|
|
8790
9083
|
strokeLinejoin: "round"
|
|
8791
9084
|
},
|
|
8792
|
-
/* @__PURE__ */
|
|
8793
|
-
/* @__PURE__ */
|
|
8794
|
-
/* @__PURE__ */
|
|
9085
|
+
/* @__PURE__ */ React19.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
9086
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
|
|
9087
|
+
/* @__PURE__ */ React19.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "8" })
|
|
8795
9088
|
),
|
|
8796
|
-
/* @__PURE__ */
|
|
8797
|
-
), canDelete && /* @__PURE__ */
|
|
9089
|
+
/* @__PURE__ */ React19.createElement("span", null, "Abrir Detalhes")
|
|
9090
|
+
), canDelete && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ React19.createElement(
|
|
8798
9091
|
"button",
|
|
8799
9092
|
{
|
|
8800
9093
|
onClick: () => setIsConfirmingDelete(true),
|
|
8801
9094
|
className: dangerButtonClass,
|
|
8802
9095
|
title: "Excluir esta conex\xE3o"
|
|
8803
9096
|
},
|
|
8804
|
-
/* @__PURE__ */
|
|
9097
|
+
/* @__PURE__ */ React19.createElement(
|
|
8805
9098
|
"svg",
|
|
8806
9099
|
{
|
|
8807
9100
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8814,19 +9107,19 @@ function RelationshipContextMenu({
|
|
|
8814
9107
|
strokeLinecap: "round",
|
|
8815
9108
|
strokeLinejoin: "round"
|
|
8816
9109
|
},
|
|
8817
|
-
/* @__PURE__ */
|
|
8818
|
-
/* @__PURE__ */
|
|
8819
|
-
/* @__PURE__ */
|
|
8820
|
-
/* @__PURE__ */
|
|
8821
|
-
/* @__PURE__ */
|
|
9110
|
+
/* @__PURE__ */ React19.createElement("polyline", { points: "3 6 5 6 21 6" }),
|
|
9111
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }),
|
|
9112
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M10 11v6" }),
|
|
9113
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M14 11v6" }),
|
|
9114
|
+
/* @__PURE__ */ React19.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
|
|
8822
9115
|
),
|
|
8823
|
-
/* @__PURE__ */
|
|
9116
|
+
/* @__PURE__ */ React19.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
|
|
8824
9117
|
)))))
|
|
8825
9118
|
);
|
|
8826
9119
|
}
|
|
8827
9120
|
|
|
8828
9121
|
// src/components/LoadingScreen.jsx
|
|
8829
|
-
import
|
|
9122
|
+
import React20 from "react";
|
|
8830
9123
|
var styles = {
|
|
8831
9124
|
loadingOverlay: {
|
|
8832
9125
|
position: "fixed",
|
|
@@ -8858,11 +9151,11 @@ var styles = {
|
|
|
8858
9151
|
`
|
|
8859
9152
|
};
|
|
8860
9153
|
function LoadingScreen() {
|
|
8861
|
-
return /* @__PURE__ */
|
|
9154
|
+
return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement("style", null, styles.keyframes), /* @__PURE__ */ React20.createElement("div", { style: styles.loadingOverlay }, /* @__PURE__ */ React20.createElement("div", { style: styles.spinner })));
|
|
8862
9155
|
}
|
|
8863
9156
|
|
|
8864
9157
|
// src/components/ImportParentFileModal.jsx
|
|
8865
|
-
import
|
|
9158
|
+
import React21, { useEffect as useEffect19, useState as useState21 } from "react";
|
|
8866
9159
|
function ImportParentFileModal({
|
|
8867
9160
|
isOpen,
|
|
8868
9161
|
onClose,
|
|
@@ -8873,11 +9166,11 @@ function ImportParentFileModal({
|
|
|
8873
9166
|
onFetchAvailableFiles,
|
|
8874
9167
|
currentViewName
|
|
8875
9168
|
}) {
|
|
8876
|
-
const [activeTab, setActiveTab] =
|
|
8877
|
-
const [availableDbs, setAvailableDbs] =
|
|
8878
|
-
const [availableViews, setAvailableViews] =
|
|
8879
|
-
const [selectedItem, setSelectedItem] =
|
|
8880
|
-
const [isLoading, setIsLoading] =
|
|
9169
|
+
const [activeTab, setActiveTab] = useState21("databases");
|
|
9170
|
+
const [availableDbs, setAvailableDbs] = useState21([]);
|
|
9171
|
+
const [availableViews, setAvailableViews] = useState21([]);
|
|
9172
|
+
const [selectedItem, setSelectedItem] = useState21(null);
|
|
9173
|
+
const [isLoading, setIsLoading] = useState21(false);
|
|
8881
9174
|
useEffect19(() => {
|
|
8882
9175
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
8883
9176
|
const fetchData = async () => {
|
|
@@ -8943,13 +9236,13 @@ function ImportParentFileModal({
|
|
|
8943
9236
|
const swallow = (e) => e.stopPropagation();
|
|
8944
9237
|
const currentList = activeTab === "databases" ? availableDbs : availableViews;
|
|
8945
9238
|
const emptyMessage = activeTab === "databases" ? "Nenhum novo arquivo parent dispon\xEDvel." : "Nenhuma view dispon\xEDvel para importa\xE7\xE3o.";
|
|
8946
|
-
return /* @__PURE__ */
|
|
9239
|
+
return /* @__PURE__ */ React21.createElement(
|
|
8947
9240
|
"div",
|
|
8948
9241
|
{
|
|
8949
9242
|
className: "ui-overlay fixed inset-0 z-[1200] flex items-center justify-center bg-black/60 backdrop-blur-sm",
|
|
8950
9243
|
onClick: onClose
|
|
8951
9244
|
},
|
|
8952
|
-
/* @__PURE__ */
|
|
9245
|
+
/* @__PURE__ */ React21.createElement(
|
|
8953
9246
|
"div",
|
|
8954
9247
|
{
|
|
8955
9248
|
className: "ui-overlay relative rounded-2xl border border-white/10 bg-slate-950/80 shadow-[0_20px_80px_rgba(0,0,0,0.6)] text-white w-[min(92vw,500px)] flex flex-col max-h-[85vh]",
|
|
@@ -8961,14 +9254,14 @@ function ImportParentFileModal({
|
|
|
8961
9254
|
onContextMenu: swallow,
|
|
8962
9255
|
onDoubleClick: swallow
|
|
8963
9256
|
},
|
|
8964
|
-
/* @__PURE__ */
|
|
9257
|
+
/* @__PURE__ */ React21.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/10 flex-shrink-0" }, /* @__PURE__ */ React21.createElement("h2", { className: "text-lg font-semibold" }, "Importar"), /* @__PURE__ */ React21.createElement(
|
|
8965
9258
|
"button",
|
|
8966
9259
|
{
|
|
8967
9260
|
onClick: onClose,
|
|
8968
9261
|
className: "p-2 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8969
9262
|
title: "Fechar"
|
|
8970
9263
|
},
|
|
8971
|
-
/* @__PURE__ */
|
|
9264
|
+
/* @__PURE__ */ React21.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React21.createElement(
|
|
8972
9265
|
"path",
|
|
8973
9266
|
{
|
|
8974
9267
|
fillRule: "evenodd",
|
|
@@ -8977,14 +9270,14 @@ function ImportParentFileModal({
|
|
|
8977
9270
|
}
|
|
8978
9271
|
))
|
|
8979
9272
|
)),
|
|
8980
|
-
/* @__PURE__ */
|
|
9273
|
+
/* @__PURE__ */ React21.createElement("div", { className: "flex px-6 border-b border-white/10 bg-white/5 flex-shrink-0" }, /* @__PURE__ */ React21.createElement(
|
|
8981
9274
|
"button",
|
|
8982
9275
|
{
|
|
8983
9276
|
onClick: () => setActiveTab("databases"),
|
|
8984
9277
|
className: `flex-1 py-3 text-sm font-medium border-b-2 transition-colors ${activeTab === "databases" ? "border-indigo-500 text-white" : "border-transparent text-slate-400 hover:text-slate-200"}`
|
|
8985
9278
|
},
|
|
8986
9279
|
"Arquivos Parent"
|
|
8987
|
-
), /* @__PURE__ */
|
|
9280
|
+
), /* @__PURE__ */ React21.createElement(
|
|
8988
9281
|
"button",
|
|
8989
9282
|
{
|
|
8990
9283
|
onClick: () => setActiveTab("views"),
|
|
@@ -8992,24 +9285,24 @@ function ImportParentFileModal({
|
|
|
8992
9285
|
},
|
|
8993
9286
|
"Views (Ancestralidades)"
|
|
8994
9287
|
)),
|
|
8995
|
-
/* @__PURE__ */
|
|
9288
|
+
/* @__PURE__ */ React21.createElement("div", { className: "p-6 overflow-y-auto custom-scrollbar flex-grow min-h-[200px]" }, isLoading ? /* @__PURE__ */ React21.createElement("div", { className: "flex items-center justify-center h-40" }, /* @__PURE__ */ React21.createElement("div", { className: "w-8 h-8 border-4 border-t-indigo-500 border-slate-700 rounded-full animate-spin" })) : /* @__PURE__ */ React21.createElement("div", { className: "space-y-2" }, currentList.length > 0 ? currentList.map((item) => /* @__PURE__ */ React21.createElement(
|
|
8996
9289
|
"div",
|
|
8997
9290
|
{
|
|
8998
9291
|
key: item.id,
|
|
8999
9292
|
onClick: () => setSelectedItem(item),
|
|
9000
9293
|
className: `px-4 py-3 rounded-lg border cursor-pointer transition-all duration-150 flex flex-col gap-1 ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "bg-indigo-600 border-indigo-500 shadow-lg" : "bg-slate-800/60 border-white/10 hover:border-white/20 hover:bg-slate-800"}`
|
|
9001
9294
|
},
|
|
9002
|
-
/* @__PURE__ */
|
|
9003
|
-
item.description && /* @__PURE__ */
|
|
9004
|
-
)) : /* @__PURE__ */
|
|
9005
|
-
/* @__PURE__ */
|
|
9295
|
+
/* @__PURE__ */ React21.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React21.createElement("span", { className: "font-medium text-slate-100" }, item.name), activeTab === "views" && /* @__PURE__ */ React21.createElement("span", { className: "text-[10px] px-1.5 py-0.5 rounded bg-black/30 text-indigo-300 border border-indigo-500/30" }, "VIEW")),
|
|
9296
|
+
item.description && /* @__PURE__ */ React21.createElement("p", { className: `text-xs ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "text-indigo-200" : "text-slate-400"}` }, item.description)
|
|
9297
|
+
)) : /* @__PURE__ */ React21.createElement("p", { className: "text-slate-400 text-center py-10" }, emptyMessage))),
|
|
9298
|
+
/* @__PURE__ */ React21.createElement("div", { className: "px-6 py-4 border-t border-white/10 flex justify-end gap-3 flex-shrink-0 bg-slate-900/50" }, /* @__PURE__ */ React21.createElement(
|
|
9006
9299
|
"button",
|
|
9007
9300
|
{
|
|
9008
9301
|
onClick: onClose,
|
|
9009
9302
|
className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm text-slate-300"
|
|
9010
9303
|
},
|
|
9011
9304
|
"Cancelar"
|
|
9012
|
-
), /* @__PURE__ */
|
|
9305
|
+
), /* @__PURE__ */ React21.createElement(
|
|
9013
9306
|
"button",
|
|
9014
9307
|
{
|
|
9015
9308
|
onClick: handleConfirm,
|
|
@@ -9023,7 +9316,7 @@ function ImportParentFileModal({
|
|
|
9023
9316
|
}
|
|
9024
9317
|
|
|
9025
9318
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
9026
|
-
import
|
|
9319
|
+
import React22, { useState as useState22 } from "react";
|
|
9027
9320
|
import { FiBookOpen as FiBookOpen5 } from "react-icons/fi";
|
|
9028
9321
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
9029
9322
|
var _a, _b, _c, _d;
|
|
@@ -9033,21 +9326,21 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9033
9326
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
9034
9327
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
9035
9328
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
9036
|
-
const [isReadMode, setIsReadMode] =
|
|
9329
|
+
const [isReadMode, setIsReadMode] = useState22(false);
|
|
9037
9330
|
const swallow = (e) => e.stopPropagation();
|
|
9038
9331
|
const handleImageClickFromText = (url, name) => {
|
|
9039
9332
|
if (onOpenImageViewer) {
|
|
9040
9333
|
onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
|
|
9041
9334
|
}
|
|
9042
9335
|
};
|
|
9043
|
-
return /* @__PURE__ */
|
|
9336
|
+
return /* @__PURE__ */ React22.createElement(
|
|
9044
9337
|
"div",
|
|
9045
9338
|
{
|
|
9046
9339
|
className: "ui-overlay fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[1200]",
|
|
9047
9340
|
onClick: onClose,
|
|
9048
9341
|
onPointerDown: swallow
|
|
9049
9342
|
},
|
|
9050
|
-
/* @__PURE__ */
|
|
9343
|
+
/* @__PURE__ */ React22.createElement(
|
|
9051
9344
|
"div",
|
|
9052
9345
|
{
|
|
9053
9346
|
className: `relative group rounded-2xl border border-white/10 bg-slate-950/80 shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col max-h-[calc(100vh-4rem)] transition-all duration-300 ease-out
|
|
@@ -9055,7 +9348,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9055
9348
|
`,
|
|
9056
9349
|
onClick: swallow
|
|
9057
9350
|
},
|
|
9058
|
-
isReadMode ? /* @__PURE__ */
|
|
9351
|
+
isReadMode ? /* @__PURE__ */ React22.createElement(
|
|
9059
9352
|
DescriptionReadModePanel,
|
|
9060
9353
|
{
|
|
9061
9354
|
title: `${sourceName} \u2794 ${targetName}`,
|
|
@@ -9067,15 +9360,15 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9067
9360
|
onMentionClick,
|
|
9068
9361
|
onImageClick: handleImageClickFromText
|
|
9069
9362
|
}
|
|
9070
|
-
) : /* @__PURE__ */
|
|
9363
|
+
) : /* @__PURE__ */ React22.createElement(React22.Fragment, null, /* @__PURE__ */ React22.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ React22.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React22.createElement("div", null, /* @__PURE__ */ React22.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React22.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-blue-500/80 shadow-[0_0_18px_2px_rgba(59,130,246,0.55)]" }), /* @__PURE__ */ React22.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Ancestralidade")), /* @__PURE__ */ React22.createElement("h2", { className: "text-lg font-semibold tracking-tight flex items-center gap-2" }, /* @__PURE__ */ React22.createElement("span", { className: "truncate max-w-[150px]" }, sourceName), /* @__PURE__ */ React22.createElement("span", { className: "text-slate-500 text-sm" }, "\u2794"), /* @__PURE__ */ React22.createElement("span", { className: "truncate max-w-[150px]" }, targetName))), /* @__PURE__ */ React22.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__ */ React22.createElement("div", { className: "px-6 pb-6 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, description && /* @__PURE__ */ React22.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React22.createElement("label", { className: "text-xs text-slate-300 font-medium" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React22.createElement(
|
|
9071
9364
|
"button",
|
|
9072
9365
|
{
|
|
9073
9366
|
onClick: () => setIsReadMode(true),
|
|
9074
9367
|
className: "p-1 text-slate-400 hover:text-white transition-colors",
|
|
9075
9368
|
title: "Modo de Leitura"
|
|
9076
9369
|
},
|
|
9077
|
-
/* @__PURE__ */
|
|
9078
|
-
)), /* @__PURE__ */
|
|
9370
|
+
/* @__PURE__ */ React22.createElement(FiBookOpen5, { size: 14 })
|
|
9371
|
+
)), /* @__PURE__ */ React22.createElement("div", { className: "bg-slate-800/40 rounded-lg border border-white/10 p-1 relative group" }, /* @__PURE__ */ React22.createElement(
|
|
9079
9372
|
DescriptionDisplay,
|
|
9080
9373
|
{
|
|
9081
9374
|
description,
|
|
@@ -9084,7 +9377,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9084
9377
|
onMentionClick,
|
|
9085
9378
|
onImageClick: handleImageClickFromText
|
|
9086
9379
|
}
|
|
9087
|
-
))), customProps.length > 0 && /* @__PURE__ */
|
|
9380
|
+
))), customProps.length > 0 && /* @__PURE__ */ React22.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React22.createElement("label", { className: "text-xs text-slate-300 font-medium mb-2 block" }, "Propriedades"), /* @__PURE__ */ React22.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop) => /* @__PURE__ */ React22.createElement(
|
|
9088
9381
|
CustomPropertyDisplay,
|
|
9089
9382
|
{
|
|
9090
9383
|
key: prop.id,
|
|
@@ -9093,25 +9386,25 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9093
9386
|
onOpenImageViewer,
|
|
9094
9387
|
onUploadFile
|
|
9095
9388
|
}
|
|
9096
|
-
)))), !description && customProps.length === 0 && /* @__PURE__ */
|
|
9389
|
+
)))), !description && customProps.length === 0 && /* @__PURE__ */ React22.createElement("div", { className: "py-8 text-center text-slate-500 text-sm italic border border-dashed border-white/10 rounded-lg" }, "Nenhum detalhe adicional dispon\xEDvel para esta conex\xE3o."), /* @__PURE__ */ React22.createElement("div", { className: "mt-4 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg text-xs text-blue-200/80 text-center" }, 'Para editar esta conex\xE3o, utilize o menu "Editar Ancestralidade".')))
|
|
9097
9390
|
)
|
|
9098
9391
|
);
|
|
9099
9392
|
}
|
|
9100
9393
|
|
|
9101
9394
|
// src/components/AncestryBoard.jsx
|
|
9102
|
-
import
|
|
9395
|
+
import React23, { useState as useState23, useMemo as useMemo11, useEffect as useEffect20, useRef as useRef17 } from "react";
|
|
9103
9396
|
import {
|
|
9104
9397
|
FiSearch as FiSearch4,
|
|
9105
9398
|
FiLayers as FiLayers6,
|
|
9106
9399
|
FiCornerUpRight as FiCornerUpRight4,
|
|
9107
9400
|
FiPlay,
|
|
9108
|
-
FiPlus as
|
|
9401
|
+
FiPlus as FiPlus8,
|
|
9109
9402
|
FiTrash2 as FiTrash23,
|
|
9110
9403
|
FiArrowLeft as FiArrowLeft3,
|
|
9111
9404
|
FiArrowRight,
|
|
9112
9405
|
FiCheckCircle,
|
|
9113
9406
|
FiLoader as FiLoader4,
|
|
9114
|
-
FiX as
|
|
9407
|
+
FiX as FiX6,
|
|
9115
9408
|
FiAlertTriangle
|
|
9116
9409
|
} from "react-icons/fi";
|
|
9117
9410
|
var GroupItem = ({
|
|
@@ -9133,7 +9426,7 @@ var GroupItem = ({
|
|
|
9133
9426
|
}) => {
|
|
9134
9427
|
const canIndent = index > 0;
|
|
9135
9428
|
const isPickingForThisGroup = pickingGroupId === group.id;
|
|
9136
|
-
const textareaRef =
|
|
9429
|
+
const textareaRef = useRef17(null);
|
|
9137
9430
|
const adjustHeight = () => {
|
|
9138
9431
|
const textarea = textareaRef.current;
|
|
9139
9432
|
if (textarea) {
|
|
@@ -9144,10 +9437,10 @@ var GroupItem = ({
|
|
|
9144
9437
|
useEffect20(() => {
|
|
9145
9438
|
adjustHeight();
|
|
9146
9439
|
}, [group.text]);
|
|
9147
|
-
return /* @__PURE__ */
|
|
9440
|
+
return /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React23.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React23.createElement("div", { className: `
|
|
9148
9441
|
flex flex-col gap-2 py-2 px-3 transition-all duration-200
|
|
9149
9442
|
${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
|
|
9150
|
-
` }, /* @__PURE__ */
|
|
9443
|
+
` }, /* @__PURE__ */ React23.createElement(
|
|
9151
9444
|
"textarea",
|
|
9152
9445
|
{
|
|
9153
9446
|
ref: textareaRef,
|
|
@@ -9164,9 +9457,9 @@ var GroupItem = ({
|
|
|
9164
9457
|
if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
|
|
9165
9458
|
}
|
|
9166
9459
|
}
|
|
9167
|
-
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */
|
|
9460
|
+
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
|
|
9168
9461
|
const isValid = availableIds.has(String(anc.ancestry_id));
|
|
9169
|
-
return /* @__PURE__ */
|
|
9462
|
+
return /* @__PURE__ */ React23.createElement(
|
|
9170
9463
|
"div",
|
|
9171
9464
|
{
|
|
9172
9465
|
key: anc.ancestry_id,
|
|
@@ -9178,28 +9471,28 @@ var GroupItem = ({
|
|
|
9178
9471
|
},
|
|
9179
9472
|
isValid ? (
|
|
9180
9473
|
// [MANTIDO] Botão Play visível para todos
|
|
9181
|
-
/* @__PURE__ */
|
|
9474
|
+
/* @__PURE__ */ React23.createElement(
|
|
9182
9475
|
"button",
|
|
9183
9476
|
{
|
|
9184
9477
|
onClick: () => onPlayAncestry(anc.ancestry_id),
|
|
9185
9478
|
className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
|
|
9186
9479
|
title: "Renderizar no cen\xE1rio"
|
|
9187
9480
|
},
|
|
9188
|
-
/* @__PURE__ */
|
|
9481
|
+
/* @__PURE__ */ React23.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
|
|
9189
9482
|
)
|
|
9190
|
-
) : /* @__PURE__ */
|
|
9191
|
-
/* @__PURE__ */
|
|
9192
|
-
canEdit && /* @__PURE__ */
|
|
9483
|
+
) : /* @__PURE__ */ React23.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React23.createElement(FiAlertTriangle, { size: 10 })),
|
|
9484
|
+
/* @__PURE__ */ React23.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
|
|
9485
|
+
canEdit && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement("div", { className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}` }), /* @__PURE__ */ React23.createElement(
|
|
9193
9486
|
"button",
|
|
9194
9487
|
{
|
|
9195
9488
|
onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
|
|
9196
9489
|
className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
|
|
9197
9490
|
title: "Remover men\xE7\xE3o"
|
|
9198
9491
|
},
|
|
9199
|
-
/* @__PURE__ */
|
|
9492
|
+
/* @__PURE__ */ React23.createElement(FiX6, { size: 12 })
|
|
9200
9493
|
))
|
|
9201
9494
|
);
|
|
9202
|
-
})), canEdit && /* @__PURE__ */
|
|
9495
|
+
})), canEdit && /* @__PURE__ */ React23.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React23.createElement(
|
|
9203
9496
|
"button",
|
|
9204
9497
|
{
|
|
9205
9498
|
onClick: () => onRequestPickAncestry(group.id),
|
|
@@ -9209,17 +9502,17 @@ var GroupItem = ({
|
|
|
9209
9502
|
`,
|
|
9210
9503
|
title: "Adicionar Ancestralidade a este grupo"
|
|
9211
9504
|
},
|
|
9212
|
-
isPickingForThisGroup ? /* @__PURE__ */
|
|
9505
|
+
isPickingForThisGroup ? /* @__PURE__ */ React23.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React23.createElement(FiSearch4, { size: 12 }),
|
|
9213
9506
|
isPickingForThisGroup ? "Selecionando..." : "Adicionar"
|
|
9214
|
-
), /* @__PURE__ */
|
|
9507
|
+
), /* @__PURE__ */ React23.createElement(
|
|
9215
9508
|
"button",
|
|
9216
9509
|
{
|
|
9217
9510
|
onClick: () => onAddSubgroup(group.id),
|
|
9218
9511
|
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
9219
9512
|
title: "Criar Subgrupo"
|
|
9220
9513
|
},
|
|
9221
|
-
/* @__PURE__ */
|
|
9222
|
-
)), /* @__PURE__ */
|
|
9514
|
+
/* @__PURE__ */ React23.createElement(FiPlus8, { size: 14 })
|
|
9515
|
+
)), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React23.createElement(
|
|
9223
9516
|
"button",
|
|
9224
9517
|
{
|
|
9225
9518
|
onClick: () => onIndent(group.id),
|
|
@@ -9227,24 +9520,24 @@ var GroupItem = ({
|
|
|
9227
9520
|
className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
|
|
9228
9521
|
title: "Aninhar no grupo acima"
|
|
9229
9522
|
},
|
|
9230
|
-
/* @__PURE__ */
|
|
9231
|
-
), /* @__PURE__ */
|
|
9523
|
+
/* @__PURE__ */ React23.createElement(FiArrowRight, { size: 14 })
|
|
9524
|
+
), /* @__PURE__ */ React23.createElement(
|
|
9232
9525
|
"button",
|
|
9233
9526
|
{
|
|
9234
9527
|
onClick: () => onOutdent(group.id),
|
|
9235
9528
|
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
9236
9529
|
title: "Desaninhar"
|
|
9237
9530
|
},
|
|
9238
|
-
/* @__PURE__ */
|
|
9239
|
-
), /* @__PURE__ */
|
|
9531
|
+
/* @__PURE__ */ React23.createElement(FiArrowLeft3, { size: 14 })
|
|
9532
|
+
), /* @__PURE__ */ React23.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React23.createElement(
|
|
9240
9533
|
"button",
|
|
9241
9534
|
{
|
|
9242
9535
|
onClick: () => onDelete(group.id),
|
|
9243
9536
|
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
|
|
9244
9537
|
title: "Remover Grupo"
|
|
9245
9538
|
},
|
|
9246
|
-
/* @__PURE__ */
|
|
9247
|
-
)))), group.children && group.children.length > 0 && /* @__PURE__ */
|
|
9539
|
+
/* @__PURE__ */ React23.createElement(FiTrash23, { size: 14 })
|
|
9540
|
+
)))), group.children && group.children.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React23.createElement(
|
|
9248
9541
|
GroupItem,
|
|
9249
9542
|
{
|
|
9250
9543
|
key: childGroup.id,
|
|
@@ -9276,11 +9569,11 @@ function AncestryBoard({
|
|
|
9276
9569
|
userRole
|
|
9277
9570
|
// [NOVO] Recebe a role do usuário
|
|
9278
9571
|
}) {
|
|
9279
|
-
const [searchTerm, setSearchTerm] =
|
|
9280
|
-
const [groups, setGroups] =
|
|
9281
|
-
const [isLoaded, setIsLoaded] =
|
|
9282
|
-
const [pickingGroupId, setPickingGroupId] =
|
|
9283
|
-
const [saveStatus, setSaveStatus] =
|
|
9572
|
+
const [searchTerm, setSearchTerm] = useState23("");
|
|
9573
|
+
const [groups, setGroups] = useState23([]);
|
|
9574
|
+
const [isLoaded, setIsLoaded] = useState23(false);
|
|
9575
|
+
const [pickingGroupId, setPickingGroupId] = useState23(null);
|
|
9576
|
+
const [saveStatus, setSaveStatus] = useState23("idle");
|
|
9284
9577
|
const canEdit = useMemo11(() => {
|
|
9285
9578
|
return userRole !== "viewer";
|
|
9286
9579
|
}, [userRole]);
|
|
@@ -9488,27 +9781,27 @@ function AncestryBoard({
|
|
|
9488
9781
|
});
|
|
9489
9782
|
};
|
|
9490
9783
|
if (!isOpen) return null;
|
|
9491
|
-
return /* @__PURE__ */
|
|
9784
|
+
return /* @__PURE__ */ React23.createElement(
|
|
9492
9785
|
"div",
|
|
9493
9786
|
{
|
|
9494
9787
|
className: "fixed inset-0 z-[2200] bg-black/80 backdrop-blur-sm flex items-center justify-center p-2",
|
|
9495
9788
|
onClick: onClose
|
|
9496
9789
|
},
|
|
9497
|
-
/* @__PURE__ */
|
|
9790
|
+
/* @__PURE__ */ React23.createElement(
|
|
9498
9791
|
"div",
|
|
9499
9792
|
{
|
|
9500
9793
|
className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
|
|
9501
9794
|
onClick: (e) => e.stopPropagation()
|
|
9502
9795
|
},
|
|
9503
|
-
/* @__PURE__ */
|
|
9796
|
+
/* @__PURE__ */ React23.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React23.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React23.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React23.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(FiLoader4, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ React23.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React23.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React23.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ React23.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ React23.createElement(
|
|
9504
9797
|
"button",
|
|
9505
9798
|
{
|
|
9506
9799
|
onClick: handleAddRootGroup,
|
|
9507
9800
|
className: "\n flex items-center gap-2 px-3 py-1.5 \n bg-white/5 hover:bg-white/10 \n border border-white/10 hover:border-white/20\n backdrop-blur-sm\n text-slate-200 hover:text-white\n rounded-md transition-all duration-200\n text-xs font-medium shadow-sm\n "
|
|
9508
9801
|
},
|
|
9509
|
-
/* @__PURE__ */
|
|
9510
|
-
/* @__PURE__ */
|
|
9511
|
-
), /* @__PURE__ */
|
|
9802
|
+
/* @__PURE__ */ React23.createElement(FiPlus8, { size: 14, className: "text-indigo-400" }),
|
|
9803
|
+
/* @__PURE__ */ React23.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
|
|
9804
|
+
), /* @__PURE__ */ React23.createElement(
|
|
9512
9805
|
"button",
|
|
9513
9806
|
{
|
|
9514
9807
|
onClick: onClose,
|
|
@@ -9516,11 +9809,11 @@ function AncestryBoard({
|
|
|
9516
9809
|
},
|
|
9517
9810
|
"\xD7"
|
|
9518
9811
|
))),
|
|
9519
|
-
/* @__PURE__ */
|
|
9812
|
+
/* @__PURE__ */ React23.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React23.createElement("div", { className: `
|
|
9520
9813
|
flex flex-col border-r border-white/10 transition-all duration-300 flex-none
|
|
9521
9814
|
${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
|
|
9522
9815
|
min-w-[280px] max-w-[500px] bg-slate-900
|
|
9523
|
-
` }, /* @__PURE__ */
|
|
9816
|
+
` }, /* @__PURE__ */ React23.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React23.createElement("div", { className: "relative group" }, /* @__PURE__ */ React23.createElement(FiSearch4, { className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}` }), /* @__PURE__ */ React23.createElement(
|
|
9524
9817
|
"input",
|
|
9525
9818
|
{
|
|
9526
9819
|
type: "text",
|
|
@@ -9533,10 +9826,10 @@ function AncestryBoard({
|
|
|
9533
9826
|
onChange: (e) => setSearchTerm(e.target.value),
|
|
9534
9827
|
autoFocus: !pickingGroupId
|
|
9535
9828
|
}
|
|
9536
|
-
))), /* @__PURE__ */
|
|
9829
|
+
))), /* @__PURE__ */ React23.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
|
|
9537
9830
|
const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
|
|
9538
9831
|
const isPicking = !!pickingGroupId;
|
|
9539
|
-
return /* @__PURE__ */
|
|
9832
|
+
return /* @__PURE__ */ React23.createElement(
|
|
9540
9833
|
"div",
|
|
9541
9834
|
{
|
|
9542
9835
|
key: anc.ancestry_id,
|
|
@@ -9548,12 +9841,12 @@ function AncestryBoard({
|
|
|
9548
9841
|
${isPicking ? "border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer" : "border-white/5 bg-slate-800/40 hover:bg-indigo-600/10 hover:border-indigo-500/30 cursor-default"}
|
|
9549
9842
|
`
|
|
9550
9843
|
},
|
|
9551
|
-
/* @__PURE__ */
|
|
9844
|
+
/* @__PURE__ */ React23.createElement("div", { className: `
|
|
9552
9845
|
mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
|
|
9553
9846
|
${isPicking ? "bg-indigo-500 text-white border-indigo-400" : "bg-slate-800 text-indigo-400 border-white/5 group-hover:bg-indigo-500 group-hover:text-white"}
|
|
9554
|
-
` }, isPicking ? /* @__PURE__ */
|
|
9555
|
-
/* @__PURE__ */
|
|
9556
|
-
!isPicking && /* @__PURE__ */
|
|
9847
|
+
` }, isPicking ? /* @__PURE__ */ React23.createElement(FiPlus8, { size: 16 }) : /* @__PURE__ */ React23.createElement(FiLayers6, { size: 14 })),
|
|
9848
|
+
/* @__PURE__ */ React23.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React23.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React23.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React23.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React23.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React23.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
|
|
9849
|
+
!isPicking && /* @__PURE__ */ React23.createElement(
|
|
9557
9850
|
"button",
|
|
9558
9851
|
{
|
|
9559
9852
|
onClick: (e) => {
|
|
@@ -9563,10 +9856,10 @@ function AncestryBoard({
|
|
|
9563
9856
|
className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
|
|
9564
9857
|
title: "Renderizar Ancestralidade"
|
|
9565
9858
|
},
|
|
9566
|
-
/* @__PURE__ */
|
|
9859
|
+
/* @__PURE__ */ React23.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React23.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
|
|
9567
9860
|
)
|
|
9568
9861
|
);
|
|
9569
|
-
}))), /* @__PURE__ */
|
|
9862
|
+
}))), /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ React23.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React23.createElement(FiLayers6, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React23.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React23.createElement(React23.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React23.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React23.createElement(React23.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React23.createElement(
|
|
9570
9863
|
GroupItem,
|
|
9571
9864
|
{
|
|
9572
9865
|
key: group.id,
|
|
@@ -9586,7 +9879,7 @@ function AncestryBoard({
|
|
|
9586
9879
|
canEdit
|
|
9587
9880
|
}
|
|
9588
9881
|
))))),
|
|
9589
|
-
/* @__PURE__ */
|
|
9882
|
+
/* @__PURE__ */ React23.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-between flex-shrink-0" }, /* @__PURE__ */ React23.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ React23.createElement("span", null, groups.length, " grupos raiz"))
|
|
9590
9883
|
)
|
|
9591
9884
|
);
|
|
9592
9885
|
}
|
|
@@ -9730,44 +10023,45 @@ function XViewScene({
|
|
|
9730
10023
|
}
|
|
9731
10024
|
return null;
|
|
9732
10025
|
}, [ownerId, sceneConfigId]);
|
|
9733
|
-
const sceneDataRef =
|
|
9734
|
-
const parentDataRef =
|
|
9735
|
-
const ancestryDataRef =
|
|
9736
|
-
const [isLoading, setIsLoading] =
|
|
9737
|
-
const [permissionStatus, setPermissionStatus] =
|
|
9738
|
-
const [userPermissionRole, setUserPermissionRole] =
|
|
9739
|
-
const [isInitialized, setIsInitialized] =
|
|
9740
|
-
const [sceneVersion, setSceneVersion] =
|
|
9741
|
-
const [contextMenu, setContextMenu] =
|
|
9742
|
-
const [multiContextMenu, setMultiContextMenu] =
|
|
9743
|
-
const [relationshipMenu, setRelationshipMenu] =
|
|
9744
|
-
const [creationMode, setCreationMode] =
|
|
9745
|
-
const [versionMode, setVersionMode] =
|
|
9746
|
-
const [
|
|
9747
|
-
const [
|
|
9748
|
-
const [
|
|
9749
|
-
const [
|
|
10026
|
+
const sceneDataRef = useRef18(null);
|
|
10027
|
+
const parentDataRef = useRef18(null);
|
|
10028
|
+
const ancestryDataRef = useRef18(null);
|
|
10029
|
+
const [isLoading, setIsLoading] = useState24(true);
|
|
10030
|
+
const [permissionStatus, setPermissionStatus] = useState24("loading");
|
|
10031
|
+
const [userPermissionRole, setUserPermissionRole] = useState24(null);
|
|
10032
|
+
const [isInitialized, setIsInitialized] = useState24(false);
|
|
10033
|
+
const [sceneVersion, setSceneVersion] = useState24(0);
|
|
10034
|
+
const [contextMenu, setContextMenu] = useState24({ visible: false, x: 0, y: 0, nodeData: null });
|
|
10035
|
+
const [multiContextMenu, setMultiContextMenu] = useState24({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
10036
|
+
const [relationshipMenu, setRelationshipMenu] = useState24({ visible: false, x: 0, y: 0, linkObject: null });
|
|
10037
|
+
const [creationMode, setCreationMode] = useState24({ isActive: false, sourceNodeData: null });
|
|
10038
|
+
const [versionMode, setVersionMode] = useState24({ isActive: false, sourceNodeData: null });
|
|
10039
|
+
const [questMode, setQuestMode] = useState24({ isActive: false });
|
|
10040
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState24(false);
|
|
10041
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState24(false);
|
|
10042
|
+
const [ancestryMode, setAncestryMode] = useState24({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
10043
|
+
const [readingMode, setReadingMode] = useState24({
|
|
9750
10044
|
isActive: false,
|
|
9751
10045
|
ancestry: null,
|
|
9752
10046
|
branchStack: [],
|
|
9753
10047
|
autoAbstraction: false
|
|
9754
10048
|
});
|
|
9755
|
-
const [formPosition, setFormPosition] =
|
|
9756
|
-
const [detailsNode, setDetailsNode] =
|
|
9757
|
-
const [detailsLink, setDetailsLink] =
|
|
9758
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] =
|
|
9759
|
-
const [imageViewer, setImageViewer] =
|
|
9760
|
-
const [editingAncestryRel, setEditingAncestryRel] =
|
|
9761
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
9762
|
-
const [importSuccessMessage, setImportSuccessMessage] =
|
|
9763
|
-
const [highlightedNodeId, setHighlightedNodeId] =
|
|
9764
|
-
const [isAncestryBoardOpen, setIsAncestryBoardOpen] =
|
|
9765
|
-
const [ancestryBoardData, setAncestryBoardData] =
|
|
9766
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
9767
|
-
const mountRef =
|
|
9768
|
-
const tooltipRef =
|
|
9769
|
-
const formRef =
|
|
9770
|
-
const stateRef =
|
|
10049
|
+
const [formPosition, setFormPosition] = useState24({ left: 16, top: 16, opacity: 0 });
|
|
10050
|
+
const [detailsNode, setDetailsNode] = useState24(null);
|
|
10051
|
+
const [detailsLink, setDetailsLink] = useState24(null);
|
|
10052
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState24(null);
|
|
10053
|
+
const [imageViewer, setImageViewer] = useState24({ visible: false, images: [], startIndex: 0 });
|
|
10054
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState24({ visible: false, data: null, path: null });
|
|
10055
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState24(false);
|
|
10056
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState24("");
|
|
10057
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState24(null);
|
|
10058
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState24(false);
|
|
10059
|
+
const [ancestryBoardData, setAncestryBoardData] = useState24([]);
|
|
10060
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState24(false);
|
|
10061
|
+
const mountRef = useRef18(null);
|
|
10062
|
+
const tooltipRef = useRef18(null);
|
|
10063
|
+
const formRef = useRef18(null);
|
|
10064
|
+
const stateRef = useRef18({
|
|
9771
10065
|
readMode: {
|
|
9772
10066
|
currentMaxIndex: 0,
|
|
9773
10067
|
progressMap: {}
|
|
@@ -10809,12 +11103,15 @@ function XViewScene({
|
|
|
10809
11103
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
10810
11104
|
}
|
|
10811
11105
|
function handleKeyDown(event) {
|
|
11106
|
+
var _a2, _b2, _c2, _d2;
|
|
10812
11107
|
const context = actionHandlerContext;
|
|
10813
11108
|
if (event.key === "Escape") {
|
|
10814
11109
|
if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
|
|
10815
11110
|
if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
|
|
10816
11111
|
if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
|
|
11112
|
+
if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
|
|
10817
11113
|
if (stateRef.current.ancestry.isActive) handleCancelAncestryCreation();
|
|
11114
|
+
if ((_b2 = context.questMode) == null ? void 0 : _b2.isActive) context.setters.setQuestMode({ isActive: false });
|
|
10818
11115
|
if (stateRef.current.selectedNodes.size > 0) {
|
|
10819
11116
|
stateRef.current.selectedNodes.clear();
|
|
10820
11117
|
}
|
|
@@ -10822,6 +11119,17 @@ function XViewScene({
|
|
|
10822
11119
|
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
10823
11120
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
10824
11121
|
}
|
|
11122
|
+
if (event.key.toLowerCase() === "q") {
|
|
11123
|
+
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_c2 = context.versionMode) == null ? void 0 : _c2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen;
|
|
11124
|
+
if (isUiClear) {
|
|
11125
|
+
const isView = ((_d2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _d2.toLowerCase()) === "view";
|
|
11126
|
+
if (!isView) {
|
|
11127
|
+
alert("Nodes de Quest s\xF3 podem ser criados dentro de uma View.");
|
|
11128
|
+
return;
|
|
11129
|
+
}
|
|
11130
|
+
setQuestMode({ isActive: true });
|
|
11131
|
+
}
|
|
11132
|
+
}
|
|
10825
11133
|
}
|
|
10826
11134
|
function handleDoubleClick(event) {
|
|
10827
11135
|
if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
|
|
@@ -10980,9 +11288,7 @@ function XViewScene({
|
|
|
10980
11288
|
mountEl: currentMount,
|
|
10981
11289
|
isSceneBusy: stateRef.current.isDragging || creation.isActive || connection.isActive || relink.isActive || ancestryMode.isActive,
|
|
10982
11290
|
parentData: parentDataRef.current,
|
|
10983
|
-
// <--- ADICIONADO AQUI
|
|
10984
11291
|
ancestryData: ancestryDataRef.current
|
|
10985
|
-
// <--- ADICIONADO AQUI
|
|
10986
11292
|
});
|
|
10987
11293
|
(_b2 = stateRef.current.tweenGroup) == null ? void 0 : _b2.update(time);
|
|
10988
11294
|
stateRef.current.controls.update();
|
|
@@ -11288,6 +11594,11 @@ function XViewScene({
|
|
|
11288
11594
|
mountRef,
|
|
11289
11595
|
creationMode,
|
|
11290
11596
|
versionMode,
|
|
11597
|
+
questMode,
|
|
11598
|
+
sceneSaveUrl,
|
|
11599
|
+
sceneConfigId,
|
|
11600
|
+
ownerId,
|
|
11601
|
+
viewType: viewParams == null ? void 0 : viewParams.type,
|
|
11291
11602
|
userId: (_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id,
|
|
11292
11603
|
setters: {
|
|
11293
11604
|
setContextMenu,
|
|
@@ -11299,7 +11610,8 @@ function XViewScene({
|
|
|
11299
11610
|
setDetailsNode,
|
|
11300
11611
|
setDetailsLink,
|
|
11301
11612
|
setSceneVersion,
|
|
11302
|
-
setAncestryMode
|
|
11613
|
+
setAncestryMode,
|
|
11614
|
+
setQuestMode
|
|
11303
11615
|
},
|
|
11304
11616
|
tweenToTarget,
|
|
11305
11617
|
handleVersionTimeline,
|
|
@@ -11315,8 +11627,13 @@ function XViewScene({
|
|
|
11315
11627
|
[
|
|
11316
11628
|
creationMode,
|
|
11317
11629
|
versionMode,
|
|
11318
|
-
|
|
11630
|
+
questMode,
|
|
11631
|
+
sceneSaveUrl,
|
|
11632
|
+
sceneConfigId,
|
|
11633
|
+
ownerId,
|
|
11634
|
+
viewParams == null ? void 0 : viewParams.type,
|
|
11319
11635
|
(_a = session == null ? void 0 : session.user) == null ? void 0 : _a.id,
|
|
11636
|
+
tweenToTarget,
|
|
11320
11637
|
handleVersionTimeline,
|
|
11321
11638
|
save_view_data,
|
|
11322
11639
|
get_single_parent_file,
|
|
@@ -11328,6 +11645,97 @@ function XViewScene({
|
|
|
11328
11645
|
const handleStartVersioning = (nodeData) => {
|
|
11329
11646
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
11330
11647
|
};
|
|
11648
|
+
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
11649
|
+
const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
|
|
11650
|
+
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
11651
|
+
const newNode = {
|
|
11652
|
+
id: short2.generate(),
|
|
11653
|
+
...newQuestData,
|
|
11654
|
+
is_quest: true,
|
|
11655
|
+
type: ["quest", ...newQuestData.type.filter((t) => t !== "quest")]
|
|
11656
|
+
};
|
|
11657
|
+
if (!graphDataRef.current[sceneConfigId2]) {
|
|
11658
|
+
graphDataRef.current[sceneConfigId2] = { nodes: [], links: [] };
|
|
11659
|
+
}
|
|
11660
|
+
graphDataRef.current[sceneConfigId2].nodes.push(newNode);
|
|
11661
|
+
const sceneFileData = {
|
|
11662
|
+
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11663
|
+
nodes: sceneDataRef2.current.nodes,
|
|
11664
|
+
// <-- Mantém o cenário inicial inalterado
|
|
11665
|
+
links: sceneDataRef2.current.links,
|
|
11666
|
+
// <-- Mantém o cenário inicial inalterado
|
|
11667
|
+
quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
|
|
11668
|
+
quest_links: graphDataRef.current[sceneConfigId2].links
|
|
11669
|
+
};
|
|
11670
|
+
try {
|
|
11671
|
+
await actions.save_view_data(sceneSaveUrl2, sceneFileData);
|
|
11672
|
+
stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
|
|
11673
|
+
parentFileId: sceneConfigId2,
|
|
11674
|
+
ownerId: ownerId2,
|
|
11675
|
+
datasetName: "Quests Internas (View)"
|
|
11676
|
+
});
|
|
11677
|
+
const basePosition = stateRef2.current.controls.target.clone();
|
|
11678
|
+
const offset = new THREE3.Vector3((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 5, 0);
|
|
11679
|
+
const finalPosition = basePosition.add(offset);
|
|
11680
|
+
addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
|
|
11681
|
+
context.tweenToTarget(finalPosition, 1.2);
|
|
11682
|
+
setters.setQuestMode({ isActive: false });
|
|
11683
|
+
setters.setSceneVersion((v) => v + 1);
|
|
11684
|
+
} catch (error) {
|
|
11685
|
+
console.error("Falha ao salvar Quest na View:", error);
|
|
11686
|
+
alert("Ocorreu um erro ao criar a Quest.");
|
|
11687
|
+
}
|
|
11688
|
+
};
|
|
11689
|
+
userActionHandlers.handleCompleteConnection = async (context, targetNodeData) => {
|
|
11690
|
+
const { stateRef: stateRef2, graphDataRef, sceneDataRef: sceneDataRef2, sceneConfigId: sceneConfigId2, sceneSaveUrl: sceneSaveUrl2, ownerId: ownerId2 } = context;
|
|
11691
|
+
const { sourceNodeData } = stateRef2.current.connection;
|
|
11692
|
+
if (!graphDataRef.current || !sceneDataRef2.current || !sourceNodeData || !targetNodeData) {
|
|
11693
|
+
userActionHandlers.handleCancelConnection(context);
|
|
11694
|
+
return;
|
|
11695
|
+
}
|
|
11696
|
+
const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2, ownerId2);
|
|
11697
|
+
const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2, ownerId2);
|
|
11698
|
+
let parentInfoToSave = sourceParentInfo;
|
|
11699
|
+
if (sourceParentInfo.parentFileId === sceneConfigId2 && targetParentInfo.parentFileId !== sceneConfigId2) {
|
|
11700
|
+
parentInfoToSave = targetParentInfo;
|
|
11701
|
+
} else if (targetParentInfo.parentFileId === sceneConfigId2 && sourceParentInfo.parentFileId !== sceneConfigId2) {
|
|
11702
|
+
parentInfoToSave = sourceParentInfo;
|
|
11703
|
+
}
|
|
11704
|
+
const { parentFileId: parentFileIdToSave, ownerId: ownerIdToSave } = parentInfoToSave;
|
|
11705
|
+
const newLink = {
|
|
11706
|
+
id: `link_${short2.generate()}`,
|
|
11707
|
+
source: sourceNodeData.id,
|
|
11708
|
+
target: targetNodeData.id
|
|
11709
|
+
};
|
|
11710
|
+
try {
|
|
11711
|
+
if (parentFileIdToSave === sceneConfigId2) {
|
|
11712
|
+
const specificParentData = graphDataRef.current[sceneConfigId2];
|
|
11713
|
+
specificParentData.links.push(newLink);
|
|
11714
|
+
const viewFilePayload = {
|
|
11715
|
+
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11716
|
+
nodes: sceneDataRef2.current.nodes,
|
|
11717
|
+
// <-- Usa o estado original intocado
|
|
11718
|
+
links: sceneDataRef2.current.links,
|
|
11719
|
+
// <-- Usa o estado original intocado
|
|
11720
|
+
quest_nodes: specificParentData.nodes,
|
|
11721
|
+
quest_links: specificParentData.links
|
|
11722
|
+
// Salva a conexão aqui!
|
|
11723
|
+
};
|
|
11724
|
+
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
11725
|
+
} else {
|
|
11726
|
+
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
11727
|
+
specificParentData.links.push(newLink);
|
|
11728
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
11729
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
11730
|
+
graphDataRef.current[parentFileIdToSave] = specificParentData;
|
|
11731
|
+
}
|
|
11732
|
+
addNewLinkToScene(stateRef2.current, newLink);
|
|
11733
|
+
} catch (error) {
|
|
11734
|
+
console.error("Falha ao salvar a nova conex\xE3o:", error);
|
|
11735
|
+
alert("Ocorreu um erro ao salvar a nova conex\xE3o.");
|
|
11736
|
+
}
|
|
11737
|
+
userActionHandlers.handleCancelConnection(context);
|
|
11738
|
+
};
|
|
11331
11739
|
const handleClearAncestryVisuals = useCallback4((ancestryId) => {
|
|
11332
11740
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
11333
11741
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
@@ -12595,6 +13003,7 @@ function XViewScene({
|
|
|
12595
13003
|
[actionHandlerContext]
|
|
12596
13004
|
);
|
|
12597
13005
|
const handleSaveCurrentView = useCallback4(async () => {
|
|
13006
|
+
var _a2, _b2, _c2;
|
|
12598
13007
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
12599
13008
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
12600
13009
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12616,17 +13025,22 @@ function XViewScene({
|
|
|
12616
13025
|
const { sourceNode, targetNode, ...serializableLinkData } = line.userData;
|
|
12617
13026
|
return serializableLinkData;
|
|
12618
13027
|
});
|
|
13028
|
+
sceneDataRef.current.nodes = currentNodes;
|
|
13029
|
+
sceneDataRef.current.links = currentLinks;
|
|
13030
|
+
const isView = ((_a2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _a2.toLowerCase()) === "view";
|
|
12619
13031
|
const sceneFileData = {
|
|
12620
13032
|
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
12621
13033
|
nodes: currentNodes,
|
|
12622
|
-
links: currentLinks
|
|
13034
|
+
links: currentLinks,
|
|
13035
|
+
quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
|
|
13036
|
+
quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || []
|
|
12623
13037
|
};
|
|
12624
13038
|
try {
|
|
12625
13039
|
await save_view_data(sceneSaveUrl, sceneFileData);
|
|
12626
13040
|
} catch (error) {
|
|
12627
13041
|
console.error("Erro na chamada de save_view_data:", error);
|
|
12628
13042
|
}
|
|
12629
|
-
}, [sceneSaveUrl, save_view_data]);
|
|
13043
|
+
}, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
|
|
12630
13044
|
const allAvailableNodes = useMemo12(() => {
|
|
12631
13045
|
if (!parentDataRef.current) return [];
|
|
12632
13046
|
return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
|
|
@@ -12712,20 +13126,20 @@ function XViewScene({
|
|
|
12712
13126
|
}
|
|
12713
13127
|
}, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
|
|
12714
13128
|
if (isLoading || status === "loading" || permissionStatus === "loading") {
|
|
12715
|
-
return /* @__PURE__ */
|
|
13129
|
+
return /* @__PURE__ */ React24.createElement(LoadingScreen, null);
|
|
12716
13130
|
}
|
|
12717
13131
|
if (permissionStatus === "denied") {
|
|
12718
|
-
return /* @__PURE__ */
|
|
13132
|
+
return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React24.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React24.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React24.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "w-16 h-16 mx-auto" }, /* @__PURE__ */ React24.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" }))), /* @__PURE__ */ React24.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React24.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React24.createElement(
|
|
12719
13133
|
"button",
|
|
12720
13134
|
{
|
|
12721
13135
|
onClick: () => router.push("/dashboard/scenes"),
|
|
12722
13136
|
className: "flex items-center justify-center gap-2 w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors font-medium"
|
|
12723
13137
|
},
|
|
12724
|
-
/* @__PURE__ */
|
|
13138
|
+
/* @__PURE__ */ React24.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", className: "w-5 h-5" }, /* @__PURE__ */ React24.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" })),
|
|
12725
13139
|
"Voltar para Scenes"
|
|
12726
13140
|
)));
|
|
12727
13141
|
}
|
|
12728
|
-
return /* @__PURE__ */
|
|
13142
|
+
return /* @__PURE__ */ React24.createElement(
|
|
12729
13143
|
"div",
|
|
12730
13144
|
{
|
|
12731
13145
|
ref: mountRef,
|
|
@@ -12737,7 +13151,7 @@ function XViewScene({
|
|
|
12737
13151
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
12738
13152
|
}
|
|
12739
13153
|
},
|
|
12740
|
-
userPermissionRole !== "link_viewer" && /* @__PURE__ */
|
|
13154
|
+
userPermissionRole !== "link_viewer" && /* @__PURE__ */ React24.createElement(
|
|
12741
13155
|
XViewSidebar,
|
|
12742
13156
|
{
|
|
12743
13157
|
dbNodes: searchableDbNodes,
|
|
@@ -12757,7 +13171,7 @@ function XViewScene({
|
|
|
12757
13171
|
userRole: userPermissionRole
|
|
12758
13172
|
}
|
|
12759
13173
|
),
|
|
12760
|
-
creationMode.isActive && /* @__PURE__ */
|
|
13174
|
+
creationMode.isActive && /* @__PURE__ */ React24.createElement(
|
|
12761
13175
|
InSceneCreationForm,
|
|
12762
13176
|
{
|
|
12763
13177
|
onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
|
|
@@ -12782,7 +13196,7 @@ function XViewScene({
|
|
|
12782
13196
|
availableAncestries: allAvailableAncestries
|
|
12783
13197
|
}
|
|
12784
13198
|
),
|
|
12785
|
-
versionMode.isActive && /* @__PURE__ */
|
|
13199
|
+
versionMode.isActive && /* @__PURE__ */ React24.createElement(
|
|
12786
13200
|
InSceneVersionForm,
|
|
12787
13201
|
{
|
|
12788
13202
|
onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
|
|
@@ -12801,13 +13215,27 @@ function XViewScene({
|
|
|
12801
13215
|
availableAncestries: allAvailableAncestries
|
|
12802
13216
|
}
|
|
12803
13217
|
),
|
|
12804
|
-
|
|
13218
|
+
questMode.isActive && /* @__PURE__ */ React24.createElement(
|
|
13219
|
+
InSceneQuestForm,
|
|
13220
|
+
{
|
|
13221
|
+
onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
|
|
13222
|
+
onCancel: () => setQuestMode({ isActive: false }),
|
|
13223
|
+
style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
13224
|
+
refEl: formRef,
|
|
13225
|
+
onOpenImageViewer: handleOpenImageViewer,
|
|
13226
|
+
onMentionClick: handleAddExistingNode,
|
|
13227
|
+
onUploadFile: upload_file_action,
|
|
13228
|
+
availableNodes: allAvailableNodes,
|
|
13229
|
+
availableAncestries: allAvailableAncestries
|
|
13230
|
+
}
|
|
13231
|
+
),
|
|
13232
|
+
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React24.createElement(
|
|
12805
13233
|
"div",
|
|
12806
13234
|
{
|
|
12807
13235
|
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"}`,
|
|
12808
13236
|
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
12809
13237
|
},
|
|
12810
|
-
/* @__PURE__ */
|
|
13238
|
+
/* @__PURE__ */ React24.createElement(
|
|
12811
13239
|
"div",
|
|
12812
13240
|
{
|
|
12813
13241
|
onPointerDown: (e) => {
|
|
@@ -12818,7 +13246,7 @@ function XViewScene({
|
|
|
12818
13246
|
title: "Arraste para redimensionar"
|
|
12819
13247
|
}
|
|
12820
13248
|
),
|
|
12821
|
-
/* @__PURE__ */
|
|
13249
|
+
/* @__PURE__ */ React24.createElement(
|
|
12822
13250
|
DescriptionReadModePanel,
|
|
12823
13251
|
{
|
|
12824
13252
|
key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
|
|
@@ -12853,7 +13281,7 @@ function XViewScene({
|
|
|
12853
13281
|
}
|
|
12854
13282
|
)
|
|
12855
13283
|
),
|
|
12856
|
-
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */
|
|
13284
|
+
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React24.createElement(
|
|
12857
13285
|
CreateAncestryPanel,
|
|
12858
13286
|
{
|
|
12859
13287
|
ancestryMode,
|
|
@@ -12880,7 +13308,7 @@ function XViewScene({
|
|
|
12880
13308
|
onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
|
|
12881
13309
|
}
|
|
12882
13310
|
),
|
|
12883
|
-
editingAncestryRel.visible && /* @__PURE__ */
|
|
13311
|
+
editingAncestryRel.visible && /* @__PURE__ */ React24.createElement(
|
|
12884
13312
|
AncestryRelationshipPanel,
|
|
12885
13313
|
{
|
|
12886
13314
|
data: editingAncestryRel.data,
|
|
@@ -12894,7 +13322,7 @@ function XViewScene({
|
|
|
12894
13322
|
onUploadFile: upload_file_action
|
|
12895
13323
|
}
|
|
12896
13324
|
),
|
|
12897
|
-
detailsNode && /* @__PURE__ */
|
|
13325
|
+
detailsNode && /* @__PURE__ */ React24.createElement(
|
|
12898
13326
|
NodeDetailsPanel,
|
|
12899
13327
|
{
|
|
12900
13328
|
node: detailsNode,
|
|
@@ -12921,7 +13349,7 @@ function XViewScene({
|
|
|
12921
13349
|
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
12922
13350
|
}
|
|
12923
13351
|
),
|
|
12924
|
-
detailsLink && /* @__PURE__ */
|
|
13352
|
+
detailsLink && /* @__PURE__ */ React24.createElement(
|
|
12925
13353
|
RelationshipDetailsPanel,
|
|
12926
13354
|
{
|
|
12927
13355
|
link: detailsLink,
|
|
@@ -12935,7 +13363,7 @@ function XViewScene({
|
|
|
12935
13363
|
userRole: userPermissionRole
|
|
12936
13364
|
}
|
|
12937
13365
|
),
|
|
12938
|
-
ancestryLinkDetails && /* @__PURE__ */
|
|
13366
|
+
ancestryLinkDetails && /* @__PURE__ */ React24.createElement(
|
|
12939
13367
|
AncestryLinkDetailsPanel,
|
|
12940
13368
|
{
|
|
12941
13369
|
data: ancestryLinkDetails,
|
|
@@ -12946,7 +13374,7 @@ function XViewScene({
|
|
|
12946
13374
|
onUploadFile: upload_file_action
|
|
12947
13375
|
}
|
|
12948
13376
|
),
|
|
12949
|
-
/* @__PURE__ */
|
|
13377
|
+
/* @__PURE__ */ React24.createElement(
|
|
12950
13378
|
"div",
|
|
12951
13379
|
{
|
|
12952
13380
|
ref: tooltipRef,
|
|
@@ -12973,7 +13401,7 @@ function XViewScene({
|
|
|
12973
13401
|
}
|
|
12974
13402
|
}
|
|
12975
13403
|
),
|
|
12976
|
-
/* @__PURE__ */
|
|
13404
|
+
/* @__PURE__ */ React24.createElement(
|
|
12977
13405
|
ContextMenu,
|
|
12978
13406
|
{
|
|
12979
13407
|
data: contextMenu,
|
|
@@ -12996,7 +13424,7 @@ function XViewScene({
|
|
|
12996
13424
|
onFocusNode: handleFocusNode
|
|
12997
13425
|
}
|
|
12998
13426
|
),
|
|
12999
|
-
/* @__PURE__ */
|
|
13427
|
+
/* @__PURE__ */ React24.createElement(
|
|
13000
13428
|
MultiNodeContextMenu,
|
|
13001
13429
|
{
|
|
13002
13430
|
data: multiContextMenu,
|
|
@@ -13007,7 +13435,7 @@ function XViewScene({
|
|
|
13007
13435
|
onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
|
|
13008
13436
|
}
|
|
13009
13437
|
),
|
|
13010
|
-
/* @__PURE__ */
|
|
13438
|
+
/* @__PURE__ */ React24.createElement(
|
|
13011
13439
|
RelationshipContextMenu,
|
|
13012
13440
|
{
|
|
13013
13441
|
data: relationshipMenu,
|
|
@@ -13025,8 +13453,8 @@ function XViewScene({
|
|
|
13025
13453
|
onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
|
|
13026
13454
|
}
|
|
13027
13455
|
),
|
|
13028
|
-
/* @__PURE__ */
|
|
13029
|
-
/* @__PURE__ */
|
|
13456
|
+
/* @__PURE__ */ React24.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
|
|
13457
|
+
/* @__PURE__ */ React24.createElement(
|
|
13030
13458
|
AncestryBoard,
|
|
13031
13459
|
{
|
|
13032
13460
|
isOpen: isAncestryBoardOpen,
|
|
@@ -13039,7 +13467,7 @@ function XViewScene({
|
|
|
13039
13467
|
userRole: userPermissionRole
|
|
13040
13468
|
}
|
|
13041
13469
|
),
|
|
13042
|
-
/* @__PURE__ */
|
|
13470
|
+
/* @__PURE__ */ React24.createElement(
|
|
13043
13471
|
ImportParentFileModal,
|
|
13044
13472
|
{
|
|
13045
13473
|
isOpen: isImportModalOpen,
|
|
@@ -13083,6 +13511,12 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
|
|
|
13083
13511
|
}
|
|
13084
13512
|
const sceneData = sceneResponse.data;
|
|
13085
13513
|
const parentDbObjects = sceneData.parent_dbs || [];
|
|
13514
|
+
if (type && type.toLowerCase().includes("database")) {
|
|
13515
|
+
const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
|
|
13516
|
+
if (!selfExists) {
|
|
13517
|
+
parentDbObjects.push({ db_id: scene_config, owner_id });
|
|
13518
|
+
}
|
|
13519
|
+
}
|
|
13086
13520
|
const parentResponsesPromises = parentDbObjects.map(
|
|
13087
13521
|
(db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
|
|
13088
13522
|
);
|
|
@@ -13100,11 +13534,28 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
|
|
|
13100
13534
|
);
|
|
13101
13535
|
}
|
|
13102
13536
|
}
|
|
13537
|
+
if (type && type.toLowerCase() === "view") {
|
|
13538
|
+
parentData[scene_config] = {
|
|
13539
|
+
dataset_name: "Quests Internas (View)",
|
|
13540
|
+
nodes: sceneData.quest_nodes || [],
|
|
13541
|
+
links: sceneData.quest_links || []
|
|
13542
|
+
};
|
|
13543
|
+
}
|
|
13103
13544
|
const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
13104
13545
|
const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
|
|
13105
13546
|
const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
|
|
13106
13547
|
const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
|
|
13107
|
-
const validatedNodes = (sceneData.nodes || []).map((sceneNode) =>
|
|
13548
|
+
const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
|
|
13549
|
+
const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
|
|
13550
|
+
if (nodeTypes.includes("quest")) {
|
|
13551
|
+
return sceneNode;
|
|
13552
|
+
}
|
|
13553
|
+
const dbNode = parentNodeMap.get(String(sceneNode.id));
|
|
13554
|
+
if (dbNode) {
|
|
13555
|
+
return { ...dbNode, ...sceneNode };
|
|
13556
|
+
}
|
|
13557
|
+
return null;
|
|
13558
|
+
}).filter(Boolean);
|
|
13108
13559
|
const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
|
|
13109
13560
|
const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
|
|
13110
13561
|
const linkExistsInParent = parentLinkMap.has(`${sceneLink.source}-${sceneLink.target}`);
|