@lv-x-software-house/x_view 1.2.4-dev.9 → 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 +1225 -551
- package/dist/index.mjs +1171 -497
- 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 {
|
|
@@ -11576,9 +12083,30 @@ function XViewScene({
|
|
|
11576
12083
|
const handleStartVersioning = (nodeData) => {
|
|
11577
12084
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
11578
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
|
+
}, []);
|
|
11579
12106
|
const handleSaveQuestNode = async (context, newQuestData) => {
|
|
11580
12107
|
const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
|
|
11581
12108
|
if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
|
|
12109
|
+
const currentCounter = sceneDataRef2.current.quest_counter || 1;
|
|
11582
12110
|
const newNode = {
|
|
11583
12111
|
id: import_short_uuid2.default.generate(),
|
|
11584
12112
|
...newQuestData,
|
|
@@ -11592,22 +12120,27 @@ function XViewScene({
|
|
|
11592
12120
|
const sceneFileData = {
|
|
11593
12121
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11594
12122
|
nodes: sceneDataRef2.current.nodes,
|
|
11595
|
-
//
|
|
12123
|
+
// Permanece intacto, como estava no último save de cena inicial
|
|
11596
12124
|
links: sceneDataRef2.current.links,
|
|
11597
|
-
// <-- Mantém o cenário inicial inalterado
|
|
11598
12125
|
quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
|
|
11599
|
-
quest_links: graphDataRef.current[sceneConfigId2].links
|
|
12126
|
+
quest_links: graphDataRef.current[sceneConfigId2].links,
|
|
12127
|
+
quest_counter: currentCounter + 1
|
|
11600
12128
|
};
|
|
11601
12129
|
try {
|
|
11602
12130
|
await actions.save_view_data(sceneSaveUrl2, sceneFileData);
|
|
12131
|
+
sceneDataRef2.current.quest_counter = currentCounter + 1;
|
|
11603
12132
|
stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
|
|
11604
12133
|
parentFileId: sceneConfigId2,
|
|
11605
12134
|
ownerId: ownerId2,
|
|
11606
12135
|
datasetName: "Quests Internas (View)"
|
|
11607
12136
|
});
|
|
11608
|
-
const
|
|
11609
|
-
const
|
|
11610
|
-
|
|
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 };
|
|
11611
12144
|
addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
|
|
11612
12145
|
context.tweenToTarget(finalPosition, 1.2);
|
|
11613
12146
|
setters.setQuestMode({ isActive: false });
|
|
@@ -11627,10 +12160,10 @@ function XViewScene({
|
|
|
11627
12160
|
const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2, ownerId2);
|
|
11628
12161
|
const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2, ownerId2);
|
|
11629
12162
|
let parentInfoToSave = sourceParentInfo;
|
|
11630
|
-
|
|
11631
|
-
|
|
11632
|
-
|
|
11633
|
-
parentInfoToSave =
|
|
12163
|
+
const isSourceQuest = sourceParentInfo.parentFileId === sceneConfigId2;
|
|
12164
|
+
const isTargetQuest = targetParentInfo.parentFileId === sceneConfigId2;
|
|
12165
|
+
if (isSourceQuest || isTargetQuest) {
|
|
12166
|
+
parentInfoToSave = { parentFileId: sceneConfigId2, ownerId: ownerId2 };
|
|
11634
12167
|
}
|
|
11635
12168
|
const { parentFileId: parentFileIdToSave, ownerId: ownerIdToSave } = parentInfoToSave;
|
|
11636
12169
|
const newLink = {
|
|
@@ -11645,12 +12178,9 @@ function XViewScene({
|
|
|
11645
12178
|
const viewFilePayload = {
|
|
11646
12179
|
parent_dbs: sceneDataRef2.current.parent_dbs,
|
|
11647
12180
|
nodes: sceneDataRef2.current.nodes,
|
|
11648
|
-
// <-- Usa o estado original intocado
|
|
11649
12181
|
links: sceneDataRef2.current.links,
|
|
11650
|
-
// <-- Usa o estado original intocado
|
|
11651
12182
|
quest_nodes: specificParentData.nodes,
|
|
11652
12183
|
quest_links: specificParentData.links
|
|
11653
|
-
// Salva a conexão aqui!
|
|
11654
12184
|
};
|
|
11655
12185
|
await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
|
|
11656
12186
|
} else {
|
|
@@ -11667,7 +12197,7 @@ function XViewScene({
|
|
|
11667
12197
|
}
|
|
11668
12198
|
userActionHandlers.handleCancelConnection(context);
|
|
11669
12199
|
};
|
|
11670
|
-
const handleClearAncestryVisuals = (0,
|
|
12200
|
+
const handleClearAncestryVisuals = (0, import_react26.useCallback)((ancestryId) => {
|
|
11671
12201
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
11672
12202
|
const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
|
|
11673
12203
|
if (renderIndex !== -1) {
|
|
@@ -11681,7 +12211,7 @@ function XViewScene({
|
|
|
11681
12211
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
11682
12212
|
}
|
|
11683
12213
|
}, []);
|
|
11684
|
-
const handleRenderAncestry = (0,
|
|
12214
|
+
const handleRenderAncestry = (0, import_react26.useCallback)(
|
|
11685
12215
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
11686
12216
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
11687
12217
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -12097,7 +12627,7 @@ function XViewScene({
|
|
|
12097
12627
|
},
|
|
12098
12628
|
[addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
|
|
12099
12629
|
);
|
|
12100
|
-
const handleRenderAbstractionTree = (0,
|
|
12630
|
+
const handleRenderAbstractionTree = (0, import_react26.useCallback)((ancestryObject, targetNodeId = null) => {
|
|
12101
12631
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
12102
12632
|
if (!ancestryObject || !ancestryObject.abstraction_tree) return;
|
|
12103
12633
|
const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
|
|
@@ -12158,7 +12688,7 @@ function XViewScene({
|
|
|
12158
12688
|
stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
|
|
12159
12689
|
tweenToTarget(rootTargetPos, 0.7);
|
|
12160
12690
|
}, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
|
|
12161
|
-
const handleReadModeBranchNav = (0,
|
|
12691
|
+
const handleReadModeBranchNav = (0, import_react26.useCallback)((nodeId, action, direction = "right") => {
|
|
12162
12692
|
const { ancestry, branchStack } = readingMode;
|
|
12163
12693
|
if (!ancestry || !ancestry.tree) return;
|
|
12164
12694
|
const allAncestries = ancestryDataRef.current || [];
|
|
@@ -12299,13 +12829,13 @@ function XViewScene({
|
|
|
12299
12829
|
}));
|
|
12300
12830
|
}
|
|
12301
12831
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
|
|
12302
|
-
const handleReadModeHighlight = (0,
|
|
12832
|
+
const handleReadModeHighlight = (0, import_react26.useCallback)((nodeId) => {
|
|
12303
12833
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
12304
12834
|
stateRef.current.highlightedNodeId = nodeId;
|
|
12305
12835
|
}
|
|
12306
12836
|
setHighlightedNodeId(nodeId);
|
|
12307
12837
|
}, []);
|
|
12308
|
-
const activeNodeBranches = (0,
|
|
12838
|
+
const activeNodeBranches = (0, import_react26.useMemo)(() => {
|
|
12309
12839
|
if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree) return null;
|
|
12310
12840
|
const fullTree = buildFullAncestryTree(
|
|
12311
12841
|
readingMode.ancestry.tree,
|
|
@@ -12342,7 +12872,7 @@ function XViewScene({
|
|
|
12342
12872
|
}
|
|
12343
12873
|
return null;
|
|
12344
12874
|
}, [highlightedNodeId, readingMode.ancestry, buildFullAncestryTree, readingMode.branchStack, ancestryDataRef.current]);
|
|
12345
|
-
const backNavigationInfo = (0,
|
|
12875
|
+
const backNavigationInfo = (0, import_react26.useMemo)(() => {
|
|
12346
12876
|
const { branchStack } = readingMode;
|
|
12347
12877
|
if (!branchStack || branchStack.length === 0) return null;
|
|
12348
12878
|
const lastStep = branchStack[branchStack.length - 1];
|
|
@@ -12353,7 +12883,7 @@ function XViewScene({
|
|
|
12353
12883
|
name: "Voltar para anterior"
|
|
12354
12884
|
};
|
|
12355
12885
|
}, [readingMode.branchStack]);
|
|
12356
|
-
const getReadModeDisplayContext = (0,
|
|
12886
|
+
const getReadModeDisplayContext = (0, import_react26.useMemo)(() => {
|
|
12357
12887
|
const { ancestry, branchStack } = readingMode;
|
|
12358
12888
|
if (!ancestry) return null;
|
|
12359
12889
|
if (branchStack.length === 0) {
|
|
@@ -12394,7 +12924,7 @@ function XViewScene({
|
|
|
12394
12924
|
customProperties: branchProps
|
|
12395
12925
|
};
|
|
12396
12926
|
}, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
|
|
12397
|
-
const readModeAbstractionTree = (0,
|
|
12927
|
+
const readModeAbstractionTree = (0, import_react26.useMemo)(() => {
|
|
12398
12928
|
if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
|
|
12399
12929
|
return null;
|
|
12400
12930
|
}
|
|
@@ -12406,7 +12936,7 @@ function XViewScene({
|
|
|
12406
12936
|
allAncestries
|
|
12407
12937
|
);
|
|
12408
12938
|
}, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
|
|
12409
|
-
const handleStartReadingAncestry = (0,
|
|
12939
|
+
const handleStartReadingAncestry = (0, import_react26.useCallback)(
|
|
12410
12940
|
async (ancestryObject) => {
|
|
12411
12941
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
12412
12942
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -12441,7 +12971,7 @@ function XViewScene({
|
|
|
12441
12971
|
},
|
|
12442
12972
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
12443
12973
|
);
|
|
12444
|
-
const handleReadModeSectionChange = (0,
|
|
12974
|
+
const handleReadModeSectionChange = (0, import_react26.useCallback)((activeSectionId) => {
|
|
12445
12975
|
const { ancestry, branchStack } = readingMode;
|
|
12446
12976
|
if (!ancestry || !readingMode.isActive) return;
|
|
12447
12977
|
let targetObj = ancestry;
|
|
@@ -12510,10 +13040,10 @@ function XViewScene({
|
|
|
12510
13040
|
}, 0);
|
|
12511
13041
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
12512
13042
|
}, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
|
|
12513
|
-
const handleCloseReadMode = (0,
|
|
13043
|
+
const handleCloseReadMode = (0, import_react26.useCallback)(() => {
|
|
12514
13044
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
12515
13045
|
}, []);
|
|
12516
|
-
const handleAncestrySectionChange = (0,
|
|
13046
|
+
const handleAncestrySectionChange = (0, import_react26.useCallback)((activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
12517
13047
|
var _a2, _b2;
|
|
12518
13048
|
const currentMode = stateRef.current.ancestry;
|
|
12519
13049
|
let targetObj = ancestryOverride;
|
|
@@ -12565,7 +13095,7 @@ function XViewScene({
|
|
|
12565
13095
|
const renderPayload = { ...targetObj, tree: treeToRender };
|
|
12566
13096
|
handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
|
|
12567
13097
|
}, [handleRenderAncestry]);
|
|
12568
|
-
const handleEditAncestry = (0,
|
|
13098
|
+
const handleEditAncestry = (0, import_react26.useCallback)(
|
|
12569
13099
|
async (ancestryObject) => {
|
|
12570
13100
|
setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
|
|
12571
13101
|
if (!ancestryObject || !ancestryObject.tree) {
|
|
@@ -12604,7 +13134,7 @@ function XViewScene({
|
|
|
12604
13134
|
const handleSelectAncestryParent = (nodeId) => {
|
|
12605
13135
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
12606
13136
|
};
|
|
12607
|
-
const handleRemoveFromAncestry = (0,
|
|
13137
|
+
const handleRemoveFromAncestry = (0, import_react26.useCallback)((pathToRemove) => {
|
|
12608
13138
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
12609
13139
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
12610
13140
|
return;
|
|
@@ -12629,7 +13159,7 @@ function XViewScene({
|
|
|
12629
13159
|
return { ...prev, tree: newTree };
|
|
12630
13160
|
});
|
|
12631
13161
|
}, []);
|
|
12632
|
-
const handleSaveAncestry = (0,
|
|
13162
|
+
const handleSaveAncestry = (0, import_react26.useCallback)(
|
|
12633
13163
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
12634
13164
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
12635
13165
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -12833,7 +13363,7 @@ function XViewScene({
|
|
|
12833
13363
|
});
|
|
12834
13364
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
12835
13365
|
};
|
|
12836
|
-
const handleDeleteAncestry = (0,
|
|
13366
|
+
const handleDeleteAncestry = (0, import_react26.useCallback)(
|
|
12837
13367
|
async (ancestryIdToDelete) => {
|
|
12838
13368
|
if (!ancestryIdToDelete) {
|
|
12839
13369
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -12895,30 +13425,30 @@ function XViewScene({
|
|
|
12895
13425
|
},
|
|
12896
13426
|
[save_view_data, delete_file_action]
|
|
12897
13427
|
);
|
|
12898
|
-
const handleOpenAncestryBoard = (0,
|
|
13428
|
+
const handleOpenAncestryBoard = (0, import_react26.useCallback)(() => {
|
|
12899
13429
|
setIsAncestryBoardOpen(true);
|
|
12900
13430
|
}, []);
|
|
12901
|
-
const handleSelectAncestryFromBoard = (0,
|
|
13431
|
+
const handleSelectAncestryFromBoard = (0, import_react26.useCallback)((ancestry) => {
|
|
12902
13432
|
setIsAncestryBoardOpen(false);
|
|
12903
13433
|
setIsSidebarOpen(false);
|
|
12904
13434
|
handleStartReadingAncestry(ancestry);
|
|
12905
13435
|
}, [handleStartReadingAncestry]);
|
|
12906
|
-
const handleSaveAncestryBoard = (0,
|
|
13436
|
+
const handleSaveAncestryBoard = (0, import_react26.useCallback)(async (groups) => {
|
|
12907
13437
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
12908
13438
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
12909
13439
|
await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
|
|
12910
13440
|
}, [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]);
|
|
12911
|
-
const existingNodeTypes = (0,
|
|
13441
|
+
const existingNodeTypes = (0, import_react26.useMemo)(() => {
|
|
12912
13442
|
if (!parentDataRef.current) {
|
|
12913
13443
|
return [];
|
|
12914
13444
|
}
|
|
12915
13445
|
const allTypes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes.flatMap((node) => {
|
|
12916
13446
|
if (Array.isArray(node.type)) return node.type;
|
|
12917
13447
|
return [node.type];
|
|
12918
|
-
})).filter(Boolean);
|
|
13448
|
+
})).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
|
|
12919
13449
|
return [...new Set(allTypes)];
|
|
12920
13450
|
}, [parentDataRef.current, sceneVersion]);
|
|
12921
|
-
const searchableDbNodes = (0,
|
|
13451
|
+
const searchableDbNodes = (0, import_react26.useMemo)(() => {
|
|
12922
13452
|
if (!parentDataRef.current) {
|
|
12923
13453
|
return [];
|
|
12924
13454
|
}
|
|
@@ -12927,14 +13457,14 @@ function XViewScene({
|
|
|
12927
13457
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
12928
13458
|
});
|
|
12929
13459
|
}, [parentDataRef.current, sceneVersion]);
|
|
12930
|
-
const handleAddExistingNode = (0,
|
|
13460
|
+
const handleAddExistingNode = (0, import_react26.useCallback)(
|
|
12931
13461
|
(nodeId) => {
|
|
12932
13462
|
return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
|
|
12933
13463
|
},
|
|
12934
13464
|
[actionHandlerContext]
|
|
12935
13465
|
);
|
|
12936
|
-
const handleSaveCurrentView = (0,
|
|
12937
|
-
var _a2, _b2;
|
|
13466
|
+
const handleSaveCurrentView = (0, import_react26.useCallback)(async () => {
|
|
13467
|
+
var _a2, _b2, _c2;
|
|
12938
13468
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
12939
13469
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
12940
13470
|
console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
|
|
@@ -12958,27 +13488,28 @@ function XViewScene({
|
|
|
12958
13488
|
});
|
|
12959
13489
|
sceneDataRef.current.nodes = currentNodes;
|
|
12960
13490
|
sceneDataRef.current.links = currentLinks;
|
|
13491
|
+
const isView = ((_a2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _a2.toLowerCase()) === "view";
|
|
12961
13492
|
const sceneFileData = {
|
|
12962
13493
|
parent_dbs: sceneDataRef.current.parent_dbs,
|
|
12963
13494
|
nodes: currentNodes,
|
|
12964
13495
|
links: currentLinks,
|
|
12965
|
-
quest_nodes: ((
|
|
12966
|
-
quest_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 || []
|
|
12967
13498
|
};
|
|
12968
13499
|
try {
|
|
12969
13500
|
await save_view_data(sceneSaveUrl, sceneFileData);
|
|
12970
13501
|
} catch (error) {
|
|
12971
13502
|
console.error("Erro na chamada de save_view_data:", error);
|
|
12972
13503
|
}
|
|
12973
|
-
}, [sceneSaveUrl, save_view_data, sceneConfigId]);
|
|
12974
|
-
const allAvailableNodes = (0,
|
|
13504
|
+
}, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
|
|
13505
|
+
const allAvailableNodes = (0, import_react26.useMemo)(() => {
|
|
12975
13506
|
if (!parentDataRef.current) return [];
|
|
12976
13507
|
return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
|
|
12977
13508
|
}, [sceneVersion, isInitialized]);
|
|
12978
|
-
const allAvailableAncestries = (0,
|
|
13509
|
+
const allAvailableAncestries = (0, import_react26.useMemo)(() => {
|
|
12979
13510
|
return ancestryDataRef.current || [];
|
|
12980
13511
|
}, [sceneVersion, isInitialized]);
|
|
12981
|
-
const handleOpenReference = (0,
|
|
13512
|
+
const handleOpenReference = (0, import_react26.useCallback)((referenceData) => {
|
|
12982
13513
|
const { type, id } = referenceData;
|
|
12983
13514
|
if (type === "node") {
|
|
12984
13515
|
const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
|
|
@@ -13005,17 +13536,17 @@ function XViewScene({
|
|
|
13005
13536
|
}
|
|
13006
13537
|
}
|
|
13007
13538
|
}, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
|
|
13008
|
-
const handleToggleAncestryAddMode = (0,
|
|
13539
|
+
const handleToggleAncestryAddMode = (0, import_react26.useCallback)(() => {
|
|
13009
13540
|
setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
|
|
13010
13541
|
}, []);
|
|
13011
|
-
const handleFocusNode = (0,
|
|
13542
|
+
const handleFocusNode = (0, import_react26.useCallback)((nodeData) => {
|
|
13012
13543
|
if (!nodeData) return;
|
|
13013
13544
|
const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
13014
13545
|
if (nodeMesh) {
|
|
13015
13546
|
tweenToTarget(nodeMesh, 1.2);
|
|
13016
13547
|
}
|
|
13017
13548
|
}, [tweenToTarget]);
|
|
13018
|
-
const availableDatasets = (0,
|
|
13549
|
+
const availableDatasets = (0, import_react26.useMemo)(() => {
|
|
13019
13550
|
if (!sceneDataRef.current || !parentDataRef.current) return [];
|
|
13020
13551
|
return sceneDataRef.current.parent_dbs.map((db) => {
|
|
13021
13552
|
var _a2;
|
|
@@ -13027,7 +13558,7 @@ function XViewScene({
|
|
|
13027
13558
|
}, [sceneVersion, isInitialized]);
|
|
13028
13559
|
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
|
|
13029
13560
|
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
13030
|
-
(0,
|
|
13561
|
+
(0, import_react26.useEffect)(() => {
|
|
13031
13562
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
13032
13563
|
const nodeObjects = stateRef.current.nodeObjects || {};
|
|
13033
13564
|
const targetMesh = nodeObjects[String(focusNodeId)];
|
|
@@ -13041,7 +13572,7 @@ function XViewScene({
|
|
|
13041
13572
|
}
|
|
13042
13573
|
}
|
|
13043
13574
|
}, [isInitialized, sceneVersion, focusNodeId, hasFocusedInitial, tweenToTarget]);
|
|
13044
|
-
(0,
|
|
13575
|
+
(0, import_react26.useEffect)(() => {
|
|
13045
13576
|
if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
|
|
13046
13577
|
const ancestries = ancestryDataRef.current || [];
|
|
13047
13578
|
const targetAncestry = ancestries.find((a) => String(a.ancestry_id) === String(focusAncestryId));
|
|
@@ -13055,21 +13586,121 @@ function XViewScene({
|
|
|
13055
13586
|
}
|
|
13056
13587
|
}
|
|
13057
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
|
+
]);
|
|
13058
13689
|
if (isLoading || status === "loading" || permissionStatus === "loading") {
|
|
13059
|
-
return /* @__PURE__ */
|
|
13690
|
+
return /* @__PURE__ */ import_react26.default.createElement(LoadingScreen, null);
|
|
13060
13691
|
}
|
|
13061
13692
|
if (permissionStatus === "denied") {
|
|
13062
|
-
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(
|
|
13063
13694
|
"button",
|
|
13064
13695
|
{
|
|
13065
13696
|
onClick: () => router.push("/dashboard/scenes"),
|
|
13066
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"
|
|
13067
13698
|
},
|
|
13068
|
-
/* @__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" })),
|
|
13069
13700
|
"Voltar para Scenes"
|
|
13070
13701
|
)));
|
|
13071
13702
|
}
|
|
13072
|
-
return /* @__PURE__ */
|
|
13703
|
+
return /* @__PURE__ */ import_react26.default.createElement(
|
|
13073
13704
|
"div",
|
|
13074
13705
|
{
|
|
13075
13706
|
ref: mountRef,
|
|
@@ -13081,7 +13712,7 @@ function XViewScene({
|
|
|
13081
13712
|
cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
|
|
13082
13713
|
}
|
|
13083
13714
|
},
|
|
13084
|
-
userPermissionRole !== "link_viewer" && /* @__PURE__ */
|
|
13715
|
+
userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react26.default.createElement(
|
|
13085
13716
|
XViewSidebar,
|
|
13086
13717
|
{
|
|
13087
13718
|
dbNodes: searchableDbNodes,
|
|
@@ -13101,7 +13732,7 @@ function XViewScene({
|
|
|
13101
13732
|
userRole: userPermissionRole
|
|
13102
13733
|
}
|
|
13103
13734
|
),
|
|
13104
|
-
creationMode.isActive && /* @__PURE__ */
|
|
13735
|
+
creationMode.isActive && /* @__PURE__ */ import_react26.default.createElement(
|
|
13105
13736
|
InSceneCreationForm,
|
|
13106
13737
|
{
|
|
13107
13738
|
onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
|
|
@@ -13126,7 +13757,7 @@ function XViewScene({
|
|
|
13126
13757
|
availableAncestries: allAvailableAncestries
|
|
13127
13758
|
}
|
|
13128
13759
|
),
|
|
13129
|
-
versionMode.isActive && /* @__PURE__ */
|
|
13760
|
+
versionMode.isActive && /* @__PURE__ */ import_react26.default.createElement(
|
|
13130
13761
|
InSceneVersionForm,
|
|
13131
13762
|
{
|
|
13132
13763
|
onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
|
|
@@ -13145,27 +13776,32 @@ function XViewScene({
|
|
|
13145
13776
|
availableAncestries: allAvailableAncestries
|
|
13146
13777
|
}
|
|
13147
13778
|
),
|
|
13148
|
-
questMode.isActive && /* @__PURE__ */
|
|
13779
|
+
questMode.isActive && /* @__PURE__ */ import_react26.default.createElement(
|
|
13149
13780
|
InSceneQuestForm,
|
|
13150
13781
|
{
|
|
13151
13782
|
onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
|
|
13152
|
-
onCancel:
|
|
13783
|
+
onCancel: handleCancelQuest,
|
|
13784
|
+
onNameChange: handleGhostNodeNameChange,
|
|
13785
|
+
onColorChange: handleGhostNodeColorChange,
|
|
13786
|
+
onSizeChange: handleGhostNodeSizeChange,
|
|
13153
13787
|
style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
|
|
13154
13788
|
refEl: formRef,
|
|
13155
13789
|
onOpenImageViewer: handleOpenImageViewer,
|
|
13156
13790
|
onMentionClick: handleAddExistingNode,
|
|
13157
13791
|
onUploadFile: upload_file_action,
|
|
13158
13792
|
availableNodes: allAvailableNodes,
|
|
13159
|
-
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
|
|
13160
13796
|
}
|
|
13161
13797
|
),
|
|
13162
|
-
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */
|
|
13798
|
+
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react26.default.createElement(
|
|
13163
13799
|
"div",
|
|
13164
13800
|
{
|
|
13165
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"}`,
|
|
13166
13802
|
style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
|
|
13167
13803
|
},
|
|
13168
|
-
/* @__PURE__ */
|
|
13804
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13169
13805
|
"div",
|
|
13170
13806
|
{
|
|
13171
13807
|
onPointerDown: (e) => {
|
|
@@ -13176,7 +13812,7 @@ function XViewScene({
|
|
|
13176
13812
|
title: "Arraste para redimensionar"
|
|
13177
13813
|
}
|
|
13178
13814
|
),
|
|
13179
|
-
/* @__PURE__ */
|
|
13815
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13180
13816
|
DescriptionReadModePanel,
|
|
13181
13817
|
{
|
|
13182
13818
|
key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
|
|
@@ -13211,7 +13847,7 @@ function XViewScene({
|
|
|
13211
13847
|
}
|
|
13212
13848
|
)
|
|
13213
13849
|
),
|
|
13214
|
-
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */
|
|
13850
|
+
ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ import_react26.default.createElement(
|
|
13215
13851
|
CreateAncestryPanel,
|
|
13216
13852
|
{
|
|
13217
13853
|
ancestryMode,
|
|
@@ -13238,7 +13874,7 @@ function XViewScene({
|
|
|
13238
13874
|
onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
|
|
13239
13875
|
}
|
|
13240
13876
|
),
|
|
13241
|
-
editingAncestryRel.visible && /* @__PURE__ */
|
|
13877
|
+
editingAncestryRel.visible && /* @__PURE__ */ import_react26.default.createElement(
|
|
13242
13878
|
AncestryRelationshipPanel,
|
|
13243
13879
|
{
|
|
13244
13880
|
data: editingAncestryRel.data,
|
|
@@ -13252,7 +13888,28 @@ function XViewScene({
|
|
|
13252
13888
|
onUploadFile: upload_file_action
|
|
13253
13889
|
}
|
|
13254
13890
|
),
|
|
13255
|
-
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(
|
|
13256
13913
|
NodeDetailsPanel,
|
|
13257
13914
|
{
|
|
13258
13915
|
node: detailsNode,
|
|
@@ -13279,7 +13936,7 @@ function XViewScene({
|
|
|
13279
13936
|
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
13280
13937
|
}
|
|
13281
13938
|
),
|
|
13282
|
-
detailsLink && /* @__PURE__ */
|
|
13939
|
+
detailsLink && /* @__PURE__ */ import_react26.default.createElement(
|
|
13283
13940
|
RelationshipDetailsPanel,
|
|
13284
13941
|
{
|
|
13285
13942
|
link: detailsLink,
|
|
@@ -13293,7 +13950,7 @@ function XViewScene({
|
|
|
13293
13950
|
userRole: userPermissionRole
|
|
13294
13951
|
}
|
|
13295
13952
|
),
|
|
13296
|
-
ancestryLinkDetails && /* @__PURE__ */
|
|
13953
|
+
ancestryLinkDetails && /* @__PURE__ */ import_react26.default.createElement(
|
|
13297
13954
|
AncestryLinkDetailsPanel,
|
|
13298
13955
|
{
|
|
13299
13956
|
data: ancestryLinkDetails,
|
|
@@ -13304,7 +13961,7 @@ function XViewScene({
|
|
|
13304
13961
|
onUploadFile: upload_file_action
|
|
13305
13962
|
}
|
|
13306
13963
|
),
|
|
13307
|
-
/* @__PURE__ */
|
|
13964
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13308
13965
|
"div",
|
|
13309
13966
|
{
|
|
13310
13967
|
ref: tooltipRef,
|
|
@@ -13331,7 +13988,7 @@ function XViewScene({
|
|
|
13331
13988
|
}
|
|
13332
13989
|
}
|
|
13333
13990
|
),
|
|
13334
|
-
/* @__PURE__ */
|
|
13991
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13335
13992
|
ContextMenu,
|
|
13336
13993
|
{
|
|
13337
13994
|
data: contextMenu,
|
|
@@ -13354,7 +14011,7 @@ function XViewScene({
|
|
|
13354
14011
|
onFocusNode: handleFocusNode
|
|
13355
14012
|
}
|
|
13356
14013
|
),
|
|
13357
|
-
/* @__PURE__ */
|
|
14014
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13358
14015
|
MultiNodeContextMenu,
|
|
13359
14016
|
{
|
|
13360
14017
|
data: multiContextMenu,
|
|
@@ -13365,7 +14022,7 @@ function XViewScene({
|
|
|
13365
14022
|
onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
|
|
13366
14023
|
}
|
|
13367
14024
|
),
|
|
13368
|
-
/* @__PURE__ */
|
|
14025
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13369
14026
|
RelationshipContextMenu,
|
|
13370
14027
|
{
|
|
13371
14028
|
data: relationshipMenu,
|
|
@@ -13383,8 +14040,8 @@ function XViewScene({
|
|
|
13383
14040
|
onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
|
|
13384
14041
|
}
|
|
13385
14042
|
),
|
|
13386
|
-
/* @__PURE__ */
|
|
13387
|
-
/* @__PURE__ */
|
|
14043
|
+
/* @__PURE__ */ import_react26.default.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
|
|
14044
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13388
14045
|
AncestryBoard,
|
|
13389
14046
|
{
|
|
13390
14047
|
isOpen: isAncestryBoardOpen,
|
|
@@ -13397,14 +14054,14 @@ function XViewScene({
|
|
|
13397
14054
|
userRole: userPermissionRole
|
|
13398
14055
|
}
|
|
13399
14056
|
),
|
|
13400
|
-
/* @__PURE__ */
|
|
14057
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
13401
14058
|
ImportParentFileModal,
|
|
13402
14059
|
{
|
|
13403
14060
|
isOpen: isImportModalOpen,
|
|
13404
14061
|
onClose: () => setIsImportModalOpen(false),
|
|
13405
14062
|
onConfirm: handleConfirmImport,
|
|
13406
14063
|
session,
|
|
13407
|
-
parentDbs: ((
|
|
14064
|
+
parentDbs: ((_h = sceneDataRef.current) == null ? void 0 : _h.parent_dbs) || [],
|
|
13408
14065
|
onFetchAvailableFiles: import_parent_file_modal_get,
|
|
13409
14066
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
13410
14067
|
currentAncestries: ancestryDataRef.current || []
|
|
@@ -13441,6 +14098,12 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
|
|
|
13441
14098
|
}
|
|
13442
14099
|
const sceneData = sceneResponse.data;
|
|
13443
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
|
+
}
|
|
13444
14107
|
const parentResponsesPromises = parentDbObjects.map(
|
|
13445
14108
|
(db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
|
|
13446
14109
|
);
|
|
@@ -13458,21 +14121,32 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
|
|
|
13458
14121
|
);
|
|
13459
14122
|
}
|
|
13460
14123
|
}
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
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
|
+
}
|
|
13466
14131
|
const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
13467
14132
|
const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
|
|
13468
14133
|
const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
|
|
13469
14134
|
const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
|
|
13470
14135
|
const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
|
|
14136
|
+
var _a2, _b2;
|
|
13471
14137
|
const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
|
|
13472
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
|
+
}
|
|
13473
14143
|
return sceneNode;
|
|
13474
14144
|
}
|
|
13475
|
-
|
|
14145
|
+
const dbNode = parentNodeMap.get(String(sceneNode.id));
|
|
14146
|
+
if (dbNode) {
|
|
14147
|
+
return { ...sceneNode, ...dbNode };
|
|
14148
|
+
}
|
|
14149
|
+
return null;
|
|
13476
14150
|
}).filter(Boolean);
|
|
13477
14151
|
const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
|
|
13478
14152
|
const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
|