@lv-x-software-house/x_view 1.2.5-dev.2 → 1.2.5-dev.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +850 -156
- package/dist/index.mjs +854 -161
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
get_ancestry_file_logic: () => get_ancestry_file_logic,
|
|
36
36
|
get_scene_view_data_logic: () => get_scene_view_data_logic,
|
|
37
37
|
get_single_parent_file_logic: () => get_single_parent_file_logic,
|
|
38
|
+
get_view_members_logic: () => get_view_members_logic,
|
|
38
39
|
import_parent_file_modal_get_logic: () => import_parent_file_modal_get_logic,
|
|
39
40
|
save_ancestry_board_logic: () => save_ancestry_board_logic,
|
|
40
41
|
save_view_data_logic: () => save_view_data_logic,
|
|
@@ -141,7 +142,10 @@ function ContextMenu({
|
|
|
141
142
|
onEditAncestry,
|
|
142
143
|
onDeleteAncestry,
|
|
143
144
|
onFocusNode,
|
|
144
|
-
onClose
|
|
145
|
+
onClose,
|
|
146
|
+
viewMembers,
|
|
147
|
+
currentUser,
|
|
148
|
+
onStartQuest
|
|
145
149
|
}) {
|
|
146
150
|
var _a, _b, _c;
|
|
147
151
|
const menuRef = (0, import_react.useRef)(null);
|
|
@@ -149,6 +153,7 @@ function ContextMenu({
|
|
|
149
153
|
const [menuView, setMenuView] = (0, import_react.useState)("main");
|
|
150
154
|
const [selectedAncestry, setSelectedAncestry] = (0, import_react.useState)(null);
|
|
151
155
|
const [versionSubMenu, setVersionSubMenu] = (0, import_react.useState)(null);
|
|
156
|
+
const [labelSubMenu, setLabelSubMenu] = (0, import_react.useState)(null);
|
|
152
157
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react.useState)(false);
|
|
153
158
|
const [selectedQuestStatus, setSelectedQuestStatus] = (0, import_react.useState)(null);
|
|
154
159
|
const ability = (0, import_react.useMemo)(() => defineAbilityFor(userRole), [userRole]);
|
|
@@ -157,6 +162,7 @@ function ContextMenu({
|
|
|
157
162
|
setMenuView("main");
|
|
158
163
|
setSelectedAncestry(null);
|
|
159
164
|
setVersionSubMenu(null);
|
|
165
|
+
setLabelSubMenu(null);
|
|
160
166
|
setSelectedQuestStatus(null);
|
|
161
167
|
}
|
|
162
168
|
}, [data.visible, (_a = data.nodeData) == null ? void 0 : _a.id]);
|
|
@@ -172,7 +178,7 @@ function ContextMenu({
|
|
|
172
178
|
if (left + w + 8 > vw) left = Math.max(8, vw - w - 8);
|
|
173
179
|
if (top + h + 8 > vh) top = Math.max(8, vh - h - 8);
|
|
174
180
|
setMenuPos({ left, top });
|
|
175
|
-
}, [data, menuView, versionSubMenu, selectedQuestStatus]);
|
|
181
|
+
}, [data, menuView, versionSubMenu, labelSubMenu, selectedQuestStatus]);
|
|
176
182
|
(0, import_react.useEffect)(() => {
|
|
177
183
|
if (!data.visible) return;
|
|
178
184
|
const handleClickOutside = (e) => {
|
|
@@ -224,7 +230,21 @@ function ContextMenu({
|
|
|
224
230
|
var _a2;
|
|
225
231
|
return (_a2 = c.targetNode) == null ? void 0 : _a2.is_quest;
|
|
226
232
|
});
|
|
227
|
-
const
|
|
233
|
+
const getLabelForConnection = (conn) => {
|
|
234
|
+
if (conn.direction === "outgoing") return conn.link.source_label || null;
|
|
235
|
+
if (conn.direction === "incoming") return conn.link.target_label || null;
|
|
236
|
+
return null;
|
|
237
|
+
};
|
|
238
|
+
const commonWithLabel = commonConnections.filter((c) => getLabelForConnection(c));
|
|
239
|
+
const commonWithoutLabel = commonConnections.filter((c) => !getLabelForConnection(c));
|
|
240
|
+
const labelGroups = commonWithLabel.reduce((acc, conn) => {
|
|
241
|
+
const label = getLabelForConnection(conn);
|
|
242
|
+
if (!acc[label]) acc[label] = [];
|
|
243
|
+
acc[label].push(conn);
|
|
244
|
+
return acc;
|
|
245
|
+
}, {});
|
|
246
|
+
const labelGroupEntries = Object.entries(labelGroups).sort(([a], [b]) => a.localeCompare(b));
|
|
247
|
+
const groupedConnections = commonWithoutLabel.reduce((acc, conn) => {
|
|
228
248
|
var _a2;
|
|
229
249
|
const { targetNode } = conn;
|
|
230
250
|
const groupingKey = ((_a2 = targetNode.version_node) == null ? void 0 : _a2.is_version) ? targetNode.version_node.parent_node : targetNode.id;
|
|
@@ -326,12 +346,25 @@ function ContextMenu({
|
|
|
326
346
|
});
|
|
327
347
|
};
|
|
328
348
|
const renderMainView = () => {
|
|
329
|
-
var _a2;
|
|
349
|
+
var _a2, _b2, _c2;
|
|
330
350
|
const hasVersions = computedVersions.length > 0;
|
|
331
351
|
const canCreateVersion = ability.can("create", "Versioning");
|
|
332
352
|
const canReadVersion = ability.can("read", "Versioning");
|
|
333
353
|
const shouldShowVersioningBtn = canCreateVersion || canReadVersion && hasVersions;
|
|
334
|
-
|
|
354
|
+
const canStartQuest = isCurrentNodeQuest && (((_a2 = data.nodeData) == null ? void 0 : _a2.status) !== "In Progress" || ((_b2 = data.nodeData) == null ? void 0 : _b2.assignee_id) !== (currentUser == null ? void 0 : currentUser.id));
|
|
355
|
+
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" }, canStartQuest && /* @__PURE__ */ import_react.default.createElement(
|
|
356
|
+
"button",
|
|
357
|
+
{
|
|
358
|
+
onClick: () => {
|
|
359
|
+
onStartQuest == null ? void 0 : onStartQuest(data.nodeData);
|
|
360
|
+
onClose();
|
|
361
|
+
},
|
|
362
|
+
className: `w-full flex items-center gap-2.5 px-2 py-1.5 text-left text-sm rounded-md bg-yellow-500/10 text-yellow-400 hover:bg-yellow-500/20 hover:text-yellow-300 transition-colors duration-150 truncate font-semibold shadow-inner`,
|
|
363
|
+
title: "Atribuir a mim e iniciar"
|
|
364
|
+
},
|
|
365
|
+
/* @__PURE__ */ import_react.default.createElement("span", null, "\u{1F680}"),
|
|
366
|
+
/* @__PURE__ */ import_react.default.createElement("span", null, "Iniciar Quest")
|
|
367
|
+
), 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") && !((_c2 = data.nodeData) == null ? void 0 : _c2.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: () => {
|
|
335
368
|
onFocusNode == null ? void 0 : onFocusNode(data.nodeData);
|
|
336
369
|
onClose();
|
|
337
370
|
}, 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"))));
|
|
@@ -352,11 +385,32 @@ function ContextMenu({
|
|
|
352
385
|
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
|
|
353
386
|
))));
|
|
354
387
|
};
|
|
388
|
+
const renderLabelSubMenuView = () => {
|
|
389
|
+
const group = labelSubMenu;
|
|
390
|
+
const isScrollable = group.connections.length > 10;
|
|
391
|
+
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: () => {
|
|
392
|
+
setLabelSubMenu(null);
|
|
393
|
+
setMenuView("connections");
|
|
394
|
+
}, 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("div", { className: "flex items-center gap-1.5 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-violet-400 flex-shrink-0" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "7", y1: "7", x2: "7.01", y2: "7" })), /* @__PURE__ */ import_react.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-violet-300/80 truncate", title: group.label }, group.label))), group.connections.length > 0 && /* @__PURE__ */ import_react.default.createElement("button", { onClick: () => handleExpandAndClose(group.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 gap-1 ${isScrollable ? "max-h-[40vh] overflow-y-auto custom-scrollbar" : ""}` }, group.connections.map((conn) => /* @__PURE__ */ import_react.default.createElement(
|
|
395
|
+
"button",
|
|
396
|
+
{
|
|
397
|
+
key: conn.targetNode.id,
|
|
398
|
+
onClick: () => handleExpandAndClose([conn.link]),
|
|
399
|
+
className: baseButtonClass,
|
|
400
|
+
title: `Expandir conex\xE3o com ${conn.targetNode.name}`
|
|
401
|
+
},
|
|
402
|
+
/* @__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: "5", y1: "12", x2: "19", y2: "12" }), /* @__PURE__ */ import_react.default.createElement("polyline", { points: "12 5 19 12 12 19" })),
|
|
403
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, conn.targetNode.name)
|
|
404
|
+
))));
|
|
405
|
+
};
|
|
355
406
|
const renderConnectionsView = () => {
|
|
356
407
|
if (versionSubMenu) {
|
|
357
408
|
return renderVersionSubMenuView();
|
|
358
409
|
}
|
|
359
|
-
|
|
410
|
+
if (labelSubMenu) {
|
|
411
|
+
return renderLabelSubMenuView();
|
|
412
|
+
}
|
|
413
|
+
const totalItems = availableAncestries.length + labelGroupEntries.length + finalRenderableConnections.length + (questConnections.length > 0 ? 1 : 0);
|
|
360
414
|
const isScrollable = totalItems > 10;
|
|
361
415
|
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(
|
|
362
416
|
"button",
|
|
@@ -368,7 +422,20 @@ function ContextMenu({
|
|
|
368
422
|
},
|
|
369
423
|
/* @__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" })),
|
|
370
424
|
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, anc.name || `Ancestralidade #${anc.ancestry_id.substring(0, 8)}`)
|
|
371
|
-
))),
|
|
425
|
+
))), labelGroupEntries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: `flex flex-col gap-1 ${availableAncestries.length > 0 ? "mt-2" : ""} ${finalRenderableConnections.length > 0 || questConnections.length > 0 ? "mb-2" : ""}` }, availableAncestries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), labelGroupEntries.map(([label, conns]) => /* @__PURE__ */ import_react.default.createElement(
|
|
426
|
+
"button",
|
|
427
|
+
{
|
|
428
|
+
key: label,
|
|
429
|
+
onClick: () => {
|
|
430
|
+
setLabelSubMenu({ label, connections: conns });
|
|
431
|
+
},
|
|
432
|
+
className: baseButtonClass,
|
|
433
|
+
title: `Ver grupo: ${label}`
|
|
434
|
+
},
|
|
435
|
+
/* @__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-violet-400" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "7", y1: "7", x2: "7.01", y2: "7" })),
|
|
436
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "flex-1 truncate" }, label),
|
|
437
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "text-xs px-2 py-0.5 bg-violet-500/20 text-violet-300 rounded-full" }, conns.length)
|
|
438
|
+
))), finalRenderableConnections.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", { className: "flex flex-col gap-1" }, (availableAncestries.length > 0 || labelGroupEntries.length > 0) && /* @__PURE__ */ import_react.default.createElement("div", { className: "my-1 h-px w-full bg-white/10" }), finalRenderableConnections.map((group) => {
|
|
372
439
|
if (group.isVersionGroup) {
|
|
373
440
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
374
441
|
"button",
|
|
@@ -552,15 +619,18 @@ function XViewSidebar({
|
|
|
552
619
|
const [isFilterMenuOpen, setIsFilterMenuOpen] = (0, import_react2.useState)(false);
|
|
553
620
|
const [filterCategory, setFilterCategory] = (0, import_react2.useState)("Type");
|
|
554
621
|
const [filterValue, setFilterValue] = (0, import_react2.useState)("");
|
|
622
|
+
const [isTypeDropdownOpen, setIsTypeDropdownOpen] = (0, import_react2.useState)(false);
|
|
623
|
+
const [highlightedTypeIndex, setHighlightedTypeIndex] = (0, import_react2.useState)(-1);
|
|
555
624
|
const containerRef = (0, import_react2.useRef)(null);
|
|
556
625
|
const inputRef = (0, import_react2.useRef)(null);
|
|
557
626
|
const filterMenuRef = (0, import_react2.useRef)(null);
|
|
627
|
+
const typeDropdownRef = (0, import_react2.useRef)(null);
|
|
558
628
|
const ability = (0, import_react2.useMemo)(() => {
|
|
559
629
|
return defineAbilityFor(userRole);
|
|
560
630
|
}, [userRole]);
|
|
561
631
|
const contextLabel = (0, import_react2.useMemo)(() => {
|
|
562
632
|
if (!viewType || !viewName) return null;
|
|
563
|
-
const typeLower = viewType.toLowerCase();
|
|
633
|
+
const typeLower = String(viewType).toLowerCase();
|
|
564
634
|
if (typeLower === "database") {
|
|
565
635
|
return `Dataset: ${viewName}`;
|
|
566
636
|
} else if (typeLower === "view") {
|
|
@@ -570,7 +640,12 @@ function XViewSidebar({
|
|
|
570
640
|
}
|
|
571
641
|
return `${viewType}: ${viewName}`;
|
|
572
642
|
}, [viewType, viewName]);
|
|
573
|
-
const normalize = (str = "") =>
|
|
643
|
+
const normalize = (str = "") => {
|
|
644
|
+
if (str === void 0 || str === null) {
|
|
645
|
+
console.warn("XViewSidebar: normalize recebeu valor nulo/indefinido:", str);
|
|
646
|
+
}
|
|
647
|
+
return String(str).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[._\-–—:,;!?'"()\[\]{}/\\]/g, " ").replace(/\s+/g, " ").trim();
|
|
648
|
+
};
|
|
574
649
|
const collator = (0, import_react2.useMemo)(
|
|
575
650
|
() => new Intl.Collator("pt-BR", { sensitivity: "base", numeric: true }),
|
|
576
651
|
[]
|
|
@@ -579,13 +654,30 @@ function XViewSidebar({
|
|
|
579
654
|
const typesSet = /* @__PURE__ */ new Set();
|
|
580
655
|
(dbNodes || []).forEach((node) => {
|
|
581
656
|
if (Array.isArray(node.type)) {
|
|
582
|
-
node.type.forEach((t) =>
|
|
583
|
-
|
|
657
|
+
node.type.forEach((t) => {
|
|
658
|
+
if (t && typeof t === "string" && t.trim() !== "") typesSet.add(t);
|
|
659
|
+
});
|
|
660
|
+
} else if (node.type && typeof node.type === "string" && node.type.trim() !== "") {
|
|
584
661
|
typesSet.add(node.type);
|
|
585
662
|
}
|
|
586
663
|
});
|
|
587
664
|
return Array.from(typesSet).sort();
|
|
588
665
|
}, [dbNodes]);
|
|
666
|
+
const availableDatasets = (0, import_react2.useMemo)(() => {
|
|
667
|
+
const datasetsSet = /* @__PURE__ */ new Set();
|
|
668
|
+
(dbNodes || []).forEach((node) => {
|
|
669
|
+
if (node.dataset_name) {
|
|
670
|
+
datasetsSet.add(node.dataset_name);
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
return Array.from(datasetsSet).sort();
|
|
674
|
+
}, [dbNodes]);
|
|
675
|
+
const filteredAutocompleteOptions = (0, import_react2.useMemo)(() => {
|
|
676
|
+
const source = filterCategory === "Dataset" ? availableDatasets : availableTypes;
|
|
677
|
+
if (!filterValue.trim()) return source;
|
|
678
|
+
const search = filterValue.toLowerCase().trim();
|
|
679
|
+
return source.filter((item) => item.toLowerCase().includes(search));
|
|
680
|
+
}, [availableTypes, availableDatasets, filterValue, filterCategory]);
|
|
589
681
|
const filteredAndSorted = (0, import_react2.useMemo)(() => {
|
|
590
682
|
const base = Array.isArray(dbNodes) ? dbNodes : [];
|
|
591
683
|
let pool = base;
|
|
@@ -605,6 +697,8 @@ function XViewSidebar({
|
|
|
605
697
|
return nodeTypes.some((t) => String(t).toLowerCase() === String(filter.value).toLowerCase());
|
|
606
698
|
} else if (filter.type === "Color") {
|
|
607
699
|
return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
|
|
700
|
+
} else if (filter.type === "Dataset") {
|
|
701
|
+
return String(node.dataset_name || "").toLowerCase() === String(filter.value).toLowerCase();
|
|
608
702
|
}
|
|
609
703
|
return true;
|
|
610
704
|
});
|
|
@@ -620,18 +714,21 @@ function XViewSidebar({
|
|
|
620
714
|
inView.sort(byName);
|
|
621
715
|
const ordered = [...notInView, ...inView];
|
|
622
716
|
return ordered.slice(0, 200);
|
|
623
|
-
}, [dbNodes, query, isNodeInView, viewVersion, activeFilters]);
|
|
717
|
+
}, [dbNodes, query, isNodeInView, viewVersion, activeFilters, filterCategory]);
|
|
624
718
|
(0, import_react2.useEffect)(() => {
|
|
625
719
|
const handleClickOutside = (event) => {
|
|
626
720
|
if (filterMenuRef.current && !filterMenuRef.current.contains(event.target)) {
|
|
627
721
|
setIsFilterMenuOpen(false);
|
|
628
722
|
}
|
|
723
|
+
if (typeDropdownRef.current && !typeDropdownRef.current.contains(event.target)) {
|
|
724
|
+
setIsTypeDropdownOpen(false);
|
|
725
|
+
}
|
|
629
726
|
};
|
|
630
|
-
if (isFilterMenuOpen) {
|
|
727
|
+
if (isFilterMenuOpen || isTypeDropdownOpen) {
|
|
631
728
|
document.addEventListener("mousedown", handleClickOutside);
|
|
632
729
|
}
|
|
633
730
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
634
|
-
}, [isFilterMenuOpen]);
|
|
731
|
+
}, [isFilterMenuOpen, isTypeDropdownOpen]);
|
|
635
732
|
(0, import_react2.useEffect)(() => {
|
|
636
733
|
if (!query) setSelectedNodeId(null);
|
|
637
734
|
}, [query]);
|
|
@@ -685,6 +782,35 @@ function XViewSidebar({
|
|
|
685
782
|
const handleRemoveFilter = (index) => {
|
|
686
783
|
setActiveFilters((prev) => prev.filter((_, i) => i !== index));
|
|
687
784
|
};
|
|
785
|
+
const handleTypeKeyDown = (e) => {
|
|
786
|
+
if (!isTypeDropdownOpen) {
|
|
787
|
+
setIsTypeDropdownOpen(true);
|
|
788
|
+
}
|
|
789
|
+
if (e.key === "ArrowDown") {
|
|
790
|
+
e.preventDefault();
|
|
791
|
+
setHighlightedTypeIndex(
|
|
792
|
+
(prev) => prev < filteredAutocompleteOptions.length - 1 ? prev + 1 : prev
|
|
793
|
+
);
|
|
794
|
+
} else if (e.key === "ArrowUp") {
|
|
795
|
+
e.preventDefault();
|
|
796
|
+
setHighlightedTypeIndex((prev) => prev > 0 ? prev - 1 : 0);
|
|
797
|
+
} else if (e.key === "Enter") {
|
|
798
|
+
e.preventDefault();
|
|
799
|
+
if (highlightedTypeIndex >= 0 && filteredAutocompleteOptions[highlightedTypeIndex]) {
|
|
800
|
+
setFilterValue(filteredAutocompleteOptions[highlightedTypeIndex]);
|
|
801
|
+
setIsTypeDropdownOpen(false);
|
|
802
|
+
setHighlightedTypeIndex(-1);
|
|
803
|
+
} else {
|
|
804
|
+
handleAddFilter();
|
|
805
|
+
}
|
|
806
|
+
} else if (e.key === "Escape") {
|
|
807
|
+
e.preventDefault();
|
|
808
|
+
setIsTypeDropdownOpen(false);
|
|
809
|
+
setHighlightedTypeIndex(-1);
|
|
810
|
+
} else if (e.key === "Tab") {
|
|
811
|
+
setIsTypeDropdownOpen(false);
|
|
812
|
+
}
|
|
813
|
+
};
|
|
688
814
|
const ToggleButton = /* @__PURE__ */ import_react2.default.createElement(
|
|
689
815
|
"button",
|
|
690
816
|
{
|
|
@@ -704,7 +830,7 @@ function XViewSidebar({
|
|
|
704
830
|
"div",
|
|
705
831
|
{
|
|
706
832
|
ref: containerRef,
|
|
707
|
-
className: "ui-overlay fixed left-0 top-0 h-
|
|
833
|
+
className: "ui-overlay fixed left-0 top-0 h-[100dvh] w-[min(92vw,320px)] z-40 overflow-hidden",
|
|
708
834
|
onPointerDown: swallow,
|
|
709
835
|
onPointerMove: swallow,
|
|
710
836
|
onPointerUp: swallow,
|
|
@@ -713,7 +839,7 @@ function XViewSidebar({
|
|
|
713
839
|
onContextMenu: swallow,
|
|
714
840
|
onDoubleClick: swallow
|
|
715
841
|
},
|
|
716
|
-
/* @__PURE__ */ import_react2.default.createElement("div", { className: "h-full flex flex-col bg-slate-950/80 backdrop-blur-xl border-r border-white/10 shadow-[0_0_40px_rgba(0,0,0,0.45)]" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative px-4 py-3 border-b border-white/10 flex items-center gap-2" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_10px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "text-sm font-medium text-slate-100" }, "Ferramentas"), /* @__PURE__ */ import_react2.default.createElement(
|
|
842
|
+
/* @__PURE__ */ import_react2.default.createElement("div", { className: "h-full flex flex-col overflow-hidden bg-slate-950/80 backdrop-blur-xl border-r border-white/10 shadow-[0_0_40px_rgba(0,0,0,0.45)]" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative px-4 py-3 border-b border-white/10 flex items-center gap-2" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_10px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "text-sm font-medium text-slate-100" }, "Ferramentas"), /* @__PURE__ */ import_react2.default.createElement(
|
|
717
843
|
"button",
|
|
718
844
|
{
|
|
719
845
|
className: "ml-auto p-2 rounded-md text-slate-400 hover:text-white hover:bg-white/10 transition-colors",
|
|
@@ -770,7 +896,7 @@ function XViewSidebar({
|
|
|
770
896
|
autoComplete: "off"
|
|
771
897
|
}
|
|
772
898
|
)
|
|
773
|
-
), showList && /* @__PURE__ */ import_react2.default.createElement("ul", { className: "custom-scrollbar absolute mt-1 z-10 w-full max-h-[
|
|
899
|
+
), showList && /* @__PURE__ */ import_react2.default.createElement("ul", { className: "custom-scrollbar absolute mt-1 z-10 w-full max-h-[min(448px,50dvh)] overflow-y-auto rounded-lg bg-slate-900/95 border border-white/10 shadow-xl" }, filteredAndSorted.length > 0 ? filteredAndSorted.map((n) => {
|
|
774
900
|
const inView = isNodeInView(n.id);
|
|
775
901
|
const active = selectedNodeId === n.id;
|
|
776
902
|
const typeLabel = Array.isArray(n.type) ? n.type.join(", ") : n.type;
|
|
@@ -804,7 +930,7 @@ function XViewSidebar({
|
|
|
804
930
|
},
|
|
805
931
|
/* @__PURE__ */ import_react2.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_react2.default.createElement("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" })),
|
|
806
932
|
"Filters"
|
|
807
|
-
), isFilterMenuOpen && /* @__PURE__ */ import_react2.default.createElement("div", { className: "absolute right-0 top-full mt-2 w-56 p-3 rounded-lg bg-slate-900 border border-white/10 shadow-xl z-50 flex flex-col gap-3 animate-in fade-in zoom-in-95 duration-100" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Filtro"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "flex bg-slate-800/50 p-1 rounded-md" }, ["Type", "Color"].map((opt) => /* @__PURE__ */ import_react2.default.createElement(
|
|
933
|
+
), isFilterMenuOpen && /* @__PURE__ */ import_react2.default.createElement("div", { className: "absolute right-0 top-full mt-2 w-56 p-3 rounded-lg bg-slate-900 border border-white/10 shadow-xl z-50 flex flex-col gap-3 animate-in fade-in zoom-in-95 duration-100" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Filtro"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "flex bg-slate-800/50 p-1 rounded-md" }, ["Type", "Color", "Dataset"].map((opt) => /* @__PURE__ */ import_react2.default.createElement(
|
|
808
934
|
"button",
|
|
809
935
|
{
|
|
810
936
|
key: opt,
|
|
@@ -815,18 +941,36 @@ function XViewSidebar({
|
|
|
815
941
|
className: `flex-1 text-xs py-1 rounded transition-colors ${filterCategory === opt ? "bg-indigo-600 text-white shadow-sm" : "text-slate-400 hover:text-slate-200"}`
|
|
816
942
|
},
|
|
817
943
|
opt
|
|
818
|
-
)))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), filterCategory === "Type" ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
944
|
+
)))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), filterCategory === "Type" || filterCategory === "Dataset" ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative", ref: typeDropdownRef }, /* @__PURE__ */ import_react2.default.createElement(
|
|
819
945
|
"input",
|
|
820
946
|
{
|
|
821
|
-
list: "typeOptions",
|
|
822
947
|
type: "text",
|
|
823
948
|
value: filterValue,
|
|
824
|
-
onChange: (e) =>
|
|
825
|
-
|
|
949
|
+
onChange: (e) => {
|
|
950
|
+
setFilterValue(e.target.value);
|
|
951
|
+
if (!isTypeDropdownOpen) setIsTypeDropdownOpen(true);
|
|
952
|
+
setHighlightedTypeIndex(-1);
|
|
953
|
+
},
|
|
954
|
+
onFocus: () => setIsTypeDropdownOpen(true),
|
|
955
|
+
onKeyDown: handleTypeKeyDown,
|
|
956
|
+
placeholder: filterCategory === "Type" ? "Ex: Concept" : "Ex: Dataset 1",
|
|
826
957
|
className: "w-full bg-slate-800 p-2 text-xs rounded border border-white/10 focus:outline-none focus:border-indigo-500/50 text-white",
|
|
827
958
|
autoFocus: true
|
|
828
959
|
}
|
|
829
|
-
),
|
|
960
|
+
), isTypeDropdownOpen && filteredAutocompleteOptions.length > 0 && /* @__PURE__ */ import_react2.default.createElement("div", { className: "absolute z-[60] left-0 right-0 mt-1 max-h-48 overflow-y-auto bg-slate-900/95 backdrop-blur-xl border border-white/10 rounded-md shadow-2xl custom-scrollbar" }, filteredAutocompleteOptions.map((t, idx) => /* @__PURE__ */ import_react2.default.createElement(
|
|
961
|
+
"div",
|
|
962
|
+
{
|
|
963
|
+
key: t,
|
|
964
|
+
className: `px-3 py-2 text-xs cursor-pointer transition-colors ${idx === highlightedTypeIndex ? "bg-indigo-600 text-white" : "text-slate-300 hover:bg-white/10"}`,
|
|
965
|
+
onMouseDown: (e) => {
|
|
966
|
+
e.preventDefault();
|
|
967
|
+
setFilterValue(t);
|
|
968
|
+
setIsTypeDropdownOpen(false);
|
|
969
|
+
setHighlightedTypeIndex(-1);
|
|
970
|
+
}
|
|
971
|
+
},
|
|
972
|
+
t
|
|
973
|
+
)))) : /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative flex items-center" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
830
974
|
"div",
|
|
831
975
|
{
|
|
832
976
|
className: "absolute left-2 w-3 h-3 rounded-full border border-white/20 shadow-sm",
|
|
@@ -2625,7 +2769,15 @@ var userActionHandlers = {
|
|
|
2625
2769
|
var _a;
|
|
2626
2770
|
const { graphDataRef, sceneDataRef, stateRef, setters } = context;
|
|
2627
2771
|
if (!graphDataRef.current || !sceneDataRef.current) return;
|
|
2628
|
-
const {
|
|
2772
|
+
const {
|
|
2773
|
+
_baseEmissiveIntensity,
|
|
2774
|
+
_baseScale,
|
|
2775
|
+
labelObject,
|
|
2776
|
+
labelOffset,
|
|
2777
|
+
timelineIntervalBar,
|
|
2778
|
+
timelineEndLabel,
|
|
2779
|
+
...nodeToSave
|
|
2780
|
+
} = updatedNode;
|
|
2629
2781
|
const parentInfo = getParentFileInfoForNode(graphDataRef.current, sceneDataRef.current, nodeToSave.id, context.sceneConfigId, context.ownerId);
|
|
2630
2782
|
if (!parentInfo || !parentInfo.ownerId) {
|
|
2631
2783
|
console.error("N\xE3o foi poss\xEDvel encontrar as informa\xE7\xF5es do arquivo pai (ou ownerId) para o Node a ser atualizado:", nodeToSave.id);
|
|
@@ -2814,18 +2966,27 @@ function createNewCustomProperty(existingProps = []) {
|
|
|
2814
2966
|
};
|
|
2815
2967
|
}
|
|
2816
2968
|
var resolveDescriptionReference = (refString, availableNodes = [], availableAncestries = []) => {
|
|
2817
|
-
const match = refString.match(
|
|
2969
|
+
const match = refString.match(
|
|
2970
|
+
/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/
|
|
2971
|
+
);
|
|
2818
2972
|
if (!match) return null;
|
|
2819
2973
|
const [_, type, itemId, sectionId] = match;
|
|
2820
2974
|
let sourceItem = null;
|
|
2821
2975
|
if (type === "node") {
|
|
2822
2976
|
sourceItem = availableNodes.find((n) => String(n.id) === String(itemId));
|
|
2823
2977
|
} else {
|
|
2824
|
-
sourceItem = availableAncestries.find(
|
|
2978
|
+
sourceItem = availableAncestries.find(
|
|
2979
|
+
(a) => String(a.ancestry_id) === String(itemId)
|
|
2980
|
+
);
|
|
2825
2981
|
}
|
|
2826
2982
|
if (!sourceItem) return null;
|
|
2827
|
-
const sections = parseDescriptionSections(
|
|
2828
|
-
|
|
2983
|
+
const sections = parseDescriptionSections(
|
|
2984
|
+
sourceItem.description,
|
|
2985
|
+
sourceItem.description_sections
|
|
2986
|
+
);
|
|
2987
|
+
const targetSection = sections.find(
|
|
2988
|
+
(s) => String(s.id) === String(sectionId)
|
|
2989
|
+
);
|
|
2829
2990
|
if (!targetSection) return null;
|
|
2830
2991
|
return {
|
|
2831
2992
|
content: targetSection.content,
|
|
@@ -2839,21 +3000,34 @@ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
|
2839
3000
|
let text = rawText;
|
|
2840
3001
|
const allNodes = parentData ? Object.values(parentData).flatMap((f) => f.nodes || []) : [];
|
|
2841
3002
|
const allAncestries = ancestryData || [];
|
|
2842
|
-
text = text.replace(
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
3003
|
+
text = text.replace(
|
|
3004
|
+
/\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g,
|
|
3005
|
+
(match, type, itemId, sectionId) => {
|
|
3006
|
+
const resolved = resolveDescriptionReference(
|
|
3007
|
+
match,
|
|
3008
|
+
allNodes,
|
|
3009
|
+
allAncestries
|
|
3010
|
+
);
|
|
3011
|
+
if (resolved && !resolved.error) {
|
|
3012
|
+
return resolved.content;
|
|
3013
|
+
}
|
|
3014
|
+
return "[Refer\xEAncia indispon\xEDvel]";
|
|
2846
3015
|
}
|
|
2847
|
-
|
|
2848
|
-
});
|
|
3016
|
+
);
|
|
2849
3017
|
text = text.replace(/\*\/\s*\d+(?::[a-zA-Z0-9-]+)?\s*\//g, "");
|
|
2850
|
-
text = text.replace(
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
3018
|
+
text = text.replace(
|
|
3019
|
+
/\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g,
|
|
3020
|
+
(match, nodeId) => {
|
|
3021
|
+
const node = allNodes.find((n) => String(n.id) === String(nodeId));
|
|
3022
|
+
return node ? `@${node.name}` : `@Men\xE7\xE3o`;
|
|
3023
|
+
}
|
|
3024
|
+
);
|
|
3025
|
+
text = text.replace(
|
|
3026
|
+
/\[\[MENTION:image:([^|\]]+)\|?([^\]]*)\]\]/g,
|
|
3027
|
+
(match, url, name) => {
|
|
3028
|
+
return name ? `[Imagem: ${name}]` : `[Imagem]`;
|
|
3029
|
+
}
|
|
3030
|
+
);
|
|
2857
3031
|
text = text.replace(/^#+\s*/gm, "");
|
|
2858
3032
|
text = text.replace(/```[\s\S]*?```/g, "[C\xF3digo]");
|
|
2859
3033
|
text = text.replace(/-\s\[[xX ]\]\s*/g, "\u2022 ");
|
|
@@ -2861,7 +3035,14 @@ function formatDescriptionForTooltip(rawText, parentData, ancestryData) {
|
|
|
2861
3035
|
return text.trim();
|
|
2862
3036
|
}
|
|
2863
3037
|
function generateTooltipHtml(data, parentData, ancestryData) {
|
|
2864
|
-
const ignoredKeys = [
|
|
3038
|
+
const ignoredKeys = [
|
|
3039
|
+
"id",
|
|
3040
|
+
"name",
|
|
3041
|
+
"type",
|
|
3042
|
+
"color",
|
|
3043
|
+
"_baseEmissiveIntensity",
|
|
3044
|
+
"description"
|
|
3045
|
+
];
|
|
2865
3046
|
const customKeys = Object.keys(data).filter((k) => !ignoredKeys.includes(k));
|
|
2866
3047
|
const extras = customKeys.length;
|
|
2867
3048
|
let typeDisplay = "Node";
|
|
@@ -2876,7 +3057,11 @@ function generateTooltipHtml(data, parentData, ancestryData) {
|
|
|
2876
3057
|
<div style="font-weight:600; font-size: 14px; color: #fff;">${typeDisplay}</div>
|
|
2877
3058
|
<div style="margin-bottom: 2px; color: #e2e8f0;">${data.name || ""}</div>`;
|
|
2878
3059
|
if (data.description) {
|
|
2879
|
-
const cleanDesc = formatDescriptionForTooltip(
|
|
3060
|
+
const cleanDesc = formatDescriptionForTooltip(
|
|
3061
|
+
data.description,
|
|
3062
|
+
parentData,
|
|
3063
|
+
ancestryData
|
|
3064
|
+
);
|
|
2880
3065
|
if (cleanDesc) {
|
|
2881
3066
|
html += `<div style="
|
|
2882
3067
|
margin-top: 6px;
|
|
@@ -2914,7 +3099,11 @@ function generateLinkTooltipHtml(data, parentData, ancestryData) {
|
|
|
2914
3099
|
html += `<div style="font-weight:600; font-size: 14px; color: #a5f3fc; margin-bottom: 4px;">${data.name}</div>`;
|
|
2915
3100
|
}
|
|
2916
3101
|
if (hasDescription) {
|
|
2917
|
-
const cleanDesc = formatDescriptionForTooltip(
|
|
3102
|
+
const cleanDesc = formatDescriptionForTooltip(
|
|
3103
|
+
data.description,
|
|
3104
|
+
parentData,
|
|
3105
|
+
ancestryData
|
|
3106
|
+
);
|
|
2918
3107
|
if (cleanDesc) {
|
|
2919
3108
|
html += `<div style="
|
|
2920
3109
|
display: -webkit-box;
|
|
@@ -2996,7 +3185,8 @@ var IGNORED_KEYS = [
|
|
|
2996
3185
|
"isAddingAbstractionNodes",
|
|
2997
3186
|
"status",
|
|
2998
3187
|
"is_quest",
|
|
2999
|
-
"raw_title"
|
|
3188
|
+
"raw_title",
|
|
3189
|
+
"assignee_id"
|
|
3000
3190
|
];
|
|
3001
3191
|
function extractCustomPropsFromNode(node) {
|
|
3002
3192
|
const customPropTypes = node._customPropTypes || {};
|
|
@@ -3006,16 +3196,40 @@ function extractCustomPropsFromNode(node) {
|
|
|
3006
3196
|
if (t === "date") {
|
|
3007
3197
|
if (val && typeof val === "object") {
|
|
3008
3198
|
if ("date_interval" in val) {
|
|
3009
|
-
return {
|
|
3199
|
+
return {
|
|
3200
|
+
id: v4_default(),
|
|
3201
|
+
key,
|
|
3202
|
+
type: "date",
|
|
3203
|
+
value: {
|
|
3204
|
+
type: "Date Interval",
|
|
3205
|
+
start: val.date_interval.start || "",
|
|
3206
|
+
end: val.date_interval.end || ""
|
|
3207
|
+
}
|
|
3208
|
+
};
|
|
3010
3209
|
}
|
|
3011
3210
|
if ("year" in val) {
|
|
3012
|
-
return {
|
|
3211
|
+
return {
|
|
3212
|
+
id: v4_default(),
|
|
3213
|
+
key,
|
|
3214
|
+
type: "date",
|
|
3215
|
+
value: { type: "Ano", value: val.year || "" }
|
|
3216
|
+
};
|
|
3013
3217
|
}
|
|
3014
3218
|
if ("date" in val) {
|
|
3015
|
-
return {
|
|
3219
|
+
return {
|
|
3220
|
+
id: v4_default(),
|
|
3221
|
+
key,
|
|
3222
|
+
type: "date",
|
|
3223
|
+
value: { type: "Data", value: val.date || "" }
|
|
3224
|
+
};
|
|
3016
3225
|
}
|
|
3017
3226
|
}
|
|
3018
|
-
return {
|
|
3227
|
+
return {
|
|
3228
|
+
id: v4_default(),
|
|
3229
|
+
key,
|
|
3230
|
+
type: "date",
|
|
3231
|
+
value: { type: "Data", value: "" }
|
|
3232
|
+
};
|
|
3019
3233
|
}
|
|
3020
3234
|
if (t === "list" || t === "links" || t === "images" || t === "documents") {
|
|
3021
3235
|
const safeList = (val || []).map((item) => ({
|
|
@@ -3025,7 +3239,12 @@ function extractCustomPropsFromNode(node) {
|
|
|
3025
3239
|
}));
|
|
3026
3240
|
return { id: v4_default(), key, type: t, value: safeList };
|
|
3027
3241
|
}
|
|
3028
|
-
return {
|
|
3242
|
+
return {
|
|
3243
|
+
id: v4_default(),
|
|
3244
|
+
key,
|
|
3245
|
+
type: t,
|
|
3246
|
+
value: t === "number" ? Number(val) || 0 : String(val ?? "")
|
|
3247
|
+
};
|
|
3029
3248
|
});
|
|
3030
3249
|
}
|
|
3031
3250
|
function toObjectFromCustomProps(customProps) {
|
|
@@ -3040,7 +3259,12 @@ function toObjectFromCustomProps(customProps) {
|
|
|
3040
3259
|
const { type: uiDateType, ...dateValues } = p.value || {};
|
|
3041
3260
|
if (uiDateType) {
|
|
3042
3261
|
if (uiDateType === "Date Interval") {
|
|
3043
|
-
out[key] = {
|
|
3262
|
+
out[key] = {
|
|
3263
|
+
date_interval: {
|
|
3264
|
+
start: dateValues.start || "",
|
|
3265
|
+
end: dateValues.end || ""
|
|
3266
|
+
}
|
|
3267
|
+
};
|
|
3044
3268
|
} else if (uiDateType === "Ano") {
|
|
3045
3269
|
out[key] = { year: dateValues.value || "" };
|
|
3046
3270
|
} else {
|
|
@@ -3076,10 +3300,20 @@ function createTextSprite(text, fontSize = 64) {
|
|
|
3076
3300
|
context.fillText(effectiveText, canvas.width / 2, canvas.height / 2);
|
|
3077
3301
|
const texture = new THREE2.CanvasTexture(canvas);
|
|
3078
3302
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
3079
|
-
const spriteMaterial = new THREE2.SpriteMaterial({
|
|
3303
|
+
const spriteMaterial = new THREE2.SpriteMaterial({
|
|
3304
|
+
map: texture,
|
|
3305
|
+
sizeAttenuation: true,
|
|
3306
|
+
depthWrite: false,
|
|
3307
|
+
transparent: true,
|
|
3308
|
+
toneMapped: false
|
|
3309
|
+
});
|
|
3080
3310
|
const sprite = new THREE2.Sprite(spriteMaterial);
|
|
3081
3311
|
const scaleFactor = 0.05;
|
|
3082
|
-
sprite.scale.set(
|
|
3312
|
+
sprite.scale.set(
|
|
3313
|
+
canvas.width * scaleFactor,
|
|
3314
|
+
canvas.height * scaleFactor,
|
|
3315
|
+
1
|
|
3316
|
+
);
|
|
3083
3317
|
sprite.layers.set(DEFAULT_LAYER);
|
|
3084
3318
|
return sprite;
|
|
3085
3319
|
}
|
|
@@ -3095,7 +3329,14 @@ function makeGlowTexture() {
|
|
|
3095
3329
|
const canvas = document.createElement("canvas");
|
|
3096
3330
|
canvas.width = canvas.height = size;
|
|
3097
3331
|
const ctx = canvas.getContext("2d");
|
|
3098
|
-
const grd = ctx.createRadialGradient(
|
|
3332
|
+
const grd = ctx.createRadialGradient(
|
|
3333
|
+
size / 2,
|
|
3334
|
+
size / 2,
|
|
3335
|
+
0,
|
|
3336
|
+
size / 2,
|
|
3337
|
+
size / 2,
|
|
3338
|
+
size / 2
|
|
3339
|
+
);
|
|
3099
3340
|
grd.addColorStop(0, "rgba(255,255,255,1)");
|
|
3100
3341
|
grd.addColorStop(0.4, "rgba(255,255,255,0.45)");
|
|
3101
3342
|
grd.addColorStop(1, "rgba(255,255,255,0)");
|
|
@@ -3111,8 +3352,19 @@ function addGlowAura(mesh, hexColor, glowTexture, auraScale) {
|
|
|
3111
3352
|
let midBoost = 1 - Math.abs(L - 0.5) * 2;
|
|
3112
3353
|
midBoost = THREE2.MathUtils.clamp(midBoost, 0, 1);
|
|
3113
3354
|
const auraOpacity = THREE2.MathUtils.lerp(0.25, 0.8, midBoost);
|
|
3114
|
-
const auraColor = new THREE2.Color(hexColor).lerp(
|
|
3115
|
-
|
|
3355
|
+
const auraColor = new THREE2.Color(hexColor).lerp(
|
|
3356
|
+
new THREE2.Color("#ffffff"),
|
|
3357
|
+
0.25
|
|
3358
|
+
);
|
|
3359
|
+
const auraMat = new THREE2.SpriteMaterial({
|
|
3360
|
+
map: glowTexture,
|
|
3361
|
+
color: auraColor,
|
|
3362
|
+
opacity: auraOpacity,
|
|
3363
|
+
blending: THREE2.AdditiveBlending,
|
|
3364
|
+
transparent: true,
|
|
3365
|
+
depthWrite: false,
|
|
3366
|
+
toneMapped: false
|
|
3367
|
+
});
|
|
3116
3368
|
const aura = new THREE2.Sprite(auraMat);
|
|
3117
3369
|
aura.scale.setScalar(auraScale);
|
|
3118
3370
|
aura.name = "aura";
|
|
@@ -3145,7 +3397,17 @@ function calculateNodePositions(nodes) {
|
|
|
3145
3397
|
}
|
|
3146
3398
|
return positions;
|
|
3147
3399
|
}
|
|
3148
|
-
function updateTooltip({
|
|
3400
|
+
function updateTooltip({
|
|
3401
|
+
tooltipEl,
|
|
3402
|
+
hoveredNode,
|
|
3403
|
+
hoveredLink,
|
|
3404
|
+
camera,
|
|
3405
|
+
mountEl,
|
|
3406
|
+
isSceneBusy,
|
|
3407
|
+
parentData,
|
|
3408
|
+
ancestryData
|
|
3409
|
+
}) {
|
|
3410
|
+
var _a, _b;
|
|
3149
3411
|
if (!tooltipEl || !camera || !mountEl) return;
|
|
3150
3412
|
let content = "";
|
|
3151
3413
|
let positionTarget = null;
|
|
@@ -3155,20 +3417,35 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3155
3417
|
currentId = `node_${hoveredNode.userData.id}`;
|
|
3156
3418
|
positionTarget = hoveredNode;
|
|
3157
3419
|
if (tooltipEl.dataset.currentId !== currentId) {
|
|
3158
|
-
content = generateTooltipHtml(
|
|
3420
|
+
content = generateTooltipHtml(
|
|
3421
|
+
hoveredNode.userData,
|
|
3422
|
+
parentData,
|
|
3423
|
+
ancestryData
|
|
3424
|
+
);
|
|
3159
3425
|
}
|
|
3160
3426
|
} else if (hoveredLink && !isSceneBusy) {
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3427
|
+
const linkData = hoveredLink.userData.isAncestryLink ? hoveredLink.userData.relationship || {} : hoveredLink.userData;
|
|
3428
|
+
const hasContent = ((_a = linkData.name) == null ? void 0 : _a.trim()) || ((_b = linkData.description) == null ? void 0 : _b.trim());
|
|
3429
|
+
if (hasContent) {
|
|
3430
|
+
currentId = `link_${hoveredLink.userData.id}`;
|
|
3431
|
+
if (hoveredLink.userData.isCurved) {
|
|
3432
|
+
const positions = hoveredLink.geometry.attributes.position.array;
|
|
3433
|
+
const midIndex = Math.floor(positions.length / 2 / 3) * 3;
|
|
3434
|
+
positionTarget = new THREE2.Vector3(
|
|
3435
|
+
positions[midIndex],
|
|
3436
|
+
positions[midIndex + 1],
|
|
3437
|
+
positions[midIndex + 2]
|
|
3438
|
+
);
|
|
3439
|
+
} else {
|
|
3440
|
+
positionTarget = new THREE2.Vector3().addVectors(
|
|
3441
|
+
hoveredLink.userData.sourceNode.position,
|
|
3442
|
+
hoveredLink.userData.targetNode.position
|
|
3443
|
+
).multiplyScalar(0.5);
|
|
3444
|
+
}
|
|
3445
|
+
isLink = true;
|
|
3446
|
+
if (tooltipEl.dataset.currentId !== currentId) {
|
|
3447
|
+
content = generateLinkTooltipHtml(linkData, parentData, ancestryData);
|
|
3448
|
+
}
|
|
3172
3449
|
}
|
|
3173
3450
|
}
|
|
3174
3451
|
if (positionTarget) {
|
|
@@ -3192,9 +3469,11 @@ function updateTooltip({ tooltipEl, hoveredNode, hoveredLink, camera, mountEl, i
|
|
|
3192
3469
|
const tooltipRect = tooltipEl.getBoundingClientRect();
|
|
3193
3470
|
const offsetX = 20;
|
|
3194
3471
|
const offsetY = 20;
|
|
3195
|
-
if (x + tooltipRect.width + offsetX > clientWidth)
|
|
3472
|
+
if (x + tooltipRect.width + offsetX > clientWidth)
|
|
3473
|
+
x = x - tooltipRect.width - offsetX;
|
|
3196
3474
|
else x = x + offsetX;
|
|
3197
|
-
if (y + tooltipRect.height + offsetY > clientHeight)
|
|
3475
|
+
if (y + tooltipRect.height + offsetY > clientHeight)
|
|
3476
|
+
y = y - tooltipRect.height - offsetY;
|
|
3198
3477
|
else y = y + offsetY;
|
|
3199
3478
|
tooltipEl.style.display = "block";
|
|
3200
3479
|
tooltipEl.style.left = `${x}px`;
|
|
@@ -3228,7 +3507,9 @@ var processDescriptionForSave = (text, existingSections = []) => {
|
|
|
3228
3507
|
const content = parts[i + 2] || "";
|
|
3229
3508
|
let finalUuid = null;
|
|
3230
3509
|
if (suffix) {
|
|
3231
|
-
const existingMatch = existingSections.find(
|
|
3510
|
+
const existingMatch = existingSections.find(
|
|
3511
|
+
(s) => s.id && s.id.includes(suffix)
|
|
3512
|
+
);
|
|
3232
3513
|
if (existingMatch) {
|
|
3233
3514
|
finalUuid = existingMatch.id;
|
|
3234
3515
|
} else {
|
|
@@ -3319,28 +3600,34 @@ var extractFileUrlsFromProperties = (dataObject) => {
|
|
|
3319
3600
|
function useResizablePanel({ initialWidth, minWidth, maxWidth }) {
|
|
3320
3601
|
const [width, setWidth] = (0, import_react3.useState)(initialWidth);
|
|
3321
3602
|
const [isResizing, setIsResizing] = (0, import_react3.useState)(false);
|
|
3322
|
-
const handlePointerDown = (0, import_react3.useCallback)(
|
|
3323
|
-
e
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
const
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3603
|
+
const handlePointerDown = (0, import_react3.useCallback)(
|
|
3604
|
+
(e) => {
|
|
3605
|
+
e.preventDefault();
|
|
3606
|
+
e.stopPropagation();
|
|
3607
|
+
setIsResizing(true);
|
|
3608
|
+
const startX = e.clientX;
|
|
3609
|
+
const startWidth = width;
|
|
3610
|
+
const originalUserSelect = document.body.style.userSelect;
|
|
3611
|
+
document.body.style.userSelect = "none";
|
|
3612
|
+
const handlePointerMove = (moveEvent) => {
|
|
3613
|
+
const deltaX = startX - moveEvent.clientX;
|
|
3614
|
+
const newWidth = Math.min(
|
|
3615
|
+
Math.max(startWidth + deltaX, minWidth),
|
|
3616
|
+
maxWidth
|
|
3617
|
+
);
|
|
3618
|
+
setWidth(newWidth);
|
|
3619
|
+
};
|
|
3620
|
+
const handlePointerUp = () => {
|
|
3621
|
+
setIsResizing(false);
|
|
3622
|
+
document.body.style.userSelect = originalUserSelect;
|
|
3623
|
+
document.removeEventListener("pointermove", handlePointerMove);
|
|
3624
|
+
document.removeEventListener("pointerup", handlePointerUp);
|
|
3625
|
+
};
|
|
3626
|
+
document.addEventListener("pointermove", handlePointerMove);
|
|
3627
|
+
document.addEventListener("pointerup", handlePointerUp);
|
|
3628
|
+
},
|
|
3629
|
+
[width, minWidth, maxWidth]
|
|
3630
|
+
);
|
|
3344
3631
|
return { width, isResizing, handlePointerDown, setWidth };
|
|
3345
3632
|
}
|
|
3346
3633
|
|
|
@@ -3477,9 +3764,9 @@ function CustomPropertyDisplay({
|
|
|
3477
3764
|
};
|
|
3478
3765
|
const handleRemoveListItem = (j) => setTempProp((p) => ({ ...p, value: p.value.filter((_, k) => k !== j) }));
|
|
3479
3766
|
const handleListItemChange = (j, f, v) => setTempProp((p) => {
|
|
3480
|
-
const
|
|
3481
|
-
|
|
3482
|
-
return { ...p, value:
|
|
3767
|
+
const newValue2 = [...p.value];
|
|
3768
|
+
newValue2[j] = { ...newValue2[j], [f]: v };
|
|
3769
|
+
return { ...p, value: newValue2 };
|
|
3483
3770
|
});
|
|
3484
3771
|
const baseInput = "w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-400/60 transition-all duration-150";
|
|
3485
3772
|
const renderEditView = () => {
|
|
@@ -3533,14 +3820,14 @@ function CustomPropertyDisplay({
|
|
|
3533
3820
|
const inputClass = `${baseInput} ${noSpinnerClass}`;
|
|
3534
3821
|
const handleDateTypeChange = (newDateType) => {
|
|
3535
3822
|
var _a3, _b2, _c2;
|
|
3536
|
-
let
|
|
3823
|
+
let newValue2 = { type: newDateType };
|
|
3537
3824
|
if (newDateType === "Date Interval") {
|
|
3538
|
-
|
|
3539
|
-
|
|
3825
|
+
newValue2.start = ((_a3 = tempProp.value) == null ? void 0 : _a3.start) || "";
|
|
3826
|
+
newValue2.end = ((_b2 = tempProp.value) == null ? void 0 : _b2.end) || "";
|
|
3540
3827
|
} else {
|
|
3541
|
-
|
|
3828
|
+
newValue2.value = ((_c2 = tempProp.value) == null ? void 0 : _c2.type) === newDateType ? tempProp.value.value : "";
|
|
3542
3829
|
}
|
|
3543
|
-
handlePropChange("value",
|
|
3830
|
+
handlePropChange("value", newValue2);
|
|
3544
3831
|
};
|
|
3545
3832
|
const handleDateValueChange = (dateField, dateValue) => {
|
|
3546
3833
|
handlePropChange("value", { ...tempProp.value, [dateField]: dateValue });
|
|
@@ -4388,7 +4675,7 @@ ${space}${bullet} `);
|
|
|
4388
4675
|
}
|
|
4389
4676
|
),
|
|
4390
4677
|
/* @__PURE__ */ import_react6.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0 shrink-0" }),
|
|
4391
|
-
/* @__PURE__ */ import_react6.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-center justify-between gap-4 shrink-0" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-sm font-medium text-slate-200" }, title || "Editar Descri\xE7\xE3o")), /* @__PURE__ */ import_react6.default.createElement("button", { onClick: handleClose, 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")),
|
|
4678
|
+
/* @__PURE__ */ import_react6.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-center justify-between gap-4 shrink-0" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-center gap-2 min-w-0" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shrink-0" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-sm font-medium text-slate-200 truncate" }, title || "Editar Descri\xE7\xE3o")), /* @__PURE__ */ import_react6.default.createElement("button", { onClick: handleClose, className: "w-9 h-9 flex-shrink-0 grid place-content-center rounded-lg border border-white/15 bg-transparent hover:bg-white/5 transition-colors text-xl", title: "Fechar" }, "\xD7")),
|
|
4392
4679
|
/* @__PURE__ */ import_react6.default.createElement("div", { className: "px-6 py-3 flex flex-col gap-3 border-b border-white/5 bg-white/5 shrink-0" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "flex items-center gap-2 flex-wrap" }, /* @__PURE__ */ import_react6.default.createElement(
|
|
4393
4680
|
"button",
|
|
4394
4681
|
{
|
|
@@ -5503,7 +5790,7 @@ function AncestryRelationshipPanel({
|
|
|
5503
5790
|
onImageClick: handleImageClickFromText,
|
|
5504
5791
|
onSaveDescription: handleSaveDescriptionInline
|
|
5505
5792
|
}
|
|
5506
|
-
) : /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-cyan-400/0 via-cyan-400/70 to-cyan-400/0" }), /* @__PURE__ */ import_react9.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react9.default.createElement("div",
|
|
5793
|
+
) : /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-cyan-400/0 via-cyan-400/70 to-cyan-400/0" }), /* @__PURE__ */ import_react9.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-cyan-400/80 shadow-[0_0_18px_2px_rgba(45,212,191,0.55)]" }), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes da Rela\xE7\xE3o de Ancestralidade")), /* @__PURE__ */ import_react9.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, "Editar Rela\xE7\xE3o")), /* @__PURE__ */ import_react9.default.createElement("button", { onClick: onClose, className: "w-9 h-9 flex-shrink-0 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_react9.default.createElement("div", { className: "px-6 pb-4 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react9.default.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o da Rela\xE7\xE3o"), /* @__PURE__ */ import_react9.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_react9.default.createElement(
|
|
5507
5794
|
DescriptionDisplay,
|
|
5508
5795
|
{
|
|
5509
5796
|
description,
|
|
@@ -5808,6 +6095,7 @@ function CreateAncestryPanel({
|
|
|
5808
6095
|
} = ancestryMode;
|
|
5809
6096
|
const [isSaving, setIsSaving] = (0, import_react11.useState)(false);
|
|
5810
6097
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react11.useState)(false);
|
|
6098
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react11.useState)(false);
|
|
5811
6099
|
const [showDeleteBranchConfirm, setShowDeleteBranchConfirm] = (0, import_react11.useState)(false);
|
|
5812
6100
|
const handleCopyLink = (e) => {
|
|
5813
6101
|
e.stopPropagation();
|
|
@@ -5875,12 +6163,14 @@ function CreateAncestryPanel({
|
|
|
5875
6163
|
};
|
|
5876
6164
|
const handleSelectAncestryParent = (nodeId, isAbstraction = false) => {
|
|
5877
6165
|
setAncestryMode((prev) => isAbstraction ? { ...prev, selectedAbstractionParentId: nodeId } : { ...prev, selectedParentId: nodeId });
|
|
6166
|
+
setHasUnsavedChanges(true);
|
|
5878
6167
|
};
|
|
5879
6168
|
const handleToggleAddMode = (isAbstraction = false) => {
|
|
5880
6169
|
if (isAbstraction && !ancestryMode.isAddingAbstractionNodes) {
|
|
5881
6170
|
setTargetRenderNodeId(null);
|
|
5882
6171
|
}
|
|
5883
6172
|
setAncestryMode((prev) => isAbstraction ? { ...prev, isAddingAbstractionNodes: !prev.isAddingAbstractionNodes } : { ...prev, isAddingNodes: !prev.isAddingNodes });
|
|
6173
|
+
setHasUnsavedChanges(true);
|
|
5884
6174
|
};
|
|
5885
6175
|
const handleRemoveNode = (0, import_react11.useCallback)((pathToRemove, isAbstraction = false) => {
|
|
5886
6176
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) return;
|
|
@@ -5898,6 +6188,7 @@ function CreateAncestryPanel({
|
|
|
5898
6188
|
const indexToRemove = pathToRemove[pathToRemove.length - 1];
|
|
5899
6189
|
if (currentParent.children && currentParent.children.length > indexToRemove) {
|
|
5900
6190
|
currentParent.children.splice(indexToRemove, 1);
|
|
6191
|
+
setHasUnsavedChanges(true);
|
|
5901
6192
|
}
|
|
5902
6193
|
return { ...prev, [treeKey]: newTree };
|
|
5903
6194
|
});
|
|
@@ -5956,6 +6247,7 @@ function CreateAncestryPanel({
|
|
|
5956
6247
|
updateGlobalTree(rootTreeClone);
|
|
5957
6248
|
}
|
|
5958
6249
|
setAncestryMode((prev) => ({ ...prev, [treeKey]: rootTreeClone }));
|
|
6250
|
+
setHasUnsavedChanges(true);
|
|
5959
6251
|
} else {
|
|
5960
6252
|
alert("N\xE3o \xE9 poss\xEDvel mover um node para dentro de seus pr\xF3prios descendentes.");
|
|
5961
6253
|
}
|
|
@@ -6028,6 +6320,7 @@ function CreateAncestryPanel({
|
|
|
6028
6320
|
const handleAddProp = () => {
|
|
6029
6321
|
const newProp = createNewCustomProperty(customProps);
|
|
6030
6322
|
setCustomProps((p) => [...p, newProp]);
|
|
6323
|
+
setHasUnsavedChanges(true);
|
|
6031
6324
|
setTimeout(() => {
|
|
6032
6325
|
var _a;
|
|
6033
6326
|
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -6036,11 +6329,13 @@ function CreateAncestryPanel({
|
|
|
6036
6329
|
const handleRemoveProp = (i) => {
|
|
6037
6330
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
6038
6331
|
setCustomProps(newProps);
|
|
6332
|
+
setHasUnsavedChanges(true);
|
|
6039
6333
|
};
|
|
6040
6334
|
const handleUpdateProp = (index, updatedProp) => {
|
|
6041
6335
|
const newProps = [...customProps];
|
|
6042
6336
|
newProps[index] = updatedProp;
|
|
6043
6337
|
setCustomProps(newProps);
|
|
6338
|
+
setHasUnsavedChanges(true);
|
|
6044
6339
|
};
|
|
6045
6340
|
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
6046
6341
|
(0, import_react11.useEffect)(() => {
|
|
@@ -6150,6 +6445,7 @@ function CreateAncestryPanel({
|
|
|
6150
6445
|
updateGlobalTree(rootTreeClone);
|
|
6151
6446
|
setBranchStack([...branchStack]);
|
|
6152
6447
|
setIsPickerOpen(false);
|
|
6448
|
+
setHasUnsavedChanges(true);
|
|
6153
6449
|
try {
|
|
6154
6450
|
setIsSaving(true);
|
|
6155
6451
|
const rootProps = extractCustomPropsFromNode(ancestryMode);
|
|
@@ -6163,6 +6459,7 @@ function CreateAncestryPanel({
|
|
|
6163
6459
|
rootExtras
|
|
6164
6460
|
);
|
|
6165
6461
|
setLastSavedSnapshot(takeSnapshot(rootTreeClone, ancestryName, description, processedSections, [], isPrivate, ancestryMode.abstraction_tree));
|
|
6462
|
+
setHasUnsavedChanges(false);
|
|
6166
6463
|
if (onRenderFullAncestry) {
|
|
6167
6464
|
const fullTreePayload = {
|
|
6168
6465
|
ancestry_id: ancestryMode.currentAncestryId || "temp_root",
|
|
@@ -6205,6 +6502,7 @@ function CreateAncestryPanel({
|
|
|
6205
6502
|
if (branchIndex !== -1) {
|
|
6206
6503
|
foundParentPath.node.parallel_branches.splice(branchIndex, 1);
|
|
6207
6504
|
updateGlobalTree(rootTreeClone);
|
|
6505
|
+
setHasUnsavedChanges(true);
|
|
6208
6506
|
try {
|
|
6209
6507
|
setIsSaving(true);
|
|
6210
6508
|
const currentRootProps = extractCustomPropsFromNode(ancestryMode);
|
|
@@ -6226,6 +6524,7 @@ function CreateAncestryPanel({
|
|
|
6226
6524
|
isPrivate,
|
|
6227
6525
|
ancestryMode.abstraction_tree
|
|
6228
6526
|
));
|
|
6527
|
+
setHasUnsavedChanges(false);
|
|
6229
6528
|
if (onClearAncestryVisuals) {
|
|
6230
6529
|
onClearAncestryVisuals(currentStep.branchId);
|
|
6231
6530
|
}
|
|
@@ -6258,6 +6557,7 @@ function CreateAncestryPanel({
|
|
|
6258
6557
|
if (branchIndex !== -1) {
|
|
6259
6558
|
foundParentPath.node.parallel_branches.splice(branchIndex, 1);
|
|
6260
6559
|
updateGlobalTree(rootTreeClone);
|
|
6560
|
+
setHasUnsavedChanges(true);
|
|
6261
6561
|
try {
|
|
6262
6562
|
setIsSaving(true);
|
|
6263
6563
|
const currentRootProps = extractCustomPropsFromNode(ancestryMode);
|
|
@@ -6279,6 +6579,7 @@ function CreateAncestryPanel({
|
|
|
6279
6579
|
isPrivate,
|
|
6280
6580
|
ancestryMode.abstraction_tree
|
|
6281
6581
|
));
|
|
6582
|
+
setHasUnsavedChanges(false);
|
|
6282
6583
|
if (onClearAncestryVisuals) {
|
|
6283
6584
|
onClearAncestryVisuals(currentStep.branchId);
|
|
6284
6585
|
}
|
|
@@ -6540,6 +6841,7 @@ function CreateAncestryPanel({
|
|
|
6540
6841
|
}
|
|
6541
6842
|
setBranchStack(parentStack);
|
|
6542
6843
|
setTargetScrollSectionId(targetFocusId);
|
|
6844
|
+
setHasUnsavedChanges(true);
|
|
6543
6845
|
if (onRenderFullAncestry) {
|
|
6544
6846
|
const parentStack2 = currentStack;
|
|
6545
6847
|
const rotation = parentStack2.reduce((acc, step) => {
|
|
@@ -6601,7 +6903,6 @@ function CreateAncestryPanel({
|
|
|
6601
6903
|
direction,
|
|
6602
6904
|
tree: {
|
|
6603
6905
|
node: nodeData,
|
|
6604
|
-
node_id: nodeId,
|
|
6605
6906
|
children: [],
|
|
6606
6907
|
relationship: {}
|
|
6607
6908
|
}
|
|
@@ -6623,6 +6924,7 @@ function CreateAncestryPanel({
|
|
|
6623
6924
|
savedMaxIndex: parentIndexToSave,
|
|
6624
6925
|
entryDirection: direction
|
|
6625
6926
|
}]);
|
|
6927
|
+
setHasUnsavedChanges(true);
|
|
6626
6928
|
if (branch && branch.tree && onRenderFullAncestry) {
|
|
6627
6929
|
const branchAncestryObj = {
|
|
6628
6930
|
ancestry_id: branch.id,
|
|
@@ -6673,6 +6975,10 @@ function CreateAncestryPanel({
|
|
|
6673
6975
|
const currentInputName = overrides.ancestryName !== void 0 ? overrides.ancestryName : ancestryName;
|
|
6674
6976
|
const currentInputDesc = overrides.description !== void 0 ? overrides.description : description;
|
|
6675
6977
|
const currentInputSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
6978
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
6979
|
+
onClose();
|
|
6980
|
+
return;
|
|
6981
|
+
}
|
|
6676
6982
|
if (!currentInputName.trim()) {
|
|
6677
6983
|
alert("O nome n\xE3o pode estar vazio.");
|
|
6678
6984
|
return;
|
|
@@ -6680,11 +6986,7 @@ function CreateAncestryPanel({
|
|
|
6680
6986
|
setIsSaving(true);
|
|
6681
6987
|
const processedSections = processDescriptionForSave(currentInputDesc, currentInputSections);
|
|
6682
6988
|
setExistingSections(processedSections);
|
|
6683
|
-
const updatedRootTree =
|
|
6684
|
-
ancestryMode.tree,
|
|
6685
|
-
currentInputDesc,
|
|
6686
|
-
processedSections
|
|
6687
|
-
);
|
|
6989
|
+
const updatedRootTree = JSON.parse(JSON.stringify(ancestryMode.tree));
|
|
6688
6990
|
const extrasObj = {
|
|
6689
6991
|
...toObjectFromCustomProps(customProps.filter((p) => !p.isEditing)),
|
|
6690
6992
|
is_private: isPrivate
|
|
@@ -6726,6 +7028,7 @@ function CreateAncestryPanel({
|
|
|
6726
7028
|
isPrivate,
|
|
6727
7029
|
ancestryMode.abstraction_tree
|
|
6728
7030
|
));
|
|
7031
|
+
setHasUnsavedChanges(false);
|
|
6729
7032
|
if (onRenderFullAncestry) {
|
|
6730
7033
|
const rotation = branchStack.reduce((acc, step) => {
|
|
6731
7034
|
return acc + (step.entryDirection === "left" ? -Math.PI / 2 : Math.PI / 2);
|
|
@@ -6777,6 +7080,7 @@ function CreateAncestryPanel({
|
|
|
6777
7080
|
updatedRootTree,
|
|
6778
7081
|
extrasObj
|
|
6779
7082
|
);
|
|
7083
|
+
setHasUnsavedChanges(false);
|
|
6780
7084
|
setLastSavedSnapshot(takeSnapshot(
|
|
6781
7085
|
updatedRootTree,
|
|
6782
7086
|
currentInputName,
|
|
@@ -6799,6 +7103,7 @@ function CreateAncestryPanel({
|
|
|
6799
7103
|
const newTreeString = JSON.stringify(newRootTree);
|
|
6800
7104
|
if (currentTreeString !== newTreeString) {
|
|
6801
7105
|
updateGlobalTree(newRootTree);
|
|
7106
|
+
setHasUnsavedChanges(true);
|
|
6802
7107
|
}
|
|
6803
7108
|
}, [description, existingSections]);
|
|
6804
7109
|
const handleTriggerFullRender = () => {
|
|
@@ -6821,6 +7126,7 @@ function CreateAncestryPanel({
|
|
|
6821
7126
|
};
|
|
6822
7127
|
const handleSaveDescriptionInline = (newDesc) => {
|
|
6823
7128
|
setDescription(newDesc);
|
|
7129
|
+
setHasUnsavedChanges(true);
|
|
6824
7130
|
handleLocalSave(true, { description: newDesc });
|
|
6825
7131
|
};
|
|
6826
7132
|
const swallow = (e) => e.stopPropagation();
|
|
@@ -6950,7 +7256,11 @@ function CreateAncestryPanel({
|
|
|
6950
7256
|
{
|
|
6951
7257
|
type: "text",
|
|
6952
7258
|
value: ancestryName,
|
|
6953
|
-
onChange: (e) =>
|
|
7259
|
+
onChange: (e) => {
|
|
7260
|
+
setAncestryName(e.target.value);
|
|
7261
|
+
setHasUnsavedChanges(true);
|
|
7262
|
+
},
|
|
7263
|
+
readOnly: isContextLinked,
|
|
6954
7264
|
placeholder: "Nome da Ancestralidade",
|
|
6955
7265
|
className: "text-xl sm:text-2xl font-semibold tracking-tight bg-transparent border-none p-0 focus:ring-2 focus:ring-indigo-500 rounded-md -ml-1.5 px-1.5 w-full outline-none transition-all focus:bg-slate-800/70"
|
|
6956
7266
|
}
|
|
@@ -7438,7 +7748,7 @@ function ColorPicker({ color, onChange, disabled }) {
|
|
|
7438
7748
|
style: { backgroundColor: preset },
|
|
7439
7749
|
title: preset
|
|
7440
7750
|
},
|
|
7441
|
-
color.toLowerCase() === preset.toLowerCase() && /* @__PURE__ */ import_react13.default.createElement(import_fi11.FiCheck, { className: `drop-shadow-md ${["#ffffff", "#4df5cb", "#84cc16", "#f59e0b"].includes(preset) ? "text-black" : "text-white"}`, size: 12 })
|
|
7751
|
+
(color || "").toLowerCase() === (preset || "").toLowerCase() && /* @__PURE__ */ import_react13.default.createElement(import_fi11.FiCheck, { className: `drop-shadow-md ${["#ffffff", "#4df5cb", "#84cc16", "#f59e0b"].includes(preset) ? "text-black" : "text-white"}`, size: 12 })
|
|
7442
7752
|
)))), /* @__PURE__ */ import_react13.default.createElement("style", null, `
|
|
7443
7753
|
.custom-react-colorful .react-colorful {
|
|
7444
7754
|
width: 100%;
|
|
@@ -7530,13 +7840,23 @@ function InSceneCreationForm({
|
|
|
7530
7840
|
}, [hasImages, useImageAsTexture, onImageChange]);
|
|
7531
7841
|
(0, import_react14.useEffect)(() => {
|
|
7532
7842
|
let result = [];
|
|
7843
|
+
const validExistingTypes = existingTypes.filter((t) => t && typeof t === "string" && t.trim() !== "");
|
|
7533
7844
|
if (typeInput.trim() === "") {
|
|
7534
|
-
result =
|
|
7845
|
+
result = validExistingTypes.filter((t) => !types.includes(t));
|
|
7535
7846
|
} else {
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7847
|
+
console.log("InSceneCreationForm: Filtrando tipos com input:", typeInput);
|
|
7848
|
+
try {
|
|
7849
|
+
const lowercasedInput = typeInput.toLowerCase();
|
|
7850
|
+
result = validExistingTypes.filter((t) => {
|
|
7851
|
+
if (!t) {
|
|
7852
|
+
console.warn("InSceneCreationForm: Tipo encontrado como undefined/null durante filtragem");
|
|
7853
|
+
return false;
|
|
7854
|
+
}
|
|
7855
|
+
return t.toLowerCase().includes(lowercasedInput) && !types.includes(t);
|
|
7856
|
+
});
|
|
7857
|
+
} catch (err) {
|
|
7858
|
+
console.error("InSceneCreationForm: Erro ao filtrar tipos:", err, "typeInput:", typeInput);
|
|
7859
|
+
}
|
|
7540
7860
|
}
|
|
7541
7861
|
if (sourceTypes) {
|
|
7542
7862
|
const priorityTypes = Array.isArray(sourceTypes) ? sourceTypes : [sourceTypes];
|
|
@@ -7599,9 +7919,9 @@ function InSceneCreationForm({
|
|
|
7599
7919
|
};
|
|
7600
7920
|
const handleToggleImageMode = () => {
|
|
7601
7921
|
var _a2, _b;
|
|
7602
|
-
const
|
|
7603
|
-
setUseImageAsTexture(
|
|
7604
|
-
if (
|
|
7922
|
+
const newValue2 = !useImageAsTexture;
|
|
7923
|
+
setUseImageAsTexture(newValue2);
|
|
7924
|
+
if (newValue2) {
|
|
7605
7925
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
7606
7926
|
if (firstImageProp && ((_b = (_a2 = firstImageProp.value) == null ? void 0 : _a2[0]) == null ? void 0 : _b.value)) {
|
|
7607
7927
|
const url = firstImageProp.value[0].value;
|
|
@@ -7899,9 +8219,9 @@ function InSceneVersionForm({
|
|
|
7899
8219
|
};
|
|
7900
8220
|
const handleToggleImageMode = () => {
|
|
7901
8221
|
var _a, _b;
|
|
7902
|
-
const
|
|
7903
|
-
setUseImageAsTexture(
|
|
7904
|
-
if (
|
|
8222
|
+
const newValue2 = !useImageAsTexture;
|
|
8223
|
+
setUseImageAsTexture(newValue2);
|
|
8224
|
+
if (newValue2) {
|
|
7905
8225
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
7906
8226
|
if (firstImageProp && ((_b = (_a = firstImageProp.value) == null ? void 0 : _a[0]) == null ? void 0 : _b.value)) {
|
|
7907
8227
|
const url = firstImageProp.value[0].value;
|
|
@@ -8077,10 +8397,13 @@ function InSceneQuestForm({
|
|
|
8077
8397
|
onSizeChange,
|
|
8078
8398
|
viewName = "Projeto",
|
|
8079
8399
|
// NOVA PROP
|
|
8080
|
-
questCounter = 1
|
|
8400
|
+
questCounter = 1,
|
|
8081
8401
|
// NOVA PROP
|
|
8402
|
+
viewMembers = []
|
|
8082
8403
|
}) {
|
|
8404
|
+
var _a, _b;
|
|
8083
8405
|
const [name, setName] = (0, import_react16.useState)("");
|
|
8406
|
+
const [assigneeId, setAssigneeId] = (0, import_react16.useState)("");
|
|
8084
8407
|
const [types, setTypes] = (0, import_react16.useState)(["quest"]);
|
|
8085
8408
|
const [typeInput, setTypeInput] = (0, import_react16.useState)("");
|
|
8086
8409
|
const [status, setStatus] = (0, import_react16.useState)("Backlog");
|
|
@@ -8088,6 +8411,8 @@ function InSceneQuestForm({
|
|
|
8088
8411
|
const [intensity, setIntensity] = (0, import_react16.useState)(0);
|
|
8089
8412
|
const [description, setDescription] = (0, import_react16.useState)("");
|
|
8090
8413
|
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react16.useState)(false);
|
|
8414
|
+
const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = (0, import_react16.useState)(false);
|
|
8415
|
+
const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react16.useState)("");
|
|
8091
8416
|
const [customProps, setCustomProps] = (0, import_react16.useState)([]);
|
|
8092
8417
|
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react16.useState)(false);
|
|
8093
8418
|
const propsEndRef = (0, import_react16.useRef)(null);
|
|
@@ -8096,8 +8421,8 @@ function InSceneQuestForm({
|
|
|
8096
8421
|
const newProp = createNewCustomProperty(customProps);
|
|
8097
8422
|
setCustomProps([...customProps, newProp]);
|
|
8098
8423
|
setTimeout(() => {
|
|
8099
|
-
var
|
|
8100
|
-
(
|
|
8424
|
+
var _a2;
|
|
8425
|
+
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
8101
8426
|
}, 100);
|
|
8102
8427
|
};
|
|
8103
8428
|
const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
|
|
@@ -8143,6 +8468,7 @@ function InSceneQuestForm({
|
|
|
8143
8468
|
type: types,
|
|
8144
8469
|
color: QUEST_STATUS_COLORS2[status],
|
|
8145
8470
|
status,
|
|
8471
|
+
assignee_id: assigneeId || null,
|
|
8146
8472
|
size,
|
|
8147
8473
|
intensity,
|
|
8148
8474
|
description: description.trim(),
|
|
@@ -8214,7 +8540,59 @@ function InSceneQuestForm({
|
|
|
8214
8540
|
},
|
|
8215
8541
|
/* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
|
|
8216
8542
|
s
|
|
8217
|
-
)))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "
|
|
8543
|
+
)))))), /* @__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" }, "Assignee (Respons\xE1vel)"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
8544
|
+
"button",
|
|
8545
|
+
{
|
|
8546
|
+
type: "button",
|
|
8547
|
+
onClick: () => setIsAssigneeDropdownOpen(!isAssigneeDropdownOpen),
|
|
8548
|
+
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"
|
|
8549
|
+
},
|
|
8550
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiUser, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-slate-200 font-medium" }, ((_a = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _a.name) || ((_b = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _b.email) || "Nenhum")),
|
|
8551
|
+
/* @__PURE__ */ import_react16.default.createElement(import_fi14.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isAssigneeDropdownOpen ? "rotate-180" : ""}` })
|
|
8552
|
+
), isAssigneeDropdownOpen && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => {
|
|
8553
|
+
setIsAssigneeDropdownOpen(false);
|
|
8554
|
+
setAssigneeSearchQuery("");
|
|
8555
|
+
} }), /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiSearch, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ import_react16.default.createElement(
|
|
8556
|
+
"input",
|
|
8557
|
+
{
|
|
8558
|
+
type: "text",
|
|
8559
|
+
autoFocus: true,
|
|
8560
|
+
placeholder: "Buscar membro...",
|
|
8561
|
+
value: assigneeSearchQuery,
|
|
8562
|
+
onChange: (e) => setAssigneeSearchQuery(e.target.value),
|
|
8563
|
+
className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
|
|
8564
|
+
onClick: (e) => e.stopPropagation()
|
|
8565
|
+
}
|
|
8566
|
+
)), /* @__PURE__ */ import_react16.default.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ import_react16.default.createElement(
|
|
8567
|
+
"li",
|
|
8568
|
+
{
|
|
8569
|
+
onClick: () => {
|
|
8570
|
+
setAssigneeId("");
|
|
8571
|
+
setIsAssigneeDropdownOpen(false);
|
|
8572
|
+
setAssigneeSearchQuery("");
|
|
8573
|
+
},
|
|
8574
|
+
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!assigneeId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
8575
|
+
},
|
|
8576
|
+
"Nenhum"
|
|
8577
|
+
), viewMembers.filter((member) => {
|
|
8578
|
+
const search = assigneeSearchQuery.toLowerCase();
|
|
8579
|
+
return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
|
|
8580
|
+
}).map((member) => /* @__PURE__ */ import_react16.default.createElement(
|
|
8581
|
+
"li",
|
|
8582
|
+
{
|
|
8583
|
+
key: member.id,
|
|
8584
|
+
onClick: () => {
|
|
8585
|
+
setAssigneeId(member.id);
|
|
8586
|
+
setIsAssigneeDropdownOpen(false);
|
|
8587
|
+
setAssigneeSearchQuery("");
|
|
8588
|
+
},
|
|
8589
|
+
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${assigneeId === member.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
8590
|
+
},
|
|
8591
|
+
member.name || member.email || member.id
|
|
8592
|
+
)), viewMembers.filter((member) => {
|
|
8593
|
+
const search = assigneeSearchQuery.toLowerCase();
|
|
8594
|
+
return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
|
|
8595
|
+
}).length === 0 && assigneeSearchQuery && /* @__PURE__ */ import_react16.default.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado")))))), /* @__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(
|
|
8218
8596
|
"input",
|
|
8219
8597
|
{
|
|
8220
8598
|
type: "text",
|
|
@@ -8321,6 +8699,7 @@ function NodeDetailsPanel({
|
|
|
8321
8699
|
return !!(node == null ? void 0 : node.useImageAsTexture);
|
|
8322
8700
|
});
|
|
8323
8701
|
const [selectedImageUrl, setSelectedImageUrl] = (0, import_react17.useState)((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
8702
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react17.useState)(false);
|
|
8324
8703
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
8325
8704
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
8326
8705
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -8358,6 +8737,7 @@ function NodeDetailsPanel({
|
|
|
8358
8737
|
else if ((node == null ? void 0 : node.useImageAsTexture) === "false") setUseImageAsTexture(false);
|
|
8359
8738
|
else setUseImageAsTexture(!!(node == null ? void 0 : node.useImageAsTexture));
|
|
8360
8739
|
setSelectedImageUrl((node == null ? void 0 : node.textureImageUrl) ?? null);
|
|
8740
|
+
setHasUnsavedChanges(false);
|
|
8361
8741
|
}
|
|
8362
8742
|
}, [node]);
|
|
8363
8743
|
const hasImages = customProps.some((p) => p.type === "images" && Array.isArray(p.value) && p.value.length > 0 && p.value.some((img) => img.value));
|
|
@@ -8368,15 +8748,22 @@ function NodeDetailsPanel({
|
|
|
8368
8748
|
}
|
|
8369
8749
|
}, [hasImages, useImageAsTexture]);
|
|
8370
8750
|
(0, import_react17.useEffect)(() => {
|
|
8751
|
+
const validExistingTypes = existingTypes.filter((t) => t && typeof t === "string" && t.trim() !== "");
|
|
8371
8752
|
if (typeInput.trim() === "") {
|
|
8372
|
-
setFilteredTypes(
|
|
8753
|
+
setFilteredTypes(validExistingTypes.filter((t) => !types.includes(t)));
|
|
8373
8754
|
} else {
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8755
|
+
console.log("NodeDetailsPanel: Filtrando tipos com input:", typeInput);
|
|
8756
|
+
try {
|
|
8757
|
+
const lowercasedInput = typeInput.toLowerCase();
|
|
8758
|
+
setFilteredTypes(
|
|
8759
|
+
validExistingTypes.filter((t) => {
|
|
8760
|
+
if (!t) return false;
|
|
8761
|
+
return t.toLowerCase().includes(lowercasedInput) && !types.includes(t);
|
|
8762
|
+
})
|
|
8763
|
+
);
|
|
8764
|
+
} catch (err) {
|
|
8765
|
+
console.error("NodeDetailsPanel: Erro ao filtrar tipos:", err, "typeInput:", typeInput);
|
|
8766
|
+
}
|
|
8380
8767
|
}
|
|
8381
8768
|
}, [typeInput, existingTypes, types]);
|
|
8382
8769
|
const handleIntensityChangeLocal = (e) => {
|
|
@@ -8384,6 +8771,7 @@ function NodeDetailsPanel({
|
|
|
8384
8771
|
setIntensity(val);
|
|
8385
8772
|
onIntensityChange == null ? void 0 : onIntensityChange(node.id, val);
|
|
8386
8773
|
onDataUpdate == null ? void 0 : onDataUpdate({ ...node, intensity: val });
|
|
8774
|
+
setHasUnsavedChanges(true);
|
|
8387
8775
|
};
|
|
8388
8776
|
const handleCopyLink = () => {
|
|
8389
8777
|
if (!(node == null ? void 0 : node.id)) return;
|
|
@@ -8401,14 +8789,17 @@ function NodeDetailsPanel({
|
|
|
8401
8789
|
const v = e.target.value;
|
|
8402
8790
|
setName(v);
|
|
8403
8791
|
onNameChange == null ? void 0 : onNameChange(node.id, v);
|
|
8792
|
+
setHasUnsavedChanges(true);
|
|
8404
8793
|
};
|
|
8405
8794
|
const handleColorChange = (val) => {
|
|
8406
8795
|
setColor(val);
|
|
8407
8796
|
onColorChange == null ? void 0 : onColorChange(node.id, val);
|
|
8797
|
+
setHasUnsavedChanges(true);
|
|
8408
8798
|
};
|
|
8409
8799
|
const handleSizeChange = (newSize) => {
|
|
8410
8800
|
setSize(newSize);
|
|
8411
8801
|
onSizeChange == null ? void 0 : onSizeChange(node.id, newSize);
|
|
8802
|
+
setHasUnsavedChanges(true);
|
|
8412
8803
|
};
|
|
8413
8804
|
const handleAddType = (newType) => {
|
|
8414
8805
|
const trimmed = newType.trim();
|
|
@@ -8416,10 +8807,12 @@ function NodeDetailsPanel({
|
|
|
8416
8807
|
setTypes([...types, trimmed]);
|
|
8417
8808
|
setTypeInput("");
|
|
8418
8809
|
setShowTypeSuggestions(false);
|
|
8810
|
+
setHasUnsavedChanges(true);
|
|
8419
8811
|
}
|
|
8420
8812
|
};
|
|
8421
8813
|
const handleRemoveType = (indexToRemove) => {
|
|
8422
8814
|
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
8815
|
+
setHasUnsavedChanges(true);
|
|
8423
8816
|
};
|
|
8424
8817
|
const handleTypeInputKeyDown = (e) => {
|
|
8425
8818
|
if (e.key === "Enter") {
|
|
@@ -8432,6 +8825,7 @@ function NodeDetailsPanel({
|
|
|
8432
8825
|
const handleAddProp = () => {
|
|
8433
8826
|
const newProp = createNewCustomProperty(customProps);
|
|
8434
8827
|
setCustomProps((p) => [...p, newProp]);
|
|
8828
|
+
setHasUnsavedChanges(true);
|
|
8435
8829
|
setTimeout(() => {
|
|
8436
8830
|
var _a;
|
|
8437
8831
|
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -8440,19 +8834,21 @@ function NodeDetailsPanel({
|
|
|
8440
8834
|
const handleRemoveProp = (i) => {
|
|
8441
8835
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
8442
8836
|
setCustomProps(newProps);
|
|
8837
|
+
setHasUnsavedChanges(true);
|
|
8443
8838
|
triggerAutoSave({ customProps: newProps });
|
|
8444
8839
|
};
|
|
8445
8840
|
const handleUpdateProp = (index, updatedProp) => {
|
|
8446
8841
|
const newProps = [...customProps];
|
|
8447
8842
|
newProps[index] = updatedProp;
|
|
8448
8843
|
setCustomProps(newProps);
|
|
8844
|
+
setHasUnsavedChanges(true);
|
|
8449
8845
|
if (!updatedProp.isEditing) {
|
|
8450
8846
|
triggerAutoSave({ customProps: newProps });
|
|
8451
8847
|
}
|
|
8452
8848
|
};
|
|
8453
8849
|
const handleToggleImageMode = () => {
|
|
8454
|
-
const newValue = !useImageAsTexture;
|
|
8455
8850
|
setUseImageAsTexture(newValue);
|
|
8851
|
+
setHasUnsavedChanges(true);
|
|
8456
8852
|
let activeUrl = null;
|
|
8457
8853
|
if (newValue) {
|
|
8458
8854
|
const firstImageProp = customProps.find((p) => p.type === "images");
|
|
@@ -8474,6 +8870,7 @@ function NodeDetailsPanel({
|
|
|
8474
8870
|
};
|
|
8475
8871
|
const handleSelectTexture = (url) => {
|
|
8476
8872
|
setSelectedImageUrl(url);
|
|
8873
|
+
setHasUnsavedChanges(true);
|
|
8477
8874
|
onImageChange == null ? void 0 : onImageChange(true, url, color);
|
|
8478
8875
|
onDataUpdate == null ? void 0 : onDataUpdate({
|
|
8479
8876
|
...node,
|
|
@@ -8484,6 +8881,7 @@ function NodeDetailsPanel({
|
|
|
8484
8881
|
};
|
|
8485
8882
|
const handleSaveDescriptionInline = (newDescription) => {
|
|
8486
8883
|
setDescription(newDescription);
|
|
8884
|
+
setHasUnsavedChanges(true);
|
|
8487
8885
|
onDataUpdate({ ...node, description: newDescription });
|
|
8488
8886
|
triggerAutoSave({ description: newDescription });
|
|
8489
8887
|
};
|
|
@@ -8494,6 +8892,10 @@ function NodeDetailsPanel({
|
|
|
8494
8892
|
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
8495
8893
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
8496
8894
|
const currentIntensity = overrides.intensity !== void 0 ? overrides.intensity : intensity;
|
|
8895
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
8896
|
+
onClose();
|
|
8897
|
+
return;
|
|
8898
|
+
}
|
|
8497
8899
|
if (!currentName.trim() || currentTypes.length === 0) {
|
|
8498
8900
|
alert("O campo 'Nome' e pelo menos um 'Tipo' s\xE3o obrigat\xF3rios.");
|
|
8499
8901
|
return;
|
|
@@ -8518,6 +8920,7 @@ function NodeDetailsPanel({
|
|
|
8518
8920
|
};
|
|
8519
8921
|
await onSave(dataToSave, keepOpen);
|
|
8520
8922
|
onDataUpdate(dataToSave);
|
|
8923
|
+
setHasUnsavedChanges(false);
|
|
8521
8924
|
if (!keepOpen) {
|
|
8522
8925
|
onClose();
|
|
8523
8926
|
}
|
|
@@ -8584,7 +8987,7 @@ function NodeDetailsPanel({
|
|
|
8584
8987
|
onImageClick: handleImageClickFromText,
|
|
8585
8988
|
onSaveDescription: handleSaveDescriptionInline
|
|
8586
8989
|
}
|
|
8587
|
-
) : /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react17.default.createElement("div",
|
|
8990
|
+
) : /* @__PURE__ */ import_react17.default.createElement(import_react17.default.Fragment, null, /* @__PURE__ */ import_react17.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "min-w-0" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react17.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react17.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ import_react17.default.createElement(
|
|
8588
8991
|
"button",
|
|
8589
8992
|
{
|
|
8590
8993
|
onClick: handleCopyLink,
|
|
@@ -8592,7 +8995,7 @@ function NodeDetailsPanel({
|
|
|
8592
8995
|
title: isLinkCopied ? "Link Copiado!" : "Copiar link para este Node"
|
|
8593
8996
|
},
|
|
8594
8997
|
isLinkCopied ? /* @__PURE__ */ import_react17.default.createElement(import_fi15.FiCheck, { size: 12 }) : /* @__PURE__ */ import_react17.default.createElement(import_fi15.FiLink, { size: 12 })
|
|
8595
|
-
)), /* @__PURE__ */ import_react17.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react17.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_react17.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ import_react17.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_react17.default.createElement("span", { key: index, className: "flex items-center gap-1 bg-indigo-500/30 text-indigo-100 px-1.5 py-0.5 rounded-md text-xs font-medium border border-indigo-500/20" }, t, canEdit && /* @__PURE__ */ import_react17.default.createElement(
|
|
8998
|
+
)), /* @__PURE__ */ import_react17.default.createElement("h2", { className: "text-xl sm:text-2xl font-semibold tracking-tight" }, name || (node == null ? void 0 : node.name))), /* @__PURE__ */ import_react17.default.createElement("button", { onClick: handleCancel, disabled: isSaving, className: "w-9 h-9 flex-shrink-0 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_react17.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 max-h-[68vh] custom-scrollbar" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react17.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos"), /* @__PURE__ */ import_react17.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_react17.default.createElement("span", { key: index, className: "flex items-center gap-1 bg-indigo-500/30 text-indigo-100 px-1.5 py-0.5 rounded-md text-xs font-medium border border-indigo-500/20" }, t, canEdit && /* @__PURE__ */ import_react17.default.createElement(
|
|
8596
8999
|
"button",
|
|
8597
9000
|
{
|
|
8598
9001
|
type: "button",
|
|
@@ -8754,6 +9157,7 @@ function NodeDetailsPanel({
|
|
|
8754
9157
|
initialValue: description,
|
|
8755
9158
|
onSave: (newDescription) => {
|
|
8756
9159
|
setDescription(newDescription);
|
|
9160
|
+
setHasUnsavedChanges(true);
|
|
8757
9161
|
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
8758
9162
|
triggerAutoSave({ description: newDescription });
|
|
8759
9163
|
},
|
|
@@ -8790,7 +9194,8 @@ function QuestDetailsPanel({
|
|
|
8790
9194
|
onMentionClick,
|
|
8791
9195
|
onUploadFile,
|
|
8792
9196
|
userRole,
|
|
8793
|
-
currentDatasetName
|
|
9197
|
+
currentDatasetName,
|
|
9198
|
+
viewMembers = []
|
|
8794
9199
|
}) {
|
|
8795
9200
|
var _a;
|
|
8796
9201
|
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) || "";
|
|
@@ -8802,9 +9207,12 @@ function QuestDetailsPanel({
|
|
|
8802
9207
|
const [typeInput, setTypeInput] = (0, import_react18.useState)("");
|
|
8803
9208
|
const [status, setStatus] = (0, import_react18.useState)((node == null ? void 0 : node.status) ?? "Backlog");
|
|
8804
9209
|
const [size, setSize] = (0, import_react18.useState)((node == null ? void 0 : node.size) ?? "medium");
|
|
9210
|
+
const [assigneeId, setAssigneeId] = (0, import_react18.useState)((node == null ? void 0 : node.assignee_id) || "");
|
|
8805
9211
|
const [description, setDescription] = (0, import_react18.useState)((node == null ? void 0 : node.description) ?? "");
|
|
8806
9212
|
const [intensity, setIntensity] = (0, import_react18.useState)((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8807
9213
|
const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react18.useState)(false);
|
|
9214
|
+
const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = (0, import_react18.useState)(false);
|
|
9215
|
+
const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react18.useState)("");
|
|
8808
9216
|
const [customProps, setCustomProps] = (0, import_react18.useState)(() => extractCustomPropsFromNode(node || {}));
|
|
8809
9217
|
const [showTypeSuggestions, setShowTypeSuggestions] = (0, import_react18.useState)(false);
|
|
8810
9218
|
const [filteredTypes, setFilteredTypes] = (0, import_react18.useState)([]);
|
|
@@ -8813,6 +9221,7 @@ function QuestDetailsPanel({
|
|
|
8813
9221
|
const [existingSections, setExistingSections] = (0, import_react18.useState)((node == null ? void 0 : node.description_sections) || []);
|
|
8814
9222
|
const [isSaving, setIsSaving] = (0, import_react18.useState)(false);
|
|
8815
9223
|
const [isLinkCopied, setIsLinkCopied] = (0, import_react18.useState)(false);
|
|
9224
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react18.useState)(false);
|
|
8816
9225
|
const maxPanelW = typeof window !== "undefined" ? window.innerWidth * 0.92 : 1200;
|
|
8817
9226
|
const { width: panelWidth, isResizing, handlePointerDown: handleResize, setWidth } = useResizablePanel({
|
|
8818
9227
|
initialWidth: isReadMode ? 700 : 440,
|
|
@@ -8840,22 +9249,34 @@ function QuestDetailsPanel({
|
|
|
8840
9249
|
setTypes((node == null ? void 0 : node.type) ? Array.isArray(node.type) ? node.type : [node.type] : ["quest"]);
|
|
8841
9250
|
setStatus((node == null ? void 0 : node.status) ?? "Backlog");
|
|
8842
9251
|
setSize((node == null ? void 0 : node.size) ?? "medium");
|
|
9252
|
+
setAssigneeId((node == null ? void 0 : node.assignee_id) || "");
|
|
8843
9253
|
setDescription((node == null ? void 0 : node.description) ?? "");
|
|
8844
9254
|
setIntensity((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
|
|
8845
9255
|
setExistingSections((node == null ? void 0 : node.description_sections) || []);
|
|
8846
9256
|
setCustomProps(extractCustomPropsFromNode(node || {}));
|
|
9257
|
+
setHasUnsavedChanges(false);
|
|
8847
9258
|
}
|
|
8848
9259
|
}, [node]);
|
|
8849
9260
|
(0, import_react18.useEffect)(() => {
|
|
9261
|
+
const validExistingTypes = existingTypes.filter((t) => t && typeof t === "string" && t.trim() !== "");
|
|
8850
9262
|
if (typeInput.trim() === "") {
|
|
8851
|
-
setFilteredTypes(
|
|
9263
|
+
setFilteredTypes(validExistingTypes.filter((t) => !types.includes(t)));
|
|
8852
9264
|
} else {
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
9265
|
+
console.log("QuestDetailsPanel: Filtrando tipos com input:", typeInput);
|
|
9266
|
+
try {
|
|
9267
|
+
const lowercasedInput = typeInput.toLowerCase();
|
|
9268
|
+
setFilteredTypes(
|
|
9269
|
+
validExistingTypes.filter((t) => {
|
|
9270
|
+
if (!t) {
|
|
9271
|
+
console.warn("QuestDetailsPanel: Tipo encontrado como undefined/null durante filtragem");
|
|
9272
|
+
return false;
|
|
9273
|
+
}
|
|
9274
|
+
return t.toLowerCase().includes(lowercasedInput) && !types.includes(t);
|
|
9275
|
+
})
|
|
9276
|
+
);
|
|
9277
|
+
} catch (err) {
|
|
9278
|
+
console.error("QuestDetailsPanel: Erro ao filtrar tipos:", err, "typeInput:", typeInput);
|
|
9279
|
+
}
|
|
8859
9280
|
}
|
|
8860
9281
|
}, [typeInput, existingTypes, types]);
|
|
8861
9282
|
const handleCopyLink = () => {
|
|
@@ -8875,16 +9296,19 @@ function QuestDetailsPanel({
|
|
|
8875
9296
|
setRawTitle(val);
|
|
8876
9297
|
const newStandardName = questPrefix ? `${questPrefix} - \xBB ${val || "Sem t\xEDtulo"}` : val;
|
|
8877
9298
|
onNameChange == null ? void 0 : onNameChange(node.id, newStandardName, val);
|
|
9299
|
+
setHasUnsavedChanges(true);
|
|
8878
9300
|
};
|
|
8879
9301
|
const handleSizeChange = (newSize) => {
|
|
8880
9302
|
setSize(newSize);
|
|
8881
9303
|
onSizeChange == null ? void 0 : onSizeChange(node.id, newSize);
|
|
9304
|
+
setHasUnsavedChanges(true);
|
|
8882
9305
|
};
|
|
8883
9306
|
const handleStatusChange = (newStatus) => {
|
|
8884
9307
|
setStatus(newStatus);
|
|
8885
9308
|
const newColor = QUEST_STATUS_COLORS3[newStatus];
|
|
8886
9309
|
onColorChange == null ? void 0 : onColorChange(node.id, newColor);
|
|
8887
9310
|
onDataUpdate == null ? void 0 : onDataUpdate({ ...node, status: newStatus, color: newColor });
|
|
9311
|
+
setHasUnsavedChanges(true);
|
|
8888
9312
|
};
|
|
8889
9313
|
const handleAddType = (newType) => {
|
|
8890
9314
|
const trimmed = newType.trim();
|
|
@@ -8892,11 +9316,13 @@ function QuestDetailsPanel({
|
|
|
8892
9316
|
setTypes([...types, trimmed]);
|
|
8893
9317
|
setTypeInput("");
|
|
8894
9318
|
setShowTypeSuggestions(false);
|
|
9319
|
+
setHasUnsavedChanges(true);
|
|
8895
9320
|
}
|
|
8896
9321
|
};
|
|
8897
9322
|
const handleRemoveType = (indexToRemove) => {
|
|
8898
9323
|
if (types[indexToRemove] === "quest") return;
|
|
8899
9324
|
setTypes(types.filter((_, index) => index !== indexToRemove));
|
|
9325
|
+
setHasUnsavedChanges(true);
|
|
8900
9326
|
};
|
|
8901
9327
|
const handleTypeInputKeyDown = (e) => {
|
|
8902
9328
|
if (e.key === "Enter") {
|
|
@@ -8909,6 +9335,7 @@ function QuestDetailsPanel({
|
|
|
8909
9335
|
const handleAddProp = () => {
|
|
8910
9336
|
const newProp = createNewCustomProperty(customProps);
|
|
8911
9337
|
setCustomProps((p) => [...p, newProp]);
|
|
9338
|
+
setHasUnsavedChanges(true);
|
|
8912
9339
|
setTimeout(() => {
|
|
8913
9340
|
var _a2;
|
|
8914
9341
|
(_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -8917,18 +9344,21 @@ function QuestDetailsPanel({
|
|
|
8917
9344
|
const handleRemoveProp = (i) => {
|
|
8918
9345
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
8919
9346
|
setCustomProps(newProps);
|
|
9347
|
+
setHasUnsavedChanges(true);
|
|
8920
9348
|
triggerAutoSave({ customProps: newProps });
|
|
8921
9349
|
};
|
|
8922
9350
|
const handleUpdateProp = (index, updatedProp) => {
|
|
8923
9351
|
const newProps = [...customProps];
|
|
8924
9352
|
newProps[index] = updatedProp;
|
|
8925
9353
|
setCustomProps(newProps);
|
|
9354
|
+
setHasUnsavedChanges(true);
|
|
8926
9355
|
if (!updatedProp.isEditing) {
|
|
8927
9356
|
triggerAutoSave({ customProps: newProps });
|
|
8928
9357
|
}
|
|
8929
9358
|
};
|
|
8930
9359
|
const handleSaveDescriptionInline = (newDescription) => {
|
|
8931
9360
|
setDescription(newDescription);
|
|
9361
|
+
setHasUnsavedChanges(true);
|
|
8932
9362
|
onDataUpdate({ ...node, description: newDescription });
|
|
8933
9363
|
triggerAutoSave({ description: newDescription });
|
|
8934
9364
|
};
|
|
@@ -8936,10 +9366,15 @@ function QuestDetailsPanel({
|
|
|
8936
9366
|
const currentRawTitle = overrides.rawTitle !== void 0 ? overrides.rawTitle : rawTitle;
|
|
8937
9367
|
const currentStandardName = questPrefix ? `${questPrefix} - \xBB ${currentRawTitle || "Sem t\xEDtulo"}` : currentRawTitle;
|
|
8938
9368
|
const currentTypes = overrides.types !== void 0 ? overrides.types : types;
|
|
9369
|
+
const currentAssigneeId = overrides.assigneeId !== void 0 ? overrides.assigneeId : assigneeId;
|
|
8939
9370
|
const currentDescription = overrides.description !== void 0 ? overrides.description : description;
|
|
8940
9371
|
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
8941
9372
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
8942
9373
|
const currentStatus = overrides.status !== void 0 ? overrides.status : status;
|
|
9374
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
9375
|
+
onClose();
|
|
9376
|
+
return;
|
|
9377
|
+
}
|
|
8943
9378
|
if (!currentRawTitle.trim() || currentTypes.length === 0) {
|
|
8944
9379
|
alert("O campo 'T\xEDtulo' e pelo menos um 'Tipo' s\xE3o obrigat\xF3rios.");
|
|
8945
9380
|
return;
|
|
@@ -8957,6 +9392,7 @@ function QuestDetailsPanel({
|
|
|
8957
9392
|
type: currentTypes,
|
|
8958
9393
|
color: QUEST_STATUS_COLORS3[currentStatus],
|
|
8959
9394
|
status: currentStatus,
|
|
9395
|
+
assignee_id: currentAssigneeId || null,
|
|
8960
9396
|
size,
|
|
8961
9397
|
description: currentDescription,
|
|
8962
9398
|
description_sections: processedSections,
|
|
@@ -8969,6 +9405,7 @@ function QuestDetailsPanel({
|
|
|
8969
9405
|
};
|
|
8970
9406
|
await onSave(dataToSave, keepOpen);
|
|
8971
9407
|
onDataUpdate(dataToSave);
|
|
9408
|
+
setHasUnsavedChanges(false);
|
|
8972
9409
|
if (!keepOpen) {
|
|
8973
9410
|
onClose();
|
|
8974
9411
|
}
|
|
@@ -8988,6 +9425,8 @@ function QuestDetailsPanel({
|
|
|
8988
9425
|
onClose();
|
|
8989
9426
|
};
|
|
8990
9427
|
const currentUsedTypes = customProps.map((p) => p.type).filter((t) => UNIQUE_PROP_TYPES.includes(t));
|
|
9428
|
+
const assigneeMember = viewMembers.find((m) => m.id === assigneeId);
|
|
9429
|
+
const isAssigneeUndefined = assigneeId && !assigneeMember;
|
|
8991
9430
|
return /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement(
|
|
8992
9431
|
"div",
|
|
8993
9432
|
{
|
|
@@ -9026,7 +9465,7 @@ function QuestDetailsPanel({
|
|
|
9026
9465
|
onImageClick: handleImageClickFromText,
|
|
9027
9466
|
onSaveDescription: handleSaveDescriptionInline
|
|
9028
9467
|
}
|
|
9029
|
-
) : /* @__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",
|
|
9468
|
+
) : /* @__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", { className: "min-w-0" }, /* @__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 flex-shrink-0 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(
|
|
9030
9469
|
"input",
|
|
9031
9470
|
{
|
|
9032
9471
|
type: "text",
|
|
@@ -9057,7 +9496,71 @@ function QuestDetailsPanel({
|
|
|
9057
9496
|
},
|
|
9058
9497
|
/* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
|
|
9059
9498
|
s
|
|
9060
|
-
)))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "
|
|
9499
|
+
)))))), /* @__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" }, "Assignee (Respons\xE1vel)"), canEdit ? /* @__PURE__ */ import_react18.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react18.default.createElement(
|
|
9500
|
+
"button",
|
|
9501
|
+
{
|
|
9502
|
+
type: "button",
|
|
9503
|
+
onClick: () => setIsAssigneeDropdownOpen(!isAssigneeDropdownOpen),
|
|
9504
|
+
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"
|
|
9505
|
+
},
|
|
9506
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiUser, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-slate-200 font-medium" }, isAssigneeUndefined ? "Undefined" : (assigneeMember == null ? void 0 : assigneeMember.name) || (assigneeMember == null ? void 0 : assigneeMember.email) || "Nenhum")),
|
|
9507
|
+
/* @__PURE__ */ import_react18.default.createElement(import_fi16.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isAssigneeDropdownOpen ? "rotate-180" : ""}` })
|
|
9508
|
+
), isAssigneeDropdownOpen && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => {
|
|
9509
|
+
setIsAssigneeDropdownOpen(false);
|
|
9510
|
+
setAssigneeSearchQuery("");
|
|
9511
|
+
} }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiSearch, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ import_react18.default.createElement(
|
|
9512
|
+
"input",
|
|
9513
|
+
{
|
|
9514
|
+
type: "text",
|
|
9515
|
+
autoFocus: true,
|
|
9516
|
+
placeholder: "Buscar membro...",
|
|
9517
|
+
value: assigneeSearchQuery,
|
|
9518
|
+
onChange: (e) => setAssigneeSearchQuery(e.target.value),
|
|
9519
|
+
className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
|
|
9520
|
+
onClick: (e) => e.stopPropagation()
|
|
9521
|
+
}
|
|
9522
|
+
)), /* @__PURE__ */ import_react18.default.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ import_react18.default.createElement(
|
|
9523
|
+
"li",
|
|
9524
|
+
{
|
|
9525
|
+
onClick: () => {
|
|
9526
|
+
setAssigneeId("");
|
|
9527
|
+
setHasUnsavedChanges(true);
|
|
9528
|
+
setIsAssigneeDropdownOpen(false);
|
|
9529
|
+
setAssigneeSearchQuery("");
|
|
9530
|
+
},
|
|
9531
|
+
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!assigneeId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
9532
|
+
},
|
|
9533
|
+
"Nenhum"
|
|
9534
|
+
), isAssigneeUndefined && /* @__PURE__ */ import_react18.default.createElement(
|
|
9535
|
+
"li",
|
|
9536
|
+
{
|
|
9537
|
+
onClick: () => {
|
|
9538
|
+
setIsAssigneeDropdownOpen(false);
|
|
9539
|
+
setAssigneeSearchQuery("");
|
|
9540
|
+
},
|
|
9541
|
+
className: "px-3 py-2.5 text-sm cursor-pointer bg-red-500/10 text-red-300 flex items-center gap-2"
|
|
9542
|
+
},
|
|
9543
|
+
"Undefined (Removido)"
|
|
9544
|
+
), viewMembers.filter((member) => {
|
|
9545
|
+
const search = assigneeSearchQuery.toLowerCase();
|
|
9546
|
+
return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
|
|
9547
|
+
}).map((member) => /* @__PURE__ */ import_react18.default.createElement(
|
|
9548
|
+
"li",
|
|
9549
|
+
{
|
|
9550
|
+
key: member.id,
|
|
9551
|
+
onClick: () => {
|
|
9552
|
+
setAssigneeId(member.id);
|
|
9553
|
+
setHasUnsavedChanges(true);
|
|
9554
|
+
setIsAssigneeDropdownOpen(false);
|
|
9555
|
+
setAssigneeSearchQuery("");
|
|
9556
|
+
},
|
|
9557
|
+
className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${assigneeId === member.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
|
|
9558
|
+
},
|
|
9559
|
+
member.name || member.email || member.id
|
|
9560
|
+
)), viewMembers.filter((member) => {
|
|
9561
|
+
const search = assigneeSearchQuery.toLowerCase();
|
|
9562
|
+
return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
|
|
9563
|
+
}).length === 0 && assigneeSearchQuery && /* @__PURE__ */ import_react18.default.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado"))))) : /* @__PURE__ */ import_react18.default.createElement("div", { className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 text-slate-400 flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiUser, { className: "opacity-50", size: 14 }), assigneeId ? assigneeMember ? assigneeMember.name || assigneeMember.email : "Undefined" : "Nenhum")), /* @__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(
|
|
9061
9564
|
"input",
|
|
9062
9565
|
{
|
|
9063
9566
|
type: "text",
|
|
@@ -9200,9 +9703,12 @@ function RelationshipDetailsPanel({
|
|
|
9200
9703
|
const [description, setDescription] = (0, import_react20.useState)((link == null ? void 0 : link.description) ?? "");
|
|
9201
9704
|
const [customProps, setCustomProps] = (0, import_react20.useState)(() => extractCustomPropsFromNode(link || {}));
|
|
9202
9705
|
const [existingSections, setExistingSections] = (0, import_react20.useState)((link == null ? void 0 : link.description_sections) || []);
|
|
9706
|
+
const [sourceLabel, setSourceLabel] = (0, import_react20.useState)((link == null ? void 0 : link.source_label) ?? "");
|
|
9707
|
+
const [targetLabel, setTargetLabel] = (0, import_react20.useState)((link == null ? void 0 : link.target_label) ?? "");
|
|
9203
9708
|
const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react20.useState)(false);
|
|
9204
9709
|
const [isSaving, setIsSaving] = (0, import_react20.useState)(false);
|
|
9205
9710
|
const [isReadMode, setIsReadMode] = (0, import_react20.useState)(false);
|
|
9711
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react20.useState)(false);
|
|
9206
9712
|
const propsEndRef = (0, import_react20.useRef)(null);
|
|
9207
9713
|
const canEdit = (0, import_react20.useMemo)(() => {
|
|
9208
9714
|
const ability = defineAbilityFor(userRole);
|
|
@@ -9213,12 +9719,16 @@ function RelationshipDetailsPanel({
|
|
|
9213
9719
|
setDescription((link == null ? void 0 : link.description) ?? "");
|
|
9214
9720
|
setExistingSections((link == null ? void 0 : link.description_sections) || []);
|
|
9215
9721
|
setCustomProps(extractCustomPropsFromNode(link || {}));
|
|
9722
|
+
setSourceLabel((link == null ? void 0 : link.source_label) ?? "");
|
|
9723
|
+
setTargetLabel((link == null ? void 0 : link.target_label) ?? "");
|
|
9724
|
+
setHasUnsavedChanges(false);
|
|
9216
9725
|
}, [link]);
|
|
9217
9726
|
const swallow = (e) => e.stopPropagation();
|
|
9218
9727
|
const handleAddProp = () => {
|
|
9219
9728
|
if (!canEdit) return;
|
|
9220
9729
|
const newProp = createNewCustomProperty(customProps);
|
|
9221
9730
|
setCustomProps((p) => [...p, newProp]);
|
|
9731
|
+
setHasUnsavedChanges(true);
|
|
9222
9732
|
setTimeout(() => {
|
|
9223
9733
|
var _a;
|
|
9224
9734
|
(_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
@@ -9230,6 +9740,12 @@ function RelationshipDetailsPanel({
|
|
|
9230
9740
|
const currentCustomProps = overrides.customProps !== void 0 ? overrides.customProps : customProps;
|
|
9231
9741
|
const currentExistingSections = overrides.existingSections !== void 0 ? overrides.existingSections : existingSections;
|
|
9232
9742
|
const currentName = overrides.name !== void 0 ? overrides.name : name;
|
|
9743
|
+
const currentSourceLabel = overrides.sourceLabel !== void 0 ? overrides.sourceLabel : sourceLabel;
|
|
9744
|
+
const currentTargetLabel = overrides.targetLabel !== void 0 ? overrides.targetLabel : targetLabel;
|
|
9745
|
+
if (!keepOpen && !hasUnsavedChanges) {
|
|
9746
|
+
onClose();
|
|
9747
|
+
return;
|
|
9748
|
+
}
|
|
9233
9749
|
setIsSaving(true);
|
|
9234
9750
|
try {
|
|
9235
9751
|
const extrasObj = toObjectFromCustomProps(currentCustomProps.filter((p) => !p.isEditing));
|
|
@@ -9245,8 +9761,11 @@ function RelationshipDetailsPanel({
|
|
|
9245
9761
|
isCurved: link.isCurved,
|
|
9246
9762
|
curveOffset: link.curveOffset
|
|
9247
9763
|
};
|
|
9764
|
+
if (currentSourceLabel.trim()) dataToSave.source_label = currentSourceLabel.trim();
|
|
9765
|
+
if (currentTargetLabel.trim()) dataToSave.target_label = currentTargetLabel.trim();
|
|
9248
9766
|
await onSave(dataToSave, keepOpen);
|
|
9249
9767
|
onDataUpdate(dataToSave);
|
|
9768
|
+
setHasUnsavedChanges(false);
|
|
9250
9769
|
if (!keepOpen) {
|
|
9251
9770
|
onClose();
|
|
9252
9771
|
}
|
|
@@ -9260,18 +9779,21 @@ function RelationshipDetailsPanel({
|
|
|
9260
9779
|
const handleSaveDescriptionInline = (newDescription) => {
|
|
9261
9780
|
if (!canEdit) return;
|
|
9262
9781
|
setDescription(newDescription);
|
|
9782
|
+
setHasUnsavedChanges(true);
|
|
9263
9783
|
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
9264
9784
|
triggerAutoSave({ description: newDescription });
|
|
9265
9785
|
};
|
|
9266
9786
|
const handleRemoveProp = (i) => {
|
|
9267
9787
|
const newProps = customProps.filter((_, idx) => idx !== i);
|
|
9268
9788
|
setCustomProps(newProps);
|
|
9789
|
+
setHasUnsavedChanges(true);
|
|
9269
9790
|
triggerAutoSave({ customProps: newProps });
|
|
9270
9791
|
};
|
|
9271
9792
|
const handleUpdateProp = (index, updatedProp) => {
|
|
9272
9793
|
const newProps = [...customProps];
|
|
9273
9794
|
newProps[index] = updatedProp;
|
|
9274
9795
|
setCustomProps(newProps);
|
|
9796
|
+
setHasUnsavedChanges(true);
|
|
9275
9797
|
if (!updatedProp.isEditing) {
|
|
9276
9798
|
triggerAutoSave({ customProps: newProps });
|
|
9277
9799
|
}
|
|
@@ -9319,19 +9841,52 @@ function RelationshipDetailsPanel({
|
|
|
9319
9841
|
onImageClick: handleImageClickFromText,
|
|
9320
9842
|
onSaveDescription: handleSaveDescriptionInline
|
|
9321
9843
|
}
|
|
9322
|
-
) : /* @__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",
|
|
9844
|
+
) : /* @__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", { className: "min-w-0" }, /* @__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 flex-shrink-0 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(
|
|
9323
9845
|
"input",
|
|
9324
9846
|
{
|
|
9325
9847
|
type: "text",
|
|
9326
9848
|
value: name,
|
|
9327
|
-
onChange: (e) =>
|
|
9849
|
+
onChange: (e) => {
|
|
9850
|
+
setName(e.target.value);
|
|
9851
|
+
setHasUnsavedChanges(true);
|
|
9852
|
+
},
|
|
9328
9853
|
placeholder: "Ex: Controla, Pertence a, Fornece...",
|
|
9329
9854
|
disabled: !canEdit,
|
|
9330
9855
|
className: `w-full bg-slate-800/70 p-2 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-400/60
|
|
9331
9856
|
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
9332
9857
|
`
|
|
9333
9858
|
}
|
|
9334
|
-
)), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1.
|
|
9859
|
+
)), /* @__PURE__ */ import_react20.default.createElement("div", { className: "rounded-xl border border-white/8 bg-slate-800/30 p-3 space-y-3" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react20.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-violet-400 flex-shrink-0" }, /* @__PURE__ */ import_react20.default.createElement("path", { d: "M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z" }), /* @__PURE__ */ import_react20.default.createElement("line", { x1: "7", y1: "7", x2: "7.01", y2: "7" })), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-xs font-medium text-violet-300/80 uppercase tracking-wider" }, "Labels de Agrupamento")), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-[11px] text-slate-400 leading-relaxed" }, "Labels agrupam conex\xF5es no menu de Conex\xF5es. Cada lado da conex\xE3o pode ter sua pr\xF3pria label."), /* @__PURE__ */ import_react20.default.createElement("div", { className: "grid grid-cols-2 gap-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-[11px] text-slate-400" }, "Label do Source"), /* @__PURE__ */ import_react20.default.createElement(
|
|
9860
|
+
"input",
|
|
9861
|
+
{
|
|
9862
|
+
type: "text",
|
|
9863
|
+
value: sourceLabel,
|
|
9864
|
+
onChange: (e) => {
|
|
9865
|
+
setSourceLabel(e.target.value);
|
|
9866
|
+
setHasUnsavedChanges(true);
|
|
9867
|
+
},
|
|
9868
|
+
placeholder: "Ex: Conceitos",
|
|
9869
|
+
disabled: !canEdit,
|
|
9870
|
+
className: `w-full bg-slate-900/60 p-2 text-xs rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-violet-400/60 placeholder:text-slate-600
|
|
9871
|
+
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
9872
|
+
`
|
|
9873
|
+
}
|
|
9874
|
+
)), /* @__PURE__ */ import_react20.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react20.default.createElement("label", { className: "text-[11px] text-slate-400" }, "Label do Target"), /* @__PURE__ */ import_react20.default.createElement(
|
|
9875
|
+
"input",
|
|
9876
|
+
{
|
|
9877
|
+
type: "text",
|
|
9878
|
+
value: targetLabel,
|
|
9879
|
+
onChange: (e) => {
|
|
9880
|
+
setTargetLabel(e.target.value);
|
|
9881
|
+
setHasUnsavedChanges(true);
|
|
9882
|
+
},
|
|
9883
|
+
placeholder: "Ex: Refer\xEAncias",
|
|
9884
|
+
disabled: !canEdit,
|
|
9885
|
+
className: `w-full bg-slate-900/60 p-2 text-xs rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-violet-400/60 placeholder:text-slate-600
|
|
9886
|
+
${!canEdit ? "opacity-50 cursor-not-allowed" : ""}
|
|
9887
|
+
`
|
|
9888
|
+
}
|
|
9889
|
+
)))), /* @__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(
|
|
9335
9890
|
DescriptionDisplay,
|
|
9336
9891
|
{
|
|
9337
9892
|
description,
|
|
@@ -9401,6 +9956,7 @@ function RelationshipDetailsPanel({
|
|
|
9401
9956
|
onSave: (newDescription) => {
|
|
9402
9957
|
if (!canEdit) return;
|
|
9403
9958
|
setDescription(newDescription);
|
|
9959
|
+
setHasUnsavedChanges(true);
|
|
9404
9960
|
onDataUpdate((prev) => ({ ...prev, description: newDescription }));
|
|
9405
9961
|
triggerAutoSave({ description: newDescription });
|
|
9406
9962
|
},
|
|
@@ -9848,7 +10404,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
9848
10404
|
onMentionClick,
|
|
9849
10405
|
onImageClick: handleImageClickFromText
|
|
9850
10406
|
}
|
|
9851
|
-
) : /* @__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",
|
|
10407
|
+
) : /* @__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", { className: "min-w-0" }, /* @__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 flex-shrink-0 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(
|
|
9852
10408
|
"button",
|
|
9853
10409
|
{
|
|
9854
10410
|
onClick: () => setIsReadMode(true),
|
|
@@ -10487,7 +11043,8 @@ function XViewScene({
|
|
|
10487
11043
|
save_ancestry_board_action,
|
|
10488
11044
|
upload_file_action,
|
|
10489
11045
|
delete_file_action,
|
|
10490
|
-
check_user_permission
|
|
11046
|
+
check_user_permission,
|
|
11047
|
+
get_view_members
|
|
10491
11048
|
}) {
|
|
10492
11049
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
10493
11050
|
const { data: session, status } = (0, import_react27.useSession)();
|
|
@@ -10520,6 +11077,13 @@ function XViewScene({
|
|
|
10520
11077
|
} else {
|
|
10521
11078
|
setPermissionStatus("denied");
|
|
10522
11079
|
setIsLoading(false);
|
|
11080
|
+
return;
|
|
11081
|
+
}
|
|
11082
|
+
if (get_view_members) {
|
|
11083
|
+
const membersRes = await get_view_members(owner_id, type, id);
|
|
11084
|
+
if (membersRes.success && membersRes.members) {
|
|
11085
|
+
setViewMembers(membersRes.members);
|
|
11086
|
+
}
|
|
10523
11087
|
}
|
|
10524
11088
|
} catch (error) {
|
|
10525
11089
|
console.error("Erro ao verificar permiss\xE3o:", error);
|
|
@@ -10560,6 +11124,7 @@ function XViewScene({
|
|
|
10560
11124
|
const [isLoading, setIsLoading] = (0, import_react26.useState)(true);
|
|
10561
11125
|
const [permissionStatus, setPermissionStatus] = (0, import_react26.useState)("loading");
|
|
10562
11126
|
const [userPermissionRole, setUserPermissionRole] = (0, import_react26.useState)(null);
|
|
11127
|
+
const [viewMembers, setViewMembers] = (0, import_react26.useState)([]);
|
|
10563
11128
|
const [isInitialized, setIsInitialized] = (0, import_react26.useState)(false);
|
|
10564
11129
|
const [sceneVersion, setSceneVersion] = (0, import_react26.useState)(0);
|
|
10565
11130
|
const [contextMenu, setContextMenu] = (0, import_react26.useState)({
|
|
@@ -10628,6 +11193,7 @@ function XViewScene({
|
|
|
10628
11193
|
});
|
|
10629
11194
|
const [isImportModalOpen, setIsImportModalOpen] = (0, import_react26.useState)(false);
|
|
10630
11195
|
const [importSuccessMessage, setImportSuccessMessage] = (0, import_react26.useState)("");
|
|
11196
|
+
const [invalidTargetError, setInvalidTargetError] = (0, import_react26.useState)(null);
|
|
10631
11197
|
const [highlightedNodeId, setHighlightedNodeId] = (0, import_react26.useState)(null);
|
|
10632
11198
|
const [isAncestryBoardOpen, setIsAncestryBoardOpen] = (0, import_react26.useState)(false);
|
|
10633
11199
|
const [ancestryBoardData, setAncestryBoardData] = (0, import_react26.useState)([]);
|
|
@@ -12476,6 +13042,28 @@ function XViewScene({
|
|
|
12476
13042
|
const handleStartVersioning = (nodeData) => {
|
|
12477
13043
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
12478
13044
|
};
|
|
13045
|
+
const handleStartQuestQuick = (0, import_react26.useCallback)((questNode) => {
|
|
13046
|
+
var _a2;
|
|
13047
|
+
if (!questNode || !actionHandlerContext) return;
|
|
13048
|
+
const {
|
|
13049
|
+
labelObject,
|
|
13050
|
+
labelOffset,
|
|
13051
|
+
aura,
|
|
13052
|
+
borderRing,
|
|
13053
|
+
timelineIntervalBar,
|
|
13054
|
+
timelineEndLabel,
|
|
13055
|
+
...cleanQuestNode
|
|
13056
|
+
} = questNode;
|
|
13057
|
+
const updatedNode = {
|
|
13058
|
+
...cleanQuestNode,
|
|
13059
|
+
status: "In Progress",
|
|
13060
|
+
color: "#eab308",
|
|
13061
|
+
assignee_id: (_a2 = session == null ? void 0 : session.user) == null ? void 0 : _a2.id
|
|
13062
|
+
};
|
|
13063
|
+
if (userActionHandlers.handleSaveNodeDetails) {
|
|
13064
|
+
userActionHandlers.handleSaveNodeDetails(actionHandlerContext, updatedNode);
|
|
13065
|
+
}
|
|
13066
|
+
}, [session, actionHandlerContext]);
|
|
12479
13067
|
const handleCancelQuest = (0, import_react26.useCallback)(() => {
|
|
12480
13068
|
const { graphGroup, ghostElements } = stateRef.current;
|
|
12481
13069
|
if (ghostElements.node && graphGroup) {
|
|
@@ -14160,7 +14748,13 @@ function XViewScene({
|
|
|
14160
14748
|
if (!parentDataRef.current) {
|
|
14161
14749
|
return [];
|
|
14162
14750
|
}
|
|
14163
|
-
return Object.
|
|
14751
|
+
return Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
|
|
14752
|
+
const datasetName = fileData.dataset_name || `Dataset #${dbId.substring(0, 6)}`;
|
|
14753
|
+
return (fileData.nodes || []).map((node) => ({
|
|
14754
|
+
...node,
|
|
14755
|
+
dataset_name: datasetName
|
|
14756
|
+
}));
|
|
14757
|
+
}).filter((node) => {
|
|
14164
14758
|
var _a2;
|
|
14165
14759
|
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
14166
14760
|
});
|
|
@@ -14304,6 +14898,9 @@ function XViewScene({
|
|
|
14304
14898
|
}, 300);
|
|
14305
14899
|
} else {
|
|
14306
14900
|
setHasFocusedInitial(true);
|
|
14901
|
+
setInvalidTargetError(
|
|
14902
|
+
"O link aponta para um item que n\xE3o foi encontrado ou foi exclu\xEDdo."
|
|
14903
|
+
);
|
|
14307
14904
|
}
|
|
14308
14905
|
}
|
|
14309
14906
|
}, [
|
|
@@ -14326,6 +14923,9 @@ function XViewScene({
|
|
|
14326
14923
|
}, 300);
|
|
14327
14924
|
} else {
|
|
14328
14925
|
setHasOpenedInitialAncestry(true);
|
|
14926
|
+
setInvalidTargetError(
|
|
14927
|
+
"O link aponta para uma ancestralidade que n\xE3o foi encontrada ou foi exclu\xEDda."
|
|
14928
|
+
);
|
|
14329
14929
|
}
|
|
14330
14930
|
}
|
|
14331
14931
|
}, [
|
|
@@ -14619,7 +15219,8 @@ function XViewScene({
|
|
|
14619
15219
|
availableNodes: allAvailableNodes,
|
|
14620
15220
|
availableAncestries: allAvailableAncestries,
|
|
14621
15221
|
viewName: viewParams == null ? void 0 : viewParams.name,
|
|
14622
|
-
questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1
|
|
15222
|
+
questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1,
|
|
15223
|
+
viewMembers
|
|
14623
15224
|
}
|
|
14624
15225
|
),
|
|
14625
15226
|
readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react26.default.createElement(
|
|
@@ -14749,7 +15350,8 @@ function XViewScene({
|
|
|
14749
15350
|
onMentionClick: handleAddExistingNode,
|
|
14750
15351
|
onUploadFile: upload_file_action,
|
|
14751
15352
|
userRole: userPermissionRole,
|
|
14752
|
-
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
|
|
15353
|
+
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
|
|
15354
|
+
viewMembers
|
|
14753
15355
|
}
|
|
14754
15356
|
),
|
|
14755
15357
|
detailsNode && !detailsNode.is_quest && /* @__PURE__ */ import_react26.default.createElement(
|
|
@@ -14862,7 +15464,10 @@ function XViewScene({
|
|
|
14862
15464
|
onRenderAncestry: handleStartReadingAncestry,
|
|
14863
15465
|
onEditAncestry: handleEditAncestry,
|
|
14864
15466
|
onDeleteAncestry: (ancestryId) => handleDeleteAncestry(ancestryId),
|
|
14865
|
-
onFocusNode: handleFocusNode
|
|
15467
|
+
onFocusNode: handleFocusNode,
|
|
15468
|
+
viewMembers,
|
|
15469
|
+
currentUser: session == null ? void 0 : session.user,
|
|
15470
|
+
onStartQuest: handleStartQuestQuick
|
|
14866
15471
|
}
|
|
14867
15472
|
),
|
|
14868
15473
|
/* @__PURE__ */ import_react26.default.createElement(
|
|
@@ -14935,6 +15540,83 @@ function XViewScene({
|
|
|
14935
15540
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
14936
15541
|
currentAncestries: ancestryDataRef.current || []
|
|
14937
15542
|
}
|
|
15543
|
+
),
|
|
15544
|
+
invalidTargetError && /* @__PURE__ */ import_react26.default.createElement(
|
|
15545
|
+
"div",
|
|
15546
|
+
{
|
|
15547
|
+
className: "ui-overlay",
|
|
15548
|
+
style: {
|
|
15549
|
+
position: "fixed",
|
|
15550
|
+
top: "24px",
|
|
15551
|
+
left: "50%",
|
|
15552
|
+
transform: "translateX(-50%)",
|
|
15553
|
+
zIndex: 1e4,
|
|
15554
|
+
padding: "16px 24px",
|
|
15555
|
+
background: "rgba(30, 20, 20, 0.85)",
|
|
15556
|
+
backdropFilter: "blur(12px)",
|
|
15557
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
15558
|
+
border: "1px solid rgba(255, 70, 70, 0.35)",
|
|
15559
|
+
borderRadius: "16px",
|
|
15560
|
+
boxShadow: "0 12px 40px rgba(0,0,0,0.5), 0 0 30px rgba(255, 50, 50, 0.1)",
|
|
15561
|
+
color: "#ffa0a0",
|
|
15562
|
+
display: "flex",
|
|
15563
|
+
alignItems: "center",
|
|
15564
|
+
gap: "16px",
|
|
15565
|
+
fontFamily: "Inter, sans-serif",
|
|
15566
|
+
animation: "fadeInDown 0.5s cubic-bezier(0.16, 1, 0.3, 1)"
|
|
15567
|
+
}
|
|
15568
|
+
},
|
|
15569
|
+
/* @__PURE__ */ import_react26.default.createElement("style", null, `
|
|
15570
|
+
@keyframes fadeInDown {
|
|
15571
|
+
from { opacity: 0; transform: translate(-50%, -20px); }
|
|
15572
|
+
to { opacity: 1; transform: translate(-50%, 0); }
|
|
15573
|
+
}
|
|
15574
|
+
`),
|
|
15575
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
15576
|
+
"svg",
|
|
15577
|
+
{
|
|
15578
|
+
width: "20",
|
|
15579
|
+
height: "20",
|
|
15580
|
+
viewBox: "0 0 24 24",
|
|
15581
|
+
fill: "none",
|
|
15582
|
+
stroke: "currentColor",
|
|
15583
|
+
strokeWidth: "2",
|
|
15584
|
+
strokeLinecap: "round",
|
|
15585
|
+
strokeLinejoin: "round"
|
|
15586
|
+
},
|
|
15587
|
+
/* @__PURE__ */ import_react26.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
|
|
15588
|
+
/* @__PURE__ */ import_react26.default.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
15589
|
+
/* @__PURE__ */ import_react26.default.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
15590
|
+
),
|
|
15591
|
+
/* @__PURE__ */ import_react26.default.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
|
|
15592
|
+
/* @__PURE__ */ import_react26.default.createElement(
|
|
15593
|
+
"button",
|
|
15594
|
+
{
|
|
15595
|
+
onClick: () => setInvalidTargetError(null),
|
|
15596
|
+
style: {
|
|
15597
|
+
background: "rgba(255, 255, 255, 0.1)",
|
|
15598
|
+
border: "none",
|
|
15599
|
+
color: "white",
|
|
15600
|
+
padding: "4px 10px",
|
|
15601
|
+
borderRadius: "8px",
|
|
15602
|
+
cursor: "pointer",
|
|
15603
|
+
fontSize: "12px",
|
|
15604
|
+
fontWeight: 600,
|
|
15605
|
+
transition: "all 0.2s",
|
|
15606
|
+
marginLeft: "8px",
|
|
15607
|
+
border: "1px solid rgba(255,255,255,0.1)"
|
|
15608
|
+
},
|
|
15609
|
+
onMouseOver: (e) => {
|
|
15610
|
+
e.currentTarget.style.background = "rgba(255, 255, 255, 0.15)";
|
|
15611
|
+
e.currentTarget.style.transform = "translateY(-1px)";
|
|
15612
|
+
},
|
|
15613
|
+
onMouseOut: (e) => {
|
|
15614
|
+
e.currentTarget.style.background = "rgba(255, 255, 255, 0.1)";
|
|
15615
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
15616
|
+
}
|
|
15617
|
+
},
|
|
15618
|
+
"Fechar"
|
|
15619
|
+
)
|
|
14938
15620
|
)
|
|
14939
15621
|
);
|
|
14940
15622
|
}
|
|
@@ -15361,6 +16043,17 @@ async function delete_uploaded_file_logic(db_services, fileUrl) {
|
|
|
15361
16043
|
return { success: false, error: error.message };
|
|
15362
16044
|
}
|
|
15363
16045
|
}
|
|
16046
|
+
async function get_view_members_logic(db_services, ownerId, type, itemId) {
|
|
16047
|
+
try {
|
|
16048
|
+
if (!db_services.get_view_members) {
|
|
16049
|
+
return { success: false, error: "Servi\xE7o de busca de membros n\xE3o configurado." };
|
|
16050
|
+
}
|
|
16051
|
+
return await db_services.get_view_members(ownerId, type, itemId);
|
|
16052
|
+
} catch (error) {
|
|
16053
|
+
console.error("Erro em get_view_members_logic:", error);
|
|
16054
|
+
return { success: false, error: error.message };
|
|
16055
|
+
}
|
|
16056
|
+
}
|
|
15364
16057
|
// Annotate the CommonJS export names for ESM import in node:
|
|
15365
16058
|
0 && (module.exports = {
|
|
15366
16059
|
XViewScene,
|
|
@@ -15369,6 +16062,7 @@ async function delete_uploaded_file_logic(db_services, fileUrl) {
|
|
|
15369
16062
|
get_ancestry_file_logic,
|
|
15370
16063
|
get_scene_view_data_logic,
|
|
15371
16064
|
get_single_parent_file_logic,
|
|
16065
|
+
get_view_members_logic,
|
|
15372
16066
|
import_parent_file_modal_get_logic,
|
|
15373
16067
|
save_ancestry_board_logic,
|
|
15374
16068
|
save_view_data_logic,
|