@lv-x-software-house/x_view 1.2.6-dev.3 → 1.2.6-dev.31
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 +1597 -866
- package/dist/index.mjs +1518 -806
- 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(
|
|
13871
|
+
"button",
|
|
13872
|
+
{
|
|
13873
|
+
onClick: navigateHome,
|
|
13874
|
+
className: `hover:text-white transition-colors flex items-center gap-1 ${navigationStack.length === 0 ? "text-indigo-400" : ""}`
|
|
13875
|
+
},
|
|
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",
|
|
13879
|
+
{
|
|
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(
|
|
13613
13885
|
"button",
|
|
13614
13886
|
{
|
|
13615
|
-
onClick:
|
|
13616
|
-
className: "
|
|
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"
|
|
13617
13889
|
},
|
|
13618
|
-
|
|
13619
|
-
|
|
13620
|
-
|
|
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,
|
|
13621
13895
|
{
|
|
13622
|
-
key:
|
|
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,95 @@ 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 handleFocusNode = useCallback5(
|
|
18098
|
+
(nodeData) => {
|
|
18099
|
+
var _a2;
|
|
18100
|
+
if (!nodeData) return;
|
|
18101
|
+
let nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
18102
|
+
if (!nodeMesh) {
|
|
18103
|
+
const spawnPos = ((_a2 = stateRef.current.controls) == null ? void 0 : _a2.target.clone()) || new THREE3.Vector3();
|
|
18104
|
+
addStandaloneNodeToScene(stateRef.current, nodeData, spawnPos);
|
|
18105
|
+
nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
18106
|
+
}
|
|
18107
|
+
if (nodeMesh) {
|
|
18108
|
+
tweenToTarget(nodeMesh, 1.2);
|
|
18109
|
+
}
|
|
18110
|
+
},
|
|
18111
|
+
[tweenToTarget]
|
|
18112
|
+
);
|
|
18113
|
+
const handleOpenReference = useCallback5(
|
|
18114
|
+
(referenceData) => {
|
|
18115
|
+
const { type, id } = referenceData;
|
|
18116
|
+
if (type === "node") {
|
|
18117
|
+
const targetNode = allAvailableNodes.find(
|
|
18118
|
+
(n) => String(n.id) === String(id)
|
|
18119
|
+
);
|
|
18120
|
+
if (targetNode) {
|
|
18121
|
+
setAncestryLinkDetails(null);
|
|
18122
|
+
setDetailsLink(null);
|
|
18123
|
+
setDetailsNode(targetNode);
|
|
18124
|
+
handleFocusNode(targetNode);
|
|
18125
|
+
} else {
|
|
18126
|
+
alert("Node original n\xE3o encontrado neste contexto.");
|
|
18127
|
+
}
|
|
18128
|
+
} else if (type === "ancestry") {
|
|
18129
|
+
const targetAncestry = allAvailableAncestries.find(
|
|
18130
|
+
(a) => String(a.ancestry_id) === String(id)
|
|
18131
|
+
);
|
|
18132
|
+
if (targetAncestry) {
|
|
18133
|
+
setDetailsNode(null);
|
|
18134
|
+
setDetailsLink(null);
|
|
18135
|
+
setAncestryLinkDetails(null);
|
|
18136
|
+
handleEditAncestry(targetAncestry);
|
|
18137
|
+
} else {
|
|
18138
|
+
alert("Ancestralidade original n\xE3o encontrada neste contexto.");
|
|
18139
|
+
}
|
|
18140
|
+
}
|
|
18141
|
+
},
|
|
18142
|
+
[
|
|
18143
|
+
allAvailableNodes,
|
|
18144
|
+
allAvailableAncestries,
|
|
18145
|
+
handleEditAncestry,
|
|
18146
|
+
handleFocusNode
|
|
18147
|
+
]
|
|
18148
|
+
);
|
|
18149
|
+
const handleSelectAncestryFromBoard = useCallback5(
|
|
17806
18150
|
(item) => {
|
|
17807
|
-
|
|
18151
|
+
setIsBoardsOpen(false);
|
|
17808
18152
|
setIsSidebarOpen(false);
|
|
17809
|
-
if (item.type === "ancestry"
|
|
18153
|
+
if (item.type === "ancestry") {
|
|
17810
18154
|
handleStartReadingAncestry(item);
|
|
17811
18155
|
} 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
|
-
}
|
|
18156
|
+
handleOpenReference({ type: "node", id: item.id });
|
|
17819
18157
|
}
|
|
17820
18158
|
},
|
|
17821
|
-
[handleStartReadingAncestry,
|
|
18159
|
+
[handleStartReadingAncestry, handleOpenReference]
|
|
17822
18160
|
);
|
|
17823
|
-
const
|
|
17824
|
-
async (
|
|
18161
|
+
const handleSaveBoards = useCallback5(
|
|
18162
|
+
async (boardItems2) => {
|
|
17825
18163
|
if (!sceneConfigId || !viewParams || !session) return;
|
|
17826
18164
|
const sceneType = (viewParams.type || "").toLowerCase().includes("database") ? "database" : "view";
|
|
17827
|
-
await
|
|
18165
|
+
await save_boards_action(
|
|
17828
18166
|
sceneConfigId,
|
|
17829
18167
|
sceneType,
|
|
17830
|
-
|
|
18168
|
+
boardItems2,
|
|
17831
18169
|
session,
|
|
17832
18170
|
ownerId
|
|
17833
18171
|
);
|
|
17834
18172
|
},
|
|
17835
|
-
[sceneConfigId, viewParams, session,
|
|
18173
|
+
[sceneConfigId, viewParams, session, save_boards_action, ownerId]
|
|
17836
18174
|
);
|
|
17837
18175
|
const existingNodeTypes = useMemo13(() => {
|
|
17838
18176
|
if (!parentDataRef.current) {
|
|
@@ -17847,27 +18185,21 @@ function XViewScene({
|
|
|
17847
18185
|
return [...new Set(allTypes)];
|
|
17848
18186
|
}, [parentDataRef.current, sceneVersion]);
|
|
17849
18187
|
const searchableDbNodes = useMemo13(() => {
|
|
17850
|
-
var _a2;
|
|
17851
18188
|
if (!parentDataRef.current) {
|
|
17852
18189
|
return [];
|
|
17853
18190
|
}
|
|
17854
|
-
|
|
18191
|
+
return Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
|
|
17855
18192
|
const datasetName = fileData.dataset_name || `Dataset #${dbId.substring(0, 6)}`;
|
|
17856
18193
|
return (fileData.nodes || []).map((node) => ({
|
|
17857
18194
|
...node,
|
|
17858
18195
|
dataset_name: datasetName
|
|
17859
18196
|
}));
|
|
18197
|
+
}).filter((node) => {
|
|
18198
|
+
var _a2;
|
|
18199
|
+
return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
|
|
17860
18200
|
});
|
|
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(
|
|
18201
|
+
}, [parentDataRef.current, sceneVersion]);
|
|
18202
|
+
const handleAddExistingNode = useCallback5(
|
|
17871
18203
|
(nodeId) => {
|
|
17872
18204
|
return userActionHandlers.handleAddExistingNodeById(
|
|
17873
18205
|
actionHandlerContext,
|
|
@@ -17876,7 +18208,7 @@ function XViewScene({
|
|
|
17876
18208
|
},
|
|
17877
18209
|
[actionHandlerContext]
|
|
17878
18210
|
);
|
|
17879
|
-
const handleUpdateMilestones =
|
|
18211
|
+
const handleUpdateMilestones = useCallback5(
|
|
17880
18212
|
async (newMilestones) => {
|
|
17881
18213
|
var _a2, _b2, _c2;
|
|
17882
18214
|
if (!sceneDataRef.current) return;
|
|
@@ -17922,7 +18254,7 @@ function XViewScene({
|
|
|
17922
18254
|
viewParams == null ? void 0 : viewParams.type
|
|
17923
18255
|
]
|
|
17924
18256
|
);
|
|
17925
|
-
const handleSaveCurrentView =
|
|
18257
|
+
const handleSaveCurrentView = useCallback5(async () => {
|
|
17926
18258
|
var _a2, _b2, _c2;
|
|
17927
18259
|
const { nodeObjects, allLinks } = stateRef.current;
|
|
17928
18260
|
if (!nodeObjects || !allLinks || !sceneSaveUrl || !parentDataRef.current) {
|
|
@@ -17965,76 +18297,12 @@ function XViewScene({
|
|
|
17965
18297
|
console.error("Erro na chamada de save_view_data:", error);
|
|
17966
18298
|
}
|
|
17967
18299
|
}, [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(() => {
|
|
18300
|
+
const handleToggleAncestryAddMode = useCallback5(() => {
|
|
18017
18301
|
setAncestryMode((prev) => ({
|
|
18018
18302
|
...prev,
|
|
18019
18303
|
isAddingNodes: !prev.isAddingNodes
|
|
18020
18304
|
}));
|
|
18021
18305
|
}, []);
|
|
18022
|
-
const handleFocusNode = useCallback4(
|
|
18023
|
-
(nodeData) => {
|
|
18024
|
-
var _a2;
|
|
18025
|
-
if (!nodeData) return;
|
|
18026
|
-
let nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
18027
|
-
if (!nodeMesh) {
|
|
18028
|
-
const spawnPos = ((_a2 = stateRef.current.controls) == null ? void 0 : _a2.target.clone()) || new THREE3.Vector3();
|
|
18029
|
-
addStandaloneNodeToScene(stateRef.current, nodeData, spawnPos);
|
|
18030
|
-
nodeMesh = stateRef.current.nodeObjects[String(nodeData.id)];
|
|
18031
|
-
}
|
|
18032
|
-
if (nodeMesh) {
|
|
18033
|
-
tweenToTarget(nodeMesh, 1.2);
|
|
18034
|
-
}
|
|
18035
|
-
},
|
|
18036
|
-
[tweenToTarget]
|
|
18037
|
-
);
|
|
18038
18306
|
const availableDatasets = useMemo13(() => {
|
|
18039
18307
|
if (!sceneDataRef.current || !parentDataRef.current) return [];
|
|
18040
18308
|
return sceneDataRef.current.parent_dbs.map((db) => {
|
|
@@ -18045,9 +18313,9 @@ function XViewScene({
|
|
|
18045
18313
|
};
|
|
18046
18314
|
});
|
|
18047
18315
|
}, [sceneVersion, isInitialized]);
|
|
18048
|
-
const sourceNodeDatasetId = creationMode.sourceNodeData ? (
|
|
18316
|
+
const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
|
|
18049
18317
|
String(creationMode.sourceNodeData.id)
|
|
18050
|
-
)) == null ? void 0 :
|
|
18318
|
+
)) == null ? void 0 : _b.parentFileId : null;
|
|
18051
18319
|
const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
|
|
18052
18320
|
useEffect24(() => {
|
|
18053
18321
|
if (isInitialized && focusNodeId && !hasFocusedInitial) {
|
|
@@ -18137,7 +18405,7 @@ function XViewScene({
|
|
|
18137
18405
|
setRelationshipMenu((prev) => ({ ...prev, visible: false }));
|
|
18138
18406
|
}
|
|
18139
18407
|
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 && !
|
|
18408
|
+
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
18409
|
if (isUiClear) {
|
|
18142
18410
|
const isView = ((_c2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _c2.toLowerCase()) === "view";
|
|
18143
18411
|
if (!isView) return;
|
|
@@ -18206,7 +18474,7 @@ function XViewScene({
|
|
|
18206
18474
|
relationshipMenu.visible,
|
|
18207
18475
|
readingMode.isActive,
|
|
18208
18476
|
isImportModalOpen,
|
|
18209
|
-
|
|
18477
|
+
isBoardsOpen,
|
|
18210
18478
|
isSidebarOpen,
|
|
18211
18479
|
detailsNode,
|
|
18212
18480
|
detailsLink,
|
|
@@ -18293,7 +18561,7 @@ function XViewScene({
|
|
|
18293
18561
|
importSuccessMessage,
|
|
18294
18562
|
onActivateTimeline: handleActivateTimeline,
|
|
18295
18563
|
onActivateQuestLens: handleActivateQuestLens,
|
|
18296
|
-
|
|
18564
|
+
onOpenBoards: handleOpenBoards,
|
|
18297
18565
|
viewType: viewParams == null ? void 0 : viewParams.type,
|
|
18298
18566
|
viewName: viewParams == null ? void 0 : viewParams.name,
|
|
18299
18567
|
onNavigateBack: handleNavigateBack,
|
|
@@ -18301,7 +18569,7 @@ function XViewScene({
|
|
|
18301
18569
|
onToggle: setIsSidebarOpen,
|
|
18302
18570
|
userRole: userPermissionRole,
|
|
18303
18571
|
viewMembers,
|
|
18304
|
-
milestones: ((
|
|
18572
|
+
milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
|
|
18305
18573
|
onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
|
|
18306
18574
|
}
|
|
18307
18575
|
),
|
|
@@ -18326,8 +18594,8 @@ function XViewScene({
|
|
|
18326
18594
|
},
|
|
18327
18595
|
refEl: formRef,
|
|
18328
18596
|
existingTypes: existingNodeTypes,
|
|
18329
|
-
initialColor: (
|
|
18330
|
-
sourceTypes: (
|
|
18597
|
+
initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
|
|
18598
|
+
sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
|
|
18331
18599
|
onIntensityChange: handleGhostNodeIntensityChange,
|
|
18332
18600
|
onUploadFile: upload_file_action,
|
|
18333
18601
|
availableDatasets,
|
|
@@ -18356,8 +18624,8 @@ function XViewScene({
|
|
|
18356
18624
|
transition: "opacity 200ms ease-out"
|
|
18357
18625
|
},
|
|
18358
18626
|
refEl: formRef,
|
|
18359
|
-
fixedType: (
|
|
18360
|
-
fixedColor: (
|
|
18627
|
+
fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
|
|
18628
|
+
fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
|
|
18361
18629
|
onUploadFile: upload_file_action,
|
|
18362
18630
|
availableNodes: allAvailableNodes,
|
|
18363
18631
|
availableAncestries: allAvailableAncestries
|
|
@@ -18385,9 +18653,9 @@ function XViewScene({
|
|
|
18385
18653
|
availableNodes: allAvailableNodes,
|
|
18386
18654
|
availableAncestries: allAvailableAncestries,
|
|
18387
18655
|
viewName: viewParams == null ? void 0 : viewParams.name,
|
|
18388
|
-
questCounter: ((
|
|
18656
|
+
questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
|
|
18389
18657
|
viewMembers,
|
|
18390
|
-
milestones: ((
|
|
18658
|
+
milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
|
|
18391
18659
|
onUpdateMilestones: handleUpdateMilestones
|
|
18392
18660
|
}
|
|
18393
18661
|
),
|
|
@@ -18522,7 +18790,7 @@ function XViewScene({
|
|
|
18522
18790
|
currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
|
|
18523
18791
|
viewMembers,
|
|
18524
18792
|
currentUser: session == null ? void 0 : session.user,
|
|
18525
|
-
milestones: ((
|
|
18793
|
+
milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
|
|
18526
18794
|
onUpdateMilestones: handleUpdateMilestones
|
|
18527
18795
|
}
|
|
18528
18796
|
),
|
|
@@ -18689,15 +18957,15 @@ function XViewScene({
|
|
|
18689
18957
|
}
|
|
18690
18958
|
),
|
|
18691
18959
|
/* @__PURE__ */ React30.createElement(
|
|
18692
|
-
|
|
18960
|
+
Boards,
|
|
18693
18961
|
{
|
|
18694
|
-
isOpen:
|
|
18695
|
-
onClose: () =>
|
|
18962
|
+
isOpen: isBoardsOpen,
|
|
18963
|
+
onClose: () => setIsBoardsOpen(false),
|
|
18696
18964
|
onSelect: handleSelectAncestryFromBoard,
|
|
18697
18965
|
availableAncestries: allAvailableAncestries,
|
|
18698
18966
|
availableNodes: allAvailableNodes,
|
|
18699
|
-
|
|
18700
|
-
onSave:
|
|
18967
|
+
initialBoardItems: boardItems,
|
|
18968
|
+
onSave: handleSaveBoards,
|
|
18701
18969
|
userRole: userPermissionRole
|
|
18702
18970
|
}
|
|
18703
18971
|
),
|
|
@@ -18706,7 +18974,7 @@ function XViewScene({
|
|
|
18706
18974
|
{
|
|
18707
18975
|
isOpen: isMilestoneManagerOpen,
|
|
18708
18976
|
onClose: () => setIsMilestoneManagerOpen(false),
|
|
18709
|
-
milestones: ((
|
|
18977
|
+
milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
|
|
18710
18978
|
onUpdateMilestones: handleUpdateMilestones
|
|
18711
18979
|
}
|
|
18712
18980
|
),
|
|
@@ -18717,7 +18985,7 @@ function XViewScene({
|
|
|
18717
18985
|
onClose: () => setIsImportModalOpen(false),
|
|
18718
18986
|
onConfirm: handleConfirmImport,
|
|
18719
18987
|
session,
|
|
18720
|
-
parentDbs: ((
|
|
18988
|
+
parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
|
|
18721
18989
|
onFetchAvailableFiles: import_parent_file_modal_get,
|
|
18722
18990
|
currentViewName: viewParams == null ? void 0 : viewParams.name,
|
|
18723
18991
|
currentAncestries: ancestryDataRef.current || []
|
|
@@ -18801,6 +19069,450 @@ function XViewScene({
|
|
|
18801
19069
|
)
|
|
18802
19070
|
);
|
|
18803
19071
|
}
|
|
19072
|
+
|
|
19073
|
+
// src/x_view_server_logic.js
|
|
19074
|
+
async function save_view_data_logic(db_services, filename, data) {
|
|
19075
|
+
try {
|
|
19076
|
+
const saveResult = await db_services.save_file(filename, data);
|
|
19077
|
+
return saveResult;
|
|
19078
|
+
} catch (error) {
|
|
19079
|
+
console.error("catch (error) em save_view_data_logic:", error);
|
|
19080
|
+
return { success: false, error: error.message };
|
|
19081
|
+
}
|
|
19082
|
+
}
|
|
19083
|
+
async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
|
|
19084
|
+
var _a, _b;
|
|
19085
|
+
try {
|
|
19086
|
+
if (!session || !session.user) {
|
|
19087
|
+
return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
|
|
19088
|
+
}
|
|
19089
|
+
const membershipCheck = await db_services.check_membership(owner_id, type, scene_config, session.user.id);
|
|
19090
|
+
const isFullMember = membershipCheck.success && membershipCheck.isValidMember;
|
|
19091
|
+
if (!isFullMember && !focusNodeId && !focusAncestryId) {
|
|
19092
|
+
return { success: false, error: "Acesso Negado: Voc\xEA n\xE3o possui permiss\xE3o para acessar este cen\xE1rio." };
|
|
19093
|
+
}
|
|
19094
|
+
const sceneResponse = await db_services.get_file(`x_view_scenes/${owner_id}/${scene_config}`);
|
|
19095
|
+
if (!sceneResponse || !sceneResponse.success) {
|
|
19096
|
+
console.error("Falha ao buscar dados da cena:", sceneResponse == null ? void 0 : sceneResponse.error);
|
|
19097
|
+
return { success: false, error: `N\xE3o foi poss\xEDvel carregar o arquivo da cena: ${scene_config}` };
|
|
19098
|
+
}
|
|
19099
|
+
const sceneData = sceneResponse.data;
|
|
19100
|
+
const parentDbObjects = sceneData.parent_dbs || [];
|
|
19101
|
+
if (type && type.toLowerCase().includes("database")) {
|
|
19102
|
+
const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
|
|
19103
|
+
if (!selfExists) {
|
|
19104
|
+
parentDbObjects.push({ db_id: scene_config, owner_id });
|
|
19105
|
+
}
|
|
19106
|
+
}
|
|
19107
|
+
const parentResponsesPromises = parentDbObjects.map(
|
|
19108
|
+
(db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
|
|
19109
|
+
);
|
|
19110
|
+
const parentResponsesResults = await Promise.allSettled(parentResponsesPromises);
|
|
19111
|
+
const parentData = {};
|
|
19112
|
+
for (let i = 0; i < parentResponsesResults.length; i++) {
|
|
19113
|
+
const result = parentResponsesResults[i];
|
|
19114
|
+
const db_info = parentDbObjects[i];
|
|
19115
|
+
if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
|
|
19116
|
+
parentData[db_info.db_id] = result.value.data;
|
|
19117
|
+
} else {
|
|
19118
|
+
console.warn(
|
|
19119
|
+
`Arquivo pai n\xE3o carregado: ${db_info.db_id}. Pode ter sido deletado.`,
|
|
19120
|
+
result.status === "rejected" ? result.reason : (_b = result.value) == null ? void 0 : _b.error
|
|
19121
|
+
);
|
|
19122
|
+
}
|
|
19123
|
+
}
|
|
19124
|
+
if (type && type.toLowerCase() === "view") {
|
|
19125
|
+
parentData[scene_config] = {
|
|
19126
|
+
dataset_name: "Quests Internas (View)",
|
|
19127
|
+
nodes: sceneData.quest_nodes || [],
|
|
19128
|
+
links: sceneData.quest_links || []
|
|
19129
|
+
};
|
|
19130
|
+
}
|
|
19131
|
+
const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
19132
|
+
const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
|
|
19133
|
+
const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
|
|
19134
|
+
const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
|
|
19135
|
+
const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
|
|
19136
|
+
var _a2, _b2;
|
|
19137
|
+
const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
|
|
19138
|
+
if (nodeTypes.includes("quest")) {
|
|
19139
|
+
const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
|
|
19140
|
+
if (dbQuestNode) {
|
|
19141
|
+
return { ...sceneNode, ...dbQuestNode };
|
|
19142
|
+
}
|
|
19143
|
+
return sceneNode;
|
|
19144
|
+
}
|
|
19145
|
+
const dbNode = parentNodeMap.get(String(sceneNode.id));
|
|
19146
|
+
if (dbNode) {
|
|
19147
|
+
return { ...sceneNode, ...dbNode };
|
|
19148
|
+
}
|
|
19149
|
+
return null;
|
|
19150
|
+
}).filter(Boolean);
|
|
19151
|
+
const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
|
|
19152
|
+
const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
|
|
19153
|
+
const linkExistsInParent = parentLinkMap.has(`${sceneLink.source}-${sceneLink.target}`);
|
|
19154
|
+
const nodesAreValidForScene = validNodeIdsInScene.has(String(sceneLink.source)) && validNodeIdsInScene.has(String(sceneLink.target));
|
|
19155
|
+
return linkExistsInParent && nodesAreValidForScene;
|
|
19156
|
+
}).map((sceneLink) => parentLinkMap.get(`${sceneLink.source}-${sceneLink.target}`));
|
|
19157
|
+
const validatedSceneData = {
|
|
19158
|
+
...sceneData,
|
|
19159
|
+
nodes: validatedNodes,
|
|
19160
|
+
links: validatedLinks
|
|
19161
|
+
};
|
|
19162
|
+
const ancestryFilePaths = [];
|
|
19163
|
+
ancestryFilePaths.push({
|
|
19164
|
+
path: `x_view_ancestry/${owner_id}/${scene_config}`,
|
|
19165
|
+
source_id: scene_config,
|
|
19166
|
+
owner_id,
|
|
19167
|
+
isSceneFile: true
|
|
19168
|
+
});
|
|
19169
|
+
parentDbObjects.forEach((db_info) => {
|
|
19170
|
+
ancestryFilePaths.push({
|
|
19171
|
+
path: `x_view_ancestry/${db_info.owner_id}/${db_info.db_id}`,
|
|
19172
|
+
source_id: db_info.db_id,
|
|
19173
|
+
owner_id: db_info.owner_id,
|
|
19174
|
+
isSceneFile: false
|
|
19175
|
+
});
|
|
19176
|
+
});
|
|
19177
|
+
const ancestryPromises = ancestryFilePaths.map((file) => db_services.get_file(file.path));
|
|
19178
|
+
const ancestryResults = await Promise.allSettled(ancestryPromises);
|
|
19179
|
+
const ancestriesFromSceneFile = [];
|
|
19180
|
+
const ancestriesFromDbFiles = [];
|
|
19181
|
+
ancestryResults.forEach((result, index) => {
|
|
19182
|
+
var _a2;
|
|
19183
|
+
const fileInfo = ancestryFilePaths[index];
|
|
19184
|
+
if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
|
|
19185
|
+
const ancestriesFromFile = result.value.data.map((ancestry) => {
|
|
19186
|
+
const existingSource = ancestry._source_file_id;
|
|
19187
|
+
const existingOwner = ancestry._source_owner_id;
|
|
19188
|
+
const isImportedItem = existingSource && existingSource !== fileInfo.source_id;
|
|
19189
|
+
return {
|
|
19190
|
+
...ancestry,
|
|
19191
|
+
_source_file_id: isImportedItem ? existingSource : fileInfo.source_id,
|
|
19192
|
+
_source_owner_id: isImportedItem ? existingOwner : fileInfo.owner_id
|
|
19193
|
+
};
|
|
19194
|
+
});
|
|
19195
|
+
if (fileInfo.isSceneFile) {
|
|
19196
|
+
ancestriesFromSceneFile.push(...ancestriesFromFile);
|
|
19197
|
+
} else {
|
|
19198
|
+
ancestriesFromDbFiles.push(...ancestriesFromFile);
|
|
19199
|
+
}
|
|
19200
|
+
}
|
|
19201
|
+
});
|
|
19202
|
+
const ancestryMap = /* @__PURE__ */ new Map();
|
|
19203
|
+
ancestriesFromDbFiles.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
|
|
19204
|
+
ancestriesFromSceneFile.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
|
|
19205
|
+
let ancestryData = Array.from(ancestryMap.values());
|
|
19206
|
+
const externalSourcesToRefresh = /* @__PURE__ */ new Map();
|
|
19207
|
+
ancestryData.forEach((anc) => {
|
|
19208
|
+
const targetSourceId = anc._source_file_id || anc._imported_from_view_id;
|
|
19209
|
+
const targetOwnerId = anc._source_owner_id || anc._imported_from_view_owner_id;
|
|
19210
|
+
if (targetSourceId && targetSourceId !== scene_config && targetOwnerId) {
|
|
19211
|
+
const isAlreadyLoadedAsParent = parentDbObjects.some((db) => String(db.db_id) === String(targetSourceId));
|
|
19212
|
+
if (!isAlreadyLoadedAsParent) {
|
|
19213
|
+
const key = `${targetOwnerId}/${targetSourceId}`;
|
|
19214
|
+
externalSourcesToRefresh.set(key, {
|
|
19215
|
+
owner_id: targetOwnerId,
|
|
19216
|
+
source_id: targetSourceId,
|
|
19217
|
+
key
|
|
19218
|
+
});
|
|
19219
|
+
}
|
|
19220
|
+
}
|
|
19221
|
+
});
|
|
19222
|
+
const successfullyFetchedSources = /* @__PURE__ */ new Set();
|
|
19223
|
+
const failedSources = /* @__PURE__ */ new Set();
|
|
19224
|
+
if (externalSourcesToRefresh.size > 0) {
|
|
19225
|
+
const refreshPromises = Array.from(externalSourcesToRefresh.values()).map(
|
|
19226
|
+
(src) => db_services.get_file(`x_view_ancestry/${src.owner_id}/${src.source_id}`).then((res) => ({ ...res, _meta_key: src.key }))
|
|
19227
|
+
);
|
|
19228
|
+
const refreshResults = await Promise.allSettled(refreshPromises);
|
|
19229
|
+
const freshAncestryMap = /* @__PURE__ */ new Map();
|
|
19230
|
+
refreshResults.forEach((result) => {
|
|
19231
|
+
var _a2, _b2;
|
|
19232
|
+
if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
|
|
19233
|
+
successfullyFetchedSources.add(result.value._meta_key);
|
|
19234
|
+
result.value.data.forEach((freshAnc) => {
|
|
19235
|
+
if (!freshAnc.is_private) {
|
|
19236
|
+
freshAncestryMap.set(String(freshAnc.ancestry_id), freshAnc);
|
|
19237
|
+
}
|
|
19238
|
+
});
|
|
19239
|
+
} else if (result.status === "fulfilled" && !((_b2 = result.value) == null ? void 0 : _b2.success)) {
|
|
19240
|
+
failedSources.add(result.value._meta_key);
|
|
19241
|
+
}
|
|
19242
|
+
});
|
|
19243
|
+
ancestryData = ancestryData.filter((localAnc) => {
|
|
19244
|
+
const targetSourceId = localAnc._source_file_id || localAnc._imported_from_view_id;
|
|
19245
|
+
const targetOwnerId = localAnc._source_owner_id || localAnc._imported_from_view_owner_id;
|
|
19246
|
+
if (!targetSourceId || targetSourceId === scene_config) return true;
|
|
19247
|
+
const key = `${targetOwnerId}/${targetSourceId}`;
|
|
19248
|
+
if (failedSources.has(key)) {
|
|
19249
|
+
return false;
|
|
19250
|
+
}
|
|
19251
|
+
if (externalSourcesToRefresh.has(key) && successfullyFetchedSources.has(key)) {
|
|
19252
|
+
const stillExists = freshAncestryMap.has(String(localAnc.ancestry_id));
|
|
19253
|
+
return stillExists;
|
|
19254
|
+
}
|
|
19255
|
+
return true;
|
|
19256
|
+
}).map((localAnc) => {
|
|
19257
|
+
const freshVersion = freshAncestryMap.get(String(localAnc.ancestry_id));
|
|
19258
|
+
if (freshVersion) {
|
|
19259
|
+
return {
|
|
19260
|
+
...freshVersion,
|
|
19261
|
+
_imported_from_view_id: localAnc._imported_from_view_id,
|
|
19262
|
+
_imported_from_view_owner_id: localAnc._imported_from_view_owner_id,
|
|
19263
|
+
_origin_db_ids: localAnc._origin_db_ids,
|
|
19264
|
+
_source_file_id: localAnc._source_file_id,
|
|
19265
|
+
_source_owner_id: localAnc._source_owner_id
|
|
19266
|
+
};
|
|
19267
|
+
}
|
|
19268
|
+
return localAnc;
|
|
19269
|
+
});
|
|
19270
|
+
}
|
|
19271
|
+
const ancestryFilePath = `x_view_ancestry/${owner_id}/${scene_config}`;
|
|
19272
|
+
const parentNodeIds = new Set(allNodes.map((node) => String(node.id)));
|
|
19273
|
+
const pruneTree = (node) => {
|
|
19274
|
+
if (!node) return null;
|
|
19275
|
+
if (node.is_section) {
|
|
19276
|
+
const validChildren2 = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
|
|
19277
|
+
return { ...node, children: validChildren2 };
|
|
19278
|
+
}
|
|
19279
|
+
if (!parentNodeIds.has(String(node.node_id))) {
|
|
19280
|
+
return null;
|
|
19281
|
+
}
|
|
19282
|
+
const validChildren = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
|
|
19283
|
+
let validBranches = [];
|
|
19284
|
+
if (node.parallel_branches) {
|
|
19285
|
+
validBranches = node.parallel_branches.map((branch) => ({
|
|
19286
|
+
...branch,
|
|
19287
|
+
tree: pruneTree(branch.tree)
|
|
19288
|
+
})).filter((b) => b.tree !== null);
|
|
19289
|
+
}
|
|
19290
|
+
return {
|
|
19291
|
+
...node,
|
|
19292
|
+
children: validChildren,
|
|
19293
|
+
parallel_branches: validBranches
|
|
19294
|
+
};
|
|
19295
|
+
};
|
|
19296
|
+
const originalAncestryDataString = JSON.stringify(Array.from(ancestryMap.values()));
|
|
19297
|
+
const cleanedAncestryData = ancestryData.map((ancestry) => {
|
|
19298
|
+
if (!parentNodeIds.has(String(ancestry.ancestral_node))) return null;
|
|
19299
|
+
const cleanedTree = pruneTree(ancestry.tree);
|
|
19300
|
+
if (!cleanedTree) return null;
|
|
19301
|
+
let cleanedAbstraction = null;
|
|
19302
|
+
if (ancestry.abstraction_tree) {
|
|
19303
|
+
cleanedAbstraction = pruneTree(ancestry.abstraction_tree);
|
|
19304
|
+
}
|
|
19305
|
+
return {
|
|
19306
|
+
...ancestry,
|
|
19307
|
+
tree: cleanedTree,
|
|
19308
|
+
abstraction_tree: cleanedAbstraction
|
|
19309
|
+
};
|
|
19310
|
+
}).filter(Boolean);
|
|
19311
|
+
if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
|
|
19312
|
+
ancestryData = cleanedAncestryData;
|
|
19313
|
+
try {
|
|
19314
|
+
await db_services.save_file(ancestryFilePath, ancestryData);
|
|
19315
|
+
} catch (saveError) {
|
|
19316
|
+
console.error("Falha ao salvar o arquivo de ancestralidade da cena atualizado:", saveError);
|
|
19317
|
+
}
|
|
19318
|
+
}
|
|
19319
|
+
if (!isFullMember) {
|
|
19320
|
+
const requiredNodeIds = /* @__PURE__ */ new Set();
|
|
19321
|
+
const requiredAncestryIds = /* @__PURE__ */ new Set();
|
|
19322
|
+
if (focusNodeId) requiredNodeIds.add(String(focusNodeId));
|
|
19323
|
+
if (focusAncestryId) requiredAncestryIds.add(String(focusAncestryId));
|
|
19324
|
+
const allNodesFromDb = Object.values(parentData).flatMap((db) => db.nodes || []);
|
|
19325
|
+
const extractDependenciesFromText = (text) => {
|
|
19326
|
+
if (!text) return;
|
|
19327
|
+
const mentionRegex = /\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g;
|
|
19328
|
+
const refRegex = /\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g;
|
|
19329
|
+
let match;
|
|
19330
|
+
while ((match = mentionRegex.exec(text)) !== null) {
|
|
19331
|
+
requiredNodeIds.add(match[1]);
|
|
19332
|
+
}
|
|
19333
|
+
while ((match = refRegex.exec(text)) !== null) {
|
|
19334
|
+
if (match[1] === "node") requiredNodeIds.add(match[2]);
|
|
19335
|
+
if (match[1] === "ancestry") requiredAncestryIds.add(match[2]);
|
|
19336
|
+
}
|
|
19337
|
+
};
|
|
19338
|
+
const extractTreeDependencies = (treeItem) => {
|
|
19339
|
+
var _a2;
|
|
19340
|
+
if (!treeItem) return;
|
|
19341
|
+
if (treeItem.node_id) requiredNodeIds.add(String(treeItem.node_id));
|
|
19342
|
+
if ((_a2 = treeItem.node) == null ? void 0 : _a2.id) requiredNodeIds.add(String(treeItem.node.id));
|
|
19343
|
+
if (treeItem.children) {
|
|
19344
|
+
treeItem.children.forEach(extractTreeDependencies);
|
|
19345
|
+
}
|
|
19346
|
+
if (treeItem.parallel_branches) {
|
|
19347
|
+
treeItem.parallel_branches.forEach((branch) => {
|
|
19348
|
+
if (branch.linked_ancestry_id) {
|
|
19349
|
+
requiredAncestryIds.add(String(branch.linked_ancestry_id));
|
|
19350
|
+
}
|
|
19351
|
+
if (branch.description) extractDependenciesFromText(branch.description);
|
|
19352
|
+
if (branch.description_sections) {
|
|
19353
|
+
branch.description_sections.forEach((s) => extractDependenciesFromText(s.content));
|
|
19354
|
+
}
|
|
19355
|
+
extractTreeDependencies(branch.tree);
|
|
19356
|
+
});
|
|
19357
|
+
}
|
|
19358
|
+
};
|
|
19359
|
+
let previousSize;
|
|
19360
|
+
do {
|
|
19361
|
+
previousSize = requiredNodeIds.size + requiredAncestryIds.size;
|
|
19362
|
+
requiredAncestryIds.forEach((ancId) => {
|
|
19363
|
+
const anc = ancestryData.find((a) => String(a.ancestry_id) === ancId);
|
|
19364
|
+
if (anc && !anc.is_private) {
|
|
19365
|
+
if (anc.description) extractDependenciesFromText(anc.description);
|
|
19366
|
+
if (anc.description_sections) {
|
|
19367
|
+
anc.description_sections.forEach((s) => extractDependenciesFromText(s.content));
|
|
19368
|
+
}
|
|
19369
|
+
extractTreeDependencies(anc.tree);
|
|
19370
|
+
extractTreeDependencies(anc.abstraction_tree);
|
|
19371
|
+
}
|
|
19372
|
+
});
|
|
19373
|
+
requiredNodeIds.forEach((nodeId) => {
|
|
19374
|
+
const node = allNodesFromDb.find((n) => String(n.id) === nodeId);
|
|
19375
|
+
if (node) {
|
|
19376
|
+
if (node.description) extractDependenciesFromText(node.description);
|
|
19377
|
+
if (node.description_sections) {
|
|
19378
|
+
node.description_sections.forEach((s) => extractDependenciesFromText(s.content));
|
|
19379
|
+
}
|
|
19380
|
+
}
|
|
19381
|
+
});
|
|
19382
|
+
} while (requiredNodeIds.size + requiredAncestryIds.size > previousSize);
|
|
19383
|
+
const restrictedSceneData = { ...validatedSceneData, nodes: [], links: [] };
|
|
19384
|
+
const restrictedParentData = {};
|
|
19385
|
+
const restrictedAncestryData = ancestryData.filter((a) => requiredAncestryIds.has(String(a.ancestry_id)) && !a.is_private);
|
|
19386
|
+
for (const [dbId, dbContent] of Object.entries(parentData)) {
|
|
19387
|
+
const filteredNodes = (dbContent.nodes || []).filter((n) => requiredNodeIds.has(String(n.id)));
|
|
19388
|
+
if (filteredNodes.length > 0) {
|
|
19389
|
+
restrictedParentData[dbId] = { ...dbContent, nodes: filteredNodes, links: [] };
|
|
19390
|
+
}
|
|
19391
|
+
}
|
|
19392
|
+
if (focusNodeId) {
|
|
19393
|
+
const mainNode = allNodesFromDb.find((n) => String(n.id) === String(focusNodeId));
|
|
19394
|
+
if (mainNode) {
|
|
19395
|
+
restrictedSceneData.nodes = [mainNode];
|
|
19396
|
+
}
|
|
19397
|
+
}
|
|
19398
|
+
return {
|
|
19399
|
+
success: true,
|
|
19400
|
+
data: {
|
|
19401
|
+
scene: restrictedSceneData,
|
|
19402
|
+
parent: restrictedParentData,
|
|
19403
|
+
ancestry: restrictedAncestryData
|
|
19404
|
+
}
|
|
19405
|
+
};
|
|
19406
|
+
}
|
|
19407
|
+
return {
|
|
19408
|
+
success: true,
|
|
19409
|
+
data: { scene: validatedSceneData, parent: parentData, ancestry: ancestryData }
|
|
19410
|
+
};
|
|
19411
|
+
} catch (error) {
|
|
19412
|
+
console.error("Erro em get_scene_view_data_logic:", error);
|
|
19413
|
+
return { success: false, error: error.message };
|
|
19414
|
+
}
|
|
19415
|
+
}
|
|
19416
|
+
async function import_parent_file_modal_get_logic(db_services, session) {
|
|
19417
|
+
try {
|
|
19418
|
+
const call_firestore_get_x_view_data = await db_services.get_firestore_data(session);
|
|
19419
|
+
const x_view_databases = call_firestore_get_x_view_data.data.sub_collections.x_view_databases || [];
|
|
19420
|
+
const x_views = call_firestore_get_x_view_data.data.sub_collections.x_views || [];
|
|
19421
|
+
return {
|
|
19422
|
+
success: true,
|
|
19423
|
+
data: {
|
|
19424
|
+
databases: x_view_databases,
|
|
19425
|
+
views: x_views
|
|
19426
|
+
}
|
|
19427
|
+
};
|
|
19428
|
+
} catch (error) {
|
|
19429
|
+
console.error("catch (error) em import_parent_file_modal_get_logic:", error);
|
|
19430
|
+
return { success: false, error: error.message };
|
|
19431
|
+
}
|
|
19432
|
+
}
|
|
19433
|
+
async function get_single_parent_file_logic(db_services, file_id, session) {
|
|
19434
|
+
try {
|
|
19435
|
+
const call_GCP_cloud_storage_get_file = await db_services.get_file(`x_view_dbs/${session.user.id}/${file_id}`);
|
|
19436
|
+
return call_GCP_cloud_storage_get_file;
|
|
19437
|
+
} catch (error) {
|
|
19438
|
+
console.error("catch (error) em get_single_parent_file_logic:", error);
|
|
19439
|
+
return { success: false, error: error.message };
|
|
19440
|
+
}
|
|
19441
|
+
}
|
|
19442
|
+
async function x_view_add_new_parent_file_to_scene_at_firebase(file_id, session, new_parent, db_services) {
|
|
19443
|
+
try {
|
|
19444
|
+
const update_data = {
|
|
19445
|
+
scene_id: file_id,
|
|
19446
|
+
new_parent,
|
|
19447
|
+
session
|
|
19448
|
+
};
|
|
19449
|
+
const call_firestore_add_new_parent_file_to_scene_at_firebase = await db_services.add_new_parent_file_to_scene_at_firebase(update_data);
|
|
19450
|
+
return call_firestore_add_new_parent_file_to_scene_at_firebase;
|
|
19451
|
+
} catch (error) {
|
|
19452
|
+
console.error("catch (error) em get_single_parent_file_logic:", error);
|
|
19453
|
+
return { success: false, error: error.message };
|
|
19454
|
+
}
|
|
19455
|
+
}
|
|
19456
|
+
async function get_ancestry_file_logic(db_services, file_id, owner_id) {
|
|
19457
|
+
try {
|
|
19458
|
+
const path = `x_view_ancestry/${owner_id}/${file_id}`;
|
|
19459
|
+
const call_GCP_cloud_storage_get_file = await db_services.get_file(path);
|
|
19460
|
+
return call_GCP_cloud_storage_get_file;
|
|
19461
|
+
} catch (error) {
|
|
19462
|
+
console.error("catch (error) em get_ancestry_file_logic:", error);
|
|
19463
|
+
return { success: false, error: error.message };
|
|
19464
|
+
}
|
|
19465
|
+
}
|
|
19466
|
+
async function save_boards_logic(db_services, scene_id, type, boardItems, session, owner_id) {
|
|
19467
|
+
try {
|
|
19468
|
+
const targetOwnerId = owner_id || session.user.id;
|
|
19469
|
+
return await db_services.save_boards(session, scene_id, type, boardItems, targetOwnerId);
|
|
19470
|
+
} catch (error) {
|
|
19471
|
+
console.error("Erro em save_boards_logic:", error);
|
|
19472
|
+
return { success: false, error: error.message };
|
|
19473
|
+
}
|
|
19474
|
+
}
|
|
19475
|
+
async function get_boards_logic(db_services, scene_id, type, session, owner_id) {
|
|
19476
|
+
try {
|
|
19477
|
+
const targetOwnerId = owner_id || session.user.id;
|
|
19478
|
+
return await db_services.get_boards(session, scene_id, type, targetOwnerId);
|
|
19479
|
+
} catch (error) {
|
|
19480
|
+
console.error("Erro em get_boards_logic:", error);
|
|
19481
|
+
return { success: false, error: error.message };
|
|
19482
|
+
}
|
|
19483
|
+
}
|
|
19484
|
+
async function delete_uploaded_file_logic(db_services, fileUrl) {
|
|
19485
|
+
try {
|
|
19486
|
+
if (db_services.delete_public_file) {
|
|
19487
|
+
return await db_services.delete_public_file(fileUrl);
|
|
19488
|
+
}
|
|
19489
|
+
return { success: false, error: "Servi\xE7o de dele\xE7\xE3o n\xE3o configurado." };
|
|
19490
|
+
} catch (error) {
|
|
19491
|
+
console.error("Erro em delete_uploaded_file_logic:", error);
|
|
19492
|
+
return { success: false, error: error.message };
|
|
19493
|
+
}
|
|
19494
|
+
}
|
|
19495
|
+
async function get_view_members_logic(db_services, ownerId, type, itemId) {
|
|
19496
|
+
try {
|
|
19497
|
+
if (!db_services.get_view_members) {
|
|
19498
|
+
return { success: false, error: "Servi\xE7o de busca de membros n\xE3o configurado." };
|
|
19499
|
+
}
|
|
19500
|
+
return await db_services.get_view_members(ownerId, type, itemId);
|
|
19501
|
+
} catch (error) {
|
|
19502
|
+
console.error("Erro em get_view_members_logic:", error);
|
|
19503
|
+
return { success: false, error: error.message };
|
|
19504
|
+
}
|
|
19505
|
+
}
|
|
18804
19506
|
export {
|
|
18805
|
-
XViewScene
|
|
19507
|
+
XViewScene,
|
|
19508
|
+
delete_uploaded_file_logic,
|
|
19509
|
+
get_ancestry_file_logic,
|
|
19510
|
+
get_boards_logic,
|
|
19511
|
+
get_scene_view_data_logic,
|
|
19512
|
+
get_single_parent_file_logic,
|
|
19513
|
+
get_view_members_logic,
|
|
19514
|
+
import_parent_file_modal_get_logic,
|
|
19515
|
+
save_boards_logic,
|
|
19516
|
+
save_view_data_logic,
|
|
19517
|
+
x_view_add_new_parent_file_to_scene_at_firebase
|
|
18806
19518
|
};
|