@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.js
CHANGED
|
@@ -43,9 +43,9 @@ __export(index_exports, {
|
|
|
43
43
|
module.exports = __toCommonJS(index_exports);
|
|
44
44
|
|
|
45
45
|
// src/XViewScene.jsx
|
|
46
|
-
var
|
|
46
|
+
var import_react26 = __toESM(require("react"));
|
|
47
47
|
var import_navigation = require("next/navigation");
|
|
48
|
-
var
|
|
48
|
+
var import_react27 = require("next-auth/react");
|
|
49
49
|
var import_crypto_js = __toESM(require("crypto-js"));
|
|
50
50
|
var THREE3 = __toESM(require("three"));
|
|
51
51
|
var import_OrbitControls = require("three/examples/jsm/controls/OrbitControls.js");
|
|
@@ -116,6 +116,13 @@ function defineAbilityFor(role) {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
// src/components/ContextMenu.jsx
|
|
119
|
+
var QUEST_STATUS_COLORS = {
|
|
120
|
+
"Backlog": "#64748b",
|
|
121
|
+
"In Progress": "#eab308",
|
|
122
|
+
"Review": "#a855f7",
|
|
123
|
+
"Done": "#22c55e"
|
|
124
|
+
};
|
|
125
|
+
var QUEST_STATUSES = ["Backlog", "In Progress", "Review", "Done"];
|
|
119
126
|
function ContextMenu({
|
|
120
127
|
data,
|
|
121
128
|
userRole,
|
|
@@ -136,19 +143,21 @@ function ContextMenu({
|
|
|
136
143
|
onFocusNode,
|
|
137
144
|
onClose
|
|
138
145
|
}) {
|
|
139
|
-
var _a, _b;
|
|
146
|
+
var _a, _b, _c;
|
|
140
147
|
const menuRef = (0, import_react.useRef)(null);
|
|
141
148
|
const [menuPos, setMenuPos] = (0, import_react.useState)({ left: 0, top: 0 });
|
|
142
149
|
const [menuView, setMenuView] = (0, import_react.useState)("main");
|
|
143
150
|
const [selectedAncestry, setSelectedAncestry] = (0, import_react.useState)(null);
|
|
144
151
|
const [versionSubMenu, setVersionSubMenu] = (0, import_react.useState)(null);
|
|
145
152
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react.useState)(false);
|
|
153
|
+
const [selectedQuestStatus, setSelectedQuestStatus] = (0, import_react.useState)(null);
|
|
146
154
|
const ability = (0, import_react.useMemo)(() => defineAbilityFor(userRole), [userRole]);
|
|
147
155
|
(0, import_react.useEffect)(() => {
|
|
148
156
|
if (data.visible) {
|
|
149
157
|
setMenuView("main");
|
|
150
158
|
setSelectedAncestry(null);
|
|
151
159
|
setVersionSubMenu(null);
|
|
160
|
+
setSelectedQuestStatus(null);
|
|
152
161
|
}
|
|
153
162
|
}, [data.visible, (_a = data.nodeData) == null ? void 0 : _a.id]);
|
|
154
163
|
(0, import_react.useLayoutEffect)(() => {
|
|
@@ -163,7 +172,7 @@ function ContextMenu({
|
|
|
163
172
|
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
164
173
|
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
165
174
|
setMenuPos({ left, top });
|
|
166
|
-
}, [data, menuView, versionSubMenu]);
|
|
175
|
+
}, [data, menuView, versionSubMenu, selectedQuestStatus]);
|
|
167
176
|
(0, import_react.useEffect)(() => {
|
|
168
177
|
if (!data.visible) return;
|
|
169
178
|
const handleClickOutside = (e) => {
|
|
@@ -206,7 +215,16 @@ function ContextMenu({
|
|
|
206
215
|
var _a2;
|
|
207
216
|
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));
|
|
208
217
|
});
|
|
209
|
-
const
|
|
218
|
+
const isCurrentNodeQuest = ((_c = data.nodeData) == null ? void 0 : _c.is_quest) === true;
|
|
219
|
+
const commonConnections = isCurrentNodeQuest ? connections : connections.filter((c) => {
|
|
220
|
+
var _a2;
|
|
221
|
+
return !((_a2 = c.targetNode) == null ? void 0 : _a2.is_quest);
|
|
222
|
+
});
|
|
223
|
+
const questConnections = isCurrentNodeQuest ? [] : connections.filter((c) => {
|
|
224
|
+
var _a2;
|
|
225
|
+
return (_a2 = c.targetNode) == null ? void 0 : _a2.is_quest;
|
|
226
|
+
});
|
|
227
|
+
const groupedConnections = commonConnections.reduce((acc, conn) => {
|
|
210
228
|
var _a2;
|
|
211
229
|
const { targetNode } = conn;
|
|
212
230
|
const groupingKey = ((_a2 = targetNode.version_node) == null ? void 0 : _a2.is_version) ? targetNode.version_node.parent_node : targetNode.id;
|
|
@@ -242,6 +260,20 @@ function ContextMenu({
|
|
|
242
260
|
};
|
|
243
261
|
}
|
|
244
262
|
}).filter(Boolean);
|
|
263
|
+
const questsByStatus = {
|
|
264
|
+
"Backlog": [],
|
|
265
|
+
"In Progress": [],
|
|
266
|
+
"Review": [],
|
|
267
|
+
"Done": []
|
|
268
|
+
};
|
|
269
|
+
questConnections.forEach((conn) => {
|
|
270
|
+
const status = conn.targetNode.status || "Backlog";
|
|
271
|
+
if (questsByStatus[status]) {
|
|
272
|
+
questsByStatus[status].push(conn);
|
|
273
|
+
} else {
|
|
274
|
+
questsByStatus["Backlog"].push(conn);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
245
277
|
const availableAncestries = (ancestryData || []).filter(
|
|
246
278
|
(ancestry) => String(ancestry.ancestral_node) === String(data.nodeData.id)
|
|
247
279
|
);
|
|
@@ -294,11 +326,12 @@ function ContextMenu({
|
|
|
294
326
|
});
|
|
295
327
|
};
|
|
296
328
|
const renderMainView = () => {
|
|
329
|
+
var _a2;
|
|
297
330
|
const hasVersions = computedVersions.length > 0;
|
|
298
331
|
const canCreateVersion = ability.can("create", "Versioning");
|
|
299
332
|
const canReadVersion = ability.can("read", "Versioning");
|
|
300
333
|
const shouldShowVersioningBtn = canCreateVersion || canReadVersion && hasVersions;
|
|
301
|
-
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("span", null, "Conectar")), ability.can("create", "Node") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ import_react.default.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
334
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, ability.can("create", "Connection") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartConnection == null ? void 0 : onStartConnection(data.nodeData), className: baseButtonClass, title: "Conectar" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("span", null, "Conectar")), ability.can("create", "Node") && !((_a2 = data.nodeData) == null ? void 0 : _a2.is_quest) && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartCreation == null ? void 0 : onStartCreation(data.nodeData), className: baseButtonClass, title: "Criar e Conectar" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "16" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "8", y1: "12", x2: "16", y2: "12" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar e Conectar")), ability.can("create", "Ancestry") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onStartAncestryCreation == null ? void 0 : onStartAncestryCreation(data.nodeData), className: baseButtonClass, title: "Criar Ancestralidade" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M10 16v-3a2 2 0 0 1 2-2h4" }), /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M14 8v3a2 2 0 0 0 2 2h4" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Criar Ancestralidade")), shouldShowVersioningBtn && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("versioning"), className: baseButtonClass, title: hasVersions ? "Versionamento" : "Criar Versionamento" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("line", { x1: "6", y1: "3", x2: "6", y2: "15" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })), /* @__PURE__ */ import_react.default.createElement("span", null, hasVersions || !canCreateVersion ? "Versionamento" : "Criar Versionamento")), (connections.length > 0 || availableAncestries.length > 0) && ability.can("read", "Connection") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: baseButtonClass, title: "Conex\xF5es" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M8 12h8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 8v8" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Conex\xF5es (", totalConnectionsCount, ")"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => {
|
|
302
335
|
onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
|
|
303
336
|
onClose();
|
|
304
337
|
}, className: baseButtonClass, title: "Focar na c\xE2mera" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Focar neste Node")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: (e) => handleCopyLink(e, data.nodeData), className: baseButtonClass, title: "Copiar Link para Compartilhar" }, isLinkCopied ? /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "20 6 9 17 4 12" })) : /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("span", { className: isLinkCopied ? "text-green-400" : "" }, isLinkCopied ? "Copiado!" : "Copiar Link")), ability.can("dismiss", "Node") && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissNode == null ? void 0 : onDismissNode(data.nodeData), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss")), /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => onDismissOtherNodes == null ? void 0 : onDismissOtherNodes(data.nodeData), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Dismiss other nodes"))), ability.can("delete", "Node") && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("deleteConfirmation"), className: deleteButtonClass, title: "Excluir Node" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ import_react.default.createElement("span", null, "Excluir Node"))));
|
|
@@ -323,9 +356,9 @@ function ContextMenu({
|
|
|
323
356
|
if (versionSubMenu) {
|
|
324
357
|
return renderVersionSubMenuView();
|
|
325
358
|
}
|
|
326
|
-
const totalItems = availableAncestries.length + finalRenderableConnections.length;
|
|
359
|
+
const totalItems = availableAncestries.length + finalRenderableConnections.length + (questConnections.length > 0 ? 1 : 0);
|
|
327
360
|
const isScrollable = totalItems > 10;
|
|
328
|
-
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")),
|
|
361
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("main"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Conex\xF5es")), commonConnections.length > 0 && /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("div", { className: `flex flex-col ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-2" : ""}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wider text-indigo-400/90" }, "Ancestralidades Salvas"), availableAncestries.map((anc) => /* @__PURE__ */ import_react.default.createElement(
|
|
329
362
|
"button",
|
|
330
363
|
{
|
|
331
364
|
key: anc.ancestry_id,
|
|
@@ -335,7 +368,7 @@ function ContextMenu({
|
|
|
335
368
|
},
|
|
336
369
|
/* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("path", { d: "M6 3v4a2 2 0 0 0 2 2h4" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M18 3v4a2 2 0 0 1-2 2h-4" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "6", cy: "3", r: "2" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "18", cy: "3", r: "2" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "11", r: "2" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M12 13v6" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "21", r: "2" })),
|
|
337
370
|
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, anc.name || `Ancestralidade #${anc.ancestry_id.substring(0, 8)}`)
|
|
338
|
-
)), finalRenderableConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "
|
|
371
|
+
))), finalRenderableConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, availableAncestries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), finalRenderableConnections.map((group) => {
|
|
339
372
|
if (group.isVersionGroup) {
|
|
340
373
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
341
374
|
"button",
|
|
@@ -363,7 +396,54 @@ function ContextMenu({
|
|
|
363
396
|
group.links.length > 1 && /* @__PURE__ */ import_react.default.createElement("span", { className: "text-xs px-2 py-0.5 bg-indigo-500/20 rounded-full" }, group.links.length)
|
|
364
397
|
);
|
|
365
398
|
}
|
|
366
|
-
}))))
|
|
399
|
+
})), questConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1 mt-1" }, (availableAncestries.length > 0 || finalRenderableConnections.length > 0) && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react.default.createElement(
|
|
400
|
+
"button",
|
|
401
|
+
{
|
|
402
|
+
onClick: () => setMenuView("quest_statuses"),
|
|
403
|
+
className: baseButtonClass,
|
|
404
|
+
title: "Ver Quests Conectadas"
|
|
405
|
+
},
|
|
406
|
+
/* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "6" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "2" })),
|
|
407
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, "quests"),
|
|
408
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "text-xs px-2 py-0.5 bg-sky-500/20 text-sky-200 rounded-full" }, questConnections.length)
|
|
409
|
+
))));
|
|
410
|
+
};
|
|
411
|
+
const renderQuestStatusesView = () => {
|
|
412
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => setMenuView("connections"), className: "p-1 rounded-full hover:bg-white/10 text-slate-400 hover:text-white" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Status das Quests"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, QUEST_STATUSES.map((status) => {
|
|
413
|
+
const count = questsByStatus[status].length;
|
|
414
|
+
const color = QUEST_STATUS_COLORS[status];
|
|
415
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
416
|
+
"button",
|
|
417
|
+
{
|
|
418
|
+
key: status,
|
|
419
|
+
onClick: () => {
|
|
420
|
+
if (count > 0) {
|
|
421
|
+
setSelectedQuestStatus(status);
|
|
422
|
+
setMenuView("quest_list");
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
className: `${baseButtonClass} ${count === 0 ? "opacity-50 cursor-default hover:bg-transparent hover:text-slate-200" : ""}`
|
|
426
|
+
},
|
|
427
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "w-3 h-3 rounded-full shadow-[0_0_8px_rgba(0,0,0,0.5)]", style: { backgroundColor: color } }),
|
|
428
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, status),
|
|
429
|
+
count > 0 && /* @__PURE__ */ import_react.default.createElement("span", { className: "text-xs px-2 py-0.5 bg-white/10 rounded-full" }, count)
|
|
430
|
+
);
|
|
431
|
+
})));
|
|
432
|
+
};
|
|
433
|
+
const renderQuestListView = () => {
|
|
434
|
+
const quests = questsByStatus[selectedQuestStatus] || [];
|
|
435
|
+
const isScrollable = quests.length > 10;
|
|
436
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center justify-between gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react.default.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__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "15 18 9 12 15 6" }))), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400 truncate", title: `Quests: ${selectedQuestStatus}` }, "Quests: ", selectedQuestStatus)), quests.length > 0 && /* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, quests.map((conn) => /* @__PURE__ */ import_react.default.createElement(
|
|
437
|
+
"button",
|
|
438
|
+
{
|
|
439
|
+
key: conn.targetNode.id,
|
|
440
|
+
onClick: () => handleConnectionClick({ links: [conn.link] }),
|
|
441
|
+
className: baseButtonClass,
|
|
442
|
+
title: `Expandir Quest ${conn.targetNode.name}`
|
|
443
|
+
},
|
|
444
|
+
/* @__PURE__ */ import_react.default.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__ */ import_react.default.createElement("polyline", { points: "13 17 18 12 13 7" }), /* @__PURE__ */ import_react.default.createElement("polyline", { points: "6 17 11 12 6 7" })),
|
|
445
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
|
|
446
|
+
))));
|
|
367
447
|
};
|
|
368
448
|
const renderAncestryActionsView = () => {
|
|
369
449
|
const ancestryTitle = (selectedAncestry == null ? void 0 : selectedAncestry.name) || `Ancestralidade #${selectedAncestry == null ? void 0 : selectedAncestry.ancestry_id.substring(0, 8)}`;
|
|
@@ -426,7 +506,7 @@ function ContextMenu({
|
|
|
426
506
|
onDoubleClick: swallow
|
|
427
507
|
},
|
|
428
508
|
/* @__PURE__ */ import_react.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
429
|
-
/* @__PURE__ */ import_react.default.createElement("div", { className: "p-1.5" }, menuView === "main" && renderMainView(), menuView === "connections" && renderConnectionsView(), menuView === "ancestryActions" && renderAncestryActionsView(), menuView === "versioning" && renderVersioningView(), menuView === "deleteConfirmation" && renderDeleteConfirmationView())
|
|
509
|
+
/* @__PURE__ */ import_react.default.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())
|
|
430
510
|
);
|
|
431
511
|
}
|
|
432
512
|
|
|
@@ -504,7 +584,11 @@ function XViewSidebar({
|
|
|
504
584
|
let pool = base;
|
|
505
585
|
const qNorm = normalize(query);
|
|
506
586
|
if (qNorm) {
|
|
507
|
-
pool = pool.filter((n) =>
|
|
587
|
+
pool = pool.filter((n) => {
|
|
588
|
+
const matchName = normalize((n == null ? void 0 : n.name) || "").includes(qNorm);
|
|
589
|
+
const matchRawTitle = n.is_quest && n.raw_title ? normalize(n.raw_title).includes(qNorm) : false;
|
|
590
|
+
return matchName || matchRawTitle;
|
|
591
|
+
});
|
|
508
592
|
}
|
|
509
593
|
if (activeFilters.length > 0) {
|
|
510
594
|
pool = pool.filter((node) => {
|
|
@@ -1006,7 +1090,8 @@ var createNodeMesh = (nodeData, position, glowTexture) => {
|
|
|
1006
1090
|
const size = nodeData.size || "medium";
|
|
1007
1091
|
const scale = NODE_SCALE_FACTORS[size] || 1;
|
|
1008
1092
|
mesh.scale.set(scale, scale, scale);
|
|
1009
|
-
const
|
|
1093
|
+
const labelText = nodeData.is_quest && nodeData.raw_title ? nodeData.raw_title : nodeData.name;
|
|
1094
|
+
const label = createTextSprite(labelText);
|
|
1010
1095
|
label.name = "label";
|
|
1011
1096
|
mesh.userData.labelObject = label;
|
|
1012
1097
|
mesh.userData.labelOffset = new THREE.Vector3(0, 3.8, 0);
|
|
@@ -1111,13 +1196,15 @@ var updateExistingNodeVisuals = (state, updatedNode) => {
|
|
|
1111
1196
|
const size = updatedNode.size || "medium";
|
|
1112
1197
|
const scale = NODE_SCALE_FACTORS[size] || 1;
|
|
1113
1198
|
existingMesh.scale.set(scale, scale, scale);
|
|
1114
|
-
|
|
1199
|
+
const oldText = existingMesh.userData.is_quest && existingMesh.userData.raw_title ? existingMesh.userData.raw_title : existingMesh.userData.name;
|
|
1200
|
+
const newText = updatedNode.is_quest && updatedNode.raw_title ? updatedNode.raw_title : updatedNode.name;
|
|
1201
|
+
if (oldText !== newText) {
|
|
1115
1202
|
const oldLabelToDispose = existingMesh.userData.labelObject;
|
|
1116
1203
|
if (oldLabelToDispose && state.graphGroup) {
|
|
1117
1204
|
state.graphGroup.remove(oldLabelToDispose);
|
|
1118
1205
|
if (oldLabelToDispose.material) oldLabelToDispose.material.dispose();
|
|
1119
1206
|
}
|
|
1120
|
-
const newLabel = createTextSprite(
|
|
1207
|
+
const newLabel = createTextSprite(newText || "");
|
|
1121
1208
|
newLabel.name = "label";
|
|
1122
1209
|
existingMesh.userData.labelObject = newLabel;
|
|
1123
1210
|
if (state.graphGroup) {
|
|
@@ -1225,8 +1312,6 @@ var createMultipleLinkLines = (linksArray, sourceNodeMesh, targetNodeMesh, resol
|
|
|
1225
1312
|
targetNodeMesh,
|
|
1226
1313
|
resolution,
|
|
1227
1314
|
isCurved,
|
|
1228
|
-
isCurved,
|
|
1229
|
-
isCurved,
|
|
1230
1315
|
curveOffset
|
|
1231
1316
|
);
|
|
1232
1317
|
line.userData = {
|
|
@@ -1839,6 +1924,7 @@ var userActionHandlers = {
|
|
|
1839
1924
|
setters.setFormPosition((p) => ({ ...p, opacity: 0 }));
|
|
1840
1925
|
},
|
|
1841
1926
|
handleSaveVersionNode: async (context, newNodeData) => {
|
|
1927
|
+
var _a;
|
|
1842
1928
|
const { graphDataRef, sceneDataRef, stateRef, versionMode, setters } = context;
|
|
1843
1929
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
1844
1930
|
const { sourceNodeData } = versionMode;
|
|
@@ -1858,9 +1944,21 @@ var userActionHandlers = {
|
|
|
1858
1944
|
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileId]));
|
|
1859
1945
|
specificParentData.nodes.push(newNode);
|
|
1860
1946
|
specificParentData.links.push(newLink);
|
|
1861
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
1862
1947
|
try {
|
|
1863
|
-
|
|
1948
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
1949
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
1950
|
+
const viewFilePayload = {
|
|
1951
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
1952
|
+
nodes: sceneDataRef.current.nodes,
|
|
1953
|
+
links: sceneDataRef.current.links,
|
|
1954
|
+
quest_nodes: specificParentData.nodes,
|
|
1955
|
+
quest_links: specificParentData.links
|
|
1956
|
+
};
|
|
1957
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
1958
|
+
} else {
|
|
1959
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
1960
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
1961
|
+
}
|
|
1864
1962
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
1865
1963
|
const finalPosition = stateRef.current.ghostElements.node.position.clone();
|
|
1866
1964
|
addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
|
|
@@ -1884,10 +1982,6 @@ var userActionHandlers = {
|
|
|
1884
1982
|
var _a;
|
|
1885
1983
|
const isSource = String(link.source) === String(sourceNode.id);
|
|
1886
1984
|
const targetNodeId = isSource ? link.target : link.source;
|
|
1887
|
-
const linkAlreadyInSceneData = sceneDataRef.current.links.some((l) => String(l.id) === String(link.id));
|
|
1888
|
-
if (!linkAlreadyInSceneData) {
|
|
1889
|
-
sceneDataRef.current.links.push(link);
|
|
1890
|
-
}
|
|
1891
1985
|
if (!nodeObjects[String(targetNodeId)]) {
|
|
1892
1986
|
const allParentNodes = Object.values(graphDataRef.current).flatMap((fileData) => fileData.nodes);
|
|
1893
1987
|
const nodeData = allParentNodes.find((n) => String(n.id) === String(targetNodeId));
|
|
@@ -1895,9 +1989,6 @@ var userActionHandlers = {
|
|
|
1895
1989
|
console.warn(`Dados do Node com ID ${targetNodeId} n\xE3o encontrados no cache.`);
|
|
1896
1990
|
return;
|
|
1897
1991
|
}
|
|
1898
|
-
if (!sceneDataRef.current.nodes.some((n) => String(n.id) === String(nodeData.id))) {
|
|
1899
|
-
sceneDataRef.current.nodes.push(nodeData);
|
|
1900
|
-
}
|
|
1901
1992
|
const startPosition = sourceNodeMesh.position.clone();
|
|
1902
1993
|
const endPosition = startPosition.clone().add(
|
|
1903
1994
|
new THREE.Vector3((Math.random() - 0.5) * 60, (Math.random() - 0.5) * 15, (Math.random() - 0.5) * 60)
|
|
@@ -2017,6 +2108,7 @@ var userActionHandlers = {
|
|
|
2017
2108
|
if (mountRef.current) mountRef.current.style.cursor = "grab";
|
|
2018
2109
|
},
|
|
2019
2110
|
handleCompleteConnection: async (context, targetNodeData) => {
|
|
2111
|
+
var _a;
|
|
2020
2112
|
const { stateRef, graphDataRef, sceneDataRef } = context;
|
|
2021
2113
|
const { sourceNodeData } = stateRef.current.connection;
|
|
2022
2114
|
if (!graphDataRef.current || !sceneDataRef.current || !sourceNodeData || !targetNodeData) {
|
|
@@ -2039,12 +2131,26 @@ var userActionHandlers = {
|
|
|
2039
2131
|
source: sourceNodeData.id,
|
|
2040
2132
|
target: targetNodeData.id
|
|
2041
2133
|
};
|
|
2042
|
-
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
2043
|
-
specificParentData.links.push(newLink);
|
|
2044
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
2045
2134
|
try {
|
|
2046
|
-
|
|
2047
|
-
|
|
2135
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2136
|
+
if (isView && parentFileIdToSave === context.sceneConfigId) {
|
|
2137
|
+
const specificParentData = graphDataRef.current[context.sceneConfigId];
|
|
2138
|
+
specificParentData.links.push(newLink);
|
|
2139
|
+
const viewFilePayload = {
|
|
2140
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2141
|
+
nodes: sceneDataRef.current.nodes,
|
|
2142
|
+
links: sceneDataRef.current.links,
|
|
2143
|
+
quest_nodes: specificParentData.nodes,
|
|
2144
|
+
quest_links: specificParentData.links
|
|
2145
|
+
};
|
|
2146
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2147
|
+
} else {
|
|
2148
|
+
const specificParentData = JSON.parse(JSON.stringify(graphDataRef.current[parentFileIdToSave]));
|
|
2149
|
+
specificParentData.links.push(newLink);
|
|
2150
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerIdToSave}/${parentFileIdToSave}`;
|
|
2151
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2152
|
+
graphDataRef.current[parentFileIdToSave] = specificParentData;
|
|
2153
|
+
}
|
|
2048
2154
|
addNewLinkToScene(stateRef.current, newLink);
|
|
2049
2155
|
} catch (error) {
|
|
2050
2156
|
console.error("Falha ao salvar a nova conex\xE3o:", error);
|
|
@@ -2113,14 +2219,28 @@ var userActionHandlers = {
|
|
|
2113
2219
|
} else {
|
|
2114
2220
|
newTargetId = newEndNodeData.id;
|
|
2115
2221
|
}
|
|
2116
|
-
const
|
|
2117
|
-
const
|
|
2118
|
-
|
|
2119
|
-
|
|
2222
|
+
const oldSourceInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldSourceId, context.sceneConfigId, context.ownerId);
|
|
2223
|
+
const oldTargetInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldTargetId, context.sceneConfigId, context.ownerId);
|
|
2224
|
+
const newSourceInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newSourceId, context.sceneConfigId, context.ownerId);
|
|
2225
|
+
const newTargetInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newTargetId, context.sceneConfigId, context.ownerId);
|
|
2226
|
+
if (!oldSourceInfo || !oldTargetInfo || !newSourceInfo || !newTargetInfo) {
|
|
2227
|
+
console.error("Informa\xE7\xF5es dos arquivos pai incompletas para o relink.");
|
|
2120
2228
|
alert("Ocorreu um erro ao identificar os arquivos pai para salvar a altera\xE7\xE3o.");
|
|
2121
2229
|
userActionHandlers.handleCancelRelink(context);
|
|
2122
2230
|
return;
|
|
2123
2231
|
}
|
|
2232
|
+
let oldGoverningFileId = oldSourceInfo.parentFileId;
|
|
2233
|
+
let oldGoverningOwnerId = oldSourceInfo.ownerId;
|
|
2234
|
+
if (oldSourceInfo.parentFileId === context.sceneConfigId || oldTargetInfo.parentFileId === context.sceneConfigId) {
|
|
2235
|
+
oldGoverningFileId = context.sceneConfigId;
|
|
2236
|
+
oldGoverningOwnerId = context.ownerId;
|
|
2237
|
+
}
|
|
2238
|
+
let newGoverningFileId = newSourceInfo.parentFileId;
|
|
2239
|
+
let newGoverningOwnerId = newSourceInfo.ownerId;
|
|
2240
|
+
if (newSourceInfo.parentFileId === context.sceneConfigId || newTargetInfo.parentFileId === context.sceneConfigId) {
|
|
2241
|
+
newGoverningFileId = context.sceneConfigId;
|
|
2242
|
+
newGoverningOwnerId = context.ownerId;
|
|
2243
|
+
}
|
|
2124
2244
|
const { sourceNode, targetNode, ...dataToKeep } = originalLinkData;
|
|
2125
2245
|
const newLinkData = {
|
|
2126
2246
|
...dataToKeep,
|
|
@@ -2128,34 +2248,44 @@ var userActionHandlers = {
|
|
|
2128
2248
|
target: newTargetId,
|
|
2129
2249
|
id: linkId
|
|
2130
2250
|
};
|
|
2251
|
+
const saveParentData = async (fileId, fileOwnerId, data) => {
|
|
2252
|
+
var _a;
|
|
2253
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2254
|
+
if (isView && fileId === context.sceneConfigId) {
|
|
2255
|
+
const viewFilePayload = {
|
|
2256
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2257
|
+
nodes: sceneDataRef.current.nodes,
|
|
2258
|
+
links: sceneDataRef.current.links,
|
|
2259
|
+
quest_nodes: data.nodes,
|
|
2260
|
+
quest_links: data.links
|
|
2261
|
+
};
|
|
2262
|
+
return context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2263
|
+
} else {
|
|
2264
|
+
return context.actions.save_view_data(`x_view_dbs/${fileOwnerId}/${fileId}`, data);
|
|
2265
|
+
}
|
|
2266
|
+
};
|
|
2131
2267
|
const savePromises = [];
|
|
2132
2268
|
const filesToUpdate = {};
|
|
2133
|
-
if (
|
|
2134
|
-
const updatedOriginalParentData = JSON.parse(JSON.stringify(graphDataRef.current[
|
|
2269
|
+
if (oldGoverningFileId !== newGoverningFileId) {
|
|
2270
|
+
const updatedOriginalParentData = JSON.parse(JSON.stringify(graphDataRef.current[oldGoverningFileId]));
|
|
2135
2271
|
updatedOriginalParentData.links = updatedOriginalParentData.links.filter(
|
|
2136
2272
|
(l) => String(l.id) !== String(linkId)
|
|
2137
2273
|
);
|
|
2138
|
-
filesToUpdate[
|
|
2139
|
-
savePromises.push(
|
|
2140
|
-
|
|
2141
|
-
);
|
|
2142
|
-
const updatedNewParentData = JSON.parse(JSON.stringify(graphDataRef.current[newParentInfo.parentFileId]));
|
|
2274
|
+
filesToUpdate[oldGoverningFileId] = updatedOriginalParentData;
|
|
2275
|
+
savePromises.push(saveParentData(oldGoverningFileId, oldGoverningOwnerId, updatedOriginalParentData));
|
|
2276
|
+
const updatedNewParentData = JSON.parse(JSON.stringify(graphDataRef.current[newGoverningFileId]));
|
|
2143
2277
|
if (!updatedNewParentData.links) updatedNewParentData.links = [];
|
|
2144
2278
|
updatedNewParentData.links.push(newLinkData);
|
|
2145
|
-
filesToUpdate[
|
|
2146
|
-
savePromises.push(
|
|
2147
|
-
context.actions.save_view_data(`x_view_dbs/${newParentInfo.ownerId}/${newParentInfo.parentFileId}`, updatedNewParentData)
|
|
2148
|
-
);
|
|
2279
|
+
filesToUpdate[newGoverningFileId] = updatedNewParentData;
|
|
2280
|
+
savePromises.push(saveParentData(newGoverningFileId, newGoverningOwnerId, updatedNewParentData));
|
|
2149
2281
|
} else {
|
|
2150
|
-
const updatedParentData = JSON.parse(JSON.stringify(graphDataRef.current[
|
|
2282
|
+
const updatedParentData = JSON.parse(JSON.stringify(graphDataRef.current[oldGoverningFileId]));
|
|
2151
2283
|
updatedParentData.links = updatedParentData.links.filter(
|
|
2152
2284
|
(l) => String(l.id) !== String(linkId)
|
|
2153
2285
|
);
|
|
2154
2286
|
updatedParentData.links.push(newLinkData);
|
|
2155
|
-
filesToUpdate[
|
|
2156
|
-
savePromises.push(
|
|
2157
|
-
context.actions.save_view_data(`x_view_dbs/${originalParentInfo.ownerId}/${originalParentInfo.parentFileId}`, updatedParentData)
|
|
2158
|
-
);
|
|
2287
|
+
filesToUpdate[oldGoverningFileId] = updatedParentData;
|
|
2288
|
+
savePromises.push(saveParentData(oldGoverningFileId, oldGoverningOwnerId, updatedParentData));
|
|
2159
2289
|
}
|
|
2160
2290
|
try {
|
|
2161
2291
|
await Promise.all(savePromises);
|
|
@@ -2173,7 +2303,7 @@ var userActionHandlers = {
|
|
|
2173
2303
|
}
|
|
2174
2304
|
},
|
|
2175
2305
|
handleDeleteLink: async (context, linkObject) => {
|
|
2176
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2306
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2177
2307
|
const { stateRef, graphDataRef, sceneDataRef, setters } = context;
|
|
2178
2308
|
setters.setRelationshipMenu({ visible: false });
|
|
2179
2309
|
if (!(linkObject == null ? void 0 : linkObject.userData) || !graphDataRef.current || !sceneDataRef.current) return;
|
|
@@ -2196,7 +2326,8 @@ var userActionHandlers = {
|
|
|
2196
2326
|
specificParentData.links = newLinks;
|
|
2197
2327
|
let filenameToSave;
|
|
2198
2328
|
let payloadToSave;
|
|
2199
|
-
|
|
2329
|
+
const isView = ((_g = context.viewType) == null ? void 0 : _g.toLowerCase()) === "view";
|
|
2330
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2200
2331
|
filenameToSave = context.sceneSaveUrl;
|
|
2201
2332
|
sceneDataRef.current.links = sceneDataRef.current.links.filter((l) => String(l.id) !== String(linkIdToDelete));
|
|
2202
2333
|
payloadToSave = {
|
|
@@ -2229,12 +2360,6 @@ var userActionHandlers = {
|
|
|
2229
2360
|
if (!nodeData || !sceneDataRef.current) return;
|
|
2230
2361
|
const nodeIdToDismiss = nodeData.id;
|
|
2231
2362
|
const strNodeId = String(nodeIdToDismiss);
|
|
2232
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2233
|
-
(n) => String(n.id) !== strNodeId
|
|
2234
|
-
);
|
|
2235
|
-
sceneDataRef.current.links = sceneDataRef.current.links.filter(
|
|
2236
|
-
(l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId
|
|
2237
|
-
);
|
|
2238
2363
|
const { ancestryGroup, ancestryLinks } = stateRef.current;
|
|
2239
2364
|
if (ancestryGroup && ancestryLinks) {
|
|
2240
2365
|
const remainingAncestryLinks = [];
|
|
@@ -2276,22 +2401,12 @@ var userActionHandlers = {
|
|
|
2276
2401
|
removeNodeFromScene(stateRef.current, nodeId);
|
|
2277
2402
|
setters.setDetailsNode((prev) => String(prev == null ? void 0 : prev.id) === String(nodeId) ? null : prev);
|
|
2278
2403
|
});
|
|
2279
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2280
|
-
(n) => String(n.id) === strNodeIdToKeep
|
|
2281
|
-
);
|
|
2282
|
-
sceneDataRef.current.links = [];
|
|
2283
2404
|
},
|
|
2284
2405
|
handleDismissMultipleNodes: (context, nodeIds) => {
|
|
2285
2406
|
const { stateRef, sceneDataRef, setters } = context;
|
|
2286
2407
|
setters.setMultiContextMenu({ visible: false });
|
|
2287
2408
|
if (!nodeIds || nodeIds.size === 0 || !sceneDataRef.current) return;
|
|
2288
2409
|
const strNodeIds = Array.from(nodeIds).map(String);
|
|
2289
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2290
|
-
(n) => !strNodeIds.includes(String(n.id))
|
|
2291
|
-
);
|
|
2292
|
-
sceneDataRef.current.links = sceneDataRef.current.links.filter(
|
|
2293
|
-
(l) => !strNodeIds.includes(String(l.source)) && !strNodeIds.includes(String(l.target))
|
|
2294
|
-
);
|
|
2295
2410
|
const { ancestryGroup, ancestryLinks } = stateRef.current;
|
|
2296
2411
|
if (ancestryGroup && ancestryLinks) {
|
|
2297
2412
|
const remainingAncestryLinks = [];
|
|
@@ -2347,15 +2462,10 @@ var userActionHandlers = {
|
|
|
2347
2462
|
removeNodeFromScene(stateRef.current, nodeId);
|
|
2348
2463
|
setters.setDetailsNode((prev) => String(prev == null ? void 0 : prev.id) === String(nodeId) ? null : prev);
|
|
2349
2464
|
});
|
|
2350
|
-
sceneDataRef.current.nodes = sceneDataRef.current.nodes.filter(
|
|
2351
|
-
(n) => strNodeIdsToKeep.includes(String(n.id))
|
|
2352
|
-
);
|
|
2353
|
-
sceneDataRef.current.links = sceneDataRef.current.links.filter(
|
|
2354
|
-
(l) => strNodeIdsToKeep.includes(String(l.source)) && strNodeIdsToKeep.includes(String(l.target))
|
|
2355
|
-
);
|
|
2356
2465
|
stateRef.current.selectedNodes.clear();
|
|
2357
2466
|
},
|
|
2358
2467
|
handleDeleteMultipleNodes: async (context, nodeIds) => {
|
|
2468
|
+
var _a;
|
|
2359
2469
|
const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
|
|
2360
2470
|
setters.setMultiContextMenu({ visible: false });
|
|
2361
2471
|
if (!nodeIds || nodeIds.size === 0 || !graphDataRef.current || !sceneDataRef.current) return;
|
|
@@ -2410,7 +2520,8 @@ var userActionHandlers = {
|
|
|
2410
2520
|
);
|
|
2411
2521
|
let filenameToSave;
|
|
2412
2522
|
let payloadToSave;
|
|
2413
|
-
|
|
2523
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2524
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2414
2525
|
filenameToSave = context.sceneSaveUrl;
|
|
2415
2526
|
const strNodesToDelete = Array.from(nodesToDelete).map(String);
|
|
2416
2527
|
const strLinksToDelete = Array.from(linksToDelete).map(String);
|
|
@@ -2448,6 +2559,7 @@ var userActionHandlers = {
|
|
|
2448
2559
|
}
|
|
2449
2560
|
},
|
|
2450
2561
|
handleDeleteNode: async (context, nodeData) => {
|
|
2562
|
+
var _a;
|
|
2451
2563
|
const { stateRef, graphDataRef, sceneDataRef, setters, actions } = context;
|
|
2452
2564
|
if (actions.delete_file && nodeData) {
|
|
2453
2565
|
const urls = extractFileUrlsFromProperties(nodeData);
|
|
@@ -2473,7 +2585,8 @@ var userActionHandlers = {
|
|
|
2473
2585
|
specificParentData.links = newLinks;
|
|
2474
2586
|
let filenameToSave;
|
|
2475
2587
|
let payloadToSave;
|
|
2476
|
-
|
|
2588
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2589
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2477
2590
|
filenameToSave = context.sceneSaveUrl;
|
|
2478
2591
|
const newVisualNodes = sceneDataRef.current.nodes.filter((n) => String(n.id) !== strNodeId);
|
|
2479
2592
|
const newVisualLinks = sceneDataRef.current.links.filter((l) => String(l.source) !== strNodeId && String(l.target) !== strNodeId);
|
|
@@ -2502,6 +2615,7 @@ var userActionHandlers = {
|
|
|
2502
2615
|
}
|
|
2503
2616
|
},
|
|
2504
2617
|
handleSaveNodeDetails: async (context, updatedNode, keepOpen = false) => {
|
|
2618
|
+
var _a;
|
|
2505
2619
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2506
2620
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2507
2621
|
const { _baseEmissiveIntensity: ignored, ...nodeToSave } = updatedNode;
|
|
@@ -2521,9 +2635,28 @@ var userActionHandlers = {
|
|
|
2521
2635
|
alert("Erro interno: Node n\xE3o encontrado para salvar.");
|
|
2522
2636
|
return;
|
|
2523
2637
|
}
|
|
2524
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2525
2638
|
try {
|
|
2526
|
-
|
|
2639
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2640
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2641
|
+
const visualNodeIndex = sceneDataRef.current.nodes.findIndex((n) => String(n.id) === String(nodeToSave.id));
|
|
2642
|
+
if (visualNodeIndex > -1) {
|
|
2643
|
+
sceneDataRef.current.nodes[visualNodeIndex] = {
|
|
2644
|
+
...sceneDataRef.current.nodes[visualNodeIndex],
|
|
2645
|
+
...nodeToSave
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2648
|
+
const viewFilePayload = {
|
|
2649
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2650
|
+
nodes: sceneDataRef.current.nodes,
|
|
2651
|
+
links: sceneDataRef.current.links,
|
|
2652
|
+
quest_nodes: specificParentData.nodes,
|
|
2653
|
+
quest_links: specificParentData.links
|
|
2654
|
+
};
|
|
2655
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2656
|
+
} else {
|
|
2657
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2658
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2659
|
+
}
|
|
2527
2660
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2528
2661
|
updateExistingNodeVisuals(stateRef.current, nodeToSave);
|
|
2529
2662
|
setters.setSceneVersion((v) => v + 1);
|
|
@@ -2536,6 +2669,7 @@ var userActionHandlers = {
|
|
|
2536
2669
|
}
|
|
2537
2670
|
},
|
|
2538
2671
|
handleSaveLinkDetails: async (context, updatedLink, keepOpen = false) => {
|
|
2672
|
+
var _a;
|
|
2539
2673
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2540
2674
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2541
2675
|
const { sourceNode, targetNode, ...linkToSave } = updatedLink;
|
|
@@ -2555,9 +2689,21 @@ var userActionHandlers = {
|
|
|
2555
2689
|
alert("Erro interno: link n\xE3o encontrado para salvar.");
|
|
2556
2690
|
return;
|
|
2557
2691
|
}
|
|
2558
|
-
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2559
2692
|
try {
|
|
2560
|
-
|
|
2693
|
+
const isView = ((_a = context.viewType) == null ? void 0 : _a.toLowerCase()) === "view";
|
|
2694
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2695
|
+
const viewFilePayload = {
|
|
2696
|
+
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
2697
|
+
nodes: sceneDataRef.current.nodes,
|
|
2698
|
+
links: sceneDataRef.current.links,
|
|
2699
|
+
quest_nodes: specificParentData.nodes,
|
|
2700
|
+
quest_links: specificParentData.links
|
|
2701
|
+
};
|
|
2702
|
+
await context.actions.save_view_data(context.sceneSaveUrl, viewFilePayload);
|
|
2703
|
+
} else {
|
|
2704
|
+
const filenameForSpecificParent = `x_view_dbs/${ownerId}/${parentFileId}`;
|
|
2705
|
+
await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
|
|
2706
|
+
}
|
|
2561
2707
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2562
2708
|
const lineObject = stateRef.current.allLinks.find(
|
|
2563
2709
|
(l) => String(l.userData.id) === String(linkToSave.id)
|
|
@@ -2580,7 +2726,7 @@ var userActionHandlers = {
|
|
|
2580
2726
|
}
|
|
2581
2727
|
},
|
|
2582
2728
|
handleAddExistingNodeById: (context, nodeId) => {
|
|
2583
|
-
var _a
|
|
2729
|
+
var _a;
|
|
2584
2730
|
const { stateRef, sceneDataRef, graphDataRef, tweenToTarget, setters } = context;
|
|
2585
2731
|
const state = stateRef.current;
|
|
2586
2732
|
const graphFull = graphDataRef.current;
|
|
@@ -2596,16 +2742,12 @@ var userActionHandlers = {
|
|
|
2596
2742
|
tweenToTarget(state.nodeObjects[strNodeId]);
|
|
2597
2743
|
return;
|
|
2598
2744
|
}
|
|
2599
|
-
const alreadyInSceneData = (((_a = sceneDataRef.current) == null ? void 0 : _a.nodes) || []).some((n) => String(n.id) === String(strNodeId));
|
|
2600
|
-
if (!alreadyInSceneData) {
|
|
2601
|
-
sceneDataRef.current.nodes.push(nodeData);
|
|
2602
|
-
}
|
|
2603
2745
|
const base = state.controls ? state.controls.target.clone() : new THREE.Vector3(0, 0, 0);
|
|
2604
2746
|
const offset = new THREE.Vector3((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 6, (Math.random() - 0.5) * 20);
|
|
2605
2747
|
const position = base.add(offset);
|
|
2606
2748
|
addStandaloneNodeToScene(state, nodeData, position);
|
|
2607
2749
|
tweenToTarget(position, 1.3);
|
|
2608
|
-
(
|
|
2750
|
+
(_a = setters == null ? void 0 : setters.setSceneVersion) == null ? void 0 : _a.call(setters, (v) => v + 1);
|
|
2609
2751
|
}
|
|
2610
2752
|
};
|
|
2611
2753
|
|
|
@@ -2844,7 +2986,10 @@ var IGNORED_KEYS = [
|
|
|
2844
2986
|
"is_private",
|
|
2845
2987
|
"abstraction_tree",
|
|
2846
2988
|
"selectedAbstractionParentId",
|
|
2847
|
-
"isAddingAbstractionNodes"
|
|
2989
|
+
"isAddingAbstractionNodes",
|
|
2990
|
+
"status",
|
|
2991
|
+
"is_quest",
|
|
2992
|
+
"raw_title"
|
|
2848
2993
|
];
|
|
2849
2994
|
function extractCustomPropsFromNode(node) {
|
|
2850
2995
|
const customPropTypes = node._customPropTypes || {};
|
|
@@ -7904,15 +8049,11 @@ function InSceneVersionForm({
|
|
|
7904
8049
|
// src/components/InSceneQuestForm.jsx
|
|
7905
8050
|
var import_react16 = __toESM(require("react"));
|
|
7906
8051
|
var import_fi14 = require("react-icons/fi");
|
|
7907
|
-
var
|
|
8052
|
+
var QUEST_STATUS_COLORS2 = {
|
|
7908
8053
|
"Backlog": "#64748b",
|
|
7909
|
-
// Slate (Cinza azulado)
|
|
7910
8054
|
"In Progress": "#eab308",
|
|
7911
|
-
// Yellow (Amarelo)
|
|
7912
8055
|
"Review": "#a855f7",
|
|
7913
|
-
// Purple (Roxo)
|
|
7914
8056
|
"Done": "#22c55e"
|
|
7915
|
-
// Green (Verde)
|
|
7916
8057
|
};
|
|
7917
8058
|
function InSceneQuestForm({
|
|
7918
8059
|
onSave,
|
|
@@ -7923,7 +8064,14 @@ function InSceneQuestForm({
|
|
|
7923
8064
|
availableNodes = [],
|
|
7924
8065
|
availableAncestries = [],
|
|
7925
8066
|
onMentionClick,
|
|
7926
|
-
onUploadFile
|
|
8067
|
+
onUploadFile,
|
|
8068
|
+
onNameChange,
|
|
8069
|
+
onColorChange,
|
|
8070
|
+
onSizeChange,
|
|
8071
|
+
viewName = "Projeto",
|
|
8072
|
+
// NOVA PROP
|
|
8073
|
+
questCounter = 1
|
|
8074
|
+
// NOVA PROP
|
|
7927
8075
|
}) {
|
|
7928
8076
|
const [name, setName] = (0, import_react16.useState)("");
|
|
7929
8077
|
const [types, setTypes] = (0, import_react16.useState)(["quest"]);
|
|
@@ -7932,9 +8080,11 @@ function InSceneQuestForm({
|
|
|
7932
8080
|
const [size, setSize] = (0, import_react16.useState)("medium");
|
|
7933
8081
|
const [intensity, setIntensity] = (0, import_react16.useState)(0);
|
|
7934
8082
|
const [description, setDescription] = (0, import_react16.useState)("");
|
|
8083
|
+
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react16.useState)(false);
|
|
7935
8084
|
const [customProps, setCustomProps] = (0, import_react16.useState)([]);
|
|
7936
8085
|
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react16.useState)(false);
|
|
7937
8086
|
const propsEndRef = (0, import_react16.useRef)(null);
|
|
8087
|
+
const standardizedName = `${viewName} - ${questCounter} - \xBB ${name || "Nova Quest"}`;
|
|
7938
8088
|
const handleAddProp = () => {
|
|
7939
8089
|
const newProp = createNewCustomProperty(customProps);
|
|
7940
8090
|
setCustomProps([...customProps, newProp]);
|
|
@@ -7971,7 +8121,7 @@ function InSceneQuestForm({
|
|
|
7971
8121
|
const handleSubmit = (e) => {
|
|
7972
8122
|
e.preventDefault();
|
|
7973
8123
|
if (!name.trim()) {
|
|
7974
|
-
alert("O campo '
|
|
8124
|
+
alert("O campo 'T\xEDtulo' \xE9 obrigat\xF3rio.");
|
|
7975
8125
|
return;
|
|
7976
8126
|
}
|
|
7977
8127
|
const additionalData = toObjectFromCustomProps(
|
|
@@ -7979,10 +8129,12 @@ function InSceneQuestForm({
|
|
|
7979
8129
|
);
|
|
7980
8130
|
const processedSections = processDescriptionForSave(description, []);
|
|
7981
8131
|
onSave({
|
|
7982
|
-
name:
|
|
8132
|
+
name: standardizedName,
|
|
8133
|
+
// SALVA O NOME FORMATADO
|
|
8134
|
+
raw_title: name.trim(),
|
|
8135
|
+
// Salva o título puro como fallback ou metadado útil
|
|
7983
8136
|
type: types,
|
|
7984
|
-
color:
|
|
7985
|
-
// Cor atrelada ao status
|
|
8137
|
+
color: QUEST_STATUS_COLORS2[status],
|
|
7986
8138
|
status,
|
|
7987
8139
|
size,
|
|
7988
8140
|
intensity,
|
|
@@ -8008,21 +8160,54 @@ function InSceneQuestForm({
|
|
|
8008
8160
|
onContextMenu: swallow,
|
|
8009
8161
|
onDoubleClick: swallow
|
|
8010
8162
|
},
|
|
8011
|
-
/* @__PURE__ */ import_react16.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${
|
|
8012
|
-
/* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pt-5 pb-3" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8163
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS2[status]}, transparent)` } }),
|
|
8164
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react16.default.createElement("div", null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Nova quest")), /* @__PURE__ */ import_react16.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")), /* @__PURE__ */ import_react16.default.createElement(
|
|
8165
|
+
"button",
|
|
8166
|
+
{
|
|
8167
|
+
type: "button",
|
|
8168
|
+
onClick: onCancel,
|
|
8169
|
+
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",
|
|
8170
|
+
title: "Fechar"
|
|
8171
|
+
},
|
|
8172
|
+
"\xD7"
|
|
8173
|
+
)),
|
|
8174
|
+
/* @__PURE__ */ import_react16.default.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ import_react16.default.createElement(
|
|
8175
|
+
"input",
|
|
8176
|
+
{
|
|
8177
|
+
required: true,
|
|
8178
|
+
type: "text",
|
|
8179
|
+
placeholder: "Ex.: Refatorar M\xF3dulo X",
|
|
8180
|
+
value: name,
|
|
8181
|
+
onChange: (e) => {
|
|
8182
|
+
const val = e.target.value;
|
|
8183
|
+
setName(val);
|
|
8184
|
+
onNameChange == null ? void 0 : onNameChange(val || "Nova Quest");
|
|
8185
|
+
},
|
|
8186
|
+
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"
|
|
8187
|
+
}
|
|
8188
|
+
), /* @__PURE__ */ import_react16.default.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
8189
|
+
"button",
|
|
8190
|
+
{
|
|
8191
|
+
type: "button",
|
|
8192
|
+
onClick: () => setIsStatusDropdownOpen(!isStatusDropdownOpen),
|
|
8193
|
+
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"
|
|
8194
|
+
},
|
|
8195
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement("span", { className: "text-slate-200 font-medium" }, status)),
|
|
8196
|
+
/* @__PURE__ */ import_react16.default.createElement(import_fi14.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
|
|
8197
|
+
), isStatusDropdownOpen && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement(
|
|
8198
|
+
"li",
|
|
8199
|
+
{
|
|
8200
|
+
key: s,
|
|
8201
|
+
onClick: () => {
|
|
8202
|
+
setStatus(s);
|
|
8203
|
+
setIsStatusDropdownOpen(false);
|
|
8204
|
+
onColorChange == null ? void 0 : onColorChange(QUEST_STATUS_COLORS2[s]);
|
|
8205
|
+
},
|
|
8206
|
+
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"}`
|
|
8020
8207
|
},
|
|
8021
|
-
/* @__PURE__ */ import_react16.default.createElement("
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
/* @__PURE__ */ import_react16.default.createElement("option", { value: "Done" }, "Done")
|
|
8025
|
-
)), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.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__ */ import_react16.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiX, { size: 12 })))), /* @__PURE__ */ import_react16.default.createElement(
|
|
8208
|
+
/* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
|
|
8209
|
+
s
|
|
8210
|
+
)))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.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__ */ import_react16.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiX, { size: 12 })))), /* @__PURE__ */ import_react16.default.createElement(
|
|
8026
8211
|
"input",
|
|
8027
8212
|
{
|
|
8028
8213
|
type: "text",
|
|
@@ -8045,7 +8230,20 @@ function InSceneQuestForm({
|
|
|
8045
8230
|
onMentionClick,
|
|
8046
8231
|
onSaveDescription: (newDesc) => setDescription(newDesc)
|
|
8047
8232
|
}
|
|
8048
|
-
), /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiEdit2, { size: 14 }))), !description && /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no
|
|
8233
|
+
), /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiEdit2, { size: 14 }))), !description && /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ import_react16.default.createElement(
|
|
8234
|
+
"button",
|
|
8235
|
+
{
|
|
8236
|
+
key: s,
|
|
8237
|
+
type: "button",
|
|
8238
|
+
onClick: () => {
|
|
8239
|
+
setSize(s);
|
|
8240
|
+
onSizeChange == null ? void 0 : onSizeChange(s);
|
|
8241
|
+
},
|
|
8242
|
+
className: "flex items-center gap-2 group cursor-pointer focus:outline-none"
|
|
8243
|
+
},
|
|
8244
|
+
/* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement(import_fi14.FiCheck, { size: 12, className: "text-white" })),
|
|
8245
|
+
/* @__PURE__ */ import_react16.default.createElement("span", { className: `text-sm capitalize transition-colors ${size === s ? "text-white font-medium" : "text-slate-400 group-hover:text-slate-300"}` }, s)
|
|
8246
|
+
)))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react16.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react16.default.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__ */ import_react16.default.createElement(import_fi14.FiPlus, { size: 14 }), " Adicionar")), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ import_react16.default.createElement(
|
|
8049
8247
|
CustomPropertyDisplay,
|
|
8050
8248
|
{
|
|
8051
8249
|
key: prop.id,
|
|
@@ -8560,136 +8758,475 @@ function NodeDetailsPanel({
|
|
|
8560
8758
|
));
|
|
8561
8759
|
}
|
|
8562
8760
|
|
|
8563
|
-
// src/components/
|
|
8761
|
+
// src/components/QuestDetailsPanel.jsx
|
|
8564
8762
|
var import_react18 = __toESM(require("react"));
|
|
8565
|
-
function MultiNodeContextMenu({
|
|
8566
|
-
data,
|
|
8567
|
-
userRole,
|
|
8568
|
-
onClose,
|
|
8569
|
-
onDismissNodes,
|
|
8570
|
-
onDismissOtherNodes,
|
|
8571
|
-
onDeleteNodes
|
|
8572
|
-
}) {
|
|
8573
|
-
const menuRef = (0, import_react18.useRef)(null);
|
|
8574
|
-
const [menuPos, setMenuPos] = (0, import_react18.useState)({ left: 0, top: 0 });
|
|
8575
|
-
const [isConfirmingDelete, setIsConfirmingDelete] = (0, import_react18.useState)(false);
|
|
8576
|
-
const ability = defineAbilityFor(userRole);
|
|
8577
|
-
const canDelete = ability.can("delete", "Node");
|
|
8578
|
-
(0, import_react18.useLayoutEffect)(() => {
|
|
8579
|
-
if (!data.visible || !menuRef.current) return;
|
|
8580
|
-
const el = menuRef.current;
|
|
8581
|
-
const w = el.clientWidth;
|
|
8582
|
-
const h = el.clientHeight;
|
|
8583
|
-
const vw = window.innerWidth;
|
|
8584
|
-
const vh = window.innerHeight;
|
|
8585
|
-
let left = data.x + 8;
|
|
8586
|
-
let top = data.y + 8;
|
|
8587
|
-
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
8588
|
-
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
8589
|
-
setMenuPos({ left, top });
|
|
8590
|
-
}, [data]);
|
|
8591
|
-
(0, import_react18.useEffect)(() => {
|
|
8592
|
-
if (data.visible) {
|
|
8593
|
-
setIsConfirmingDelete(false);
|
|
8594
|
-
}
|
|
8595
|
-
const handleClickOutside = (e) => {
|
|
8596
|
-
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
8597
|
-
};
|
|
8598
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
8599
|
-
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
8600
|
-
}, [data.visible, onClose]);
|
|
8601
|
-
if (!data.visible || !data.nodeIds || data.nodeIds.size === 0) return null;
|
|
8602
|
-
const swallow = (e) => e.stopPropagation();
|
|
8603
|
-
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";
|
|
8604
|
-
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";
|
|
8605
|
-
const nodeCount = data.nodeIds.size;
|
|
8606
|
-
return /* @__PURE__ */ import_react18.default.createElement(
|
|
8607
|
-
"div",
|
|
8608
|
-
{
|
|
8609
|
-
ref: menuRef,
|
|
8610
|
-
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",
|
|
8611
|
-
style: { position: "absolute", left: `${menuPos.left}px`, top: `${menuPos.top}px`, zIndex: 1e3 },
|
|
8612
|
-
onPointerDown: swallow,
|
|
8613
|
-
onPointerMove: swallow,
|
|
8614
|
-
onPointerUp: swallow,
|
|
8615
|
-
onClick: swallow,
|
|
8616
|
-
onWheel: swallow,
|
|
8617
|
-
onContextMenu: swallow,
|
|
8618
|
-
onDoubleClick: swallow
|
|
8619
|
-
},
|
|
8620
|
-
/* @__PURE__ */ import_react18.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
8621
|
-
/* @__PURE__ */ import_react18.default.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 mb-1" }, /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ import_react18.default.createElement("strong", null, nodeCount, " Nodes"), "?"), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ import_react18.default.createElement(
|
|
8622
|
-
"button",
|
|
8623
|
-
{
|
|
8624
|
-
onClick: () => setIsConfirmingDelete(false),
|
|
8625
|
-
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8626
|
-
},
|
|
8627
|
-
"Cancelar"
|
|
8628
|
-
), /* @__PURE__ */ import_react18.default.createElement(
|
|
8629
|
-
"button",
|
|
8630
|
-
{
|
|
8631
|
-
onClick: () => onDeleteNodes(data.nodeIds),
|
|
8632
|
-
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
8633
|
-
},
|
|
8634
|
-
"Excluir"
|
|
8635
|
-
))) : /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es em Grupo (", nodeCount, " Nodes)")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ import_react18.default.createElement("button", { onClick: () => onDismissNodes(data.nodeIds), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.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__ */ import_react18.default.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ import_react18.default.createElement("span", null, "Dismiss (", nodeCount, ")")), /* @__PURE__ */ import_react18.default.createElement("button", { onClick: () => onDismissOtherNodes(data.nodeIds), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ import_react18.default.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ import_react18.default.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react18.default.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ import_react18.default.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ import_react18.default.createElement("span", null, "Dismiss other nodes")), canDelete && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react18.default.createElement("button", { onClick: () => setIsConfirmingDelete(true), className: deleteButtonClass, title: "Excluir Nodes" }, /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ import_react18.default.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ import_react18.default.createElement("span", null, "Excluir Nodes (", nodeCount, ")"))))))
|
|
8636
|
-
);
|
|
8637
|
-
}
|
|
8638
|
-
|
|
8639
|
-
// src/components/RelationshipDetailsPanel.jsx
|
|
8640
|
-
var import_react19 = __toESM(require("react"));
|
|
8641
8763
|
var import_fi16 = require("react-icons/fi");
|
|
8642
|
-
|
|
8643
|
-
|
|
8764
|
+
var QUEST_STATUS_COLORS3 = {
|
|
8765
|
+
"Backlog": "#64748b",
|
|
8766
|
+
"In Progress": "#eab308",
|
|
8767
|
+
"Review": "#a855f7",
|
|
8768
|
+
"Done": "#22c55e"
|
|
8769
|
+
};
|
|
8770
|
+
function QuestDetailsPanel({
|
|
8771
|
+
node,
|
|
8644
8772
|
onClose,
|
|
8645
8773
|
onSave,
|
|
8774
|
+
onNameChange,
|
|
8775
|
+
onColorChange,
|
|
8776
|
+
onSizeChange,
|
|
8646
8777
|
onDataUpdate,
|
|
8647
8778
|
onOpenImageViewer,
|
|
8779
|
+
existingTypes = [],
|
|
8648
8780
|
availableNodes = [],
|
|
8649
8781
|
availableAncestries = [],
|
|
8650
8782
|
onOpenReference,
|
|
8651
8783
|
onMentionClick,
|
|
8652
8784
|
onUploadFile,
|
|
8653
|
-
userRole
|
|
8785
|
+
userRole,
|
|
8786
|
+
currentDatasetName
|
|
8654
8787
|
}) {
|
|
8655
|
-
|
|
8656
|
-
const
|
|
8657
|
-
const [
|
|
8658
|
-
const
|
|
8659
|
-
const
|
|
8660
|
-
const
|
|
8661
|
-
const [
|
|
8662
|
-
const
|
|
8663
|
-
const
|
|
8664
|
-
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
(0,
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
const
|
|
8674
|
-
const
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8788
|
+
var _a;
|
|
8789
|
+
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) || "";
|
|
8790
|
+
const [rawTitle, setRawTitle] = (0, import_react18.useState)(initialRawTitle);
|
|
8791
|
+
const prefixParts = ((node == null ? void 0 : node.name) || "").split(" - \xBB ");
|
|
8792
|
+
const questPrefix = prefixParts.length > 1 ? prefixParts[0] : "";
|
|
8793
|
+
const standardizedName = questPrefix ? `${questPrefix} - \xBB ${rawTitle || "Sem t\xEDtulo"}` : rawTitle;
|
|
8794
|
+
const [types, setTypes] = (0, import_react18.useState)((node == null ? void 0 : node.type) ? Array.isArray(node.type) ? node.type : [node.type] : ["quest"]);
|
|
8795
|
+
const [typeInput, setTypeInput] = (0, import_react18.useState)("");
|
|
8796
|
+
const [status, setStatus] = (0, import_react18.useState)((node == null ? void 0 : node.status) ?? "Backlog");
|
|
8797
|
+
const [size, setSize] = (0, import_react18.useState)((node == null ? void 0 : node.size) ?? "medium");
|
|
8798
|
+
const [description, setDescription] = (0, import_react18.useState)((node == null ? void 0 : node.description) ?? "");
|
|
8799
|
+
const [intensity, setIntensity] = (0, import_react18.useState)((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8800
|
+
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react18.useState)(false);
|
|
8801
|
+
const [customProps, setCustomProps] = (0, import_react18.useState)(() => extractCustomPropsFromNode(node || {}));
|
|
8802
|
+
const [showTypeSuggestions, setShowTypeSuggestions] = (0, import_react18.useState)(false);
|
|
8803
|
+
const [filteredTypes, setFilteredTypes] = (0, import_react18.useState)([]);
|
|
8804
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react18.useState)(false);
|
|
8805
|
+
const [isReadMode, setIsReadMode] = (0, import_react18.useState)(false);
|
|
8806
|
+
const [existingSections, setExistingSections] = (0, import_react18.useState)((node == null ? void 0 : node.description_sections) || []);
|
|
8807
|
+
const [isSaving, setIsSaving] = (0, import_react18.useState)(false);
|
|
8808
|
+
const [isLinkCopied, setIsLinkCopied] = (0, import_react18.useState)(false);
|
|
8809
|
+
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
8810
|
+
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
8811
|
+
initialWidth: isReadMode ? 700 : 440,
|
|
8812
|
+
minWidth: 320,
|
|
8813
|
+
maxWidth: maxPanelW
|
|
8814
|
+
});
|
|
8815
|
+
(0, import_react18.useEffect)(() => {
|
|
8816
|
+
setWidth(isReadMode ? 700 : 440);
|
|
8817
|
+
}, [isReadMode, setWidth]);
|
|
8818
|
+
const prevNodeIdRef = (0, import_react18.useRef)(null);
|
|
8819
|
+
const propsEndRef = (0, import_react18.useRef)(null);
|
|
8820
|
+
const canEdit = userRole !== "viewer";
|
|
8821
|
+
const availableImages = customProps.filter((p) => p.type === "images").flatMap((p) => Array.isArray(p.value) ? p.value : []).filter((img) => img.value && img.value.trim() !== "");
|
|
8822
|
+
const handleImageClickFromText = (url, name) => {
|
|
8823
|
+
if (onOpenImageViewer) {
|
|
8824
|
+
onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
|
|
8825
|
+
}
|
|
8826
|
+
};
|
|
8827
|
+
(0, import_react18.useEffect)(() => {
|
|
8828
|
+
var _a2;
|
|
8829
|
+
if ((node == null ? void 0 : node.id) !== prevNodeIdRef.current) {
|
|
8830
|
+
prevNodeIdRef.current = node == null ? void 0 : node.id;
|
|
8831
|
+
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) || "";
|
|
8832
|
+
setRawTitle(newRawTitle);
|
|
8833
|
+
setTypes((node == null ? void 0 : node.type) ? Array.isArray(node.type) ? node.type : [node.type] : ["quest"]);
|
|
8834
|
+
setStatus((node == null ? void 0 : node.status) ?? "Backlog");
|
|
8835
|
+
setSize((node == null ? void 0 : node.size) ?? "medium");
|
|
8836
|
+
setDescription((node == null ? void 0 : node.description) ?? "");
|
|
8837
|
+
setIntensity((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8838
|
+
setExistingSections((node == null ? void 0 : node.description_sections) || []);
|
|
8839
|
+
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
8840
|
+
}
|
|
8841
|
+
}, [node]);
|
|
8842
|
+
(0, import_react18.useEffect)(() => {
|
|
8843
|
+
if (typeInput.trim() === "") {
|
|
8844
|
+
setFilteredTypes(existingTypes.filter((t) => !types.includes(t)));
|
|
8845
|
+
} else {
|
|
8846
|
+
const lowercasedInput = typeInput.toLowerCase();
|
|
8847
|
+
setFilteredTypes(
|
|
8848
|
+
existingTypes.filter(
|
|
8849
|
+
(t) => t.toLowerCase().includes(lowercasedInput) && !types.includes(t)
|
|
8850
|
+
)
|
|
8851
|
+
);
|
|
8852
|
+
}
|
|
8853
|
+
}, [typeInput, existingTypes, types]);
|
|
8854
|
+
const handleCopyLink = () => {
|
|
8855
|
+
if (!(node == null ? void 0 : node.id)) return;
|
|
8856
|
+
const baseUrl = window.location.origin + window.location.pathname;
|
|
8857
|
+
const fullUrl = `${baseUrl}?focus=${node.id}`;
|
|
8858
|
+
navigator.clipboard.writeText(fullUrl).then(() => {
|
|
8859
|
+
setIsLinkCopied(true);
|
|
8860
|
+
setTimeout(() => setIsLinkCopied(false), 2e3);
|
|
8861
|
+
}).catch((err) => {
|
|
8862
|
+
console.error("Erro ao copiar link:", err);
|
|
8863
|
+
});
|
|
8864
|
+
};
|
|
8865
|
+
const swallow = (e) => e.stopPropagation();
|
|
8866
|
+
const handleNameChange = (e) => {
|
|
8867
|
+
const val = e.target.value;
|
|
8868
|
+
setRawTitle(val);
|
|
8869
|
+
const newStandardName = questPrefix ? `${questPrefix} - \xBB ${val || "Sem t\xEDtulo"}` : val;
|
|
8870
|
+
onNameChange == null ? void 0 : onNameChange(node.id, newStandardName, val);
|
|
8871
|
+
};
|
|
8872
|
+
const handleSizeChange = (newSize) => {
|
|
8873
|
+
setSize(newSize);
|
|
8874
|
+
onSizeChange == null ? void 0 : onSizeChange(node.id, newSize);
|
|
8875
|
+
};
|
|
8876
|
+
const handleStatusChange = (newStatus) => {
|
|
8877
|
+
setStatus(newStatus);
|
|
8878
|
+
const newColor = QUEST_STATUS_COLORS3[newStatus];
|
|
8879
|
+
onColorChange == null ? void 0 : onColorChange(node.id, newColor);
|
|
8880
|
+
onDataUpdate == null ? void 0 : onDataUpdate({ ...node, status: newStatus, color: newColor });
|
|
8881
|
+
};
|
|
8882
|
+
const handleAddType = (newType) => {
|
|
8883
|
+
const trimmed = newType.trim();
|
|
8884
|
+
if (trimmed && !types.includes(trimmed)) {
|
|
8885
|
+
setTypes([...types, trimmed]);
|
|
8886
|
+
setTypeInput("");
|
|
8887
|
+
setShowTypeSuggestions(false);
|
|
8888
|
+
}
|
|
8889
|
+
};
|
|
8890
|
+
const handleRemoveType = (indexToRemove) => {
|
|
8891
|
+
if (types[indexToRemove] === "quest") return;
|
|
8892
|
+
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
8893
|
+
};
|
|
8894
|
+
const handleTypeInputKeyDown = (e) => {
|
|
8895
|
+
if (e.key === "Enter") {
|
|
8896
|
+
e.preventDefault();
|
|
8897
|
+
handleAddType(typeInput);
|
|
8898
|
+
} else if (e.key === "Backspace" && typeInput === "" && types.length > 1) {
|
|
8899
|
+
handleRemoveType(types.length - 1);
|
|
8900
|
+
}
|
|
8901
|
+
};
|
|
8902
|
+
const handleAddProp = () => {
|
|
8903
|
+
const newProp = createNewCustomProperty(customProps);
|
|
8904
|
+
setCustomProps((p) => [...p, newProp]);
|
|
8905
|
+
setTimeout(() => {
|
|
8906
|
+
var _a2;
|
|
8907
|
+
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
8908
|
+
}, 100);
|
|
8909
|
+
};
|
|
8910
|
+
const handleRemoveProp = (i) => {
|
|
8911
|
+
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
8912
|
+
setCustomProps(newProps);
|
|
8913
|
+
triggerAutoSave({ customProps: newProps });
|
|
8914
|
+
};
|
|
8915
|
+
const handleUpdateProp = (index, updatedProp) => {
|
|
8916
|
+
const newProps = [...customProps];
|
|
8917
|
+
newProps[index] = updatedProp;
|
|
8918
|
+
setCustomProps(newProps);
|
|
8919
|
+
if (!updatedProp.isEditing) {
|
|
8920
|
+
triggerAutoSave({ customProps: newProps });
|
|
8921
|
+
}
|
|
8922
|
+
};
|
|
8923
|
+
const handleSaveDescriptionInline = (newDescription) => {
|
|
8924
|
+
setDescription(newDescription);
|
|
8925
|
+
onDataUpdate({ ...node, description: newDescription });
|
|
8926
|
+
triggerAutoSave({ description: newDescription });
|
|
8927
|
+
};
|
|
8928
|
+
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
8929
|
+
const currentRawTitle = overrides.rawTitle !== void 0 ? overrides.rawTitle : rawTitle;
|
|
8930
|
+
const currentStandardName = questPrefix ? `${questPrefix} - \xBB ${currentRawTitle || "Sem t\xEDtulo"}` : currentRawTitle;
|
|
8931
|
+
const currentTypes = overrides.types !== void 0 ? overrides.types : types;
|
|
8932
|
+
const currentDescription = overrides.description !== void 0 ? overrides.description : description;
|
|
8933
|
+
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
8934
|
+
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
8935
|
+
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
8936
|
+
if (!currentRawTitle.trim() || currentTypes.length === 0) {
|
|
8937
|
+
alert("O campo 'T\xEDtulo' e pelo menos um 'Tipo' s\xE3o obrigat\xF3rios.");
|
|
8938
|
+
return;
|
|
8939
|
+
}
|
|
8940
|
+
setIsSaving(true);
|
|
8941
|
+
try {
|
|
8942
|
+
const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
|
|
8943
|
+
const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
|
|
8944
|
+
const dataToSave = {
|
|
8945
|
+
id: node.id,
|
|
8946
|
+
name: currentStandardName.trim(),
|
|
8947
|
+
// Salva o nome completo formatado
|
|
8948
|
+
raw_title: currentRawTitle.trim(),
|
|
8949
|
+
// Salva o título simples
|
|
8950
|
+
type: currentTypes,
|
|
8951
|
+
color: QUEST_STATUS_COLORS3[currentStatus],
|
|
8952
|
+
status: currentStatus,
|
|
8953
|
+
size,
|
|
8954
|
+
description: currentDescription,
|
|
8955
|
+
description_sections: processedSections,
|
|
8956
|
+
useImageAsTexture: false,
|
|
8957
|
+
textureImageUrl: null,
|
|
8958
|
+
intensity,
|
|
8959
|
+
is_quest: true,
|
|
8960
|
+
...extrasObj,
|
|
8961
|
+
version_node: node.version_node
|
|
8962
|
+
};
|
|
8963
|
+
await onSave(dataToSave, keepOpen);
|
|
8964
|
+
onDataUpdate(dataToSave);
|
|
8965
|
+
if (!keepOpen) {
|
|
8966
|
+
onClose();
|
|
8967
|
+
}
|
|
8968
|
+
} finally {
|
|
8969
|
+
setIsSaving(false);
|
|
8970
|
+
}
|
|
8971
|
+
};
|
|
8972
|
+
const triggerAutoSave = (overrides = {}) => {
|
|
8973
|
+
handleSave(true, overrides);
|
|
8974
|
+
};
|
|
8975
|
+
const handleCancel = () => {
|
|
8976
|
+
if (node) {
|
|
8977
|
+
onNameChange == null ? void 0 : onNameChange(node.id, node.name);
|
|
8978
|
+
onColorChange == null ? void 0 : onColorChange(node.id, node.color);
|
|
8979
|
+
onSizeChange == null ? void 0 : onSizeChange(node.id, node.size || "medium");
|
|
8980
|
+
}
|
|
8981
|
+
onClose();
|
|
8982
|
+
};
|
|
8983
|
+
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
8984
|
+
return /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement(
|
|
8985
|
+
"div",
|
|
8986
|
+
{
|
|
8987
|
+
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"}`,
|
|
8988
|
+
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${panelWidth}px`, maxWidth: "92vw" },
|
|
8989
|
+
onPointerDown: swallow,
|
|
8990
|
+
onPointerMove: swallow,
|
|
8991
|
+
onPointerUp: swallow,
|
|
8992
|
+
onClick: swallow,
|
|
8993
|
+
onWheel: swallow,
|
|
8994
|
+
onContextMenu: swallow,
|
|
8995
|
+
onDoubleClick: swallow
|
|
8996
|
+
},
|
|
8997
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { onPointerDown: (e) => {
|
|
8998
|
+
e.stopPropagation();
|
|
8999
|
+
handleResize(e);
|
|
9000
|
+
}, 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" }),
|
|
9001
|
+
isReadMode ? /* @__PURE__ */ import_react18.default.createElement(
|
|
9002
|
+
DescriptionReadModePanel,
|
|
9003
|
+
{
|
|
9004
|
+
title: standardizedName || (node == null ? void 0 : node.name),
|
|
9005
|
+
description,
|
|
9006
|
+
savedSections: existingSections,
|
|
9007
|
+
onBack: () => setIsReadMode(false),
|
|
9008
|
+
onEdit: () => {
|
|
9009
|
+
if (canEdit) {
|
|
9010
|
+
setIsReadMode(false);
|
|
9011
|
+
setIsDescriptionModalOpen(true);
|
|
9012
|
+
}
|
|
9013
|
+
},
|
|
9014
|
+
onClose: handleCancel,
|
|
9015
|
+
availableNodes,
|
|
9016
|
+
availableAncestries,
|
|
9017
|
+
onOpenReference,
|
|
9018
|
+
onMentionClick,
|
|
9019
|
+
onImageClick: handleImageClickFromText,
|
|
9020
|
+
onSaveDescription: handleSaveDescriptionInline
|
|
9021
|
+
}
|
|
9022
|
+
) : /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "h-[2px]", style: { background: `linear-gradient(to right, transparent, ${QUEST_STATUS_COLORS3[status]}, transparent)` } }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react18.default.createElement("div", null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiTarget, { className: "text-sky-400", size: 14 }), /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Quest"), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement(import_fi16.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiLink, { size: 12 }))), /* @__PURE__ */ import_react18.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, standardizedName || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ import_react18.default.createElement(
|
|
9023
|
+
"input",
|
|
9024
|
+
{
|
|
9025
|
+
type: "text",
|
|
9026
|
+
value: rawTitle,
|
|
9027
|
+
onChange: handleNameChange,
|
|
9028
|
+
readOnly: !canEdit,
|
|
9029
|
+
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"}`
|
|
9030
|
+
}
|
|
9031
|
+
), /* @__PURE__ */ import_react18.default.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }), /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ import_react18.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react18.default.createElement(
|
|
9032
|
+
"button",
|
|
9033
|
+
{
|
|
9034
|
+
type: "button",
|
|
9035
|
+
onClick: () => canEdit && setIsStatusDropdownOpen(!isStatusDropdownOpen),
|
|
9036
|
+
disabled: !canEdit,
|
|
9037
|
+
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"}`
|
|
9038
|
+
},
|
|
9039
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("span", { className: "text-slate-200 font-medium" }, status)),
|
|
9040
|
+
canEdit && /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isStatusDropdownOpen ? "rotate-180" : ""}` })
|
|
9041
|
+
), isStatusDropdownOpen && canEdit && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsStatusDropdownOpen(false) }), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement(
|
|
9042
|
+
"li",
|
|
9043
|
+
{
|
|
9044
|
+
key: s,
|
|
9045
|
+
onClick: () => {
|
|
9046
|
+
handleStatusChange(s);
|
|
9047
|
+
setIsStatusDropdownOpen(false);
|
|
9048
|
+
},
|
|
9049
|
+
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"}`
|
|
9050
|
+
},
|
|
9051
|
+
/* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
|
|
9052
|
+
s
|
|
9053
|
+
)))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.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__ */ import_react18.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiX, { size: 12 })))), canEdit && /* @__PURE__ */ import_react18.default.createElement(
|
|
9054
|
+
"input",
|
|
9055
|
+
{
|
|
9056
|
+
type: "text",
|
|
9057
|
+
value: typeInput,
|
|
9058
|
+
onChange: (e) => {
|
|
9059
|
+
setTypeInput(e.target.value);
|
|
9060
|
+
setShowTypeSuggestions(true);
|
|
9061
|
+
},
|
|
9062
|
+
onKeyDown: handleTypeInputKeyDown,
|
|
9063
|
+
onClick: () => setShowTypeSuggestions(true),
|
|
9064
|
+
onBlur: () => {
|
|
9065
|
+
if (typeInput.trim()) {
|
|
9066
|
+
handleAddType(typeInput);
|
|
9067
|
+
}
|
|
9068
|
+
setTimeout(() => setShowTypeSuggestions(false), 150);
|
|
9069
|
+
},
|
|
9070
|
+
className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200",
|
|
9071
|
+
placeholder: "",
|
|
9072
|
+
autoComplete: "off"
|
|
9073
|
+
}
|
|
9074
|
+
), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("li", { key: index, className: "px-3 py-2 text-sm text-slate-200 cursor-pointer hover:bg-indigo-600/50", onMouseDown: (e) => {
|
|
9075
|
+
e.preventDefault();
|
|
9076
|
+
handleAddType(suggestedType);
|
|
9077
|
+
} }, suggestedType))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement(DescriptionDisplay, { description, savedSections: existingSections, availableNodes, availableAncestries, onOpenReference, onMentionClick, onImageClick: handleImageClickFromText, onSaveDescription: handleSaveDescriptionInline }), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.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__ */ import_react18.default.createElement(import_fi16.FiBookOpen, { size: 14 })), canEdit && /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement(import_fi16.FiEdit2, { size: 14 }))), canEdit && !description && /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
|
|
9078
|
+
const isSelected = size === s;
|
|
9079
|
+
return /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.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__ */ import_react18.default.createElement(import_fi16.FiCheck, { size: 12, className: "text-white" })), /* @__PURE__ */ import_react18.default.createElement("span", { className: `text-sm capitalize transition-colors ${isSelected ? "text-white font-medium" : "text-slate-400 " + (canEdit ? "group-hover:text-slate-300" : "")}` }, s));
|
|
9080
|
+
}))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react18.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement(import_fi16.FiPlus, { size: 14 }), " Adicionar")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("div", { ref: propsEndRef }))), currentDatasetName && /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.createElement("span", { className: "truncate text-right" }, /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-slate-200 font-medium" }, currentDatasetName)))), /* @__PURE__ */ import_react18.default.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__ */ import_react18.default.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__ */ import_react18.default.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__ */ import_react18.default.createElement(import_fi16.FiLoader, { className: "animate-spin" }), isSaving ? "Salvando..." : "Salvar Quest")))
|
|
9081
|
+
), isDescriptionModalOpen && canEdit && /* @__PURE__ */ import_react18.default.createElement(
|
|
9082
|
+
DescriptionEditModal,
|
|
9083
|
+
{
|
|
9084
|
+
isOpen: isDescriptionModalOpen,
|
|
9085
|
+
title: "Editar Descri\xE7\xE3o da Quest",
|
|
9086
|
+
initialValue: description,
|
|
9087
|
+
onSave: (newDescription) => {
|
|
9088
|
+
setDescription(newDescription);
|
|
9089
|
+
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
9090
|
+
triggerAutoSave({ description: newDescription });
|
|
9091
|
+
},
|
|
9092
|
+
onClose: () => setIsDescriptionModalOpen(false),
|
|
9093
|
+
availableNodes,
|
|
9094
|
+
availableAncestries,
|
|
9095
|
+
availableImages
|
|
9096
|
+
}
|
|
9097
|
+
));
|
|
9098
|
+
}
|
|
9099
|
+
|
|
9100
|
+
// src/components/MultiNodeContextMenu.jsx
|
|
9101
|
+
var import_react19 = __toESM(require("react"));
|
|
9102
|
+
function MultiNodeContextMenu({
|
|
9103
|
+
data,
|
|
9104
|
+
userRole,
|
|
9105
|
+
onClose,
|
|
9106
|
+
onDismissNodes,
|
|
9107
|
+
onDismissOtherNodes,
|
|
9108
|
+
onDeleteNodes
|
|
9109
|
+
}) {
|
|
9110
|
+
const menuRef = (0, import_react19.useRef)(null);
|
|
9111
|
+
const [menuPos, setMenuPos] = (0, import_react19.useState)({ left: 0, top: 0 });
|
|
9112
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = (0, import_react19.useState)(false);
|
|
9113
|
+
const ability = defineAbilityFor(userRole);
|
|
9114
|
+
const canDelete = ability.can("delete", "Node");
|
|
9115
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
9116
|
+
if (!data.visible || !menuRef.current) return;
|
|
9117
|
+
const el = menuRef.current;
|
|
9118
|
+
const w = el.clientWidth;
|
|
9119
|
+
const h = el.clientHeight;
|
|
9120
|
+
const vw = window.innerWidth;
|
|
9121
|
+
const vh = window.innerHeight;
|
|
9122
|
+
let left = data.x + 8;
|
|
9123
|
+
let top = data.y + 8;
|
|
9124
|
+
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
9125
|
+
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
9126
|
+
setMenuPos({ left, top });
|
|
9127
|
+
}, [data]);
|
|
9128
|
+
(0, import_react19.useEffect)(() => {
|
|
9129
|
+
if (data.visible) {
|
|
9130
|
+
setIsConfirmingDelete(false);
|
|
9131
|
+
}
|
|
9132
|
+
const handleClickOutside = (e) => {
|
|
9133
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) onClose();
|
|
9134
|
+
};
|
|
9135
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
9136
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
9137
|
+
}, [data.visible, onClose]);
|
|
9138
|
+
if (!data.visible || !data.nodeIds || data.nodeIds.size === 0) return null;
|
|
9139
|
+
const swallow = (e) => e.stopPropagation();
|
|
9140
|
+
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";
|
|
9141
|
+
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";
|
|
9142
|
+
const nodeCount = data.nodeIds.size;
|
|
9143
|
+
return /* @__PURE__ */ import_react19.default.createElement(
|
|
9144
|
+
"div",
|
|
9145
|
+
{
|
|
9146
|
+
ref: menuRef,
|
|
9147
|
+
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",
|
|
9148
|
+
style: { position: "absolute", left: `${menuPos.left}px`, top: `${menuPos.top}px`, zIndex: 1e3 },
|
|
9149
|
+
onPointerDown: swallow,
|
|
9150
|
+
onPointerMove: swallow,
|
|
9151
|
+
onPointerUp: swallow,
|
|
9152
|
+
onClick: swallow,
|
|
9153
|
+
onWheel: swallow,
|
|
9154
|
+
onContextMenu: swallow,
|
|
9155
|
+
onDoubleClick: swallow
|
|
9156
|
+
},
|
|
9157
|
+
/* @__PURE__ */ import_react19.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }),
|
|
9158
|
+
/* @__PURE__ */ import_react19.default.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "w-10 h-10 rounded-full bg-red-500/20 flex items-center justify-center text-red-400 mb-1" }, /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("p", { className: "text-sm text-slate-200" }, "Excluir ", /* @__PURE__ */ import_react19.default.createElement("strong", null, nodeCount, " Nodes"), "?"), /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ import_react19.default.createElement(
|
|
9159
|
+
"button",
|
|
9160
|
+
{
|
|
9161
|
+
onClick: () => setIsConfirmingDelete(false),
|
|
9162
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
9163
|
+
},
|
|
9164
|
+
"Cancelar"
|
|
9165
|
+
), /* @__PURE__ */ import_react19.default.createElement(
|
|
9166
|
+
"button",
|
|
9167
|
+
{
|
|
9168
|
+
onClick: () => onDeleteNodes(data.nodeIds),
|
|
9169
|
+
className: "flex-1 px-2 py-2 text-xs font-medium bg-red-500 hover:bg-red-600 rounded-md text-white transition-colors"
|
|
9170
|
+
},
|
|
9171
|
+
"Excluir"
|
|
9172
|
+
))) : /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es em Grupo (", nodeCount, " Nodes)")), /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ import_react19.default.createElement("button", { onClick: () => onDismissNodes(data.nodeIds), className: baseButtonClass, title: "Remover da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.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__ */ import_react19.default.createElement("line", { x1: "2", y1: "2", x2: "22", y2: "22" })), /* @__PURE__ */ import_react19.default.createElement("span", null, "Dismiss (", nodeCount, ")")), /* @__PURE__ */ import_react19.default.createElement("button", { onClick: () => onDismissOtherNodes(data.nodeIds), className: baseButtonClass, title: "Remover outros da visualiza\xE7\xE3o" }, /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("circle", { cx: "12", cy: "12", r: "3" }), /* @__PURE__ */ import_react19.default.createElement("path", { d: "M3 7V5a2 2 0 0 1 2-2h2" }), /* @__PURE__ */ import_react19.default.createElement("path", { d: "M17 3h2a2 2 0 0 1 2 2v2" }), /* @__PURE__ */ import_react19.default.createElement("path", { d: "M21 17v2a2 2 0 0 1-2 2h-2" }), /* @__PURE__ */ import_react19.default.createElement("path", { d: "M7 21H5a2 2 0 0 1-2-2v-2" })), /* @__PURE__ */ import_react19.default.createElement("span", null, "Dismiss other nodes")), canDelete && /* @__PURE__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), /* @__PURE__ */ import_react19.default.createElement("button", { onClick: () => setIsConfirmingDelete(true), className: deleteButtonClass, title: "Excluir Nodes" }, /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react19.default.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__ */ import_react19.default.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), /* @__PURE__ */ import_react19.default.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" })), /* @__PURE__ */ import_react19.default.createElement("span", null, "Excluir Nodes (", nodeCount, ")"))))))
|
|
9173
|
+
);
|
|
9174
|
+
}
|
|
9175
|
+
|
|
9176
|
+
// src/components/RelationshipDetailsPanel.jsx
|
|
9177
|
+
var import_react20 = __toESM(require("react"));
|
|
9178
|
+
var import_fi17 = require("react-icons/fi");
|
|
9179
|
+
function RelationshipDetailsPanel({
|
|
9180
|
+
link,
|
|
9181
|
+
onClose,
|
|
9182
|
+
onSave,
|
|
9183
|
+
onDataUpdate,
|
|
9184
|
+
onOpenImageViewer,
|
|
9185
|
+
availableNodes = [],
|
|
9186
|
+
availableAncestries = [],
|
|
9187
|
+
onOpenReference,
|
|
9188
|
+
onMentionClick,
|
|
9189
|
+
onUploadFile,
|
|
9190
|
+
userRole
|
|
9191
|
+
}) {
|
|
9192
|
+
const [name, setName] = (0, import_react20.useState)((link == null ? void 0 : link.name) ?? "");
|
|
9193
|
+
const [description, setDescription] = (0, import_react20.useState)((link == null ? void 0 : link.description) ?? "");
|
|
9194
|
+
const [customProps, setCustomProps] = (0, import_react20.useState)(() => extractCustomPropsFromNode(link || {}));
|
|
9195
|
+
const [existingSections, setExistingSections] = (0, import_react20.useState)((link == null ? void 0 : link.description_sections) || []);
|
|
9196
|
+
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react20.useState)(false);
|
|
9197
|
+
const [isSaving, setIsSaving] = (0, import_react20.useState)(false);
|
|
9198
|
+
const [isReadMode, setIsReadMode] = (0, import_react20.useState)(false);
|
|
9199
|
+
const propsEndRef = (0, import_react20.useRef)(null);
|
|
9200
|
+
const canEdit = (0, import_react20.useMemo)(() => {
|
|
9201
|
+
const ability = defineAbilityFor(userRole);
|
|
9202
|
+
return ability.can("update", "Connection");
|
|
9203
|
+
}, [userRole]);
|
|
9204
|
+
(0, import_react20.useEffect)(() => {
|
|
9205
|
+
setName((link == null ? void 0 : link.name) ?? "");
|
|
9206
|
+
setDescription((link == null ? void 0 : link.description) ?? "");
|
|
9207
|
+
setExistingSections((link == null ? void 0 : link.description_sections) || []);
|
|
9208
|
+
setCustomProps(extractCustomPropsFromNode(link || {}));
|
|
9209
|
+
}, [link]);
|
|
9210
|
+
const swallow = (e) => e.stopPropagation();
|
|
9211
|
+
const handleAddProp = () => {
|
|
9212
|
+
if (!canEdit) return;
|
|
9213
|
+
const newProp = createNewCustomProperty(customProps);
|
|
9214
|
+
setCustomProps((p) => [...p, newProp]);
|
|
9215
|
+
setTimeout(() => {
|
|
9216
|
+
var _a;
|
|
9217
|
+
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
9218
|
+
}, 100);
|
|
9219
|
+
};
|
|
9220
|
+
const handleSave = async (keepOpen = false, overrides = {}) => {
|
|
9221
|
+
if (!canEdit) return;
|
|
9222
|
+
const currentDescription = overrides.description !== void 0 ? overrides.description : description;
|
|
9223
|
+
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
9224
|
+
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
9225
|
+
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
9226
|
+
setIsSaving(true);
|
|
9227
|
+
try {
|
|
9228
|
+
const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
|
|
9229
|
+
const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
|
|
8693
9230
|
const dataToSave = {
|
|
8694
9231
|
id: link.id,
|
|
8695
9232
|
source: link.source,
|
|
@@ -8739,7 +9276,7 @@ function RelationshipDetailsPanel({
|
|
|
8739
9276
|
onOpenImageViewer([{ name: name2 || "Imagem", value: url }], 0);
|
|
8740
9277
|
}
|
|
8741
9278
|
};
|
|
8742
|
-
return /* @__PURE__ */
|
|
9279
|
+
return /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(
|
|
8743
9280
|
"div",
|
|
8744
9281
|
{
|
|
8745
9282
|
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
|
|
@@ -8754,7 +9291,7 @@ function RelationshipDetailsPanel({
|
|
|
8754
9291
|
onContextMenu: swallow,
|
|
8755
9292
|
onDoubleClick: swallow
|
|
8756
9293
|
},
|
|
8757
|
-
isReadMode ? /* @__PURE__ */
|
|
9294
|
+
isReadMode ? /* @__PURE__ */ import_react20.default.createElement(
|
|
8758
9295
|
DescriptionReadModePanel,
|
|
8759
9296
|
{
|
|
8760
9297
|
title: name || "Rela\xE7\xE3o",
|
|
@@ -8775,7 +9312,7 @@ function RelationshipDetailsPanel({
|
|
|
8775
9312
|
onImageClick: handleImageClickFromText,
|
|
8776
9313
|
onSaveDescription: handleSaveDescriptionInline
|
|
8777
9314
|
}
|
|
8778
|
-
) : /* @__PURE__ */
|
|
9315
|
+
) : /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ import_react20.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react20.default.createElement("div", null, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ import_react20.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ import_react20.default.createElement(
|
|
8779
9316
|
"input",
|
|
8780
9317
|
{
|
|
8781
9318
|
type: "text",
|
|
@@ -8787,7 +9324,7 @@ function RelationshipDetailsPanel({
|
|
|
8787
9324
|
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
8788
9325
|
`
|
|
8789
9326
|
}
|
|
8790
|
-
)), /* @__PURE__ */
|
|
9327
|
+
)), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.createElement(
|
|
8791
9328
|
DescriptionDisplay,
|
|
8792
9329
|
{
|
|
8793
9330
|
description,
|
|
@@ -8799,7 +9336,7 @@ function RelationshipDetailsPanel({
|
|
|
8799
9336
|
onImageClick: handleImageClickFromText,
|
|
8800
9337
|
onSaveDescription: handleSaveDescriptionInline
|
|
8801
9338
|
}
|
|
8802
|
-
), /* @__PURE__ */
|
|
9339
|
+
), /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.createElement(
|
|
8803
9340
|
"button",
|
|
8804
9341
|
{
|
|
8805
9342
|
type: "button",
|
|
@@ -8807,8 +9344,8 @@ function RelationshipDetailsPanel({
|
|
|
8807
9344
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors border-r border-white/5",
|
|
8808
9345
|
title: "Modo de Leitura"
|
|
8809
9346
|
},
|
|
8810
|
-
/* @__PURE__ */
|
|
8811
|
-
), canEdit && /* @__PURE__ */
|
|
9347
|
+
/* @__PURE__ */ import_react20.default.createElement(import_fi17.FiBookOpen, { size: 14 })
|
|
9348
|
+
), canEdit && /* @__PURE__ */ import_react20.default.createElement(
|
|
8812
9349
|
"button",
|
|
8813
9350
|
{
|
|
8814
9351
|
type: "button",
|
|
@@ -8816,15 +9353,15 @@ function RelationshipDetailsPanel({
|
|
|
8816
9353
|
className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
8817
9354
|
title: "Editar descri\xE7\xE3o"
|
|
8818
9355
|
},
|
|
8819
|
-
/* @__PURE__ */
|
|
8820
|
-
)), !description && canEdit && /* @__PURE__ */
|
|
9356
|
+
/* @__PURE__ */ import_react20.default.createElement(import_fi17.FiEdit2, { size: 14 })
|
|
9357
|
+
)), !description && canEdit && /* @__PURE__ */ import_react20.default.createElement(
|
|
8821
9358
|
"div",
|
|
8822
9359
|
{
|
|
8823
9360
|
onClick: () => setIsDescriptionModalOpen(true),
|
|
8824
9361
|
className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
|
|
8825
9362
|
},
|
|
8826
9363
|
"Adicionar descri\xE7\xE3o..."
|
|
8827
|
-
))), /* @__PURE__ */
|
|
9364
|
+
))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react20.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.createElement(import_fi17.FiPlus, { size: 14 }), " Adicionar")), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react20.default.createElement(
|
|
8828
9365
|
CustomPropertyDisplay,
|
|
8829
9366
|
{
|
|
8830
9367
|
key: prop.id,
|
|
@@ -8836,7 +9373,7 @@ function RelationshipDetailsPanel({
|
|
|
8836
9373
|
onUploadFile,
|
|
8837
9374
|
disabled: !canEdit
|
|
8838
9375
|
}
|
|
8839
|
-
)), /* @__PURE__ */
|
|
9376
|
+
)), /* @__PURE__ */ import_react20.default.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ import_react20.default.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__ */ import_react20.default.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__ */ import_react20.default.createElement(
|
|
8840
9377
|
"button",
|
|
8841
9378
|
{
|
|
8842
9379
|
onClick: () => handleSave(false),
|
|
@@ -8845,10 +9382,10 @@ function RelationshipDetailsPanel({
|
|
|
8845
9382
|
${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"}
|
|
8846
9383
|
`
|
|
8847
9384
|
},
|
|
8848
|
-
isSaving && /* @__PURE__ */
|
|
9385
|
+
isSaving && /* @__PURE__ */ import_react20.default.createElement(import_fi17.FiLoader, { className: "animate-spin" }),
|
|
8849
9386
|
isSaving ? "Salvando..." : "Salvar"
|
|
8850
9387
|
)))
|
|
8851
|
-
), isDescriptionModalOpen && /* @__PURE__ */
|
|
9388
|
+
), isDescriptionModalOpen && /* @__PURE__ */ import_react20.default.createElement(
|
|
8852
9389
|
DescriptionEditModal,
|
|
8853
9390
|
{
|
|
8854
9391
|
isOpen: isDescriptionModalOpen,
|
|
@@ -8869,7 +9406,7 @@ function RelationshipDetailsPanel({
|
|
|
8869
9406
|
}
|
|
8870
9407
|
|
|
8871
9408
|
// src/components/RelationshipContextMenu.jsx
|
|
8872
|
-
var
|
|
9409
|
+
var import_react21 = __toESM(require("react"));
|
|
8873
9410
|
function RelationshipContextMenu({
|
|
8874
9411
|
data,
|
|
8875
9412
|
userRole,
|
|
@@ -8879,25 +9416,25 @@ function RelationshipContextMenu({
|
|
|
8879
9416
|
onDelete,
|
|
8880
9417
|
onClose
|
|
8881
9418
|
}) {
|
|
8882
|
-
const menuRef = (0,
|
|
8883
|
-
const [menuPos, setMenuPos] = (0,
|
|
8884
|
-
const [isConfirmingDelete, setIsConfirmingDelete] = (0,
|
|
8885
|
-
const ability = (0,
|
|
8886
|
-
const sourceName = (0,
|
|
9419
|
+
const menuRef = (0, import_react21.useRef)(null);
|
|
9420
|
+
const [menuPos, setMenuPos] = (0, import_react21.useState)({ left: 0, top: 0 });
|
|
9421
|
+
const [isConfirmingDelete, setIsConfirmingDelete] = (0, import_react21.useState)(false);
|
|
9422
|
+
const ability = (0, import_react21.useMemo)(() => defineAbilityFor(userRole), [userRole]);
|
|
9423
|
+
const sourceName = (0, import_react21.useMemo)(
|
|
8887
9424
|
() => {
|
|
8888
9425
|
var _a, _b, _c, _d;
|
|
8889
9426
|
return ((_d = (_c = (_b = (_a = data == null ? void 0 : data.linkObject) == null ? void 0 : _a.userData) == null ? void 0 : _b.sourceNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) ?? "(sem nome)";
|
|
8890
9427
|
},
|
|
8891
9428
|
[data == null ? void 0 : data.linkObject]
|
|
8892
9429
|
);
|
|
8893
|
-
const targetName = (0,
|
|
9430
|
+
const targetName = (0, import_react21.useMemo)(
|
|
8894
9431
|
() => {
|
|
8895
9432
|
var _a, _b, _c, _d;
|
|
8896
9433
|
return ((_d = (_c = (_b = (_a = data == null ? void 0 : data.linkObject) == null ? void 0 : _a.userData) == null ? void 0 : _b.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) ?? "(sem nome)";
|
|
8897
9434
|
},
|
|
8898
9435
|
[data == null ? void 0 : data.linkObject]
|
|
8899
9436
|
);
|
|
8900
|
-
(0,
|
|
9437
|
+
(0, import_react21.useLayoutEffect)(() => {
|
|
8901
9438
|
if (!data.visible || !menuRef.current) return;
|
|
8902
9439
|
const el = menuRef.current;
|
|
8903
9440
|
const w = el.clientWidth;
|
|
@@ -8910,7 +9447,7 @@ function RelationshipContextMenu({
|
|
|
8910
9447
|
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
8911
9448
|
setMenuPos({ left, top });
|
|
8912
9449
|
}, [data]);
|
|
8913
|
-
(0,
|
|
9450
|
+
(0, import_react21.useEffect)(() => {
|
|
8914
9451
|
if (data.visible) {
|
|
8915
9452
|
setIsConfirmingDelete(false);
|
|
8916
9453
|
}
|
|
@@ -8926,7 +9463,7 @@ function RelationshipContextMenu({
|
|
|
8926
9463
|
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";
|
|
8927
9464
|
const canUpdate = ability.can("update", "Connection");
|
|
8928
9465
|
const canDelete = ability.can("delete", "Connection");
|
|
8929
|
-
return /* @__PURE__ */
|
|
9466
|
+
return /* @__PURE__ */ import_react21.default.createElement(
|
|
8930
9467
|
"div",
|
|
8931
9468
|
{
|
|
8932
9469
|
ref: menuRef,
|
|
@@ -8940,29 +9477,29 @@ function RelationshipContextMenu({
|
|
|
8940
9477
|
onContextMenu: swallow,
|
|
8941
9478
|
onDoubleClick: swallow
|
|
8942
9479
|
},
|
|
8943
|
-
/* @__PURE__ */
|
|
8944
|
-
/* @__PURE__ */
|
|
9480
|
+
/* @__PURE__ */ import_react21.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
|
|
9481
|
+
/* @__PURE__ */ import_react21.default.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "w-10 h-10 rounded-full bg-rose-500/20 flex items-center justify-center text-rose-400 mb-1" }, /* @__PURE__ */ import_react21.default.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__ */ import_react21.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react21.default.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), /* @__PURE__ */ import_react21.default.createElement("path", { d: "M10 11v6" }), /* @__PURE__ */ import_react21.default.createElement("path", { d: "M14 11v6" }), /* @__PURE__ */ import_react21.default.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ import_react21.default.createElement("p", { className: "text-sm text-slate-200" }, "Excluir rela\xE7\xE3o?"), /* @__PURE__ */ import_react21.default.createElement("p", { className: "text-[11px] text-slate-400 leading-tight break-words" }, "Desconectar ", /* @__PURE__ */ import_react21.default.createElement("strong", null, sourceName), " de ", /* @__PURE__ */ import_react21.default.createElement("strong", null, targetName), ".")), /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ import_react21.default.createElement(
|
|
8945
9482
|
"button",
|
|
8946
9483
|
{
|
|
8947
9484
|
onClick: () => setIsConfirmingDelete(false),
|
|
8948
9485
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-white/10 hover:bg-white/20 rounded-md text-white transition-colors"
|
|
8949
9486
|
},
|
|
8950
9487
|
"Cancelar"
|
|
8951
|
-
), /* @__PURE__ */
|
|
9488
|
+
), /* @__PURE__ */ import_react21.default.createElement(
|
|
8952
9489
|
"button",
|
|
8953
9490
|
{
|
|
8954
9491
|
onClick: () => onDelete == null ? void 0 : onDelete(data.linkObject),
|
|
8955
9492
|
className: "flex-1 px-2 py-2 text-xs font-medium bg-rose-600 hover:bg-rose-500 rounded-md text-white transition-colors"
|
|
8956
9493
|
},
|
|
8957
9494
|
"Excluir"
|
|
8958
|
-
))) : /* @__PURE__ */
|
|
9495
|
+
))) : /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react21.default.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__ */ import_react21.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Rela\xE7\xE3o")), /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex flex-col gap-1" }, canUpdate && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement(
|
|
8959
9496
|
"button",
|
|
8960
9497
|
{
|
|
8961
9498
|
onClick: () => onRelinkSource == null ? void 0 : onRelinkSource(data.linkObject),
|
|
8962
9499
|
className: baseButtonClass,
|
|
8963
9500
|
title: "Desconectar ponta ligada ao Source"
|
|
8964
9501
|
},
|
|
8965
|
-
/* @__PURE__ */
|
|
9502
|
+
/* @__PURE__ */ import_react21.default.createElement(
|
|
8966
9503
|
"svg",
|
|
8967
9504
|
{
|
|
8968
9505
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8975,18 +9512,18 @@ function RelationshipContextMenu({
|
|
|
8975
9512
|
strokeLinecap: "round",
|
|
8976
9513
|
strokeLinejoin: "round"
|
|
8977
9514
|
},
|
|
8978
|
-
/* @__PURE__ */
|
|
8979
|
-
/* @__PURE__ */
|
|
9515
|
+
/* @__PURE__ */ import_react21.default.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" }),
|
|
9516
|
+
/* @__PURE__ */ import_react21.default.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" })
|
|
8980
9517
|
),
|
|
8981
|
-
/* @__PURE__ */
|
|
8982
|
-
), /* @__PURE__ */
|
|
9518
|
+
/* @__PURE__ */ import_react21.default.createElement("span", null, "Desconectar Source (", sourceName, ")")
|
|
9519
|
+
), /* @__PURE__ */ import_react21.default.createElement(
|
|
8983
9520
|
"button",
|
|
8984
9521
|
{
|
|
8985
9522
|
onClick: () => onRelinkTarget == null ? void 0 : onRelinkTarget(data.linkObject),
|
|
8986
9523
|
className: baseButtonClass,
|
|
8987
9524
|
title: "Desconectar ponta ligada ao Target"
|
|
8988
9525
|
},
|
|
8989
|
-
/* @__PURE__ */
|
|
9526
|
+
/* @__PURE__ */ import_react21.default.createElement(
|
|
8990
9527
|
"svg",
|
|
8991
9528
|
{
|
|
8992
9529
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -8999,21 +9536,21 @@ function RelationshipContextMenu({
|
|
|
8999
9536
|
strokeLinecap: "round",
|
|
9000
9537
|
strokeLinejoin: "round"
|
|
9001
9538
|
},
|
|
9002
|
-
/* @__PURE__ */
|
|
9003
|
-
/* @__PURE__ */
|
|
9004
|
-
/* @__PURE__ */
|
|
9005
|
-
/* @__PURE__ */
|
|
9006
|
-
/* @__PURE__ */
|
|
9539
|
+
/* @__PURE__ */ import_react21.default.createElement("polyline", { points: "16 3 21 3 21 8" }),
|
|
9540
|
+
/* @__PURE__ */ import_react21.default.createElement("line", { x1: "4", y1: "20", x2: "21", y2: "3" }),
|
|
9541
|
+
/* @__PURE__ */ import_react21.default.createElement("polyline", { points: "21 16 21 21 16 21" }),
|
|
9542
|
+
/* @__PURE__ */ import_react21.default.createElement("line", { x1: "15", y1: "15", x2: "21", y2: "21" }),
|
|
9543
|
+
/* @__PURE__ */ import_react21.default.createElement("line", { x1: "4", y1: "4", x2: "9", y2: "9" })
|
|
9007
9544
|
),
|
|
9008
|
-
/* @__PURE__ */
|
|
9009
|
-
), /* @__PURE__ */
|
|
9545
|
+
/* @__PURE__ */ import_react21.default.createElement("span", null, "Desconectar Target (", targetName, ")")
|
|
9546
|
+
), /* @__PURE__ */ import_react21.default.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" })), /* @__PURE__ */ import_react21.default.createElement(
|
|
9010
9547
|
"button",
|
|
9011
9548
|
{
|
|
9012
9549
|
onClick: () => onOpenDetails == null ? void 0 : onOpenDetails(data.linkObject),
|
|
9013
9550
|
className: baseButtonClass,
|
|
9014
9551
|
title: "Abrir detalhes da rela\xE7\xE3o"
|
|
9015
9552
|
},
|
|
9016
|
-
/* @__PURE__ */
|
|
9553
|
+
/* @__PURE__ */ import_react21.default.createElement(
|
|
9017
9554
|
"svg",
|
|
9018
9555
|
{
|
|
9019
9556
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -9026,19 +9563,19 @@ function RelationshipContextMenu({
|
|
|
9026
9563
|
strokeLinecap: "round",
|
|
9027
9564
|
strokeLinejoin: "round"
|
|
9028
9565
|
},
|
|
9029
|
-
/* @__PURE__ */
|
|
9030
|
-
/* @__PURE__ */
|
|
9031
|
-
/* @__PURE__ */
|
|
9566
|
+
/* @__PURE__ */ import_react21.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
9567
|
+
/* @__PURE__ */ import_react21.default.createElement("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
|
|
9568
|
+
/* @__PURE__ */ import_react21.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "8" })
|
|
9032
9569
|
),
|
|
9033
|
-
/* @__PURE__ */
|
|
9034
|
-
), canDelete && /* @__PURE__ */
|
|
9570
|
+
/* @__PURE__ */ import_react21.default.createElement("span", null, "Abrir Detalhes")
|
|
9571
|
+
), canDelete && /* @__PURE__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ import_react21.default.createElement(
|
|
9035
9572
|
"button",
|
|
9036
9573
|
{
|
|
9037
9574
|
onClick: () => setIsConfirmingDelete(true),
|
|
9038
9575
|
className: dangerButtonClass,
|
|
9039
9576
|
title: "Excluir esta conex\xE3o"
|
|
9040
9577
|
},
|
|
9041
|
-
/* @__PURE__ */
|
|
9578
|
+
/* @__PURE__ */ import_react21.default.createElement(
|
|
9042
9579
|
"svg",
|
|
9043
9580
|
{
|
|
9044
9581
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -9051,19 +9588,19 @@ function RelationshipContextMenu({
|
|
|
9051
9588
|
strokeLinecap: "round",
|
|
9052
9589
|
strokeLinejoin: "round"
|
|
9053
9590
|
},
|
|
9054
|
-
/* @__PURE__ */
|
|
9055
|
-
/* @__PURE__ */
|
|
9056
|
-
/* @__PURE__ */
|
|
9057
|
-
/* @__PURE__ */
|
|
9058
|
-
/* @__PURE__ */
|
|
9591
|
+
/* @__PURE__ */ import_react21.default.createElement("polyline", { points: "3 6 5 6 21 6" }),
|
|
9592
|
+
/* @__PURE__ */ import_react21.default.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }),
|
|
9593
|
+
/* @__PURE__ */ import_react21.default.createElement("path", { d: "M10 11v6" }),
|
|
9594
|
+
/* @__PURE__ */ import_react21.default.createElement("path", { d: "M14 11v6" }),
|
|
9595
|
+
/* @__PURE__ */ import_react21.default.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
|
|
9059
9596
|
),
|
|
9060
|
-
/* @__PURE__ */
|
|
9597
|
+
/* @__PURE__ */ import_react21.default.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
|
|
9061
9598
|
)))))
|
|
9062
9599
|
);
|
|
9063
9600
|
}
|
|
9064
9601
|
|
|
9065
9602
|
// src/components/LoadingScreen.jsx
|
|
9066
|
-
var
|
|
9603
|
+
var import_react22 = __toESM(require("react"));
|
|
9067
9604
|
var styles = {
|
|
9068
9605
|
loadingOverlay: {
|
|
9069
9606
|
position: "fixed",
|
|
@@ -9095,11 +9632,11 @@ var styles = {
|
|
|
9095
9632
|
`
|
|
9096
9633
|
};
|
|
9097
9634
|
function LoadingScreen() {
|
|
9098
|
-
return /* @__PURE__ */
|
|
9635
|
+
return /* @__PURE__ */ import_react22.default.createElement(import_react22.default.Fragment, null, /* @__PURE__ */ import_react22.default.createElement("style", null, styles.keyframes), /* @__PURE__ */ import_react22.default.createElement("div", { style: styles.loadingOverlay }, /* @__PURE__ */ import_react22.default.createElement("div", { style: styles.spinner })));
|
|
9099
9636
|
}
|
|
9100
9637
|
|
|
9101
9638
|
// src/components/ImportParentFileModal.jsx
|
|
9102
|
-
var
|
|
9639
|
+
var import_react23 = __toESM(require("react"));
|
|
9103
9640
|
function ImportParentFileModal({
|
|
9104
9641
|
isOpen,
|
|
9105
9642
|
onClose,
|
|
@@ -9110,12 +9647,12 @@ function ImportParentFileModal({
|
|
|
9110
9647
|
onFetchAvailableFiles,
|
|
9111
9648
|
currentViewName
|
|
9112
9649
|
}) {
|
|
9113
|
-
const [activeTab, setActiveTab] = (0,
|
|
9114
|
-
const [availableDbs, setAvailableDbs] = (0,
|
|
9115
|
-
const [availableViews, setAvailableViews] = (0,
|
|
9116
|
-
const [selectedItem, setSelectedItem] = (0,
|
|
9117
|
-
const [isLoading, setIsLoading] = (0,
|
|
9118
|
-
(0,
|
|
9650
|
+
const [activeTab, setActiveTab] = (0, import_react23.useState)("databases");
|
|
9651
|
+
const [availableDbs, setAvailableDbs] = (0, import_react23.useState)([]);
|
|
9652
|
+
const [availableViews, setAvailableViews] = (0, import_react23.useState)([]);
|
|
9653
|
+
const [selectedItem, setSelectedItem] = (0, import_react23.useState)(null);
|
|
9654
|
+
const [isLoading, setIsLoading] = (0, import_react23.useState)(false);
|
|
9655
|
+
(0, import_react23.useEffect)(() => {
|
|
9119
9656
|
if (isOpen && session && onFetchAvailableFiles) {
|
|
9120
9657
|
const fetchData = async () => {
|
|
9121
9658
|
setIsLoading(true);
|
|
@@ -9151,7 +9688,7 @@ function ImportParentFileModal({
|
|
|
9151
9688
|
fetchData();
|
|
9152
9689
|
}
|
|
9153
9690
|
}, [isOpen, session, parentDbs, onFetchAvailableFiles, currentViewName]);
|
|
9154
|
-
(0,
|
|
9691
|
+
(0, import_react23.useEffect)(() => {
|
|
9155
9692
|
setSelectedItem(null);
|
|
9156
9693
|
}, [activeTab]);
|
|
9157
9694
|
if (!isOpen) {
|
|
@@ -9180,13 +9717,13 @@ function ImportParentFileModal({
|
|
|
9180
9717
|
const swallow = (e) => e.stopPropagation();
|
|
9181
9718
|
const currentList = activeTab === "databases" ? availableDbs : availableViews;
|
|
9182
9719
|
const emptyMessage = activeTab === "databases" ? "Nenhum novo arquivo parent dispon\xEDvel." : "Nenhuma view dispon\xEDvel para importa\xE7\xE3o.";
|
|
9183
|
-
return /* @__PURE__ */
|
|
9720
|
+
return /* @__PURE__ */ import_react23.default.createElement(
|
|
9184
9721
|
"div",
|
|
9185
9722
|
{
|
|
9186
9723
|
className: "ui-overlay fixed inset-0 z-[1200] flex items-center justify-center bg-black/60 backdrop-blur-sm",
|
|
9187
9724
|
onClick: onClose
|
|
9188
9725
|
},
|
|
9189
|
-
/* @__PURE__ */
|
|
9726
|
+
/* @__PURE__ */ import_react23.default.createElement(
|
|
9190
9727
|
"div",
|
|
9191
9728
|
{
|
|
9192
9729
|
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]",
|
|
@@ -9198,14 +9735,14 @@ function ImportParentFileModal({
|
|
|
9198
9735
|
onContextMenu: swallow,
|
|
9199
9736
|
onDoubleClick: swallow
|
|
9200
9737
|
},
|
|
9201
|
-
/* @__PURE__ */
|
|
9738
|
+
/* @__PURE__ */ import_react23.default.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/10 flex-shrink-0" }, /* @__PURE__ */ import_react23.default.createElement("h2", { className: "text-lg font-semibold" }, "Importar"), /* @__PURE__ */ import_react23.default.createElement(
|
|
9202
9739
|
"button",
|
|
9203
9740
|
{
|
|
9204
9741
|
onClick: onClose,
|
|
9205
9742
|
className: "p-2 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
9206
9743
|
title: "Fechar"
|
|
9207
9744
|
},
|
|
9208
|
-
/* @__PURE__ */
|
|
9745
|
+
/* @__PURE__ */ import_react23.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ import_react23.default.createElement(
|
|
9209
9746
|
"path",
|
|
9210
9747
|
{
|
|
9211
9748
|
fillRule: "evenodd",
|
|
@@ -9214,14 +9751,14 @@ function ImportParentFileModal({
|
|
|
9214
9751
|
}
|
|
9215
9752
|
))
|
|
9216
9753
|
)),
|
|
9217
|
-
/* @__PURE__ */
|
|
9754
|
+
/* @__PURE__ */ import_react23.default.createElement("div", { className: "flex px-6 border-b border-white/10 bg-white/5 flex-shrink-0" }, /* @__PURE__ */ import_react23.default.createElement(
|
|
9218
9755
|
"button",
|
|
9219
9756
|
{
|
|
9220
9757
|
onClick: () => setActiveTab("databases"),
|
|
9221
9758
|
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"}`
|
|
9222
9759
|
},
|
|
9223
9760
|
"Arquivos Parent"
|
|
9224
|
-
), /* @__PURE__ */
|
|
9761
|
+
), /* @__PURE__ */ import_react23.default.createElement(
|
|
9225
9762
|
"button",
|
|
9226
9763
|
{
|
|
9227
9764
|
onClick: () => setActiveTab("views"),
|
|
@@ -9229,24 +9766,24 @@ function ImportParentFileModal({
|
|
|
9229
9766
|
},
|
|
9230
9767
|
"Views (Ancestralidades)"
|
|
9231
9768
|
)),
|
|
9232
|
-
/* @__PURE__ */
|
|
9769
|
+
/* @__PURE__ */ import_react23.default.createElement("div", { className: "p-6 overflow-y-auto custom-scrollbar flex-grow min-h-[200px]" }, isLoading ? /* @__PURE__ */ import_react23.default.createElement("div", { className: "flex items-center justify-center h-40" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "w-8 h-8 border-4 border-t-indigo-500 border-slate-700 rounded-full animate-spin" })) : /* @__PURE__ */ import_react23.default.createElement("div", { className: "space-y-2" }, currentList.length > 0 ? currentList.map((item) => /* @__PURE__ */ import_react23.default.createElement(
|
|
9233
9770
|
"div",
|
|
9234
9771
|
{
|
|
9235
9772
|
key: item.id,
|
|
9236
9773
|
onClick: () => setSelectedItem(item),
|
|
9237
9774
|
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"}`
|
|
9238
9775
|
},
|
|
9239
|
-
/* @__PURE__ */
|
|
9240
|
-
item.description && /* @__PURE__ */
|
|
9241
|
-
)) : /* @__PURE__ */
|
|
9242
|
-
/* @__PURE__ */
|
|
9776
|
+
/* @__PURE__ */ import_react23.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react23.default.createElement("span", { className: "font-medium text-slate-100" }, item.name), activeTab === "views" && /* @__PURE__ */ import_react23.default.createElement("span", { className: "text-[10px] px-1.5 py-0.5 rounded bg-black/30 text-indigo-300 border border-indigo-500/30" }, "VIEW")),
|
|
9777
|
+
item.description && /* @__PURE__ */ import_react23.default.createElement("p", { className: `text-xs ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "text-indigo-200" : "text-slate-400"}` }, item.description)
|
|
9778
|
+
)) : /* @__PURE__ */ import_react23.default.createElement("p", { className: "text-slate-400 text-center py-10" }, emptyMessage))),
|
|
9779
|
+
/* @__PURE__ */ import_react23.default.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__ */ import_react23.default.createElement(
|
|
9243
9780
|
"button",
|
|
9244
9781
|
{
|
|
9245
9782
|
onClick: onClose,
|
|
9246
9783
|
className: "px-4 py-2 rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-sm text-slate-300"
|
|
9247
9784
|
},
|
|
9248
9785
|
"Cancelar"
|
|
9249
|
-
), /* @__PURE__ */
|
|
9786
|
+
), /* @__PURE__ */ import_react23.default.createElement(
|
|
9250
9787
|
"button",
|
|
9251
9788
|
{
|
|
9252
9789
|
onClick: handleConfirm,
|
|
@@ -9260,8 +9797,8 @@ function ImportParentFileModal({
|
|
|
9260
9797
|
}
|
|
9261
9798
|
|
|
9262
9799
|
// src/components/AncestryLinkDetailsPanel.jsx
|
|
9263
|
-
var
|
|
9264
|
-
var
|
|
9800
|
+
var import_react24 = __toESM(require("react"));
|
|
9801
|
+
var import_fi18 = require("react-icons/fi");
|
|
9265
9802
|
function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenReference, onMentionClick, onUploadFile }) {
|
|
9266
9803
|
var _a, _b, _c, _d;
|
|
9267
9804
|
const relationshipData = data.relationship || {};
|
|
@@ -9270,21 +9807,21 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9270
9807
|
const customProps = extractCustomPropsFromNode(relationshipData);
|
|
9271
9808
|
const sourceName = ((_b = (_a = data.sourceNode) == null ? void 0 : _a.userData) == null ? void 0 : _b.name) || "Origem";
|
|
9272
9809
|
const targetName = ((_d = (_c = data.targetNode) == null ? void 0 : _c.userData) == null ? void 0 : _d.name) || "Destino";
|
|
9273
|
-
const [isReadMode, setIsReadMode] = (0,
|
|
9810
|
+
const [isReadMode, setIsReadMode] = (0, import_react24.useState)(false);
|
|
9274
9811
|
const swallow = (e) => e.stopPropagation();
|
|
9275
9812
|
const handleImageClickFromText = (url, name) => {
|
|
9276
9813
|
if (onOpenImageViewer) {
|
|
9277
9814
|
onOpenImageViewer([{ name: name || "Imagem", value: url }], 0);
|
|
9278
9815
|
}
|
|
9279
9816
|
};
|
|
9280
|
-
return /* @__PURE__ */
|
|
9817
|
+
return /* @__PURE__ */ import_react24.default.createElement(
|
|
9281
9818
|
"div",
|
|
9282
9819
|
{
|
|
9283
9820
|
className: "ui-overlay fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[1200]",
|
|
9284
9821
|
onClick: onClose,
|
|
9285
9822
|
onPointerDown: swallow
|
|
9286
9823
|
},
|
|
9287
|
-
/* @__PURE__ */
|
|
9824
|
+
/* @__PURE__ */ import_react24.default.createElement(
|
|
9288
9825
|
"div",
|
|
9289
9826
|
{
|
|
9290
9827
|
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
|
|
@@ -9292,7 +9829,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9292
9829
|
`,
|
|
9293
9830
|
onClick: swallow
|
|
9294
9831
|
},
|
|
9295
|
-
isReadMode ? /* @__PURE__ */
|
|
9832
|
+
isReadMode ? /* @__PURE__ */ import_react24.default.createElement(
|
|
9296
9833
|
DescriptionReadModePanel,
|
|
9297
9834
|
{
|
|
9298
9835
|
title: `${sourceName} \u2794 ${targetName}`,
|
|
@@ -9304,15 +9841,15 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9304
9841
|
onMentionClick,
|
|
9305
9842
|
onImageClick: handleImageClickFromText
|
|
9306
9843
|
}
|
|
9307
|
-
) : /* @__PURE__ */
|
|
9844
|
+
) : /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, /* @__PURE__ */ import_react24.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ import_react24.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react24.default.createElement("div", null, /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react24.default.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__ */ import_react24.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Ancestralidade")), /* @__PURE__ */ import_react24.default.createElement("h2", { className: "text-lg font-semibold tracking-tight flex items-center gap-2" }, /* @__PURE__ */ import_react24.default.createElement("span", { className: "truncate max-w-[150px]" }, sourceName), /* @__PURE__ */ import_react24.default.createElement("span", { className: "text-slate-500 text-sm" }, "\u2794"), /* @__PURE__ */ import_react24.default.createElement("span", { className: "truncate max-w-[150px]" }, targetName))), /* @__PURE__ */ import_react24.default.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__ */ import_react24.default.createElement("div", { className: "px-6 pb-6 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, description && /* @__PURE__ */ import_react24.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react24.default.createElement("label", { className: "text-xs text-slate-300 font-medium" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react24.default.createElement(
|
|
9308
9845
|
"button",
|
|
9309
9846
|
{
|
|
9310
9847
|
onClick: () => setIsReadMode(true),
|
|
9311
9848
|
className: "p-1 text-slate-400 hover:text-white transition-colors",
|
|
9312
9849
|
title: "Modo de Leitura"
|
|
9313
9850
|
},
|
|
9314
|
-
/* @__PURE__ */
|
|
9315
|
-
)), /* @__PURE__ */
|
|
9851
|
+
/* @__PURE__ */ import_react24.default.createElement(import_fi18.FiBookOpen, { size: 14 })
|
|
9852
|
+
)), /* @__PURE__ */ import_react24.default.createElement("div", { className: "bg-slate-800/40 rounded-lg border border-white/10 p-1 relative group" }, /* @__PURE__ */ import_react24.default.createElement(
|
|
9316
9853
|
DescriptionDisplay,
|
|
9317
9854
|
{
|
|
9318
9855
|
description,
|
|
@@ -9321,7 +9858,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9321
9858
|
onMentionClick,
|
|
9322
9859
|
onImageClick: handleImageClickFromText
|
|
9323
9860
|
}
|
|
9324
|
-
))), customProps.length > 0 && /* @__PURE__ */
|
|
9861
|
+
))), customProps.length > 0 && /* @__PURE__ */ import_react24.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react24.default.createElement("label", { className: "text-xs text-slate-300 font-medium mb-2 block" }, "Propriedades"), /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop) => /* @__PURE__ */ import_react24.default.createElement(
|
|
9325
9862
|
CustomPropertyDisplay,
|
|
9326
9863
|
{
|
|
9327
9864
|
key: prop.id,
|
|
@@ -9330,14 +9867,14 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9330
9867
|
onOpenImageViewer,
|
|
9331
9868
|
onUploadFile
|
|
9332
9869
|
}
|
|
9333
|
-
)))), !description && customProps.length === 0 && /* @__PURE__ */
|
|
9870
|
+
)))), !description && customProps.length === 0 && /* @__PURE__ */ import_react24.default.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__ */ import_react24.default.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".')))
|
|
9334
9871
|
)
|
|
9335
9872
|
);
|
|
9336
9873
|
}
|
|
9337
9874
|
|
|
9338
9875
|
// src/components/AncestryBoard.jsx
|
|
9339
|
-
var
|
|
9340
|
-
var
|
|
9876
|
+
var import_react25 = __toESM(require("react"));
|
|
9877
|
+
var import_fi19 = require("react-icons/fi");
|
|
9341
9878
|
var GroupItem = ({
|
|
9342
9879
|
group,
|
|
9343
9880
|
index,
|
|
@@ -9357,7 +9894,7 @@ var GroupItem = ({
|
|
|
9357
9894
|
}) => {
|
|
9358
9895
|
const canIndent = index > 0;
|
|
9359
9896
|
const isPickingForThisGroup = pickingGroupId === group.id;
|
|
9360
|
-
const textareaRef = (0,
|
|
9897
|
+
const textareaRef = (0, import_react25.useRef)(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
|
-
(0,
|
|
9905
|
+
(0, import_react25.useEffect)(() => {
|
|
9369
9906
|
adjustHeight();
|
|
9370
9907
|
}, [group.text]);
|
|
9371
|
-
return /* @__PURE__ */
|
|
9908
|
+
return /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiPlay, { size: 10, className: "ml-0.5 fill-current" })
|
|
9413
9950
|
)
|
|
9414
|
-
) : /* @__PURE__ */
|
|
9415
|
-
/* @__PURE__ */
|
|
9416
|
-
canEdit && /* @__PURE__ */
|
|
9951
|
+
) : /* @__PURE__ */ import_react25.default.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiAlertTriangle, { size: 10 })),
|
|
9952
|
+
/* @__PURE__ */ import_react25.default.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
|
|
9953
|
+
canEdit && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement("div", { className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}` }), /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiX, { size: 12 })
|
|
9424
9961
|
))
|
|
9425
9962
|
);
|
|
9426
|
-
})), canEdit && /* @__PURE__ */
|
|
9963
|
+
})), canEdit && /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiCheckCircle, { size: 12 }) : /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiSearch, { size: 12 }),
|
|
9437
9974
|
isPickingForThisGroup ? "Selecionando..." : "Adicionar"
|
|
9438
|
-
), /* @__PURE__ */
|
|
9975
|
+
), /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiPlus, { size: 14 })
|
|
9983
|
+
)), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiArrowRight, { size: 14 })
|
|
9992
|
+
), /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiArrowLeft, { size: 14 })
|
|
10000
|
+
), /* @__PURE__ */ import_react25.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiTrash2, { size: 14 })
|
|
10008
|
+
)))), group.children && group.children.length > 0 && /* @__PURE__ */ import_react25.default.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ import_react25.default.createElement(
|
|
9472
10009
|
GroupItem,
|
|
9473
10010
|
{
|
|
9474
10011
|
key: childGroup.id,
|
|
@@ -9500,21 +10037,21 @@ function AncestryBoard({
|
|
|
9500
10037
|
userRole
|
|
9501
10038
|
// [NOVO] Recebe a role do usuário
|
|
9502
10039
|
}) {
|
|
9503
|
-
const [searchTerm, setSearchTerm] = (0,
|
|
9504
|
-
const [groups, setGroups] = (0,
|
|
9505
|
-
const [isLoaded, setIsLoaded] = (0,
|
|
9506
|
-
const [pickingGroupId, setPickingGroupId] = (0,
|
|
9507
|
-
const [saveStatus, setSaveStatus] = (0,
|
|
9508
|
-
const canEdit = (0,
|
|
10040
|
+
const [searchTerm, setSearchTerm] = (0, import_react25.useState)("");
|
|
10041
|
+
const [groups, setGroups] = (0, import_react25.useState)([]);
|
|
10042
|
+
const [isLoaded, setIsLoaded] = (0, import_react25.useState)(false);
|
|
10043
|
+
const [pickingGroupId, setPickingGroupId] = (0, import_react25.useState)(null);
|
|
10044
|
+
const [saveStatus, setSaveStatus] = (0, import_react25.useState)("idle");
|
|
10045
|
+
const canEdit = (0, import_react25.useMemo)(() => {
|
|
9509
10046
|
return userRole !== "viewer";
|
|
9510
10047
|
}, [userRole]);
|
|
9511
|
-
(0,
|
|
10048
|
+
(0, import_react25.useEffect)(() => {
|
|
9512
10049
|
if (initialGroups && !isLoaded) {
|
|
9513
10050
|
setGroups(initialGroups);
|
|
9514
10051
|
setIsLoaded(true);
|
|
9515
10052
|
}
|
|
9516
10053
|
}, [initialGroups, isLoaded]);
|
|
9517
|
-
const nodeNamesMap = (0,
|
|
10054
|
+
const nodeNamesMap = (0, import_react25.useMemo)(() => {
|
|
9518
10055
|
const map = /* @__PURE__ */ new Map();
|
|
9519
10056
|
if (availableNodes && Array.isArray(availableNodes)) {
|
|
9520
10057
|
availableNodes.forEach((node) => {
|
|
@@ -9525,7 +10062,7 @@ function AncestryBoard({
|
|
|
9525
10062
|
}
|
|
9526
10063
|
return map;
|
|
9527
10064
|
}, [availableNodes]);
|
|
9528
|
-
const availableIds = (0,
|
|
10065
|
+
const availableIds = (0, import_react25.useMemo)(() => {
|
|
9529
10066
|
return new Set(availableAncestries.map((a) => String(a.ancestry_id)));
|
|
9530
10067
|
}, [availableAncestries]);
|
|
9531
10068
|
const sanitizeGroups = (groupList) => {
|
|
@@ -9539,7 +10076,7 @@ function AncestryBoard({
|
|
|
9539
10076
|
children: sanitizeGroups(g.children || [])
|
|
9540
10077
|
}));
|
|
9541
10078
|
};
|
|
9542
|
-
(0,
|
|
10079
|
+
(0, import_react25.useEffect)(() => {
|
|
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
|
-
(0,
|
|
10097
|
+
(0, import_react25.useEffect)(() => {
|
|
9561
10098
|
if (!isOpen) return;
|
|
9562
10099
|
const handleKeyDown = (e) => {
|
|
9563
10100
|
if (e.key === "Escape") {
|
|
@@ -9573,7 +10110,7 @@ function AncestryBoard({
|
|
|
9573
10110
|
window.addEventListener("keydown", handleKeyDown);
|
|
9574
10111
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
9575
10112
|
}, [isOpen, onClose, pickingGroupId]);
|
|
9576
|
-
const filtered = (0,
|
|
10113
|
+
const filtered = (0, import_react25.useMemo)(() => {
|
|
9577
10114
|
const term = searchTerm.toLowerCase().trim();
|
|
9578
10115
|
return availableAncestries.filter((a) => {
|
|
9579
10116
|
if (!term) return true;
|
|
@@ -9712,27 +10249,27 @@ function AncestryBoard({
|
|
|
9712
10249
|
});
|
|
9713
10250
|
};
|
|
9714
10251
|
if (!isOpen) return null;
|
|
9715
|
-
return /* @__PURE__ */
|
|
10252
|
+
return /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react25.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLoader, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, /* @__PURE__ */ import_react25.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ import_react25.default.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiPlus, { size: 14, className: "text-indigo-400" }),
|
|
10271
|
+
/* @__PURE__ */ import_react25.default.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
|
|
10272
|
+
), /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiSearch, { 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__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiPlus, { size: 16 }) : /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiLayers, { size: 14 })),
|
|
10316
|
+
/* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiCornerUpRight, { size: 10 }), /* @__PURE__ */ import_react25.default.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ import_react25.default.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
|
|
10317
|
+
!isPicking && /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlay, { size: 14, className: "ml-0.5" }))
|
|
9791
10328
|
)
|
|
9792
10329
|
);
|
|
9793
|
-
}))), /* @__PURE__ */
|
|
10330
|
+
}))), /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.createElement(import_fi19.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react25.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ import_react25.default.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ import_react25.default.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__ */ import_react25.default.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__ */ import_react25.default.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ import_react25.default.createElement("span", null, groups.length, " grupos raiz"))
|
|
9814
10351
|
)
|
|
9815
10352
|
);
|
|
9816
10353
|
}
|
|
@@ -9889,13 +10426,13 @@ function XViewScene({
|
|
|
9889
10426
|
delete_file_action,
|
|
9890
10427
|
check_user_permission
|
|
9891
10428
|
}) {
|
|
9892
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
9893
|
-
const { data: session, status } = (0,
|
|
10429
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
10430
|
+
const { data: session, status } = (0, import_react27.useSession)();
|
|
9894
10431
|
const router = (0, import_navigation.useRouter)();
|
|
9895
10432
|
const searchParams = (0, import_navigation.useSearchParams)();
|
|
9896
10433
|
const focusNodeId = searchParams == null ? void 0 : searchParams.get("focus");
|
|
9897
10434
|
const focusAncestryId = searchParams == null ? void 0 : searchParams.get("ancestry");
|
|
9898
|
-
const viewParams = (0,
|
|
10435
|
+
const viewParams = (0, import_react26.useMemo)(() => {
|
|
9899
10436
|
if (encryptedConfig) {
|
|
9900
10437
|
const data = decryptData(encryptedConfig);
|
|
9901
10438
|
if (data) {
|
|
@@ -9904,7 +10441,7 @@ function XViewScene({
|
|
|
9904
10441
|
}
|
|
9905
10442
|
return null;
|
|
9906
10443
|
}, [encryptedConfig, session]);
|
|
9907
|
-
(0,
|
|
10444
|
+
(0, import_react26.useEffect)(() => {
|
|
9908
10445
|
async function verifyPermission() {
|
|
9909
10446
|
if (!viewParams || !session || !check_user_permission) return;
|
|
9910
10447
|
const { id, type, owner_id } = viewParams;
|
|
@@ -9934,65 +10471,65 @@ function XViewScene({
|
|
|
9934
10471
|
setIsLoading(false);
|
|
9935
10472
|
}
|
|
9936
10473
|
}, [viewParams, session, status, check_user_permission]);
|
|
9937
|
-
const sceneConfigId = (0,
|
|
9938
|
-
const ownerId = (0,
|
|
9939
|
-
const dbSaveUrl = (0,
|
|
10474
|
+
const sceneConfigId = (0, import_react26.useMemo)(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
|
|
10475
|
+
const ownerId = (0, import_react26.useMemo)(() => (viewParams == null ? void 0 : viewParams.owner_id) || null, [viewParams]);
|
|
10476
|
+
const dbSaveUrl = (0, import_react26.useMemo)(() => {
|
|
9940
10477
|
if (ownerId && sceneConfigId) {
|
|
9941
10478
|
return `x_view_dbs/${ownerId}/${sceneConfigId}`;
|
|
9942
10479
|
}
|
|
9943
10480
|
return null;
|
|
9944
10481
|
}, [ownerId, sceneConfigId]);
|
|
9945
|
-
const sceneSaveUrl = (0,
|
|
10482
|
+
const sceneSaveUrl = (0, import_react26.useMemo)(() => {
|
|
9946
10483
|
if (ownerId && sceneConfigId) {
|
|
9947
10484
|
return `x_view_scenes/${ownerId}/${sceneConfigId}`;
|
|
9948
10485
|
}
|
|
9949
10486
|
return null;
|
|
9950
10487
|
}, [ownerId, sceneConfigId]);
|
|
9951
|
-
const ancestry_save_url = (0,
|
|
10488
|
+
const ancestry_save_url = (0, import_react26.useMemo)(() => {
|
|
9952
10489
|
if (ownerId && sceneConfigId) {
|
|
9953
10490
|
return `x_view_ancestry/${ownerId}/${sceneConfigId}`;
|
|
9954
10491
|
}
|
|
9955
10492
|
return null;
|
|
9956
10493
|
}, [ownerId, sceneConfigId]);
|
|
9957
|
-
const sceneDataRef = (0,
|
|
9958
|
-
const parentDataRef = (0,
|
|
9959
|
-
const ancestryDataRef = (0,
|
|
9960
|
-
const [isLoading, setIsLoading] = (0,
|
|
9961
|
-
const [permissionStatus, setPermissionStatus] = (0,
|
|
9962
|
-
const [userPermissionRole, setUserPermissionRole] = (0,
|
|
9963
|
-
const [isInitialized, setIsInitialized] = (0,
|
|
9964
|
-
const [sceneVersion, setSceneVersion] = (0,
|
|
9965
|
-
const [contextMenu, setContextMenu] = (0,
|
|
9966
|
-
const [multiContextMenu, setMultiContextMenu] = (0,
|
|
9967
|
-
const [relationshipMenu, setRelationshipMenu] = (0,
|
|
9968
|
-
const [creationMode, setCreationMode] = (0,
|
|
9969
|
-
const [versionMode, setVersionMode] = (0,
|
|
9970
|
-
const [questMode, setQuestMode] = (0,
|
|
9971
|
-
const [hasFocusedInitial, setHasFocusedInitial] = (0,
|
|
9972
|
-
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0,
|
|
9973
|
-
const [ancestryMode, setAncestryMode] = (0,
|
|
9974
|
-
const [readingMode, setReadingMode] = (0,
|
|
10494
|
+
const sceneDataRef = (0, import_react26.useRef)(null);
|
|
10495
|
+
const parentDataRef = (0, import_react26.useRef)(null);
|
|
10496
|
+
const ancestryDataRef = (0, import_react26.useRef)(null);
|
|
10497
|
+
const [isLoading, setIsLoading] = (0, import_react26.useState)(true);
|
|
10498
|
+
const [permissionStatus, setPermissionStatus] = (0, import_react26.useState)("loading");
|
|
10499
|
+
const [userPermissionRole, setUserPermissionRole] = (0, import_react26.useState)(null);
|
|
10500
|
+
const [isInitialized, setIsInitialized] = (0, import_react26.useState)(false);
|
|
10501
|
+
const [sceneVersion, setSceneVersion] = (0, import_react26.useState)(0);
|
|
10502
|
+
const [contextMenu, setContextMenu] = (0, import_react26.useState)({ visible: false, x: 0, y: 0, nodeData: null });
|
|
10503
|
+
const [multiContextMenu, setMultiContextMenu] = (0, import_react26.useState)({ visible: false, x: 0, y: 0, nodeIds: null });
|
|
10504
|
+
const [relationshipMenu, setRelationshipMenu] = (0, import_react26.useState)({ visible: false, x: 0, y: 0, linkObject: null });
|
|
10505
|
+
const [creationMode, setCreationMode] = (0, import_react26.useState)({ isActive: false, sourceNodeData: null });
|
|
10506
|
+
const [versionMode, setVersionMode] = (0, import_react26.useState)({ isActive: false, sourceNodeData: null });
|
|
10507
|
+
const [questMode, setQuestMode] = (0, import_react26.useState)({ isActive: false });
|
|
10508
|
+
const [hasFocusedInitial, setHasFocusedInitial] = (0, import_react26.useState)(false);
|
|
10509
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0, import_react26.useState)(false);
|
|
10510
|
+
const [ancestryMode, setAncestryMode] = (0, import_react26.useState)({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
|
|
10511
|
+
const [readingMode, setReadingMode] = (0, import_react26.useState)({
|
|
9975
10512
|
isActive: false,
|
|
9976
10513
|
ancestry: null,
|
|
9977
10514
|
branchStack: [],
|
|
9978
10515
|
autoAbstraction: false
|
|
9979
10516
|
});
|
|
9980
|
-
const [formPosition, setFormPosition] = (0,
|
|
9981
|
-
const [detailsNode, setDetailsNode] = (0,
|
|
9982
|
-
const [detailsLink, setDetailsLink] = (0,
|
|
9983
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] = (0,
|
|
9984
|
-
const [imageViewer, setImageViewer] = (0,
|
|
9985
|
-
const [editingAncestryRel, setEditingAncestryRel] = (0,
|
|
9986
|
-
const [isImportModalOpen, setIsImportModalOpen] = (0,
|
|
9987
|
-
const [importSuccessMessage, setImportSuccessMessage] = (0,
|
|
9988
|
-
const [highlightedNodeId, setHighlightedNodeId] = (0,
|
|
9989
|
-
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = (0,
|
|
9990
|
-
const [ancestryBoardData, setAncestryBoardData] = (0,
|
|
9991
|
-
const [isSidebarOpen, setIsSidebarOpen] = (0,
|
|
9992
|
-
const mountRef = (0,
|
|
9993
|
-
const tooltipRef = (0,
|
|
9994
|
-
const formRef = (0,
|
|
9995
|
-
const stateRef = (0,
|
|
10517
|
+
const [formPosition, setFormPosition] = (0, import_react26.useState)({ left: 16, top: 16, opacity: 0 });
|
|
10518
|
+
const [detailsNode, setDetailsNode] = (0, import_react26.useState)(null);
|
|
10519
|
+
const [detailsLink, setDetailsLink] = (0, import_react26.useState)(null);
|
|
10520
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = (0, import_react26.useState)(null);
|
|
10521
|
+
const [imageViewer, setImageViewer] = (0, import_react26.useState)({ visible: false, images: [], startIndex: 0 });
|
|
10522
|
+
const [editingAncestryRel, setEditingAncestryRel] = (0, import_react26.useState)({ visible: false, data: null, path: null });
|
|
10523
|
+
const [isImportModalOpen, setIsImportModalOpen] = (0, import_react26.useState)(false);
|
|
10524
|
+
const [importSuccessMessage, setImportSuccessMessage] = (0, import_react26.useState)("");
|
|
10525
|
+
const [highlightedNodeId, setHighlightedNodeId] = (0, import_react26.useState)(null);
|
|
10526
|
+
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = (0, import_react26.useState)(false);
|
|
10527
|
+
const [ancestryBoardData, setAncestryBoardData] = (0, import_react26.useState)([]);
|
|
10528
|
+
const [isSidebarOpen, setIsSidebarOpen] = (0, import_react26.useState)(false);
|
|
10529
|
+
const mountRef = (0, import_react26.useRef)(null);
|
|
10530
|
+
const tooltipRef = (0, import_react26.useRef)(null);
|
|
10531
|
+
const formRef = (0, import_react26.useRef)(null);
|
|
10532
|
+
const stateRef = (0, import_react26.useRef)({
|
|
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
|
-
(0,
|
|
10577
|
+
(0, import_react26.useEffect)(() => {
|
|
10041
10578
|
stateRef.current.ancestry = ancestryMode;
|
|
10042
10579
|
}, [ancestryMode]);
|
|
10043
|
-
(0,
|
|
10580
|
+
(0, import_react26.useEffect)(() => {
|
|
10044
10581
|
var _a2;
|
|
10045
10582
|
if (!isInitialized) return;
|
|
10046
10583
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -10061,10 +10598,10 @@ function XViewScene({
|
|
|
10061
10598
|
}
|
|
10062
10599
|
stateRef.current.nodeIdToParentFileMap = map;
|
|
10063
10600
|
}, [isInitialized, sceneVersion]);
|
|
10064
|
-
const handleNavigateBack = (0,
|
|
10601
|
+
const handleNavigateBack = (0, import_react26.useCallback)(() => {
|
|
10065
10602
|
router.push("/dashboard/scenes");
|
|
10066
10603
|
}, [router]);
|
|
10067
|
-
const handleConfirmImport = (0,
|
|
10604
|
+
const handleConfirmImport = (0, import_react26.useCallback)(
|
|
10068
10605
|
async (importPayload) => {
|
|
10069
10606
|
var _a2, _b2;
|
|
10070
10607
|
let files = [];
|
|
@@ -10162,7 +10699,7 @@ function XViewScene({
|
|
|
10162
10699
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
10163
10700
|
setImageViewer({ visible: true, images, startIndex });
|
|
10164
10701
|
};
|
|
10165
|
-
const tweenToTarget = (0,
|
|
10702
|
+
const tweenToTarget = (0, import_react26.useCallback)((target, zoomFactor = 1, forcedDirection = null) => {
|
|
10166
10703
|
const { camera, controls, tweenGroup } = stateRef.current;
|
|
10167
10704
|
if (!camera || !controls || !tweenGroup) return;
|
|
10168
10705
|
const targetPos = target instanceof THREE3.Mesh ? target.getWorldPosition(new THREE3.Vector3()) : target;
|
|
@@ -10185,7 +10722,7 @@ function XViewScene({
|
|
|
10185
10722
|
if (!t || typeof t.closest !== "function") return false;
|
|
10186
10723
|
return !!t.closest(".ui-overlay");
|
|
10187
10724
|
};
|
|
10188
|
-
const buildFullAncestryTree = (0,
|
|
10725
|
+
const buildFullAncestryTree = (0, import_react26.useCallback)((idTree, nodes, ancestries = []) => {
|
|
10189
10726
|
if (!idTree) return null;
|
|
10190
10727
|
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
10191
10728
|
const ancestryMap = new Map(ancestries.map((a) => [String(a.ancestry_id), a]));
|
|
@@ -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
|
|
@@ -10261,7 +10798,7 @@ function XViewScene({
|
|
|
10261
10798
|
}
|
|
10262
10799
|
return recursiveBuild(idTree);
|
|
10263
10800
|
}, []);
|
|
10264
|
-
const handleActivateTimeline = (0,
|
|
10801
|
+
const handleActivateTimeline = (0, import_react26.useCallback)(() => {
|
|
10265
10802
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
10266
10803
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
10267
10804
|
while (timelineIntervalsGroup.children.length > 0) {
|
|
@@ -10414,7 +10951,7 @@ function XViewScene({
|
|
|
10414
10951
|
}
|
|
10415
10952
|
});
|
|
10416
10953
|
}, []);
|
|
10417
|
-
const handleVersionTimeline = (0,
|
|
10954
|
+
const handleVersionTimeline = (0, import_react26.useCallback)((sourceMesh, versionMeshes) => {
|
|
10418
10955
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
10419
10956
|
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0) return;
|
|
10420
10957
|
versionMeshes.forEach((mesh) => {
|
|
@@ -10537,7 +11074,7 @@ function XViewScene({
|
|
|
10537
11074
|
}
|
|
10538
11075
|
});
|
|
10539
11076
|
}, []);
|
|
10540
|
-
(0,
|
|
11077
|
+
(0, import_react26.useEffect)(() => {
|
|
10541
11078
|
async function fetchAllData(configPath, ownerId2) {
|
|
10542
11079
|
var _a2, _b2;
|
|
10543
11080
|
if (!get_scene_view_data) {
|
|
@@ -10609,12 +11146,12 @@ function XViewScene({
|
|
|
10609
11146
|
focusNodeId,
|
|
10610
11147
|
focusAncestryId
|
|
10611
11148
|
]);
|
|
10612
|
-
const isNodeInView = (0,
|
|
11149
|
+
const isNodeInView = (0, import_react26.useCallback)((id) => {
|
|
10613
11150
|
const key = String(id);
|
|
10614
11151
|
const objs = stateRef.current.nodeObjects || {};
|
|
10615
11152
|
return !!objs[key];
|
|
10616
11153
|
}, []);
|
|
10617
|
-
const addOrUpdateNodeMesh = (0,
|
|
11154
|
+
const addOrUpdateNodeMesh = (0, import_react26.useCallback)((nodeData, position, suppressVersionUpdate = false) => {
|
|
10618
11155
|
const { graphGroup, nodeObjects, clickableNodes, glowTexture, tweenGroup } = stateRef.current;
|
|
10619
11156
|
const nodeId = String(nodeData.id);
|
|
10620
11157
|
if (nodeObjects[nodeId]) {
|
|
@@ -10641,7 +11178,7 @@ function XViewScene({
|
|
|
10641
11178
|
}
|
|
10642
11179
|
return mesh;
|
|
10643
11180
|
}, []);
|
|
10644
|
-
(0,
|
|
11181
|
+
(0, import_react26.useEffect)(() => {
|
|
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);
|
|
@@ -11286,7 +11788,7 @@ function XViewScene({
|
|
|
11286
11788
|
}
|
|
11287
11789
|
};
|
|
11288
11790
|
}, [isInitialized, tweenToTarget, dbSaveUrl, isNodeInView, addOrUpdateNodeMesh, handleActivateTimeline, get_scene_view_data, save_view_data]);
|
|
11289
|
-
const handleGhostNodeImageChange = (0,
|
|
11791
|
+
const handleGhostNodeImageChange = (0, import_react26.useCallback)((useImage, imageUrl) => {
|
|
11290
11792
|
const { node: ghostNode, line: ghostLine, aura: ghostAura } = stateRef.current.ghostElements;
|
|
11291
11793
|
const { graphGroup, glowTexture } = stateRef.current;
|
|
11292
11794
|
if (!ghostNode || !graphGroup) return;
|
|
@@ -11328,7 +11830,7 @@ function XViewScene({
|
|
|
11328
11830
|
aura: newGhostNode.getObjectByName("aura")
|
|
11329
11831
|
};
|
|
11330
11832
|
}, []);
|
|
11331
|
-
const handleGhostNodeIntensityChange = (0,
|
|
11833
|
+
const handleGhostNodeIntensityChange = (0, import_react26.useCallback)((newIntensity) => {
|
|
11332
11834
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
11333
11835
|
if (!ghostNode) return;
|
|
11334
11836
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -11349,7 +11851,7 @@ function XViewScene({
|
|
|
11349
11851
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
11350
11852
|
}
|
|
11351
11853
|
}, []);
|
|
11352
|
-
const handleDetailNodeIntensityChange = (0,
|
|
11854
|
+
const handleDetailNodeIntensityChange = (0, import_react26.useCallback)((nodeId, newIntensity) => {
|
|
11353
11855
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
11354
11856
|
if (!mesh) return;
|
|
11355
11857
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -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;
|
|
@@ -11495,7 +12002,7 @@ function XViewScene({
|
|
|
11495
12002
|
mountRef.current.style.cursor = "default";
|
|
11496
12003
|
}
|
|
11497
12004
|
};
|
|
11498
|
-
const handleAncestryTreeUpdate = (0,
|
|
12005
|
+
const handleAncestryTreeUpdate = (0, import_react26.useCallback)((newTree, extraData = null) => {
|
|
11499
12006
|
setAncestryMode((prev) => {
|
|
11500
12007
|
const prevTreeStr = JSON.stringify(prev.tree);
|
|
11501
12008
|
const newTreeStr = JSON.stringify(newTree);
|
|
@@ -11515,7 +12022,7 @@ function XViewScene({
|
|
|
11515
12022
|
};
|
|
11516
12023
|
});
|
|
11517
12024
|
}, []);
|
|
11518
|
-
const actionHandlerContext = (0,
|
|
12025
|
+
const actionHandlerContext = (0, import_react26.useMemo)(
|
|
11519
12026
|
() => {
|
|
11520
12027
|
var _a2;
|
|
11521
12028
|
return {
|
|
@@ -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 = (0, import_react26.useCallback)(() => {
|
|
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: import_short_uuid2.default.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 {
|
|
@@ -11688,7 +12197,7 @@ function XViewScene({
|
|
|
11688
12197
|
}
|
|
11689
12198
|
userActionHandlers.handleCancelConnection(context);
|
|
11690
12199
|
};
|
|
11691
|
-
const handleClearAncestryVisuals = (0,
|
|
12200
|
+
const handleClearAncestryVisuals = (0, import_react26.useCallback)((ancestryId) => {
|
|
11692
12201
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
11693
12202
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
11694
12203
|
if (renderIndex !== -1) {
|
|
@@ -11702,7 +12211,7 @@ function XViewScene({
|
|
|
11702
12211
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
11703
12212
|
}
|
|
11704
12213
|
}, []);
|
|
11705
|
-
const handleRenderAncestry = (0,
|
|
12214
|
+
const handleRenderAncestry = (0, import_react26.useCallback)(
|
|
11706
12215
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
11707
12216
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11708
12217
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -12118,7 +12627,7 @@ function XViewScene({
|
|
|
12118
12627
|
},
|
|
12119
12628
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
12120
12629
|
);
|
|
12121
|
-
const handleRenderAbstractionTree = (0,
|
|
12630
|
+
const handleRenderAbstractionTree = (0, import_react26.useCallback)((ancestryObject, targetNodeId = null) => {
|
|
12122
12631
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
12123
12632
|
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
12124
12633
|
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
@@ -12179,7 +12688,7 @@ function XViewScene({
|
|
|
12179
12688
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
12180
12689
|
tweenToTarget(rootTargetPos, 0.7);
|
|
12181
12690
|
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
12182
|
-
const handleReadModeBranchNav = (0,
|
|
12691
|
+
const handleReadModeBranchNav = (0, import_react26.useCallback)((nodeId, action, direction = "right") => {
|
|
12183
12692
|
const { ancestry, branchStack } = readingMode;
|
|
12184
12693
|
if (!ancestry || !ancestry.tree) return;
|
|
12185
12694
|
const allAncestries = ancestryDataRef.current || [];
|
|
@@ -12320,13 +12829,13 @@ function XViewScene({
|
|
|
12320
12829
|
}));
|
|
12321
12830
|
}
|
|
12322
12831
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
12323
|
-
const handleReadModeHighlight = (0,
|
|
12832
|
+
const handleReadModeHighlight = (0, import_react26.useCallback)((nodeId) => {
|
|
12324
12833
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
12325
12834
|
stateRef.current.highlightedNodeId = nodeId;
|
|
12326
12835
|
}
|
|
12327
12836
|
setHighlightedNodeId(nodeId);
|
|
12328
12837
|
}, []);
|
|
12329
|
-
const activeNodeBranches = (0,
|
|
12838
|
+
const activeNodeBranches = (0, import_react26.useMemo)(() => {
|
|
12330
12839
|
if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree) return null;
|
|
12331
12840
|
const fullTree = buildFullAncestryTree(
|
|
12332
12841
|
readingMode.ancestry.tree,
|
|
@@ -12363,7 +12872,7 @@ function XViewScene({
|
|
|
12363
12872
|
}
|
|
12364
12873
|
return null;
|
|
12365
12874
|
}, [highlightedNodeId, readingMode.ancestry, buildFullAncestryTree, readingMode.branchStack, ancestryDataRef.current]);
|
|
12366
|
-
const backNavigationInfo = (0,
|
|
12875
|
+
const backNavigationInfo = (0, import_react26.useMemo)(() => {
|
|
12367
12876
|
const { branchStack } = readingMode;
|
|
12368
12877
|
if (!branchStack || branchStack.length === 0) return null;
|
|
12369
12878
|
const lastStep = branchStack[branchStack.length - 1];
|
|
@@ -12374,7 +12883,7 @@ function XViewScene({
|
|
|
12374
12883
|
name: "Voltar para anterior"
|
|
12375
12884
|
};
|
|
12376
12885
|
}, [readingMode.branchStack]);
|
|
12377
|
-
const getReadModeDisplayContext = (0,
|
|
12886
|
+
const getReadModeDisplayContext = (0, import_react26.useMemo)(() => {
|
|
12378
12887
|
const { ancestry, branchStack } = readingMode;
|
|
12379
12888
|
if (!ancestry) return null;
|
|
12380
12889
|
if (branchStack.length === 0) {
|
|
@@ -12415,7 +12924,7 @@ function XViewScene({
|
|
|
12415
12924
|
customProperties: branchProps
|
|
12416
12925
|
};
|
|
12417
12926
|
}, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
|
|
12418
|
-
const readModeAbstractionTree = (0,
|
|
12927
|
+
const readModeAbstractionTree = (0, import_react26.useMemo)(() => {
|
|
12419
12928
|
if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
|
|
12420
12929
|
return null;
|
|
12421
12930
|
}
|
|
@@ -12427,7 +12936,7 @@ function XViewScene({
|
|
|
12427
12936
|
allAncestries
|
|
12428
12937
|
);
|
|
12429
12938
|
}, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
|
|
12430
|
-
const handleStartReadingAncestry = (0,
|
|
12939
|
+
const handleStartReadingAncestry = (0, import_react26.useCallback)(
|
|
12431
12940
|
async (ancestryObject) => {
|
|
12432
12941
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
12433
12942
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -12462,7 +12971,7 @@ function XViewScene({
|
|
|
12462
12971
|
},
|
|
12463
12972
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
12464
12973
|
);
|
|
12465
|
-
const handleReadModeSectionChange = (0,
|
|
12974
|
+
const handleReadModeSectionChange = (0, import_react26.useCallback)((activeSectionId) => {
|
|
12466
12975
|
const { ancestry, branchStack } = readingMode;
|
|
12467
12976
|
if (!ancestry || !readingMode.isActive) return;
|
|
12468
12977
|
let targetObj = ancestry;
|
|
@@ -12531,10 +13040,10 @@ function XViewScene({
|
|
|
12531
13040
|
}, 0);
|
|
12532
13041
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
12533
13042
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
|
|
12534
|
-
const handleCloseReadMode = (0,
|
|
13043
|
+
const handleCloseReadMode = (0, import_react26.useCallback)(() => {
|
|
12535
13044
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
12536
13045
|
}, []);
|
|
12537
|
-
const handleAncestrySectionChange = (0,
|
|
13046
|
+
const handleAncestrySectionChange = (0, import_react26.useCallback)((activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
12538
13047
|
var _a2, _b2;
|
|
12539
13048
|
const currentMode = stateRef.current.ancestry;
|
|
12540
13049
|
let targetObj = ancestryOverride;
|
|
@@ -12586,7 +13095,7 @@ function XViewScene({
|
|
|
12586
13095
|
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
12587
13096
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
12588
13097
|
}, [handleRenderAncestry]);
|
|
12589
|
-
const handleEditAncestry = (0,
|
|
13098
|
+
const handleEditAncestry = (0, import_react26.useCallback)(
|
|
12590
13099
|
async (ancestryObject) => {
|
|
12591
13100
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
12592
13101
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -12625,7 +13134,7 @@ function XViewScene({
|
|
|
12625
13134
|
const handleSelectAncestryParent = (nodeId) => {
|
|
12626
13135
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
12627
13136
|
};
|
|
12628
|
-
const handleRemoveFromAncestry = (0,
|
|
13137
|
+
const handleRemoveFromAncestry = (0, import_react26.useCallback)((pathToRemove) => {
|
|
12629
13138
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
12630
13139
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
12631
13140
|
return;
|
|
@@ -12650,7 +13159,7 @@ function XViewScene({
|
|
|
12650
13159
|
return { ...prev, tree: newTree };
|
|
12651
13160
|
});
|
|
12652
13161
|
}, []);
|
|
12653
|
-
const handleSaveAncestry = (0,
|
|
13162
|
+
const handleSaveAncestry = (0, import_react26.useCallback)(
|
|
12654
13163
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
12655
13164
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
12656
13165
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -12854,7 +13363,7 @@ function XViewScene({
|
|
|
12854
13363
|
});
|
|
12855
13364
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
12856
13365
|
};
|
|
12857
|
-
const handleDeleteAncestry = (0,
|
|
13366
|
+
const handleDeleteAncestry = (0, import_react26.useCallback)(
|
|
12858
13367
|
async (ancestryIdToDelete) => {
|
|
12859
13368
|
if (!ancestryIdToDelete) {
|
|
12860
13369
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -12916,30 +13425,30 @@ function XViewScene({
|
|
|
12916
13425
|
},
|
|
12917
13426
|
[save_view_data, delete_file_action]
|
|
12918
13427
|
);
|
|
12919
|
-
const handleOpenAncestryBoard = (0,
|
|
13428
|
+
const handleOpenAncestryBoard = (0, import_react26.useCallback)(() => {
|
|
12920
13429
|
setIsAncestryBoardOpen(true);
|
|
12921
13430
|
}, []);
|
|
12922
|
-
const handleSelectAncestryFromBoard = (0,
|
|
13431
|
+
const handleSelectAncestryFromBoard = (0, import_react26.useCallback)((ancestry) => {
|
|
12923
13432
|
setIsAncestryBoardOpen(false);
|
|
12924
13433
|
setIsSidebarOpen(false);
|
|
12925
13434
|
handleStartReadingAncestry(ancestry);
|
|
12926
13435
|
}, [handleStartReadingAncestry]);
|
|
12927
|
-
const handleSaveAncestryBoard = (0,
|
|
13436
|
+
const handleSaveAncestryBoard = (0, import_react26.useCallback)(async (groups) => {
|
|
12928
13437
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
12929
13438
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
12930
13439
|
await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
|
|
12931
13440
|
}, [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]);
|
|
12932
|
-
const existingNodeTypes = (0,
|
|
13441
|
+
const existingNodeTypes = (0, import_react26.useMemo)(() => {
|
|
12933
13442
|
if (!parentDataRef.current) {
|
|
12934
13443
|
return [];
|
|
12935
13444
|
}
|
|
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
|
-
const searchableDbNodes = (0,
|
|
13451
|
+
const searchableDbNodes = (0, import_react26.useMemo)(() => {
|
|
12943
13452
|
if (!parentDataRef.current) {
|
|
12944
13453
|
return [];
|
|
12945
13454
|
}
|
|
@@ -12948,14 +13457,14 @@ function XViewScene({
|
|
|
12948
13457
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
12949
13458
|
});
|
|
12950
13459
|
}, [parentDataRef.current, sceneVersion]);
|
|
12951
|
-
const handleAddExistingNode = (0,
|
|
13460
|
+
const handleAddExistingNode = (0, import_react26.useCallback)(
|
|
12952
13461
|
(nodeId) => {
|
|
12953
13462
|
return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
|
|
12954
13463
|
},
|
|
12955
13464
|
[actionHandlerContext]
|
|
12956
13465
|
);
|
|
12957
|
-
const handleSaveCurrentView = (0,
|
|
12958
|
-
var _a2, _b2;
|
|
13466
|
+
const handleSaveCurrentView = (0, import_react26.useCallback)(async () => {
|
|
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,28 +13486,30 @@ 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]);
|
|
12994
|
-
const allAvailableNodes = (0,
|
|
13504
|
+
}, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
|
|
13505
|
+
const allAvailableNodes = (0, import_react26.useMemo)(() => {
|
|
12995
13506
|
if (!parentDataRef.current) return [];
|
|
12996
13507
|
return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
|
|
12997
13508
|
}, [sceneVersion, isInitialized]);
|
|
12998
|
-
const allAvailableAncestries = (0,
|
|
13509
|
+
const allAvailableAncestries = (0, import_react26.useMemo)(() => {
|
|
12999
13510
|
return ancestryDataRef.current || [];
|
|
13000
13511
|
}, [sceneVersion, isInitialized]);
|
|
13001
|
-
const handleOpenReference = (0,
|
|
13512
|
+
const handleOpenReference = (0, import_react26.useCallback)((referenceData) => {
|
|
13002
13513
|
const { type, id } = referenceData;
|
|
13003
13514
|
if (type === "node") {
|
|
13004
13515
|
const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
|
|
@@ -13025,17 +13536,17 @@ function XViewScene({
|
|
|
13025
13536
|
}
|
|
13026
13537
|
}
|
|
13027
13538
|
}, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
|
|
13028
|
-
const handleToggleAncestryAddMode = (0,
|
|
13539
|
+
const handleToggleAncestryAddMode = (0, import_react26.useCallback)(() => {
|
|
13029
13540
|
setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
|
|
13030
13541
|
}, []);
|
|
13031
|
-
const handleFocusNode = (0,
|
|
13542
|
+
const handleFocusNode = (0, import_react26.useCallback)((nodeData) => {
|
|
13032
13543
|
if (!nodeData) return;
|
|
13033
13544
|
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
13034
13545
|
if (nodeMesh) {
|
|
13035
13546
|
tweenToTarget(nodeMesh, 1.2);
|
|
13036
13547
|
}
|
|
13037
13548
|
}, [tweenToTarget]);
|
|
13038
|
-
const availableDatasets = (0,
|
|
13549
|
+
const availableDatasets = (0, import_react26.useMemo)(() => {
|
|
13039
13550
|
if (!sceneDataRef.current || !parentDataRef.current) return [];
|
|
13040
13551
|
return sceneDataRef.current.parent_dbs.map((db) => {
|
|
13041
13552
|
var _a2;
|
|
@@ -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
|
-
(0,
|
|
13561
|
+
(0, import_react26.useEffect)(() => {
|
|
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
|
-
(0,
|
|
13575
|
+
(0, import_react26.useEffect)(() => {
|
|
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
|
+
(0, import_react26.useEffect)(() => {
|
|
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__ */ import_react26.default.createElement(LoadingScreen, null);
|
|
13080
13691
|
}
|
|
13081
13692
|
if (permissionStatus === "denied") {
|
|
13082
|
-
return /* @__PURE__ */
|
|
13693
|
+
return /* @__PURE__ */ import_react26.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react26.default.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ import_react26.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.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__ */ import_react26.default.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
|
|
14044
|
+
/* @__PURE__ */ import_react26.default.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__ */ import_react26.default.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) => {
|