@lv-x-software-house/x_view 1.2.4-dev.8 → 1.2.4
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/README.md +1 -1
- package/dist/index.js +1234 -580
- package/dist/index.mjs +1180 -526
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/XViewScene.jsx
|
|
2
|
-
import
|
|
2
|
+
import React25, { useCallback as useCallback4, useEffect as useEffect22, useRef as useRef19, useState as useState25, 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";
|
|
@@ -72,6 +72,13 @@ function defineAbilityFor(role) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// src/components/ContextMenu.jsx
|
|
75
|
+
var QUEST_STATUS_COLORS = {
|
|
76
|
+
"Backlog": "#64748b",
|
|
77
|
+
"In Progress": "#eab308",
|
|
78
|
+
"Review": "#a855f7",
|
|
79
|
+
"Done": "#22c55e"
|
|
80
|
+
};
|
|
81
|
+
var QUEST_STATUSES = ["Backlog", "In Progress", "Review", "Done"];
|
|
75
82
|
function ContextMenu({
|
|
76
83
|
data,
|
|
77
84
|
userRole,
|
|
@@ -92,19 +99,21 @@ function ContextMenu({
|
|
|
92
99
|
onFocusNode,
|
|
93
100
|
onClose
|
|
94
101
|
}) {
|
|
95
|
-
var _a, _b;
|
|
102
|
+
var _a, _b, _c;
|
|
96
103
|
const menuRef = useRef(null);
|
|
97
104
|
const [menuPos, setMenuPos] = useState({ left: 0, top: 0 });
|
|
98
105
|
const [menuView, setMenuView] = useState("main");
|
|
99
106
|
const [selectedAncestry, setSelectedAncestry] = useState(null);
|
|
100
107
|
const [versionSubMenu, setVersionSubMenu] = useState(null);
|
|
101
108
|
const [isLinkCopied, setIsLinkCopied] = useState(false);
|
|
109
|
+
const [selectedQuestStatus, setSelectedQuestStatus] = useState(null);
|
|
102
110
|
const ability = useMemo(() => defineAbilityFor(userRole), [userRole]);
|
|
103
111
|
useEffect(() => {
|
|
104
112
|
if (data.visible) {
|
|
105
113
|
setMenuView("main");
|
|
106
114
|
setSelectedAncestry(null);
|
|
107
115
|
setVersionSubMenu(null);
|
|
116
|
+
setSelectedQuestStatus(null);
|
|
108
117
|
}
|
|
109
118
|
}, [data.visible, (_a = data.nodeData) == null ? void 0 : _a.id]);
|
|
110
119
|
useLayoutEffect(() => {
|
|
@@ -119,7 +128,7 @@ function ContextMenu({
|
|
|
119
128
|
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
120
129
|
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
121
130
|
setMenuPos({ left, top });
|
|
122
|
-
}, [data, menuView, versionSubMenu]);
|
|
131
|
+
}, [data, menuView, versionSubMenu, selectedQuestStatus]);
|
|
123
132
|
useEffect(() => {
|
|
124
133
|
if (!data.visible) return;
|
|
125
134
|
const handleClickOutside = (e) => {
|
|
@@ -162,7 +171,16 @@ function ContextMenu({
|
|
|
162
171
|
var _a2;
|
|
163
172
|
return c.targetNode && !(((_a2 = c.targetNode.version_node) == null ? void 0 : _a2.is_version) && String(c.targetNode.version_node.parent_node) === String(data.nodeData.id));
|
|
164
173
|
});
|
|
165
|
-
const
|
|
174
|
+
const isCurrentNodeQuest = ((_c = data.nodeData) == null ? void 0 : _c.is_quest) === true;
|
|
175
|
+
const commonConnections = isCurrentNodeQuest ? connections : connections.filter((c) => {
|
|
176
|
+
var _a2;
|
|
177
|
+
return !((_a2 = c.targetNode) == null ? void 0 : _a2.is_quest);
|
|
178
|
+
});
|
|
179
|
+
const questConnections = isCurrentNodeQuest ? [] : connections.filter((c) => {
|
|
180
|
+
var _a2;
|
|
181
|
+
return (_a2 = c.targetNode) == null ? void 0 : _a2.is_quest;
|
|
182
|
+
});
|
|
183
|
+
const groupedConnections = commonConnections.reduce((acc, conn) => {
|
|
166
184
|
var _a2;
|
|
167
185
|
const { targetNode } = conn;
|
|
168
186
|
const groupingKey = ((_a2 = targetNode.version_node) == null ? void 0 : _a2.is_version) ? targetNode.version_node.parent_node : targetNode.id;
|
|
@@ -198,6 +216,20 @@ function ContextMenu({
|
|
|
198
216
|
};
|
|
199
217
|
}
|
|
200
218
|
}).filter(Boolean);
|
|
219
|
+
const questsByStatus = {
|
|
220
|
+
"Backlog": [],
|
|
221
|
+
"In Progress": [],
|
|
222
|
+
"Review": [],
|
|
223
|
+
"Done": []
|
|
224
|
+
};
|
|
225
|
+
questConnections.forEach((conn) => {
|
|
226
|
+
const status = conn.targetNode.status || "Backlog";
|
|
227
|
+
if (questsByStatus[status]) {
|
|
228
|
+
questsByStatus[status].push(conn);
|
|
229
|
+
} else {
|
|
230
|
+
questsByStatus["Backlog"].push(conn);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
201
233
|
const availableAncestries = (ancestryData || []).filter(
|
|
202
234
|
(ancestry) => String(ancestry.ancestral_node) === String(data.nodeData.id)
|
|
203
235
|
);
|
|
@@ -250,11 +282,12 @@ function ContextMenu({
|
|
|
250
282
|
});
|
|
251
283
|
};
|
|
252
284
|
const renderMainView = () => {
|
|
285
|
+
var _a2;
|
|
253
286
|
const hasVersions = computedVersions.length > 0;
|
|
254
287
|
const canCreateVersion = ability.can("create", "Versioning");
|
|
255
288
|
const canReadVersion = ability.can("read", "Versioning");
|
|
256
289
|
const shouldShowVersioningBtn = canCreateVersion || canReadVersion && hasVersions;
|
|
257
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.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__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.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" })), /* @__PURE__ */ React.createElement("span", null, "Conectar")), ability.can("create", "Node") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ React.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ React.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ React.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ React.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ React.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ React.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ React.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
290
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.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__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.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" })), /* @__PURE__ */ React.createElement("span", null, "Conectar")), ability.can("create", "Node") && !((_a2 = data.nodeData) == null ? void 0 : _a2.is_quest) && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ React.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ React.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ React.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 20.5c.5-.5.8-1.2.8-2s-.3-1.5-.8-2c-.5-.5-1.2-.8-2-.8s-1.5.3-2 .8c-.5.5-.8 1.2-.8 2s.3 1.5.8 2c.5.5 1.2-.8 2 .8s1.5-.3 2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M14 3.5c.5.5.8 1.2.8 2s-.3 1.5-.8 2c-.5-.5-1.2-.8-2 .8s1.5.3-2-.8c-.5-.5-.8-1.2-.8-2s.3-1.5.8-2c.5.5 1.2-.8 2 .8s1.5.3 2 .8Z" }), /* @__PURE__ */ React.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ React.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ React.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2z" }), /* @__PURE__ */ React.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ React.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ React.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement("button", { onClick: () => {
|
|
258
291
|
onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
|
|
259
292
|
onClose();
|
|
260
293
|
}, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ React.createElement("span", null, "Focar neste Node")), /* @__PURE__ */ React.createElement("button", { onClick: (e) => handleCopyLink(e, data.nodeData), className: baseButtonClass, title: "Copiar Link para Compartilhar" }, isLinkCopied ? /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "#4ade80", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.72" }), /* @__PURE__ */ React.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" })), /* @__PURE__ */ React.createElement("span", { className: isLinkCopied ? "text-green-400" : "" }, isLinkCopied ? "Copiado!" : "Copiar Link")), ability.can("dismiss", "Node") && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React.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__ */ React.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__ */ React.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss")), /* @__PURE__ */ React.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("deleteConfirmation"), className: deleteButtonClass, title: "Excluir Node" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React.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__ */ React.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React.createElement("span", null, "Excluir Node"))));
|
|
@@ -279,9 +312,9 @@ function ContextMenu({
|
|
|
279
312
|
if (versionSubMenu) {
|
|
280
313
|
return renderVersionSubMenuView();
|
|
281
314
|
}
|
|
282
|
-
const totalItems = availableAncestries.length + finalRenderableConnections.length;
|
|
315
|
+
const totalItems = availableAncestries.length + finalRenderableConnections.length + (questConnections.length > 0 ? 1 : 0);
|
|
283
316
|
const isScrollable = totalItems > 10;
|
|
284
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")),
|
|
317
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), commonConnections.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(commonConnections.map((c) => c.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-2" : ""}` }, /* @__PURE__ */ React.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ React.createElement(
|
|
285
318
|
"button",
|
|
286
319
|
{
|
|
287
320
|
key: anc.ancestry_id,
|
|
@@ -291,7 +324,7 @@ function ContextMenu({
|
|
|
291
324
|
},
|
|
292
325
|
/* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M6 3v4a2 2 0 0 0 2 2h4" }), /* @__PURE__ */ React.createElement("path", { d: "M18 3v4a2 2 0 0 1-2 2h-4" }), /* @__PURE__ */ React.createElement("circle", { cx: "6", cy: "3", r: "2" }), /* @__PURE__ */ React.createElement("circle", { cx: "18", cy: "3", r: "2" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "11", r: "2" }), /* @__PURE__ */ React.createElement("path", { d: "M12 13v6" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "21", r: "2" })),
|
|
293
326
|
/* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, anc.name || `Ancestralidade #${anc.ancestry_id.substring(0, 8)}`)
|
|
294
|
-
)), finalRenderableConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "
|
|
327
|
+
))), finalRenderableConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, availableAncestries.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), finalRenderableConnections.map((group) => {
|
|
295
328
|
if (group.isVersionGroup) {
|
|
296
329
|
return /* @__PURE__ */ React.createElement(
|
|
297
330
|
"button",
|
|
@@ -319,7 +352,54 @@ function ContextMenu({
|
|
|
319
352
|
group.links.length > 1 && /* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-indigo-500/20 rounded-full" }, group.links.length)
|
|
320
353
|
);
|
|
321
354
|
}
|
|
322
|
-
}))))
|
|
355
|
+
})), questConnections.length > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1 mt-1" }, (availableAncestries.length > 0 || finalRenderableConnections.length > 0) && /* @__PURE__ */ React.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React.createElement(
|
|
356
|
+
"button",
|
|
357
|
+
{
|
|
358
|
+
onClick: () => setMenuView("quest_statuses"),
|
|
359
|
+
className: baseButtonClass,
|
|
360
|
+
title: "Ver Quests Conectadas"
|
|
361
|
+
},
|
|
362
|
+
/* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-sky-400" }, /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "6" }), /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "2" })),
|
|
363
|
+
/* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, "quests"),
|
|
364
|
+
/* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-sky-500/20 text-sky-200 rounded-full" }, questConnections.length)
|
|
365
|
+
))));
|
|
366
|
+
};
|
|
367
|
+
const renderQuestStatusesView = () => {
|
|
368
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Status das Quests"))), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, QUEST_STATUSES.map((status) => {
|
|
369
|
+
const count = questsByStatus[status].length;
|
|
370
|
+
const color = QUEST_STATUS_COLORS[status];
|
|
371
|
+
return /* @__PURE__ */ React.createElement(
|
|
372
|
+
"button",
|
|
373
|
+
{
|
|
374
|
+
key: status,
|
|
375
|
+
onClick: () => {
|
|
376
|
+
if (count > 0) {
|
|
377
|
+
setSelectedQuestStatus(status);
|
|
378
|
+
setMenuView("quest_list");
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
className: `${baseButtonClass} ${count === 0 ? "opacity-50 cursor-default hover:bg-transparent hover:text-slate-200" : ""}`
|
|
382
|
+
},
|
|
383
|
+
/* @__PURE__ */ React.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: color } }),
|
|
384
|
+
/* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, status),
|
|
385
|
+
count > 0 && /* @__PURE__ */ React.createElement("span", { className: "text-xs px-2 py-0.5 bg-white/10 rounded-full" }, count)
|
|
386
|
+
);
|
|
387
|
+
})));
|
|
388
|
+
};
|
|
389
|
+
const renderQuestListView = () => {
|
|
390
|
+
const quests = questsByStatus[selectedQuestStatus] || [];
|
|
391
|
+
const isScrollable = quests.length > 10;
|
|
392
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ React.createElement("button", { onClick: () => setMenuView("quest_statuses"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white flex-shrink-0" }, /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: `Quests: ${selectedQuestStatus}` }, "Quests: ", selectedQuestStatus)), quests.length > 0 && /* @__PURE__ */ React.createElement("button", { onClick: () => handleExpandAndClose(quests.map((q) => q.link)), className: "px-2 py-0.5 text-xs bg-indigo-500/50 hover:bg-indigo-500/80 rounded-md transition-colors" }, "Expandir Todas")), /* @__PURE__ */ React.createElement("div", { className: `flex flex-col gap-1 ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, quests.map((conn) => /* @__PURE__ */ React.createElement(
|
|
393
|
+
"button",
|
|
394
|
+
{
|
|
395
|
+
key: conn.targetNode.id,
|
|
396
|
+
onClick: () => handleConnectionClick({ links: [conn.link] }),
|
|
397
|
+
className: baseButtonClass,
|
|
398
|
+
title: `Expandir Quest ${conn.targetNode.name}`
|
|
399
|
+
},
|
|
400
|
+
/* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "opacity-70" }, /* @__PURE__ */ React.createElement("polyline", { points: "13 17 18 12 13 7" }), /* @__PURE__ */ React.createElement("polyline", { points: "6 17 11 12 6 7" })),
|
|
401
|
+
/* @__PURE__ */ React.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
|
|
402
|
+
))));
|
|
323
403
|
};
|
|
324
404
|
const renderAncestryActionsView = () => {
|
|
325
405
|
const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
|
|
@@ -382,7 +462,7 @@ function ContextMenu({
|
|
|
382
462
|
onDoubleClick: swallow
|
|
383
463
|
},
|
|
384
464
|
/* @__PURE__ */ React.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
385
|
-
/* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
|
|
465
|
+
/* @__PURE__ */ React.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "quest_statuses" && renderQuestStatusesView(), menuView === "quest_list" && renderQuestListView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
|
|
386
466
|
);
|
|
387
467
|
}
|
|
388
468
|
|
|
@@ -460,7 +540,11 @@ function XViewSidebar({
|
|
|
460
540
|
let pool = base;
|
|
461
541
|
const qNorm = normalize(query);
|
|
462
542
|
if (qNorm) {
|
|
463
|
-
pool = pool.filter((n) =>
|
|
543
|
+
pool = pool.filter((n) => {
|
|
544
|
+
const matchName = normalize((n == null ? void 0 : n.name) || "").includes(qNorm);
|
|
545
|
+
const matchRawTitle = n.is_quest && n.raw_title ? normalize(n.raw_title).includes(qNorm) : false;
|
|
546
|
+
return matchName || matchRawTitle;
|
|
547
|
+
});
|
|
464
548
|
}
|
|
465
549
|
if (activeFilters.length > 0) {
|
|
466
550
|
pool = pool.filter((node) => {
|
|
@@ -962,7 +1046,8 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
|
|
|
962
1046
|
const size = nodeData.size || "medium";
|
|
963
1047
|
const scale = NODE_SCALE_FACTORS[size] || 1;
|
|
964
1048
|
mesh.scale.set(scale, scale, scale);
|
|
965
|
-
const
|
|
1049
|
+
const labelText = nodeData.is_quest && nodeData.raw_title ? nodeData.raw_title : nodeData.name;
|
|
1050
|
+
const label = createTextSprite(labelText);
|
|
966
1051
|
label.name = "label";
|
|
967
1052
|
mesh.userData.labelObject = label;
|
|
968
1053
|
mesh.userData.labelOffset = new THREE.Vector3(0, 3.8, 0);
|
|
@@ -1067,13 +1152,15 @@ var updateExistingNodeVisuals = (state, updatedNode) => {
|
|
|
1067
1152
|
const size = updatedNode.size || "medium";
|
|
1068
1153
|
const scale = NODE_SCALE_FACTORS[size] || 1;
|
|
1069
1154
|
existingMesh.scale.set(scale, scale, scale);
|
|
1070
|
-
|
|
1155
|
+
const oldText = existingMesh.userData.is_quest && existingMesh.userData.raw_title ? existingMesh.userData.raw_title : existingMesh.userData.name;
|
|
1156
|
+
const newText = updatedNode.is_quest && updatedNode.raw_title ? updatedNode.raw_title : updatedNode.name;
|
|
1157
|
+
if (oldText !== newText) {
|
|
1071
1158
|
const oldLabelToDispose = existingMesh.userData.labelObject;
|
|
1072
1159
|
if (oldLabelToDispose && state.graphGroup) {
|
|
1073
1160
|
state.graphGroup.remove(oldLabelToDispose);
|
|
1074
1161
|
if (oldLabelToDispose.material) oldLabelToDispose.material.dispose();
|
|
1075
1162
|
}
|
|
1076
|
-
const newLabel = createTextSprite(
|
|
1163
|
+
const newLabel = createTextSprite(newText || "");
|
|
1077
1164
|
newLabel.name = "label";
|
|
1078
1165
|
existingMesh.userData.labelObject = newLabel;
|
|
1079
1166
|
if (state.graphGroup) {
|
|
@@ -1181,8 +1268,6 @@ var createMultipleLinkLines = (linksArray, sourceNodeMesh, targetNodeMesh, resol
|
|
|
1181
1268
|
targetNodeMesh,
|
|
1182
1269
|
resolution,
|
|
1183
1270
|
isCurved,
|
|
1184
|
-
isCurved,
|
|
1185
|
-
isCurved,
|
|
1186
1271
|
curveOffset
|
|
1187
1272
|
);
|
|
1188
1273
|
line.userData = {
|
|
@@ -1795,6 +1880,7 @@ var userActionHandlers = {
|
|
|
1795
1880
|
setters.setFormPosition((p) => ({ ...p, opacity: 0 }));
|
|
1796
1881
|
},
|
|
1797
1882
|
handleSaveVersionNode: async (context, newNodeData) => {
|
|
1883
|
+
var _a;
|
|
1798
1884
|
const { graphDataRef, sceneDataRef, stateRef, versionMode, setters } = context;
|
|
1799
1885
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
1800
1886
|
const { sourceNodeData } = versionMode;
|
|
@@ -1814,9 +1900,21 @@ var userActionHandlers = {
|
|
|
1814
1900
|
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
|
|
1815
1901
|
specificParentData.nodes.push(newNode);
|
|
1816
1902
|
specificParentData.links.push(newLink);
|
|
1817
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
1818
1903
|
try {
|
|
1819
|
-
|
|
1904
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
1905
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
1906
|
+
const viewFilePayload = {
|
|
1907
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
1908
|
+
nodes: sceneDataRef.current.nodes,
|
|
1909
|
+
links: sceneDataRef.current.links,
|
|
1910
|
+
quest_nodes: specificParentData.nodes,
|
|
1911
|
+
quest_links: specificParentData.links
|
|
1912
|
+
};
|
|
1913
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
1914
|
+
} else {
|
|
1915
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
1916
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
1917
|
+
}
|
|
1820
1918
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
1821
1919
|
const finalPosition = stateRef.current.ghostElements.node.position.clone();
|
|
1822
1920
|
addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
|
|
@@ -1840,10 +1938,6 @@ var userActionHandlers = {
|
|
|
1840
1938
|
var _a;
|
|
1841
1939
|
const isSource = String(link.source) === String(sourceNode.id);
|
|
1842
1940
|
const targetNodeId = isSource ? link.target : link.source;
|
|
1843
|
-
const linkAlreadyInSceneData = sceneDataRef.current.links.some((l) => String(l.id) === String(link.id));
|
|
1844
|
-
if (!linkAlreadyInSceneData) {
|
|
1845
|
-
sceneDataRef.current.links.push(link);
|
|
1846
|
-
}
|
|
1847
1941
|
if (!nodeObjects[String(targetNodeId)]) {
|
|
1848
1942
|
const allParentNodes = Object.values(graphDataRef.current).flatMap((fileData) => fileData.nodes);
|
|
1849
1943
|
const nodeData = allParentNodes.find((n) => String(n.id) === String(targetNodeId));
|
|
@@ -1851,9 +1945,6 @@ var userActionHandlers = {
|
|
|
1851
1945
|
console.warn(`Dados do Node com ID ${targetNodeId} n\xE3o encontrados no cache.`);
|
|
1852
1946
|
return;
|
|
1853
1947
|
}
|
|
1854
|
-
if (!sceneDataRef.current.nodes.some((n) => String(n.id) === String(nodeData.id))) {
|
|
1855
|
-
sceneDataRef.current.nodes.push(nodeData);
|
|
1856
|
-
}
|
|
1857
1948
|
const startPosition = sourceNodeMesh.position.clone();
|
|
1858
1949
|
const endPosition = startPosition.clone().add(
|
|
1859
1950
|
new THREE.Vector3((Math.random() - 0.5) * 60, (Math.random() - 0.5) * 15, (Math.random() - 0.5) * 60)
|
|
@@ -1973,6 +2064,7 @@ var userActionHandlers = {
|
|
|
1973
2064
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
1974
2065
|
},
|
|
1975
2066
|
handleCompleteConnection: async (context, targetNodeData) => {
|
|
2067
|
+
var _a;
|
|
1976
2068
|
const { stateRef, graphDataRef, sceneDataRef } = context;
|
|
1977
2069
|
const { sourceNodeData } = stateRef.current.connection;
|
|
1978
2070
|
if (!graphDataRef.current || !sceneDataRef.current || !sourceNodeData || !targetNodeData) {
|
|
@@ -1995,12 +2087,26 @@ var userActionHandlers = {
|
|
|
1995
2087
|
source: sourceNodeData.id,
|
|
1996
2088
|
target: targetNodeData.id
|
|
1997
2089
|
};
|
|
1998
|
-
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
1999
|
-
specificParentData.links.push(newLink);
|
|
2000
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
2001
2090
|
try {
|
|
2002
|
-
|
|
2003
|
-
|
|
2091
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2092
|
+
if (isView && parentFileIdToSave === context.sceneConfigId) {
|
|
2093
|
+
const specificParentData = graphDataRef.current[context.sceneConfigId];
|
|
2094
|
+
specificParentData.links.push(newLink);
|
|
2095
|
+
const viewFilePayload = {
|
|
2096
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2097
|
+
nodes: sceneDataRef.current.nodes,
|
|
2098
|
+
links: sceneDataRef.current.links,
|
|
2099
|
+
quest_nodes: specificParentData.nodes,
|
|
2100
|
+
quest_links: specificParentData.links
|
|
2101
|
+
};
|
|
2102
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2103
|
+
} else {
|
|
2104
|
+
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
2105
|
+
specificParentData.links.push(newLink);
|
|
2106
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
2107
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2108
|
+
graphDataRef.current[parentFileIdToSave] = specificParentData;
|
|
2109
|
+
}
|
|
2004
2110
|
addNewLinkToScene(stateRef.current, newLink);
|
|
2005
2111
|
} catch (error) {
|
|
2006
2112
|
console.error("Falha ao salvar a nova conex\xE3o:", error);
|
|
@@ -2069,14 +2175,28 @@ var userActionHandlers = {
|
|
|
2069
2175
|
} else {
|
|
2070
2176
|
newTargetId = newEndNodeData.id;
|
|
2071
2177
|
}
|
|
2072
|
-
const
|
|
2073
|
-
const
|
|
2074
|
-
|
|
2075
|
-
|
|
2178
|
+
const oldSourceInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldSourceId, context.sceneConfigId, context.ownerId);
|
|
2179
|
+
const oldTargetInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldTargetId, context.sceneConfigId, context.ownerId);
|
|
2180
|
+
const newSourceInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newSourceId, context.sceneConfigId, context.ownerId);
|
|
2181
|
+
const newTargetInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newTargetId, context.sceneConfigId, context.ownerId);
|
|
2182
|
+
if (!oldSourceInfo || !oldTargetInfo || !newSourceInfo || !newTargetInfo) {
|
|
2183
|
+
console.error("Informa\xE7\xF5es dos arquivos pai incompletas para o relink.");
|
|
2076
2184
|
alert("Ocorreu um erro ao identificar os arquivos pai para salvar a altera\xE7\xE3o.");
|
|
2077
2185
|
userActionHandlers.handleCancelRelink(context);
|
|
2078
2186
|
return;
|
|
2079
2187
|
}
|
|
2188
|
+
let oldGoverningFileId = oldSourceInfo.parentFileId;
|
|
2189
|
+
let oldGoverningOwnerId = oldSourceInfo.ownerId;
|
|
2190
|
+
if (oldSourceInfo.parentFileId === context.sceneConfigId || oldTargetInfo.parentFileId === context.sceneConfigId) {
|
|
2191
|
+
oldGoverningFileId = context.sceneConfigId;
|
|
2192
|
+
oldGoverningOwnerId = context.ownerId;
|
|
2193
|
+
}
|
|
2194
|
+
let newGoverningFileId = newSourceInfo.parentFileId;
|
|
2195
|
+
let newGoverningOwnerId = newSourceInfo.ownerId;
|
|
2196
|
+
if (newSourceInfo.parentFileId === context.sceneConfigId || newTargetInfo.parentFileId === context.sceneConfigId) {
|
|
2197
|
+
newGoverningFileId = context.sceneConfigId;
|
|
2198
|
+
newGoverningOwnerId = context.ownerId;
|
|
2199
|
+
}
|
|
2080
2200
|
const { sourceNode, targetNode, ...dataToKeep } = originalLinkData;
|
|
2081
2201
|
const newLinkData = {
|
|
2082
2202
|
...dataToKeep,
|
|
@@ -2084,34 +2204,44 @@ var userActionHandlers = {
|
|
|
2084
2204
|
target: newTargetId,
|
|
2085
2205
|
id: linkId
|
|
2086
2206
|
};
|
|
2207
|
+
const saveParentData = async (fileId, fileOwnerId, data) => {
|
|
2208
|
+
var _a;
|
|
2209
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2210
|
+
if (isView && fileId === context.sceneConfigId) {
|
|
2211
|
+
const viewFilePayload = {
|
|
2212
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2213
|
+
nodes: sceneDataRef.current.nodes,
|
|
2214
|
+
links: sceneDataRef.current.links,
|
|
2215
|
+
quest_nodes: data.nodes,
|
|
2216
|
+
quest_links: data.links
|
|
2217
|
+
};
|
|
2218
|
+
return context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2219
|
+
} else {
|
|
2220
|
+
return context.actions.save_view_data(`x_view_dbs/${fileOwnerId}/${fileId}`, data);
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2087
2223
|
const savePromises = [];
|
|
2088
2224
|
const filesToUpdate = {};
|
|
2089
|
-
if (
|
|
2090
|
-
const updatedOriginalParentData = JSON.parse(JSON.stringify(graphDataRef.current[
|
|
2225
|
+
if (oldGoverningFileId !== newGoverningFileId) {
|
|
2226
|
+
const updatedOriginalParentData = JSON.parse(JSON.stringify(graphDataRef.current[oldGoverningFileId]));
|
|
2091
2227
|
updatedOriginalParentData.links = updatedOriginalParentData.links.filter(
|
|
2092
2228
|
(l) => String(l.id) !== String(linkId)
|
|
2093
2229
|
);
|
|
2094
|
-
filesToUpdate[
|
|
2095
|
-
savePromises.push(
|
|
2096
|
-
|
|
2097
|
-
);
|
|
2098
|
-
const updatedNewParentData = JSON.parse(JSON.stringify(graphDataRef.current[newParentInfo.parentFileId]));
|
|
2230
|
+
filesToUpdate[oldGoverningFileId] = updatedOriginalParentData;
|
|
2231
|
+
savePromises.push(saveParentData(oldGoverningFileId, oldGoverningOwnerId, updatedOriginalParentData));
|
|
2232
|
+
const updatedNewParentData = JSON.parse(JSON.stringify(graphDataRef.current[newGoverningFileId]));
|
|
2099
2233
|
if (!updatedNewParentData.links) updatedNewParentData.links = [];
|
|
2100
2234
|
updatedNewParentData.links.push(newLinkData);
|
|
2101
|
-
filesToUpdate[
|
|
2102
|
-
savePromises.push(
|
|
2103
|
-
context.actions.save_view_data(`x_view_dbs/${newParentInfo.ownerId}/${newParentInfo.parentFileId}`, updatedNewParentData)
|
|
2104
|
-
);
|
|
2235
|
+
filesToUpdate[newGoverningFileId] = updatedNewParentData;
|
|
2236
|
+
savePromises.push(saveParentData(newGoverningFileId, newGoverningOwnerId, updatedNewParentData));
|
|
2105
2237
|
} else {
|
|
2106
|
-
const updatedParentData = JSON.parse(JSON.stringify(graphDataRef.current[
|
|
2238
|
+
const updatedParentData = JSON.parse(JSON.stringify(graphDataRef.current[oldGoverningFileId]));
|
|
2107
2239
|
updatedParentData.links = updatedParentData.links.filter(
|
|
2108
2240
|
(l) => String(l.id) !== String(linkId)
|
|
2109
2241
|
);
|
|
2110
2242
|
updatedParentData.links.push(newLinkData);
|
|
2111
|
-
filesToUpdate[
|
|
2112
|
-
savePromises.push(
|
|
2113
|
-
context.actions.save_view_data(`x_view_dbs/${originalParentInfo.ownerId}/${originalParentInfo.parentFileId}`, updatedParentData)
|
|
2114
|
-
);
|
|
2243
|
+
filesToUpdate[oldGoverningFileId] = updatedParentData;
|
|
2244
|
+
savePromises.push(saveParentData(oldGoverningFileId, oldGoverningOwnerId, updatedParentData));
|
|
2115
2245
|
}
|
|
2116
2246
|
try {
|
|
2117
2247
|
await Promise.all(savePromises);
|
|
@@ -2129,7 +2259,7 @@ var userActionHandlers = {
|
|
|
2129
2259
|
}
|
|
2130
2260
|
},
|
|
2131
2261
|
handleDeleteLink: async (context, linkObject) => {
|
|
2132
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2262
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2133
2263
|
const { stateRef, graphDataRef, sceneDataRef, setters } = context;
|
|
2134
2264
|
setters.setRelationshipMenu({ visible: false });
|
|
2135
2265
|
if (!(linkObject == null ? void 0 : linkObject.userData) || !graphDataRef.current || !sceneDataRef.current) return;
|
|
@@ -2152,7 +2282,8 @@ var userActionHandlers = {
|
|
|
2152
2282
|
specificParentData.links = newLinks;
|
|
2153
2283
|
let filenameToSave;
|
|
2154
2284
|
let payloadToSave;
|
|
2155
|
-
|
|
2285
|
+
const isView = ((_g = context.viewType) == null ? void 0 : _g.toLowerCase()) === "view";
|
|
2286
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2156
2287
|
filenameToSave = context.sceneSaveUrl;
|
|
2157
2288
|
sceneDataRef.current.links = sceneDataRef.current.links.filter((l) => String(l.id) !== String(linkIdToDelete));
|
|
2158
2289
|
payloadToSave = {
|
|
@@ -2185,12 +2316,6 @@ var userActionHandlers = {
|
|
|
2185
2316
|
if (!nodeData || !sceneDataRef.current) return;
|
|
2186
2317
|
const nodeIdToDismiss = nodeData.id;
|
|
2187
2318
|
const strNodeId = String(nodeIdToDismiss);
|
|
2188
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2189
|
-
(n) => String(n.id) !== strNodeId
|
|
2190
|
-
);
|
|
2191
|
-
sceneDataRef.current.links = sceneDataRef.current.links.filter(
|
|
2192
|
-
(l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId
|
|
2193
|
-
);
|
|
2194
2319
|
const { ancestryGroup, ancestryLinks } = stateRef.current;
|
|
2195
2320
|
if (ancestryGroup && ancestryLinks) {
|
|
2196
2321
|
const remainingAncestryLinks = [];
|
|
@@ -2232,22 +2357,12 @@ var userActionHandlers = {
|
|
|
2232
2357
|
removeNodeFromScene(stateRef.current, nodeId);
|
|
2233
2358
|
setters.setDetailsNode((prev) => String(prev == null ? void 0 : prev.id) === String(nodeId) ? null : prev);
|
|
2234
2359
|
});
|
|
2235
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2236
|
-
(n) => String(n.id) === strNodeIdToKeep
|
|
2237
|
-
);
|
|
2238
|
-
sceneDataRef.current.links = [];
|
|
2239
2360
|
},
|
|
2240
2361
|
handleDismissMultipleNodes: (context, nodeIds) => {
|
|
2241
2362
|
const { stateRef, sceneDataRef, setters } = context;
|
|
2242
2363
|
setters.setMultiContextMenu({ visible: false });
|
|
2243
2364
|
if (!nodeIds || nodeIds.size === 0 || !sceneDataRef.current) return;
|
|
2244
2365
|
const strNodeIds = Array.from(nodeIds).map(String);
|
|
2245
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2246
|
-
(n) => !strNodeIds.includes(String(n.id))
|
|
2247
|
-
);
|
|
2248
|
-
sceneDataRef.current.links = sceneDataRef.current.links.filter(
|
|
2249
|
-
(l) => !strNodeIds.includes(String(l.source)) && !strNodeIds.includes(String(l.target))
|
|
2250
|
-
);
|
|
2251
2366
|
const { ancestryGroup, ancestryLinks } = stateRef.current;
|
|
2252
2367
|
if (ancestryGroup && ancestryLinks) {
|
|
2253
2368
|
const remainingAncestryLinks = [];
|
|
@@ -2303,15 +2418,10 @@ var userActionHandlers = {
|
|
|
2303
2418
|
removeNodeFromScene(stateRef.current, nodeId);
|
|
2304
2419
|
setters.setDetailsNode((prev) => String(prev == null ? void 0 : prev.id) === String(nodeId) ? null : prev);
|
|
2305
2420
|
});
|
|
2306
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2307
|
-
(n) => strNodeIdsToKeep.includes(String(n.id))
|
|
2308
|
-
);
|
|
2309
|
-
sceneDataRef.current.links = sceneDataRef.current.links.filter(
|
|
2310
|
-
(l) => strNodeIdsToKeep.includes(String(l.source)) && strNodeIdsToKeep.includes(String(l.target))
|
|
2311
|
-
);
|
|
2312
2421
|
stateRef.current.selectedNodes.clear();
|
|
2313
2422
|
},
|
|
2314
2423
|
handleDeleteMultipleNodes: async (context, nodeIds) => {
|
|
2424
|
+
var _a;
|
|
2315
2425
|
const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
|
|
2316
2426
|
setters.setMultiContextMenu({ visible: false });
|
|
2317
2427
|
if (!nodeIds || nodeIds.size === 0 || !graphDataRef.current || !sceneDataRef.current) return;
|
|
@@ -2366,7 +2476,8 @@ var userActionHandlers = {
|
|
|
2366
2476
|
);
|
|
2367
2477
|
let filenameToSave;
|
|
2368
2478
|
let payloadToSave;
|
|
2369
|
-
|
|
2479
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2480
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2370
2481
|
filenameToSave = context.sceneSaveUrl;
|
|
2371
2482
|
const strNodesToDelete = Array.from(nodesToDelete).map(String);
|
|
2372
2483
|
const strLinksToDelete = Array.from(linksToDelete).map(String);
|
|
@@ -2404,6 +2515,7 @@ var userActionHandlers = {
|
|
|
2404
2515
|
}
|
|
2405
2516
|
},
|
|
2406
2517
|
handleDeleteNode: async (context, nodeData) => {
|
|
2518
|
+
var _a;
|
|
2407
2519
|
const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
|
|
2408
2520
|
if (actions.delete_file && nodeData) {
|
|
2409
2521
|
const urls = extractFileUrlsFromProperties(nodeData);
|
|
@@ -2429,7 +2541,8 @@ var userActionHandlers = {
|
|
|
2429
2541
|
specificParentData.links = newLinks;
|
|
2430
2542
|
let filenameToSave;
|
|
2431
2543
|
let payloadToSave;
|
|
2432
|
-
|
|
2544
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2545
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2433
2546
|
filenameToSave = context.sceneSaveUrl;
|
|
2434
2547
|
const newVisualNodes = sceneDataRef.current.nodes.filter((n) => String(n.id) !== strNodeId);
|
|
2435
2548
|
const newVisualLinks = sceneDataRef.current.links.filter((l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId);
|
|
@@ -2458,6 +2571,7 @@ var userActionHandlers = {
|
|
|
2458
2571
|
}
|
|
2459
2572
|
},
|
|
2460
2573
|
handleSaveNodeDetails: async (context, updatedNode, keepOpen = false) => {
|
|
2574
|
+
var _a;
|
|
2461
2575
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2462
2576
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2463
2577
|
const { _baseEmissiveIntensity: ignored, ...nodeToSave } = updatedNode;
|
|
@@ -2477,9 +2591,28 @@ var userActionHandlers = {
|
|
|
2477
2591
|
alert("Erro interno: Node n\xE3o encontrado para salvar.");
|
|
2478
2592
|
return;
|
|
2479
2593
|
}
|
|
2480
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2481
2594
|
try {
|
|
2482
|
-
|
|
2595
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2596
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2597
|
+
const visualNodeIndex = sceneDataRef.current.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2598
|
+
if (visualNodeIndex > -1) {
|
|
2599
|
+
sceneDataRef.current.nodes[visualNodeIndex] = {
|
|
2600
|
+
...sceneDataRef.current.nodes[visualNodeIndex],
|
|
2601
|
+
...nodeToSave
|
|
2602
|
+
};
|
|
2603
|
+
}
|
|
2604
|
+
const viewFilePayload = {
|
|
2605
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2606
|
+
nodes: sceneDataRef.current.nodes,
|
|
2607
|
+
links: sceneDataRef.current.links,
|
|
2608
|
+
quest_nodes: specificParentData.nodes,
|
|
2609
|
+
quest_links: specificParentData.links
|
|
2610
|
+
};
|
|
2611
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2612
|
+
} else {
|
|
2613
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2614
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2615
|
+
}
|
|
2483
2616
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2484
2617
|
updateExistingNodeVisuals(stateRef.current, nodeToSave);
|
|
2485
2618
|
setters.setSceneVersion((v) => v + 1);
|
|
@@ -2492,6 +2625,7 @@ var userActionHandlers = {
|
|
|
2492
2625
|
}
|
|
2493
2626
|
},
|
|
2494
2627
|
handleSaveLinkDetails: async (context, updatedLink, keepOpen = false) => {
|
|
2628
|
+
var _a;
|
|
2495
2629
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2496
2630
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2497
2631
|
const { sourceNode, targetNode, ...linkToSave } = updatedLink;
|
|
@@ -2511,9 +2645,21 @@ var userActionHandlers = {
|
|
|
2511
2645
|
alert("Erro interno: link n\xE3o encontrado para salvar.");
|
|
2512
2646
|
return;
|
|
2513
2647
|
}
|
|
2514
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2515
2648
|
try {
|
|
2516
|
-
|
|
2649
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2650
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2651
|
+
const viewFilePayload = {
|
|
2652
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2653
|
+
nodes: sceneDataRef.current.nodes,
|
|
2654
|
+
links: sceneDataRef.current.links,
|
|
2655
|
+
quest_nodes: specificParentData.nodes,
|
|
2656
|
+
quest_links: specificParentData.links
|
|
2657
|
+
};
|
|
2658
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2659
|
+
} else {
|
|
2660
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2661
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2662
|
+
}
|
|
2517
2663
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2518
2664
|
const lineObject = stateRef.current.allLinks.find(
|
|
2519
2665
|
(l) => String(l.userData.id) === String(linkToSave.id)
|
|
@@ -2536,7 +2682,7 @@ var userActionHandlers = {
|
|
|
2536
2682
|
}
|
|
2537
2683
|
},
|
|
2538
2684
|
handleAddExistingNodeById: (context, nodeId) => {
|
|
2539
|
-
var _a
|
|
2685
|
+
var _a;
|
|
2540
2686
|
const { stateRef, sceneDataRef, graphDataRef, tweenToTarget, setters } = context;
|
|
2541
2687
|
const state = stateRef.current;
|
|
2542
2688
|
const graphFull = graphDataRef.current;
|
|
@@ -2552,16 +2698,12 @@ var userActionHandlers = {
|
|
|
2552
2698
|
tweenToTarget(state.nodeObjects[strNodeId]);
|
|
2553
2699
|
return;
|
|
2554
2700
|
}
|
|
2555
|
-
const alreadyInSceneData = (((_a = sceneDataRef.current) == null ? void 0 : _a.nodes) || []).some((n) => String(n.id) === String(strNodeId));
|
|
2556
|
-
if (!alreadyInSceneData) {
|
|
2557
|
-
sceneDataRef.current.nodes.push(nodeData);
|
|
2558
|
-
}
|
|
2559
2701
|
const base = state.controls ? state.controls.target.clone() : new THREE.Vector3(0, 0, 0);
|
|
2560
2702
|
const offset = new THREE.Vector3((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 6, (Math.random() - 0.5) * 20);
|
|
2561
2703
|
const position = base.add(offset);
|
|
2562
2704
|
addStandaloneNodeToScene(state, nodeData, position);
|
|
2563
2705
|
tweenToTarget(position, 1.3);
|
|
2564
|
-
(
|
|
2706
|
+
(_a = setters == null ? void 0 : setters.setSceneVersion) == null ? void 0 : _a.call(setters, (v) => v + 1);
|
|
2565
2707
|
}
|
|
2566
2708
|
};
|
|
2567
2709
|
|
|
@@ -2800,7 +2942,10 @@ var IGNORED_KEYS = [
|
|
|
2800
2942
|
"is_private",
|
|
2801
2943
|
"abstraction_tree",
|
|
2802
2944
|
"selectedAbstractionParentId",
|
|
2803
|
-
"isAddingAbstractionNodes"
|
|
2945
|
+
"isAddingAbstractionNodes",
|
|
2946
|
+
"status",
|
|
2947
|
+
"is_quest",
|
|
2948
|
+
"raw_title"
|
|
2804
2949
|
];
|
|
2805
2950
|
function extractCustomPropsFromNode(node) {
|
|
2806
2951
|
const customPropTypes = node._customPropTypes || {};
|
|
@@ -7890,16 +8035,12 @@ function InSceneVersionForm({
|
|
|
7890
8035
|
|
|
7891
8036
|
// src/components/InSceneQuestForm.jsx
|
|
7892
8037
|
import React15, { useState as useState16, useRef as useRef12 } from "react";
|
|
7893
|
-
import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4 } from "react-icons/fi";
|
|
7894
|
-
var
|
|
8038
|
+
import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4, FiChevronDown as FiChevronDown5 } from "react-icons/fi";
|
|
8039
|
+
var QUEST_STATUS_COLORS2 = {
|
|
7895
8040
|
"Backlog": "#64748b",
|
|
7896
|
-
// Slate (Cinza azulado)
|
|
7897
8041
|
"In Progress": "#eab308",
|
|
7898
|
-
// Yellow (Amarelo)
|
|
7899
8042
|
"Review": "#a855f7",
|
|
7900
|
-
// Purple (Roxo)
|
|
7901
8043
|
"Done": "#22c55e"
|
|
7902
|
-
// Green (Verde)
|
|
7903
8044
|
};
|
|
7904
8045
|
function InSceneQuestForm({
|
|
7905
8046
|
onSave,
|
|
@@ -7910,7 +8051,14 @@ function InSceneQuestForm({
|
|
|
7910
8051
|
availableNodes = [],
|
|
7911
8052
|
availableAncestries = [],
|
|
7912
8053
|
onMentionClick,
|
|
7913
|
-
onUploadFile
|
|
8054
|
+
onUploadFile,
|
|
8055
|
+
onNameChange,
|
|
8056
|
+
onColorChange,
|
|
8057
|
+
onSizeChange,
|
|
8058
|
+
viewName = "Projeto",
|
|
8059
|
+
// NOVA PROP
|
|
8060
|
+
questCounter = 1
|
|
8061
|
+
// NOVA PROP
|
|
7914
8062
|
}) {
|
|
7915
8063
|
const [name, setName] = useState16("");
|
|
7916
8064
|
const [types, setTypes] = useState16(["quest"]);
|
|
@@ -7919,9 +8067,11 @@ function InSceneQuestForm({
|
|
|
7919
8067
|
const [size, setSize] = useState16("medium");
|
|
7920
8068
|
const [intensity, setIntensity] = useState16(0);
|
|
7921
8069
|
const [description, setDescription] = useState16("");
|
|
8070
|
+
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState16(false);
|
|
7922
8071
|
const [customProps, setCustomProps] = useState16([]);
|
|
7923
8072
|
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
|
|
7924
8073
|
const propsEndRef = useRef12(null);
|
|
8074
|
+
const standardizedName = `${viewName} - ${questCounter} - \xBB ${name || "Nova Quest"}`;
|
|
7925
8075
|
const handleAddProp = () => {
|
|
7926
8076
|
const newProp = createNewCustomProperty(customProps);
|
|
7927
8077
|
setCustomProps([...customProps, newProp]);
|
|
@@ -7958,7 +8108,7 @@ function InSceneQuestForm({
|
|
|
7958
8108
|
const handleSubmit = (e) => {
|
|
7959
8109
|
e.preventDefault();
|
|
7960
8110
|
if (!name.trim()) {
|
|
7961
|
-
alert("O campo '
|
|
8111
|
+
alert("O campo 'T\xEDtulo' \xE9 obrigat\xF3rio.");
|
|
7962
8112
|
return;
|
|
7963
8113
|
}
|
|
7964
8114
|
const additionalData = toObjectFromCustomProps(
|
|
@@ -7966,10 +8116,12 @@ function InSceneQuestForm({
|
|
|
7966
8116
|
);
|
|
7967
8117
|
const processedSections = processDescriptionForSave(description, []);
|
|
7968
8118
|
onSave({
|
|
7969
|
-
name:
|
|
8119
|
+
name: standardizedName,
|
|
8120
|
+
// SALVA O NOME FORMATADO
|
|
8121
|
+
raw_title: name.trim(),
|
|
8122
|
+
// Salva o título puro como fallback ou metadado útil
|
|
7970
8123
|
type: types,
|
|
7971
|
-
color:
|
|
7972
|
-
// Cor atrelada ao status
|
|
8124
|
+
color: QUEST_STATUS_COLORS2[status],
|
|
7973
8125
|
status,
|
|
7974
8126
|
size,
|
|
7975
8127
|
intensity,
|
|
@@ -7995,21 +8147,54 @@ function InSceneQuestForm({
|
|
|
7995
8147
|
onContextMenu: swallow,
|
|
7996
8148
|
onDoubleClick: swallow
|
|
7997
8149
|
},
|
|
7998
|
-
/* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${
|
|
7999
|
-
/* @__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
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8150
|
+
/* @__PURE__ */ React15.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS2[status]}, transparent)` } }),
|
|
8151
|
+
/* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement(FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova quest")), /* @__PURE__ */ React15.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")), /* @__PURE__ */ React15.createElement(
|
|
8152
|
+
"button",
|
|
8153
|
+
{
|
|
8154
|
+
type: "button",
|
|
8155
|
+
onClick: onCancel,
|
|
8156
|
+
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",
|
|
8157
|
+
title: "Fechar"
|
|
8158
|
+
},
|
|
8159
|
+
"\xD7"
|
|
8160
|
+
)),
|
|
8161
|
+
/* @__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" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ React15.createElement(
|
|
8162
|
+
"input",
|
|
8163
|
+
{
|
|
8164
|
+
required: true,
|
|
8165
|
+
type: "text",
|
|
8166
|
+
placeholder: "Ex.: Refatorar M\xF3dulo X",
|
|
8167
|
+
value: name,
|
|
8168
|
+
onChange: (e) => {
|
|
8169
|
+
const val = e.target.value;
|
|
8170
|
+
setName(val);
|
|
8171
|
+
onNameChange == null ? void 0 : onNameChange(val || "Nova Quest");
|
|
8172
|
+
},
|
|
8173
|
+
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"
|
|
8174
|
+
}
|
|
8175
|
+
), /* @__PURE__ */ React15.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ React15.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React15.createElement("div", { className: "relative" }, /* @__PURE__ */ React15.createElement(
|
|
8176
|
+
"button",
|
|
8177
|
+
{
|
|
8178
|
+
type: "button",
|
|
8179
|
+
onClick: () => setIsStatusDropdownOpen(!isStatusDropdownOpen),
|
|
8180
|
+
className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
|
|
8181
|
+
},
|
|
8182
|
+
/* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS2[status] } }), /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, status)),
|
|
8183
|
+
/* @__PURE__ */ React15.createElement(FiChevronDown5, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
|
|
8184
|
+
), isStatusDropdownOpen && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React15.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS2).map((s) => /* @__PURE__ */ React15.createElement(
|
|
8185
|
+
"li",
|
|
8186
|
+
{
|
|
8187
|
+
key: s,
|
|
8188
|
+
onClick: () => {
|
|
8189
|
+
setStatus(s);
|
|
8190
|
+
setIsStatusDropdownOpen(false);
|
|
8191
|
+
onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS2[s]);
|
|
8192
|
+
},
|
|
8193
|
+
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
8007
8194
|
},
|
|
8008
|
-
/* @__PURE__ */ React15.createElement("
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
/* @__PURE__ */ React15.createElement("option", { value: "Done" }, "Done")
|
|
8012
|
-
)), /* @__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(
|
|
8195
|
+
/* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
|
|
8196
|
+
s
|
|
8197
|
+
)))))), /* @__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(
|
|
8013
8198
|
"input",
|
|
8014
8199
|
{
|
|
8015
8200
|
type: "text",
|
|
@@ -8032,7 +8217,20 @@ function InSceneQuestForm({
|
|
|
8032
8217
|
onMentionClick,
|
|
8033
8218
|
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
8034
8219
|
}
|
|
8035
|
-
), /* @__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
|
|
8220
|
+
), /* @__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 Node (Size)"), /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ React15.createElement(
|
|
8221
|
+
"button",
|
|
8222
|
+
{
|
|
8223
|
+
key: s,
|
|
8224
|
+
type: "button",
|
|
8225
|
+
onClick: () => {
|
|
8226
|
+
setSize(s);
|
|
8227
|
+
onSizeChange == null ? void 0 : onSizeChange(s);
|
|
8228
|
+
},
|
|
8229
|
+
className: "flex items-center gap-2 group cursor-pointer focus:outline-none"
|
|
8230
|
+
},
|
|
8231
|
+
/* @__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" })),
|
|
8232
|
+
/* @__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)
|
|
8233
|
+
)))), /* @__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(
|
|
8036
8234
|
CustomPropertyDisplay,
|
|
8037
8235
|
{
|
|
8038
8236
|
key: prop.id,
|
|
@@ -8547,136 +8745,475 @@ function NodeDetailsPanel({
|
|
|
8547
8745
|
));
|
|
8548
8746
|
}
|
|
8549
8747
|
|
|
8550
|
-
// src/components/
|
|
8551
|
-
import React17, {
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
const [menuPos, setMenuPos] = useState18({ left: 0, top: 0 });
|
|
8562
|
-
const [isConfirmingDelete, setIsConfirmingDelete] = useState18(false);
|
|
8563
|
-
const ability = defineAbilityFor(userRole);
|
|
8564
|
-
const canDelete = ability.can("delete", "Node");
|
|
8565
|
-
useLayoutEffect3(() => {
|
|
8566
|
-
if (!data.visible || !menuRef.current) return;
|
|
8567
|
-
const el = menuRef.current;
|
|
8568
|
-
const w = el.clientWidth;
|
|
8569
|
-
const h = el.clientHeight;
|
|
8570
|
-
const vw = window.innerWidth;
|
|
8571
|
-
const vh = window.innerHeight;
|
|
8572
|
-
let left = data.x + 8;
|
|
8573
|
-
let top = data.y + 8;
|
|
8574
|
-
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
8575
|
-
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
8576
|
-
setMenuPos({ left, top });
|
|
8577
|
-
}, [data]);
|
|
8578
|
-
useEffect16(() => {
|
|
8579
|
-
if (data.visible) {
|
|
8580
|
-
setIsConfirmingDelete(false);
|
|
8581
|
-
}
|
|
8582
|
-
const handleClickOutside = (e) => {
|
|
8583
|
-
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
8584
|
-
};
|
|
8585
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
8586
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
8587
|
-
}, [data.visible, onClose]);
|
|
8588
|
-
if (!data.visible || !data.nodeIds || data.nodeIds.size === 0) return null;
|
|
8589
|
-
const swallow = (e) => e.stopPropagation();
|
|
8590
|
-
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";
|
|
8591
|
-
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";
|
|
8592
|
-
const nodeCount = data.nodeIds.size;
|
|
8593
|
-
return /* @__PURE__ */ React17.createElement(
|
|
8594
|
-
"div",
|
|
8595
|
-
{
|
|
8596
|
-
ref: menuRef,
|
|
8597
|
-
className: "ui-overlay context-menu-class origin-top-left rounded-xl 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,250px)] overflow-hidden",
|
|
8598
|
-
style: { position: "absolute", left: `${menuPos.left}px`, top: `${menuPos.top}px`, zIndex: 1e3 },
|
|
8599
|
-
onPointerDown: swallow,
|
|
8600
|
-
onPointerMove: swallow,
|
|
8601
|
-
onPointerUp: swallow,
|
|
8602
|
-
onClick: swallow,
|
|
8603
|
-
onWheel: swallow,
|
|
8604
|
-
onContextMenu: swallow,
|
|
8605
|
-
onDoubleClick: swallow
|
|
8606
|
-
},
|
|
8607
|
-
/* @__PURE__ */ React17.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
8608
|
-
/* @__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(
|
|
8609
|
-
"button",
|
|
8610
|
-
{
|
|
8611
|
-
onClick: () => setIsConfirmingDelete(false),
|
|
8612
|
-
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8613
|
-
},
|
|
8614
|
-
"Cancelar"
|
|
8615
|
-
), /* @__PURE__ */ React17.createElement(
|
|
8616
|
-
"button",
|
|
8617
|
-
{
|
|
8618
|
-
onClick: () => onDeleteNodes(data.nodeIds),
|
|
8619
|
-
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
8620
|
-
},
|
|
8621
|
-
"Excluir"
|
|
8622
|
-
))) : /* @__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, ")"))))))
|
|
8623
|
-
);
|
|
8624
|
-
}
|
|
8625
|
-
|
|
8626
|
-
// src/components/RelationshipDetailsPanel.jsx
|
|
8627
|
-
import React18, { useState as useState19, useEffect as useEffect17, useRef as useRef15, useMemo as useMemo9 } from "react";
|
|
8628
|
-
import { FiPlus as FiPlus7, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4 } from "react-icons/fi";
|
|
8629
|
-
function RelationshipDetailsPanel({
|
|
8630
|
-
link,
|
|
8748
|
+
// src/components/QuestDetailsPanel.jsx
|
|
8749
|
+
import React17, { useState as useState18, useEffect as useEffect16, useRef as useRef14 } from "react";
|
|
8750
|
+
import { FiPlus as FiPlus7, FiX as FiX6, FiCheck as FiCheck11, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4, FiLink as FiLink6, FiTarget as FiTarget2, FiChevronDown as FiChevronDown6 } from "react-icons/fi";
|
|
8751
|
+
var QUEST_STATUS_COLORS3 = {
|
|
8752
|
+
"Backlog": "#64748b",
|
|
8753
|
+
"In Progress": "#eab308",
|
|
8754
|
+
"Review": "#a855f7",
|
|
8755
|
+
"Done": "#22c55e"
|
|
8756
|
+
};
|
|
8757
|
+
function QuestDetailsPanel({
|
|
8758
|
+
node,
|
|
8631
8759
|
onClose,
|
|
8632
8760
|
onSave,
|
|
8761
|
+
onNameChange,
|
|
8762
|
+
onColorChange,
|
|
8763
|
+
onSizeChange,
|
|
8633
8764
|
onDataUpdate,
|
|
8634
8765
|
onOpenImageViewer,
|
|
8766
|
+
existingTypes = [],
|
|
8635
8767
|
availableNodes = [],
|
|
8636
8768
|
availableAncestries = [],
|
|
8637
8769
|
onOpenReference,
|
|
8638
8770
|
onMentionClick,
|
|
8639
8771
|
onUploadFile,
|
|
8640
|
-
userRole
|
|
8772
|
+
userRole,
|
|
8773
|
+
currentDatasetName
|
|
8641
8774
|
}) {
|
|
8642
|
-
|
|
8643
|
-
const
|
|
8644
|
-
const [
|
|
8645
|
-
const
|
|
8646
|
-
const [
|
|
8647
|
-
const
|
|
8648
|
-
const [
|
|
8649
|
-
const
|
|
8650
|
-
const
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
const
|
|
8661
|
-
const
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8775
|
+
var _a;
|
|
8776
|
+
const initialRawTitle = (node == null ? void 0 : node.raw_title) || (((_a = node == null ? void 0 : node.name) == null ? void 0 : _a.includes(" - \xBB ")) ? node.name.split(" - \xBB ")[1] : node == null ? void 0 : node.name) || "";
|
|
8777
|
+
const [rawTitle, setRawTitle] = useState18(initialRawTitle);
|
|
8778
|
+
const prefixParts = ((node == null ? void 0 : node.name) || "").split(" - \xBB ");
|
|
8779
|
+
const questPrefix = prefixParts.length > 1 ? prefixParts[0] : "";
|
|
8780
|
+
const standardizedName = questPrefix ? `${questPrefix} - \xBB ${rawTitle || "Sem t\xEDtulo"}` : rawTitle;
|
|
8781
|
+
const [types, setTypes] = useState18((node == null ? void 0 : node.type) ? Array.isArray(node.type) ? node.type : [node.type] : ["quest"]);
|
|
8782
|
+
const [typeInput, setTypeInput] = useState18("");
|
|
8783
|
+
const [status, setStatus] = useState18((node == null ? void 0 : node.status) ?? "Backlog");
|
|
8784
|
+
const [size, setSize] = useState18((node == null ? void 0 : node.size) ?? "medium");
|
|
8785
|
+
const [description, setDescription] = useState18((node == null ? void 0 : node.description) ?? "");
|
|
8786
|
+
const [intensity, setIntensity] = useState18((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8787
|
+
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState18(false);
|
|
8788
|
+
const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(node || {}));
|
|
8789
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = useState18(false);
|
|
8790
|
+
const [filteredTypes, setFilteredTypes] = useState18([]);
|
|
8791
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState18(false);
|
|
8792
|
+
const [isReadMode, setIsReadMode] = useState18(false);
|
|
8793
|
+
const [existingSections, setExistingSections] = useState18((node == null ? void 0 : node.description_sections) || []);
|
|
8794
|
+
const [isSaving, setIsSaving] = useState18(false);
|
|
8795
|
+
const [isLinkCopied, setIsLinkCopied] = useState18(false);
|
|
8796
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
8797
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
8798
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
8799
|
+
minWidth: 320,
|
|
8800
|
+
maxWidth: maxPanelW
|
|
8801
|
+
});
|
|
8802
|
+
useEffect16(() => {
|
|
8803
|
+
setWidth(isReadMode ? 700 : 440);
|
|
8804
|
+
}, [isReadMode, setWidth]);
|
|
8805
|
+
const prevNodeIdRef = useRef14(null);
|
|
8806
|
+
const propsEndRef = useRef14(null);
|
|
8807
|
+
const canEdit = userRole !== "viewer";
|
|
8808
|
+
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
8809
|
+
const handleImageClickFromText = (url, name) => {
|
|
8810
|
+
if (onOpenImageViewer) {
|
|
8811
|
+
onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
|
|
8812
|
+
}
|
|
8813
|
+
};
|
|
8814
|
+
useEffect16(() => {
|
|
8815
|
+
var _a2;
|
|
8816
|
+
if ((node == null ? void 0 : node.id) !== prevNodeIdRef.current) {
|
|
8817
|
+
prevNodeIdRef.current = node == null ? void 0 : node.id;
|
|
8818
|
+
const newRawTitle = (node == null ? void 0 : node.raw_title) || (((_a2 = node == null ? void 0 : node.name) == null ? void 0 : _a2.includes(" - \xBB ")) ? node.name.split(" - \xBB ")[1] : node == null ? void 0 : node.name) || "";
|
|
8819
|
+
setRawTitle(newRawTitle);
|
|
8820
|
+
setTypes((node == null ? void 0 : node.type) ? Array.isArray(node.type) ? node.type : [node.type] : ["quest"]);
|
|
8821
|
+
setStatus((node == null ? void 0 : node.status) ?? "Backlog");
|
|
8822
|
+
setSize((node == null ? void 0 : node.size) ?? "medium");
|
|
8823
|
+
setDescription((node == null ? void 0 : node.description) ?? "");
|
|
8824
|
+
setIntensity((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8825
|
+
setExistingSections((node == null ? void 0 : node.description_sections) || []);
|
|
8826
|
+
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
8827
|
+
}
|
|
8828
|
+
}, [node]);
|
|
8829
|
+
useEffect16(() => {
|
|
8830
|
+
if (typeInput.trim() === "") {
|
|
8831
|
+
setFilteredTypes(existingTypes.filter((t) => !types.includes(t)));
|
|
8832
|
+
} else {
|
|
8833
|
+
const lowercasedInput = typeInput.toLowerCase();
|
|
8834
|
+
setFilteredTypes(
|
|
8835
|
+
existingTypes.filter(
|
|
8836
|
+
(t) => t.toLowerCase().includes(lowercasedInput) && !types.includes(t)
|
|
8837
|
+
)
|
|
8838
|
+
);
|
|
8839
|
+
}
|
|
8840
|
+
}, [typeInput, existingTypes, types]);
|
|
8841
|
+
const handleCopyLink = () => {
|
|
8842
|
+
if (!(node == null ? void 0 : node.id)) return;
|
|
8843
|
+
const baseUrl = window.location.origin + window.location.pathname;
|
|
8844
|
+
const fullUrl = `${baseUrl}?focus=${node.id}`;
|
|
8845
|
+
navigator.clipboard.writeText(fullUrl).then(() => {
|
|
8846
|
+
setIsLinkCopied(true);
|
|
8847
|
+
setTimeout(() => setIsLinkCopied(false), 2e3);
|
|
8848
|
+
}).catch((err) => {
|
|
8849
|
+
console.error("Erro ao copiar link:", err);
|
|
8850
|
+
});
|
|
8851
|
+
};
|
|
8852
|
+
const swallow = (e) => e.stopPropagation();
|
|
8853
|
+
const handleNameChange = (e) => {
|
|
8854
|
+
const val = e.target.value;
|
|
8855
|
+
setRawTitle(val);
|
|
8856
|
+
const newStandardName = questPrefix ? `${questPrefix} - \xBB ${val || "Sem t\xEDtulo"}` : val;
|
|
8857
|
+
onNameChange == null ? void 0 : onNameChange(node.id, newStandardName, val);
|
|
8858
|
+
};
|
|
8859
|
+
const handleSizeChange = (newSize) => {
|
|
8860
|
+
setSize(newSize);
|
|
8861
|
+
onSizeChange == null ? void 0 : onSizeChange(node.id, newSize);
|
|
8862
|
+
};
|
|
8863
|
+
const handleStatusChange = (newStatus) => {
|
|
8864
|
+
setStatus(newStatus);
|
|
8865
|
+
const newColor = QUEST_STATUS_COLORS3[newStatus];
|
|
8866
|
+
onColorChange == null ? void 0 : onColorChange(node.id, newColor);
|
|
8867
|
+
onDataUpdate == null ? void 0 : onDataUpdate({ ...node, status: newStatus, color: newColor });
|
|
8868
|
+
};
|
|
8869
|
+
const handleAddType = (newType) => {
|
|
8870
|
+
const trimmed = newType.trim();
|
|
8871
|
+
if (trimmed && !types.includes(trimmed)) {
|
|
8872
|
+
setTypes([...types, trimmed]);
|
|
8873
|
+
setTypeInput("");
|
|
8874
|
+
setShowTypeSuggestions(false);
|
|
8875
|
+
}
|
|
8876
|
+
};
|
|
8877
|
+
const handleRemoveType = (indexToRemove) => {
|
|
8878
|
+
if (types[indexToRemove] === "quest") return;
|
|
8879
|
+
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
8880
|
+
};
|
|
8881
|
+
const handleTypeInputKeyDown = (e) => {
|
|
8882
|
+
if (e.key === "Enter") {
|
|
8883
|
+
e.preventDefault();
|
|
8884
|
+
handleAddType(typeInput);
|
|
8885
|
+
} else if (e.key === "Backspace" && typeInput === "" && types.length > 1) {
|
|
8886
|
+
handleRemoveType(types.length - 1);
|
|
8887
|
+
}
|
|
8888
|
+
};
|
|
8889
|
+
const handleAddProp = () => {
|
|
8890
|
+
const newProp = createNewCustomProperty(customProps);
|
|
8891
|
+
setCustomProps((p) => [...p, newProp]);
|
|
8892
|
+
setTimeout(() => {
|
|
8893
|
+
var _a2;
|
|
8894
|
+
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
8895
|
+
}, 100);
|
|
8896
|
+
};
|
|
8897
|
+
const handleRemoveProp = (i) => {
|
|
8898
|
+
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
8899
|
+
setCustomProps(newProps);
|
|
8900
|
+
triggerAutoSave({ customProps: newProps });
|
|
8901
|
+
};
|
|
8902
|
+
const handleUpdateProp = (index, updatedProp) => {
|
|
8903
|
+
const newProps = [...customProps];
|
|
8904
|
+
newProps[index] = updatedProp;
|
|
8905
|
+
setCustomProps(newProps);
|
|
8906
|
+
if (!updatedProp.isEditing) {
|
|
8907
|
+
triggerAutoSave({ customProps: newProps });
|
|
8908
|
+
}
|
|
8909
|
+
};
|
|
8910
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
8911
|
+
setDescription(newDescription);
|
|
8912
|
+
onDataUpdate({ ...node, description: newDescription });
|
|
8913
|
+
triggerAutoSave({ description: newDescription });
|
|
8914
|
+
};
|
|
8915
|
+
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
8916
|
+
const currentRawTitle = overrides.rawTitle !== void 0 ? overrides.rawTitle : rawTitle;
|
|
8917
|
+
const currentStandardName = questPrefix ? `${questPrefix} - \xBB ${currentRawTitle || "Sem t\xEDtulo"}` : currentRawTitle;
|
|
8918
|
+
const currentTypes = overrides.types !== void 0 ? overrides.types : types;
|
|
8919
|
+
const currentDescription = overrides.description !== void 0 ? overrides.description : description;
|
|
8920
|
+
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
8921
|
+
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
8922
|
+
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
8923
|
+
if (!currentRawTitle.trim() || currentTypes.length === 0) {
|
|
8924
|
+
alert("O campo 'T\xEDtulo' e pelo menos um 'Tipo' s\xE3o obrigat\xF3rios.");
|
|
8925
|
+
return;
|
|
8926
|
+
}
|
|
8927
|
+
setIsSaving(true);
|
|
8928
|
+
try {
|
|
8929
|
+
const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
|
|
8930
|
+
const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
|
|
8931
|
+
const dataToSave = {
|
|
8932
|
+
id: node.id,
|
|
8933
|
+
name: currentStandardName.trim(),
|
|
8934
|
+
// Salva o nome completo formatado
|
|
8935
|
+
raw_title: currentRawTitle.trim(),
|
|
8936
|
+
// Salva o título simples
|
|
8937
|
+
type: currentTypes,
|
|
8938
|
+
color: QUEST_STATUS_COLORS3[currentStatus],
|
|
8939
|
+
status: currentStatus,
|
|
8940
|
+
size,
|
|
8941
|
+
description: currentDescription,
|
|
8942
|
+
description_sections: processedSections,
|
|
8943
|
+
useImageAsTexture: false,
|
|
8944
|
+
textureImageUrl: null,
|
|
8945
|
+
intensity,
|
|
8946
|
+
is_quest: true,
|
|
8947
|
+
...extrasObj,
|
|
8948
|
+
version_node: node.version_node
|
|
8949
|
+
};
|
|
8950
|
+
await onSave(dataToSave, keepOpen);
|
|
8951
|
+
onDataUpdate(dataToSave);
|
|
8952
|
+
if (!keepOpen) {
|
|
8953
|
+
onClose();
|
|
8954
|
+
}
|
|
8955
|
+
} finally {
|
|
8956
|
+
setIsSaving(false);
|
|
8957
|
+
}
|
|
8958
|
+
};
|
|
8959
|
+
const triggerAutoSave = (overrides = {}) => {
|
|
8960
|
+
handleSave(true, overrides);
|
|
8961
|
+
};
|
|
8962
|
+
const handleCancel = () => {
|
|
8963
|
+
if (node) {
|
|
8964
|
+
onNameChange == null ? void 0 : onNameChange(node.id, node.name);
|
|
8965
|
+
onColorChange == null ? void 0 : onColorChange(node.id, node.color);
|
|
8966
|
+
onSizeChange == null ? void 0 : onSizeChange(node.id, node.size || "medium");
|
|
8967
|
+
}
|
|
8968
|
+
onClose();
|
|
8969
|
+
};
|
|
8970
|
+
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
8971
|
+
return /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(
|
|
8972
|
+
"div",
|
|
8973
|
+
{
|
|
8974
|
+
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"}`,
|
|
8975
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
8976
|
+
onPointerDown: swallow,
|
|
8977
|
+
onPointerMove: swallow,
|
|
8978
|
+
onPointerUp: swallow,
|
|
8979
|
+
onClick: swallow,
|
|
8980
|
+
onWheel: swallow,
|
|
8981
|
+
onContextMenu: swallow,
|
|
8982
|
+
onDoubleClick: swallow
|
|
8983
|
+
},
|
|
8984
|
+
/* @__PURE__ */ React17.createElement("div", { onPointerDown: (e) => {
|
|
8985
|
+
e.stopPropagation();
|
|
8986
|
+
handleResize(e);
|
|
8987
|
+
}, className: "absolute left-0 top-0 bottom-0 w-2 cursor-col-resize hover:bg-indigo-500/50 z-[2000] transition-colors", title: "Arraste para redimensionar" }),
|
|
8988
|
+
isReadMode ? /* @__PURE__ */ React17.createElement(
|
|
8989
|
+
DescriptionReadModePanel,
|
|
8990
|
+
{
|
|
8991
|
+
title: standardizedName || (node == null ? void 0 : node.name),
|
|
8992
|
+
description,
|
|
8993
|
+
savedSections: existingSections,
|
|
8994
|
+
onBack: () => setIsReadMode(false),
|
|
8995
|
+
onEdit: () => {
|
|
8996
|
+
if (canEdit) {
|
|
8997
|
+
setIsReadMode(false);
|
|
8998
|
+
setIsDescriptionModalOpen(true);
|
|
8999
|
+
}
|
|
9000
|
+
},
|
|
9001
|
+
onClose: handleCancel,
|
|
9002
|
+
availableNodes,
|
|
9003
|
+
availableAncestries,
|
|
9004
|
+
onOpenReference,
|
|
9005
|
+
onMentionClick,
|
|
9006
|
+
onImageClick: handleImageClickFromText,
|
|
9007
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
9008
|
+
}
|
|
9009
|
+
) : /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS3[status]}, transparent)` } }), /* @__PURE__ */ React17.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React17.createElement("div", null, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React17.createElement(FiTarget2, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ React17.createElement("button", { onClick: handleCopyLink, className: `ml-1 p-1 transition-colors ${isLinkCopied ? "text-green-400" : "text-slate-400 hover:text-sky-400"}`, title: isLinkCopied ? "Link Copiado!" : "Copiar link para esta Quest" }, isLinkCopied ? /* @__PURE__ */ React17.createElement(FiCheck11, { size: 12 }) : /* @__PURE__ */ React17.createElement(FiLink6, { size: 12 }))), /* @__PURE__ */ React17.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ React17.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__ */ React17.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ React17.createElement(
|
|
9010
|
+
"input",
|
|
9011
|
+
{
|
|
9012
|
+
type: "text",
|
|
9013
|
+
value: rawTitle,
|
|
9014
|
+
onChange: handleNameChange,
|
|
9015
|
+
readOnly: !canEdit,
|
|
9016
|
+
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"}`
|
|
9017
|
+
}
|
|
9018
|
+
), /* @__PURE__ */ React17.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ React17.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }), /* @__PURE__ */ React17.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React17.createElement("div", { className: "relative" }, /* @__PURE__ */ React17.createElement(
|
|
9019
|
+
"button",
|
|
9020
|
+
{
|
|
9021
|
+
type: "button",
|
|
9022
|
+
onClick: () => canEdit && setIsStatusDropdownOpen(!isStatusDropdownOpen),
|
|
9023
|
+
disabled: !canEdit,
|
|
9024
|
+
className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 transition-colors flex items-center justify-between ${canEdit ? "hover:border-white/20 focus:ring-2 focus:ring-indigo-400/60 cursor-pointer" : "cursor-default opacity-80"}`
|
|
9025
|
+
},
|
|
9026
|
+
/* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: QUEST_STATUS_COLORS3[status] } }), /* @__PURE__ */ React17.createElement("span", { className: "text-slate-200 font-medium" }, status)),
|
|
9027
|
+
canEdit && /* @__PURE__ */ React17.createElement(FiChevronDown6, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
|
|
9028
|
+
), isStatusDropdownOpen && canEdit && /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ React17.createElement("ul", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-800 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden" }, Object.keys(QUEST_STATUS_COLORS3).map((s) => /* @__PURE__ */ React17.createElement(
|
|
9029
|
+
"li",
|
|
9030
|
+
{
|
|
9031
|
+
key: s,
|
|
9032
|
+
onClick: () => {
|
|
9033
|
+
handleStatusChange(s);
|
|
9034
|
+
setIsStatusDropdownOpen(false);
|
|
9035
|
+
},
|
|
9036
|
+
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${status === s ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
9037
|
+
},
|
|
9038
|
+
/* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
|
|
9039
|
+
s
|
|
9040
|
+
)))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React17.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__ */ React17.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, canEdit && t !== "quest" && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React17.createElement(FiX6, { size: 12 })))), canEdit && /* @__PURE__ */ React17.createElement(
|
|
9041
|
+
"input",
|
|
9042
|
+
{
|
|
9043
|
+
type: "text",
|
|
9044
|
+
value: typeInput,
|
|
9045
|
+
onChange: (e) => {
|
|
9046
|
+
setTypeInput(e.target.value);
|
|
9047
|
+
setShowTypeSuggestions(true);
|
|
9048
|
+
},
|
|
9049
|
+
onKeyDown: handleTypeInputKeyDown,
|
|
9050
|
+
onClick: () => setShowTypeSuggestions(true),
|
|
9051
|
+
onBlur: () => {
|
|
9052
|
+
if (typeInput.trim()) {
|
|
9053
|
+
handleAddType(typeInput);
|
|
9054
|
+
}
|
|
9055
|
+
setTimeout(() => setShowTypeSuggestions(false), 150);
|
|
9056
|
+
},
|
|
9057
|
+
className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200",
|
|
9058
|
+
placeholder: "",
|
|
9059
|
+
autoComplete: "off"
|
|
9060
|
+
}
|
|
9061
|
+
), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ React17.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__ */ React17.createElement("li", { key: index, className: "px-3 py-2 text-sm text-slate-200 cursor-pointer hover:bg-indigo-600/50", onMouseDown: (e) => {
|
|
9062
|
+
e.preventDefault();
|
|
9063
|
+
handleAddType(suggestedType);
|
|
9064
|
+
} }, suggestedType))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React17.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__ */ React17.createElement(DescriptionDisplay, { description, savedSections: existingSections, availableNodes, availableAncestries, onOpenReference, onMentionClick, onImageClick: handleImageClickFromText, onSaveDescription: handleSaveDescriptionInline }), /* @__PURE__ */ React17.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => setIsReadMode(true), className: `p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors ${canEdit ? "border-r border-white/5" : ""}`, title: "Modo de Leitura" }, /* @__PURE__ */ React17.createElement(FiBookOpen4, { size: 14 })), canEdit && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors", title: "Editar descri\xE7\xE3o (Modo de Escrita)" }, /* @__PURE__ */ React17.createElement(FiEdit28, { size: 14 }))), canEdit && !description && /* @__PURE__ */ React17.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__ */ React17.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
|
|
9065
|
+
const isSelected = size === s;
|
|
9066
|
+
return /* @__PURE__ */ React17.createElement("button", { key: s, type: "button", onClick: () => canEdit && handleSizeChange(s), className: `flex items-center gap-2 group focus:outline-none ${canEdit ? "cursor-pointer" : "cursor-default opacity-80"}` }, /* @__PURE__ */ React17.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__ */ React17.createElement(FiCheck11, { size: 12, className: "text-white" })), /* @__PURE__ */ React17.createElement("span", { className: `text-sm capitalize transition-colors ${isSelected ? "text-white font-medium" : "text-slate-400 " + (canEdit ? "group-hover:text-slate-300" : "")}` }, s));
|
|
9067
|
+
}))), /* @__PURE__ */ React17.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React17.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React17.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__ */ React17.createElement(FiPlus7, { size: 14 }), " Adicionar")), /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React17.createElement(CustomPropertyDisplay, { key: prop.id, prop, onUpdate: canEdit ? (updatedProp) => handleUpdateProp(idx, updatedProp) : void 0, onRemove: canEdit ? () => handleRemoveProp(idx) : void 0, onOpenImageViewer, unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type), isTextureMode: false, onUploadFile: canEdit ? onUploadFile : void 0, readOnly: !canEdit })), /* @__PURE__ */ React17.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ React17.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__ */ React17.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ React17.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ React17.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__ */ React17.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__ */ React17.createElement("button", { onClick: () => handleSave(false), disabled: isSaving, className: `px-4 py-2 rounded-lg transition-all font-semibold text-sm shadow-[0_8px_24px_rgba(99,102,241,0.35)] flex items-center gap-2 ${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"}` }, isSaving && /* @__PURE__ */ React17.createElement(FiLoader3, { className: "animate-spin" }), isSaving ? "Salvando..." : "Salvar Quest")))
|
|
9068
|
+
), isDescriptionModalOpen && canEdit && /* @__PURE__ */ React17.createElement(
|
|
9069
|
+
DescriptionEditModal,
|
|
9070
|
+
{
|
|
9071
|
+
isOpen: isDescriptionModalOpen,
|
|
9072
|
+
title: "Editar Descri\xE7\xE3o da Quest",
|
|
9073
|
+
initialValue: description,
|
|
9074
|
+
onSave: (newDescription) => {
|
|
9075
|
+
setDescription(newDescription);
|
|
9076
|
+
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
9077
|
+
triggerAutoSave({ description: newDescription });
|
|
9078
|
+
},
|
|
9079
|
+
onClose: () => setIsDescriptionModalOpen(false),
|
|
9080
|
+
availableNodes,
|
|
9081
|
+
availableAncestries,
|
|
9082
|
+
availableImages
|
|
9083
|
+
}
|
|
9084
|
+
));
|
|
9085
|
+
}
|
|
9086
|
+
|
|
9087
|
+
// src/components/MultiNodeContextMenu.jsx
|
|
9088
|
+
import React18, { useLayoutEffect as useLayoutEffect3, useRef as useRef15, useState as useState19, useEffect as useEffect17 } from "react";
|
|
9089
|
+
function MultiNodeContextMenu({
|
|
9090
|
+
data,
|
|
9091
|
+
userRole,
|
|
9092
|
+
onClose,
|
|
9093
|
+
onDismissNodes,
|
|
9094
|
+
onDismissOtherNodes,
|
|
9095
|
+
onDeleteNodes
|
|
9096
|
+
}) {
|
|
9097
|
+
const menuRef = useRef15(null);
|
|
9098
|
+
const [menuPos, setMenuPos] = useState19({ left: 0, top: 0 });
|
|
9099
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState19(false);
|
|
9100
|
+
const ability = defineAbilityFor(userRole);
|
|
9101
|
+
const canDelete = ability.can("delete", "Node");
|
|
9102
|
+
useLayoutEffect3(() => {
|
|
9103
|
+
if (!data.visible || !menuRef.current) return;
|
|
9104
|
+
const el = menuRef.current;
|
|
9105
|
+
const w = el.clientWidth;
|
|
9106
|
+
const h = el.clientHeight;
|
|
9107
|
+
const vw = window.innerWidth;
|
|
9108
|
+
const vh = window.innerHeight;
|
|
9109
|
+
let left = data.x + 8;
|
|
9110
|
+
let top = data.y + 8;
|
|
9111
|
+
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
9112
|
+
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
9113
|
+
setMenuPos({ left, top });
|
|
9114
|
+
}, [data]);
|
|
9115
|
+
useEffect17(() => {
|
|
9116
|
+
if (data.visible) {
|
|
9117
|
+
setIsConfirmingDelete(false);
|
|
9118
|
+
}
|
|
9119
|
+
const handleClickOutside = (e) => {
|
|
9120
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
9121
|
+
};
|
|
9122
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
9123
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
9124
|
+
}, [data.visible, onClose]);
|
|
9125
|
+
if (!data.visible || !data.nodeIds || data.nodeIds.size === 0) return null;
|
|
9126
|
+
const swallow = (e) => e.stopPropagation();
|
|
9127
|
+
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";
|
|
9128
|
+
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";
|
|
9129
|
+
const nodeCount = data.nodeIds.size;
|
|
9130
|
+
return /* @__PURE__ */ React18.createElement(
|
|
9131
|
+
"div",
|
|
9132
|
+
{
|
|
9133
|
+
ref: menuRef,
|
|
9134
|
+
className: "ui-overlay context-menu-class origin-top-left rounded-xl 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,250px)] overflow-hidden",
|
|
9135
|
+
style: { position: "absolute", left: `${menuPos.left}px`, top: `${menuPos.top}px`, zIndex: 1e3 },
|
|
9136
|
+
onPointerDown: swallow,
|
|
9137
|
+
onPointerMove: swallow,
|
|
9138
|
+
onPointerUp: swallow,
|
|
9139
|
+
onClick: swallow,
|
|
9140
|
+
onWheel: swallow,
|
|
9141
|
+
onContextMenu: swallow,
|
|
9142
|
+
onDoubleClick: swallow
|
|
9143
|
+
},
|
|
9144
|
+
/* @__PURE__ */ React18.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
9145
|
+
/* @__PURE__ */ React18.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React18.createElement("div", { className: "w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 mb-1" }, /* @__PURE__ */ React18.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__ */ React18.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React18.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__ */ React18.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ React18.createElement("strong", null, nodeCount, " Nodes"), "?"), /* @__PURE__ */ React18.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__ */ React18.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React18.createElement(
|
|
9146
|
+
"button",
|
|
9147
|
+
{
|
|
9148
|
+
onClick: () => setIsConfirmingDelete(false),
|
|
9149
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
9150
|
+
},
|
|
9151
|
+
"Cancelar"
|
|
9152
|
+
), /* @__PURE__ */ React18.createElement(
|
|
9153
|
+
"button",
|
|
9154
|
+
{
|
|
9155
|
+
onClick: () => onDeleteNodes(data.nodeIds),
|
|
9156
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
9157
|
+
},
|
|
9158
|
+
"Excluir"
|
|
9159
|
+
))) : /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React18.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__ */ React18.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es em Grupo (", nodeCount, " Nodes)")), /* @__PURE__ */ React18.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React18.createElement("button", { onClick: () => onDismissNodes(data.nodeIds), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ React18.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__ */ React18.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ React18.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__ */ React18.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__ */ React18.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ React18.createElement("span", null, "Dismiss (", nodeCount, ")")), /* @__PURE__ */ React18.createElement("button", { onClick: () => onDismissOtherNodes(data.nodeIds), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ React18.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__ */ React18.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ React18.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ React18.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ React18.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ React18.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ React18.createElement("span", null, "Dismiss other nodes")), canDelete && /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ React18.createElement("button", { onClick: () => setIsConfirmingDelete(true), className: deleteButtonClass, title: "Excluir Nodes" }, /* @__PURE__ */ React18.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__ */ React18.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React18.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__ */ React18.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ React18.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ React18.createElement("span", null, "Excluir Nodes (", nodeCount, ")"))))))
|
|
9160
|
+
);
|
|
9161
|
+
}
|
|
9162
|
+
|
|
9163
|
+
// src/components/RelationshipDetailsPanel.jsx
|
|
9164
|
+
import React19, { useState as useState20, useEffect as useEffect18, useRef as useRef16, useMemo as useMemo9 } from "react";
|
|
9165
|
+
import { FiPlus as FiPlus8, FiEdit2 as FiEdit29, FiLoader as FiLoader4, FiBookOpen as FiBookOpen5 } from "react-icons/fi";
|
|
9166
|
+
function RelationshipDetailsPanel({
|
|
9167
|
+
link,
|
|
9168
|
+
onClose,
|
|
9169
|
+
onSave,
|
|
9170
|
+
onDataUpdate,
|
|
9171
|
+
onOpenImageViewer,
|
|
9172
|
+
availableNodes = [],
|
|
9173
|
+
availableAncestries = [],
|
|
9174
|
+
onOpenReference,
|
|
9175
|
+
onMentionClick,
|
|
9176
|
+
onUploadFile,
|
|
9177
|
+
userRole
|
|
9178
|
+
}) {
|
|
9179
|
+
const [name, setName] = useState20((link == null ? void 0 : link.name) ?? "");
|
|
9180
|
+
const [description, setDescription] = useState20((link == null ? void 0 : link.description) ?? "");
|
|
9181
|
+
const [customProps, setCustomProps] = useState20(() => extractCustomPropsFromNode(link || {}));
|
|
9182
|
+
const [existingSections, setExistingSections] = useState20((link == null ? void 0 : link.description_sections) || []);
|
|
9183
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState20(false);
|
|
9184
|
+
const [isSaving, setIsSaving] = useState20(false);
|
|
9185
|
+
const [isReadMode, setIsReadMode] = useState20(false);
|
|
9186
|
+
const propsEndRef = useRef16(null);
|
|
9187
|
+
const canEdit = useMemo9(() => {
|
|
9188
|
+
const ability = defineAbilityFor(userRole);
|
|
9189
|
+
return ability.can("update", "Connection");
|
|
9190
|
+
}, [userRole]);
|
|
9191
|
+
useEffect18(() => {
|
|
9192
|
+
setName((link == null ? void 0 : link.name) ?? "");
|
|
9193
|
+
setDescription((link == null ? void 0 : link.description) ?? "");
|
|
9194
|
+
setExistingSections((link == null ? void 0 : link.description_sections) || []);
|
|
9195
|
+
setCustomProps(extractCustomPropsFromNode(link || {}));
|
|
9196
|
+
}, [link]);
|
|
9197
|
+
const swallow = (e) => e.stopPropagation();
|
|
9198
|
+
const handleAddProp = () => {
|
|
9199
|
+
if (!canEdit) return;
|
|
9200
|
+
const newProp = createNewCustomProperty(customProps);
|
|
9201
|
+
setCustomProps((p) => [...p, newProp]);
|
|
9202
|
+
setTimeout(() => {
|
|
9203
|
+
var _a;
|
|
9204
|
+
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
9205
|
+
}, 100);
|
|
9206
|
+
};
|
|
9207
|
+
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
9208
|
+
if (!canEdit) return;
|
|
9209
|
+
const currentDescription = overrides.description !== void 0 ? overrides.description : description;
|
|
9210
|
+
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
9211
|
+
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
9212
|
+
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
9213
|
+
setIsSaving(true);
|
|
9214
|
+
try {
|
|
9215
|
+
const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
|
|
9216
|
+
const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
|
|
8680
9217
|
const dataToSave = {
|
|
8681
9218
|
id: link.id,
|
|
8682
9219
|
source: link.source,
|
|
@@ -8726,7 +9263,7 @@ function RelationshipDetailsPanel({
|
|
|
8726
9263
|
onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
|
|
8727
9264
|
}
|
|
8728
9265
|
};
|
|
8729
|
-
return /* @__PURE__ */
|
|
9266
|
+
return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(
|
|
8730
9267
|
"div",
|
|
8731
9268
|
{
|
|
8732
9269
|
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
|
|
@@ -8741,7 +9278,7 @@ function RelationshipDetailsPanel({
|
|
|
8741
9278
|
onContextMenu: swallow,
|
|
8742
9279
|
onDoubleClick: swallow
|
|
8743
9280
|
},
|
|
8744
|
-
isReadMode ? /* @__PURE__ */
|
|
9281
|
+
isReadMode ? /* @__PURE__ */ React19.createElement(
|
|
8745
9282
|
DescriptionReadModePanel,
|
|
8746
9283
|
{
|
|
8747
9284
|
title: name || "Rela\xE7\xE3o",
|
|
@@ -8762,7 +9299,7 @@ function RelationshipDetailsPanel({
|
|
|
8762
9299
|
onImageClick: handleImageClickFromText,
|
|
8763
9300
|
onSaveDescription: handleSaveDescriptionInline
|
|
8764
9301
|
}
|
|
8765
|
-
) : /* @__PURE__ */
|
|
9302
|
+
) : /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ React19.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React19.createElement("div", null, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React19.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__ */ React19.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ React19.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ React19.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__ */ React19.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ React19.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ React19.createElement(
|
|
8766
9303
|
"input",
|
|
8767
9304
|
{
|
|
8768
9305
|
type: "text",
|
|
@@ -8774,7 +9311,7 @@ function RelationshipDetailsPanel({
|
|
|
8774
9311
|
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
8775
9312
|
`
|
|
8776
9313
|
}
|
|
8777
|
-
)), /* @__PURE__ */
|
|
9314
|
+
)), /* @__PURE__ */ React19.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React19.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__ */ React19.createElement(
|
|
8778
9315
|
DescriptionDisplay,
|
|
8779
9316
|
{
|
|
8780
9317
|
description,
|
|
@@ -8786,7 +9323,7 @@ function RelationshipDetailsPanel({
|
|
|
8786
9323
|
onImageClick: handleImageClickFromText,
|
|
8787
9324
|
onSaveDescription: handleSaveDescriptionInline
|
|
8788
9325
|
}
|
|
8789
|
-
), /* @__PURE__ */
|
|
9326
|
+
), /* @__PURE__ */ React19.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__ */ React19.createElement(
|
|
8790
9327
|
"button",
|
|
8791
9328
|
{
|
|
8792
9329
|
type: "button",
|
|
@@ -8794,8 +9331,8 @@ function RelationshipDetailsPanel({
|
|
|
8794
9331
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors border-r border-white/5",
|
|
8795
9332
|
title: "Modo de Leitura"
|
|
8796
9333
|
},
|
|
8797
|
-
/* @__PURE__ */
|
|
8798
|
-
), canEdit && /* @__PURE__ */
|
|
9334
|
+
/* @__PURE__ */ React19.createElement(FiBookOpen5, { size: 14 })
|
|
9335
|
+
), canEdit && /* @__PURE__ */ React19.createElement(
|
|
8799
9336
|
"button",
|
|
8800
9337
|
{
|
|
8801
9338
|
type: "button",
|
|
@@ -8803,15 +9340,15 @@ function RelationshipDetailsPanel({
|
|
|
8803
9340
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8804
9341
|
title: "Editar descri\xE7\xE3o"
|
|
8805
9342
|
},
|
|
8806
|
-
/* @__PURE__ */
|
|
8807
|
-
)), !description && canEdit && /* @__PURE__ */
|
|
9343
|
+
/* @__PURE__ */ React19.createElement(FiEdit29, { size: 14 })
|
|
9344
|
+
)), !description && canEdit && /* @__PURE__ */ React19.createElement(
|
|
8808
9345
|
"div",
|
|
8809
9346
|
{
|
|
8810
9347
|
onClick: () => setIsDescriptionModalOpen(true),
|
|
8811
9348
|
className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
|
|
8812
9349
|
},
|
|
8813
9350
|
"Adicionar descri\xE7\xE3o..."
|
|
8814
|
-
))), /* @__PURE__ */
|
|
9351
|
+
))), /* @__PURE__ */ React19.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React19.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React19.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__ */ React19.createElement(FiPlus8, { size: 14 }), " Adicionar")), /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React19.createElement(
|
|
8815
9352
|
CustomPropertyDisplay,
|
|
8816
9353
|
{
|
|
8817
9354
|
key: prop.id,
|
|
@@ -8823,7 +9360,7 @@ function RelationshipDetailsPanel({
|
|
|
8823
9360
|
onUploadFile,
|
|
8824
9361
|
disabled: !canEdit
|
|
8825
9362
|
}
|
|
8826
|
-
)), /* @__PURE__ */
|
|
9363
|
+
)), /* @__PURE__ */ React19.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ React19.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__ */ React19.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__ */ React19.createElement(
|
|
8827
9364
|
"button",
|
|
8828
9365
|
{
|
|
8829
9366
|
onClick: () => handleSave(false),
|
|
@@ -8832,10 +9369,10 @@ function RelationshipDetailsPanel({
|
|
|
8832
9369
|
${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"}
|
|
8833
9370
|
`
|
|
8834
9371
|
},
|
|
8835
|
-
isSaving && /* @__PURE__ */
|
|
9372
|
+
isSaving && /* @__PURE__ */ React19.createElement(FiLoader4, { className: "animate-spin" }),
|
|
8836
9373
|
isSaving ? "Salvando..." : "Salvar"
|
|
8837
9374
|
)))
|
|
8838
|
-
), isDescriptionModalOpen && /* @__PURE__ */
|
|
9375
|
+
), isDescriptionModalOpen && /* @__PURE__ */ React19.createElement(
|
|
8839
9376
|
DescriptionEditModal,
|
|
8840
9377
|
{
|
|
8841
9378
|
isOpen: isDescriptionModalOpen,
|
|
@@ -8856,7 +9393,7 @@ function RelationshipDetailsPanel({
|
|
|
8856
9393
|
}
|
|
8857
9394
|
|
|
8858
9395
|
// src/components/RelationshipContextMenu.jsx
|
|
8859
|
-
import
|
|
9396
|
+
import React20, { useLayoutEffect as useLayoutEffect4, useRef as useRef17, useState as useState21, useEffect as useEffect19, useMemo as useMemo10 } from "react";
|
|
8860
9397
|
function RelationshipContextMenu({
|
|
8861
9398
|
data,
|
|
8862
9399
|
userRole,
|
|
@@ -8866,9 +9403,9 @@ function RelationshipContextMenu({
|
|
|
8866
9403
|
onDelete,
|
|
8867
9404
|
onClose
|
|
8868
9405
|
}) {
|
|
8869
|
-
const menuRef =
|
|
8870
|
-
const [menuPos, setMenuPos] =
|
|
8871
|
-
const [isConfirmingDelete, setIsConfirmingDelete] =
|
|
9406
|
+
const menuRef = useRef17(null);
|
|
9407
|
+
const [menuPos, setMenuPos] = useState21({ left: 0, top: 0 });
|
|
9408
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = useState21(false);
|
|
8872
9409
|
const ability = useMemo10(() => defineAbilityFor(userRole), [userRole]);
|
|
8873
9410
|
const sourceName = useMemo10(
|
|
8874
9411
|
() => {
|
|
@@ -8897,7 +9434,7 @@ function RelationshipContextMenu({
|
|
|
8897
9434
|
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
8898
9435
|
setMenuPos({ left, top });
|
|
8899
9436
|
}, [data]);
|
|
8900
|
-
|
|
9437
|
+
useEffect19(() => {
|
|
8901
9438
|
if (data.visible) {
|
|
8902
9439
|
setIsConfirmingDelete(false);
|
|
8903
9440
|
}
|
|
@@ -8913,7 +9450,7 @@ function RelationshipContextMenu({
|
|
|
8913
9450
|
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";
|
|
8914
9451
|
const canUpdate = ability.can("update", "Connection");
|
|
8915
9452
|
const canDelete = ability.can("delete", "Connection");
|
|
8916
|
-
return /* @__PURE__ */
|
|
9453
|
+
return /* @__PURE__ */ React20.createElement(
|
|
8917
9454
|
"div",
|
|
8918
9455
|
{
|
|
8919
9456
|
ref: menuRef,
|
|
@@ -8927,29 +9464,29 @@ function RelationshipContextMenu({
|
|
|
8927
9464
|
onContextMenu: swallow,
|
|
8928
9465
|
onDoubleClick: swallow
|
|
8929
9466
|
},
|
|
8930
|
-
/* @__PURE__ */
|
|
8931
|
-
/* @__PURE__ */
|
|
9467
|
+
/* @__PURE__ */ React20.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
|
|
9468
|
+
/* @__PURE__ */ React20.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ React20.createElement("div", { className: "w-10 h-10 rounded-full bg-rose-500/20 flex items-center justify-center text-rose-400 mb-1" }, /* @__PURE__ */ React20.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__ */ React20.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ React20.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), /* @__PURE__ */ React20.createElement("path", { d: "M10 11v6" }), /* @__PURE__ */ React20.createElement("path", { d: "M14 11v6" }), /* @__PURE__ */ React20.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ React20.createElement("p", { className: "text-sm text-slate-200" }, "Excluir rela\xE7\xE3o?"), /* @__PURE__ */ React20.createElement("p", { className: "text-[11px] text-slate-400 leading-tight break-words" }, "Desconectar ", /* @__PURE__ */ React20.createElement("strong", null, sourceName), " de ", /* @__PURE__ */ React20.createElement("strong", null, targetName), ".")), /* @__PURE__ */ React20.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ React20.createElement(
|
|
8932
9469
|
"button",
|
|
8933
9470
|
{
|
|
8934
9471
|
onClick: () => setIsConfirmingDelete(false),
|
|
8935
9472
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8936
9473
|
},
|
|
8937
9474
|
"Cancelar"
|
|
8938
|
-
), /* @__PURE__ */
|
|
9475
|
+
), /* @__PURE__ */ React20.createElement(
|
|
8939
9476
|
"button",
|
|
8940
9477
|
{
|
|
8941
9478
|
onClick: () => onDelete == null ? void 0 : onDelete(data.linkObject),
|
|
8942
9479
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-rose-600 hover:bg-rose-500 rounded-md text-white transition-colors"
|
|
8943
9480
|
},
|
|
8944
9481
|
"Excluir"
|
|
8945
|
-
))) : /* @__PURE__ */
|
|
9482
|
+
))) : /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React20.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__ */ React20.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Rela\xE7\xE3o")), /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col gap-1" }, canUpdate && /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(
|
|
8946
9483
|
"button",
|
|
8947
9484
|
{
|
|
8948
9485
|
onClick: () => onRelinkSource == null ? void 0 : onRelinkSource(data.linkObject),
|
|
8949
9486
|
className: baseButtonClass,
|
|
8950
9487
|
title: "Desconectar ponta ligada ao Source"
|
|
8951
9488
|
},
|
|
8952
|
-
/* @__PURE__ */
|
|
9489
|
+
/* @__PURE__ */ React20.createElement(
|
|
8953
9490
|
"svg",
|
|
8954
9491
|
{
|
|
8955
9492
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8962,18 +9499,18 @@ function RelationshipContextMenu({
|
|
|
8962
9499
|
strokeLinecap: "round",
|
|
8963
9500
|
strokeLinejoin: "round"
|
|
8964
9501
|
},
|
|
8965
|
-
/* @__PURE__ */
|
|
8966
|
-
/* @__PURE__ */
|
|
9502
|
+
/* @__PURE__ */ React20.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" }),
|
|
9503
|
+
/* @__PURE__ */ React20.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" })
|
|
8967
9504
|
),
|
|
8968
|
-
/* @__PURE__ */
|
|
8969
|
-
), /* @__PURE__ */
|
|
9505
|
+
/* @__PURE__ */ React20.createElement("span", null, "Desconectar Source (", sourceName, ")")
|
|
9506
|
+
), /* @__PURE__ */ React20.createElement(
|
|
8970
9507
|
"button",
|
|
8971
9508
|
{
|
|
8972
9509
|
onClick: () => onRelinkTarget == null ? void 0 : onRelinkTarget(data.linkObject),
|
|
8973
9510
|
className: baseButtonClass,
|
|
8974
9511
|
title: "Desconectar ponta ligada ao Target"
|
|
8975
9512
|
},
|
|
8976
|
-
/* @__PURE__ */
|
|
9513
|
+
/* @__PURE__ */ React20.createElement(
|
|
8977
9514
|
"svg",
|
|
8978
9515
|
{
|
|
8979
9516
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8986,21 +9523,21 @@ function RelationshipContextMenu({
|
|
|
8986
9523
|
strokeLinecap: "round",
|
|
8987
9524
|
strokeLinejoin: "round"
|
|
8988
9525
|
},
|
|
8989
|
-
/* @__PURE__ */
|
|
8990
|
-
/* @__PURE__ */
|
|
8991
|
-
/* @__PURE__ */
|
|
8992
|
-
/* @__PURE__ */
|
|
8993
|
-
/* @__PURE__ */
|
|
9526
|
+
/* @__PURE__ */ React20.createElement("polyline", { points: "16 3 21 3 21 8" }),
|
|
9527
|
+
/* @__PURE__ */ React20.createElement("line", { x1: "4", y1: "20", x2: "21", y2: "3" }),
|
|
9528
|
+
/* @__PURE__ */ React20.createElement("polyline", { points: "21 16 21 21 16 21" }),
|
|
9529
|
+
/* @__PURE__ */ React20.createElement("line", { x1: "15", y1: "15", x2: "21", y2: "21" }),
|
|
9530
|
+
/* @__PURE__ */ React20.createElement("line", { x1: "4", y1: "4", x2: "9", y2: "9" })
|
|
8994
9531
|
),
|
|
8995
|
-
/* @__PURE__ */
|
|
8996
|
-
), /* @__PURE__ */
|
|
9532
|
+
/* @__PURE__ */ React20.createElement("span", null, "Desconectar Target (", targetName, ")")
|
|
9533
|
+
), /* @__PURE__ */ React20.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" })), /* @__PURE__ */ React20.createElement(
|
|
8997
9534
|
"button",
|
|
8998
9535
|
{
|
|
8999
9536
|
onClick: () => onOpenDetails == null ? void 0 : onOpenDetails(data.linkObject),
|
|
9000
9537
|
className: baseButtonClass,
|
|
9001
9538
|
title: "Abrir detalhes da rela\xE7\xE3o"
|
|
9002
9539
|
},
|
|
9003
|
-
/* @__PURE__ */
|
|
9540
|
+
/* @__PURE__ */ React20.createElement(
|
|
9004
9541
|
"svg",
|
|
9005
9542
|
{
|
|
9006
9543
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -9013,19 +9550,19 @@ function RelationshipContextMenu({
|
|
|
9013
9550
|
strokeLinecap: "round",
|
|
9014
9551
|
strokeLinejoin: "round"
|
|
9015
9552
|
},
|
|
9016
|
-
/* @__PURE__ */
|
|
9017
|
-
/* @__PURE__ */
|
|
9018
|
-
/* @__PURE__ */
|
|
9553
|
+
/* @__PURE__ */ React20.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
9554
|
+
/* @__PURE__ */ React20.createElement("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
|
|
9555
|
+
/* @__PURE__ */ React20.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "8" })
|
|
9019
9556
|
),
|
|
9020
|
-
/* @__PURE__ */
|
|
9021
|
-
), canDelete && /* @__PURE__ */
|
|
9557
|
+
/* @__PURE__ */ React20.createElement("span", null, "Abrir Detalhes")
|
|
9558
|
+
), canDelete && /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ React20.createElement(
|
|
9022
9559
|
"button",
|
|
9023
9560
|
{
|
|
9024
9561
|
onClick: () => setIsConfirmingDelete(true),
|
|
9025
9562
|
className: dangerButtonClass,
|
|
9026
9563
|
title: "Excluir esta conex\xE3o"
|
|
9027
9564
|
},
|
|
9028
|
-
/* @__PURE__ */
|
|
9565
|
+
/* @__PURE__ */ React20.createElement(
|
|
9029
9566
|
"svg",
|
|
9030
9567
|
{
|
|
9031
9568
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -9038,19 +9575,19 @@ function RelationshipContextMenu({
|
|
|
9038
9575
|
strokeLinecap: "round",
|
|
9039
9576
|
strokeLinejoin: "round"
|
|
9040
9577
|
},
|
|
9041
|
-
/* @__PURE__ */
|
|
9042
|
-
/* @__PURE__ */
|
|
9043
|
-
/* @__PURE__ */
|
|
9044
|
-
/* @__PURE__ */
|
|
9045
|
-
/* @__PURE__ */
|
|
9578
|
+
/* @__PURE__ */ React20.createElement("polyline", { points: "3 6 5 6 21 6" }),
|
|
9579
|
+
/* @__PURE__ */ React20.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }),
|
|
9580
|
+
/* @__PURE__ */ React20.createElement("path", { d: "M10 11v6" }),
|
|
9581
|
+
/* @__PURE__ */ React20.createElement("path", { d: "M14 11v6" }),
|
|
9582
|
+
/* @__PURE__ */ React20.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
|
|
9046
9583
|
),
|
|
9047
|
-
/* @__PURE__ */
|
|
9584
|
+
/* @__PURE__ */ React20.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
|
|
9048
9585
|
)))))
|
|
9049
9586
|
);
|
|
9050
9587
|
}
|
|
9051
9588
|
|
|
9052
9589
|
// src/components/LoadingScreen.jsx
|
|
9053
|
-
import
|
|
9590
|
+
import React21 from "react";
|
|
9054
9591
|
var styles = {
|
|
9055
9592
|
loadingOverlay: {
|
|
9056
9593
|
position: "fixed",
|
|
@@ -9082,11 +9619,11 @@ var styles = {
|
|
|
9082
9619
|
`
|
|
9083
9620
|
};
|
|
9084
9621
|
function LoadingScreen() {
|
|
9085
|
-
return /* @__PURE__ */
|
|
9622
|
+
return /* @__PURE__ */ React21.createElement(React21.Fragment, null, /* @__PURE__ */ React21.createElement("style", null, styles.keyframes), /* @__PURE__ */ React21.createElement("div", { style: styles.loadingOverlay }, /* @__PURE__ */ React21.createElement("div", { style: styles.spinner })));
|
|
9086
9623
|
}
|
|
9087
9624
|
|
|
9088
9625
|
// src/components/ImportParentFileModal.jsx
|
|
9089
|
-
import
|
|
9626
|
+
import React22, { useEffect as useEffect20, useState as useState22 } from "react";
|
|
9090
9627
|
function ImportParentFileModal({
|
|
9091
9628
|
isOpen,
|
|
9092
9629
|
onClose,
|
|
@@ -9097,12 +9634,12 @@ function ImportParentFileModal({
|
|
|
9097
9634
|
onFetchAvailableFiles,
|
|
9098
9635
|
currentViewName
|
|
9099
9636
|
}) {
|
|
9100
|
-
const [activeTab, setActiveTab] =
|
|
9101
|
-
const [availableDbs, setAvailableDbs] =
|
|
9102
|
-
const [availableViews, setAvailableViews] =
|
|
9103
|
-
const [selectedItem, setSelectedItem] =
|
|
9104
|
-
const [isLoading, setIsLoading] =
|
|
9105
|
-
|
|
9637
|
+
const [activeTab, setActiveTab] = useState22("databases");
|
|
9638
|
+
const [availableDbs, setAvailableDbs] = useState22([]);
|
|
9639
|
+
const [availableViews, setAvailableViews] = useState22([]);
|
|
9640
|
+
const [selectedItem, setSelectedItem] = useState22(null);
|
|
9641
|
+
const [isLoading, setIsLoading] = useState22(false);
|
|
9642
|
+
useEffect20(() => {
|
|
9106
9643
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
9107
9644
|
const fetchData = async () => {
|
|
9108
9645
|
setIsLoading(true);
|
|
@@ -9138,7 +9675,7 @@ function ImportParentFileModal({
|
|
|
9138
9675
|
fetchData();
|
|
9139
9676
|
}
|
|
9140
9677
|
}, [isOpen, session, parentDbs, onFetchAvailableFiles, currentViewName]);
|
|
9141
|
-
|
|
9678
|
+
useEffect20(() => {
|
|
9142
9679
|
setSelectedItem(null);
|
|
9143
9680
|
}, [activeTab]);
|
|
9144
9681
|
if (!isOpen) {
|
|
@@ -9167,13 +9704,13 @@ function ImportParentFileModal({
|
|
|
9167
9704
|
const swallow = (e) => e.stopPropagation();
|
|
9168
9705
|
const currentList = activeTab === "databases" ? availableDbs : availableViews;
|
|
9169
9706
|
const emptyMessage = activeTab === "databases" ? "Nenhum novo arquivo parent dispon\xEDvel." : "Nenhuma view dispon\xEDvel para importa\xE7\xE3o.";
|
|
9170
|
-
return /* @__PURE__ */
|
|
9707
|
+
return /* @__PURE__ */ React22.createElement(
|
|
9171
9708
|
"div",
|
|
9172
9709
|
{
|
|
9173
9710
|
className: "ui-overlay fixed inset-0 z-[1200] flex items-center justify-center bg-black/60 backdrop-blur-sm",
|
|
9174
9711
|
onClick: onClose
|
|
9175
9712
|
},
|
|
9176
|
-
/* @__PURE__ */
|
|
9713
|
+
/* @__PURE__ */ React22.createElement(
|
|
9177
9714
|
"div",
|
|
9178
9715
|
{
|
|
9179
9716
|
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]",
|
|
@@ -9185,14 +9722,14 @@ function ImportParentFileModal({
|
|
|
9185
9722
|
onContextMenu: swallow,
|
|
9186
9723
|
onDoubleClick: swallow
|
|
9187
9724
|
},
|
|
9188
|
-
/* @__PURE__ */
|
|
9725
|
+
/* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/10 flex-shrink-0" }, /* @__PURE__ */ React22.createElement("h2", { className: "text-lg font-semibold" }, "Importar"), /* @__PURE__ */ React22.createElement(
|
|
9189
9726
|
"button",
|
|
9190
9727
|
{
|
|
9191
9728
|
onClick: onClose,
|
|
9192
9729
|
className: "p-2 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
9193
9730
|
title: "Fechar"
|
|
9194
9731
|
},
|
|
9195
|
-
/* @__PURE__ */
|
|
9732
|
+
/* @__PURE__ */ React22.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React22.createElement(
|
|
9196
9733
|
"path",
|
|
9197
9734
|
{
|
|
9198
9735
|
fillRule: "evenodd",
|
|
@@ -9201,14 +9738,14 @@ function ImportParentFileModal({
|
|
|
9201
9738
|
}
|
|
9202
9739
|
))
|
|
9203
9740
|
)),
|
|
9204
|
-
/* @__PURE__ */
|
|
9741
|
+
/* @__PURE__ */ React22.createElement("div", { className: "flex px-6 border-b border-white/10 bg-white/5 flex-shrink-0" }, /* @__PURE__ */ React22.createElement(
|
|
9205
9742
|
"button",
|
|
9206
9743
|
{
|
|
9207
9744
|
onClick: () => setActiveTab("databases"),
|
|
9208
9745
|
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"}`
|
|
9209
9746
|
},
|
|
9210
9747
|
"Arquivos Parent"
|
|
9211
|
-
), /* @__PURE__ */
|
|
9748
|
+
), /* @__PURE__ */ React22.createElement(
|
|
9212
9749
|
"button",
|
|
9213
9750
|
{
|
|
9214
9751
|
onClick: () => setActiveTab("views"),
|
|
@@ -9216,24 +9753,24 @@ function ImportParentFileModal({
|
|
|
9216
9753
|
},
|
|
9217
9754
|
"Views (Ancestralidades)"
|
|
9218
9755
|
)),
|
|
9219
|
-
/* @__PURE__ */
|
|
9756
|
+
/* @__PURE__ */ React22.createElement("div", { className: "p-6 overflow-y-auto custom-scrollbar flex-grow min-h-[200px]" }, isLoading ? /* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-center h-40" }, /* @__PURE__ */ React22.createElement("div", { className: "w-8 h-8 border-4 border-t-indigo-500 border-slate-700 rounded-full animate-spin" })) : /* @__PURE__ */ React22.createElement("div", { className: "space-y-2" }, currentList.length > 0 ? currentList.map((item) => /* @__PURE__ */ React22.createElement(
|
|
9220
9757
|
"div",
|
|
9221
9758
|
{
|
|
9222
9759
|
key: item.id,
|
|
9223
9760
|
onClick: () => setSelectedItem(item),
|
|
9224
9761
|
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"}`
|
|
9225
9762
|
},
|
|
9226
|
-
/* @__PURE__ */
|
|
9227
|
-
item.description && /* @__PURE__ */
|
|
9228
|
-
)) : /* @__PURE__ */
|
|
9229
|
-
/* @__PURE__ */
|
|
9763
|
+
/* @__PURE__ */ React22.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React22.createElement("span", { className: "font-medium text-slate-100" }, item.name), activeTab === "views" && /* @__PURE__ */ React22.createElement("span", { className: "text-[10px] px-1.5 py-0.5 rounded bg-black/30 text-indigo-300 border border-indigo-500/30" }, "VIEW")),
|
|
9764
|
+
item.description && /* @__PURE__ */ React22.createElement("p", { className: `text-xs ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "text-indigo-200" : "text-slate-400"}` }, item.description)
|
|
9765
|
+
)) : /* @__PURE__ */ React22.createElement("p", { className: "text-slate-400 text-center py-10" }, emptyMessage))),
|
|
9766
|
+
/* @__PURE__ */ React22.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__ */ React22.createElement(
|
|
9230
9767
|
"button",
|
|
9231
9768
|
{
|
|
9232
9769
|
onClick: onClose,
|
|
9233
9770
|
className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm text-slate-300"
|
|
9234
9771
|
},
|
|
9235
9772
|
"Cancelar"
|
|
9236
|
-
), /* @__PURE__ */
|
|
9773
|
+
), /* @__PURE__ */ React22.createElement(
|
|
9237
9774
|
"button",
|
|
9238
9775
|
{
|
|
9239
9776
|
onClick: handleConfirm,
|
|
@@ -9247,8 +9784,8 @@ function ImportParentFileModal({
|
|
|
9247
9784
|
}
|
|
9248
9785
|
|
|
9249
9786
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
9250
|
-
import
|
|
9251
|
-
import { FiBookOpen as
|
|
9787
|
+
import React23, { useState as useState23 } from "react";
|
|
9788
|
+
import { FiBookOpen as FiBookOpen6 } from "react-icons/fi";
|
|
9252
9789
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
9253
9790
|
var _a, _b, _c, _d;
|
|
9254
9791
|
const relationshipData = data.relationship || {};
|
|
@@ -9257,21 +9794,21 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9257
9794
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
9258
9795
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
9259
9796
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
9260
|
-
const [isReadMode, setIsReadMode] =
|
|
9797
|
+
const [isReadMode, setIsReadMode] = useState23(false);
|
|
9261
9798
|
const swallow = (e) => e.stopPropagation();
|
|
9262
9799
|
const handleImageClickFromText = (url, name) => {
|
|
9263
9800
|
if (onOpenImageViewer) {
|
|
9264
9801
|
onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
|
|
9265
9802
|
}
|
|
9266
9803
|
};
|
|
9267
|
-
return /* @__PURE__ */
|
|
9804
|
+
return /* @__PURE__ */ React23.createElement(
|
|
9268
9805
|
"div",
|
|
9269
9806
|
{
|
|
9270
9807
|
className: "ui-overlay fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[1200]",
|
|
9271
9808
|
onClick: onClose,
|
|
9272
9809
|
onPointerDown: swallow
|
|
9273
9810
|
},
|
|
9274
|
-
/* @__PURE__ */
|
|
9811
|
+
/* @__PURE__ */ React23.createElement(
|
|
9275
9812
|
"div",
|
|
9276
9813
|
{
|
|
9277
9814
|
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
|
|
@@ -9279,7 +9816,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9279
9816
|
`,
|
|
9280
9817
|
onClick: swallow
|
|
9281
9818
|
},
|
|
9282
|
-
isReadMode ? /* @__PURE__ */
|
|
9819
|
+
isReadMode ? /* @__PURE__ */ React23.createElement(
|
|
9283
9820
|
DescriptionReadModePanel,
|
|
9284
9821
|
{
|
|
9285
9822
|
title: `${sourceName} \u2794 ${targetName}`,
|
|
@@ -9291,15 +9828,15 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9291
9828
|
onMentionClick,
|
|
9292
9829
|
onImageClick: handleImageClickFromText
|
|
9293
9830
|
}
|
|
9294
|
-
) : /* @__PURE__ */
|
|
9831
|
+
) : /* @__PURE__ */ React23.createElement(React23.Fragment, null, /* @__PURE__ */ React23.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ React23.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React23.createElement("div", null, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React23.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__ */ React23.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Ancestralidade")), /* @__PURE__ */ React23.createElement("h2", { className: "text-lg font-semibold tracking-tight flex items-center gap-2" }, /* @__PURE__ */ React23.createElement("span", { className: "truncate max-w-[150px]" }, sourceName), /* @__PURE__ */ React23.createElement("span", { className: "text-slate-500 text-sm" }, "\u2794"), /* @__PURE__ */ React23.createElement("span", { className: "truncate max-w-[150px]" }, targetName))), /* @__PURE__ */ React23.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__ */ React23.createElement("div", { className: "px-6 pb-6 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, description && /* @__PURE__ */ React23.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React23.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React23.createElement("label", { className: "text-xs text-slate-300 font-medium" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React23.createElement(
|
|
9295
9832
|
"button",
|
|
9296
9833
|
{
|
|
9297
9834
|
onClick: () => setIsReadMode(true),
|
|
9298
9835
|
className: "p-1 text-slate-400 hover:text-white transition-colors",
|
|
9299
9836
|
title: "Modo de Leitura"
|
|
9300
9837
|
},
|
|
9301
|
-
/* @__PURE__ */
|
|
9302
|
-
)), /* @__PURE__ */
|
|
9838
|
+
/* @__PURE__ */ React23.createElement(FiBookOpen6, { size: 14 })
|
|
9839
|
+
)), /* @__PURE__ */ React23.createElement("div", { className: "bg-slate-800/40 rounded-lg border border-white/10 p-1 relative group" }, /* @__PURE__ */ React23.createElement(
|
|
9303
9840
|
DescriptionDisplay,
|
|
9304
9841
|
{
|
|
9305
9842
|
description,
|
|
@@ -9308,7 +9845,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9308
9845
|
onMentionClick,
|
|
9309
9846
|
onImageClick: handleImageClickFromText
|
|
9310
9847
|
}
|
|
9311
|
-
))), customProps.length > 0 && /* @__PURE__ */
|
|
9848
|
+
))), customProps.length > 0 && /* @__PURE__ */ React23.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React23.createElement("label", { className: "text-xs text-slate-300 font-medium mb-2 block" }, "Propriedades"), /* @__PURE__ */ React23.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop) => /* @__PURE__ */ React23.createElement(
|
|
9312
9849
|
CustomPropertyDisplay,
|
|
9313
9850
|
{
|
|
9314
9851
|
key: prop.id,
|
|
@@ -9317,25 +9854,25 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9317
9854
|
onOpenImageViewer,
|
|
9318
9855
|
onUploadFile
|
|
9319
9856
|
}
|
|
9320
|
-
)))), !description && customProps.length === 0 && /* @__PURE__ */
|
|
9857
|
+
)))), !description && customProps.length === 0 && /* @__PURE__ */ React23.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__ */ React23.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".')))
|
|
9321
9858
|
)
|
|
9322
9859
|
);
|
|
9323
9860
|
}
|
|
9324
9861
|
|
|
9325
9862
|
// src/components/AncestryBoard.jsx
|
|
9326
|
-
import
|
|
9863
|
+
import React24, { useState as useState24, useMemo as useMemo11, useEffect as useEffect21, useRef as useRef18 } from "react";
|
|
9327
9864
|
import {
|
|
9328
9865
|
FiSearch as FiSearch4,
|
|
9329
9866
|
FiLayers as FiLayers6,
|
|
9330
9867
|
FiCornerUpRight as FiCornerUpRight4,
|
|
9331
9868
|
FiPlay,
|
|
9332
|
-
FiPlus as
|
|
9869
|
+
FiPlus as FiPlus9,
|
|
9333
9870
|
FiTrash2 as FiTrash23,
|
|
9334
9871
|
FiArrowLeft as FiArrowLeft3,
|
|
9335
9872
|
FiArrowRight,
|
|
9336
9873
|
FiCheckCircle,
|
|
9337
|
-
FiLoader as
|
|
9338
|
-
FiX as
|
|
9874
|
+
FiLoader as FiLoader5,
|
|
9875
|
+
FiX as FiX7,
|
|
9339
9876
|
FiAlertTriangle
|
|
9340
9877
|
} from "react-icons/fi";
|
|
9341
9878
|
var GroupItem = ({
|
|
@@ -9357,7 +9894,7 @@ var GroupItem = ({
|
|
|
9357
9894
|
}) => {
|
|
9358
9895
|
const canIndent = index > 0;
|
|
9359
9896
|
const isPickingForThisGroup = pickingGroupId === group.id;
|
|
9360
|
-
const textareaRef =
|
|
9897
|
+
const textareaRef = useRef18(null);
|
|
9361
9898
|
const adjustHeight = () => {
|
|
9362
9899
|
const textarea = textareaRef.current;
|
|
9363
9900
|
if (textarea) {
|
|
@@ -9365,13 +9902,13 @@ var GroupItem = ({
|
|
|
9365
9902
|
textarea.style.height = `${textarea.scrollHeight}px`;
|
|
9366
9903
|
}
|
|
9367
9904
|
};
|
|
9368
|
-
|
|
9905
|
+
useEffect21(() => {
|
|
9369
9906
|
adjustHeight();
|
|
9370
9907
|
}, [group.text]);
|
|
9371
|
-
return /* @__PURE__ */
|
|
9908
|
+
return /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React24.createElement("div", { className: `
|
|
9372
9909
|
flex flex-col gap-2 py-2 px-3 transition-all duration-200
|
|
9373
9910
|
${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
|
|
9374
|
-
` }, /* @__PURE__ */
|
|
9911
|
+
` }, /* @__PURE__ */ React24.createElement(
|
|
9375
9912
|
"textarea",
|
|
9376
9913
|
{
|
|
9377
9914
|
ref: textareaRef,
|
|
@@ -9388,9 +9925,9 @@ var GroupItem = ({
|
|
|
9388
9925
|
if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
|
|
9389
9926
|
}
|
|
9390
9927
|
}
|
|
9391
|
-
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */
|
|
9928
|
+
), group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
|
|
9392
9929
|
const isValid = availableIds.has(String(anc.ancestry_id));
|
|
9393
|
-
return /* @__PURE__ */
|
|
9930
|
+
return /* @__PURE__ */ React24.createElement(
|
|
9394
9931
|
"div",
|
|
9395
9932
|
{
|
|
9396
9933
|
key: anc.ancestry_id,
|
|
@@ -9402,28 +9939,28 @@ var GroupItem = ({
|
|
|
9402
9939
|
},
|
|
9403
9940
|
isValid ? (
|
|
9404
9941
|
// [MANTIDO] Botão Play visível para todos
|
|
9405
|
-
/* @__PURE__ */
|
|
9942
|
+
/* @__PURE__ */ React24.createElement(
|
|
9406
9943
|
"button",
|
|
9407
9944
|
{
|
|
9408
9945
|
onClick: () => onPlayAncestry(anc.ancestry_id),
|
|
9409
9946
|
className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
|
|
9410
9947
|
title: "Renderizar no cen\xE1rio"
|
|
9411
9948
|
},
|
|
9412
|
-
/* @__PURE__ */
|
|
9949
|
+
/* @__PURE__ */ React24.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
|
|
9413
9950
|
)
|
|
9414
|
-
) : /* @__PURE__ */
|
|
9415
|
-
/* @__PURE__ */
|
|
9416
|
-
canEdit && /* @__PURE__ */
|
|
9951
|
+
) : /* @__PURE__ */ React24.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React24.createElement(FiAlertTriangle, { size: 10 })),
|
|
9952
|
+
/* @__PURE__ */ React24.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
|
|
9953
|
+
canEdit && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement("div", { className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}` }), /* @__PURE__ */ React24.createElement(
|
|
9417
9954
|
"button",
|
|
9418
9955
|
{
|
|
9419
9956
|
onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
|
|
9420
9957
|
className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
|
|
9421
9958
|
title: "Remover men\xE7\xE3o"
|
|
9422
9959
|
},
|
|
9423
|
-
/* @__PURE__ */
|
|
9960
|
+
/* @__PURE__ */ React24.createElement(FiX7, { size: 12 })
|
|
9424
9961
|
))
|
|
9425
9962
|
);
|
|
9426
|
-
})), canEdit && /* @__PURE__ */
|
|
9963
|
+
})), canEdit && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
9427
9964
|
"button",
|
|
9428
9965
|
{
|
|
9429
9966
|
onClick: () => onRequestPickAncestry(group.id),
|
|
@@ -9433,17 +9970,17 @@ var GroupItem = ({
|
|
|
9433
9970
|
`,
|
|
9434
9971
|
title: "Adicionar Ancestralidade a este grupo"
|
|
9435
9972
|
},
|
|
9436
|
-
isPickingForThisGroup ? /* @__PURE__ */
|
|
9973
|
+
isPickingForThisGroup ? /* @__PURE__ */ React24.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React24.createElement(FiSearch4, { size: 12 }),
|
|
9437
9974
|
isPickingForThisGroup ? "Selecionando..." : "Adicionar"
|
|
9438
|
-
), /* @__PURE__ */
|
|
9975
|
+
), /* @__PURE__ */ React24.createElement(
|
|
9439
9976
|
"button",
|
|
9440
9977
|
{
|
|
9441
9978
|
onClick: () => onAddSubgroup(group.id),
|
|
9442
9979
|
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
9443
9980
|
title: "Criar Subgrupo"
|
|
9444
9981
|
},
|
|
9445
|
-
/* @__PURE__ */
|
|
9446
|
-
)), /* @__PURE__ */
|
|
9982
|
+
/* @__PURE__ */ React24.createElement(FiPlus9, { size: 14 })
|
|
9983
|
+
)), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React24.createElement(
|
|
9447
9984
|
"button",
|
|
9448
9985
|
{
|
|
9449
9986
|
onClick: () => onIndent(group.id),
|
|
@@ -9451,24 +9988,24 @@ var GroupItem = ({
|
|
|
9451
9988
|
className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
|
|
9452
9989
|
title: "Aninhar no grupo acima"
|
|
9453
9990
|
},
|
|
9454
|
-
/* @__PURE__ */
|
|
9455
|
-
), /* @__PURE__ */
|
|
9991
|
+
/* @__PURE__ */ React24.createElement(FiArrowRight, { size: 14 })
|
|
9992
|
+
), /* @__PURE__ */ React24.createElement(
|
|
9456
9993
|
"button",
|
|
9457
9994
|
{
|
|
9458
9995
|
onClick: () => onOutdent(group.id),
|
|
9459
9996
|
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
9460
9997
|
title: "Desaninhar"
|
|
9461
9998
|
},
|
|
9462
|
-
/* @__PURE__ */
|
|
9463
|
-
), /* @__PURE__ */
|
|
9999
|
+
/* @__PURE__ */ React24.createElement(FiArrowLeft3, { size: 14 })
|
|
10000
|
+
), /* @__PURE__ */ React24.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement(
|
|
9464
10001
|
"button",
|
|
9465
10002
|
{
|
|
9466
10003
|
onClick: () => onDelete(group.id),
|
|
9467
10004
|
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
|
|
9468
10005
|
title: "Remover Grupo"
|
|
9469
10006
|
},
|
|
9470
|
-
/* @__PURE__ */
|
|
9471
|
-
)))), group.children && group.children.length > 0 && /* @__PURE__ */
|
|
10007
|
+
/* @__PURE__ */ React24.createElement(FiTrash23, { size: 14 })
|
|
10008
|
+
)))), group.children && group.children.length > 0 && /* @__PURE__ */ React24.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React24.createElement(
|
|
9472
10009
|
GroupItem,
|
|
9473
10010
|
{
|
|
9474
10011
|
key: childGroup.id,
|
|
@@ -9500,15 +10037,15 @@ function AncestryBoard({
|
|
|
9500
10037
|
userRole
|
|
9501
10038
|
// [NOVO] Recebe a role do usuário
|
|
9502
10039
|
}) {
|
|
9503
|
-
const [searchTerm, setSearchTerm] =
|
|
9504
|
-
const [groups, setGroups] =
|
|
9505
|
-
const [isLoaded, setIsLoaded] =
|
|
9506
|
-
const [pickingGroupId, setPickingGroupId] =
|
|
9507
|
-
const [saveStatus, setSaveStatus] =
|
|
10040
|
+
const [searchTerm, setSearchTerm] = useState24("");
|
|
10041
|
+
const [groups, setGroups] = useState24([]);
|
|
10042
|
+
const [isLoaded, setIsLoaded] = useState24(false);
|
|
10043
|
+
const [pickingGroupId, setPickingGroupId] = useState24(null);
|
|
10044
|
+
const [saveStatus, setSaveStatus] = useState24("idle");
|
|
9508
10045
|
const canEdit = useMemo11(() => {
|
|
9509
10046
|
return userRole !== "viewer";
|
|
9510
10047
|
}, [userRole]);
|
|
9511
|
-
|
|
10048
|
+
useEffect21(() => {
|
|
9512
10049
|
if (initialGroups && !isLoaded) {
|
|
9513
10050
|
setGroups(initialGroups);
|
|
9514
10051
|
setIsLoaded(true);
|
|
@@ -9539,7 +10076,7 @@ function AncestryBoard({
|
|
|
9539
10076
|
children: sanitizeGroups(g.children || [])
|
|
9540
10077
|
}));
|
|
9541
10078
|
};
|
|
9542
|
-
|
|
10079
|
+
useEffect21(() => {
|
|
9543
10080
|
if (!isLoaded || !onSave) return;
|
|
9544
10081
|
const timeoutId = setTimeout(async () => {
|
|
9545
10082
|
setSaveStatus("saving");
|
|
@@ -9557,7 +10094,7 @@ function AncestryBoard({
|
|
|
9557
10094
|
}, 3e3);
|
|
9558
10095
|
return () => clearTimeout(timeoutId);
|
|
9559
10096
|
}, [groups, isLoaded, onSave]);
|
|
9560
|
-
|
|
10097
|
+
useEffect21(() => {
|
|
9561
10098
|
if (!isOpen) return;
|
|
9562
10099
|
const handleKeyDown = (e) => {
|
|
9563
10100
|
if (e.key === "Escape") {
|
|
@@ -9712,27 +10249,27 @@ function AncestryBoard({
|
|
|
9712
10249
|
});
|
|
9713
10250
|
};
|
|
9714
10251
|
if (!isOpen) return null;
|
|
9715
|
-
return /* @__PURE__ */
|
|
10252
|
+
return /* @__PURE__ */ React24.createElement(
|
|
9716
10253
|
"div",
|
|
9717
10254
|
{
|
|
9718
10255
|
className: "fixed inset-0 z-[2200] bg-black/80 backdrop-blur-sm flex items-center justify-center p-2",
|
|
9719
10256
|
onClick: onClose
|
|
9720
10257
|
},
|
|
9721
|
-
/* @__PURE__ */
|
|
10258
|
+
/* @__PURE__ */ React24.createElement(
|
|
9722
10259
|
"div",
|
|
9723
10260
|
{
|
|
9724
10261
|
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",
|
|
9725
10262
|
onClick: (e) => e.stopPropagation()
|
|
9726
10263
|
},
|
|
9727
|
-
/* @__PURE__ */
|
|
10264
|
+
/* @__PURE__ */ React24.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React24.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React24.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React24.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(FiLoader5, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React24.createElement(React24.Fragment, null, /* @__PURE__ */ React24.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React24.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ React24.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ React24.createElement(
|
|
9728
10265
|
"button",
|
|
9729
10266
|
{
|
|
9730
10267
|
onClick: handleAddRootGroup,
|
|
9731
10268
|
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 "
|
|
9732
10269
|
},
|
|
9733
|
-
/* @__PURE__ */
|
|
9734
|
-
/* @__PURE__ */
|
|
9735
|
-
), /* @__PURE__ */
|
|
10270
|
+
/* @__PURE__ */ React24.createElement(FiPlus9, { size: 14, className: "text-indigo-400" }),
|
|
10271
|
+
/* @__PURE__ */ React24.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
|
|
10272
|
+
), /* @__PURE__ */ React24.createElement(
|
|
9736
10273
|
"button",
|
|
9737
10274
|
{
|
|
9738
10275
|
onClick: onClose,
|
|
@@ -9740,11 +10277,11 @@ function AncestryBoard({
|
|
|
9740
10277
|
},
|
|
9741
10278
|
"\xD7"
|
|
9742
10279
|
))),
|
|
9743
|
-
/* @__PURE__ */
|
|
10280
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React24.createElement("div", { className: `
|
|
9744
10281
|
flex flex-col border-r border-white/10 transition-all duration-300 flex-none
|
|
9745
10282
|
${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
|
|
9746
10283
|
min-w-[280px] max-w-[500px] bg-slate-900
|
|
9747
|
-
` }, /* @__PURE__ */
|
|
10284
|
+
` }, /* @__PURE__ */ React24.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React24.createElement("div", { className: "relative group" }, /* @__PURE__ */ React24.createElement(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__ */ React24.createElement(
|
|
9748
10285
|
"input",
|
|
9749
10286
|
{
|
|
9750
10287
|
type: "text",
|
|
@@ -9757,10 +10294,10 @@ function AncestryBoard({
|
|
|
9757
10294
|
onChange: (e) => setSearchTerm(e.target.value),
|
|
9758
10295
|
autoFocus: !pickingGroupId
|
|
9759
10296
|
}
|
|
9760
|
-
))), /* @__PURE__ */
|
|
10297
|
+
))), /* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
|
|
9761
10298
|
const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
|
|
9762
10299
|
const isPicking = !!pickingGroupId;
|
|
9763
|
-
return /* @__PURE__ */
|
|
10300
|
+
return /* @__PURE__ */ React24.createElement(
|
|
9764
10301
|
"div",
|
|
9765
10302
|
{
|
|
9766
10303
|
key: anc.ancestry_id,
|
|
@@ -9772,12 +10309,12 @@ function AncestryBoard({
|
|
|
9772
10309
|
${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"}
|
|
9773
10310
|
`
|
|
9774
10311
|
},
|
|
9775
|
-
/* @__PURE__ */
|
|
10312
|
+
/* @__PURE__ */ React24.createElement("div", { className: `
|
|
9776
10313
|
mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
|
|
9777
10314
|
${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"}
|
|
9778
|
-
` }, isPicking ? /* @__PURE__ */
|
|
9779
|
-
/* @__PURE__ */
|
|
9780
|
-
!isPicking && /* @__PURE__ */
|
|
10315
|
+
` }, isPicking ? /* @__PURE__ */ React24.createElement(FiPlus9, { size: 16 }) : /* @__PURE__ */ React24.createElement(FiLayers6, { size: 14 })),
|
|
10316
|
+
/* @__PURE__ */ React24.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React24.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React24.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.name || "Sem Nome"), anc.is_private && /* @__PURE__ */ React24.createElement("span", { className: "text-[9px] px-1 py-0.5 rounded bg-amber-500/10 text-amber-300 border border-amber-500/20" }, "Priv")), /* @__PURE__ */ React24.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React24.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React24.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ React24.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
|
|
10317
|
+
!isPicking && /* @__PURE__ */ React24.createElement(
|
|
9781
10318
|
"button",
|
|
9782
10319
|
{
|
|
9783
10320
|
onClick: (e) => {
|
|
@@ -9787,10 +10324,10 @@ function AncestryBoard({
|
|
|
9787
10324
|
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",
|
|
9788
10325
|
title: "Renderizar Ancestralidade"
|
|
9789
10326
|
},
|
|
9790
|
-
/* @__PURE__ */
|
|
10327
|
+
/* @__PURE__ */ React24.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React24.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
|
|
9791
10328
|
)
|
|
9792
10329
|
);
|
|
9793
|
-
}))), /* @__PURE__ */
|
|
10330
|
+
}))), /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ React24.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React24.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React24.createElement(FiLayers6, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React24.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React24.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React24.createElement(React24.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React24.createElement(
|
|
9794
10331
|
GroupItem,
|
|
9795
10332
|
{
|
|
9796
10333
|
key: group.id,
|
|
@@ -9810,7 +10347,7 @@ function AncestryBoard({
|
|
|
9810
10347
|
canEdit
|
|
9811
10348
|
}
|
|
9812
10349
|
))))),
|
|
9813
|
-
/* @__PURE__ */
|
|
10350
|
+
/* @__PURE__ */ React24.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__ */ React24.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ React24.createElement("span", null, groups.length, " grupos raiz"))
|
|
9814
10351
|
)
|
|
9815
10352
|
);
|
|
9816
10353
|
}
|
|
@@ -9889,7 +10426,7 @@ function XViewScene({
|
|
|
9889
10426
|
delete_file_action,
|
|
9890
10427
|
check_user_permission
|
|
9891
10428
|
}) {
|
|
9892
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
10429
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
9893
10430
|
const { data: session, status } = useSession();
|
|
9894
10431
|
const router = useRouter();
|
|
9895
10432
|
const searchParams = useSearchParams();
|
|
@@ -9904,7 +10441,7 @@ function XViewScene({
|
|
|
9904
10441
|
}
|
|
9905
10442
|
return null;
|
|
9906
10443
|
}, [encryptedConfig, session]);
|
|
9907
|
-
|
|
10444
|
+
useEffect22(() => {
|
|
9908
10445
|
async function verifyPermission() {
|
|
9909
10446
|
if (!viewParams || !session || !check_user_permission) return;
|
|
9910
10447
|
const { id, type, owner_id } = viewParams;
|
|
@@ -9954,45 +10491,45 @@ function XViewScene({
|
|
|
9954
10491
|
}
|
|
9955
10492
|
return null;
|
|
9956
10493
|
}, [ownerId, sceneConfigId]);
|
|
9957
|
-
const sceneDataRef =
|
|
9958
|
-
const parentDataRef =
|
|
9959
|
-
const ancestryDataRef =
|
|
9960
|
-
const [isLoading, setIsLoading] =
|
|
9961
|
-
const [permissionStatus, setPermissionStatus] =
|
|
9962
|
-
const [userPermissionRole, setUserPermissionRole] =
|
|
9963
|
-
const [isInitialized, setIsInitialized] =
|
|
9964
|
-
const [sceneVersion, setSceneVersion] =
|
|
9965
|
-
const [contextMenu, setContextMenu] =
|
|
9966
|
-
const [multiContextMenu, setMultiContextMenu] =
|
|
9967
|
-
const [relationshipMenu, setRelationshipMenu] =
|
|
9968
|
-
const [creationMode, setCreationMode] =
|
|
9969
|
-
const [versionMode, setVersionMode] =
|
|
9970
|
-
const [questMode, setQuestMode] =
|
|
9971
|
-
const [hasFocusedInitial, setHasFocusedInitial] =
|
|
9972
|
-
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] =
|
|
9973
|
-
const [ancestryMode, setAncestryMode] =
|
|
9974
|
-
const [readingMode, setReadingMode] =
|
|
10494
|
+
const sceneDataRef = useRef19(null);
|
|
10495
|
+
const parentDataRef = useRef19(null);
|
|
10496
|
+
const ancestryDataRef = useRef19(null);
|
|
10497
|
+
const [isLoading, setIsLoading] = useState25(true);
|
|
10498
|
+
const [permissionStatus, setPermissionStatus] = useState25("loading");
|
|
10499
|
+
const [userPermissionRole, setUserPermissionRole] = useState25(null);
|
|
10500
|
+
const [isInitialized, setIsInitialized] = useState25(false);
|
|
10501
|
+
const [sceneVersion, setSceneVersion] = useState25(0);
|
|
10502
|
+
const [contextMenu, setContextMenu] = useState25({ visible: false, x: 0, y: 0, nodeData: null });
|
|
10503
|
+
const [multiContextMenu, setMultiContextMenu] = useState25({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
10504
|
+
const [relationshipMenu, setRelationshipMenu] = useState25({ visible: false, x: 0, y: 0, linkObject: null });
|
|
10505
|
+
const [creationMode, setCreationMode] = useState25({ isActive: false, sourceNodeData: null });
|
|
10506
|
+
const [versionMode, setVersionMode] = useState25({ isActive: false, sourceNodeData: null });
|
|
10507
|
+
const [questMode, setQuestMode] = useState25({ isActive: false });
|
|
10508
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState25(false);
|
|
10509
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState25(false);
|
|
10510
|
+
const [ancestryMode, setAncestryMode] = useState25({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
10511
|
+
const [readingMode, setReadingMode] = useState25({
|
|
9975
10512
|
isActive: false,
|
|
9976
10513
|
ancestry: null,
|
|
9977
10514
|
branchStack: [],
|
|
9978
10515
|
autoAbstraction: false
|
|
9979
10516
|
});
|
|
9980
|
-
const [formPosition, setFormPosition] =
|
|
9981
|
-
const [detailsNode, setDetailsNode] =
|
|
9982
|
-
const [detailsLink, setDetailsLink] =
|
|
9983
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] =
|
|
9984
|
-
const [imageViewer, setImageViewer] =
|
|
9985
|
-
const [editingAncestryRel, setEditingAncestryRel] =
|
|
9986
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
9987
|
-
const [importSuccessMessage, setImportSuccessMessage] =
|
|
9988
|
-
const [highlightedNodeId, setHighlightedNodeId] =
|
|
9989
|
-
const [isAncestryBoardOpen, setIsAncestryBoardOpen] =
|
|
9990
|
-
const [ancestryBoardData, setAncestryBoardData] =
|
|
9991
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
9992
|
-
const mountRef =
|
|
9993
|
-
const tooltipRef =
|
|
9994
|
-
const formRef =
|
|
9995
|
-
const stateRef =
|
|
10517
|
+
const [formPosition, setFormPosition] = useState25({ left: 16, top: 16, opacity: 0 });
|
|
10518
|
+
const [detailsNode, setDetailsNode] = useState25(null);
|
|
10519
|
+
const [detailsLink, setDetailsLink] = useState25(null);
|
|
10520
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState25(null);
|
|
10521
|
+
const [imageViewer, setImageViewer] = useState25({ visible: false, images: [], startIndex: 0 });
|
|
10522
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState25({ visible: false, data: null, path: null });
|
|
10523
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState25(false);
|
|
10524
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState25("");
|
|
10525
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState25(null);
|
|
10526
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState25(false);
|
|
10527
|
+
const [ancestryBoardData, setAncestryBoardData] = useState25([]);
|
|
10528
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState25(false);
|
|
10529
|
+
const mountRef = useRef19(null);
|
|
10530
|
+
const tooltipRef = useRef19(null);
|
|
10531
|
+
const formRef = useRef19(null);
|
|
10532
|
+
const stateRef = useRef19({
|
|
9996
10533
|
readMode: {
|
|
9997
10534
|
currentMaxIndex: 0,
|
|
9998
10535
|
progressMap: {}
|
|
@@ -10037,10 +10574,10 @@ function XViewScene({
|
|
|
10037
10574
|
minWidth: 320,
|
|
10038
10575
|
maxWidth: maxReadPanelW
|
|
10039
10576
|
});
|
|
10040
|
-
|
|
10577
|
+
useEffect22(() => {
|
|
10041
10578
|
stateRef.current.ancestry = ancestryMode;
|
|
10042
10579
|
}, [ancestryMode]);
|
|
10043
|
-
|
|
10580
|
+
useEffect22(() => {
|
|
10044
10581
|
var _a2;
|
|
10045
10582
|
if (!isInitialized) return;
|
|
10046
10583
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -10225,7 +10762,7 @@ function XViewScene({
|
|
|
10225
10762
|
});
|
|
10226
10763
|
}
|
|
10227
10764
|
return {
|
|
10228
|
-
node: effectiveNode
|
|
10765
|
+
...effectiveNode ? { node: effectiveNode } : { node: { id: nodeId, name: "Unknown" } },
|
|
10229
10766
|
relationship: treeItem.relationship || {},
|
|
10230
10767
|
children: (treeItem.children || []).map(recursiveBuild).filter(Boolean),
|
|
10231
10768
|
parallel_branches: processedBranches
|
|
@@ -10537,7 +11074,7 @@ function XViewScene({
|
|
|
10537
11074
|
}
|
|
10538
11075
|
});
|
|
10539
11076
|
}, []);
|
|
10540
|
-
|
|
11077
|
+
useEffect22(() => {
|
|
10541
11078
|
async function fetchAllData(configPath, ownerId2) {
|
|
10542
11079
|
var _a2, _b2;
|
|
10543
11080
|
if (!get_scene_view_data) {
|
|
@@ -10641,7 +11178,7 @@ function XViewScene({
|
|
|
10641
11178
|
}
|
|
10642
11179
|
return mesh;
|
|
10643
11180
|
}, []);
|
|
10644
|
-
|
|
11181
|
+
useEffect22(() => {
|
|
10645
11182
|
if (!isInitialized || !sceneDataRef.current) return;
|
|
10646
11183
|
const currentMount = mountRef.current;
|
|
10647
11184
|
if (!currentMount) return;
|
|
@@ -11029,39 +11566,6 @@ function XViewScene({
|
|
|
11029
11566
|
}
|
|
11030
11567
|
}
|
|
11031
11568
|
}
|
|
11032
|
-
function handleCancelAncestryCreation() {
|
|
11033
|
-
setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
11034
|
-
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
11035
|
-
}
|
|
11036
|
-
function handleKeyDown(event) {
|
|
11037
|
-
var _a2, _b2, _c2, _d2;
|
|
11038
|
-
const context = actionHandlerContext;
|
|
11039
|
-
if (event.key === "Escape") {
|
|
11040
|
-
if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
|
|
11041
|
-
if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
|
|
11042
|
-
if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
|
|
11043
|
-
if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
|
|
11044
|
-
if (stateRef.current.ancestry.isActive) handleCancelAncestryCreation();
|
|
11045
|
-
if ((_b2 = context.questMode) == null ? void 0 : _b2.isActive) context.setters.setQuestMode({ isActive: false });
|
|
11046
|
-
if (stateRef.current.selectedNodes.size > 0) {
|
|
11047
|
-
stateRef.current.selectedNodes.clear();
|
|
11048
|
-
}
|
|
11049
|
-
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11050
|
-
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
11051
|
-
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
11052
|
-
}
|
|
11053
|
-
if (event.key.toLowerCase() === "q") {
|
|
11054
|
-
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;
|
|
11055
|
-
if (isUiClear) {
|
|
11056
|
-
const isView = ((_d2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _d2.toLowerCase()) === "view";
|
|
11057
|
-
if (!isView) {
|
|
11058
|
-
alert("Nodes de Quest s\xF3 podem ser criados dentro de uma View.");
|
|
11059
|
-
return;
|
|
11060
|
-
}
|
|
11061
|
-
setQuestMode({ isActive: true });
|
|
11062
|
-
}
|
|
11063
|
-
}
|
|
11064
|
-
}
|
|
11065
11569
|
function handleDoubleClick(event) {
|
|
11066
11570
|
if (stateRef.current.camera) stateRef.current.camera.layers.enableAll();
|
|
11067
11571
|
if (isFromUiOverlay(event) || stateRef.current.isDragging || stateRef.current.creation.isActive || stateRef.current.connection.isActive || stateRef.current.relink.isActive) return;
|
|
@@ -11114,7 +11618,6 @@ function XViewScene({
|
|
|
11114
11618
|
currentMount.addEventListener("dblclick", handleDoubleClick);
|
|
11115
11619
|
currentMount.addEventListener("pointermove", onPointerMove);
|
|
11116
11620
|
currentMount.addEventListener("contextmenu", handleContextMenu);
|
|
11117
|
-
window.addEventListener("keydown", handleKeyDown);
|
|
11118
11621
|
const originalBackground = scene.background;
|
|
11119
11622
|
const clock = new THREE3.Clock();
|
|
11120
11623
|
let animationFrameId = 0;
|
|
@@ -11252,7 +11755,6 @@ function XViewScene({
|
|
|
11252
11755
|
return () => {
|
|
11253
11756
|
cancelAnimationFrame(animationFrameId);
|
|
11254
11757
|
window.removeEventListener("resize", handleResize);
|
|
11255
|
-
window.removeEventListener("keydown", handleKeyDown);
|
|
11256
11758
|
currentMount.removeEventListener("pointerdown", onPointerDown);
|
|
11257
11759
|
currentMount.removeEventListener("pointerup", onPointerUp);
|
|
11258
11760
|
currentMount.removeEventListener("dblclick", handleDoubleClick);
|
|
@@ -11422,7 +11924,7 @@ function XViewScene({
|
|
|
11422
11924
|
graphGroup.add(newLabel);
|
|
11423
11925
|
ghostNode.userData.labelObject = newLabel;
|
|
11424
11926
|
};
|
|
11425
|
-
const handleDetailNodeNameChange = (nodeId, newName) => {
|
|
11927
|
+
const handleDetailNodeNameChange = (nodeId, newName, newRawTitle) => {
|
|
11426
11928
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
11427
11929
|
const { graphGroup } = stateRef.current;
|
|
11428
11930
|
if (!mesh || !graphGroup) return;
|
|
@@ -11432,10 +11934,15 @@ function XViewScene({
|
|
|
11432
11934
|
if (oldLabel.material.map) oldLabel.material.map.dispose();
|
|
11433
11935
|
oldLabel.material.dispose();
|
|
11434
11936
|
}
|
|
11435
|
-
const
|
|
11937
|
+
const isQuest = mesh.userData.is_quest;
|
|
11938
|
+
const displayText = isQuest && newRawTitle !== void 0 ? newRawTitle : newName;
|
|
11939
|
+
const newLabel = createTextSprite(displayText || "");
|
|
11436
11940
|
graphGroup.add(newLabel);
|
|
11437
11941
|
mesh.userData.labelObject = newLabel;
|
|
11438
11942
|
mesh.userData.name = newName;
|
|
11943
|
+
if (newRawTitle !== void 0) {
|
|
11944
|
+
mesh.userData.raw_title = newRawTitle;
|
|
11945
|
+
}
|
|
11439
11946
|
};
|
|
11440
11947
|
const handleDetailNodeColorChange = (nodeId, newColor) => {
|
|
11441
11948
|
var _a2;
|
|
@@ -11526,15 +12033,10 @@ function XViewScene({
|
|
|
11526
12033
|
creationMode,
|
|
11527
12034
|
versionMode,
|
|
11528
12035
|
questMode,
|
|
11529
|
-
// <-- Adicionado
|
|
11530
12036
|
sceneSaveUrl,
|
|
11531
|
-
// <-- Adicionado
|
|
11532
12037
|
sceneConfigId,
|
|
11533
|
-
// <-- Adicionado
|
|
11534
12038
|
ownerId,
|
|
11535
|
-
// <-- Adicionado
|
|
11536
12039
|
viewType: viewParams == null ? void 0 : viewParams.type,
|
|
11537
|
-
// <-- Adicionado
|
|
11538
12040
|
userId: (_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id,
|
|
11539
12041
|
setters: {
|
|
11540
12042
|
setContextMenu,
|
|
@@ -11548,7 +12050,6 @@ function XViewScene({
|
|
|
11548
12050
|
setSceneVersion,
|
|
11549
12051
|
setAncestryMode,
|
|
11550
12052
|
setQuestMode
|
|
11551
|
-
// <-- Adicionado
|
|
11552
12053
|
},
|
|
11553
12054
|
tweenToTarget,
|
|
11554
12055
|
handleVersionTimeline,
|
|
@@ -11582,9 +12083,30 @@ function XViewScene({
|
|
|
11582
12083
|
const handleStartVersioning = (nodeData) => {
|
|
11583
12084
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
11584
12085
|
};
|
|
12086
|
+
const handleCancelQuest = useCallback4(() => {
|
|
12087
|
+
const { graphGroup, ghostElements } = stateRef.current;
|
|
12088
|
+
if (ghostElements.node && graphGroup) {
|
|
12089
|
+
if (ghostElements.node.userData.labelObject) {
|
|
12090
|
+
graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
12091
|
+
if (ghostElements.node.userData.labelObject.material.map) ghostElements.node.userData.labelObject.material.map.dispose();
|
|
12092
|
+
ghostElements.node.userData.labelObject.material.dispose();
|
|
12093
|
+
}
|
|
12094
|
+
graphGroup.remove(ghostElements.node);
|
|
12095
|
+
ghostElements.node.traverse((child) => {
|
|
12096
|
+
if (child.material) {
|
|
12097
|
+
if (Array.isArray(child.material)) child.material.forEach((m) => m.dispose());
|
|
12098
|
+
else child.material.dispose();
|
|
12099
|
+
}
|
|
12100
|
+
if (child.geometry) child.geometry.dispose();
|
|
12101
|
+
});
|
|
12102
|
+
}
|
|
12103
|
+
stateRef.current.ghostElements = { node: null, line: null, aura: null };
|
|
12104
|
+
setQuestMode({ isActive: false });
|
|
12105
|
+
}, []);
|
|
11585
12106
|
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
11586
12107
|
const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
|
|
11587
12108
|
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
12109
|
+
const currentCounter = sceneDataRef2.current.quest_counter || 1;
|
|
11588
12110
|
const newNode = {
|
|
11589
12111
|
id: short2.generate(),
|
|
11590
12112
|
...newQuestData,
|
|
@@ -11595,33 +12117,30 @@ function XViewScene({
|
|
|
11595
12117
|
graphDataRef.current[sceneConfigId2] = { nodes: [], links: [] };
|
|
11596
12118
|
}
|
|
11597
12119
|
graphDataRef.current[sceneConfigId2].nodes.push(newNode);
|
|
11598
|
-
sceneDataRef2.current.nodes.push(newNode);
|
|
11599
|
-
const currentVisualNodes = Object.values(stateRef2.current.nodeObjects).map((mesh) => {
|
|
11600
|
-
const { _baseEmissiveIntensity, labelObject, labelOffset, timelineIntervalBar, timelineEndLabel, ...rest } = mesh.userData;
|
|
11601
|
-
return rest;
|
|
11602
|
-
});
|
|
11603
|
-
currentVisualNodes.push(newNode);
|
|
11604
|
-
const currentVisualLinks = stateRef2.current.allLinks.map((line) => {
|
|
11605
|
-
const { sourceNode, targetNode, ...rest } = line.userData;
|
|
11606
|
-
return rest;
|
|
11607
|
-
});
|
|
11608
12120
|
const sceneFileData = {
|
|
11609
12121
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11610
|
-
nodes:
|
|
11611
|
-
|
|
12122
|
+
nodes: sceneDataRef2.current.nodes,
|
|
12123
|
+
// Permanece intacto, como estava no último save de cena inicial
|
|
12124
|
+
links: sceneDataRef2.current.links,
|
|
11612
12125
|
quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
|
|
11613
|
-
quest_links: graphDataRef.current[sceneConfigId2].links
|
|
12126
|
+
quest_links: graphDataRef.current[sceneConfigId2].links,
|
|
12127
|
+
quest_counter: currentCounter + 1
|
|
11614
12128
|
};
|
|
11615
12129
|
try {
|
|
11616
12130
|
await actions.save_view_data(sceneSaveUrl2, sceneFileData);
|
|
12131
|
+
sceneDataRef2.current.quest_counter = currentCounter + 1;
|
|
11617
12132
|
stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
|
|
11618
12133
|
parentFileId: sceneConfigId2,
|
|
11619
12134
|
ownerId: ownerId2,
|
|
11620
12135
|
datasetName: "Quests Internas (View)"
|
|
11621
12136
|
});
|
|
11622
|
-
const
|
|
11623
|
-
const
|
|
11624
|
-
|
|
12137
|
+
const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
|
|
12138
|
+
const { graphGroup, ghostElements } = stateRef2.current;
|
|
12139
|
+
if (ghostElements.node && graphGroup) {
|
|
12140
|
+
if (ghostElements.node.userData.labelObject) graphGroup.remove(ghostElements.node.userData.labelObject);
|
|
12141
|
+
graphGroup.remove(ghostElements.node);
|
|
12142
|
+
}
|
|
12143
|
+
stateRef2.current.ghostElements = { node: null, line: null, aura: null };
|
|
11625
12144
|
addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
|
|
11626
12145
|
context.tweenToTarget(finalPosition, 1.2);
|
|
11627
12146
|
setters.setQuestMode({ isActive: false });
|
|
@@ -11632,19 +12151,19 @@ function XViewScene({
|
|
|
11632
12151
|
}
|
|
11633
12152
|
};
|
|
11634
12153
|
userActionHandlers.handleCompleteConnection = async (context, targetNodeData) => {
|
|
11635
|
-
const { stateRef: stateRef2, graphDataRef, sceneDataRef: sceneDataRef2, sceneConfigId: sceneConfigId2, sceneSaveUrl: sceneSaveUrl2 } = context;
|
|
12154
|
+
const { stateRef: stateRef2, graphDataRef, sceneDataRef: sceneDataRef2, sceneConfigId: sceneConfigId2, sceneSaveUrl: sceneSaveUrl2, ownerId: ownerId2 } = context;
|
|
11636
12155
|
const { sourceNodeData } = stateRef2.current.connection;
|
|
11637
12156
|
if (!graphDataRef.current || !sceneDataRef2.current || !sourceNodeData || !targetNodeData) {
|
|
11638
12157
|
userActionHandlers.handleCancelConnection(context);
|
|
11639
12158
|
return;
|
|
11640
12159
|
}
|
|
11641
|
-
const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2,
|
|
11642
|
-
const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2,
|
|
12160
|
+
const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2, ownerId2);
|
|
12161
|
+
const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2, ownerId2);
|
|
11643
12162
|
let parentInfoToSave = sourceParentInfo;
|
|
11644
|
-
|
|
11645
|
-
|
|
11646
|
-
|
|
11647
|
-
parentInfoToSave =
|
|
12163
|
+
const isSourceQuest = sourceParentInfo.parentFileId === sceneConfigId2;
|
|
12164
|
+
const isTargetQuest = targetParentInfo.parentFileId === sceneConfigId2;
|
|
12165
|
+
if (isSourceQuest || isTargetQuest) {
|
|
12166
|
+
parentInfoToSave = { parentFileId: sceneConfigId2, ownerId: ownerId2 };
|
|
11648
12167
|
}
|
|
11649
12168
|
const { parentFileId: parentFileIdToSave, ownerId: ownerIdToSave } = parentInfoToSave;
|
|
11650
12169
|
const newLink = {
|
|
@@ -11656,22 +12175,12 @@ function XViewScene({
|
|
|
11656
12175
|
if (parentFileIdToSave === sceneConfigId2) {
|
|
11657
12176
|
const specificParentData = graphDataRef.current[sceneConfigId2];
|
|
11658
12177
|
specificParentData.links.push(newLink);
|
|
11659
|
-
const currentVisualNodes = Object.values(stateRef2.current.nodeObjects).map((m) => {
|
|
11660
|
-
const { _baseEmissiveIntensity, labelObject, labelOffset, timelineIntervalBar, timelineEndLabel, ...rest } = m.userData;
|
|
11661
|
-
return rest;
|
|
11662
|
-
});
|
|
11663
|
-
const currentVisualLinks = stateRef2.current.allLinks.map((l) => {
|
|
11664
|
-
const { sourceNode, targetNode, ...rest } = l.userData;
|
|
11665
|
-
return rest;
|
|
11666
|
-
});
|
|
11667
|
-
currentVisualLinks.push(newLink);
|
|
11668
12178
|
const viewFilePayload = {
|
|
11669
12179
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11670
|
-
nodes:
|
|
11671
|
-
links:
|
|
12180
|
+
nodes: sceneDataRef2.current.nodes,
|
|
12181
|
+
links: sceneDataRef2.current.links,
|
|
11672
12182
|
quest_nodes: specificParentData.nodes,
|
|
11673
12183
|
quest_links: specificParentData.links
|
|
11674
|
-
// Salva a conexão aqui!
|
|
11675
12184
|
};
|
|
11676
12185
|
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
11677
12186
|
} else {
|
|
@@ -12936,7 +13445,7 @@ function XViewScene({
|
|
|
12936
13445
|
const allTypes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes.flatMap((node) => {
|
|
12937
13446
|
if (Array.isArray(node.type)) return node.type;
|
|
12938
13447
|
return [node.type];
|
|
12939
|
-
})).filter(Boolean);
|
|
13448
|
+
})).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
|
|
12940
13449
|
return [...new Set(allTypes)];
|
|
12941
13450
|
}, [parentDataRef.current, sceneVersion]);
|
|
12942
13451
|
const searchableDbNodes = useMemo12(() => {
|
|
@@ -12955,7 +13464,7 @@ function XViewScene({
|
|
|
12955
13464
|
[actionHandlerContext]
|
|
12956
13465
|
);
|
|
12957
13466
|
const handleSaveCurrentView = useCallback4(async () => {
|
|
12958
|
-
var _a2, _b2;
|
|
13467
|
+
var _a2, _b2, _c2;
|
|
12959
13468
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
12960
13469
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
12961
13470
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12977,20 +13486,22 @@ function XViewScene({
|
|
|
12977
13486
|
const { sourceNode, targetNode, ...serializableLinkData } = line.userData;
|
|
12978
13487
|
return serializableLinkData;
|
|
12979
13488
|
});
|
|
13489
|
+
sceneDataRef.current.nodes = currentNodes;
|
|
13490
|
+
sceneDataRef.current.links = currentLinks;
|
|
13491
|
+
const isView = ((_a2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _a2.toLowerCase()) === "view";
|
|
12980
13492
|
const sceneFileData = {
|
|
12981
13493
|
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
12982
13494
|
nodes: currentNodes,
|
|
12983
13495
|
links: currentLinks,
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
quest_links: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.links) || []
|
|
13496
|
+
quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
|
|
13497
|
+
quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || []
|
|
12987
13498
|
};
|
|
12988
13499
|
try {
|
|
12989
13500
|
await save_view_data(sceneSaveUrl, sceneFileData);
|
|
12990
13501
|
} catch (error) {
|
|
12991
13502
|
console.error("Erro na chamada de save_view_data:", error);
|
|
12992
13503
|
}
|
|
12993
|
-
}, [sceneSaveUrl, save_view_data, sceneConfigId]);
|
|
13504
|
+
}, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
|
|
12994
13505
|
const allAvailableNodes = useMemo12(() => {
|
|
12995
13506
|
if (!parentDataRef.current) return [];
|
|
12996
13507
|
return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
|
|
@@ -13047,7 +13558,7 @@ function XViewScene({
|
|
|
13047
13558
|
}, [sceneVersion, isInitialized]);
|
|
13048
13559
|
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
|
|
13049
13560
|
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
13050
|
-
|
|
13561
|
+
useEffect22(() => {
|
|
13051
13562
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
13052
13563
|
const nodeObjects = stateRef.current.nodeObjects || {};
|
|
13053
13564
|
const targetMesh = nodeObjects[String(focusNodeId)];
|
|
@@ -13061,7 +13572,7 @@ function XViewScene({
|
|
|
13061
13572
|
}
|
|
13062
13573
|
}
|
|
13063
13574
|
}, [isInitialized, sceneVersion, focusNodeId, hasFocusedInitial, tweenToTarget]);
|
|
13064
|
-
|
|
13575
|
+
useEffect22(() => {
|
|
13065
13576
|
if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
|
|
13066
13577
|
const ancestries = ancestryDataRef.current || [];
|
|
13067
13578
|
const targetAncestry = ancestries.find((a) => String(a.ancestry_id) === String(focusAncestryId));
|
|
@@ -13075,21 +13586,121 @@ function XViewScene({
|
|
|
13075
13586
|
}
|
|
13076
13587
|
}
|
|
13077
13588
|
}, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
|
|
13589
|
+
useEffect22(() => {
|
|
13590
|
+
function handleKeyDown(event) {
|
|
13591
|
+
var _a2, _b2, _c2;
|
|
13592
|
+
const context = actionHandlerContext;
|
|
13593
|
+
if (event.key === "Escape") {
|
|
13594
|
+
if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
|
|
13595
|
+
if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
|
|
13596
|
+
if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
|
|
13597
|
+
if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
|
|
13598
|
+
if (stateRef.current.ancestry.isActive) {
|
|
13599
|
+
setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
13600
|
+
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
13601
|
+
}
|
|
13602
|
+
if (questMode.isActive) {
|
|
13603
|
+
handleCancelQuest();
|
|
13604
|
+
}
|
|
13605
|
+
if (stateRef.current.selectedNodes.size > 0) {
|
|
13606
|
+
stateRef.current.selectedNodes.clear();
|
|
13607
|
+
}
|
|
13608
|
+
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
13609
|
+
setMultiContextMenu((prev) => ({ ...prev, visible: false }));
|
|
13610
|
+
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
13611
|
+
}
|
|
13612
|
+
if (event.key.toLowerCase() === "q") {
|
|
13613
|
+
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
|
|
13614
|
+
if (isUiClear) {
|
|
13615
|
+
const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
|
|
13616
|
+
if (!isView) return;
|
|
13617
|
+
const { graphGroup, glowTexture, controls, nodeObjects } = stateRef.current;
|
|
13618
|
+
if (graphGroup) {
|
|
13619
|
+
let ghostPosition = controls.target.clone();
|
|
13620
|
+
const existingNodes = Object.values(nodeObjects);
|
|
13621
|
+
let isOccupied = true;
|
|
13622
|
+
let radius = 18;
|
|
13623
|
+
let angle = 0;
|
|
13624
|
+
let attempts = 0;
|
|
13625
|
+
const MIN_CLEARANCE = 15;
|
|
13626
|
+
while (isOccupied && attempts < 30) {
|
|
13627
|
+
isOccupied = existingNodes.some((mesh) => mesh.position.distanceTo(ghostPosition) < MIN_CLEARANCE);
|
|
13628
|
+
if (isOccupied) {
|
|
13629
|
+
ghostPosition.x = controls.target.x + Math.cos(angle) * radius;
|
|
13630
|
+
ghostPosition.y = controls.target.y + (Math.random() - 0.5) * 8;
|
|
13631
|
+
ghostPosition.z = controls.target.z + Math.sin(angle) * radius;
|
|
13632
|
+
angle += Math.PI / 3;
|
|
13633
|
+
radius += 2.5;
|
|
13634
|
+
attempts++;
|
|
13635
|
+
}
|
|
13636
|
+
}
|
|
13637
|
+
const ghostData = {
|
|
13638
|
+
id: "ghost_quest",
|
|
13639
|
+
name: "Nova Quest",
|
|
13640
|
+
color: "#64748b",
|
|
13641
|
+
// Cor padrão de "Backlog"
|
|
13642
|
+
size: "medium",
|
|
13643
|
+
intensity: 0,
|
|
13644
|
+
type: ["quest"]
|
|
13645
|
+
};
|
|
13646
|
+
const ghostNode = createNodeMesh(ghostData, ghostPosition, glowTexture);
|
|
13647
|
+
ghostNode.traverse((child) => {
|
|
13648
|
+
if (child.isMesh) {
|
|
13649
|
+
child.material.transparent = true;
|
|
13650
|
+
child.material.opacity = 0.75;
|
|
13651
|
+
}
|
|
13652
|
+
});
|
|
13653
|
+
graphGroup.add(ghostNode);
|
|
13654
|
+
if (ghostNode.userData.labelObject) {
|
|
13655
|
+
graphGroup.add(ghostNode.userData.labelObject);
|
|
13656
|
+
}
|
|
13657
|
+
stateRef.current.ghostElements = {
|
|
13658
|
+
node: ghostNode,
|
|
13659
|
+
line: null,
|
|
13660
|
+
aura: ghostNode.getObjectByName("aura")
|
|
13661
|
+
};
|
|
13662
|
+
context.tweenToTarget(ghostPosition, 1.6);
|
|
13663
|
+
}
|
|
13664
|
+
setQuestMode({ isActive: true });
|
|
13665
|
+
}
|
|
13666
|
+
}
|
|
13667
|
+
}
|
|
13668
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
13669
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
13670
|
+
}, [
|
|
13671
|
+
contextMenu.visible,
|
|
13672
|
+
multiContextMenu.visible,
|
|
13673
|
+
relationshipMenu.visible,
|
|
13674
|
+
readingMode.isActive,
|
|
13675
|
+
isImportModalOpen,
|
|
13676
|
+
isAncestryBoardOpen,
|
|
13677
|
+
isSidebarOpen,
|
|
13678
|
+
detailsNode,
|
|
13679
|
+
detailsLink,
|
|
13680
|
+
ancestryLinkDetails,
|
|
13681
|
+
imageViewer.visible,
|
|
13682
|
+
editingAncestryRel.visible,
|
|
13683
|
+
questMode.isActive,
|
|
13684
|
+
viewParams,
|
|
13685
|
+
actionHandlerContext,
|
|
13686
|
+
handleCancelQuest
|
|
13687
|
+
// <-- handleCancelQuest adicionado aqui
|
|
13688
|
+
]);
|
|
13078
13689
|
if (isLoading || status === "loading" || permissionStatus === "loading") {
|
|
13079
|
-
return /* @__PURE__ */
|
|
13690
|
+
return /* @__PURE__ */ React25.createElement(LoadingScreen, null);
|
|
13080
13691
|
}
|
|
13081
13692
|
if (permissionStatus === "denied") {
|
|
13082
|
-
return /* @__PURE__ */
|
|
13693
|
+
return /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React25.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React25.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React25.createElement("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__ */ React25.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__ */ React25.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React25.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React25.createElement(
|
|
13083
13694
|
"button",
|
|
13084
13695
|
{
|
|
13085
13696
|
onClick: () => router.push("/dashboard/scenes"),
|
|
13086
13697
|
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"
|
|
13087
13698
|
},
|
|
13088
|
-
/* @__PURE__ */
|
|
13699
|
+
/* @__PURE__ */ React25.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__ */ React25.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" })),
|
|
13089
13700
|
"Voltar para Scenes"
|
|
13090
13701
|
)));
|
|
13091
13702
|
}
|
|
13092
|
-
return /* @__PURE__ */
|
|
13703
|
+
return /* @__PURE__ */ React25.createElement(
|
|
13093
13704
|
"div",
|
|
13094
13705
|
{
|
|
13095
13706
|
ref: mountRef,
|
|
@@ -13101,7 +13712,7 @@ function XViewScene({
|
|
|
13101
13712
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
13102
13713
|
}
|
|
13103
13714
|
},
|
|
13104
|
-
userPermissionRole !== "link_viewer" && /* @__PURE__ */
|
|
13715
|
+
userPermissionRole !== "link_viewer" && /* @__PURE__ */ React25.createElement(
|
|
13105
13716
|
XViewSidebar,
|
|
13106
13717
|
{
|
|
13107
13718
|
dbNodes: searchableDbNodes,
|
|
@@ -13121,7 +13732,7 @@ function XViewScene({
|
|
|
13121
13732
|
userRole: userPermissionRole
|
|
13122
13733
|
}
|
|
13123
13734
|
),
|
|
13124
|
-
creationMode.isActive && /* @__PURE__ */
|
|
13735
|
+
creationMode.isActive && /* @__PURE__ */ React25.createElement(
|
|
13125
13736
|
InSceneCreationForm,
|
|
13126
13737
|
{
|
|
13127
13738
|
onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
|
|
@@ -13146,7 +13757,7 @@ function XViewScene({
|
|
|
13146
13757
|
availableAncestries: allAvailableAncestries
|
|
13147
13758
|
}
|
|
13148
13759
|
),
|
|
13149
|
-
versionMode.isActive && /* @__PURE__ */
|
|
13760
|
+
versionMode.isActive && /* @__PURE__ */ React25.createElement(
|
|
13150
13761
|
InSceneVersionForm,
|
|
13151
13762
|
{
|
|
13152
13763
|
onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
|
|
@@ -13165,27 +13776,32 @@ function XViewScene({
|
|
|
13165
13776
|
availableAncestries: allAvailableAncestries
|
|
13166
13777
|
}
|
|
13167
13778
|
),
|
|
13168
|
-
questMode.isActive && /* @__PURE__ */
|
|
13779
|
+
questMode.isActive && /* @__PURE__ */ React25.createElement(
|
|
13169
13780
|
InSceneQuestForm,
|
|
13170
13781
|
{
|
|
13171
13782
|
onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
|
|
13172
|
-
onCancel:
|
|
13783
|
+
onCancel: handleCancelQuest,
|
|
13784
|
+
onNameChange: handleGhostNodeNameChange,
|
|
13785
|
+
onColorChange: handleGhostNodeColorChange,
|
|
13786
|
+
onSizeChange: handleGhostNodeSizeChange,
|
|
13173
13787
|
style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
13174
13788
|
refEl: formRef,
|
|
13175
13789
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13176
13790
|
onMentionClick: handleAddExistingNode,
|
|
13177
13791
|
onUploadFile: upload_file_action,
|
|
13178
13792
|
availableNodes: allAvailableNodes,
|
|
13179
|
-
availableAncestries: allAvailableAncestries
|
|
13793
|
+
availableAncestries: allAvailableAncestries,
|
|
13794
|
+
viewName: viewParams == null ? void 0 : viewParams.name,
|
|
13795
|
+
questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1
|
|
13180
13796
|
}
|
|
13181
13797
|
),
|
|
13182
|
-
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */
|
|
13798
|
+
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React25.createElement(
|
|
13183
13799
|
"div",
|
|
13184
13800
|
{
|
|
13185
13801
|
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"}`,
|
|
13186
13802
|
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
13187
13803
|
},
|
|
13188
|
-
/* @__PURE__ */
|
|
13804
|
+
/* @__PURE__ */ React25.createElement(
|
|
13189
13805
|
"div",
|
|
13190
13806
|
{
|
|
13191
13807
|
onPointerDown: (e) => {
|
|
@@ -13196,7 +13812,7 @@ function XViewScene({
|
|
|
13196
13812
|
title: "Arraste para redimensionar"
|
|
13197
13813
|
}
|
|
13198
13814
|
),
|
|
13199
|
-
/* @__PURE__ */
|
|
13815
|
+
/* @__PURE__ */ React25.createElement(
|
|
13200
13816
|
DescriptionReadModePanel,
|
|
13201
13817
|
{
|
|
13202
13818
|
key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
|
|
@@ -13231,7 +13847,7 @@ function XViewScene({
|
|
|
13231
13847
|
}
|
|
13232
13848
|
)
|
|
13233
13849
|
),
|
|
13234
|
-
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */
|
|
13850
|
+
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React25.createElement(
|
|
13235
13851
|
CreateAncestryPanel,
|
|
13236
13852
|
{
|
|
13237
13853
|
ancestryMode,
|
|
@@ -13258,7 +13874,7 @@ function XViewScene({
|
|
|
13258
13874
|
onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
|
|
13259
13875
|
}
|
|
13260
13876
|
),
|
|
13261
|
-
editingAncestryRel.visible && /* @__PURE__ */
|
|
13877
|
+
editingAncestryRel.visible && /* @__PURE__ */ React25.createElement(
|
|
13262
13878
|
AncestryRelationshipPanel,
|
|
13263
13879
|
{
|
|
13264
13880
|
data: editingAncestryRel.data,
|
|
@@ -13272,7 +13888,28 @@ function XViewScene({
|
|
|
13272
13888
|
onUploadFile: upload_file_action
|
|
13273
13889
|
}
|
|
13274
13890
|
),
|
|
13275
|
-
detailsNode && /* @__PURE__ */
|
|
13891
|
+
detailsNode && detailsNode.is_quest && /* @__PURE__ */ React25.createElement(
|
|
13892
|
+
QuestDetailsPanel,
|
|
13893
|
+
{
|
|
13894
|
+
node: detailsNode,
|
|
13895
|
+
onClose: () => setDetailsNode(null),
|
|
13896
|
+
onSave: (data) => userActionHandlers.handleSaveNodeDetails(actionHandlerContext, data),
|
|
13897
|
+
onNameChange: handleDetailNodeNameChange,
|
|
13898
|
+
onColorChange: handleDetailNodeColorChange,
|
|
13899
|
+
onSizeChange: handleDetailNodeSizeChange,
|
|
13900
|
+
onDataUpdate: setDetailsNode,
|
|
13901
|
+
onOpenImageViewer: handleOpenImageViewer,
|
|
13902
|
+
existingTypes: existingNodeTypes,
|
|
13903
|
+
availableNodes: allAvailableNodes,
|
|
13904
|
+
availableAncestries: allAvailableAncestries,
|
|
13905
|
+
onOpenReference: handleOpenReference,
|
|
13906
|
+
onMentionClick: handleAddExistingNode,
|
|
13907
|
+
onUploadFile: upload_file_action,
|
|
13908
|
+
userRole: userPermissionRole,
|
|
13909
|
+
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
13910
|
+
}
|
|
13911
|
+
),
|
|
13912
|
+
detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React25.createElement(
|
|
13276
13913
|
NodeDetailsPanel,
|
|
13277
13914
|
{
|
|
13278
13915
|
node: detailsNode,
|
|
@@ -13299,7 +13936,7 @@ function XViewScene({
|
|
|
13299
13936
|
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
13300
13937
|
}
|
|
13301
13938
|
),
|
|
13302
|
-
detailsLink && /* @__PURE__ */
|
|
13939
|
+
detailsLink && /* @__PURE__ */ React25.createElement(
|
|
13303
13940
|
RelationshipDetailsPanel,
|
|
13304
13941
|
{
|
|
13305
13942
|
link: detailsLink,
|
|
@@ -13313,7 +13950,7 @@ function XViewScene({
|
|
|
13313
13950
|
userRole: userPermissionRole
|
|
13314
13951
|
}
|
|
13315
13952
|
),
|
|
13316
|
-
ancestryLinkDetails && /* @__PURE__ */
|
|
13953
|
+
ancestryLinkDetails && /* @__PURE__ */ React25.createElement(
|
|
13317
13954
|
AncestryLinkDetailsPanel,
|
|
13318
13955
|
{
|
|
13319
13956
|
data: ancestryLinkDetails,
|
|
@@ -13324,7 +13961,7 @@ function XViewScene({
|
|
|
13324
13961
|
onUploadFile: upload_file_action
|
|
13325
13962
|
}
|
|
13326
13963
|
),
|
|
13327
|
-
/* @__PURE__ */
|
|
13964
|
+
/* @__PURE__ */ React25.createElement(
|
|
13328
13965
|
"div",
|
|
13329
13966
|
{
|
|
13330
13967
|
ref: tooltipRef,
|
|
@@ -13351,7 +13988,7 @@ function XViewScene({
|
|
|
13351
13988
|
}
|
|
13352
13989
|
}
|
|
13353
13990
|
),
|
|
13354
|
-
/* @__PURE__ */
|
|
13991
|
+
/* @__PURE__ */ React25.createElement(
|
|
13355
13992
|
ContextMenu,
|
|
13356
13993
|
{
|
|
13357
13994
|
data: contextMenu,
|
|
@@ -13374,7 +14011,7 @@ function XViewScene({
|
|
|
13374
14011
|
onFocusNode: handleFocusNode
|
|
13375
14012
|
}
|
|
13376
14013
|
),
|
|
13377
|
-
/* @__PURE__ */
|
|
14014
|
+
/* @__PURE__ */ React25.createElement(
|
|
13378
14015
|
MultiNodeContextMenu,
|
|
13379
14016
|
{
|
|
13380
14017
|
data: multiContextMenu,
|
|
@@ -13385,7 +14022,7 @@ function XViewScene({
|
|
|
13385
14022
|
onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
|
|
13386
14023
|
}
|
|
13387
14024
|
),
|
|
13388
|
-
/* @__PURE__ */
|
|
14025
|
+
/* @__PURE__ */ React25.createElement(
|
|
13389
14026
|
RelationshipContextMenu,
|
|
13390
14027
|
{
|
|
13391
14028
|
data: relationshipMenu,
|
|
@@ -13403,8 +14040,8 @@ function XViewScene({
|
|
|
13403
14040
|
onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
|
|
13404
14041
|
}
|
|
13405
14042
|
),
|
|
13406
|
-
/* @__PURE__ */
|
|
13407
|
-
/* @__PURE__ */
|
|
14043
|
+
/* @__PURE__ */ React25.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
|
|
14044
|
+
/* @__PURE__ */ React25.createElement(
|
|
13408
14045
|
AncestryBoard,
|
|
13409
14046
|
{
|
|
13410
14047
|
isOpen: isAncestryBoardOpen,
|
|
@@ -13417,14 +14054,14 @@ function XViewScene({
|
|
|
13417
14054
|
userRole: userPermissionRole
|
|
13418
14055
|
}
|
|
13419
14056
|
),
|
|
13420
|
-
/* @__PURE__ */
|
|
14057
|
+
/* @__PURE__ */ React25.createElement(
|
|
13421
14058
|
ImportParentFileModal,
|
|
13422
14059
|
{
|
|
13423
14060
|
isOpen: isImportModalOpen,
|
|
13424
14061
|
onClose: () => setIsImportModalOpen(false),
|
|
13425
14062
|
onConfirm: handleConfirmImport,
|
|
13426
14063
|
session,
|
|
13427
|
-
parentDbs: ((
|
|
14064
|
+
parentDbs: ((_h = sceneDataRef.current) == null ? void 0 : _h.parent_dbs) || [],
|
|
13428
14065
|
onFetchAvailableFiles: import_parent_file_modal_get,
|
|
13429
14066
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
13430
14067
|
currentAncestries: ancestryDataRef.current || []
|
|
@@ -13461,6 +14098,12 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
|
|
|
13461
14098
|
}
|
|
13462
14099
|
const sceneData = sceneResponse.data;
|
|
13463
14100
|
const parentDbObjects = sceneData.parent_dbs || [];
|
|
14101
|
+
if (type && type.toLowerCase().includes("database")) {
|
|
14102
|
+
const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
|
|
14103
|
+
if (!selfExists) {
|
|
14104
|
+
parentDbObjects.push({ db_id: scene_config, owner_id });
|
|
14105
|
+
}
|
|
14106
|
+
}
|
|
13464
14107
|
const parentResponsesPromises = parentDbObjects.map(
|
|
13465
14108
|
(db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
|
|
13466
14109
|
);
|
|
@@ -13478,21 +14121,32 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
|
|
|
13478
14121
|
);
|
|
13479
14122
|
}
|
|
13480
14123
|
}
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
14124
|
+
if (type && type.toLowerCase() === "view") {
|
|
14125
|
+
parentData[scene_config] = {
|
|
14126
|
+
dataset_name: "Quests Internas (View)",
|
|
14127
|
+
nodes: sceneData.quest_nodes || [],
|
|
14128
|
+
links: sceneData.quest_links || []
|
|
14129
|
+
};
|
|
14130
|
+
}
|
|
13486
14131
|
const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
13487
14132
|
const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
|
|
13488
14133
|
const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
|
|
13489
14134
|
const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
|
|
13490
14135
|
const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
|
|
14136
|
+
var _a2, _b2;
|
|
13491
14137
|
const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
|
|
13492
14138
|
if (nodeTypes.includes("quest")) {
|
|
14139
|
+
const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
|
|
14140
|
+
if (dbQuestNode) {
|
|
14141
|
+
return { ...sceneNode, ...dbQuestNode };
|
|
14142
|
+
}
|
|
13493
14143
|
return sceneNode;
|
|
13494
14144
|
}
|
|
13495
|
-
|
|
14145
|
+
const dbNode = parentNodeMap.get(String(sceneNode.id));
|
|
14146
|
+
if (dbNode) {
|
|
14147
|
+
return { ...sceneNode, ...dbNode };
|
|
14148
|
+
}
|
|
14149
|
+
return null;
|
|
13496
14150
|
}).filter(Boolean);
|
|
13497
14151
|
const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
|
|
13498
14152
|
const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
|