@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.
Files changed (4) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1225 -551
  3. package/dist/index.mjs +1171 -497
  4. 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 import_react25 = __toESM(require("react"));
46
+ var import_react26 = __toESM(require("react"));
47
47
  var import_navigation = require("next/navigation");
48
- var import_react26 = require("next-auth/react");
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 groupedConnections = connections.reduce((acc, conn) => {
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")), connections.length > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => handleExpandAndClose(connections.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 ? "mb-4" : "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(
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: "my-1 h-px w-full bg-white/10" })), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, finalRenderableConnections.map((group) => {
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) => normalize((n == null ? void 0 : n.name) || "").includes(qNorm));
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 label = createTextSprite(nodeData.name);
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
- if (existingMesh.userData.name !== updatedNode.name) {
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(updatedNode.name || "");
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
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
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
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
2047
- graphDataRef.current[parentFileIdToSave] = specificParentData;
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 originalParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, oldSourceId, context.sceneConfigId, context.ownerId);
2117
- const newParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, newSourceId, context.sceneConfigId, context.ownerId);
2118
- if (!originalParentInfo || !newParentInfo || !originalParentInfo.ownerId || !newParentInfo.ownerId) {
2119
- console.error("N\xE3o foi poss\xEDvel encontrar informa\xE7\xF5es dos arquivos pai para o relink.");
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 (originalParentInfo.parentFileId !== newParentInfo.parentFileId) {
2134
- const updatedOriginalParentData = JSON.parse(JSON.stringify(graphDataRef.current[originalParentInfo.parentFileId]));
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[originalParentInfo.parentFileId] = updatedOriginalParentData;
2139
- savePromises.push(
2140
- context.actions.save_view_data(`x_view_dbs/${originalParentInfo.ownerId}/${originalParentInfo.parentFileId}`, updatedOriginalParentData)
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[newParentInfo.parentFileId] = updatedNewParentData;
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[originalParentInfo.parentFileId]));
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[originalParentInfo.parentFileId] = updatedParentData;
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
- if (parentFileId === context.sceneConfigId) {
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
- if (parentFileId === context.sceneConfigId) {
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
- if (parentFileId === context.sceneConfigId) {
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
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
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
- await context.actions.save_view_data(filenameForSpecificParent, specificParentData);
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, _b;
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
- (_b = setters == null ? void 0 : setters.setSceneVersion) == null ? void 0 : _b.call(setters, (v) => v + 1);
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 QUEST_STATUS_COLORS = {
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 'Nome' \xE9 obrigat\xF3rio.");
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: name.trim(),
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: QUEST_STATUS_COLORS[status],
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, ${QUEST_STATUS_COLORS[status]}, 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 Tarefa / Objetivo")), /* @__PURE__ */ import_react16.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Criar Quest")),
8013
- /* @__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 relative" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ import_react16.default.createElement(
8014
- "select",
8015
- {
8016
- value: status,
8017
- onChange: (e) => setStatus(e.target.value),
8018
- className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 appearance-none cursor-pointer",
8019
- style: { borderLeft: `4px solid ${QUEST_STATUS_COLORS[status]}` }
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("option", { value: "Backlog" }, "Backlog"),
8022
- /* @__PURE__ */ import_react16.default.createElement("option", { value: "In Progress" }, "In Progress"),
8023
- /* @__PURE__ */ import_react16.default.createElement("option", { value: "Review" }, "Review"),
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 Cen\xE1rio (Size)"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => /* @__PURE__ */ import_react16.default.createElement("button", { key: s, type: "button", onClick: () => setSize(s), className: "flex items-center gap-2 group cursor-pointer focus:outline-none" }, /* @__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" })), /* @__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))))), /* @__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(
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/MultiNodeContextMenu.jsx
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
- function RelationshipDetailsPanel({
8643
- link,
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
- const [name, setName] = (0, import_react19.useState)((link == null ? void 0 : link.name) ?? "");
8656
- const [description, setDescription] = (0, import_react19.useState)((link == null ? void 0 : link.description) ?? "");
8657
- const [customProps, setCustomProps] = (0, import_react19.useState)(() => extractCustomPropsFromNode(link || {}));
8658
- const [existingSections, setExistingSections] = (0, import_react19.useState)((link == null ? void 0 : link.description_sections) || []);
8659
- const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react19.useState)(false);
8660
- const [isSaving, setIsSaving] = (0, import_react19.useState)(false);
8661
- const [isReadMode, setIsReadMode] = (0, import_react19.useState)(false);
8662
- const propsEndRef = (0, import_react19.useRef)(null);
8663
- const canEdit = (0, import_react19.useMemo)(() => {
8664
- const ability = defineAbilityFor(userRole);
8665
- return ability.can("update", "Connection");
8666
- }, [userRole]);
8667
- (0, import_react19.useEffect)(() => {
8668
- setName((link == null ? void 0 : link.name) ?? "");
8669
- setDescription((link == null ? void 0 : link.description) ?? "");
8670
- setExistingSections((link == null ? void 0 : link.description_sections) || []);
8671
- setCustomProps(extractCustomPropsFromNode(link || {}));
8672
- }, [link]);
8673
- const swallow = (e) => e.stopPropagation();
8674
- const handleAddProp = () => {
8675
- if (!canEdit) return;
8676
- const newProp = createNewCustomProperty(customProps);
8677
- setCustomProps((p) => [...p, newProp]);
8678
- setTimeout(() => {
8679
- var _a;
8680
- (_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
8681
- }, 100);
8682
- };
8683
- const handleSave = async (keepOpen = false, overrides = {}) => {
8684
- if (!canEdit) return;
8685
- const currentDescription = overrides.description !== void 0 ? overrides.description : description;
8686
- const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
8687
- const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
8688
- const currentName = overrides.name !== void 0 ? overrides.name : name;
8689
- setIsSaving(true);
8690
- try {
8691
- const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
8692
- const processedSections = processDescriptionForSave(currentDescription, currentExistingSections);
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__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement(
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__ */ import_react19.default.createElement(
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__ */ import_react19.default.createElement(import_react19.default.Fragment, null, /* @__PURE__ */ import_react19.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }), /* @__PURE__ */ import_react19.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react19.default.createElement("div", null, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react19.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_react19.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o")), /* @__PURE__ */ import_react19.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || "Rela\xE7\xE3o")), /* @__PURE__ */ import_react19.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_react19.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react19.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Rela\xE7\xE3o (Opcional)"), /* @__PURE__ */ import_react19.default.createElement(
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__ */ import_react19.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react19.default.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react19.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_react19.default.createElement(
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__ */ import_react19.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_react19.default.createElement(
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__ */ import_react19.default.createElement(import_fi16.FiBookOpen, { size: 14 })
8811
- ), canEdit && /* @__PURE__ */ import_react19.default.createElement(
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__ */ import_react19.default.createElement(import_fi16.FiEdit2, { size: 14 })
8820
- )), !description && canEdit && /* @__PURE__ */ import_react19.default.createElement(
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__ */ import_react19.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react19.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ import_react19.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_react19.default.createElement(import_fi16.FiPlus, { size: 14 }), " Adicionar")), /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react19.default.createElement(
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__ */ import_react19.default.createElement("div", { ref: propsEndRef })))), /* @__PURE__ */ import_react19.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_react19.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_react19.default.createElement(
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__ */ import_react19.default.createElement(import_fi16.FiLoader, { className: "animate-spin" }),
9385
+ isSaving && /* @__PURE__ */ import_react20.default.createElement(import_fi17.FiLoader, { className: "animate-spin" }),
8849
9386
  isSaving ? "Salvando..." : "Salvar"
8850
9387
  )))
