@lv-x-software-house/x_view 1.2.4-dev.8 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +1234 -580
  3. package/dist/index.mjs +1180 -526
  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 {
@@ -11526,15 +12033,10 @@ function XViewScene({
11526
12033
  creationMode,
11527
12034
  versionMode,
11528
12035
  questMode,
11529
- // <-- Adicionado
11530
12036
  sceneSaveUrl,
11531
- // <-- Adicionado
11532
12037
  sceneConfigId,
11533
- // <-- Adicionado
11534
12038
  ownerId,
11535
- // <-- Adicionado
11536
12039
  viewType: viewParams == null ? void 0 : viewParams.type,
11537
- // <-- Adicionado
11538
12040
  userId: (_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id,
11539
12041
  setters: {
11540
12042
  setContextMenu,
@@ -11548,7 +12050,6 @@ function XViewScene({
11548
12050
  setSceneVersion,
11549
12051
  setAncestryMode,
11550
12052
  setQuestMode
11551
- // <-- Adicionado
11552
12053
  },
11553
12054
  tweenToTarget,
11554
12055
  handleVersionTimeline,
@@ -11582,9 +12083,30 @@ function XViewScene({
11582
12083
  const handleStartVersioning = (nodeData) => {
11583
12084
  userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
11584
12085
  };
12086
+ const handleCancelQuest = (0, import_react26.useCallback)(() => {
12087
+ const { graphGroup, ghostElements } = stateRef.current;
12088
+ if (ghostElements.node && graphGroup) {
12089
+ if (ghostElements.node.userData.labelObject) {
12090
+ graphGroup.remove(ghostElements.node.userData.labelObject);
12091
+ if (ghostElements.node.userData.labelObject.material.map) ghostElements.node.userData.labelObject.material.map.dispose();
12092
+ ghostElements.node.userData.labelObject.material.dispose();
12093
+ }
12094
+ graphGroup.remove(ghostElements.node);
12095
+ ghostElements.node.traverse((child) => {
12096
+ if (child.material) {
12097
+ if (Array.isArray(child.material)) child.material.forEach((m) => m.dispose());
12098
+ else child.material.dispose();
12099
+ }
12100
+ if (child.geometry) child.geometry.dispose();
12101
+ });
12102
+ }
12103
+ stateRef.current.ghostElements = { node: null, line: null, aura: null };
12104
+ setQuestMode({ isActive: false });
12105
+ }, []);
11585
12106
  const handleSaveQuestNode = async (context, newQuestData) => {
11586
12107
  const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
11587
12108
  if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
12109
+ const currentCounter = sceneDataRef2.current.quest_counter || 1;
11588
12110
  const newNode = {
11589
12111
  id: import_short_uuid2.default.generate(),
11590
12112
  ...newQuestData,
@@ -11595,33 +12117,30 @@ function XViewScene({
11595
12117
  graphDataRef.current[sceneConfigId2] = { nodes: [], links: [] };
11596
12118
  }
11597
12119
  graphDataRef.current[sceneConfigId2].nodes.push(newNode);
11598
- sceneDataRef2.current.nodes.push(newNode);
11599
- const currentVisualNodes = Object.values(stateRef2.current.nodeObjects).map((mesh) => {
11600
- const { _baseEmissiveIntensity, labelObject, labelOffset, timelineIntervalBar, timelineEndLabel, ...rest } = mesh.userData;
11601
- return rest;
11602
- });
11603
- currentVisualNodes.push(newNode);
11604
- const currentVisualLinks = stateRef2.current.allLinks.map((line) => {
11605
- const { sourceNode, targetNode, ...rest } = line.userData;
11606
- return rest;
11607
- });
11608
12120
  const sceneFileData = {
11609
12121
  parent_dbs: sceneDataRef2.current.parent_dbs,
11610
- nodes: currentVisualNodes,
11611
- links: currentVisualLinks,
12122
+ nodes: sceneDataRef2.current.nodes,
12123
+ // Permanece intacto, como estava no último save de cena inicial
12124
+ links: sceneDataRef2.current.links,
11612
12125
  quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
11613
- quest_links: graphDataRef.current[sceneConfigId2].links
12126
+ quest_links: graphDataRef.current[sceneConfigId2].links,
12127
+ quest_counter: currentCounter + 1
11614
12128
  };
11615
12129
  try {
11616
12130
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
12131
+ sceneDataRef2.current.quest_counter = currentCounter + 1;
11617
12132
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
11618
12133
  parentFileId: sceneConfigId2,
11619
12134
  ownerId: ownerId2,
11620
12135
  datasetName: "Quests Internas (View)"
11621
12136
  });
11622
- const basePosition = stateRef2.current.controls.target.clone();
11623
- const offset = new THREE3.Vector3((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 5, 0);
11624
- 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 };
11625
12144
  addStandaloneNodeToScene(stateRef2.current, newNode, finalPosition);
11626
12145
  context.tweenToTarget(finalPosition, 1.2);
11627
12146
  setters.setQuestMode({ isActive: false });
@@ -11632,19 +12151,19 @@ function XViewScene({
11632
12151
  }
11633
12152
  };
11634
12153
  userActionHandlers.handleCompleteConnection = async (context, targetNodeData) => {
11635
- const { stateRef: stateRef2, graphDataRef, sceneDataRef: sceneDataRef2, sceneConfigId: sceneConfigId2, sceneSaveUrl: sceneSaveUrl2 } = context;
12154
+ const { stateRef: stateRef2, graphDataRef, sceneDataRef: sceneDataRef2, sceneConfigId: sceneConfigId2, sceneSaveUrl: sceneSaveUrl2, ownerId: ownerId2 } = context;
11636
12155
  const { sourceNodeData } = stateRef2.current.connection;
11637
12156
  if (!graphDataRef.current || !sceneDataRef2.current || !sourceNodeData || !targetNodeData) {
11638
12157
  userActionHandlers.handleCancelConnection(context);
11639
12158
  return;
11640
12159
  }
11641
- const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2, ownerId);
11642
- const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2, ownerId);
12160
+ const sourceParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, sourceNodeData.id, sceneConfigId2, ownerId2);
12161
+ const targetParentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef2.current, targetNodeData.id, sceneConfigId2, ownerId2);
11643
12162
  let parentInfoToSave = sourceParentInfo;
11644
- if (sourceParentInfo.parentFileId === sceneConfigId2 && targetParentInfo.parentFileId !== sceneConfigId2) {
11645
- parentInfoToSave = targetParentInfo;
11646
- } else if (targetParentInfo.parentFileId === sceneConfigId2 && sourceParentInfo.parentFileId !== sceneConfigId2) {
11647
- parentInfoToSave = sourceParentInfo;
12163
+ const isSourceQuest = sourceParentInfo.parentFileId === sceneConfigId2;
12164
+ const isTargetQuest = targetParentInfo.parentFileId === sceneConfigId2;
12165
+ if (isSourceQuest || isTargetQuest) {
12166
+ parentInfoToSave = { parentFileId: sceneConfigId2, ownerId: ownerId2 };
11648
12167
  }
11649
12168
  const { parentFileId: parentFileIdToSave, ownerId: ownerIdToSave } = parentInfoToSave;
11650
12169
  const newLink = {
@@ -11656,22 +12175,12 @@ function XViewScene({
11656
12175
  if (parentFileIdToSave === sceneConfigId2) {
11657
12176
  const specificParentData = graphDataRef.current[sceneConfigId2];
11658
12177
  specificParentData.links.push(newLink);
11659
- const currentVisualNodes = Object.values(stateRef2.current.nodeObjects).map((m) => {
11660
- const { _baseEmissiveIntensity, labelObject, labelOffset, timelineIntervalBar, timelineEndLabel, ...rest } = m.userData;
11661
- return rest;
11662
- });
11663
- const currentVisualLinks = stateRef2.current.allLinks.map((l) => {
11664
- const { sourceNode, targetNode, ...rest } = l.userData;
11665
- return rest;
11666
- });
11667
- currentVisualLinks.push(newLink);
11668
12178
  const viewFilePayload = {
11669
12179
  parent_dbs: sceneDataRef2.current.parent_dbs,
11670
- nodes: currentVisualNodes,
11671
- links: currentVisualLinks,
12180
+ nodes: sceneDataRef2.current.nodes,
12181
+ links: sceneDataRef2.current.links,
11672
12182
  quest_nodes: specificParentData.nodes,
11673
12183
  quest_links: specificParentData.links
11674
- // Salva a conexão aqui!
11675
12184
  };
11676
12185
  await context.actions.save_view_data(sceneSaveUrl2, viewFilePayload);
11677
12186
  } else {
@@ -11688,7 +12197,7 @@ function XViewScene({
11688
12197
  }
11689
12198
  userActionHandlers.handleCancelConnection(context);
11690
12199
  };
11691
- const handleClearAncestryVisuals = (0, import_react25.useCallback)((ancestryId) => {
12200
+ const handleClearAncestryVisuals = (0, import_react26.useCallback)((ancestryId) => {
11692
12201
  const { renderedAncestries, ancestryGroup } = stateRef.current;
11693
12202
  const renderIndex = renderedAncestries.findIndex((a) => String(a.id) === String(ancestryId));
11694
12203
  if (renderIndex !== -1) {
@@ -11702,7 +12211,7 @@ function XViewScene({
11702
12211
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
11703
12212
  }
11704
12213
  }, []);
11705
- const handleRenderAncestry = (0, import_react25.useCallback)(
12214
+ const handleRenderAncestry = (0, import_react26.useCallback)(
11706
12215
  async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
11707
12216
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
11708
12217
  if (!ancestryObject || !ancestryObject.tree) {
@@ -12118,7 +12627,7 @@ function XViewScene({
12118
12627
  },
12119
12628
  [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, readingMode.isActive, ancestryMode.isActive]
12120
12629
  );
12121
- const handleRenderAbstractionTree = (0, import_react25.useCallback)((ancestryObject, targetNodeId = null) => {
12630
+ const handleRenderAbstractionTree = (0, import_react26.useCallback)((ancestryObject, targetNodeId = null) => {
12122
12631
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
12123
12632
  if (!ancestryObject || !ancestryObject.abstraction_tree) return;
12124
12633
  const { ancestryGroup, nodeObjects, renderer, renderedAncestries } = stateRef.current;
@@ -12179,7 +12688,7 @@ function XViewScene({
12179
12688
  stateRef.current.ancestryLinks = renderedAncestries.flatMap((a) => a.lines);
12180
12689
  tweenToTarget(rootTargetPos, 0.7);
12181
12690
  }, [addOrUpdateNodeMesh, tweenToTarget, buildFullAncestryTree, handleClearAncestryVisuals]);
12182
- const handleReadModeBranchNav = (0, import_react25.useCallback)((nodeId, action, direction = "right") => {
12691
+ const handleReadModeBranchNav = (0, import_react26.useCallback)((nodeId, action, direction = "right") => {
12183
12692
  const { ancestry, branchStack } = readingMode;
12184
12693
  if (!ancestry || !ancestry.tree) return;
12185
12694
  const allAncestries = ancestryDataRef.current || [];
@@ -12320,13 +12829,13 @@ function XViewScene({
12320
12829
  }));
12321
12830
  }
12322
12831
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]);
12323
- const handleReadModeHighlight = (0, import_react25.useCallback)((nodeId) => {
12832
+ const handleReadModeHighlight = (0, import_react26.useCallback)((nodeId) => {
12324
12833
  if (stateRef.current.highlightedNodeId !== nodeId) {
12325
12834
  stateRef.current.highlightedNodeId = nodeId;
12326
12835
  }
12327
12836
  setHighlightedNodeId(nodeId);
12328
12837
  }, []);
12329
- const activeNodeBranches = (0, import_react25.useMemo)(() => {
12838
+ const activeNodeBranches = (0, import_react26.useMemo)(() => {
12330
12839
  if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree) return null;
12331
12840
  const fullTree = buildFullAncestryTree(
12332
12841
  readingMode.ancestry.tree,
@@ -12363,7 +12872,7 @@ function XViewScene({
12363
12872
  }
12364
12873
  return null;
12365
12874
  }, [highlightedNodeId, readingMode.ancestry, buildFullAncestryTree, readingMode.branchStack, ancestryDataRef.current]);
12366
- const backNavigationInfo = (0, import_react25.useMemo)(() => {
12875
+ const backNavigationInfo = (0, import_react26.useMemo)(() => {
12367
12876
  const { branchStack } = readingMode;
12368
12877
  if (!branchStack || branchStack.length === 0) return null;
12369
12878
  const lastStep = branchStack[branchStack.length - 1];
@@ -12374,7 +12883,7 @@ function XViewScene({
12374
12883
  name: "Voltar para anterior"
12375
12884
  };
12376
12885
  }, [readingMode.branchStack]);
12377
- const getReadModeDisplayContext = (0, import_react25.useMemo)(() => {
12886
+ const getReadModeDisplayContext = (0, import_react26.useMemo)(() => {
12378
12887
  const { ancestry, branchStack } = readingMode;
12379
12888
  if (!ancestry) return null;
12380
12889
  if (branchStack.length === 0) {
@@ -12415,7 +12924,7 @@ function XViewScene({
12415
12924
  customProperties: branchProps
12416
12925
  };
12417
12926
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
12418
- const readModeAbstractionTree = (0, import_react25.useMemo)(() => {
12927
+ const readModeAbstractionTree = (0, import_react26.useMemo)(() => {
12419
12928
  if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
12420
12929
  return null;
12421
12930
  }
@@ -12427,7 +12936,7 @@ function XViewScene({
12427
12936
  allAncestries
12428
12937
  );
12429
12938
  }, [readingMode.isActive, readingMode.ancestry, buildFullAncestryTree, sceneVersion]);
12430
- const handleStartReadingAncestry = (0, import_react25.useCallback)(
12939
+ const handleStartReadingAncestry = (0, import_react26.useCallback)(
12431
12940
  async (ancestryObject) => {
12432
12941
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
12433
12942
  if (!ancestryObject || !ancestryObject.tree) {
@@ -12462,7 +12971,7 @@ function XViewScene({
12462
12971
  },
12463
12972
  [handleRenderAncestry, handleRenderAbstractionTree]
12464
12973
  );
12465
- const handleReadModeSectionChange = (0, import_react25.useCallback)((activeSectionId) => {
12974
+ const handleReadModeSectionChange = (0, import_react26.useCallback)((activeSectionId) => {
12466
12975
  const { ancestry, branchStack } = readingMode;
12467
12976
  if (!ancestry || !readingMode.isActive) return;
12468
12977
  let targetObj = ancestry;
@@ -12531,10 +13040,10 @@ function XViewScene({
12531
13040
  }, 0);
12532
13041
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
12533
13042
  }, [readingMode, handleRenderAncestry, buildFullAncestryTree, ancestryDataRef.current]);
12534
- const handleCloseReadMode = (0, import_react25.useCallback)(() => {
13043
+ const handleCloseReadMode = (0, import_react26.useCallback)(() => {
12535
13044
  setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
12536
13045
  }, []);
12537
- const handleAncestrySectionChange = (0, import_react25.useCallback)((activeSectionId, ancestryOverride = null, rotation = 0) => {
13046
+ const handleAncestrySectionChange = (0, import_react26.useCallback)((activeSectionId, ancestryOverride = null, rotation = 0) => {
12538
13047
  var _a2, _b2;
12539
13048
  const currentMode = stateRef.current.ancestry;
12540
13049
  let targetObj = ancestryOverride;
@@ -12586,7 +13095,7 @@ function XViewScene({
12586
13095
  const renderPayload = { ...targetObj, tree: treeToRender };
12587
13096
  handleRenderAncestry(renderPayload, allowedIds, focusTargetId, rotation);
12588
13097
  }, [handleRenderAncestry]);
12589
- const handleEditAncestry = (0, import_react25.useCallback)(
13098
+ const handleEditAncestry = (0, import_react26.useCallback)(
12590
13099
  async (ancestryObject) => {
12591
13100
  setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
12592
13101
  if (!ancestryObject || !ancestryObject.tree) {
@@ -12625,7 +13134,7 @@ function XViewScene({
12625
13134
  const handleSelectAncestryParent = (nodeId) => {
12626
13135
  setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
12627
13136
  };
12628
- const handleRemoveFromAncestry = (0, import_react25.useCallback)((pathToRemove) => {
13137
+ const handleRemoveFromAncestry = (0, import_react26.useCallback)((pathToRemove) => {
12629
13138
  if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
12630
13139
  console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
12631
13140
  return;
@@ -12650,7 +13159,7 @@ function XViewScene({
12650
13159
  return { ...prev, tree: newTree };
12651
13160
  });
12652
13161
  }, []);
12653
- const handleSaveAncestry = (0, import_react25.useCallback)(
13162
+ const handleSaveAncestry = (0, import_react26.useCallback)(
12654
13163
  async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
12655
13164
  const treeToUse = treeOverride || ancestryMode.tree;
12656
13165
  const { isEditMode, currentAncestryId } = ancestryMode;
@@ -12854,7 +13363,7 @@ function XViewScene({
12854
13363
  });
12855
13364
  setEditingAncestryRel({ visible: false, data: null, path: null });
12856
13365
  };
12857
- const handleDeleteAncestry = (0, import_react25.useCallback)(
13366
+ const handleDeleteAncestry = (0, import_react26.useCallback)(
12858
13367
  async (ancestryIdToDelete) => {
12859
13368
  if (!ancestryIdToDelete) {
12860
13369
  alert("ID da ancestralidade n\xE3o encontrado.");
@@ -12916,30 +13425,30 @@ function XViewScene({
12916
13425
  },
12917
13426
  [save_view_data, delete_file_action]
12918
13427
  );
12919
- const handleOpenAncestryBoard = (0, import_react25.useCallback)(() => {
13428
+ const handleOpenAncestryBoard = (0, import_react26.useCallback)(() => {
12920
13429
  setIsAncestryBoardOpen(true);
12921
13430
  }, []);
12922
- const handleSelectAncestryFromBoard = (0, import_react25.useCallback)((ancestry) => {
13431
+ const handleSelectAncestryFromBoard = (0, import_react26.useCallback)((ancestry) => {
12923
13432
  setIsAncestryBoardOpen(false);
12924
13433
  setIsSidebarOpen(false);
12925
13434
  handleStartReadingAncestry(ancestry);
12926
13435
  }, [handleStartReadingAncestry]);
12927
- const handleSaveAncestryBoard = (0, import_react25.useCallback)(async (groups) => {
13436
+ const handleSaveAncestryBoard = (0, import_react26.useCallback)(async (groups) => {
12928
13437
  if (!sceneConfigId || !viewParams || !session) return;
12929
13438
  const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
12930
13439
  await save_ancestry_board_action(sceneConfigId, sceneType, groups, session, ownerId);
12931
13440
  }, [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]);
12932
- const existingNodeTypes = (0, import_react25.useMemo)(() => {
13441
+ const existingNodeTypes = (0, import_react26.useMemo)(() => {
12933
13442
  if (!parentDataRef.current) {
12934
13443
  return [];
12935
13444
  }
12936
13445
  const allTypes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes.flatMap((node) => {
12937
13446
  if (Array.isArray(node.type)) return node.type;
12938
13447
  return [node.type];
12939
- })).filter(Boolean);
13448
+ })).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
12940
13449
  return [...new Set(allTypes)];
12941
13450
  }, [parentDataRef.current, sceneVersion]);
12942
- const searchableDbNodes = (0, import_react25.useMemo)(() => {
13451
+ const searchableDbNodes = (0, import_react26.useMemo)(() => {
12943
13452
  if (!parentDataRef.current) {
12944
13453
  return [];
12945
13454
  }
@@ -12948,14 +13457,14 @@ function XViewScene({
12948
13457
  return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
12949
13458
  });
12950
13459
  }, [parentDataRef.current, sceneVersion]);
12951
- const handleAddExistingNode = (0, import_react25.useCallback)(
13460
+ const handleAddExistingNode = (0, import_react26.useCallback)(
12952
13461
  (nodeId) => {
12953
13462
  return userActionHandlers.handleAddExistingNodeById(actionHandlerContext, nodeId);
12954
13463
  },
12955
13464
  [actionHandlerContext]
12956
13465
  );
12957
- const handleSaveCurrentView = (0, import_react25.useCallback)(async () => {
12958
- var _a2, _b2;
13466
+ const handleSaveCurrentView = (0, import_react26.useCallback)(async () => {
13467
+ var _a2, _b2, _c2;
12959
13468
  const { nodeObjects, allLinks } = stateRef.current;
12960
13469
  if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
12961
13470
  console.warn("N\xE3o \xE9 poss\xEDvel salvar a cena: estado n\xE3o inicializado ou URL de salvamento ausente.");
@@ -12977,28 +13486,30 @@ function XViewScene({
12977
13486
  const { sourceNode, targetNode, ...serializableLinkData } = line.userData;
12978
13487
  return serializableLinkData;
12979
13488
  });
13489
+ sceneDataRef.current.nodes = currentNodes;
13490
+ sceneDataRef.current.links = currentLinks;
13491
+ const isView = ((_a2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _a2.toLowerCase()) === "view";
12980
13492
  const sceneFileData = {
12981
13493
  parent_dbs: sceneDataRef.current.parent_dbs,
12982
13494
  nodes: currentNodes,
12983
13495
  links: currentLinks,
12984
- // --- ADICIONE ESTAS DUAS LINHAS PARA PRESERVAR A FONTE DA VERDADE ---
12985
- quest_nodes: ((_a2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _a2.nodes) || [],
12986
- quest_links: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.links) || []
13496
+ quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
13497
+ quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || []
12987
13498
  };
12988
13499
  try {
12989
13500
  await save_view_data(sceneSaveUrl, sceneFileData);
12990
13501
  } catch (error) {
12991
13502
  console.error("Erro na chamada de save_view_data:", error);
12992
13503
  }
12993
- }, [sceneSaveUrl, save_view_data, sceneConfigId]);
12994
- const allAvailableNodes = (0, import_react25.useMemo)(() => {
13504
+ }, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
13505
+ const allAvailableNodes = (0, import_react26.useMemo)(() => {
12995
13506
  if (!parentDataRef.current) return [];
12996
13507
  return Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
12997
13508
  }, [sceneVersion, isInitialized]);
12998
- const allAvailableAncestries = (0, import_react25.useMemo)(() => {
13509
+ const allAvailableAncestries = (0, import_react26.useMemo)(() => {
12999
13510
  return ancestryDataRef.current || [];
13000
13511
  }, [sceneVersion, isInitialized]);
13001
- const handleOpenReference = (0, import_react25.useCallback)((referenceData) => {
13512
+ const handleOpenReference = (0, import_react26.useCallback)((referenceData) => {
13002
13513
  const { type, id } = referenceData;
13003
13514
  if (type === "node") {
13004
13515
  const targetNode = allAvailableNodes.find((n) => String(n.id) === String(id));
@@ -13025,17 +13536,17 @@ function XViewScene({
13025
13536
  }
13026
13537
  }
13027
13538
  }, [allAvailableNodes, allAvailableAncestries, handleEditAncestry, tweenToTarget]);
13028
- const handleToggleAncestryAddMode = (0, import_react25.useCallback)(() => {
13539
+ const handleToggleAncestryAddMode = (0, import_react26.useCallback)(() => {
13029
13540
  setAncestryMode((prev) => ({ ...prev, isAddingNodes: !prev.isAddingNodes }));
13030
13541
  }, []);
13031
- const handleFocusNode = (0, import_react25.useCallback)((nodeData) => {
13542
+ const handleFocusNode = (0, import_react26.useCallback)((nodeData) => {
13032
13543
  if (!nodeData) return;
13033
13544
  const nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
13034
13545
  if (nodeMesh) {
13035
13546
  tweenToTarget(nodeMesh, 1.2);
13036
13547
  }
13037
13548
  }, [tweenToTarget]);
13038
- const availableDatasets = (0, import_react25.useMemo)(() => {
13549
+ const availableDatasets = (0, import_react26.useMemo)(() => {
13039
13550
  if (!sceneDataRef.current || !parentDataRef.current) return [];
13040
13551
  return sceneDataRef.current.parent_dbs.map((db) => {
13041
13552
  var _a2;
@@ -13047,7 +13558,7 @@ function XViewScene({
13047
13558
  }, [sceneVersion, isInitialized]);
13048
13559
  const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(String(creationMode.sourceNodeData.id))) == null ? void 0 : _b.parentFileId : null;
13049
13560
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
13050
- (0, import_react25.useEffect)(() => {
13561
+ (0, import_react26.useEffect)(() => {
13051
13562
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
13052
13563
  const nodeObjects = stateRef.current.nodeObjects || {};
13053
13564
  const targetMesh = nodeObjects[String(focusNodeId)];
@@ -13061,7 +13572,7 @@ function XViewScene({
13061
13572
  }
13062
13573
  }
13063
13574
  }, [isInitialized, sceneVersion, focusNodeId, hasFocusedInitial, tweenToTarget]);
13064
- (0, import_react25.useEffect)(() => {
13575
+ (0, import_react26.useEffect)(() => {
13065
13576
  if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
13066
13577
  const ancestries = ancestryDataRef.current || [];
13067
13578
  const targetAncestry = ancestries.find((a) => String(a.ancestry_id) === String(focusAncestryId));
@@ -13075,21 +13586,121 @@ function XViewScene({
13075
13586
  }
13076
13587
  }
13077
13588
  }, [isInitialized, sceneVersion, focusAncestryId, hasOpenedInitialAncestry, handleStartReadingAncestry]);
13589
+ (0, import_react26.useEffect)(() => {
13590
+ function handleKeyDown(event) {
13591
+ var _a2, _b2, _c2;
13592
+ const context = actionHandlerContext;
13593
+ if (event.key === "Escape") {
13594
+ if (stateRef.current.connection.isActive) userActionHandlers.handleCancelConnection(context);
13595
+ if (stateRef.current.relink.isActive) userActionHandlers.handleCancelRelink(context);
13596
+ if (stateRef.current.creation.isActive) userActionHandlers.handleCancelCreation(context);
13597
+ if ((_a2 = stateRef.current.versionMode) == null ? void 0 : _a2.isActive) userActionHandlers.handleCancelVersioning(context);
13598
+ if (stateRef.current.ancestry.isActive) {
13599
+ setAncestryMode({ isActive: false, tree: null, selectedParentId: null, isEditMode: false, currentAncestryId: null, ancestryName: "", ancestryDescription: "", ancestryDescriptionSections: [], isAddingNodes: false });
13600
+ if (mountRef.current) mountRef.current.style.cursor = "grab";
13601
+ }
13602
+ if (questMode.isActive) {
13603
+ handleCancelQuest();
13604
+ }
13605
+ if (stateRef.current.selectedNodes.size > 0) {
13606
+ stateRef.current.selectedNodes.clear();
13607
+ }
13608
+ setContextMenu((prev) => prev.visible ? { ...prev, visible: false } : prev);
13609
+ setMultiContextMenu((prev) => ({ ...prev, visible: false }));
13610
+ setRelationshipMenu((prev) => ({ ...prev, visible: false }));
13611
+ }
13612
+ if (event.key.toLowerCase() === "q") {
13613
+ const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isAncestryBoardOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
13614
+ if (isUiClear) {
13615
+ const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
13616
+ if (!isView) return;
13617
+ const { graphGroup, glowTexture, controls, nodeObjects } = stateRef.current;
13618
+ if (graphGroup) {
13619
+ let ghostPosition = controls.target.clone();
13620
+ const existingNodes = Object.values(nodeObjects);
13621
+ let isOccupied = true;
13622
+ let radius = 18;
13623
+ let angle = 0;
13624
+ let attempts = 0;
13625
+ const MIN_CLEARANCE = 15;
13626
+ while (isOccupied && attempts < 30) {
13627
+ isOccupied = existingNodes.some((mesh) => mesh.position.distanceTo(ghostPosition) < MIN_CLEARANCE);
13628
+ if (isOccupied) {
13629
+ ghostPosition.x = controls.target.x + Math.cos(angle) * radius;
13630
+ ghostPosition.y = controls.target.y + (Math.random() - 0.5) * 8;
13631
+ ghostPosition.z = controls.target.z + Math.sin(angle) * radius;
13632
+ angle += Math.PI / 3;
13633
+ radius += 2.5;
13634
+ attempts++;
13635
+ }
13636
+ }
13637
+ const ghostData = {
13638
+ id: "ghost_quest",
13639
+ name: "Nova Quest",
13640
+ color: "#64748b",
13641
+ // Cor padrão de "Backlog"
13642
+ size: "medium",
13643
+ intensity: 0,
13644
+ type: ["quest"]
13645
+ };
13646
+ const ghostNode = createNodeMesh(ghostData, ghostPosition, glowTexture);
13647
+ ghostNode.traverse((child) => {
13648
+ if (child.isMesh) {
13649
+ child.material.transparent = true;
13650
+ child.material.opacity = 0.75;
13651
+ }
13652
+ });
13653
+ graphGroup.add(ghostNode);
13654
+ if (ghostNode.userData.labelObject) {
13655
+ graphGroup.add(ghostNode.userData.labelObject);
13656
+ }
13657
+ stateRef.current.ghostElements = {
13658
+ node: ghostNode,
13659
+ line: null,
13660
+ aura: ghostNode.getObjectByName("aura")
13661
+ };
13662
+ context.tweenToTarget(ghostPosition, 1.6);
13663
+ }
13664
+ setQuestMode({ isActive: true });
13665
+ }
13666
+ }
13667
+ }
13668
+ window.addEventListener("keydown", handleKeyDown);
13669
+ return () => window.removeEventListener("keydown", handleKeyDown);
13670
+ }, [
13671
+ contextMenu.visible,
13672
+ multiContextMenu.visible,
13673
+ relationshipMenu.visible,
13674
+ readingMode.isActive,
13675
+ isImportModalOpen,
13676
+ isAncestryBoardOpen,
13677
+ isSidebarOpen,
13678
+ detailsNode,
13679
+ detailsLink,
13680
+ ancestryLinkDetails,
13681
+ imageViewer.visible,
13682
+ editingAncestryRel.visible,
13683
+ questMode.isActive,
13684
+ viewParams,
13685
+ actionHandlerContext,
13686
+ handleCancelQuest
13687
+ // <-- handleCancelQuest adicionado aqui
13688
+ ]);
13078
13689
  if (isLoading || status === "loading" || permissionStatus === "loading") {
13079
- return /* @__PURE__ */ import_react25.default.createElement(LoadingScreen, null);
13690
+ return /* @__PURE__ */ import_react26.default.createElement(LoadingScreen, null);
13080
13691
  }
13081
13692
  if (permissionStatus === "denied") {
13082
- 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(
13083
13694
  "button",
13084
13695
  {
13085
13696
  onClick: () => router.push("/dashboard/scenes"),
13086
13697
  className: "flex items-center justify-center gap-2 w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors font-medium"
13087
13698
  },
13088
- /* @__PURE__ */ 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" })),
13089
13700
  "Voltar para Scenes"
13090
13701
  )));
13091
13702
  }
13092
- return /* @__PURE__ */ import_react25.default.createElement(
13703
+ return /* @__PURE__ */ import_react26.default.createElement(
13093
13704
  "div",
13094
13705
  {
13095
13706
  ref: mountRef,
@@ -13101,7 +13712,7 @@ function XViewScene({
13101
13712
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
13102
13713
  }
13103
13714
  },
13104
- userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react25.default.createElement(
13715
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ import_react26.default.createElement(
13105
13716
  XViewSidebar,
13106
13717
  {
13107
13718
  dbNodes: searchableDbNodes,
@@ -13121,7 +13732,7 @@ function XViewScene({
13121
13732
  userRole: userPermissionRole
13122
13733
  }
13123
13734
  ),
13124
- creationMode.isActive && /* @__PURE__ */ import_react25.default.createElement(
13735
+ creationMode.isActive && /* @__PURE__ */ import_react26.default.createElement(
13125
13736
  InSceneCreationForm,
13126
13737
  {
13127
13738
  onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
@@ -13146,7 +13757,7 @@ function XViewScene({
13146
13757
  availableAncestries: allAvailableAncestries
13147
13758
  }
13148
13759
  ),
13149
- versionMode.isActive && /* @__PURE__ */ import_react25.default.createElement(
13760
+ versionMode.isActive && /* @__PURE__ */ import_react26.default.createElement(
13150
13761
  InSceneVersionForm,
13151
13762
  {
13152
13763
  onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
@@ -13165,27 +13776,32 @@ function XViewScene({
13165
13776
  availableAncestries: allAvailableAncestries
13166
13777
  }
13167
13778
  ),
13168
- questMode.isActive && /* @__PURE__ */ import_react25.default.createElement(
13779
+ questMode.isActive && /* @__PURE__ */ import_react26.default.createElement(
13169
13780
  InSceneQuestForm,
13170
13781
  {
13171
13782
  onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
13172
- onCancel: () => setQuestMode({ isActive: false }),
13783
+ onCancel: handleCancelQuest,
13784
+ onNameChange: handleGhostNodeNameChange,
13785
+ onColorChange: handleGhostNodeColorChange,
13786
+ onSizeChange: handleGhostNodeSizeChange,
13173
13787
  style: { position: "absolute", left: `16px`, top: `16px`, zIndex: 20, transition: "opacity 200ms ease-out" },
13174
13788
  refEl: formRef,
13175
13789
  onOpenImageViewer: handleOpenImageViewer,
13176
13790
  onMentionClick: handleAddExistingNode,
13177
13791
  onUploadFile: upload_file_action,
13178
13792
  availableNodes: allAvailableNodes,
13179
- availableAncestries: allAvailableAncestries
13793
+ availableAncestries: allAvailableAncestries,
13794
+ viewName: viewParams == null ? void 0 : viewParams.name,
13795
+ questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1
13180
13796
  }
13181
13797
  ),
13182
- readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react25.default.createElement(
13798
+ readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react26.default.createElement(
13183
13799
  "div",
13184
13800
  {
13185
13801
  className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isReadModeResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
13186
13802
  style: { top: 16, right: 16, zIndex: 1100, maxHeight: "calc(100vh - 32px)", width: `${readModeWidth}px`, maxWidth: "92vw" }
13187
13803
  },
13188
- /* @__PURE__ */ import_react25.default.createElement(
13804
+ /* @__PURE__ */ import_react26.default.createElement(
13189
13805
  "div",
13190
13806
  {
13191
13807
  onPointerDown: (e) => {
@@ -13196,7 +13812,7 @@ function XViewScene({
13196
13812
  title: "Arraste para redimensionar"
13197
13813
  }
13198
13814
  ),
13199
- /* @__PURE__ */ import_react25.default.createElement(
13815
+ /* @__PURE__ */ import_react26.default.createElement(
13200
13816
  DescriptionReadModePanel,
13201
13817
  {
13202
13818
  key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
@@ -13231,7 +13847,7 @@ function XViewScene({
13231
13847
  }
13232
13848
  )
13233
13849
  ),
13234
- ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ import_react25.default.createElement(
13850
+ ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ import_react26.default.createElement(
13235
13851
  CreateAncestryPanel,
13236
13852
  {
13237
13853
  ancestryMode,
@@ -13258,7 +13874,7 @@ function XViewScene({
13258
13874
  onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
13259
13875
  }
13260
13876
  ),
13261
- editingAncestryRel.visible && /* @__PURE__ */ import_react25.default.createElement(
13877
+ editingAncestryRel.visible && /* @__PURE__ */ import_react26.default.createElement(
13262
13878
  AncestryRelationshipPanel,
13263
13879
  {
13264
13880
  data: editingAncestryRel.data,
@@ -13272,7 +13888,28 @@ function XViewScene({
13272
13888
  onUploadFile: upload_file_action
13273
13889
  }
13274
13890
  ),
13275
- detailsNode && /* @__PURE__ */ 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(
13276
13913
  NodeDetailsPanel,
13277
13914
  {
13278
13915
  node: detailsNode,
@@ -13299,7 +13936,7 @@ function XViewScene({
13299
13936
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
13300
13937
  }
13301
13938
  ),
13302
- detailsLink && /* @__PURE__ */ import_react25.default.createElement(
13939
+ detailsLink && /* @__PURE__ */ import_react26.default.createElement(
13303
13940
  RelationshipDetailsPanel,
13304
13941
  {
13305
13942
  link: detailsLink,
@@ -13313,7 +13950,7 @@ function XViewScene({
13313
13950
  userRole: userPermissionRole
13314
13951
  }
13315
13952
  ),
13316
- ancestryLinkDetails && /* @__PURE__ */ import_react25.default.createElement(
13953
+ ancestryLinkDetails && /* @__PURE__ */ import_react26.default.createElement(
13317
13954
  AncestryLinkDetailsPanel,
13318
13955
  {
13319
13956
  data: ancestryLinkDetails,
@@ -13324,7 +13961,7 @@ function XViewScene({
13324
13961
  onUploadFile: upload_file_action
13325
13962
  }
13326
13963
  ),
13327
- /* @__PURE__ */ import_react25.default.createElement(
13964
+ /* @__PURE__ */ import_react26.default.createElement(
13328
13965
  "div",
13329
13966
  {
13330
13967
  ref: tooltipRef,
@@ -13351,7 +13988,7 @@ function XViewScene({
13351
13988
  }
13352
13989
  }
13353
13990
  ),
13354
- /* @__PURE__ */ import_react25.default.createElement(
13991
+ /* @__PURE__ */ import_react26.default.createElement(
13355
13992
  ContextMenu,
13356
13993
  {
13357
13994
  data: contextMenu,
@@ -13374,7 +14011,7 @@ function XViewScene({
13374
14011
  onFocusNode: handleFocusNode
13375
14012
  }
13376
14013
  ),
13377
- /* @__PURE__ */ import_react25.default.createElement(
14014
+ /* @__PURE__ */ import_react26.default.createElement(
13378
14015
  MultiNodeContextMenu,
13379
14016
  {
13380
14017
  data: multiContextMenu,
@@ -13385,7 +14022,7 @@ function XViewScene({
13385
14022
  onDeleteNodes: (ids) => userActionHandlers.handleDeleteMultipleNodes(actionHandlerContext, ids)
13386
14023
  }
13387
14024
  ),
13388
- /* @__PURE__ */ import_react25.default.createElement(
14025
+ /* @__PURE__ */ import_react26.default.createElement(
13389
14026
  RelationshipContextMenu,
13390
14027
  {
13391
14028
  data: relationshipMenu,
@@ -13403,8 +14040,8 @@ function XViewScene({
13403
14040
  onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
13404
14041
  }
13405
14042
  ),
13406
- /* @__PURE__ */ import_react25.default.createElement(ImageViewer, { data: imageViewer, onClose: () => setImageViewer({ ...imageViewer, visible: false }) }),
13407
- /* @__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(
13408
14045
  AncestryBoard,
13409
14046
  {
13410
14047
  isOpen: isAncestryBoardOpen,
@@ -13417,14 +14054,14 @@ function XViewScene({
13417
14054
  userRole: userPermissionRole
13418
14055
  }
13419
14056
  ),
13420
- /* @__PURE__ */ import_react25.default.createElement(
14057
+ /* @__PURE__ */ import_react26.default.createElement(
13421
14058
  ImportParentFileModal,
13422
14059
  {
13423
14060
  isOpen: isImportModalOpen,
13424
14061
  onClose: () => setIsImportModalOpen(false),
13425
14062
  onConfirm: handleConfirmImport,
13426
14063
  session,
13427
- parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
14064
+ parentDbs: ((_h = sceneDataRef.current) == null ? void 0 : _h.parent_dbs) || [],
13428
14065
  onFetchAvailableFiles: import_parent_file_modal_get,
13429
14066
  currentViewName: viewParams == null ? void 0 : viewParams.name,
13430
14067
  currentAncestries: ancestryDataRef.current || []
@@ -13461,6 +14098,12 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
13461
14098
  }
13462
14099
  const sceneData = sceneResponse.data;
13463
14100
  const parentDbObjects = sceneData.parent_dbs || [];
14101
+ if (type && type.toLowerCase().includes("database")) {
14102
+ const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
14103
+ if (!selfExists) {
14104
+ parentDbObjects.push({ db_id: scene_config, owner_id });
14105
+ }
14106
+ }
13464
14107
  const parentResponsesPromises = parentDbObjects.map(
13465
14108
  (db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
13466
14109
  );
@@ -13478,21 +14121,32 @@ async function get_scene_view_data_logic(db_services, scene_config, owner_id, ty
13478
14121
  );
13479
14122
  }
13480
14123
  }
13481
- parentData[scene_config] = {
13482
- dataset_name: "Quests Internas (View)",
13483
- nodes: sceneData.quest_nodes || [],
13484
- links: sceneData.quest_links || []
13485
- };
14124
+ if (type && type.toLowerCase() === "view") {
14125
+ parentData[scene_config] = {
14126
+ dataset_name: "Quests Internas (View)",
14127
+ nodes: sceneData.quest_nodes || [],
14128
+ links: sceneData.quest_links || []
14129
+ };
14130
+ }
13486
14131
  const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
13487
14132
  const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
13488
14133
  const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
13489
14134
  const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
13490
14135
  const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
14136
+ var _a2, _b2;
13491
14137
  const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
13492
14138
  if (nodeTypes.includes("quest")) {
14139
+ const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
14140
+ if (dbQuestNode) {
14141
+ return { ...sceneNode, ...dbQuestNode };
14142
+ }
13493
14143
  return sceneNode;
13494
14144
  }
13495
- 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;
13496
14150
  }).filter(Boolean);
13497
14151
  const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
13498
14152
  const validatedLinks = (sceneData.links || []).filter((sceneLink) => {