@lv-x-software-house/x_view 1.2.6-dev.3 → 1.2.6-dev.30
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 +1585 -851
- package/dist/index.mjs +1506 -791
- package/package.json +4 -22
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
1
|
// src/XViewScene.jsx
|
|
4
2
|
import React30, {
|
|
5
|
-
useCallback as
|
|
3
|
+
useCallback as useCallback5,
|
|
6
4
|
useEffect as useEffect24,
|
|
7
|
-
useRef as
|
|
8
|
-
useState as
|
|
5
|
+
useRef as useRef21,
|
|
6
|
+
useState as useState29,
|
|
9
7
|
useMemo as useMemo13
|
|
10
8
|
} from "react";
|
|
11
9
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
@@ -40,8 +38,8 @@ function defineAbilityFor(role) {
|
|
|
40
38
|
can("read", "Versioning");
|
|
41
39
|
can("read", "Node");
|
|
42
40
|
can("read", "Scene");
|
|
43
|
-
can("read", "
|
|
44
|
-
can("read", "
|
|
41
|
+
can("read", "Boards");
|
|
42
|
+
can("read", "BoardGroups");
|
|
45
43
|
can("dismiss", "Node");
|
|
46
44
|
cannot("update", "Scene");
|
|
47
45
|
cannot("import", "File");
|
|
@@ -54,10 +52,10 @@ function defineAbilityFor(role) {
|
|
|
54
52
|
cannot("create", "Ancestry");
|
|
55
53
|
cannot("update", "Ancestry");
|
|
56
54
|
cannot("delete", "Ancestry");
|
|
57
|
-
cannot("create", "
|
|
58
|
-
cannot("update", "
|
|
59
|
-
cannot("delete", "
|
|
60
|
-
cannot("manage", "
|
|
55
|
+
cannot("create", "BoardGroups");
|
|
56
|
+
cannot("update", "BoardGroups");
|
|
57
|
+
cannot("delete", "BoardGroups");
|
|
58
|
+
cannot("manage", "Boards");
|
|
61
59
|
cannot("update", "Node");
|
|
62
60
|
break;
|
|
63
61
|
case "link_viewer":
|
|
@@ -66,8 +64,8 @@ function defineAbilityFor(role) {
|
|
|
66
64
|
can("read", "Versioning");
|
|
67
65
|
cannot("read", "Scene");
|
|
68
66
|
cannot("read", "Connection");
|
|
69
|
-
cannot("read", "
|
|
70
|
-
cannot("read", "
|
|
67
|
+
cannot("read", "Boards");
|
|
68
|
+
cannot("read", "BoardGroups");
|
|
71
69
|
cannot("dismiss", "Node");
|
|
72
70
|
cannot("manage", "all");
|
|
73
71
|
break;
|
|
@@ -1055,6 +1053,8 @@ var userActionHandlers = {
|
|
|
1055
1053
|
if (isCrossDataset) {
|
|
1056
1054
|
graphDataRef.current[finalTargetDatasetId] = targetDataToUpdate;
|
|
1057
1055
|
}
|
|
1056
|
+
if (sceneDataRef.current.parent_dbs.some((db) => String(db.db_id) === String(sourceParentInfo.parentFileId))) {
|
|
1057
|
+
}
|
|
1058
1058
|
const finalPosition = stateRef.current.ghostElements.node.position.clone();
|
|
1059
1059
|
addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
|
|
1060
1060
|
stateRef.current.nodeIdToParentFileMap.set(String(newNode.id), {
|
|
@@ -1253,6 +1253,9 @@ var userActionHandlers = {
|
|
|
1253
1253
|
);
|
|
1254
1254
|
}
|
|
1255
1255
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
1256
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
1257
|
+
sceneDataRef.current.quest_nodes = [...specificParentData.nodes];
|
|
1258
|
+
}
|
|
1256
1259
|
const finalPosition = stateRef.current.ghostElements.node.position.clone();
|
|
1257
1260
|
addNewNodeToScene(stateRef.current, newNode, newLink, finalPosition);
|
|
1258
1261
|
setters.setSceneVersion((v) => v + 1);
|
|
@@ -2272,8 +2275,6 @@ var userActionHandlers = {
|
|
|
2272
2275
|
milestones: sceneDataRef.current.milestones || [],
|
|
2273
2276
|
quest_counter: sceneDataRef.current.quest_counter || 1
|
|
2274
2277
|
};
|
|
2275
|
-
sceneDataRef.current.quest_nodes = specificParentData.nodes;
|
|
2276
|
-
sceneDataRef.current.quest_links = specificParentData.links;
|
|
2277
2278
|
await context.actions.save_view_data(
|
|
2278
2279
|
context.sceneSaveUrl,
|
|
2279
2280
|
viewFilePayload
|
|
@@ -2286,6 +2287,10 @@ var userActionHandlers = {
|
|
|
2286
2287
|
);
|
|
2287
2288
|
}
|
|
2288
2289
|
graphDataRef.current[parentFileId] = specificParentData;
|
|
2290
|
+
if (isView && parentFileId === context.sceneConfigId) {
|
|
2291
|
+
sceneDataRef.current.quest_nodes = [...specificParentData.nodes];
|
|
2292
|
+
sceneDataRef.current.quest_counter = specificParentData.quest_counter || sceneDataRef.current.quest_counter;
|
|
2293
|
+
}
|
|
2289
2294
|
updateExistingNodeVisuals(stateRef.current, nodeToSave);
|
|
2290
2295
|
setters.setSceneVersion((v) => v + 1);
|
|
2291
2296
|
if (!keepOpen) {
|
|
@@ -3838,7 +3843,7 @@ function XViewSidebar({
|
|
|
3838
3843
|
importSuccessMessage = "",
|
|
3839
3844
|
onActivateTimeline = () => {
|
|
3840
3845
|
},
|
|
3841
|
-
|
|
3846
|
+
onOpenBoards = () => {
|
|
3842
3847
|
},
|
|
3843
3848
|
viewType,
|
|
3844
3849
|
viewName,
|
|
@@ -4339,12 +4344,12 @@ function XViewSidebar({
|
|
|
4339
4344
|
), /* @__PURE__ */ React2.createElement(
|
|
4340
4345
|
"button",
|
|
4341
4346
|
{
|
|
4342
|
-
onClick:
|
|
4347
|
+
onClick: onOpenBoards,
|
|
4343
4348
|
className: buttonBaseClass,
|
|
4344
|
-
title: "Abrir painel de
|
|
4349
|
+
title: "Abrir painel de Boards"
|
|
4345
4350
|
},
|
|
4346
|
-
/* @__PURE__ */ React2.createElement(
|
|
4347
|
-
"
|
|
4351
|
+
/* @__PURE__ */ React2.createElement(FiLayers, { size: 16 }),
|
|
4352
|
+
"Boards"
|
|
4348
4353
|
)), /* @__PURE__ */ React2.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ React2.createElement("section", { className: "space-y-3" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Milestones"), /* @__PURE__ */ React2.createElement(
|
|
4349
4354
|
"button",
|
|
4350
4355
|
{
|
|
@@ -12944,586 +12949,806 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
|
|
|
12944
12949
|
);
|
|
12945
12950
|
}
|
|
12946
12951
|
|
|
12947
|
-
// src/components/
|
|
12948
|
-
import React28, { useState as
|
|
12952
|
+
// src/components/Boards.jsx
|
|
12953
|
+
import React28, { useState as useState27, useMemo as useMemo12, useEffect as useEffect23, useRef as useRef20 } from "react";
|
|
12949
12954
|
import {
|
|
12950
|
-
FiSearch as
|
|
12955
|
+
FiSearch as FiSearch8,
|
|
12951
12956
|
FiLayers as FiLayers7,
|
|
12952
|
-
FiCornerUpRight as FiCornerUpRight4,
|
|
12953
12957
|
FiPlay,
|
|
12954
12958
|
FiPlus as FiPlus10,
|
|
12955
12959
|
FiTrash2 as FiTrash23,
|
|
12956
12960
|
FiArrowLeft as FiArrowLeft3,
|
|
12957
12961
|
FiArrowRight as FiArrowRight2,
|
|
12962
|
+
FiArrowUp,
|
|
12963
|
+
FiArrowDown,
|
|
12958
12964
|
FiCheckCircle,
|
|
12959
12965
|
FiLoader as FiLoader5,
|
|
12960
12966
|
FiX as FiX8,
|
|
12961
|
-
FiAlertTriangle,
|
|
12962
|
-
FiCheckSquare as FiCheckSquare4,
|
|
12963
12967
|
FiBox as FiBox2,
|
|
12964
|
-
|
|
12968
|
+
FiCheckSquare as FiCheckSquare4,
|
|
12969
|
+
FiGitBranch as FiGitBranch4,
|
|
12970
|
+
FiFolder as FiFolder3,
|
|
12971
|
+
FiChevronRight as FiChevronRight7,
|
|
12972
|
+
FiCornerUpLeft as FiCornerUpLeft3
|
|
12965
12973
|
} from "react-icons/fi";
|
|
12966
12974
|
import { v4 as uuidv411 } from "uuid";
|
|
12967
12975
|
|
|
12968
|
-
// src/components/
|
|
12969
|
-
import React27, {
|
|
12970
|
-
import { useEditor, EditorContent, ReactRenderer } from "@tiptap/react";
|
|
12971
|
-
import StarterKit from "@tiptap/starter-kit";
|
|
12972
|
-
import Mention from "@tiptap/extension-mention";
|
|
12973
|
-
import tippy from "tippy.js";
|
|
12976
|
+
// src/components/RichGroupEditor.jsx
|
|
12977
|
+
import React27, { useEffect as useEffect22, useRef as useRef19, useState as useState26, useCallback as useCallback4 } from "react";
|
|
12974
12978
|
|
|
12975
|
-
// src/components/
|
|
12976
|
-
import React26, {
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
};
|
|
12997
|
-
|
|
12998
|
-
|
|
12999
|
-
(
|
|
13000
|
-
|
|
13001
|
-
|
|
13002
|
-
|
|
13003
|
-
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
|
|
13007
|
-
|
|
13008
|
-
|
|
13009
|
-
|
|
13010
|
-
|
|
13011
|
-
|
|
13012
|
-
|
|
13013
|
-
return true;
|
|
13014
|
-
}
|
|
13015
|
-
if (event.key === "ArrowDown") {
|
|
13016
|
-
downHandler();
|
|
13017
|
-
return true;
|
|
13018
|
-
}
|
|
13019
|
-
if (event.key === "Enter") {
|
|
13020
|
-
enterHandler();
|
|
13021
|
-
return true;
|
|
12979
|
+
// src/components/MentionPopover.jsx
|
|
12980
|
+
import React26, { useEffect as useEffect21, useRef as useRef18, useState as useState25, useMemo as useMemo11 } from "react";
|
|
12981
|
+
import { FiLayers as FiLayers6, FiCheckSquare as FiCheckSquare3, FiGitBranch as FiGitBranch3, FiBox } from "react-icons/fi";
|
|
12982
|
+
var TYPE_CONFIG = {
|
|
12983
|
+
ancestry: { Icon: FiLayers6, color: "text-indigo-400", label: "Ancestralidade" },
|
|
12984
|
+
quest: { Icon: FiCheckSquare3, color: "text-emerald-400", label: "Quest" },
|
|
12985
|
+
version: { Icon: FiGitBranch3, color: "text-amber-400", label: "Vers\xE3o" },
|
|
12986
|
+
node: { Icon: FiBox, color: "text-slate-400", label: "Node" }
|
|
12987
|
+
};
|
|
12988
|
+
function MentionPopover({ query, items, position, onSelect, onClose }) {
|
|
12989
|
+
const [activeIndex, setActiveIndex] = useState25(0);
|
|
12990
|
+
const listRef = useRef18(null);
|
|
12991
|
+
const filtered = useMemo11(() => {
|
|
12992
|
+
const term = (query || "").toLowerCase().trim();
|
|
12993
|
+
if (!term) return items.slice(0, 8);
|
|
12994
|
+
return items.filter(
|
|
12995
|
+
(item) => (item.searchLabel || "").toLowerCase().includes(term) || (item.searchDesc || "").toLowerCase().includes(term)
|
|
12996
|
+
).slice(0, 8);
|
|
12997
|
+
}, [items, query]);
|
|
12998
|
+
useEffect21(() => {
|
|
12999
|
+
setActiveIndex(0);
|
|
13000
|
+
}, [query]);
|
|
13001
|
+
useEffect21(() => {
|
|
13002
|
+
const handleKeyDown = (e) => {
|
|
13003
|
+
if (e.key === "ArrowDown") {
|
|
13004
|
+
e.preventDefault();
|
|
13005
|
+
setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
|
|
13006
|
+
} else if (e.key === "ArrowUp") {
|
|
13007
|
+
e.preventDefault();
|
|
13008
|
+
setActiveIndex((i) => Math.max(i - 1, 0));
|
|
13009
|
+
} else if (e.key === "Enter" || e.key === "Tab") {
|
|
13010
|
+
e.preventDefault();
|
|
13011
|
+
if (filtered[activeIndex]) onSelect(filtered[activeIndex]);
|
|
13012
|
+
} else if (e.key === "Escape") {
|
|
13013
|
+
e.preventDefault();
|
|
13014
|
+
e.stopPropagation();
|
|
13015
|
+
e.stopImmediatePropagation();
|
|
13016
|
+
onClose();
|
|
13022
13017
|
}
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
}
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
var MentionList_default = MentionList;
|
|
13018
|
+
};
|
|
13019
|
+
window.addEventListener("keydown", handleKeyDown, true);
|
|
13020
|
+
return () => window.removeEventListener("keydown", handleKeyDown, true);
|
|
13021
|
+
}, [filtered, activeIndex, onSelect, onClose]);
|
|
13022
|
+
useEffect21(() => {
|
|
13023
|
+
if (listRef.current) {
|
|
13024
|
+
const el = listRef.current.children[activeIndex];
|
|
13025
|
+
if (el) el.scrollIntoView({ block: "nearest" });
|
|
13026
|
+
}
|
|
13027
|
+
}, [activeIndex]);
|
|
13028
|
+
return /* @__PURE__ */ React26.createElement(
|
|
13029
|
+
"div",
|
|
13030
|
+
{
|
|
13031
|
+
style: { top: position.top, left: position.left, position: "fixed", zIndex: 9999 },
|
|
13032
|
+
className: "bg-slate-900 border border-white/10 rounded-xl shadow-2xl py-1.5 min-w-[260px] max-h-[240px] overflow-y-auto custom-scrollbar animate-in fade-in zoom-in-95 duration-100",
|
|
13033
|
+
ref: listRef,
|
|
13034
|
+
onMouseDown: (e) => e.preventDefault()
|
|
13035
|
+
},
|
|
13036
|
+
filtered.length === 0 ? /* @__PURE__ */ React26.createElement("div", { className: "px-4 py-3 text-xs text-slate-500" }, "Nenhum resultado para", " ", /* @__PURE__ */ React26.createElement("span", { className: "text-slate-300 font-medium" }, '"', query, '"')) : filtered.map((item, idx) => {
|
|
13037
|
+
const config = TYPE_CONFIG[item.type] || TYPE_CONFIG.node;
|
|
13038
|
+
const { Icon } = config;
|
|
13039
|
+
return /* @__PURE__ */ React26.createElement(
|
|
13040
|
+
"div",
|
|
13041
|
+
{
|
|
13042
|
+
key: item.id,
|
|
13043
|
+
onMouseDown: (e) => {
|
|
13044
|
+
e.preventDefault();
|
|
13045
|
+
onSelect(item);
|
|
13046
|
+
},
|
|
13047
|
+
onMouseEnter: () => setActiveIndex(idx),
|
|
13048
|
+
className: `flex items-center gap-2.5 px-3 py-2 cursor-pointer text-sm transition-colors duration-100 ${idx === activeIndex ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5"}`
|
|
13049
|
+
},
|
|
13050
|
+
/* @__PURE__ */ React26.createElement(Icon, { size: 13, className: config.color }),
|
|
13051
|
+
/* @__PURE__ */ React26.createElement("span", { className: "flex-1 truncate font-medium" }, item.searchLabel || "Sem Nome"),
|
|
13052
|
+
/* @__PURE__ */ React26.createElement("span", { className: "text-[9px] px-1.5 py-0.5 rounded-full bg-white/5 text-slate-500 border border-white/5 uppercase tracking-wide shrink-0" }, config.label)
|
|
13053
|
+
);
|
|
13054
|
+
})
|
|
13055
|
+
);
|
|
13056
|
+
}
|
|
13063
13057
|
|
|
13064
|
-
// src/components/
|
|
13065
|
-
var
|
|
13066
|
-
|
|
13058
|
+
// src/components/RichGroupEditor.jsx
|
|
13059
|
+
var MENTION_BASE_STYLE = "display:inline-flex;align-items:center;padding:1px 7px;border-radius:5px;margin:0 2px;font-size:0.78em;font-weight:600;cursor:pointer;white-space:nowrap;vertical-align:middle;user-select:none;line-height:1.6;";
|
|
13060
|
+
var MENTION_TYPE_STYLE = {
|
|
13061
|
+
ancestry: "background:rgba(99,102,241,0.18);color:#a5b4fc;border:1px solid rgba(99,102,241,0.35);",
|
|
13062
|
+
quest: "background:rgba(16,185,129,0.18);color:#6ee7b7;border:1px solid rgba(16,185,129,0.35);",
|
|
13063
|
+
version: "background:rgba(245,158,11,0.18);color:#fcd34d;border:1px solid rgba(245,158,11,0.35);",
|
|
13064
|
+
node: "background:rgba(100,116,139,0.18);color:#94a3b8;border:1px solid rgba(100,116,139,0.35);"
|
|
13065
|
+
};
|
|
13066
|
+
function mentionStyle(type) {
|
|
13067
|
+
return MENTION_BASE_STYLE + (MENTION_TYPE_STYLE[type] || MENTION_TYPE_STYLE.node);
|
|
13068
|
+
}
|
|
13069
|
+
function escapeHtml(str) {
|
|
13070
|
+
return String(str || "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
13071
|
+
}
|
|
13072
|
+
function contentToHTML(content) {
|
|
13073
|
+
if (!content || content.length === 0) return "";
|
|
13074
|
+
return content.map((seg) => {
|
|
13075
|
+
if (seg.type === "text") {
|
|
13076
|
+
return escapeHtml(seg.value).replace(/\n/g, "<br>");
|
|
13077
|
+
}
|
|
13078
|
+
if (seg.type === "mention") {
|
|
13079
|
+
const style = mentionStyle(seg.mentionType);
|
|
13080
|
+
return `<span contenteditable="false" data-mention="true" data-id="${escapeHtml(String(seg.id))}" data-name="${escapeHtml(seg.name || "")}" data-mention-type="${escapeHtml(seg.mentionType || "node")}" style="${style}" title="Clique para focar na cena">@${escapeHtml(seg.name || "")}</span>`;
|
|
13081
|
+
}
|
|
13082
|
+
return "";
|
|
13083
|
+
}).join("");
|
|
13084
|
+
}
|
|
13085
|
+
function domToContent(el) {
|
|
13086
|
+
const segments = [];
|
|
13087
|
+
function pushText(text) {
|
|
13088
|
+
const clean = text.replace(/\u200B/g, "");
|
|
13089
|
+
if (!clean) return;
|
|
13090
|
+
const last = segments[segments.length - 1];
|
|
13091
|
+
if (last && last.type === "text") {
|
|
13092
|
+
last.value += clean;
|
|
13093
|
+
} else {
|
|
13094
|
+
segments.push({ type: "text", value: clean });
|
|
13095
|
+
}
|
|
13096
|
+
}
|
|
13097
|
+
function walk(node) {
|
|
13067
13098
|
var _a;
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
default: null,
|
|
13084
|
-
parseHTML: (element) => element.getAttribute("data-label"),
|
|
13085
|
-
renderHTML: (attributes) => {
|
|
13086
|
-
if (!attributes.label) {
|
|
13087
|
-
return {};
|
|
13088
|
-
}
|
|
13089
|
-
return {
|
|
13090
|
-
"data-label": attributes.label
|
|
13091
|
-
};
|
|
13099
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
13100
|
+
pushText(node.textContent);
|
|
13101
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
13102
|
+
if (((_a = node.dataset) == null ? void 0 : _a.mention) === "true") {
|
|
13103
|
+
segments.push({
|
|
13104
|
+
type: "mention",
|
|
13105
|
+
id: node.dataset.id,
|
|
13106
|
+
name: node.dataset.name,
|
|
13107
|
+
mentionType: node.dataset.mentionType
|
|
13108
|
+
});
|
|
13109
|
+
} else if (node.tagName === "BR") {
|
|
13110
|
+
pushText("\n");
|
|
13111
|
+
} else {
|
|
13112
|
+
if (["DIV", "P"].includes(node.tagName) && segments.length > 0) {
|
|
13113
|
+
pushText("\n");
|
|
13092
13114
|
}
|
|
13115
|
+
node.childNodes.forEach(walk);
|
|
13093
13116
|
}
|
|
13094
|
-
}
|
|
13117
|
+
}
|
|
13095
13118
|
}
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13119
|
+
el.childNodes.forEach(walk);
|
|
13120
|
+
return segments;
|
|
13121
|
+
}
|
|
13122
|
+
function RichGroupEditor({
|
|
13123
|
+
content,
|
|
13099
13124
|
onChange,
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
placeholder
|
|
13104
|
-
})
|
|
13105
|
-
const
|
|
13106
|
-
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
|
|
13110
|
-
|
|
13111
|
-
|
|
13112
|
-
|
|
13113
|
-
|
|
13114
|
-
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
const content = useMemo11(() => parseInitialContent(initialValue), [initialValue]);
|
|
13118
|
-
const editor = useEditor({
|
|
13119
|
-
extensions: [
|
|
13120
|
-
StarterKit.configure({
|
|
13121
|
-
heading: false,
|
|
13122
|
-
bulletList: false,
|
|
13123
|
-
orderedList: false,
|
|
13124
|
-
codeBlock: false,
|
|
13125
|
-
blockquote: false
|
|
13126
|
-
}),
|
|
13127
|
-
CustomMention.configure({
|
|
13128
|
-
HTMLAttributes: {
|
|
13129
|
-
class: "mention"
|
|
13130
|
-
},
|
|
13131
|
-
suggestion: {
|
|
13132
|
-
items: ({ query }) => {
|
|
13133
|
-
return availableItems.filter(
|
|
13134
|
-
(item) => item.name.toLowerCase().includes(query.toLowerCase())
|
|
13135
|
-
).slice(0, 10);
|
|
13136
|
-
},
|
|
13137
|
-
render: () => {
|
|
13138
|
-
let component;
|
|
13139
|
-
let popup;
|
|
13140
|
-
return {
|
|
13141
|
-
onStart: (props) => {
|
|
13142
|
-
component = new ReactRenderer(MentionList_default, {
|
|
13143
|
-
props,
|
|
13144
|
-
editor: props.editor
|
|
13145
|
-
});
|
|
13146
|
-
if (!props.clientRect) {
|
|
13147
|
-
return;
|
|
13148
|
-
}
|
|
13149
|
-
popup = tippy("body", {
|
|
13150
|
-
getReferenceClientRect: props.clientRect,
|
|
13151
|
-
appendTo: () => document.body,
|
|
13152
|
-
content: component.element,
|
|
13153
|
-
showOnCreate: true,
|
|
13154
|
-
interactive: true,
|
|
13155
|
-
trigger: "manual",
|
|
13156
|
-
placement: "bottom-start",
|
|
13157
|
-
theme: "x-view-dark"
|
|
13158
|
-
});
|
|
13159
|
-
},
|
|
13160
|
-
onUpdate(props) {
|
|
13161
|
-
component.updateProps(props);
|
|
13162
|
-
if (!props.clientRect) {
|
|
13163
|
-
return;
|
|
13164
|
-
}
|
|
13165
|
-
popup[0].setProps({
|
|
13166
|
-
getReferenceClientRect: props.clientRect
|
|
13167
|
-
});
|
|
13168
|
-
},
|
|
13169
|
-
onKeyDown(props) {
|
|
13170
|
-
var _a;
|
|
13171
|
-
if (props.event.key === "Escape") {
|
|
13172
|
-
popup[0].hide();
|
|
13173
|
-
return true;
|
|
13174
|
-
}
|
|
13175
|
-
return (_a = component == null ? void 0 : component.ref) == null ? void 0 : _a.onKeyDown(props);
|
|
13176
|
-
},
|
|
13177
|
-
onExit() {
|
|
13178
|
-
if (popup && popup[0]) popup[0].destroy();
|
|
13179
|
-
if (component) component.destroy();
|
|
13180
|
-
}
|
|
13181
|
-
};
|
|
13182
|
-
}
|
|
13183
|
-
}
|
|
13184
|
-
})
|
|
13185
|
-
],
|
|
13186
|
-
content,
|
|
13187
|
-
editable: canEdit,
|
|
13188
|
-
onUpdate: ({ editor: editor2 }) => {
|
|
13189
|
-
const serialize = (json) => {
|
|
13190
|
-
if (!json.content) return "";
|
|
13191
|
-
return json.content.map((block) => {
|
|
13192
|
-
if (block.type === "paragraph") {
|
|
13193
|
-
const inner = block.content ? block.content.map((node) => {
|
|
13194
|
-
if (node.type === "text") return node.text;
|
|
13195
|
-
if (node.type === "mention") {
|
|
13196
|
-
return `[[MENTION:${node.attrs.type}:${node.attrs.id}:${node.attrs.label}]]`;
|
|
13197
|
-
}
|
|
13198
|
-
return "";
|
|
13199
|
-
}).join("") : "";
|
|
13200
|
-
return inner;
|
|
13201
|
-
}
|
|
13202
|
-
return "";
|
|
13203
|
-
}).join("\n").trim();
|
|
13204
|
-
};
|
|
13205
|
-
const serialized = serialize(editor2.getJSON());
|
|
13206
|
-
onChange(serialized);
|
|
13125
|
+
onMentionClick,
|
|
13126
|
+
searchItems,
|
|
13127
|
+
readOnly,
|
|
13128
|
+
placeholder
|
|
13129
|
+
}) {
|
|
13130
|
+
const editorRef = useRef19(null);
|
|
13131
|
+
const isMountedRef = useRef19(false);
|
|
13132
|
+
const dismissedTriggerRef = useRef19(null);
|
|
13133
|
+
const [mentionState, setMentionState] = useState26(null);
|
|
13134
|
+
const [isEmpty, setIsEmpty] = useState26(true);
|
|
13135
|
+
useEffect22(() => {
|
|
13136
|
+
if (!isMountedRef.current && editorRef.current) {
|
|
13137
|
+
editorRef.current.innerHTML = contentToHTML(content);
|
|
13138
|
+
const hasContent = !!editorRef.current.innerText.replace(/\u200B/g, "").trim();
|
|
13139
|
+
const hasMentions = !!editorRef.current.querySelector("[data-mention]");
|
|
13140
|
+
setIsEmpty(!hasContent && !hasMentions);
|
|
13141
|
+
isMountedRef.current = true;
|
|
13207
13142
|
}
|
|
13208
|
-
});
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
|
|
13212
|
-
|
|
13213
|
-
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13225
|
-
|
|
13226
|
-
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13230
|
-
|
|
13231
|
-
|
|
13232
|
-
|
|
13233
|
-
|
|
13234
|
-
|
|
13235
|
-
|
|
13236
|
-
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
|
|
13240
|
-
|
|
13241
|
-
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
.
|
|
13267
|
-
|
|
13268
|
-
|
|
13269
|
-
|
|
13270
|
-
|
|
13271
|
-
|
|
13272
|
-
|
|
13273
|
-
|
|
13274
|
-
|
|
13143
|
+
}, []);
|
|
13144
|
+
const getMentionContext = useCallback4(() => {
|
|
13145
|
+
const selection = window.getSelection();
|
|
13146
|
+
if (!selection || selection.rangeCount === 0) return null;
|
|
13147
|
+
const range = selection.getRangeAt(0);
|
|
13148
|
+
const node = range.startContainer;
|
|
13149
|
+
if (node.nodeType !== Node.TEXT_NODE) return null;
|
|
13150
|
+
const textBefore = node.textContent.substring(0, range.startOffset);
|
|
13151
|
+
const atIndex = textBefore.lastIndexOf("@");
|
|
13152
|
+
if (atIndex === -1) {
|
|
13153
|
+
dismissedTriggerRef.current = null;
|
|
13154
|
+
return null;
|
|
13155
|
+
}
|
|
13156
|
+
const charBeforeAt = atIndex > 0 ? textBefore[atIndex - 1] : null;
|
|
13157
|
+
if (charBeforeAt && !/\s/.test(charBeforeAt)) {
|
|
13158
|
+
return null;
|
|
13159
|
+
}
|
|
13160
|
+
if (dismissedTriggerRef.current && dismissedTriggerRef.current.node === node && dismissedTriggerRef.current.atIndex === atIndex) {
|
|
13161
|
+
return null;
|
|
13162
|
+
}
|
|
13163
|
+
const query = textBefore.substring(atIndex + 1);
|
|
13164
|
+
if (query.includes(" ") || query.includes(".") || query.includes(",") || query.length > 40) {
|
|
13165
|
+
return null;
|
|
13166
|
+
}
|
|
13167
|
+
const rect = range.getBoundingClientRect();
|
|
13168
|
+
return {
|
|
13169
|
+
query,
|
|
13170
|
+
position: { top: rect.bottom + 6, left: rect.left }
|
|
13171
|
+
};
|
|
13172
|
+
}, []);
|
|
13173
|
+
const handleInput = useCallback4(() => {
|
|
13174
|
+
if (!editorRef.current) return;
|
|
13175
|
+
const serialized = domToContent(editorRef.current);
|
|
13176
|
+
onChange(serialized);
|
|
13177
|
+
const text = editorRef.current.innerText.replace(/\u200B/g, "").trim();
|
|
13178
|
+
const hasMentions = !!editorRef.current.querySelector("[data-mention]");
|
|
13179
|
+
setIsEmpty(!text && !hasMentions);
|
|
13180
|
+
const ctx = getMentionContext();
|
|
13181
|
+
setMentionState(ctx);
|
|
13182
|
+
}, [onChange, getMentionContext]);
|
|
13183
|
+
const handleKeyDown = useCallback4(
|
|
13184
|
+
(e) => {
|
|
13185
|
+
if (mentionState && ["ArrowDown", "ArrowUp", "Enter", "Tab", "Escape"].includes(e.key)) {
|
|
13186
|
+
return;
|
|
13187
|
+
}
|
|
13188
|
+
if (e.key === "Enter") {
|
|
13189
|
+
e.preventDefault();
|
|
13190
|
+
const sel = window.getSelection();
|
|
13191
|
+
const range = sel.getRangeAt(0);
|
|
13192
|
+
const br = document.createElement("br");
|
|
13193
|
+
range.deleteContents();
|
|
13194
|
+
range.insertNode(br);
|
|
13195
|
+
const afterBr = br.nextSibling || (() => {
|
|
13196
|
+
const zws = document.createTextNode("\u200B");
|
|
13197
|
+
br.parentNode.insertBefore(zws, br.nextSibling);
|
|
13198
|
+
return zws;
|
|
13199
|
+
})();
|
|
13200
|
+
const newRange = document.createRange();
|
|
13201
|
+
newRange.setStartBefore(afterBr);
|
|
13202
|
+
newRange.collapse(true);
|
|
13203
|
+
sel.removeAllRanges();
|
|
13204
|
+
sel.addRange(newRange);
|
|
13205
|
+
handleInput();
|
|
13206
|
+
}
|
|
13207
|
+
},
|
|
13208
|
+
[mentionState, handleInput]
|
|
13209
|
+
);
|
|
13210
|
+
const insertMention = useCallback4(
|
|
13211
|
+
(item) => {
|
|
13212
|
+
if (!editorRef.current) return;
|
|
13213
|
+
const sel = window.getSelection();
|
|
13214
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
13215
|
+
const range = sel.getRangeAt(0);
|
|
13216
|
+
const textNode = range.startContainer;
|
|
13217
|
+
if (textNode.nodeType !== Node.TEXT_NODE) {
|
|
13218
|
+
setMentionState(null);
|
|
13219
|
+
return;
|
|
13220
|
+
}
|
|
13221
|
+
const cursorPos = range.startOffset;
|
|
13222
|
+
const textContent = textNode.textContent;
|
|
13223
|
+
const atIndex = textContent.lastIndexOf("@", cursorPos - 1);
|
|
13224
|
+
if (atIndex === -1) {
|
|
13225
|
+
setMentionState(null);
|
|
13226
|
+
return;
|
|
13227
|
+
}
|
|
13228
|
+
const before = textContent.substring(0, atIndex);
|
|
13229
|
+
const after = textContent.substring(cursorPos);
|
|
13230
|
+
textNode.textContent = before;
|
|
13231
|
+
const parent = textNode.parentNode;
|
|
13232
|
+
const nextSib = textNode.nextSibling;
|
|
13233
|
+
const span = document.createElement("span");
|
|
13234
|
+
span.contentEditable = "false";
|
|
13235
|
+
span.dataset.mention = "true";
|
|
13236
|
+
span.dataset.id = item.id;
|
|
13237
|
+
span.dataset.name = item.searchLabel || item.name || "";
|
|
13238
|
+
span.dataset.mentionType = item.type;
|
|
13239
|
+
span.style.cssText = mentionStyle(item.type);
|
|
13240
|
+
span.title = "Clique para focar na cena";
|
|
13241
|
+
span.textContent = `@${item.searchLabel || item.name || ""}`;
|
|
13242
|
+
parent.insertBefore(span, nextSib);
|
|
13243
|
+
const trailing = document.createTextNode(after || "\u200B");
|
|
13244
|
+
parent.insertBefore(trailing, span.nextSibling);
|
|
13245
|
+
const newRange = document.createRange();
|
|
13246
|
+
newRange.setStart(trailing, after ? 0 : 1);
|
|
13247
|
+
newRange.collapse(true);
|
|
13248
|
+
sel.removeAllRanges();
|
|
13249
|
+
sel.addRange(newRange);
|
|
13250
|
+
const serialized = domToContent(editorRef.current);
|
|
13251
|
+
onChange(serialized);
|
|
13252
|
+
setMentionState(null);
|
|
13253
|
+
setIsEmpty(false);
|
|
13254
|
+
},
|
|
13255
|
+
[onChange]
|
|
13256
|
+
);
|
|
13257
|
+
const handlePaste = useCallback4(
|
|
13258
|
+
(e) => {
|
|
13259
|
+
e.preventDefault();
|
|
13260
|
+
const text = e.clipboardData.getData("text/plain");
|
|
13261
|
+
if (text) {
|
|
13262
|
+
document.execCommand("insertText", false, text);
|
|
13263
|
+
handleInput();
|
|
13264
|
+
}
|
|
13265
|
+
},
|
|
13266
|
+
[handleInput]
|
|
13267
|
+
);
|
|
13268
|
+
const handleClick = useCallback4(
|
|
13269
|
+
(e) => {
|
|
13270
|
+
const chip = e.target.closest("[data-mention='true']");
|
|
13271
|
+
if (chip && onMentionClick) {
|
|
13272
|
+
e.stopPropagation();
|
|
13273
|
+
const id = chip.dataset.id;
|
|
13274
|
+
const full = searchItems == null ? void 0 : searchItems.find((i) => String(i.id) === String(id));
|
|
13275
|
+
if (full) {
|
|
13276
|
+
onMentionClick(full);
|
|
13277
|
+
} else {
|
|
13278
|
+
onMentionClick({
|
|
13279
|
+
id,
|
|
13280
|
+
name: chip.dataset.name,
|
|
13281
|
+
type: chip.dataset.mentionType,
|
|
13282
|
+
searchLabel: chip.dataset.name
|
|
13283
|
+
});
|
|
13275
13284
|
}
|
|
13276
|
-
|
|
13277
|
-
|
|
13278
|
-
|
|
13279
|
-
|
|
13285
|
+
return;
|
|
13286
|
+
}
|
|
13287
|
+
},
|
|
13288
|
+
[onMentionClick, getMentionContext, searchItems]
|
|
13289
|
+
);
|
|
13290
|
+
const handleBlur = useCallback4(() => {
|
|
13291
|
+
setTimeout(() => setMentionState(null), 200);
|
|
13292
|
+
}, []);
|
|
13293
|
+
const handleMentionDismiss = useCallback4(() => {
|
|
13294
|
+
const selection = window.getSelection();
|
|
13295
|
+
if (selection && selection.rangeCount > 0) {
|
|
13296
|
+
const range = selection.getRangeAt(0);
|
|
13297
|
+
const node = range.startContainer;
|
|
13298
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
13299
|
+
const textBefore = node.textContent.substring(0, range.startOffset);
|
|
13300
|
+
const atIndex = textBefore.lastIndexOf("@");
|
|
13301
|
+
if (atIndex !== -1) {
|
|
13302
|
+
dismissedTriggerRef.current = { node, atIndex };
|
|
13280
13303
|
}
|
|
13304
|
+
}
|
|
13305
|
+
}
|
|
13306
|
+
setMentionState(null);
|
|
13307
|
+
}, []);
|
|
13308
|
+
return /* @__PURE__ */ React27.createElement("div", { className: "relative" }, isEmpty && !readOnly && /* @__PURE__ */ React27.createElement("div", { className: "absolute top-0 left-0 text-sm text-slate-600 pointer-events-none select-none" }, placeholder || "Escreva sobre este grupo\u2026 ou digite @ para mencionar"), /* @__PURE__ */ React27.createElement(
|
|
13309
|
+
"div",
|
|
13310
|
+
{
|
|
13311
|
+
ref: editorRef,
|
|
13312
|
+
contentEditable: readOnly ? "false" : "true",
|
|
13313
|
+
suppressContentEditableWarning: true,
|
|
13314
|
+
onInput: handleInput,
|
|
13315
|
+
onKeyDown: handleKeyDown,
|
|
13316
|
+
onPaste: handlePaste,
|
|
13317
|
+
onClick: handleClick,
|
|
13318
|
+
onBlur: handleBlur,
|
|
13319
|
+
className: `w-full min-h-[1.5rem] max-h-[250px] overflow-y-auto text-sm text-slate-200 focus:outline-none leading-relaxed ${!readOnly ? "cursor-text" : "cursor-default"}`,
|
|
13320
|
+
style: { overflowWrap: "break-word", wordBreak: "break-word" }
|
|
13321
|
+
}
|
|
13322
|
+
), mentionState && !readOnly && /* @__PURE__ */ React27.createElement(
|
|
13323
|
+
MentionPopover,
|
|
13324
|
+
{
|
|
13325
|
+
query: mentionState.query,
|
|
13326
|
+
items: searchItems || [],
|
|
13327
|
+
position: mentionState.position,
|
|
13328
|
+
onSelect: insertMention,
|
|
13329
|
+
onClose: handleMentionDismiss
|
|
13330
|
+
}
|
|
13331
|
+
));
|
|
13332
|
+
}
|
|
13281
13333
|
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
.ProseMirror-placeholder:first-child::before {
|
|
13287
|
-
content: attr(data-placeholder);
|
|
13288
|
-
float: left;
|
|
13289
|
-
color: #475569;
|
|
13290
|
-
pointer-events: none;
|
|
13291
|
-
height: 0;
|
|
13292
|
-
font-style: italic;
|
|
13293
|
-
}
|
|
13294
|
-
`));
|
|
13334
|
+
// src/components/Boards.jsx
|
|
13335
|
+
var Tooltip = ({ text, children }) => {
|
|
13336
|
+
if (!text) return children;
|
|
13337
|
+
return /* @__PURE__ */ React28.createElement("div", { className: "relative group/tooltip" }, children, /* @__PURE__ */ React28.createElement("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-slate-900 border border-white/10 text-white text-[10px] rounded opacity-0 group-hover/tooltip:opacity-100 transition-opacity pointer-events-none whitespace-nowrap z-[3000] shadow-2xl" }, text));
|
|
13295
13338
|
};
|
|
13296
|
-
var
|
|
13297
|
-
|
|
13298
|
-
// src/components/AncestryBoard.jsx
|
|
13299
|
-
var GroupItem = ({
|
|
13300
|
-
group,
|
|
13339
|
+
var BoardItem = ({
|
|
13340
|
+
item,
|
|
13301
13341
|
index,
|
|
13342
|
+
prevItem,
|
|
13343
|
+
nextItem,
|
|
13302
13344
|
onUpdate,
|
|
13303
13345
|
onDelete,
|
|
13304
13346
|
onAddSubgroup,
|
|
13305
13347
|
onIndent,
|
|
13348
|
+
onIndentDown,
|
|
13306
13349
|
onOutdent,
|
|
13307
|
-
|
|
13308
|
-
|
|
13309
|
-
|
|
13350
|
+
onMoveUp,
|
|
13351
|
+
onMoveDown,
|
|
13352
|
+
searchItems,
|
|
13353
|
+
onMentionClick,
|
|
13354
|
+
onEnterFolder,
|
|
13355
|
+
canEdit,
|
|
13356
|
+
isAtRoot = false
|
|
13310
13357
|
}) => {
|
|
13311
|
-
|
|
13312
|
-
|
|
13313
|
-
|
|
13314
|
-
|
|
13315
|
-
|
|
13316
|
-
|
|
13317
|
-
|
|
13318
|
-
|
|
13319
|
-
|
|
13320
|
-
|
|
13321
|
-
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
)
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
|
|
13337
|
-
/* @__PURE__ */ React28.createElement(FiPlus10, { size: 14 }),
|
|
13338
|
-
/* @__PURE__ */ React28.createElement("span", null, "Adicionar Subgrupo")
|
|
13339
|
-
)), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React28.createElement(
|
|
13340
|
-
"button",
|
|
13341
|
-
{
|
|
13342
|
-
onClick: () => onIndent(group.id),
|
|
13343
|
-
disabled: !canIndent,
|
|
13344
|
-
className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
|
|
13345
|
-
title: "Aninhar no grupo acima"
|
|
13346
|
-
},
|
|
13347
|
-
/* @__PURE__ */ React28.createElement(FiArrowRight2, { size: 14 })
|
|
13348
|
-
), /* @__PURE__ */ React28.createElement(
|
|
13349
|
-
"button",
|
|
13350
|
-
{
|
|
13351
|
-
onClick: () => onOutdent(group.id),
|
|
13352
|
-
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
13353
|
-
title: "Desaninhar"
|
|
13354
|
-
},
|
|
13355
|
-
/* @__PURE__ */ React28.createElement(FiArrowLeft3, { size: 14 })
|
|
13356
|
-
), /* @__PURE__ */ React28.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React28.createElement(
|
|
13357
|
-
"button",
|
|
13358
|
+
var _a;
|
|
13359
|
+
const isFolder = item.type === "folder";
|
|
13360
|
+
const canMoveUp = index > 0;
|
|
13361
|
+
const canMoveDown = nextItem !== void 0;
|
|
13362
|
+
const isNested = onOutdent !== void 0;
|
|
13363
|
+
const getIndentUpTooltip = () => {
|
|
13364
|
+
if (!prevItem) return null;
|
|
13365
|
+
const typeLabel = prevItem.type === "folder" ? "pasta" : "grupo de texto";
|
|
13366
|
+
return isFolder ? prevItem.type === "folder" ? "Aninhar na pasta acima" : null : `Mover para dentro do ${typeLabel} acima`;
|
|
13367
|
+
};
|
|
13368
|
+
const getIndentDownTooltip = () => {
|
|
13369
|
+
if (!nextItem) return null;
|
|
13370
|
+
const typeLabel = nextItem.type === "folder" ? "pasta" : "grupo de texto";
|
|
13371
|
+
return isFolder ? nextItem.type === "folder" ? "Aninhar na pasta abaixo" : null : `Mover para dentro do ${typeLabel} abaixo`;
|
|
13372
|
+
};
|
|
13373
|
+
const showIndentUp = !!getIndentUpTooltip();
|
|
13374
|
+
const showIndentDown = !!getIndentDownTooltip();
|
|
13375
|
+
const handleContentChange = (content) => {
|
|
13376
|
+
onUpdate(item.id, { ...item, content });
|
|
13377
|
+
};
|
|
13378
|
+
const handleNameChange = (e) => {
|
|
13379
|
+
onUpdate(item.id, { ...item, name: e.target.value });
|
|
13380
|
+
};
|
|
13381
|
+
if (isFolder) {
|
|
13382
|
+
return /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col gap-2 mb-3 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React28.createElement(
|
|
13383
|
+
"div",
|
|
13358
13384
|
{
|
|
13359
|
-
onClick: () =>
|
|
13360
|
-
className: "
|
|
13361
|
-
title: "Remover Grupo"
|
|
13385
|
+
onClick: () => onEnterFolder(item.id),
|
|
13386
|
+
className: "flex items-center gap-3 py-3 px-4 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 rounded-xl cursor-pointer transition-all duration-200 group/folder"
|
|
13362
13387
|
},
|
|
13363
|
-
/* @__PURE__ */ React28.createElement(
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13369
|
-
|
|
13370
|
-
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
onDelete,
|
|
13374
|
-
onAddSubgroup,
|
|
13375
|
-
onIndent,
|
|
13376
|
-
onOutdent,
|
|
13377
|
-
onPlayAncestry,
|
|
13378
|
-
availableMentionItems,
|
|
13379
|
-
canEdit
|
|
13380
|
-
}
|
|
13381
|
-
))));
|
|
13382
|
-
};
|
|
13383
|
-
function AncestryBoard({
|
|
13384
|
-
isOpen,
|
|
13385
|
-
onClose,
|
|
13386
|
-
onSelect,
|
|
13387
|
-
availableAncestries = [],
|
|
13388
|
-
availableNodes = [],
|
|
13389
|
-
initialGroups = [],
|
|
13390
|
-
onSave,
|
|
13391
|
-
userRole
|
|
13392
|
-
}) {
|
|
13393
|
-
const [groups, setGroups] = useState26([]);
|
|
13394
|
-
const [isLoaded, setIsLoaded] = useState26(false);
|
|
13395
|
-
const [saveStatus, setSaveStatus] = useState26("idle");
|
|
13396
|
-
const canEdit = useMemo12(() => {
|
|
13397
|
-
return userRole !== "viewer";
|
|
13398
|
-
}, [userRole]);
|
|
13399
|
-
useEffect23(() => {
|
|
13400
|
-
if (initialGroups && !isLoaded) {
|
|
13401
|
-
setGroups(initialGroups);
|
|
13402
|
-
setIsLoaded(true);
|
|
13403
|
-
}
|
|
13404
|
-
}, [initialGroups, isLoaded]);
|
|
13405
|
-
const nodeNamesMap = useMemo12(() => {
|
|
13406
|
-
const map = /* @__PURE__ */ new Map();
|
|
13407
|
-
if (availableNodes && Array.isArray(availableNodes)) {
|
|
13408
|
-
availableNodes.forEach((node) => {
|
|
13409
|
-
if (node && node.id) {
|
|
13410
|
-
map.set(String(node.id), node.name);
|
|
13388
|
+
/* @__PURE__ */ React28.createElement("div", { className: "w-10 h-10 rounded-lg bg-indigo-500/10 flex items-center justify-center text-indigo-400 group-hover/folder:scale-110 transition-transform" }, /* @__PURE__ */ React28.createElement(FiFolder3, { size: 20 })),
|
|
13389
|
+
/* @__PURE__ */ React28.createElement("div", { className: "flex-1 min-w-0" }, canEdit ? /* @__PURE__ */ React28.createElement(
|
|
13390
|
+
"input",
|
|
13391
|
+
{
|
|
13392
|
+
type: "text",
|
|
13393
|
+
value: item.name,
|
|
13394
|
+
onChange: handleNameChange,
|
|
13395
|
+
onClick: (e) => e.stopPropagation(),
|
|
13396
|
+
className: "bg-transparent border-none outline-none text-sm font-medium text-slate-200 w-full focus:text-white",
|
|
13397
|
+
placeholder: "Nome da pasta..."
|
|
13411
13398
|
}
|
|
13412
|
-
})
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13428
|
-
|
|
13429
|
-
|
|
13430
|
-
|
|
13431
|
-
|
|
13432
|
-
|
|
13433
|
-
|
|
13434
|
-
|
|
13435
|
-
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
|
|
13440
|
-
|
|
13441
|
-
|
|
13442
|
-
|
|
13443
|
-
|
|
13444
|
-
|
|
13445
|
-
|
|
13446
|
-
|
|
13447
|
-
|
|
13448
|
-
|
|
13449
|
-
|
|
13450
|
-
|
|
13451
|
-
|
|
13452
|
-
|
|
13453
|
-
|
|
13454
|
-
|
|
13455
|
-
|
|
13456
|
-
|
|
13457
|
-
|
|
13458
|
-
|
|
13459
|
-
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13399
|
+
) : /* @__PURE__ */ React28.createElement("span", { className: "text-sm font-medium text-slate-200" }, item.name), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-2 mt-0.5" }, /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider font-semibold" }, ((_a = item.children) == null ? void 0 : _a.length) || 0, " itens"))),
|
|
13400
|
+
/* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1.5 opacity-0 group-item/item:opacity-100 group-hover/folder:opacity-100 transition-opacity" }, canEdit && /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-0.5 bg-slate-900/80 backdrop-blur-sm p-1 rounded-lg border border-white/5 shadow-xl" }, /* @__PURE__ */ React28.createElement(Tooltip, { text: "Subir" }, /* @__PURE__ */ React28.createElement(
|
|
13401
|
+
"button",
|
|
13402
|
+
{
|
|
13403
|
+
onClick: (e) => {
|
|
13404
|
+
e.stopPropagation();
|
|
13405
|
+
onMoveUp(item.id);
|
|
13406
|
+
},
|
|
13407
|
+
disabled: !canMoveUp,
|
|
13408
|
+
className: `p-1.5 rounded transition-colors ${!canMoveUp ? "text-slate-800 cursor-not-allowed" : "text-slate-400 hover:text-white hover:bg-white/10"}`
|
|
13409
|
+
},
|
|
13410
|
+
/* @__PURE__ */ React28.createElement(FiArrowUp, { size: 14 })
|
|
13411
|
+
)), /* @__PURE__ */ React28.createElement(Tooltip, { text: "Descer" }, /* @__PURE__ */ React28.createElement(
|
|
13412
|
+
"button",
|
|
13413
|
+
{
|
|
13414
|
+
onClick: (e) => {
|
|
13415
|
+
e.stopPropagation();
|
|
13416
|
+
onMoveDown(item.id);
|
|
13417
|
+
},
|
|
13418
|
+
disabled: !canMoveDown,
|
|
13419
|
+
className: `p-1.5 rounded transition-colors ${!canMoveDown ? "text-slate-800 cursor-not-allowed" : "text-slate-400 hover:text-white hover:bg-white/10"}`
|
|
13420
|
+
},
|
|
13421
|
+
/* @__PURE__ */ React28.createElement(FiArrowDown, { size: 14 })
|
|
13422
|
+
)), /* @__PURE__ */ React28.createElement("div", { className: "w-px h-3 bg-white/10 mx-0.5" }), showIndentUp && /* @__PURE__ */ React28.createElement(Tooltip, { text: getIndentUpTooltip() }, /* @__PURE__ */ React28.createElement(
|
|
13423
|
+
"button",
|
|
13424
|
+
{
|
|
13425
|
+
onClick: (e) => {
|
|
13426
|
+
e.stopPropagation();
|
|
13427
|
+
onIndent(item.id);
|
|
13428
|
+
},
|
|
13429
|
+
className: "p-1.5 text-slate-400 hover:text-white hover:bg-white/10 rounded transition-colors"
|
|
13430
|
+
},
|
|
13431
|
+
/* @__PURE__ */ React28.createElement(FiArrowLeft3, { size: 14 })
|
|
13432
|
+
)), showIndentDown && /* @__PURE__ */ React28.createElement(Tooltip, { text: getIndentDownTooltip() }, /* @__PURE__ */ React28.createElement(
|
|
13433
|
+
"button",
|
|
13434
|
+
{
|
|
13435
|
+
onClick: (e) => {
|
|
13436
|
+
e.stopPropagation();
|
|
13437
|
+
onIndentDown(item.id);
|
|
13438
|
+
},
|
|
13439
|
+
className: "p-1.5 text-slate-400 hover:text-white hover:bg-white/10 rounded transition-colors"
|
|
13440
|
+
},
|
|
13441
|
+
/* @__PURE__ */ React28.createElement(FiArrowRight2, { size: 14 })
|
|
13442
|
+
)), !isAtRoot && /* @__PURE__ */ React28.createElement(Tooltip, { text: "Desaninhar / Recuar n\xEDvel" }, /* @__PURE__ */ React28.createElement(
|
|
13443
|
+
"button",
|
|
13444
|
+
{
|
|
13445
|
+
onClick: (e) => {
|
|
13446
|
+
e.stopPropagation();
|
|
13447
|
+
onOutdent(item.id);
|
|
13448
|
+
},
|
|
13449
|
+
disabled: !onOutdent,
|
|
13450
|
+
className: `p-1.5 rounded transition-colors ${!onOutdent ? "text-slate-800 cursor-not-allowed" : "text-slate-400 hover:text-white hover:bg-white/10"}`
|
|
13451
|
+
},
|
|
13452
|
+
/* @__PURE__ */ React28.createElement(FiCornerUpLeft3, { size: 14 })
|
|
13453
|
+
)), /* @__PURE__ */ React28.createElement("div", { className: "w-px h-3 bg-white/10 mx-0.5" }), /* @__PURE__ */ React28.createElement(Tooltip, { text: "Remover Pasta" }, /* @__PURE__ */ React28.createElement(
|
|
13454
|
+
"button",
|
|
13455
|
+
{
|
|
13456
|
+
onClick: (e) => {
|
|
13457
|
+
e.stopPropagation();
|
|
13458
|
+
onDelete(item.id);
|
|
13459
|
+
},
|
|
13460
|
+
className: "p-1.5 text-slate-500 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors"
|
|
13461
|
+
},
|
|
13462
|
+
/* @__PURE__ */ React28.createElement(FiTrash23, { size: 14 })
|
|
13463
|
+
))), /* @__PURE__ */ React28.createElement(FiChevronRight7, { className: "text-slate-500 group-hover/folder:translate-x-1 transition-transform" }))
|
|
13464
|
+
));
|
|
13465
|
+
}
|
|
13466
|
+
return /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React28.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col gap-2 py-2 px-3 transition-all duration-200 hover:bg-white/5 border-l-2 border-transparent hover:border-white/20" }, /* @__PURE__ */ React28.createElement(
|
|
13467
|
+
RichGroupEditor,
|
|
13468
|
+
{
|
|
13469
|
+
content: item.content,
|
|
13470
|
+
onChange: handleContentChange,
|
|
13471
|
+
onMentionClick,
|
|
13472
|
+
searchItems,
|
|
13473
|
+
readOnly: !canEdit,
|
|
13474
|
+
placeholder: "Escreva sobre este grupo de texto\u2026 ou @ para mencionar"
|
|
13475
|
+
}
|
|
13476
|
+
), canEdit && /* @__PURE__ */ React28.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React28.createElement(
|
|
13477
|
+
"button",
|
|
13478
|
+
{
|
|
13479
|
+
onClick: () => onAddSubgroup(item.id, "text_group"),
|
|
13480
|
+
className: "flex items-center gap-1 px-1.5 py-1 text-[10px] uppercase font-bold tracking-wider text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
|
|
13481
|
+
title: "Criar Subgrupo de Texto"
|
|
13482
|
+
},
|
|
13483
|
+
/* @__PURE__ */ React28.createElement(FiPlus10, { size: 12 }),
|
|
13484
|
+
/* @__PURE__ */ React28.createElement("span", null, "Subgrupo")
|
|
13485
|
+
)), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React28.createElement(Tooltip, { text: "Subir" }, /* @__PURE__ */ React28.createElement(
|
|
13486
|
+
"button",
|
|
13487
|
+
{
|
|
13488
|
+
onClick: () => onMoveUp(item.id),
|
|
13489
|
+
disabled: !canMoveUp,
|
|
13490
|
+
className: `p-1.5 rounded transition-colors ${!canMoveUp ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`
|
|
13491
|
+
},
|
|
13492
|
+
/* @__PURE__ */ React28.createElement(FiArrowUp, { size: 14 })
|
|
13493
|
+
)), /* @__PURE__ */ React28.createElement(Tooltip, { text: "Descer" }, /* @__PURE__ */ React28.createElement(
|
|
13494
|
+
"button",
|
|
13495
|
+
{
|
|
13496
|
+
onClick: () => onMoveDown(item.id),
|
|
13497
|
+
disabled: !canMoveDown,
|
|
13498
|
+
className: `p-1.5 rounded transition-colors ${!canMoveDown ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`
|
|
13499
|
+
},
|
|
13500
|
+
/* @__PURE__ */ React28.createElement(FiArrowDown, { size: 14 })
|
|
13501
|
+
)), /* @__PURE__ */ React28.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), showIndentUp && /* @__PURE__ */ React28.createElement(Tooltip, { text: getIndentUpTooltip() }, /* @__PURE__ */ React28.createElement(
|
|
13502
|
+
"button",
|
|
13503
|
+
{
|
|
13504
|
+
onClick: () => onIndent(item.id),
|
|
13505
|
+
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors"
|
|
13506
|
+
},
|
|
13507
|
+
/* @__PURE__ */ React28.createElement(FiArrowLeft3, { size: 14 })
|
|
13508
|
+
)), showIndentDown && /* @__PURE__ */ React28.createElement(Tooltip, { text: getIndentDownTooltip() }, /* @__PURE__ */ React28.createElement(
|
|
13509
|
+
"button",
|
|
13510
|
+
{
|
|
13511
|
+
onClick: () => onIndentDown(item.id),
|
|
13512
|
+
className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors"
|
|
13513
|
+
},
|
|
13514
|
+
/* @__PURE__ */ React28.createElement(FiArrowRight2, { size: 14 })
|
|
13515
|
+
)), !isAtRoot && /* @__PURE__ */ React28.createElement(Tooltip, { text: "Desaninhar / Recuar n\xEDvel" }, /* @__PURE__ */ React28.createElement(
|
|
13516
|
+
"button",
|
|
13517
|
+
{
|
|
13518
|
+
onClick: () => onOutdent(item.id),
|
|
13519
|
+
disabled: !onOutdent,
|
|
13520
|
+
className: `p-1.5 rounded transition-colors ${!onOutdent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`
|
|
13521
|
+
},
|
|
13522
|
+
/* @__PURE__ */ React28.createElement(FiCornerUpLeft3, { size: 14 })
|
|
13523
|
+
)), /* @__PURE__ */ React28.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React28.createElement(Tooltip, { text: "Remover Grupo de Texto" }, /* @__PURE__ */ React28.createElement(
|
|
13524
|
+
"button",
|
|
13525
|
+
{
|
|
13526
|
+
onClick: () => onDelete(item.id),
|
|
13527
|
+
className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors"
|
|
13528
|
+
},
|
|
13529
|
+
/* @__PURE__ */ React28.createElement(FiTrash23, { size: 14 })
|
|
13530
|
+
))))), item.children && item.children.length > 0 && /* @__PURE__ */ React28.createElement("div", { className: "ml-2" }, item.children.map((child, idx) => /* @__PURE__ */ React28.createElement(
|
|
13531
|
+
BoardItem,
|
|
13532
|
+
{
|
|
13533
|
+
key: child.id,
|
|
13534
|
+
index: idx,
|
|
13535
|
+
prevItem: item.children[idx - 1],
|
|
13536
|
+
nextItem: item.children[idx + 1],
|
|
13537
|
+
item: child,
|
|
13538
|
+
onUpdate,
|
|
13539
|
+
onDelete,
|
|
13540
|
+
onAddSubgroup,
|
|
13541
|
+
onIndent,
|
|
13542
|
+
onIndentDown,
|
|
13543
|
+
onOutdent,
|
|
13544
|
+
onMoveUp,
|
|
13545
|
+
onMoveDown,
|
|
13546
|
+
searchItems,
|
|
13547
|
+
onMentionClick,
|
|
13548
|
+
onEnterFolder,
|
|
13549
|
+
canEdit,
|
|
13550
|
+
isAtRoot: false
|
|
13551
|
+
}
|
|
13552
|
+
))));
|
|
13553
|
+
};
|
|
13554
|
+
function Boards({
|
|
13555
|
+
isOpen,
|
|
13556
|
+
onClose,
|
|
13557
|
+
onSelect,
|
|
13558
|
+
availableAncestries = [],
|
|
13559
|
+
availableNodes = [],
|
|
13560
|
+
initialBoardItems = [],
|
|
13561
|
+
onSave,
|
|
13562
|
+
userRole
|
|
13563
|
+
}) {
|
|
13564
|
+
const [boardItems, setBoardItems] = useState27([]);
|
|
13565
|
+
const [isLoaded, setIsLoaded] = useState27(false);
|
|
13566
|
+
const [saveStatus, setSaveStatus] = useState27("idle");
|
|
13567
|
+
const [navigationStack, setNavigationStack] = useState27([]);
|
|
13568
|
+
const lastSavedBoardItemsRef = useRef20(null);
|
|
13569
|
+
const canEdit = useMemo12(() => userRole !== "viewer", [userRole]);
|
|
13570
|
+
const sanitizeBoardItems = (list) => list.map((g) => ({
|
|
13571
|
+
id: g.id,
|
|
13572
|
+
type: g.type || "text_group",
|
|
13573
|
+
name: g.name || "",
|
|
13574
|
+
content: g.content || [],
|
|
13575
|
+
children: sanitizeBoardItems(g.children || [])
|
|
13576
|
+
}));
|
|
13577
|
+
useEffect23(() => {
|
|
13578
|
+
if (initialBoardItems && !isLoaded) {
|
|
13579
|
+
const hasLegacyTypes = (list) => list.some(
|
|
13580
|
+
(g) => g.type === "group" || hasLegacyTypes(g.children || [])
|
|
13581
|
+
);
|
|
13582
|
+
let preparedItems = [];
|
|
13583
|
+
if (hasLegacyTypes(initialBoardItems)) {
|
|
13584
|
+
console.warn("Legacy Boards detected. Resetting board to empty list.");
|
|
13585
|
+
preparedItems = [];
|
|
13586
|
+
} else {
|
|
13587
|
+
const prepare = (list) => list.map((g) => ({
|
|
13588
|
+
id: g.id || uuidv411(),
|
|
13589
|
+
type: g.type || "text_group",
|
|
13590
|
+
name: g.name || "",
|
|
13591
|
+
content: Array.isArray(g.content) ? g.content : [],
|
|
13592
|
+
children: prepare(g.children || [])
|
|
13593
|
+
}));
|
|
13594
|
+
preparedItems = prepare(initialBoardItems);
|
|
13595
|
+
}
|
|
13596
|
+
setBoardItems(preparedItems);
|
|
13597
|
+
lastSavedBoardItemsRef.current = JSON.stringify(
|
|
13598
|
+
sanitizeBoardItems(preparedItems)
|
|
13599
|
+
);
|
|
13600
|
+
setIsLoaded(true);
|
|
13601
|
+
}
|
|
13602
|
+
}, [initialBoardItems, isLoaded]);
|
|
13603
|
+
const allSearchableItems = useMemo12(() => {
|
|
13604
|
+
const items = [];
|
|
13605
|
+
availableAncestries.forEach((anc) => {
|
|
13606
|
+
items.push({
|
|
13607
|
+
...anc,
|
|
13608
|
+
id: String(anc.ancestry_id),
|
|
13609
|
+
type: "ancestry",
|
|
13610
|
+
searchLabel: anc.name || "",
|
|
13611
|
+
searchDesc: anc.description || ""
|
|
13612
|
+
});
|
|
13613
|
+
});
|
|
13614
|
+
availableNodes.forEach((node) => {
|
|
13615
|
+
var _a;
|
|
13616
|
+
let type = "node";
|
|
13617
|
+
if (node.is_quest) type = "quest";
|
|
13618
|
+
else if ((_a = node.version_node) == null ? void 0 : _a.is_version) type = "version";
|
|
13619
|
+
items.push({
|
|
13620
|
+
...node,
|
|
13621
|
+
id: String(node.id),
|
|
13622
|
+
type,
|
|
13623
|
+
searchLabel: node.name || node.raw_title || "",
|
|
13624
|
+
searchDesc: node.description || ""
|
|
13625
|
+
});
|
|
13626
|
+
});
|
|
13627
|
+
return items;
|
|
13628
|
+
}, [availableAncestries, availableNodes]);
|
|
13629
|
+
useEffect23(() => {
|
|
13630
|
+
if (!isLoaded || !onSave) return;
|
|
13631
|
+
const id = setTimeout(async () => {
|
|
13632
|
+
const currentSanitized = sanitizeBoardItems(boardItems);
|
|
13633
|
+
const currentJson = JSON.stringify(currentSanitized);
|
|
13634
|
+
if (currentJson === lastSavedBoardItemsRef.current) return;
|
|
13635
|
+
setSaveStatus("saving");
|
|
13636
|
+
try {
|
|
13637
|
+
await onSave(currentSanitized);
|
|
13638
|
+
lastSavedBoardItemsRef.current = currentJson;
|
|
13639
|
+
setSaveStatus("saved");
|
|
13640
|
+
setTimeout(() => setSaveStatus("idle"), 3e3);
|
|
13641
|
+
} catch (err) {
|
|
13642
|
+
console.error("Erro ao salvar board:", err);
|
|
13643
|
+
setSaveStatus("error");
|
|
13644
|
+
}
|
|
13645
|
+
}, 3e3);
|
|
13646
|
+
return () => clearTimeout(id);
|
|
13647
|
+
}, [boardItems, isLoaded, onSave]);
|
|
13648
|
+
const triggerInstantSave = async (updatedBoardItems) => {
|
|
13649
|
+
if (!onSave) return;
|
|
13650
|
+
const sanitized = sanitizeBoardItems(updatedBoardItems);
|
|
13651
|
+
const sanitizedJson = JSON.stringify(sanitized);
|
|
13652
|
+
lastSavedBoardItemsRef.current = sanitizedJson;
|
|
13653
|
+
setSaveStatus("saving");
|
|
13654
|
+
try {
|
|
13655
|
+
await onSave(sanitized);
|
|
13656
|
+
setSaveStatus("saved");
|
|
13657
|
+
setTimeout(() => setSaveStatus("idle"), 3e3);
|
|
13658
|
+
} catch (err) {
|
|
13659
|
+
console.error("Erro ao salvar board:", err);
|
|
13660
|
+
setSaveStatus("error");
|
|
13661
|
+
}
|
|
13662
|
+
};
|
|
13663
|
+
useEffect23(() => {
|
|
13664
|
+
if (!isOpen) return;
|
|
13665
|
+
const handler = (e) => {
|
|
13666
|
+
if (e.key === "Escape") {
|
|
13667
|
+
onClose();
|
|
13668
|
+
e.preventDefault();
|
|
13669
|
+
e.stopPropagation();
|
|
13475
13670
|
}
|
|
13476
13671
|
};
|
|
13477
|
-
window.addEventListener("keydown",
|
|
13478
|
-
return () => window.removeEventListener("keydown",
|
|
13672
|
+
window.addEventListener("keydown", handler);
|
|
13673
|
+
return () => window.removeEventListener("keydown", handler);
|
|
13479
13674
|
}, [isOpen, onClose]);
|
|
13480
|
-
const
|
|
13481
|
-
const
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
|
|
13675
|
+
const currentPath = useMemo12(() => {
|
|
13676
|
+
const path = [];
|
|
13677
|
+
let currentLevel = boardItems;
|
|
13678
|
+
for (const folderId of navigationStack) {
|
|
13679
|
+
const folder = currentLevel.find((f) => f.id === folderId);
|
|
13680
|
+
if (folder) {
|
|
13681
|
+
path.push(folder);
|
|
13682
|
+
currentLevel = folder.children;
|
|
13683
|
+
}
|
|
13684
|
+
}
|
|
13685
|
+
return path;
|
|
13686
|
+
}, [boardItems, navigationStack]);
|
|
13687
|
+
const currentBoardItems = useMemo12(() => {
|
|
13688
|
+
const lastFolder = currentPath[currentPath.length - 1];
|
|
13689
|
+
return lastFolder ? lastFolder.children : boardItems;
|
|
13690
|
+
}, [boardItems, currentPath]);
|
|
13691
|
+
const navigateUp = () => {
|
|
13692
|
+
setNavigationStack((prev) => prev.slice(0, -1));
|
|
13693
|
+
};
|
|
13694
|
+
const navigateTo = (folderId) => {
|
|
13695
|
+
setNavigationStack((prev) => [...prev, folderId]);
|
|
13696
|
+
};
|
|
13697
|
+
const navigateToBreadcrumb = (index) => {
|
|
13698
|
+
setNavigationStack((prev) => prev.slice(0, index + 1));
|
|
13699
|
+
};
|
|
13700
|
+
const navigateHome = () => {
|
|
13701
|
+
setNavigationStack([]);
|
|
13487
13702
|
};
|
|
13488
|
-
const
|
|
13489
|
-
const
|
|
13703
|
+
const handleAddItem = (type = "text_group") => {
|
|
13704
|
+
const newItem = {
|
|
13490
13705
|
id: uuidv411(),
|
|
13491
|
-
|
|
13706
|
+
type,
|
|
13707
|
+
name: type === "folder" ? "Nova Pasta" : "",
|
|
13708
|
+
content: [],
|
|
13492
13709
|
children: []
|
|
13493
13710
|
};
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13711
|
+
if (navigationStack.length === 0) {
|
|
13712
|
+
setBoardItems((prev) => [...prev, newItem]);
|
|
13713
|
+
} else {
|
|
13714
|
+
const parentId = navigationStack[navigationStack.length - 1];
|
|
13715
|
+
const add = (list) => list.map(
|
|
13716
|
+
(g) => g.id === parentId ? { ...g, children: [...g.children, newItem] } : { ...g, children: add(g.children) }
|
|
13717
|
+
);
|
|
13718
|
+
setBoardItems((prev) => add(prev));
|
|
13719
|
+
}
|
|
13503
13720
|
};
|
|
13504
|
-
const
|
|
13505
|
-
const
|
|
13506
|
-
|
|
13507
|
-
if (g.
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
|
|
13721
|
+
const handleAddSubgroup = (parentId, type = "text_group") => {
|
|
13722
|
+
const add = (list) => list.map((g) => {
|
|
13723
|
+
if (g.id === parentId) {
|
|
13724
|
+
if (g.type === "text_group" && type === "folder") return g;
|
|
13725
|
+
const newItem = {
|
|
13726
|
+
id: uuidv411(),
|
|
13727
|
+
type,
|
|
13728
|
+
name: type === "folder" ? "Nova Pasta" : "",
|
|
13729
|
+
content: [],
|
|
13730
|
+
children: []
|
|
13731
|
+
};
|
|
13732
|
+
return { ...g, children: [...g.children, newItem] };
|
|
13733
|
+
}
|
|
13734
|
+
return { ...g, children: add(g.children) };
|
|
13735
|
+
});
|
|
13736
|
+
setBoardItems((prev) => add(prev));
|
|
13512
13737
|
};
|
|
13513
|
-
const
|
|
13514
|
-
const
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13738
|
+
const handleUpdateItem = (id, newData) => {
|
|
13739
|
+
const update = (list) => list.map(
|
|
13740
|
+
(g) => g.id === id ? newData : { ...g, children: update(g.children) }
|
|
13741
|
+
);
|
|
13742
|
+
setBoardItems((prev) => update(prev));
|
|
13743
|
+
};
|
|
13744
|
+
const handleDeleteItem = (id) => {
|
|
13745
|
+
const del = (list) => list.filter((g) => g.id !== id).map((g) => ({ ...g, children: del(g.children) }));
|
|
13746
|
+
setBoardItems((prev) => del(prev));
|
|
13521
13747
|
};
|
|
13522
13748
|
const findGroupAndParent = (list, targetId, parent = null) => {
|
|
13523
13749
|
for (let i = 0; i < list.length; i++) {
|
|
13524
|
-
if (list[i].id === targetId)
|
|
13750
|
+
if (list[i].id === targetId)
|
|
13525
13751
|
return { group: list[i], parent, index: i, siblings: list };
|
|
13526
|
-
}
|
|
13527
13752
|
if (list[i].children.length > 0) {
|
|
13528
13753
|
const found = findGroupAndParent(list[i].children, targetId, list[i]);
|
|
13529
13754
|
if (found) return found;
|
|
@@ -13532,47 +13757,72 @@ function AncestryBoard({
|
|
|
13532
13757
|
return null;
|
|
13533
13758
|
};
|
|
13534
13759
|
const handleIndent = (id) => {
|
|
13535
|
-
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13760
|
+
const next = JSON.parse(JSON.stringify(boardItems));
|
|
13761
|
+
const found = findGroupAndParent(next, id);
|
|
13762
|
+
if (!found || found.index === 0) return;
|
|
13763
|
+
const { group, siblings, index } = found;
|
|
13764
|
+
const targetParent = siblings[index - 1];
|
|
13765
|
+
if (group.type === "folder" && targetParent.type === "text_group") {
|
|
13766
|
+
return;
|
|
13767
|
+
}
|
|
13768
|
+
siblings.splice(index, 1);
|
|
13769
|
+
targetParent.children.push(group);
|
|
13770
|
+
setBoardItems(next);
|
|
13771
|
+
triggerInstantSave(next);
|
|
13545
13772
|
};
|
|
13546
|
-
const
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
return newList;
|
|
13560
|
-
});
|
|
13773
|
+
const handleIndentDown = (id) => {
|
|
13774
|
+
const next = JSON.parse(JSON.stringify(boardItems));
|
|
13775
|
+
const found = findGroupAndParent(next, id);
|
|
13776
|
+
if (!found || found.index === found.siblings.length - 1) return;
|
|
13777
|
+
const { group, siblings, index } = found;
|
|
13778
|
+
const targetParent = siblings[index + 1];
|
|
13779
|
+
if (group.type === "folder" && targetParent.type === "text_group") {
|
|
13780
|
+
return;
|
|
13781
|
+
}
|
|
13782
|
+
siblings.splice(index, 1);
|
|
13783
|
+
targetParent.children.push(group);
|
|
13784
|
+
setBoardItems(next);
|
|
13785
|
+
triggerInstantSave(next);
|
|
13561
13786
|
};
|
|
13562
|
-
const
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13787
|
+
const handleOutdent = (id) => {
|
|
13788
|
+
const next = JSON.parse(JSON.stringify(boardItems));
|
|
13789
|
+
const found = findGroupAndParent(next, id);
|
|
13790
|
+
if (!found || !found.parent) return;
|
|
13791
|
+
const { group, siblings, index, parent } = found;
|
|
13792
|
+
siblings.splice(index, 1);
|
|
13793
|
+
const parentFound = findGroupAndParent(next, parent.id);
|
|
13794
|
+
if (parentFound) {
|
|
13795
|
+
parentFound.siblings.splice(parentFound.index + 1, 0, group);
|
|
13568
13796
|
} else {
|
|
13569
|
-
|
|
13570
|
-
(n) => String(n.id) === String(item.id)
|
|
13571
|
-
) || item;
|
|
13572
|
-
}
|
|
13573
|
-
if (fullItem && onSelect) {
|
|
13574
|
-
onSelect(fullItem);
|
|
13797
|
+
next.push(group);
|
|
13575
13798
|
}
|
|
13799
|
+
setBoardItems(next);
|
|
13800
|
+
triggerInstantSave(next);
|
|
13801
|
+
};
|
|
13802
|
+
const handleMoveUp = (id) => {
|
|
13803
|
+
const next = JSON.parse(JSON.stringify(boardItems));
|
|
13804
|
+
const found = findGroupAndParent(next, id);
|
|
13805
|
+
if (!found || found.index === 0) return;
|
|
13806
|
+
const { siblings, index } = found;
|
|
13807
|
+
const item = siblings[index];
|
|
13808
|
+
siblings.splice(index, 1);
|
|
13809
|
+
siblings.splice(index - 1, 0, item);
|
|
13810
|
+
setBoardItems(next);
|
|
13811
|
+
triggerInstantSave(next);
|
|
13812
|
+
};
|
|
13813
|
+
const handleMoveDown = (id) => {
|
|
13814
|
+
const next = JSON.parse(JSON.stringify(boardItems));
|
|
13815
|
+
const found = findGroupAndParent(next, id);
|
|
13816
|
+
if (!found || found.index === found.siblings.length - 1) return;
|
|
13817
|
+
const { siblings, index } = found;
|
|
13818
|
+
const item = siblings[index];
|
|
13819
|
+
siblings.splice(index, 1);
|
|
13820
|
+
siblings.splice(index + 1, 0, item);
|
|
13821
|
+
setBoardItems(next);
|
|
13822
|
+
triggerInstantSave(next);
|
|
13823
|
+
};
|
|
13824
|
+
const handleMentionClick = (item) => {
|
|
13825
|
+
if (onSelect) onSelect(item);
|
|
13576
13826
|
};
|
|
13577
13827
|
if (!isOpen) return null;
|
|
13578
13828
|
return /* @__PURE__ */ React28.createElement(
|
|
@@ -13584,61 +13834,92 @@ function AncestryBoard({
|
|
|
13584
13834
|
/* @__PURE__ */ React28.createElement(
|
|
13585
13835
|
"div",
|
|
13586
13836
|
{
|
|
13587
|
-
className: "bg-slate-950 border border-white/10 rounded-xl w-
|
|
13837
|
+
className: "bg-slate-950 border border-white/10 rounded-xl w-full max-w-[calc(100vw-32px)] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
|
|
13588
13838
|
onClick: (e) => e.stopPropagation()
|
|
13589
13839
|
},
|
|
13590
|
-
/* @__PURE__ */ React28.createElement("div", { className: "h-14 px-
|
|
13840
|
+
/* @__PURE__ */ React28.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React28.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React28.createElement(FiLayers7, { className: "text-indigo-400" }), "Boards"), saveStatus !== "idle" && /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React28.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(
|
|
13591
13841
|
FiLoader5,
|
|
13592
13842
|
{
|
|
13593
13843
|
className: "animate-spin text-indigo-400",
|
|
13594
13844
|
size: 12
|
|
13595
13845
|
}
|
|
13596
|
-
), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ React28.createElement(
|
|
13846
|
+
), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(
|
|
13597
13847
|
"button",
|
|
13598
13848
|
{
|
|
13599
|
-
onClick:
|
|
13600
|
-
className: "
|
|
13849
|
+
onClick: () => handleAddItem("folder"),
|
|
13850
|
+
className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
|
|
13601
13851
|
},
|
|
13602
|
-
/* @__PURE__ */ React28.createElement(FiPlus10, { size: 14, className: "text-
|
|
13603
|
-
/* @__PURE__ */ React28.createElement("span", { className: "hidden sm:inline" }, "
|
|
13852
|
+
/* @__PURE__ */ React28.createElement(FiPlus10, { size: 14, className: "text-amber-400" }),
|
|
13853
|
+
/* @__PURE__ */ React28.createElement("span", { className: "hidden sm:inline" }, "Pasta")
|
|
13604
13854
|
), /* @__PURE__ */ React28.createElement(
|
|
13855
|
+
"button",
|
|
13856
|
+
{
|
|
13857
|
+
onClick: () => handleAddItem("text_group"),
|
|
13858
|
+
className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
|
|
13859
|
+
},
|
|
13860
|
+
/* @__PURE__ */ React28.createElement(FiPlus10, { size: 14, className: "text-indigo-400" }),
|
|
13861
|
+
/* @__PURE__ */ React28.createElement("span", { className: "hidden sm:inline" }, "Texto")
|
|
13862
|
+
)), /* @__PURE__ */ React28.createElement(
|
|
13605
13863
|
"button",
|
|
13606
13864
|
{
|
|
13607
13865
|
onClick: onClose,
|
|
13608
13866
|
className: "w-8 h-8 rounded-lg flex items-center justify-center text-slate-400 hover:text-white hover:bg-white/10 transition-colors"
|
|
13609
13867
|
},
|
|
13610
|
-
|
|
13868
|
+
/* @__PURE__ */ React28.createElement(FiX8, { size: 16 })
|
|
13611
13869
|
))),
|
|
13612
|
-
/* @__PURE__ */ React28.createElement("div", { className: "
|
|
13870
|
+
/* @__PURE__ */ React28.createElement("div", { className: "h-10 px-6 bg-slate-900/40 border-b border-white/5 flex items-center gap-2 text-[10px] uppercase font-bold tracking-widest text-slate-500 overflow-x-auto no-scrollbar whitespace-nowrap" }, /* @__PURE__ */ React28.createElement(
|
|
13613
13871
|
"button",
|
|
13614
13872
|
{
|
|
13615
|
-
onClick:
|
|
13616
|
-
className:
|
|
13873
|
+
onClick: navigateHome,
|
|
13874
|
+
className: `hover:text-white transition-colors flex items-center gap-1 ${navigationStack.length === 0 ? "text-indigo-400" : ""}`
|
|
13617
13875
|
},
|
|
13618
|
-
"
|
|
13619
|
-
)
|
|
13620
|
-
|
|
13876
|
+
"Home"
|
|
13877
|
+
), currentPath.map((folder, idx) => /* @__PURE__ */ React28.createElement(React28.Fragment, { key: folder.id }, /* @__PURE__ */ React28.createElement(FiChevronRight7, { size: 10, className: "shrink-0" }), /* @__PURE__ */ React28.createElement(
|
|
13878
|
+
"button",
|
|
13621
13879
|
{
|
|
13622
|
-
|
|
13880
|
+
onClick: () => navigateToBreadcrumb(idx),
|
|
13881
|
+
className: `hover:text-white transition-colors ${idx === currentPath.length - 1 ? "text-indigo-400" : ""}`
|
|
13882
|
+
},
|
|
13883
|
+
folder.name || "Sem Nome"
|
|
13884
|
+
))), navigationStack.length > 0 && /* @__PURE__ */ React28.createElement("div", { className: "ml-auto" }, /* @__PURE__ */ React28.createElement(
|
|
13885
|
+
"button",
|
|
13886
|
+
{
|
|
13887
|
+
onClick: navigateUp,
|
|
13888
|
+
className: "flex items-center gap-1 px-2 py-1 rounded bg-white/5 hover:bg-white/10 text-slate-400 hover:text-white transition-all"
|
|
13889
|
+
},
|
|
13890
|
+
/* @__PURE__ */ React28.createElement(FiArrowLeft3, { size: 10 }),
|
|
13891
|
+
/* @__PURE__ */ React28.createElement("span", null, "Voltar")
|
|
13892
|
+
))),
|
|
13893
|
+
/* @__PURE__ */ React28.createElement("div", { className: "flex-1 overflow-y-auto overflow-x-hidden custom-scrollbar bg-slate-950/30 p-6 space-y-4" }, currentBoardItems.length === 0 ? /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl bg-slate-900/20" }, /* @__PURE__ */ React28.createElement(FiLayers7, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React28.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React28.createElement(React28.Fragment, null, "Esta pasta est\xE1 vazia.", /* @__PURE__ */ React28.createElement("br", null), "Use os bot\xF5es acima para criar conte\xFAdo.") : /* @__PURE__ */ React28.createElement(React28.Fragment, null, "Nenhum conte\xFAdo dispon\xEDvel nesta pasta."))) : currentBoardItems.map((item, index) => /* @__PURE__ */ React28.createElement(
|
|
13894
|
+
BoardItem,
|
|
13895
|
+
{
|
|
13896
|
+
key: item.id,
|
|
13623
13897
|
index,
|
|
13624
|
-
|
|
13625
|
-
|
|
13626
|
-
|
|
13898
|
+
prevItem: currentBoardItems[index - 1],
|
|
13899
|
+
nextItem: currentBoardItems[index + 1],
|
|
13900
|
+
item,
|
|
13901
|
+
onUpdate: handleUpdateItem,
|
|
13902
|
+
onDelete: handleDeleteItem,
|
|
13627
13903
|
onAddSubgroup: handleAddSubgroup,
|
|
13628
13904
|
onIndent: handleIndent,
|
|
13905
|
+
onIndentDown: handleIndentDown,
|
|
13629
13906
|
onOutdent: handleOutdent,
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13907
|
+
onMoveUp: handleMoveUp,
|
|
13908
|
+
onMoveDown: handleMoveDown,
|
|
13909
|
+
searchItems: allSearchableItems,
|
|
13910
|
+
onMentionClick: handleMentionClick,
|
|
13911
|
+
onEnterFolder: navigateTo,
|
|
13912
|
+
canEdit,
|
|
13913
|
+
isAtRoot: navigationStack.length === 0
|
|
13633
13914
|
}
|
|
13634
|
-
)))
|
|
13635
|
-
/* @__PURE__ */ React28.createElement("div", { className: "px-
|
|
13915
|
+
))),
|
|
13916
|
+
/* @__PURE__ */ React28.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-end flex-shrink-0" }, /* @__PURE__ */ React28.createElement("span", null, currentBoardItems.length, " itens nesta visualiza\xE7\xE3o"))
|
|
13636
13917
|
)
|
|
13637
13918
|
);
|
|
13638
13919
|
}
|
|
13639
13920
|
|
|
13640
13921
|
// src/components/MilestoneManager.jsx
|
|
13641
|
-
import React29, { useState as
|
|
13922
|
+
import React29, { useState as useState28 } from "react";
|
|
13642
13923
|
import { FiTarget as FiTarget4, FiPlus as FiPlus11, FiTrash2 as FiTrash24, FiX as FiX9, FiCheck as FiCheck12, FiPauseCircle, FiPlayCircle } from "react-icons/fi";
|
|
13643
13924
|
function MilestoneManager({
|
|
13644
13925
|
isOpen,
|
|
@@ -13647,7 +13928,7 @@ function MilestoneManager({
|
|
|
13647
13928
|
onUpdateMilestones = () => {
|
|
13648
13929
|
}
|
|
13649
13930
|
}) {
|
|
13650
|
-
const [newMilestoneName, setNewMilestoneName] =
|
|
13931
|
+
const [newMilestoneName, setNewMilestoneName] = useState28("");
|
|
13651
13932
|
const handleAddMilestone = () => {
|
|
13652
13933
|
if (!newMilestoneName.trim()) return;
|
|
13653
13934
|
const newMilestone = {
|
|
@@ -13821,14 +14102,14 @@ function XViewScene({
|
|
|
13821
14102
|
get_ancestry_file,
|
|
13822
14103
|
import_parent_file_modal_get,
|
|
13823
14104
|
add_new_parent_file_to_scene_at_firebase_action,
|
|
13824
|
-
|
|
13825
|
-
|
|
14105
|
+
get_boards_action,
|
|
14106
|
+
save_boards_action,
|
|
13826
14107
|
upload_file_action,
|
|
13827
14108
|
delete_file_action,
|
|
13828
14109
|
check_user_permission,
|
|
13829
14110
|
get_view_members
|
|
13830
14111
|
}) {
|
|
13831
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l
|
|
14112
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
13832
14113
|
const { data: session, status } = useSession();
|
|
13833
14114
|
const router = useRouter();
|
|
13834
14115
|
const searchParams = useSearchParams();
|
|
@@ -13900,45 +14181,45 @@ function XViewScene({
|
|
|
13900
14181
|
}
|
|
13901
14182
|
return null;
|
|
13902
14183
|
}, [ownerId, sceneConfigId]);
|
|
13903
|
-
const sceneDataRef =
|
|
13904
|
-
const parentDataRef =
|
|
13905
|
-
const ancestryDataRef =
|
|
13906
|
-
const [isLoading, setIsLoading] =
|
|
13907
|
-
const [permissionStatus, setPermissionStatus] =
|
|
13908
|
-
const [userPermissionRole, setUserPermissionRole] =
|
|
13909
|
-
const [viewMembers, setViewMembers] =
|
|
13910
|
-
const [isInitialized, setIsInitialized] =
|
|
13911
|
-
const [sceneVersion, setSceneVersion] =
|
|
13912
|
-
const [contextMenu, setContextMenu] =
|
|
14184
|
+
const sceneDataRef = useRef21(null);
|
|
14185
|
+
const parentDataRef = useRef21(null);
|
|
14186
|
+
const ancestryDataRef = useRef21(null);
|
|
14187
|
+
const [isLoading, setIsLoading] = useState29(true);
|
|
14188
|
+
const [permissionStatus, setPermissionStatus] = useState29("loading");
|
|
14189
|
+
const [userPermissionRole, setUserPermissionRole] = useState29(null);
|
|
14190
|
+
const [viewMembers, setViewMembers] = useState29([]);
|
|
14191
|
+
const [isInitialized, setIsInitialized] = useState29(false);
|
|
14192
|
+
const [sceneVersion, setSceneVersion] = useState29(0);
|
|
14193
|
+
const [contextMenu, setContextMenu] = useState29({
|
|
13913
14194
|
visible: false,
|
|
13914
14195
|
x: 0,
|
|
13915
14196
|
y: 0,
|
|
13916
14197
|
nodeData: null
|
|
13917
14198
|
});
|
|
13918
|
-
const [multiContextMenu, setMultiContextMenu] =
|
|
14199
|
+
const [multiContextMenu, setMultiContextMenu] = useState29({
|
|
13919
14200
|
visible: false,
|
|
13920
14201
|
x: 0,
|
|
13921
14202
|
y: 0,
|
|
13922
14203
|
nodeIds: null
|
|
13923
14204
|
});
|
|
13924
|
-
const [relationshipMenu, setRelationshipMenu] =
|
|
14205
|
+
const [relationshipMenu, setRelationshipMenu] = useState29({
|
|
13925
14206
|
visible: false,
|
|
13926
14207
|
x: 0,
|
|
13927
14208
|
y: 0,
|
|
13928
14209
|
linkObject: null
|
|
13929
14210
|
});
|
|
13930
|
-
const [creationMode, setCreationMode] =
|
|
14211
|
+
const [creationMode, setCreationMode] = useState29({
|
|
13931
14212
|
isActive: false,
|
|
13932
14213
|
sourceNodeData: null
|
|
13933
14214
|
});
|
|
13934
|
-
const [versionMode, setVersionMode] =
|
|
14215
|
+
const [versionMode, setVersionMode] = useState29({
|
|
13935
14216
|
isActive: false,
|
|
13936
14217
|
sourceNodeData: null
|
|
13937
14218
|
});
|
|
13938
|
-
const [questMode, setQuestMode] =
|
|
13939
|
-
const [hasFocusedInitial, setHasFocusedInitial] =
|
|
13940
|
-
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] =
|
|
13941
|
-
const [ancestryMode, setAncestryMode] =
|
|
14219
|
+
const [questMode, setQuestMode] = useState29({ isActive: false });
|
|
14220
|
+
const [hasFocusedInitial, setHasFocusedInitial] = useState29(false);
|
|
14221
|
+
const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState29(false);
|
|
14222
|
+
const [ancestryMode, setAncestryMode] = useState29({
|
|
13942
14223
|
isActive: false,
|
|
13943
14224
|
tree: null,
|
|
13944
14225
|
selectedParentId: null,
|
|
@@ -13949,42 +14230,42 @@ function XViewScene({
|
|
|
13949
14230
|
ancestryDescriptionSections: [],
|
|
13950
14231
|
isAddingNodes: false
|
|
13951
14232
|
});
|
|
13952
|
-
const [readingMode, setReadingMode] =
|
|
14233
|
+
const [readingMode, setReadingMode] = useState29({
|
|
13953
14234
|
isActive: false,
|
|
13954
14235
|
ancestry: null,
|
|
13955
14236
|
branchStack: [],
|
|
13956
14237
|
autoAbstraction: false
|
|
13957
14238
|
});
|
|
13958
|
-
const [formPosition, setFormPosition] =
|
|
14239
|
+
const [formPosition, setFormPosition] = useState29({
|
|
13959
14240
|
left: 16,
|
|
13960
14241
|
top: 16,
|
|
13961
14242
|
opacity: 0
|
|
13962
14243
|
});
|
|
13963
|
-
const [detailsNode, setDetailsNode] =
|
|
13964
|
-
const [detailsLink, setDetailsLink] =
|
|
13965
|
-
const [ancestryLinkDetails, setAncestryLinkDetails] =
|
|
13966
|
-
const [imageViewer, setImageViewer] =
|
|
14244
|
+
const [detailsNode, setDetailsNode] = useState29(null);
|
|
14245
|
+
const [detailsLink, setDetailsLink] = useState29(null);
|
|
14246
|
+
const [ancestryLinkDetails, setAncestryLinkDetails] = useState29(null);
|
|
14247
|
+
const [imageViewer, setImageViewer] = useState29({
|
|
13967
14248
|
visible: false,
|
|
13968
14249
|
images: [],
|
|
13969
14250
|
startIndex: 0
|
|
13970
14251
|
});
|
|
13971
|
-
const [editingAncestryRel, setEditingAncestryRel] =
|
|
14252
|
+
const [editingAncestryRel, setEditingAncestryRel] = useState29({
|
|
13972
14253
|
visible: false,
|
|
13973
14254
|
data: null,
|
|
13974
14255
|
path: null
|
|
13975
14256
|
});
|
|
13976
|
-
const [isImportModalOpen, setIsImportModalOpen] =
|
|
13977
|
-
const [importSuccessMessage, setImportSuccessMessage] =
|
|
13978
|
-
const [invalidTargetError, setInvalidTargetError] =
|
|
13979
|
-
const [highlightedNodeId, setHighlightedNodeId] =
|
|
13980
|
-
const [
|
|
13981
|
-
const [
|
|
13982
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
13983
|
-
const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] =
|
|
13984
|
-
const mountRef =
|
|
13985
|
-
const tooltipRef =
|
|
13986
|
-
const formRef =
|
|
13987
|
-
const stateRef =
|
|
14257
|
+
const [isImportModalOpen, setIsImportModalOpen] = useState29(false);
|
|
14258
|
+
const [importSuccessMessage, setImportSuccessMessage] = useState29("");
|
|
14259
|
+
const [invalidTargetError, setInvalidTargetError] = useState29(null);
|
|
14260
|
+
const [highlightedNodeId, setHighlightedNodeId] = useState29(null);
|
|
14261
|
+
const [isBoardsOpen, setIsBoardsOpen] = useState29(false);
|
|
14262
|
+
const [boardItems, setBoardItems] = useState29([]);
|
|
14263
|
+
const [isSidebarOpen, setIsSidebarOpen] = useState29(false);
|
|
14264
|
+
const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] = useState29(false);
|
|
14265
|
+
const mountRef = useRef21(null);
|
|
14266
|
+
const tooltipRef = useRef21(null);
|
|
14267
|
+
const formRef = useRef21(null);
|
|
14268
|
+
const stateRef = useRef21({
|
|
13988
14269
|
readMode: {
|
|
13989
14270
|
currentMaxIndex: 0,
|
|
13990
14271
|
progressMap: {}
|
|
@@ -14074,10 +14355,10 @@ function XViewScene({
|
|
|
14074
14355
|
}
|
|
14075
14356
|
stateRef.current.nodeIdToParentFileMap = map;
|
|
14076
14357
|
}, [isInitialized, sceneVersion]);
|
|
14077
|
-
const handleNavigateBack =
|
|
14358
|
+
const handleNavigateBack = useCallback5(() => {
|
|
14078
14359
|
router.push("/dashboard/scenes");
|
|
14079
14360
|
}, [router]);
|
|
14080
|
-
const handleConfirmImport =
|
|
14361
|
+
const handleConfirmImport = useCallback5(
|
|
14081
14362
|
async (importPayload) => {
|
|
14082
14363
|
var _a2, _b2;
|
|
14083
14364
|
let files = [];
|
|
@@ -14205,7 +14486,7 @@ function XViewScene({
|
|
|
14205
14486
|
const handleOpenImageViewer = (images, startIndex) => {
|
|
14206
14487
|
setImageViewer({ visible: true, images, startIndex });
|
|
14207
14488
|
};
|
|
14208
|
-
const tweenToTarget =
|
|
14489
|
+
const tweenToTarget = useCallback5(
|
|
14209
14490
|
(target, zoomFactor = 1, forcedDirection = null) => {
|
|
14210
14491
|
const { camera, controls, tweenGroup } = stateRef.current;
|
|
14211
14492
|
if (!camera || !controls || !tweenGroup) return;
|
|
@@ -14231,7 +14512,7 @@ function XViewScene({
|
|
|
14231
14512
|
if (!t || typeof t.closest !== "function") return false;
|
|
14232
14513
|
return !!t.closest(".ui-overlay");
|
|
14233
14514
|
};
|
|
14234
|
-
const buildFullAncestryTree =
|
|
14515
|
+
const buildFullAncestryTree = useCallback5(
|
|
14235
14516
|
(idTree, nodes, ancestries = []) => {
|
|
14236
14517
|
if (!idTree) return null;
|
|
14237
14518
|
const nodeMap = new Map(nodes.map((n) => [String(n.id), n]));
|
|
@@ -14316,7 +14597,7 @@ function XViewScene({
|
|
|
14316
14597
|
},
|
|
14317
14598
|
[]
|
|
14318
14599
|
);
|
|
14319
|
-
const handleActivateTimeline =
|
|
14600
|
+
const handleActivateTimeline = useCallback5(() => {
|
|
14320
14601
|
const { nodeObjects, tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
14321
14602
|
if (!nodeObjects || !tweenGroup || !timelineIntervalsGroup) return;
|
|
14322
14603
|
while (timelineIntervalsGroup.children.length > 0) {
|
|
@@ -14476,7 +14757,7 @@ function XViewScene({
|
|
|
14476
14757
|
}
|
|
14477
14758
|
});
|
|
14478
14759
|
}, []);
|
|
14479
|
-
const handleVersionTimeline =
|
|
14760
|
+
const handleVersionTimeline = useCallback5((sourceMesh, versionMeshes) => {
|
|
14480
14761
|
const { tweenGroup, timelineIntervalsGroup } = stateRef.current;
|
|
14481
14762
|
if (!tweenGroup || !timelineIntervalsGroup || versionMeshes.length === 0)
|
|
14482
14763
|
return;
|
|
@@ -14632,7 +14913,7 @@ function XViewScene({
|
|
|
14632
14913
|
focusNodeId,
|
|
14633
14914
|
focusAncestryId
|
|
14634
14915
|
);
|
|
14635
|
-
const boardPromise =
|
|
14916
|
+
const boardPromise = get_boards_action && session ? get_boards_action(configPath, sceneType, session, ownerId2) : Promise.resolve({ success: false, data: [] });
|
|
14636
14917
|
const [sceneResponse, boardResponse] = await Promise.all([
|
|
14637
14918
|
scenePromise,
|
|
14638
14919
|
boardPromise
|
|
@@ -14683,10 +14964,10 @@ function XViewScene({
|
|
|
14683
14964
|
(sceneResponse == null ? void 0 : sceneResponse.error) || "Resposta inv\xE1lida."
|
|
14684
14965
|
);
|
|
14685
14966
|
}
|
|
14686
|
-
if (boardResponse
|
|
14687
|
-
|
|
14967
|
+
if (boardResponse.success && boardResponse.data) {
|
|
14968
|
+
setBoardItems(boardResponse.data);
|
|
14688
14969
|
} else {
|
|
14689
|
-
|
|
14970
|
+
setBoardItems([]);
|
|
14690
14971
|
}
|
|
14691
14972
|
} catch (error) {
|
|
14692
14973
|
console.error("Erro cr\xEDtico no carregamento inicial:", error);
|
|
@@ -14712,18 +14993,18 @@ function XViewScene({
|
|
|
14712
14993
|
ownerId,
|
|
14713
14994
|
viewParams,
|
|
14714
14995
|
get_scene_view_data,
|
|
14715
|
-
|
|
14996
|
+
get_boards_action,
|
|
14716
14997
|
isInitialized,
|
|
14717
14998
|
permissionStatus,
|
|
14718
14999
|
focusNodeId,
|
|
14719
15000
|
focusAncestryId
|
|
14720
15001
|
]);
|
|
14721
|
-
const isNodeInView =
|
|
15002
|
+
const isNodeInView = useCallback5((id) => {
|
|
14722
15003
|
const key = String(id);
|
|
14723
15004
|
const objs = stateRef.current.nodeObjects || {};
|
|
14724
15005
|
return !!objs[key];
|
|
14725
15006
|
}, []);
|
|
14726
|
-
const addOrUpdateNodeMesh =
|
|
15007
|
+
const addOrUpdateNodeMesh = useCallback5(
|
|
14727
15008
|
(nodeData, position, suppressVersionUpdate = false, forceShowQuestDate = false) => {
|
|
14728
15009
|
const {
|
|
14729
15010
|
graphGroup,
|
|
@@ -14764,7 +15045,7 @@ function XViewScene({
|
|
|
14764
15045
|
},
|
|
14765
15046
|
[]
|
|
14766
15047
|
);
|
|
14767
|
-
const handleActivateQuestLens =
|
|
15048
|
+
const handleActivateQuestLens = useCallback5(({ assigneeId, status: status2, milestoneId }) => {
|
|
14768
15049
|
var _a2;
|
|
14769
15050
|
const { nodeObjects, tweenGroup, graphGroup } = stateRef.current;
|
|
14770
15051
|
if (!nodeObjects || !tweenGroup || !graphGroup) return;
|
|
@@ -15734,7 +16015,7 @@ function XViewScene({
|
|
|
15734
16015
|
get_scene_view_data,
|
|
15735
16016
|
save_view_data
|
|
15736
16017
|
]);
|
|
15737
|
-
const handleGhostNodeImageChange =
|
|
16018
|
+
const handleGhostNodeImageChange = useCallback5((useImage, imageUrl) => {
|
|
15738
16019
|
const {
|
|
15739
16020
|
node: ghostNode,
|
|
15740
16021
|
line: ghostLine,
|
|
@@ -15782,7 +16063,7 @@ function XViewScene({
|
|
|
15782
16063
|
aura: newGhostNode.getObjectByName("aura")
|
|
15783
16064
|
};
|
|
15784
16065
|
}, []);
|
|
15785
|
-
const handleGhostNodeIntensityChange =
|
|
16066
|
+
const handleGhostNodeIntensityChange = useCallback5((newIntensity) => {
|
|
15786
16067
|
const { node: ghostNode, aura: ghostAura } = stateRef.current.ghostElements;
|
|
15787
16068
|
if (!ghostNode) return;
|
|
15788
16069
|
const adjustedIntensity = newIntensity + MIN_VISIBILITY_INTENSITY;
|
|
@@ -15803,7 +16084,7 @@ function XViewScene({
|
|
|
15803
16084
|
ghostAura.material.opacity = Math.min(0.8, newIntensity * 0.15);
|
|
15804
16085
|
}
|
|
15805
16086
|
}, []);
|
|
15806
|
-
const handleDetailNodeIntensityChange =
|
|
16087
|
+
const handleDetailNodeIntensityChange = useCallback5(
|
|
15807
16088
|
(nodeId, newIntensity) => {
|
|
15808
16089
|
const mesh = stateRef.current.nodeObjects[String(nodeId)];
|
|
15809
16090
|
if (!mesh) return;
|
|
@@ -15959,7 +16240,7 @@ function XViewScene({
|
|
|
15959
16240
|
mountRef.current.style.cursor = "default";
|
|
15960
16241
|
}
|
|
15961
16242
|
};
|
|
15962
|
-
const handleAncestryTreeUpdate =
|
|
16243
|
+
const handleAncestryTreeUpdate = useCallback5((newTree, extraData = null) => {
|
|
15963
16244
|
setAncestryMode((prev) => {
|
|
15964
16245
|
const prevTreeStr = JSON.stringify(prev.tree);
|
|
15965
16246
|
const newTreeStr = JSON.stringify(newTree);
|
|
@@ -16043,7 +16324,7 @@ function XViewScene({
|
|
|
16043
16324
|
const handleStartVersioning = (nodeData) => {
|
|
16044
16325
|
userActionHandlers.handleStartVersioning(actionHandlerContext, nodeData);
|
|
16045
16326
|
};
|
|
16046
|
-
const handleStartQuestQuick =
|
|
16327
|
+
const handleStartQuestQuick = useCallback5((questNode) => {
|
|
16047
16328
|
var _a2, _b2, _c2;
|
|
16048
16329
|
if (!questNode || !actionHandlerContext) return;
|
|
16049
16330
|
const allParentNodes = Object.values(parentDataRef.current).flatMap((fileData) => fileData.nodes || []);
|
|
@@ -16078,7 +16359,7 @@ function XViewScene({
|
|
|
16078
16359
|
}
|
|
16079
16360
|
setDetailsNode(updatedNode);
|
|
16080
16361
|
}, [session, actionHandlerContext]);
|
|
16081
|
-
const handleFinishQuestQuick =
|
|
16362
|
+
const handleFinishQuestQuick = useCallback5((questNode) => {
|
|
16082
16363
|
var _a2, _b2, _c2, _d2;
|
|
16083
16364
|
if (!questNode || !actionHandlerContext) return;
|
|
16084
16365
|
const {
|
|
@@ -16152,7 +16433,7 @@ function XViewScene({
|
|
|
16152
16433
|
setDetailsNode(null);
|
|
16153
16434
|
}
|
|
16154
16435
|
}, [session, actionHandlerContext, viewMembers, detailsNode]);
|
|
16155
|
-
const handleCancelQuest =
|
|
16436
|
+
const handleCancelQuest = useCallback5(() => {
|
|
16156
16437
|
const { graphGroup, ghostElements } = stateRef.current;
|
|
16157
16438
|
if (ghostElements.node && graphGroup) {
|
|
16158
16439
|
if (ghostElements.node.userData.labelObject) {
|
|
@@ -16211,13 +16492,15 @@ function XViewScene({
|
|
|
16211
16492
|
try {
|
|
16212
16493
|
await actions.save_view_data(sceneSaveUrl2, sceneFileData);
|
|
16213
16494
|
sceneDataRef2.current.quest_counter = currentCounter + 1;
|
|
16214
|
-
sceneDataRef2.current.quest_nodes = sceneFileData.quest_nodes;
|
|
16215
|
-
sceneDataRef2.current.quest_links = sceneFileData.quest_links;
|
|
16216
16495
|
stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
|
|
16217
16496
|
parentFileId: sceneConfigId2,
|
|
16218
16497
|
ownerId: ownerId2,
|
|
16219
16498
|
datasetName: "Quests Internas (View)"
|
|
16220
16499
|
});
|
|
16500
|
+
sceneDataRef2.current.quest_nodes = [...graphDataRef.current[sceneConfigId2].nodes];
|
|
16501
|
+
if (parentDataRef.current[sceneConfigId2]) {
|
|
16502
|
+
parentDataRef.current[sceneConfigId2].nodes = [...graphDataRef.current[sceneConfigId2].nodes];
|
|
16503
|
+
}
|
|
16221
16504
|
const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
|
|
16222
16505
|
const { graphGroup, ghostElements } = stateRef2.current;
|
|
16223
16506
|
if (ghostElements.node && graphGroup) {
|
|
@@ -16307,7 +16590,7 @@ function XViewScene({
|
|
|
16307
16590
|
}
|
|
16308
16591
|
userActionHandlers.handleCancelConnection(context);
|
|
16309
16592
|
};
|
|
16310
|
-
const handleClearAncestryVisuals =
|
|
16593
|
+
const handleClearAncestryVisuals = useCallback5((ancestryId) => {
|
|
16311
16594
|
const { renderedAncestries, ancestryGroup } = stateRef.current;
|
|
16312
16595
|
const renderIndex = renderedAncestries.findIndex(
|
|
16313
16596
|
(a) => String(a.id) === String(ancestryId)
|
|
@@ -16325,7 +16608,7 @@ function XViewScene({
|
|
|
16325
16608
|
);
|
|
16326
16609
|
}
|
|
16327
16610
|
}, []);
|
|
16328
|
-
const handleRenderAncestry =
|
|
16611
|
+
const handleRenderAncestry = useCallback5(
|
|
16329
16612
|
async (ancestryObject, allowedSectionIds = null, activeSectionIdForFocus = null, baseRotation = 0, forceReprocess = true) => {
|
|
16330
16613
|
setContextMenu(
|
|
16331
16614
|
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
@@ -16819,7 +17102,7 @@ function XViewScene({
|
|
|
16819
17102
|
ancestryMode.isActive
|
|
16820
17103
|
]
|
|
16821
17104
|
);
|
|
16822
|
-
const handleRenderAbstractionTree =
|
|
17105
|
+
const handleRenderAbstractionTree = useCallback5(
|
|
16823
17106
|
(ancestryObject, targetNodeId = null) => {
|
|
16824
17107
|
setContextMenu(
|
|
16825
17108
|
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
@@ -16907,7 +17190,7 @@ function XViewScene({
|
|
|
16907
17190
|
handleClearAncestryVisuals
|
|
16908
17191
|
]
|
|
16909
17192
|
);
|
|
16910
|
-
const handleReadModeBranchNav =
|
|
17193
|
+
const handleReadModeBranchNav = useCallback5(
|
|
16911
17194
|
(nodeId, action, direction = "right") => {
|
|
16912
17195
|
const { ancestry, branchStack } = readingMode;
|
|
16913
17196
|
if (!ancestry || !ancestry.tree) return;
|
|
@@ -17085,7 +17368,7 @@ function XViewScene({
|
|
|
17085
17368
|
},
|
|
17086
17369
|
[readingMode, handleRenderAncestry, buildFullAncestryTree, tweenToTarget]
|
|
17087
17370
|
);
|
|
17088
|
-
const handleReadModeHighlight =
|
|
17371
|
+
const handleReadModeHighlight = useCallback5((nodeId) => {
|
|
17089
17372
|
if (stateRef.current.highlightedNodeId !== nodeId) {
|
|
17090
17373
|
stateRef.current.highlightedNodeId = nodeId;
|
|
17091
17374
|
}
|
|
@@ -17208,7 +17491,7 @@ function XViewScene({
|
|
|
17208
17491
|
buildFullAncestryTree,
|
|
17209
17492
|
sceneVersion
|
|
17210
17493
|
]);
|
|
17211
|
-
const handleStartReadingAncestry =
|
|
17494
|
+
const handleStartReadingAncestry = useCallback5(
|
|
17212
17495
|
async (ancestryObject, renderMode = "full") => {
|
|
17213
17496
|
setContextMenu(
|
|
17214
17497
|
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
@@ -17251,7 +17534,7 @@ function XViewScene({
|
|
|
17251
17534
|
},
|
|
17252
17535
|
[handleRenderAncestry, handleRenderAbstractionTree]
|
|
17253
17536
|
);
|
|
17254
|
-
const handleReadModeSectionChange =
|
|
17537
|
+
const handleReadModeSectionChange = useCallback5(
|
|
17255
17538
|
(activeSectionId) => {
|
|
17256
17539
|
const { ancestry, branchStack } = readingMode;
|
|
17257
17540
|
if (!ancestry || !readingMode.isActive) return;
|
|
@@ -17336,10 +17619,10 @@ function XViewScene({
|
|
|
17336
17619
|
ancestryDataRef.current
|
|
17337
17620
|
]
|
|
17338
17621
|
);
|
|
17339
|
-
const handleCloseReadMode =
|
|
17622
|
+
const handleCloseReadMode = useCallback5(() => {
|
|
17340
17623
|
setReadingMode({ isActive: false, ancestry: null, branchStack: [] });
|
|
17341
17624
|
}, []);
|
|
17342
|
-
const handleAncestrySectionChange =
|
|
17625
|
+
const handleAncestrySectionChange = useCallback5(
|
|
17343
17626
|
(activeSectionId, ancestryOverride = null, rotation = 0) => {
|
|
17344
17627
|
var _a2, _b2;
|
|
17345
17628
|
const currentMode = stateRef.current.ancestry;
|
|
@@ -17401,7 +17684,7 @@ function XViewScene({
|
|
|
17401
17684
|
},
|
|
17402
17685
|
[handleRenderAncestry]
|
|
17403
17686
|
);
|
|
17404
|
-
const handleEditAncestry =
|
|
17687
|
+
const handleEditAncestry = useCallback5(
|
|
17405
17688
|
async (ancestryObject) => {
|
|
17406
17689
|
setContextMenu(
|
|
17407
17690
|
(prev) => prev.visible ? { ...prev, visible: false } : prev
|
|
@@ -17456,7 +17739,7 @@ function XViewScene({
|
|
|
17456
17739
|
const handleSelectAncestryParent = (nodeId) => {
|
|
17457
17740
|
setAncestryMode((prev) => ({ ...prev, selectedParentId: nodeId }));
|
|
17458
17741
|
};
|
|
17459
|
-
const handleRemoveFromAncestry =
|
|
17742
|
+
const handleRemoveFromAncestry = useCallback5((pathToRemove) => {
|
|
17460
17743
|
if (!Array.isArray(pathToRemove) || pathToRemove.length === 0) {
|
|
17461
17744
|
console.warn("Tentativa de remover a raiz ou caminho inv\xE1lido.");
|
|
17462
17745
|
return;
|
|
@@ -17481,7 +17764,7 @@ function XViewScene({
|
|
|
17481
17764
|
return { ...prev, tree: newTree };
|
|
17482
17765
|
});
|
|
17483
17766
|
}, []);
|
|
17484
|
-
const handleSaveAncestry =
|
|
17767
|
+
const handleSaveAncestry = useCallback5(
|
|
17485
17768
|
async (ancestryName, ancestryDescription, ancestrySections, keepOpen = false, treeOverride = null, ancestryCustomProps = {}) => {
|
|
17486
17769
|
const treeToUse = treeOverride || ancestryMode.tree;
|
|
17487
17770
|
const { isEditMode, currentAncestryId } = ancestryMode;
|
|
@@ -17717,7 +18000,7 @@ function XViewScene({
|
|
|
17717
18000
|
});
|
|
17718
18001
|
setEditingAncestryRel({ visible: false, data: null, path: null });
|
|
17719
18002
|
};
|
|
17720
|
-
const handleDeleteAncestry =
|
|
18003
|
+
const handleDeleteAncestry = useCallback5(
|
|
17721
18004
|
async (ancestryIdToDelete) => {
|
|
17722
18005
|
if (!ancestryIdToDelete) {
|
|
17723
18006
|
alert("ID da ancestralidade n\xE3o encontrado.");
|
|
@@ -17799,40 +18082,82 @@ function XViewScene({
|
|
|
17799
18082
|
},
|
|
17800
18083
|
[save_view_data, delete_file_action]
|
|
17801
18084
|
);
|
|
17802
|
-
const
|
|
17803
|
-
|
|
18085
|
+
const handleOpenBoards = useCallback5(() => {
|
|
18086
|
+
setIsBoardsOpen(true);
|
|
17804
18087
|
}, []);
|
|
17805
|
-
const
|
|
18088
|
+
const allAvailableNodes = useMemo13(() => {
|
|
18089
|
+
if (!parentDataRef.current) return [];
|
|
18090
|
+
return Object.values(parentDataRef.current).flatMap(
|
|
18091
|
+
(fileData) => fileData.nodes || []
|
|
18092
|
+
);
|
|
18093
|
+
}, [sceneVersion, isInitialized]);
|
|
18094
|
+
const allAvailableAncestries = useMemo13(() => {
|
|
18095
|
+
return ancestryDataRef.current || [];
|
|
18096
|
+
}, [sceneVersion, isInitialized]);
|
|
18097
|
+
const handleOpenReference = useCallback5(
|
|
18098
|
+
(referenceData) => {
|
|
18099
|
+
const { type, id } = referenceData;
|
|
18100
|
+
if (type === "node") {
|
|
18101
|
+
const targetNode = allAvailableNodes.find(
|
|
18102
|
+
(n) => String(n.id) === String(id)
|
|
18103
|
+
);
|
|
18104
|
+
if (targetNode) {
|
|
18105
|
+
setAncestryLinkDetails(null);
|
|
18106
|
+
setDetailsLink(null);
|
|
18107
|
+
setDetailsNode(targetNode);
|
|
18108
|
+
const sceneMesh = stateRef.current.nodeObjects[String(id)];
|
|
18109
|
+
if (sceneMesh) {
|
|
18110
|
+
tweenToTarget(sceneMesh);
|
|
18111
|
+
}
|
|
18112
|
+
} else {
|
|
18113
|
+
alert("Node original n\xE3o encontrado neste contexto.");
|
|
18114
|
+
}
|
|
18115
|
+
} else if (type === "ancestry") {
|
|
18116
|
+
const targetAncestry = allAvailableAncestries.find(
|
|
18117
|
+
(a) => String(a.ancestry_id) === String(id)
|
|
18118
|
+
);
|
|
18119
|
+
if (targetAncestry) {
|
|
18120
|
+
setDetailsNode(null);
|
|
18121
|
+
setDetailsLink(null);
|
|
18122
|
+
setAncestryLinkDetails(null);
|
|
18123
|
+
handleEditAncestry(targetAncestry);
|
|
18124
|
+
} else {
|
|
18125
|
+
alert("Ancestralidade original n\xE3o encontrada neste contexto.");
|
|
18126
|
+
}
|
|
18127
|
+
}
|
|
18128
|
+
},
|
|
18129
|
+
[
|
|
18130
|
+
allAvailableNodes,
|
|
18131
|
+
allAvailableAncestries,
|
|
18132
|
+
handleEditAncestry,
|
|
18133
|
+
tweenToTarget
|
|
18134
|
+
]
|
|
18135
|
+
);
|
|
18136
|
+
const handleSelectAncestryFromBoard = useCallback5(
|
|
17806
18137
|
(item) => {
|
|
17807
|
-
|
|
18138
|
+
setIsBoardsOpen(false);
|
|
17808
18139
|
setIsSidebarOpen(false);
|
|
17809
|
-
if (item.type === "ancestry"
|
|
18140
|
+
if (item.type === "ancestry") {
|
|
17810
18141
|
handleStartReadingAncestry(item);
|
|
17811
18142
|
} else {
|
|
17812
|
-
|
|
17813
|
-
const sceneMesh = stateRef.current.nodeObjects[nodeId];
|
|
17814
|
-
if (sceneMesh) {
|
|
17815
|
-
tweenToTarget(sceneMesh);
|
|
17816
|
-
} else {
|
|
17817
|
-
console.warn("Objeto n\xE3o encontrado na cena para foco:", nodeId);
|
|
17818
|
-
}
|
|
18143
|
+
handleOpenReference({ type: "node", id: item.id });
|
|
17819
18144
|
}
|
|
17820
18145
|
},
|
|
17821
|
-
[handleStartReadingAncestry,
|
|
18146
|
+
[handleStartReadingAncestry, handleOpenReference]
|
|
17822
18147
|
);
|
|
17823
|
-
const
|
|
17824
|
-
async (
|
|
18148
|
+
const handleSaveBoards = useCallback5(
|
|
18149
|
+
async (boardItems2) => {
|
|
17825
18150
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
17826
18151
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
17827
|
-
await
|
|
18152
|
+
await save_boards_action(
|
|
17828
18153
|
sceneConfigId,
|
|
17829
18154
|
sceneType,
|
|
17830
|
-
|
|
18155
|
+
boardItems2,
|
|
17831
18156
|
session,
|
|
17832
18157
|
ownerId
|
|
17833
18158
|
);
|
|
17834
18159
|
},
|
|
17835
|
-
[sceneConfigId, viewParams, session,
|
|
18160
|
+
[sceneConfigId, viewParams, session, save_boards_action, ownerId]
|
|
17836
18161
|
);
|
|
17837
18162
|
const existingNodeTypes = useMemo13(() => {
|
|
17838
18163
|
if (!parentDataRef.current) {
|
|
@@ -17847,27 +18172,21 @@ function XViewScene({
|
|
|
17847
18172
|
return [...new Set(allTypes)];
|
|
17848
18173
|
}, [parentDataRef.current, sceneVersion]);
|
|
17849
18174
|
const searchableDbNodes = useMemo13(() => {
|
|
17850
|
-
var _a2;
|
|
17851
18175
|
if (!parentDataRef.current) {
|
|
17852
18176
|
return [];
|
|
17853
18177
|
}
|
|
17854
|
-
|
|
18178
|
+
return Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
|
|
17855
18179
|
const datasetName = fileData.dataset_name || `Dataset #${dbId.substring(0, 6)}`;
|
|
17856
18180
|
return (fileData.nodes || []).map((node) => ({
|
|
17857
18181
|
...node,
|
|
17858
18182
|
dataset_name: datasetName
|
|
17859
18183
|
}));
|
|
18184
|
+
}).filter((node) => {
|
|
18185
|
+
var _a2;
|
|
18186
|
+
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
17860
18187
|
});
|
|
17861
|
-
|
|
17862
|
-
|
|
17863
|
-
dataset_name: "Quests Internas (View)"
|
|
17864
|
-
}));
|
|
17865
|
-
return [...datasetsPool, ...questsPool].filter((node) => {
|
|
17866
|
-
var _a3;
|
|
17867
|
-
return !((_a3 = node.version_node) == null ? void 0 : _a3.is_version);
|
|
17868
|
-
});
|
|
17869
|
-
}, [parentDataRef.current, (_b = sceneDataRef.current) == null ? void 0 : _b.quest_nodes, sceneVersion]);
|
|
17870
|
-
const handleAddExistingNode = useCallback4(
|
|
18188
|
+
}, [parentDataRef.current, sceneVersion]);
|
|
18189
|
+
const handleAddExistingNode = useCallback5(
|
|
17871
18190
|
(nodeId) => {
|
|
17872
18191
|
return userActionHandlers.handleAddExistingNodeById(
|
|
17873
18192
|
actionHandlerContext,
|
|
@@ -17876,7 +18195,7 @@ function XViewScene({
|
|
|
17876
18195
|
},
|
|
17877
18196
|
[actionHandlerContext]
|
|
17878
18197
|
);
|
|
17879
|
-
const handleUpdateMilestones =
|
|
18198
|
+
const handleUpdateMilestones = useCallback5(
|
|
17880
18199
|
async (newMilestones) => {
|
|
17881
18200
|
var _a2, _b2, _c2;
|
|
17882
18201
|
if (!sceneDataRef.current) return;
|
|
@@ -17922,7 +18241,7 @@ function XViewScene({
|
|
|
17922
18241
|
viewParams == null ? void 0 : viewParams.type
|
|
17923
18242
|
]
|
|
17924
18243
|
);
|
|
17925
|
-
const handleSaveCurrentView =
|
|
18244
|
+
const handleSaveCurrentView = useCallback5(async () => {
|
|
17926
18245
|
var _a2, _b2, _c2;
|
|
17927
18246
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
17928
18247
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
@@ -17965,61 +18284,13 @@ function XViewScene({
|
|
|
17965
18284
|
console.error("Erro na chamada de save_view_data:", error);
|
|
17966
18285
|
}
|
|
17967
18286
|
}, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
|
|
17968
|
-
const
|
|
17969
|
-
if (!parentDataRef.current) return [];
|
|
17970
|
-
return Object.values(parentDataRef.current).flatMap(
|
|
17971
|
-
(fileData) => fileData.nodes || []
|
|
17972
|
-
);
|
|
17973
|
-
}, [sceneVersion, isInitialized]);
|
|
17974
|
-
const allAvailableAncestries = useMemo13(() => {
|
|
17975
|
-
return ancestryDataRef.current || [];
|
|
17976
|
-
}, [sceneVersion, isInitialized]);
|
|
17977
|
-
const handleOpenReference = useCallback4(
|
|
17978
|
-
(referenceData) => {
|
|
17979
|
-
const { type, id } = referenceData;
|
|
17980
|
-
if (type === "node") {
|
|
17981
|
-
const targetNode = allAvailableNodes.find(
|
|
17982
|
-
(n) => String(n.id) === String(id)
|
|
17983
|
-
);
|
|
17984
|
-
if (targetNode) {
|
|
17985
|
-
setAncestryLinkDetails(null);
|
|
17986
|
-
setDetailsLink(null);
|
|
17987
|
-
setDetailsNode(targetNode);
|
|
17988
|
-
const sceneMesh = stateRef.current.nodeObjects[String(id)];
|
|
17989
|
-
if (sceneMesh) {
|
|
17990
|
-
tweenToTarget(sceneMesh);
|
|
17991
|
-
}
|
|
17992
|
-
} else {
|
|
17993
|
-
alert("Node original n\xE3o encontrado neste contexto.");
|
|
17994
|
-
}
|
|
17995
|
-
} else if (type === "ancestry") {
|
|
17996
|
-
const targetAncestry = allAvailableAncestries.find(
|
|
17997
|
-
(a) => String(a.ancestry_id) === String(id)
|
|
17998
|
-
);
|
|
17999
|
-
if (targetAncestry) {
|
|
18000
|
-
setDetailsNode(null);
|
|
18001
|
-
setDetailsLink(null);
|
|
18002
|
-
setAncestryLinkDetails(null);
|
|
18003
|
-
handleEditAncestry(targetAncestry);
|
|
18004
|
-
} else {
|
|
18005
|
-
alert("Ancestralidade original n\xE3o encontrada neste contexto.");
|
|
18006
|
-
}
|
|
18007
|
-
}
|
|
18008
|
-
},
|
|
18009
|
-
[
|
|
18010
|
-
allAvailableNodes,
|
|
18011
|
-
allAvailableAncestries,
|
|
18012
|
-
handleEditAncestry,
|
|
18013
|
-
tweenToTarget
|
|
18014
|
-
]
|
|
18015
|
-
);
|
|
18016
|
-
const handleToggleAncestryAddMode = useCallback4(() => {
|
|
18287
|
+
const handleToggleAncestryAddMode = useCallback5(() => {
|
|
18017
18288
|
setAncestryMode((prev) => ({
|
|
18018
18289
|
...prev,
|
|
18019
18290
|
isAddingNodes: !prev.isAddingNodes
|
|
18020
18291
|
}));
|
|
18021
18292
|
}, []);
|
|
18022
|
-
const handleFocusNode =
|
|
18293
|
+
const handleFocusNode = useCallback5(
|
|
18023
18294
|
(nodeData) => {
|
|
18024
18295
|
var _a2;
|
|
18025
18296
|
if (!nodeData) return;
|
|
@@ -18045,9 +18316,9 @@ function XViewScene({
|
|
|
18045
18316
|
};
|
|
18046
18317
|
});
|
|
18047
18318
|
}, [sceneVersion, isInitialized]);
|
|
18048
|
-
const sourceNodeDatasetId = creationMode.sourceNodeData ? (
|
|
18319
|
+
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
|
|
18049
18320
|
String(creationMode.sourceNodeData.id)
|
|
18050
|
-
)) == null ? void 0 :
|
|
18321
|
+
)) == null ? void 0 : _b.parentFileId : null;
|
|
18051
18322
|
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
18052
18323
|
useEffect24(() => {
|
|
18053
18324
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
@@ -18137,7 +18408,7 @@ function XViewScene({
|
|
|
18137
18408
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
18138
18409
|
}
|
|
18139
18410
|
if (event.key.toLowerCase() === "q") {
|
|
18140
|
-
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !
|
|
18411
|
+
const isUiClear = !stateRef.current.creation.isActive && !stateRef.current.connection.isActive && !stateRef.current.relink.isActive && !stateRef.current.ancestry.isActive && !((_b2 = context.versionMode) == null ? void 0 : _b2.isActive) && !contextMenu.visible && !multiContextMenu.visible && !relationshipMenu.visible && !readingMode.isActive && !isImportModalOpen && !isBoardsOpen && !isSidebarOpen && !detailsNode && !detailsLink && !ancestryLinkDetails && !imageViewer.visible && !editingAncestryRel.visible && !questMode.isActive;
|
|
18141
18412
|
if (isUiClear) {
|
|
18142
18413
|
const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
|
|
18143
18414
|
if (!isView) return;
|
|
@@ -18206,7 +18477,7 @@ function XViewScene({
|
|
|
18206
18477
|
relationshipMenu.visible,
|
|
18207
18478
|
readingMode.isActive,
|
|
18208
18479
|
isImportModalOpen,
|
|
18209
|
-
|
|
18480
|
+
isBoardsOpen,
|
|
18210
18481
|
isSidebarOpen,
|
|
18211
18482
|
detailsNode,
|
|
18212
18483
|
detailsLink,
|
|
@@ -18293,7 +18564,7 @@ function XViewScene({
|
|
|
18293
18564
|
importSuccessMessage,
|
|
18294
18565
|
onActivateTimeline: handleActivateTimeline,
|
|
18295
18566
|
onActivateQuestLens: handleActivateQuestLens,
|
|
18296
|
-
|
|
18567
|
+
onOpenBoards: handleOpenBoards,
|
|
18297
18568
|
viewType: viewParams == null ? void 0 : viewParams.type,
|
|
18298
18569
|
viewName: viewParams == null ? void 0 : viewParams.name,
|
|
18299
18570
|
onNavigateBack: handleNavigateBack,
|
|
@@ -18301,7 +18572,7 @@ function XViewScene({
|
|
|
18301
18572
|
onToggle: setIsSidebarOpen,
|
|
18302
18573
|
userRole: userPermissionRole,
|
|
18303
18574
|
viewMembers,
|
|
18304
|
-
milestones: ((
|
|
18575
|
+
milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
|
|
18305
18576
|
onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
|
|
18306
18577
|
}
|
|
18307
18578
|
),
|
|
@@ -18326,8 +18597,8 @@ function XViewScene({
|
|
|
18326
18597
|
},
|
|
18327
18598
|
refEl: formRef,
|
|
18328
18599
|
existingTypes: existingNodeTypes,
|
|
18329
|
-
initialColor: (
|
|
18330
|
-
sourceTypes: (
|
|
18600
|
+
initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
|
|
18601
|
+
sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
|
|
18331
18602
|
onIntensityChange: handleGhostNodeIntensityChange,
|
|
18332
18603
|
onUploadFile: upload_file_action,
|
|
18333
18604
|
availableDatasets,
|
|
@@ -18356,8 +18627,8 @@ function XViewScene({
|
|
|
18356
18627
|
transition: "opacity 200ms ease-out"
|
|
18357
18628
|
},
|
|
18358
18629
|
refEl: formRef,
|
|
18359
|
-
fixedType: (
|
|
18360
|
-
fixedColor: (
|
|
18630
|
+
fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
|
|
18631
|
+
fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
|
|
18361
18632
|
onUploadFile: upload_file_action,
|
|
18362
18633
|
availableNodes: allAvailableNodes,
|
|
18363
18634
|
availableAncestries: allAvailableAncestries
|
|
@@ -18385,9 +18656,9 @@ function XViewScene({
|
|
|
18385
18656
|
availableNodes: allAvailableNodes,
|
|
18386
18657
|
availableAncestries: allAvailableAncestries,
|
|
18387
18658
|
viewName: viewParams == null ? void 0 : viewParams.name,
|
|
18388
|
-
questCounter: ((
|
|
18659
|
+
questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
|
|
18389
18660
|
viewMembers,
|
|
18390
|
-
milestones: ((
|
|
18661
|
+
milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
|
|
18391
18662
|
onUpdateMilestones: handleUpdateMilestones
|
|
18392
18663
|
}
|
|
18393
18664
|
),
|
|
@@ -18522,7 +18793,7 @@ function XViewScene({
|
|
|
18522
18793
|
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
|
|
18523
18794
|
viewMembers,
|
|
18524
18795
|
currentUser: session == null ? void 0 : session.user,
|
|
18525
|
-
milestones: ((
|
|
18796
|
+
milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
|
|
18526
18797
|
onUpdateMilestones: handleUpdateMilestones
|
|
18527
18798
|
}
|
|
18528
18799
|
),
|
|
@@ -18689,15 +18960,15 @@ function XViewScene({
|
|
|
18689
18960
|
}
|
|
18690
18961
|
),
|
|
18691
18962
|
/* @__PURE__ */ React30.createElement(
|
|
18692
|
-
|
|
18963
|
+
Boards,
|
|
18693
18964
|
{
|
|
18694
|
-
isOpen:
|
|
18695
|
-
onClose: () =>
|
|
18965
|
+
isOpen: isBoardsOpen,
|
|
18966
|
+
onClose: () => setIsBoardsOpen(false),
|
|
18696
18967
|
onSelect: handleSelectAncestryFromBoard,
|
|
18697
18968
|
availableAncestries: allAvailableAncestries,
|
|
18698
18969
|
availableNodes: allAvailableNodes,
|
|
18699
|
-
|
|
18700
|
-
onSave:
|
|
18970
|
+
initialBoardItems: boardItems,
|
|
18971
|
+
onSave: handleSaveBoards,
|
|
18701
18972
|
userRole: userPermissionRole
|
|
18702
18973
|
}
|
|
18703
18974
|
),
|
|
@@ -18706,7 +18977,7 @@ function XViewScene({
|
|
|
18706
18977
|
{
|
|
18707
18978
|
isOpen: isMilestoneManagerOpen,
|
|
18708
18979
|
onClose: () => setIsMilestoneManagerOpen(false),
|
|
18709
|
-
milestones: ((
|
|
18980
|
+
milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
|
|
18710
18981
|
onUpdateMilestones: handleUpdateMilestones
|
|
18711
18982
|
}
|
|
18712
18983
|
),
|
|
@@ -18717,7 +18988,7 @@ function XViewScene({
|
|
|
18717
18988
|
onClose: () => setIsImportModalOpen(false),
|
|
18718
18989
|
onConfirm: handleConfirmImport,
|
|
18719
18990
|
session,
|
|
18720
|
-
parentDbs: ((
|
|
18991
|
+
parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
|
|
18721
18992
|
onFetchAvailableFiles: import_parent_file_modal_get,
|
|
18722
18993
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
18723
18994
|
currentAncestries: ancestryDataRef.current || []
|
|
@@ -18801,6 +19072,450 @@ function XViewScene({
|
|
|
18801
19072
|
)
|
|
18802
19073
|
);
|
|
18803
19074
|
}
|
|
19075
|
+
|
|
19076
|
+
// src/x_view_server_logic.js
|
|
19077
|
+
async function save_view_data_logic(db_services, filename, data) {
|
|
19078
|
+
try {
|
|
19079
|
+
const saveResult = await db_services.save_file(filename, data);
|
|
19080
|
+
return saveResult;
|
|
19081
|
+
} catch (error) {
|
|
19082
|
+
console.error("catch (error) em save_view_data_logic:", error);
|
|
19083
|
+
return { success: false, error: error.message };
|
|
19084
|
+
}
|
|
19085
|
+
}
|
|
19086
|
+
async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
|
|
19087
|
+
var _a, _b;
|
|
19088
|
+
try {
|
|
19089
|
+
if (!session || !session.user) {
|
|
19090
|
+
return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
|
|
19091
|
+
}
|
|
19092
|
+
const membershipCheck = await db_services.check_membership(owner_id, type, scene_config, session.user.id);
|
|
19093
|
+
const isFullMember = membershipCheck.success && membershipCheck.isValidMember;
|
|
19094
|
+
if (!isFullMember && !focusNodeId && !focusAncestryId) {
|
|
19095
|
+
return { success: false, error: "Acesso Negado: Voc\xEA n\xE3o possui permiss\xE3o para acessar este cen\xE1rio." };
|
|
19096
|
+
}
|
|
19097
|
+
const sceneResponse = await db_services.get_file(`x_view_scenes/${owner_id}/${scene_config}`);
|
|
19098
|
+
if (!sceneResponse || !sceneResponse.success) {
|
|
19099
|
+
console.error("Falha ao buscar dados da cena:", sceneResponse == null ? void 0 : sceneResponse.error);
|
|
19100
|
+
return { success: false, error: `N\xE3o foi poss\xEDvel carregar o arquivo da cena: ${scene_config}` };
|
|
19101
|
+
}
|
|
19102
|
+
const sceneData = sceneResponse.data;
|
|
19103
|
+
const parentDbObjects = sceneData.parent_dbs || [];
|
|
19104
|
+
if (type && type.toLowerCase().includes("database")) {
|
|
19105
|
+
const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
|
|
19106
|
+
if (!selfExists) {
|
|
19107
|
+
parentDbObjects.push({ db_id: scene_config, owner_id });
|
|
19108
|
+
}
|
|
19109
|
+
}
|
|
19110
|
+
const parentResponsesPromises = parentDbObjects.map(
|
|
19111
|
+
(db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
|
|
19112
|
+
);
|
|
19113
|
+
const parentResponsesResults = await Promise.allSettled(parentResponsesPromises);
|
|
19114
|
+
const parentData = {};
|
|
19115
|
+
for (let i = 0; i < parentResponsesResults.length; i++) {
|
|
19116
|
+
const result = parentResponsesResults[i];
|
|
19117
|
+
const db_info = parentDbObjects[i];
|
|
19118
|
+
if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
|
|
19119
|
+
parentData[db_info.db_id] = result.value.data;
|
|
19120
|
+
} else {
|
|
19121
|
+
console.warn(
|
|
19122
|
+
`Arquivo pai n\xE3o carregado: ${db_info.db_id}. Pode ter sido deletado.`,
|
|
19123
|
+
result.status === "rejected" ? result.reason : (_b = result.value) == null ? void 0 : _b.error
|
|
19124
|
+
);
|
|
19125
|
+
}
|
|
19126
|
+
}
|
|
19127
|
+
if (type && type.toLowerCase() === "view") {
|
|
19128
|
+
parentData[scene_config] = {
|
|
19129
|
+
dataset_name: "Quests Internas (View)",
|
|
19130
|
+
nodes: sceneData.quest_nodes || [],
|
|
19131
|
+
links: sceneData.quest_links || []
|
|
19132
|
+
};
|
|
19133
|
+
}
|
|
19134
|
+
const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
19135
|
+
const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
|
|
19136
|
+
const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
|
|
19137
|
+
const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
|
|
19138
|
+
const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
|
|
19139
|
+
var _a2, _b2;
|
|
19140
|
+
const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
|
|
19141
|
+
if (nodeTypes.includes("quest")) {
|
|
19142
|
+
const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
|
|
19143
|
+
if (dbQuestNode) {
|
|
19144
|
+
return { ...sceneNode, ...dbQuestNode };
|
|
19145
|
+
}
|
|
19146
|
+
return sceneNode;
|
|
19147
|
+
}
|
|
19148
|
+
const dbNode = parentNodeMap.get(String(sceneNode.id));
|
|
19149
|
+
if (dbNode) {
|
|
19150
|
+
return { ...sceneNode, ...dbNode };
|
|
19151
|
+
}
|
|
19152
|
+
return null;
|
|
19153
|
+
}).filter(Boolean);
|
|
19154
|
+
const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
|
|
19155
|
+
const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
|
|
19156
|
+
const linkExistsInParent = parentLinkMap.has(`${sceneLink.source}-${sceneLink.target}`);
|
|
19157
|
+
const nodesAreValidForScene = validNodeIdsInScene.has(String(sceneLink.source)) && validNodeIdsInScene.has(String(sceneLink.target));
|
|
19158
|
+
return linkExistsInParent && nodesAreValidForScene;
|
|
19159
|
+
}).map((sceneLink) => parentLinkMap.get(`${sceneLink.source}-${sceneLink.target}`));
|
|
19160
|
+
const validatedSceneData = {
|
|
19161
|
+
...sceneData,
|
|
19162
|
+
nodes: validatedNodes,
|
|
19163
|
+
links: validatedLinks
|
|
19164
|
+
};
|
|
19165
|
+
const ancestryFilePaths = [];
|
|
19166
|
+
ancestryFilePaths.push({
|
|
19167
|
+
path: `x_view_ancestry/${owner_id}/${scene_config}`,
|
|
19168
|
+
source_id: scene_config,
|
|
19169
|
+
owner_id,
|
|
19170
|
+
isSceneFile: true
|
|
19171
|
+
});
|
|
19172
|
+
parentDbObjects.forEach((db_info) => {
|
|
19173
|
+
ancestryFilePaths.push({
|
|
19174
|
+
path: `x_view_ancestry/${db_info.owner_id}/${db_info.db_id}`,
|
|
19175
|
+
source_id: db_info.db_id,
|
|
19176
|
+
owner_id: db_info.owner_id,
|
|
19177
|
+
isSceneFile: false
|
|
19178
|
+
});
|
|
19179
|
+
});
|
|
19180
|
+
const ancestryPromises = ancestryFilePaths.map((file) => db_services.get_file(file.path));
|
|
19181
|
+
const ancestryResults = await Promise.allSettled(ancestryPromises);
|
|
19182
|
+
const ancestriesFromSceneFile = [];
|
|
19183
|
+
const ancestriesFromDbFiles = [];
|
|
19184
|
+
ancestryResults.forEach((result, index) => {
|
|
19185
|
+
var _a2;
|
|
19186
|
+
const fileInfo = ancestryFilePaths[index];
|
|
19187
|
+
if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
|
|
19188
|
+
const ancestriesFromFile = result.value.data.map((ancestry) => {
|
|
19189
|
+
const existingSource = ancestry._source_file_id;
|
|
19190
|
+
const existingOwner = ancestry._source_owner_id;
|
|
19191
|
+
const isImportedItem = existingSource && existingSource !== fileInfo.source_id;
|
|
19192
|
+
return {
|
|
19193
|
+
...ancestry,
|
|
19194
|
+
_source_file_id: isImportedItem ? existingSource : fileInfo.source_id,
|
|
19195
|
+
_source_owner_id: isImportedItem ? existingOwner : fileInfo.owner_id
|
|
19196
|
+
};
|
|
19197
|
+
});
|
|
19198
|
+
if (fileInfo.isSceneFile) {
|
|
19199
|
+
ancestriesFromSceneFile.push(...ancestriesFromFile);
|
|
19200
|
+
} else {
|
|
19201
|
+
ancestriesFromDbFiles.push(...ancestriesFromFile);
|
|
19202
|
+
}
|
|
19203
|
+
}
|
|
19204
|
+
});
|
|
19205
|
+
const ancestryMap = /* @__PURE__ */ new Map();
|
|
19206
|
+
ancestriesFromDbFiles.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
|
|
19207
|
+
ancestriesFromSceneFile.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
|
|
19208
|
+
let ancestryData = Array.from(ancestryMap.values());
|
|
19209
|
+
const externalSourcesToRefresh = /* @__PURE__ */ new Map();
|
|
19210
|
+
ancestryData.forEach((anc) => {
|
|
19211
|
+
const targetSourceId = anc._source_file_id || anc._imported_from_view_id;
|
|
19212
|
+
const targetOwnerId = anc._source_owner_id || anc._imported_from_view_owner_id;
|
|
19213
|
+
if (targetSourceId && targetSourceId !== scene_config && targetOwnerId) {
|
|
19214
|
+
const isAlreadyLoadedAsParent = parentDbObjects.some((db) => String(db.db_id) === String(targetSourceId));
|
|
19215
|
+
if (!isAlreadyLoadedAsParent) {
|
|
19216
|
+
const key = `${targetOwnerId}/${targetSourceId}`;
|
|
19217
|
+
externalSourcesToRefresh.set(key, {
|
|
19218
|
+
owner_id: targetOwnerId,
|
|
19219
|
+
source_id: targetSourceId,
|
|
19220
|
+
key
|
|
19221
|
+
});
|
|
19222
|
+
}
|
|
19223
|
+
}
|
|
19224
|
+
});
|
|
19225
|
+
const successfullyFetchedSources = /* @__PURE__ */ new Set();
|
|
19226
|
+
const failedSources = /* @__PURE__ */ new Set();
|
|
19227
|
+
if (externalSourcesToRefresh.size > 0) {
|
|
19228
|
+
const refreshPromises = Array.from(externalSourcesToRefresh.values()).map(
|
|
19229
|
+
(src) => db_services.get_file(`x_view_ancestry/${src.owner_id}/${src.source_id}`).then((res) => ({ ...res, _meta_key: src.key }))
|
|
19230
|
+
);
|
|
19231
|
+
const refreshResults = await Promise.allSettled(refreshPromises);
|
|
19232
|
+
const freshAncestryMap = /* @__PURE__ */ new Map();
|
|
19233
|
+
refreshResults.forEach((result) => {
|
|
19234
|
+
var _a2, _b2;
|
|
19235
|
+
if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
|
|
19236
|
+
successfullyFetchedSources.add(result.value._meta_key);
|
|
19237
|
+
result.value.data.forEach((freshAnc) => {
|
|
19238
|
+
if (!freshAnc.is_private) {
|
|
19239
|
+
freshAncestryMap.set(String(freshAnc.ancestry_id), freshAnc);
|
|
19240
|
+
}
|
|
19241
|
+
});
|
|
19242
|
+
} else if (result.status === "fulfilled" && !((_b2 = result.value) == null ? void 0 : _b2.success)) {
|
|
19243
|
+
failedSources.add(result.value._meta_key);
|
|
19244
|
+
}
|
|
19245
|
+
});
|
|
19246
|
+
ancestryData = ancestryData.filter((localAnc) => {
|
|
19247
|
+
const targetSourceId = localAnc._source_file_id || localAnc._imported_from_view_id;
|
|
19248
|
+
const targetOwnerId = localAnc._source_owner_id || localAnc._imported_from_view_owner_id;
|
|
19249
|
+
if (!targetSourceId || targetSourceId === scene_config) return true;
|
|
19250
|
+
const key = `${targetOwnerId}/${targetSourceId}`;
|
|
19251
|
+
if (failedSources.has(key)) {
|
|
19252
|
+
return false;
|
|
19253
|
+
}
|
|
19254
|
+
if (externalSourcesToRefresh.has(key) && successfullyFetchedSources.has(key)) {
|
|
19255
|
+
const stillExists = freshAncestryMap.has(String(localAnc.ancestry_id));
|
|
19256
|
+
return stillExists;
|
|
19257
|
+
}
|
|
19258
|
+
return true;
|
|
19259
|
+
}).map((localAnc) => {
|
|
19260
|
+
const freshVersion = freshAncestryMap.get(String(localAnc.ancestry_id));
|
|
19261
|
+
if (freshVersion) {
|
|
19262
|
+
return {
|
|
19263
|
+
...freshVersion,
|
|
19264
|
+
_imported_from_view_id: localAnc._imported_from_view_id,
|
|
19265
|
+
_imported_from_view_owner_id: localAnc._imported_from_view_owner_id,
|
|
19266
|
+
_origin_db_ids: localAnc._origin_db_ids,
|
|
19267
|
+
_source_file_id: localAnc._source_file_id,
|
|
19268
|
+
_source_owner_id: localAnc._source_owner_id
|
|
19269
|
+
};
|
|
19270
|
+
}
|
|
19271
|
+
return localAnc;
|
|
19272
|
+
});
|
|
19273
|
+
}
|
|
19274
|
+
const ancestryFilePath = `x_view_ancestry/${owner_id}/${scene_config}`;
|
|
19275
|
+
const parentNodeIds = new Set(allNodes.map((node) => String(node.id)));
|
|
19276
|
+
const pruneTree = (node) => {
|
|
19277
|
+
if (!node) return null;
|
|
19278
|
+
if (node.is_section) {
|
|
19279
|
+
const validChildren2 = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
|
|
19280
|
+
return { ...node, children: validChildren2 };
|
|
19281
|
+
}
|
|
19282
|
+
if (!parentNodeIds.has(String(node.node_id))) {
|
|
19283
|
+
return null;
|
|
19284
|
+
}
|
|
19285
|
+
const validChildren = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
|
|
19286
|
+
let validBranches = [];
|
|
19287
|
+
if (node.parallel_branches) {
|
|
19288
|
+
validBranches = node.parallel_branches.map((branch) => ({
|
|
19289
|
+
...branch,
|
|
19290
|
+
tree: pruneTree(branch.tree)
|
|
19291
|
+
})).filter((b) => b.tree !== null);
|
|
19292
|
+
}
|
|
19293
|
+
return {
|
|
19294
|
+
...node,
|
|
19295
|
+
children: validChildren,
|
|
19296
|
+
parallel_branches: validBranches
|
|
19297
|
+
};
|
|
19298
|
+
};
|
|
19299
|
+
const originalAncestryDataString = JSON.stringify(Array.from(ancestryMap.values()));
|
|
19300
|
+
const cleanedAncestryData = ancestryData.map((ancestry) => {
|
|
19301
|
+
if (!parentNodeIds.has(String(ancestry.ancestral_node))) return null;
|
|
19302
|
+
const cleanedTree = pruneTree(ancestry.tree);
|
|
19303
|
+
if (!cleanedTree) return null;
|
|
19304
|
+
let cleanedAbstraction = null;
|
|
19305
|
+
if (ancestry.abstraction_tree) {
|
|
19306
|
+
cleanedAbstraction = pruneTree(ancestry.abstraction_tree);
|
|
19307
|
+
}
|
|
19308
|
+
return {
|
|
19309
|
+
...ancestry,
|
|
19310
|
+
tree: cleanedTree,
|
|
19311
|
+
abstraction_tree: cleanedAbstraction
|
|
19312
|
+
};
|
|
19313
|
+
}).filter(Boolean);
|
|
19314
|
+
if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
|
|
19315
|
+
ancestryData = cleanedAncestryData;
|
|
19316
|
+
try {
|
|
19317
|
+
await db_services.save_file(ancestryFilePath, ancestryData);
|
|
19318
|
+
} catch (saveError) {
|
|
19319
|
+
console.error("Falha ao salvar o arquivo de ancestralidade da cena atualizado:", saveError);
|
|
19320
|
+
}
|
|
19321
|
+
}
|
|
19322
|
+
if (!isFullMember) {
|
|
19323
|
+
const requiredNodeIds = /* @__PURE__ */ new Set();
|
|
19324
|
+
const requiredAncestryIds = /* @__PURE__ */ new Set();
|
|
19325
|
+
if (focusNodeId) requiredNodeIds.add(String(focusNodeId));
|
|
19326
|
+
if (focusAncestryId) requiredAncestryIds.add(String(focusAncestryId));
|
|
19327
|
+
const allNodesFromDb = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
19328
|
+
const extractDependenciesFromText = (text) => {
|
|
19329
|
+
if (!text) return;
|
|
19330
|
+
const mentionRegex = /\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g;
|
|
19331
|
+
const refRegex = /\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g;
|
|
19332
|
+
let match;
|
|
19333
|
+
while ((match = mentionRegex.exec(text)) !== null) {
|
|
19334
|
+
requiredNodeIds.add(match[1]);
|
|
19335
|
+
}
|
|
19336
|
+
while ((match = refRegex.exec(text)) !== null) {
|
|
19337
|
+
if (match[1] === "node") requiredNodeIds.add(match[2]);
|
|
19338
|
+
if (match[1] === "ancestry") requiredAncestryIds.add(match[2]);
|
|
19339
|
+
}
|
|
19340
|
+
};
|
|
19341
|
+
const extractTreeDependencies = (treeItem) => {
|
|
19342
|
+
var _a2;
|
|
19343
|
+
if (!treeItem) return;
|
|
19344
|
+
if (treeItem.node_id) requiredNodeIds.add(String(treeItem.node_id));
|
|
19345
|
+
if ((_a2 = treeItem.node) == null ? void 0 : _a2.id) requiredNodeIds.add(String(treeItem.node.id));
|
|
19346
|
+
if (treeItem.children) {
|
|
19347
|
+
treeItem.children.forEach(extractTreeDependencies);
|
|
19348
|
+
}
|
|
19349
|
+
if (treeItem.parallel_branches) {
|
|
19350
|
+
treeItem.parallel_branches.forEach((branch) => {
|
|
19351
|
+
if (branch.linked_ancestry_id) {
|
|
19352
|
+
requiredAncestryIds.add(String(branch.linked_ancestry_id));
|
|
19353
|
+
}
|
|
19354
|
+
if (branch.description) extractDependenciesFromText(branch.description);
|
|
19355
|
+
if (branch.description_sections) {
|
|
19356
|
+
branch.description_sections.forEach((s) => extractDependenciesFromText(s.content));
|
|
19357
|
+
}
|
|
19358
|
+
extractTreeDependencies(branch.tree);
|
|
19359
|
+
});
|
|
19360
|
+
}
|
|
19361
|
+
};
|
|
19362
|
+
let previousSize;
|
|
19363
|
+
do {
|
|
19364
|
+
previousSize = requiredNodeIds.size + requiredAncestryIds.size;
|
|
19365
|
+
requiredAncestryIds.forEach((ancId) => {
|
|
19366
|
+
const anc = ancestryData.find((a) => String(a.ancestry_id) === ancId);
|
|
19367
|
+
if (anc && !anc.is_private) {
|
|
19368
|
+
if (anc.description) extractDependenciesFromText(anc.description);
|
|
19369
|
+
if (anc.description_sections) {
|
|
19370
|
+
anc.description_sections.forEach((s) => extractDependenciesFromText(s.content));
|
|
19371
|
+
}
|
|
19372
|
+
extractTreeDependencies(anc.tree);
|
|
19373
|
+
extractTreeDependencies(anc.abstraction_tree);
|
|
19374
|
+
}
|
|
19375
|
+
});
|
|
19376
|
+
requiredNodeIds.forEach((nodeId) => {
|
|
19377
|
+
const node = allNodesFromDb.find((n) => String(n.id) === nodeId);
|
|
19378
|
+
if (node) {
|
|
19379
|
+
if (node.description) extractDependenciesFromText(node.description);
|
|
19380
|
+
if (node.description_sections) {
|
|
19381
|
+
node.description_sections.forEach((s) => extractDependenciesFromText(s.content));
|
|
19382
|
+
}
|
|
19383
|
+
}
|
|
19384
|
+
});
|
|
19385
|
+
} while (requiredNodeIds.size + requiredAncestryIds.size > previousSize);
|
|
19386
|
+
const restrictedSceneData = { ...validatedSceneData, nodes: [], links: [] };
|
|
19387
|
+
const restrictedParentData = {};
|
|
19388
|
+
const restrictedAncestryData = ancestryData.filter((a) => requiredAncestryIds.has(String(a.ancestry_id)) && !a.is_private);
|
|
19389
|
+
for (const [dbId, dbContent] of Object.entries(parentData)) {
|
|
19390
|
+
const filteredNodes = (dbContent.nodes || []).filter((n) => requiredNodeIds.has(String(n.id)));
|
|
19391
|
+
if (filteredNodes.length > 0) {
|
|
19392
|
+
restrictedParentData[dbId] = { ...dbContent, nodes: filteredNodes, links: [] };
|
|
19393
|
+
}
|
|
19394
|
+
}
|
|
19395
|
+
if (focusNodeId) {
|
|
19396
|
+
const mainNode = allNodesFromDb.find((n) => String(n.id) === String(focusNodeId));
|
|
19397
|
+
if (mainNode) {
|
|
19398
|
+
restrictedSceneData.nodes = [mainNode];
|
|
19399
|
+
}
|
|
19400
|
+
}
|
|
19401
|
+
return {
|
|
19402
|
+
success: true,
|
|
19403
|
+
data: {
|
|
19404
|
+
scene: restrictedSceneData,
|
|
19405
|
+
parent: restrictedParentData,
|
|
19406
|
+
ancestry: restrictedAncestryData
|
|
19407
|
+
}
|
|
19408
|
+
};
|
|
19409
|
+
}
|
|
19410
|
+
return {
|
|
19411
|
+
success: true,
|
|
19412
|
+
data: { scene: validatedSceneData, parent: parentData, ancestry: ancestryData }
|
|
19413
|
+
};
|
|
19414
|
+
} catch (error) {
|
|
19415
|
+
console.error("Erro em get_scene_view_data_logic:", error);
|
|
19416
|
+
return { success: false, error: error.message };
|
|
19417
|
+
}
|
|
19418
|
+
}
|
|
19419
|
+
async function import_parent_file_modal_get_logic(db_services, session) {
|
|
19420
|
+
try {
|
|
19421
|
+
const call_firestore_get_x_view_data = await db_services.get_firestore_data(session);
|
|
19422
|
+
const x_view_databases = call_firestore_get_x_view_data.data.sub_collections.x_view_databases || [];
|
|
19423
|
+
const x_views = call_firestore_get_x_view_data.data.sub_collections.x_views || [];
|
|
19424
|
+
return {
|
|
19425
|
+
success: true,
|
|
19426
|
+
data: {
|
|
19427
|
+
databases: x_view_databases,
|
|
19428
|
+
views: x_views
|
|
19429
|
+
}
|
|
19430
|
+
};
|
|
19431
|
+
} catch (error) {
|
|
19432
|
+
console.error("catch (error) em import_parent_file_modal_get_logic:", error);
|
|
19433
|
+
return { success: false, error: error.message };
|
|
19434
|
+
}
|
|
19435
|
+
}
|
|
19436
|
+
async function get_single_parent_file_logic(db_services, file_id, session) {
|
|
19437
|
+
try {
|
|
19438
|
+
const call_GCP_cloud_storage_get_file = await db_services.get_file(`x_view_dbs/${session.user.id}/${file_id}`);
|
|
19439
|
+
return call_GCP_cloud_storage_get_file;
|
|
19440
|
+
} catch (error) {
|
|
19441
|
+
console.error("catch (error) em get_single_parent_file_logic:", error);
|
|
19442
|
+
return { success: false, error: error.message };
|
|
19443
|
+
}
|
|
19444
|
+
}
|
|
19445
|
+
async function x_view_add_new_parent_file_to_scene_at_firebase(file_id, session, new_parent, db_services) {
|
|
19446
|
+
try {
|
|
19447
|
+
const update_data = {
|
|
19448
|
+
scene_id: file_id,
|
|
19449
|
+
new_parent,
|
|
19450
|
+
session
|
|
19451
|
+
};
|
|
19452
|
+
const call_firestore_add_new_parent_file_to_scene_at_firebase = await db_services.add_new_parent_file_to_scene_at_firebase(update_data);
|
|
19453
|
+
return call_firestore_add_new_parent_file_to_scene_at_firebase;
|
|
19454
|
+
} catch (error) {
|
|
19455
|
+
console.error("catch (error) em get_single_parent_file_logic:", error);
|
|
19456
|
+
return { success: false, error: error.message };
|
|
19457
|
+
}
|
|
19458
|
+
}
|
|
19459
|
+
async function get_ancestry_file_logic(db_services, file_id, owner_id) {
|
|
19460
|
+
try {
|
|
19461
|
+
const path = `x_view_ancestry/${owner_id}/${file_id}`;
|
|
19462
|
+
const call_GCP_cloud_storage_get_file = await db_services.get_file(path);
|
|
19463
|
+
return call_GCP_cloud_storage_get_file;
|
|
19464
|
+
} catch (error) {
|
|
19465
|
+
console.error("catch (error) em get_ancestry_file_logic:", error);
|
|
19466
|
+
return { success: false, error: error.message };
|
|
19467
|
+
}
|
|
19468
|
+
}
|
|
19469
|
+
async function save_boards_logic(db_services, scene_id, type, boardItems, session, owner_id) {
|
|
19470
|
+
try {
|
|
19471
|
+
const targetOwnerId = owner_id || session.user.id;
|
|
19472
|
+
return await db_services.save_boards(session, scene_id, type, boardItems, targetOwnerId);
|
|
19473
|
+
} catch (error) {
|
|
19474
|
+
console.error("Erro em save_boards_logic:", error);
|
|
19475
|
+
return { success: false, error: error.message };
|
|
19476
|
+
}
|
|
19477
|
+
}
|
|
19478
|
+
async function get_boards_logic(db_services, scene_id, type, session, owner_id) {
|
|
19479
|
+
try {
|
|
19480
|
+
const targetOwnerId = owner_id || session.user.id;
|
|
19481
|
+
return await db_services.get_boards(session, scene_id, type, targetOwnerId);
|
|
19482
|
+
} catch (error) {
|
|
19483
|
+
console.error("Erro em get_boards_logic:", error);
|
|
19484
|
+
return { success: false, error: error.message };
|
|
19485
|
+
}
|
|
19486
|
+
}
|
|
19487
|
+
async function delete_uploaded_file_logic(db_services, fileUrl) {
|
|
19488
|
+
try {
|
|
19489
|
+
if (db_services.delete_public_file) {
|
|
19490
|
+
return await db_services.delete_public_file(fileUrl);
|
|
19491
|
+
}
|
|
19492
|
+
return { success: false, error: "Servi\xE7o de dele\xE7\xE3o n\xE3o configurado." };
|
|
19493
|
+
} catch (error) {
|
|
19494
|
+
console.error("Erro em delete_uploaded_file_logic:", error);
|
|
19495
|
+
return { success: false, error: error.message };
|
|
19496
|
+
}
|
|
19497
|
+
}
|
|
19498
|
+
async function get_view_members_logic(db_services, ownerId, type, itemId) {
|
|
19499
|
+
try {
|
|
19500
|
+
if (!db_services.get_view_members) {
|
|
19501
|
+
return { success: false, error: "Servi\xE7o de busca de membros n\xE3o configurado." };
|
|
19502
|
+
}
|
|
19503
|
+
return await db_services.get_view_members(ownerId, type, itemId);
|
|
19504
|
+
} catch (error) {
|
|
19505
|
+
console.error("Erro em get_view_members_logic:", error);
|
|
19506
|
+
return { success: false, error: error.message };
|
|
19507
|
+
}
|
|
19508
|
+
}
|
|
18804
19509
|
export {
|
|
18805
|
-
XViewScene
|
|
19510
|
+
XViewScene,
|
|
19511
|
+
delete_uploaded_file_logic,
|
|
19512
|
+
get_ancestry_file_logic,
|
|
19513
|
+
get_boards_logic,
|
|
19514
|
+
get_scene_view_data_logic,
|
|
19515
|
+
get_single_parent_file_logic,
|
|
19516
|
+
get_view_members_logic,
|
|
19517
|
+
import_parent_file_modal_get_logic,
|
|
19518
|
+
save_boards_logic,
|
|
19519
|
+
save_view_data_logic,
|
|
19520
|
+
x_view_add_new_parent_file_to_scene_at_firebase
|
|
18806
19521
|
};
|