8851
- ), isDescriptionModalOpen && /* @__PURE__ */ import_react19.default.createElement(
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 import_react20 = __toESM(require("react"));
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, import_react20.useRef)(null);
8883
- const [menuPos, setMenuPos] = (0, import_react20.useState)({ left: 0, top: 0 });
8884
- const [isConfirmingDelete, setIsConfirmingDelete] = (0, import_react20.useState)(false);
8885
- const ability = (0, import_react20.useMemo)(() => defineAbilityFor(userRole), [userRole]);
8886
- const sourceName = (0, import_react20.useMemo)(
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, import_react20.useMemo)(
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, import_react20.useLayoutEffect)(() => {
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, import_react20.useEffect)(() => {
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__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-teal-400/0 via-teal-400/70 to-teal-400/0" }),
8944
- /* @__PURE__ */ import_react20.default.createElement("div", { className: "p-1.5" }, isConfirmingDelete ? /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-col gap-3 p-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-col items-center text-center gap-2" }, /* @__PURE__ */ import_react20.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_react20.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_react20.default.createElement("polyline", { points: "3 6 5 6 21 6" }), /* @__PURE__ */ import_react20.default.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), /* @__PURE__ */ import_react20.default.createElement("path", { d: "M10 11v6" }), /* @__PURE__ */ import_react20.default.createElement("path", { d: "M14 11v6" }), /* @__PURE__ */ import_react20.default.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" }))), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-sm text-slate-200" }, "Excluir rela\xE7\xE3o?"), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-[11px] text-slate-400 leading-tight break-words" }, "Desconectar ", /* @__PURE__ */ import_react20.default.createElement("strong", null, sourceName), " de ", /* @__PURE__ */ import_react20.default.createElement("strong", null, targetName), ".")), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex gap-2 mt-1" }, /* @__PURE__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ import_react20.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_react20.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Rela\xE7\xE3o")), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-col gap-1" }, canUpdate && /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement(
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__ */ import_react20.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" }),
8979
- /* @__PURE__ */ import_react20.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" })
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__ */ import_react20.default.createElement("span", null, "Desconectar Source (", sourceName, ")")
8982
- ), /* @__PURE__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement("polyline", { points: "16 3 21 3 21 8" }),
9003
- /* @__PURE__ */ import_react20.default.createElement("line", { x1: "4", y1: "20", x2: "21", y2: "3" }),
9004
- /* @__PURE__ */ import_react20.default.createElement("polyline", { points: "21 16 21 21 16 21" }),
9005
- /* @__PURE__ */ import_react20.default.createElement("line", { x1: "15", y1: "15", x2: "21", y2: "21" }),
9006
- /* @__PURE__ */ import_react20.default.createElement("line", { x1: "4", y1: "4", x2: "9", y2: "9" })
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__ */ import_react20.default.createElement("span", null, "Desconectar Target (", targetName, ")")
9009
- ), /* @__PURE__ */ import_react20.default.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" })), /* @__PURE__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
9030
- /* @__PURE__ */ import_react20.default.createElement("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
9031
- /* @__PURE__ */ import_react20.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "8" })
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__ */ import_react20.default.createElement("span", null, "Abrir Detalhes")
9034
- ), canDelete && /* @__PURE__ */ import_react20.default.createElement(import_react20.default.Fragment, null, /* @__PURE__ */ import_react20.default.createElement("div", { className: "h-[1px] my-1 mx-1 bg-white/10" }), /* @__PURE__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement(
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__ */ import_react20.default.createElement("polyline", { points: "3 6 5 6 21 6" }),
9055
- /* @__PURE__ */ import_react20.default.createElement("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }),
9056
- /* @__PURE__ */ import_react20.default.createElement("path", { d: "M10 11v6" }),
9057
- /* @__PURE__ */ import_react20.default.createElement("path", { d: "M14 11v6" }),
9058
- /* @__PURE__ */ import_react20.default.createElement("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })
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__ */ import_react20.default.createElement("span", null, "Excluir conex\xE3o (", sourceName, " \u2192 ", targetName, ")")
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 import_react21 = __toESM(require("react"));
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__ */ import_react21.default.createElement(import_react21.default.Fragment, null, /* @__PURE__ */ import_react21.default.createElement("style", null, styles.keyframes), /* @__PURE__ */ import_react21.default.createElement("div", { style: styles.loadingOverlay }, /* @__PURE__ */ import_react21.default.createElement("div", { style: styles.spinner })));
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 import_react22 = __toESM(require("react"));
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, import_react22.useState)("databases");
9114
- const [availableDbs, setAvailableDbs] = (0, import_react22.useState)([]);
9115
- const [availableViews, setAvailableViews] = (0, import_react22.useState)([]);
9116
- const [selectedItem, setSelectedItem] = (0, import_react22.useState)(null);
9117
- const [isLoading, setIsLoading] = (0, import_react22.useState)(false);
9118
- (0, import_react22.useEffect)(() => {
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, import_react22.useEffect)(() => {
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__ */ import_react22.default.createElement(
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__ */ import_react22.default.createElement(
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__ */ import_react22.default.createElement("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/10 flex-shrink-0" }, /* @__PURE__ */ import_react22.default.createElement("h2", { className: "text-lg font-semibold" }, "Importar"), /* @__PURE__ */ import_react22.default.createElement(
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__ */ import_react22.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ import_react22.default.createElement(
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__ */ import_react22.default.createElement("div", { className: "flex px-6 border-b border-white/10 bg-white/5 flex-shrink-0" }, /* @__PURE__ */ import_react22.default.createElement(
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__ */ import_react22.default.createElement(
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__ */ import_react22.default.createElement("div", { className: "p-6 overflow-y-auto custom-scrollbar flex-grow min-h-[200px]" }, isLoading ? /* @__PURE__ */ import_react22.default.createElement("div", { className: "flex items-center justify-center h-40" }, /* @__PURE__ */ import_react22.default.createElement("div", { className: "w-8 h-8 border-4 border-t-indigo-500 border-slate-700 rounded-full animate-spin" })) : /* @__PURE__ */ import_react22.default.createElement("div", { className: "space-y-2" }, currentList.length > 0 ? currentList.map((item) => /* @__PURE__ */ import_react22.default.createElement(
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__ */ import_react22.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react22.default.createElement("span", { className: "font-medium text-slate-100" }, item.name), activeTab === "views" && /* @__PURE__ */ import_react22.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")),
9240
- item.description && /* @__PURE__ */ import_react22.default.createElement("p", { className: `text-xs ${(selectedItem == null ? void 0 : selectedItem.id) === item.id ? "text-indigo-200" : "text-slate-400"}` }, item.description)
9241
- )) : /* @__PURE__ */ import_react22.default.createElement("p", { className: "text-slate-400 text-center py-10" }, emptyMessage))),
9242
- /* @__PURE__ */ import_react22.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_react22.default.createElement(
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__ */ import_react22.default.createElement(
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 import_react23 = __toESM(require("react"));
9264
- var import_fi17 = require("react-icons/fi");
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, import_react23.useState)(false);
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__ */ import_react23.default.createElement(
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__ */ import_react23.default.createElement(
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__ */ import_react23.default.createElement(
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__ */ import_react23.default.createElement(import_react23.default.Fragment, null, /* @__PURE__ */ import_react23.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-blue-500/0 via-blue-500/70 to-blue-500/0" }), /* @__PURE__ */ import_react23.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react23.default.createElement("div", null, /* @__PURE__ */ import_react23.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react23.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_react23.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Ancestralidade")), /* @__PURE__ */ import_react23.default.createElement("h2", { className: "text-lg font-semibold tracking-tight flex items-center gap-2" }, /* @__PURE__ */ import_react23.default.createElement("span", { className: "truncate max-w-[150px]" }, sourceName), /* @__PURE__ */ import_react23.default.createElement("span", { className: "text-slate-500 text-sm" }, "\u2794"), /* @__PURE__ */ import_react23.default.createElement("span", { className: "truncate max-w-[150px]" }, targetName))), /* @__PURE__ */ import_react23.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_react23.default.createElement("div", { className: "px-6 pb-6 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, description && /* @__PURE__ */ import_react23.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ import_react23.default.createElement("label", { className: "text-xs text-slate-300 font-medium" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react23.default.createElement(
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__ */ import_react23.default.createElement(import_fi17.FiBookOpen, { size: 14 })
9315
- )), /* @__PURE__ */ import_react23.default.createElement("div", { className: "bg-slate-800/40 rounded-lg border border-white/10 p-1 relative group" }, /* @__PURE__ */ import_react23.default.createElement(
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__ */ import_react23.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react23.default.createElement("label", { className: "text-xs text-slate-300 font-medium mb-2 block" }, "Propriedades"), /* @__PURE__ */ import_react23.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop) => /* @__PURE__ */ import_react23.default.createElement(
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__ */ import_react23.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_react23.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".')))
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 import_react24 = __toESM(require("react"));
9340
- var import_fi18 = require("react-icons/fi");
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, import_react24.useRef)(null);
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, import_react24.useEffect)(() => {
9905
+ (0, import_react25.useEffect)(() => {
9369
9906
  adjustHeight();
9370
9907
  }, [group.text]);
9371
- return /* @__PURE__ */ import_react24.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_react24.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react24.default.createElement("div", { className: `
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__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
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__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiPlay, { size: 10, className: "ml-0.5 fill-current" })
9949
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiPlay, { size: 10, className: "ml-0.5 fill-current" })
9413
9950
  )
9414
- ) : /* @__PURE__ */ import_react24.default.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ import_react24.default.createElement(import_fi18.FiAlertTriangle, { size: 10 })),
9415
- /* @__PURE__ */ import_react24.default.createElement("span", { className: `font-medium truncate max-w-[150px] ${!isValid && "line-through decoration-red-500/50"}` }, anc.name),
9416
- canEdit && /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, /* @__PURE__ */ import_react24.default.createElement("div", { className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}` }), /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiX, { size: 12 })
9960
+ /* @__PURE__ */ import_react25.default.createElement(import_fi19.FiX, { size: 12 })
9424
9961
  ))
9425
9962
  );
9426
- })), canEdit && /* @__PURE__ */ import_react24.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_react24.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiCheckCircle, { size: 12 }) : /* @__PURE__ */ import_react24.default.createElement(import_fi18.FiSearch, { size: 12 }),
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__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiPlus, { size: 14 })
9446
- )), /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiArrowRight, { size: 14 })
9455
- ), /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiArrowLeft, { size: 14 })
9463
- ), /* @__PURE__ */ import_react24.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiTrash2, { size: 14 })
9471
- )))), group.children && group.children.length > 0 && /* @__PURE__ */ import_react24.default.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ import_react24.default.createElement(
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, import_react24.useState)("");
9504
- const [groups, setGroups] = (0, import_react24.useState)([]);
9505
- const [isLoaded, setIsLoaded] = (0, import_react24.useState)(false);
9506
- const [pickingGroupId, setPickingGroupId] = (0, import_react24.useState)(null);
9507
- const [saveStatus, setSaveStatus] = (0, import_react24.useState)("idle");
9508
- const canEdit = (0, import_react24.useMemo)(() => {
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, import_react24.useEffect)(() => {
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, import_react24.useMemo)(() => {
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, import_react24.useMemo)(() => {
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, import_react24.useEffect)(() => {
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, import_react24.useEffect)(() => {
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, import_react24.useMemo)(() => {
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__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement(
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__ */ import_react24.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_react24.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react24.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react24.default.createElement(import_fi18.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react24.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_react24.default.createElement(import_react24.default.Fragment, null, /* @__PURE__ */ import_react24.default.createElement(import_fi18.FiLoader, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ import_react24.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, /* @__PURE__ */ import_react24.default.createElement(import_fi18.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react24.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, /* @__PURE__ */ import_react24.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react24.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ import_react24.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_react24.default.createElement(
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__ */ import_react24.default.createElement(import_fi18.FiPlus, { size: 14, className: "text-indigo-400" }),
9734
- /* @__PURE__ */ import_react24.default.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
9735
- ), /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: `
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__ */ import_react24.default.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react24.default.createElement(import_fi18.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_react24.default.createElement(
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__ */ import_react24.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
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__ */ import_react24.default.createElement(
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__ */ import_react24.default.createElement("div", { className: `
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__ */ import_react24.default.createElement(import_fi18.FiPlus, { size: 16 }) : /* @__PURE__ */ import_react24.default.createElement(import_fi18.FiLayers, { size: 14 })),
9779
- /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ import_react24.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_react24.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_react24.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_react24.default.createElement(import_fi18.FiCornerUpRight, { size: 10 }), /* @__PURE__ */ import_react24.default.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.description && /* @__PURE__ */ import_react24.default.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.description)),
9780
- !isPicking && /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.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_react24.default.createElement(import_fi18.FiPlay, { size: 14, className: "ml-0.5" }))
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__ */ import_react24.default.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ import_react24.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ import_react24.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_react24.default.createElement(import_fi18.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react24.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ import_react24.default.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ import_react24.default.createElement(import_react24.default.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ import_react24.default.createElement(
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__ */ import_react24.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_react24.default.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ import_react24.default.createElement("span", null, groups.length, " grupos raiz"))
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, import_react26.useSession)();
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, import_react25.useMemo)(() => {
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, import_react25.useEffect)(() => {
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, import_react25.useMemo)(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
9938
- const ownerId = (0, import_react25.useMemo)(() => (viewParams == null ? void 0 : viewParams.owner_id) || null, [viewParams]);
9939
- const dbSaveUrl = (0, import_react25.useMemo)(() => {
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, import_react25.useMemo)(() => {
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, import_react25.useMemo)(() => {
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, import_react25.useRef)(null);
9958
- const parentDataRef = (0, import_react25.useRef)(null);
9959
- const ancestryDataRef = (0, import_react25.useRef)(null);
9960
- const [isLoading, setIsLoading] = (0, import_react25.useState)(true);
9961
- const [permissionStatus, setPermissionStatus] = (0, import_react25.useState)("loading");
9962
- const [userPermissionRole, setUserPermissionRole] = (0, import_react25.useState)(null);
9963
- const [isInitialized, setIsInitialized] = (0, import_react25.useState)(false);
9964
- const [sceneVersion, setSceneVersion] = (0, import_react25.useState)(0);
9965
- const [contextMenu, setContextMenu] = (0, import_react25.useState)({ visible: false, x: 0, y: 0, nodeData: null });
9966
- const [multiContextMenu, setMultiContextMenu] = (0, import_react25.useState)({ visible: false, x: 0, y: 0, nodeIds: null });
9967
- const [relationshipMenu, setRelationshipMenu] = (0, import_react25.useState)({ visible: false, x: 0, y: 0, linkObject: null });
9968
- const [creationMode, setCreationMode] = (0, import_react25.useState)({ isActive: false, sourceNodeData: null });
9969
- const [versionMode, setVersionMode] = (0, import_react25.useState)({ isActive: false, sourceNodeData: null });
9970
- const [questMode, setQuestMode] = (0, import_react25.useState)({ isActive: false });
9971
- const [hasFocusedInitial, setHasFocusedInitial] = (0, import_react25.useState)(false);
9972
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = (0, import_react25.useState)(false);
9973
- const [ancestryMode, setAncestryMode] = (0, import_react25.useState)({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
9974
- const [readingMode, setReadingMode] = (0, import_react25.useState)({
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, import_react25.useState)({ left: 16, top: 16, opacity: 0 });
9981
- const [detailsNode, setDetailsNode] = (0, import_react25.useState)(null);
9982
- const [detailsLink, setDetailsLink] = (0, import_react25.useState)(null);
9983
- const [ancestryLinkDetails, setAncestryLinkDetails] = (0, import_react25.useState)(null);
9984
- const [imageViewer, setImageViewer] = (0, import_react25.useState)({ visible: false, images: [], startIndex: 0 });
9985
- const [editingAncestryRel, setEditingAncestryRel] = (0, import_react25.useState)({ visible: false, data: null, path: null });
9986
- const [isImportModalOpen, setIsImportModalOpen] = (0, import_react25.useState)(false);
9987
- const [importSuccessMessage, setImportSuccessMessage] = (0, import_react25.useState)("");
9988
- const [highlightedNodeId, setHighlightedNodeId] = (0, import_react25.useState)(null);
9989
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = (0, import_react25.useState)(false);
9990
- const [ancestryBoardData, setAncestryBoardData] = (0, import_react25.useState)([]);
9991
- const [isSidebarOpen, setIsSidebarOpen] = (0, import_react25.useState)(false);
9992
- const mountRef = (0, import_react25.useRef)(null);
9993
- const tooltipRef = (0, import_react25.useRef)(null);
9994
- const formRef = (0, import_react25.useRef)(null);
9995
- const stateRef = (0, import_react25.useRef)({
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, import_react25.useEffect)(() => {
10577
+ (0, import_react26.useEffect)(() => {
10041
10578
  stateRef.current.ancestry = ancestryMode;
10042
10579
  }, [ancestryMode]);
10043
- (0, import_react25.useEffect)(() => {
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, import_react25.useCallback)(() => {
10601
+ const handleNavigateBack = (0, import_react26.useCallback)(() => {
10065
10602
  router.push("/dashboard/scenes");
10066
10603
  }, [router]);
10067
- const handleConfirmImport = (0, import_react25.useCallback)(
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, import_react25.useCallback)((target, zoomFactor = 1, forcedDirection = null) => {
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, import_react25.useCallback)((idTree, nodes, ancestries = []) => {
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 || { id: nodeId, name: "Unknown" },
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, import_react25.useCallback)(() => {
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, import_react25.useCallback)((sourceMesh, versionMeshes) => {
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, import_react25.useEffect)(() => {
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, import_react25.useCallback)((id) => {
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, import_react25.useCallback)((nodeData, position, suppressVersionUpdate = false) => {
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, import_react25.useEffect)(() => {
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, import_react25.useCallback)((useImage, imageUrl) => {
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, import_react25.useCallback)((newIntensity) => {
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, import_react25.useCallback)((nodeId, newIntensity) => {
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 newLabel = createTextSprite(newName || "");
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, import_react25.useCallback)((newTree, extraData = null) => {
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, import_react25.useMemo)(
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
- // <-- Mantém o cenário inicial inalterado
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 basePosition = stateRef2.current.controls.target.clone();
11609
- const offset = new THREE3.Vector3((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 5, 0);
11610
- const finalPosition = basePosition.add(offset);
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
- if (sourceParentInfo.parentFileId === sceneConfigId2 && targetParentInfo.parentFileId !== sceneConfigId2) {
11631
- parentInfoToSave = targetParentInfo;
11632
- } else if (targetParentInfo.parentFileId === sceneConfigId2 && sourceParentInfo.parentFileId !== sceneConfigId2) {
11633
- parentInfoToSave = sourceParentInfo;
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, import_react25.useCallback)((ancestryId) => {
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, import_react25.useCallback)(
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, import_react25.useCallback)((ancestryObject, targetNodeId = null) => {
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, import_react25.useCallback)((nodeId, action, direction = "right") => {
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, import_react25.useCallback)((nodeId) => {
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, import_react25.useMemo)(() => {
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, import_react25.useMemo)(() => {
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, import_react25.useMemo)(() => {
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, import_react25.useMemo)(() => {
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, import_react25.useCallback)(
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, import_react25.useCallback)((activeSectionId) => {
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, import_react25.useCallback)(() => {
13043
+ const handleCloseReadMode = (0, import_react26.useCallback)(() => {
12514
13044
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
12515
13045
  }, []);
12516
- const handleAncestrySectionChange = (0, import_react25.useCallback)((activeSectionId, ancestryOverride = null, rotation = 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, import_react25.useCallback)(
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, import_react25.useCallback)((pathToRemove) => {
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, import_react25.useCallback)(
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, import_react25.useCallback)(
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, import_react25.useCallback)(() => {
13428
+ const handleOpenAncestryBoard = (0, import_react26.useCallback)(() => {
12899
13429
  setIsAncestryBoardOpen(true);
12900
13430
  }, []);
12901
- const handleSelectAncestryFromBoard = (0, import_react25.useCallback)((ancestry) => {
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, import_react25.useCallback)(async (groups) => {
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, import_react25.useMemo)(() => {
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, import_react25.useMemo)(() => {
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, import_react25.useCallback)(
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, import_react25.useCallback)(async () => {
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: ((_a2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _a2.nodes) || [],
12966
- quest_links: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.links) || []
13496
+ quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
13497
+ quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || []
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, import_react25.useMemo)(() => {
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, import_react25.useMemo)(() => {
13509
+ const allAvailableAncestries = (0, import_react26.useMemo)(() => {
12979
13510
  return ancestryDataRef.current || [];
12980
13511
  }, [sceneVersion, isInitialized]);
12981
- const handleOpenReference = (0, import_react25.useCallback)((referenceData) => {
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, import_react25.useCallback)(() => {
13539
+ const handleToggleAncestryAddMode = (0, import_react26.useCallback)(() => {
13009
13540
  setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
13010
13541
  }, []);
13011
- const handleFocusNode = (0, import_react25.useCallback)((nodeData) => {
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, import_react25.useMemo)(() => {
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, import_react25.useEffect)(() => {
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, import_react25.useEffect)(() => {
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__ */ import_react25.default.createElement(LoadingScreen, null);
13690
+ return /* @__PURE__ */ import_react26.default.createElement(LoadingScreen, null);
13060
13691
  }
13061
13692
  if (permissionStatus === "denied") {
13062
- return /* @__PURE__ */ import_react25.default.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ import_react25.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_react25.default.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ import_react25.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_react25.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_react25.default.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ import_react25.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_react25.default.createElement(
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__ */ import_react25.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_react25.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" })),
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
13779
+ questMode.isActive && /* @__PURE__ */ import_react26.default.createElement(
13149
13780
  InSceneQuestForm,
13150
13781
  {
13151
13782
  onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
13152
- onCancel: () => setQuestMode({ isActive: false }),
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
13387
- /* @__PURE__ */ import_react25.default.createElement(
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__ */ import_react25.default.createElement(
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: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
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
- parentData[scene_config] = {
13462
- dataset_name: "Quests Internas (View)",
13463
- nodes: sceneData.quest_nodes || [],
13464
- links: sceneData.quest_links || []
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
- return parentNodeMap.get(String(sceneNode.id));
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) => {