@lv-x-software-house/x_view 1.2.6-dev.3 → 1.2.6-dev.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +960 -605
  2. package/dist/index.mjs +908 -575
  3. package/package.json +4 -22
package/dist/index.mjs CHANGED
@@ -1,12 +1,10 @@
1
- "use client";
2
-
3
1
  // src/XViewScene.jsx
4
- import React30, {
2
+ import React28, {
5
3
  useCallback as useCallback4,
6
- useEffect as useEffect24,
4
+ useEffect as useEffect22,
7
5
  useRef as useRef19,
8
- useState as useState28,
9
- useMemo as useMemo13
6
+ useState as useState27,
7
+ useMemo as useMemo12
10
8
  } from "react";
11
9
  import { useRouter, useSearchParams } from "next/navigation";
12
10
  import { useSession } from "next-auth/react";
@@ -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) {
@@ -12945,10 +12950,10 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
12945
12950
  }
12946
12951
 
12947
12952
  // src/components/AncestryBoard.jsx
12948
- import React28, { useState as useState26, useMemo as useMemo12, useEffect as useEffect23, useRef as useRef18 } from "react";
12953
+ import React26, { useState as useState25, useMemo as useMemo11, useEffect as useEffect21, useRef as useRef18 } from "react";
12949
12954
  import {
12950
- FiSearch as FiSearch9,
12951
- FiLayers as FiLayers7,
12955
+ FiSearch as FiSearch8,
12956
+ FiLayers as FiLayers6,
12952
12957
  FiCornerUpRight as FiCornerUpRight4,
12953
12958
  FiPlay,
12954
12959
  FiPlus as FiPlus10,
@@ -12959,384 +12964,132 @@ import {
12959
12964
  FiLoader as FiLoader5,
12960
12965
  FiX as FiX8,
12961
12966
  FiAlertTriangle,
12962
- FiCheckSquare as FiCheckSquare4,
12963
- FiBox as FiBox2,
12964
- FiGitBranch as FiGitBranch4
12965
- } from "react-icons/fi";
12966
- import { v4 as uuidv411 } from "uuid";
12967
-
12968
- // src/components/MentionEditor.jsx
12969
- import React27, { useMemo as useMemo11, useEffect as useEffect22 } from "react";
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";
12974
-
12975
- // src/components/MentionList.jsx
12976
- import React26, {
12977
- forwardRef,
12978
- useEffect as useEffect21,
12979
- useImperativeHandle,
12980
- useState as useState25
12981
- } from "react";
12982
- import {
12983
- FiLayers as FiLayers6,
12984
- FiCheckSquare as FiCheckSquare3,
12985
12967
  FiBox,
12986
- FiGitBranch as FiGitBranch3,
12987
- FiSearch as FiSearch8
12968
+ FiCheckSquare as FiCheckSquare3,
12969
+ FiGitBranch as FiGitBranch3
12988
12970
  } from "react-icons/fi";
12989
- var MentionList = forwardRef((props, ref) => {
12990
- const [selectedIndex, setSelectedIndex] = useState25(0);
12991
- const selectItem = (index) => {
12992
- const item = props.items[index];
12993
- if (item) {
12994
- props.command({ id: item.id, label: item.name, type: item.type });
12995
- }
12996
- };
12997
- const upHandler = () => {
12998
- setSelectedIndex(
12999
- (selectedIndex + props.items.length - 1) % props.items.length
13000
- );
13001
- };
13002
- const downHandler = () => {
13003
- setSelectedIndex((selectedIndex + 1) % props.items.length);
13004
- };
13005
- const enterHandler = () => {
13006
- selectItem(selectedIndex);
13007
- };
13008
- useEffect21(() => setSelectedIndex(0), [props.items]);
13009
- useImperativeHandle(ref, () => ({
13010
- onKeyDown: ({ event }) => {
13011
- if (event.key === "ArrowUp") {
13012
- upHandler();
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;
13022
- }
13023
- return false;
13024
- }
13025
- }));
13026
- return /* @__PURE__ */ React26.createElement("div", { className: "z-[3000] bg-slate-900 border border-white/10 rounded-lg shadow-2xl overflow-hidden min-w-[280px] max-w-[400px] animate-in fade-in zoom-in-95 duration-200" }, /* @__PURE__ */ React26.createElement("div", { className: "p-2 border-b border-white/5 bg-slate-950/50 flex items-center gap-2" }, /* @__PURE__ */ React26.createElement(FiSearch8, { className: "text-indigo-400", size: 14 }), /* @__PURE__ */ React26.createElement("span", { className: "text-[10px] uppercase tracking-wider font-bold text-slate-500" }, "Mencionar Recurso")), /* @__PURE__ */ React26.createElement("div", { className: "p-1 max-h-[300px] overflow-y-auto custom-scrollbar" }, props.items.length ? props.items.map((item, index) => {
13027
- const isQuest = item.type === "quest";
13028
- const isVersion = item.type === "version";
13029
- const isNode = item.type === "node";
13030
- let Icon = FiLayers6;
13031
- let colorClass = "text-indigo-400";
13032
- let badgeText = "Ancestralidade";
13033
- if (isQuest) {
13034
- Icon = FiCheckSquare3;
13035
- colorClass = "text-amber-400";
13036
- badgeText = "Quest";
13037
- } else if (isVersion) {
13038
- Icon = FiGitBranch3;
13039
- colorClass = "text-purple-400";
13040
- badgeText = "Vers\xE3o";
13041
- } else if (isNode) {
13042
- Icon = FiBox;
13043
- colorClass = "text-emerald-400";
13044
- badgeText = "Node";
13045
- }
13046
- return /* @__PURE__ */ React26.createElement(
13047
- "button",
13048
- {
13049
- className: `
13050
- w-full flex items-center gap-3 px-3 py-2 text-left rounded-md transition-all
13051
- ${index === selectedIndex ? "bg-indigo-500/20 border border-indigo-500/30 text-white" : "text-slate-400 hover:bg-white/5 border border-transparent"}
13052
- `,
13053
- key: item.id,
13054
- onClick: () => selectItem(index)
13055
- },
13056
- /* @__PURE__ */ React26.createElement("div", { className: `shrink-0 w-8 h-8 rounded border border-white/5 flex items-center justify-center bg-slate-800/50 ${colorClass}` }, /* @__PURE__ */ React26.createElement(Icon, { size: 14 })),
13057
- /* @__PURE__ */ React26.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React26.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React26.createElement("span", { className: "text-sm font-medium truncate" }, item.name), /* @__PURE__ */ React26.createElement("span", { className: `text-[9px] px-1 py-0.5 rounded border border-current opacity-60 ${colorClass}` }, badgeText)))
13058
- );
13059
- }) : /* @__PURE__ */ React26.createElement("div", { className: "p-4 text-center text-slate-500 text-sm italic" }, "Nenhum resultado encontrado...")));
13060
- });
13061
- MentionList.displayName = "MentionList";
13062
- var MentionList_default = MentionList;
13063
-
13064
- // src/components/MentionEditor.jsx
13065
- var CustomMention = Mention.extend({
13066
- addAttributes() {
13067
- var _a;
13068
- return {
13069
- ...(_a = this.parent) == null ? void 0 : _a.call(this),
13070
- type: {
13071
- default: null,
13072
- parseHTML: (element) => element.getAttribute("data-mention-type"),
13073
- renderHTML: (attributes) => {
13074
- if (!attributes.type) {
13075
- return {};
13076
- }
13077
- return {
13078
- "data-mention-type": attributes.type
13079
- };
13080
- }
13081
- },
13082
- label: {
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
- };
13092
- }
13093
- }
13094
- };
13095
- }
13096
- });
13097
- var MentionEditor = ({
13098
- initialValue = "",
13099
- onChange,
13100
- onPlay,
13101
- availableItems = [],
13102
- canEdit = true,
13103
- placeholder = "Escreva algo... use @ para mencionar"
13104
- }) => {
13105
- const parseInitialContent = (text) => {
13106
- if (!text) return "<p></p>";
13107
- const parts = text.split(/(\[\[MENTION:[^\]]+\]\])/g);
13108
- return parts.map((part) => {
13109
- const match = part.match(/\[\[MENTION:([^:]+):([^:]+):([^\]]+)\]\]/);
13110
- if (match) {
13111
- const [, type, id, label] = match;
13112
- return `<span data-type="mention" data-id="${id}" data-mention-type="${type}" data-label="${label}">@${label}</span>`;
13113
- }
13114
- return part;
13115
- }).join("");
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);
13207
- }
13208
- });
13209
- if (!editor) {
13210
- return null;
13211
- }
13212
- return /* @__PURE__ */ React27.createElement("div", { className: "relative group/editor min-h-[1.5rem] w-full" }, /* @__PURE__ */ React27.createElement(
13213
- EditorContent,
13214
- {
13215
- editor,
13216
- className: "text-sm text-slate-200 placeholder-slate-600 focus:outline-none"
13217
- }
13218
- ), /* @__PURE__ */ React27.createElement("style", null, `
13219
- .tiptap p {
13220
- margin: 0;
13221
- min-height: 1.25rem;
13222
- line-height: 1.5;
13223
- }
13224
- .tiptap .mention {
13225
- display: inline-flex;
13226
- align-items: center;
13227
- background: rgba(99, 102, 241, 0.12);
13228
- border: 1px solid rgba(99, 102, 241, 0.25);
13229
- border-radius: 6px;
13230
- padding: 1px 6px;
13231
- color: #a5b4fc;
13232
- font-weight: 600;
13233
- cursor: pointer;
13234
- margin: 0 1px;
13235
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
13236
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
13237
- font-size: 0.85rem;
13238
- text-decoration: none;
13239
- vertical-align: baseline;
13240
- }
13241
- .tiptap .mention:hover {
13242
- background: rgba(99, 102, 241, 0.22);
13243
- border-color: rgba(99, 102, 241, 0.5);
13244
- color: #fff;
13245
- transform: translateY(-1px);
13246
- box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
13247
- }
13248
- .tiptap .mention::before {
13249
- content: "";
13250
- display: inline-block;
13251
- width: 12px;
13252
- height: 12px;
13253
- margin-right: 4px;
13254
- background-size: contain;
13255
- background-repeat: no-repeat;
13256
- opacity: 0.8;
13257
- filter: brightness(1.2);
13258
- }
13259
-
13260
- /* Type specific styles */
13261
- .tiptap .mention[data-mention-type="ancestry"] {
13262
- background: rgba(139, 92, 246, 0.15);
13263
- border-color: rgba(139, 92, 246, 0.3);
13264
- color: #c4b5fd;
13265
- }
13266
- .tiptap .mention[data-mention-type="quest"] {
13267
- background: rgba(16, 185, 129, 0.15);
13268
- border-color: rgba(16, 185, 129, 0.3);
13269
- color: #6ee7b7;
13270
- }
13271
- .tiptap .mention[data-mention-type="node"] {
13272
- background: rgba(59, 130, 246, 0.15);
13273
- border-color: rgba(59, 130, 246, 0.3);
13274
- color: #93c5fd;
13275
- }
13276
- .tiptap .mention[data-mention-type="version"] {
13277
- background: rgba(245, 158, 11, 0.15);
13278
- border-color: rgba(245, 158, 11, 0.3);
13279
- color: #fcd34d;
13280
- }
13281
-
13282
- .tiptap:focus {
13283
- outline: none;
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
- `));
13295
- };
13296
- var MentionEditor_default = MentionEditor;
13297
-
13298
- // src/components/AncestryBoard.jsx
12971
+ import { v4 as uuidv411 } from "uuid";
13299
12972
  var GroupItem = ({
13300
12973
  group,
13301
12974
  index,
12975
+ siblings,
13302
12976
  onUpdate,
13303
12977
  onDelete,
13304
12978
  onAddSubgroup,
13305
12979
  onIndent,
13306
12980
  onOutdent,
12981
+ onRemoveAncestry,
12982
+ onRequestPickAncestry,
12983
+ pickingGroupId,
13307
12984
  onPlayAncestry,
13308
- availableMentionItems,
12985
+ availableIds,
13309
12986
  canEdit
13310
12987
  }) => {
13311
12988
  const canIndent = index > 0;
13312
- 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(
12989
+ const isPickingForThisGroup = pickingGroupId === group.id;
12990
+ const textareaRef = useRef18(null);
12991
+ const adjustHeight = () => {
12992
+ const textarea = textareaRef.current;
12993
+ if (textarea) {
12994
+ textarea.style.height = "auto";
12995
+ textarea.style.height = `${textarea.scrollHeight}px`;
12996
+ }
12997
+ };
12998
+ useEffect21(() => {
12999
+ adjustHeight();
13000
+ }, [group.text]);
13001
+ return /* @__PURE__ */ React26.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__ */ React26.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React26.createElement(
13313
13002
  "div",
13314
13003
  {
13315
- 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"
13004
+ className: `
13005
+ flex flex-col gap-2 py-2 px-3 transition-all duration-200
13006
+ ${isPickingForThisGroup ? "bg-indigo-500/10 border-l-2 border-indigo-500" : "hover:bg-white/5 border-l-2 border-transparent hover:border-white/20"}
13007
+ `
13316
13008
  },
13317
- /* @__PURE__ */ React28.createElement(
13318
- MentionEditor_default,
13009
+ /* @__PURE__ */ React26.createElement(
13010
+ "textarea",
13319
13011
  {
13320
- initialValue: group.text,
13321
- onChange: (newText) => {
13322
- if (canEdit) onUpdate(group.id, { ...group, text: newText });
13012
+ ref: textareaRef,
13013
+ className: `w-full bg-transparent text-sm text-slate-200 placeholder-slate-600 resize-none focus:outline-none focus:placeholder-slate-500 overflow-y-auto ${!canEdit ? "cursor-default" : ""}`,
13014
+ rows: 1,
13015
+ style: {
13016
+ minHeight: "1.5rem",
13017
+ maxHeight: "250px"
13323
13018
  },
13324
- onPlay: onPlayAncestry,
13325
- availableItems: availableMentionItems,
13326
- canEdit,
13327
- placeholder: "Escreva sobre este grupo... use @ para mencionar"
13019
+ placeholder: canEdit ? "Escreva sobre este grupo..." : "",
13020
+ value: group.text,
13021
+ readOnly: !canEdit,
13022
+ onChange: (e) => {
13023
+ if (canEdit) onUpdate(group.id, { ...group, text: e.target.value });
13024
+ }
13328
13025
  }
13329
13026
  ),
13330
- canEdit && /* @__PURE__ */ React28.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-0 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React28.createElement(
13027
+ group.ancestries && group.ancestries.length > 0 && /* @__PURE__ */ React26.createElement("div", { className: "flex flex-wrap gap-2 mt-1" }, group.ancestries.map((anc) => {
13028
+ const isValid = availableIds.has(String(anc.ancestry_id));
13029
+ return /* @__PURE__ */ React26.createElement(
13030
+ "div",
13031
+ {
13032
+ key: anc.ancestry_id,
13033
+ className: `
13034
+ flex items-center gap-2 rounded-md px-3 py-1.5 text-xs transition-all group/card border
13035
+ ${isValid ? "bg-slate-800/60 border-white/10 hover:border-indigo-500/30 text-slate-200" : "bg-red-900/10 border-red-500/30 text-red-300/70 hover:bg-red-900/20"}
13036
+ `,
13037
+ title: isValid ? "" : "Esta ancestralidade foi removida ou n\xE3o existe mais."
13038
+ },
13039
+ isValid ? /* @__PURE__ */ React26.createElement(
13040
+ "button",
13041
+ {
13042
+ onClick: () => onPlayAncestry(anc),
13043
+ className: "text-indigo-400 hover:text-white hover:bg-indigo-500 p-1 rounded-full transition-colors",
13044
+ title: "Focar no cen\xE1rio"
13045
+ },
13046
+ /* @__PURE__ */ React26.createElement(FiPlay, { size: 10, className: "ml-0.5 fill-current" })
13047
+ ) : /* @__PURE__ */ React26.createElement("div", { className: "p-1 text-red-500 cursor-not-allowed" }, /* @__PURE__ */ React26.createElement(FiAlertTriangle, { size: 10 })),
13048
+ /* @__PURE__ */ React26.createElement(
13049
+ "div",
13050
+ {
13051
+ className: `flex items-center gap-1.5 font-medium truncate max-w-[180px] ${!isValid && "line-through decoration-red-500/50"}`
13052
+ },
13053
+ !isValid ? null : anc.type === "node" ? /* @__PURE__ */ React26.createElement(FiBox, { size: 10, className: "text-slate-400" }) : anc.type === "quest" ? /* @__PURE__ */ React26.createElement(FiCheckSquare3, { size: 10, className: "text-emerald-400" }) : anc.type === "version" ? /* @__PURE__ */ React26.createElement(FiGitBranch3, { size: 10, className: "text-amber-400" }) : /* @__PURE__ */ React26.createElement(FiLayers6, { size: 10, className: "text-indigo-400" }),
13054
+ anc.name
13055
+ ),
13056
+ canEdit && /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement(
13057
+ "div",
13058
+ {
13059
+ className: `w-px h-3 mx-0.5 ${isValid ? "bg-white/10" : "bg-red-500/20"}`
13060
+ }
13061
+ ), /* @__PURE__ */ React26.createElement(
13062
+ "button",
13063
+ {
13064
+ onClick: () => onRemoveAncestry(group.id, anc.ancestry_id),
13065
+ className: `${isValid ? "text-slate-500 hover:text-red-400" : "text-red-400 hover:text-red-200"} p-0.5 rounded transition-colors`,
13066
+ title: "Remover men\xE7\xE3o"
13067
+ },
13068
+ /* @__PURE__ */ React26.createElement(FiX8, { size: 12 })
13069
+ ))
13070
+ );
13071
+ })),
13072
+ canEdit && /* @__PURE__ */ React26.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__ */ React26.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React26.createElement(
13073
+ "button",
13074
+ {
13075
+ onClick: () => onRequestPickAncestry(group.id),
13076
+ className: `
13077
+ flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium transition-colors
13078
+ ${isPickingForThisGroup ? "text-indigo-300 animate-pulse" : "text-slate-500 hover:text-indigo-300 hover:bg-indigo-500/10"}
13079
+ `,
13080
+ title: "Adicionar Ancestralidade a este grupo"
13081
+ },
13082
+ isPickingForThisGroup ? /* @__PURE__ */ React26.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React26.createElement(FiSearch8, { size: 12 }),
13083
+ isPickingForThisGroup ? "Selecionando..." : "Adicionar"
13084
+ ), /* @__PURE__ */ React26.createElement(
13331
13085
  "button",
13332
13086
  {
13333
13087
  onClick: () => onAddSubgroup(group.id),
13334
- className: "flex items-center gap-1.5 px-3 py-1.5 text-xs text-slate-500 hover:text-white hover:bg-white/10 rounded-md transition-colors",
13088
+ className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13335
13089
  title: "Criar Subgrupo"
13336
13090
  },
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(
13091
+ /* @__PURE__ */ React26.createElement(FiPlus10, { size: 14 })
13092
+ )), /* @__PURE__ */ React26.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React26.createElement(
13340
13093
  "button",
13341
13094
  {
13342
13095
  onClick: () => onIndent(group.id),
@@ -13344,25 +13097,25 @@ var GroupItem = ({
13344
13097
  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
13098
  title: "Aninhar no grupo acima"
13346
13099
  },
13347
- /* @__PURE__ */ React28.createElement(FiArrowRight2, { size: 14 })
13348
- ), /* @__PURE__ */ React28.createElement(
13100
+ /* @__PURE__ */ React26.createElement(FiArrowRight2, { size: 14 })
13101
+ ), /* @__PURE__ */ React26.createElement(
13349
13102
  "button",
13350
13103
  {
13351
13104
  onClick: () => onOutdent(group.id),
13352
13105
  className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13353
13106
  title: "Desaninhar"
13354
13107
  },
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(
13108
+ /* @__PURE__ */ React26.createElement(FiArrowLeft3, { size: 14 })
13109
+ ), /* @__PURE__ */ React26.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React26.createElement(
13357
13110
  "button",
13358
13111
  {
13359
13112
  onClick: () => onDelete(group.id),
13360
13113
  className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
13361
13114
  title: "Remover Grupo"
13362
13115
  },
13363
- /* @__PURE__ */ React28.createElement(FiTrash23, { size: 14 })
13116
+ /* @__PURE__ */ React26.createElement(FiTrash23, { size: 14 })
13364
13117
  )))
13365
- ), group.children && group.children.length > 0 && /* @__PURE__ */ React28.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React28.createElement(
13118
+ ), group.children && group.children.length > 0 && /* @__PURE__ */ React26.createElement("div", { className: "ml-2" }, group.children.map((childGroup, idx) => /* @__PURE__ */ React26.createElement(
13366
13119
  GroupItem,
13367
13120
  {
13368
13121
  key: childGroup.id,
@@ -13374,8 +13127,11 @@ var GroupItem = ({
13374
13127
  onAddSubgroup,
13375
13128
  onIndent,
13376
13129
  onOutdent,
13130
+ onRemoveAncestry,
13131
+ onRequestPickAncestry,
13132
+ pickingGroupId,
13377
13133
  onPlayAncestry,
13378
- availableMentionItems,
13134
+ availableIds,
13379
13135
  canEdit
13380
13136
  }
13381
13137
  ))));
@@ -13389,20 +13145,23 @@ function AncestryBoard({
13389
13145
  initialGroups = [],
13390
13146
  onSave,
13391
13147
  userRole
13148
+ // [NOVO] Recebe a role do usuário
13392
13149
  }) {
13393
- const [groups, setGroups] = useState26([]);
13394
- const [isLoaded, setIsLoaded] = useState26(false);
13395
- const [saveStatus, setSaveStatus] = useState26("idle");
13396
- const canEdit = useMemo12(() => {
13150
+ const [searchTerm, setSearchTerm] = useState25("");
13151
+ const [groups, setGroups] = useState25([]);
13152
+ const [isLoaded, setIsLoaded] = useState25(false);
13153
+ const [pickingGroupId, setPickingGroupId] = useState25(null);
13154
+ const [saveStatus, setSaveStatus] = useState25("idle");
13155
+ const canEdit = useMemo11(() => {
13397
13156
  return userRole !== "viewer";
13398
13157
  }, [userRole]);
13399
- useEffect23(() => {
13158
+ useEffect21(() => {
13400
13159
  if (initialGroups && !isLoaded) {
13401
13160
  setGroups(initialGroups);
13402
13161
  setIsLoaded(true);
13403
13162
  }
13404
13163
  }, [initialGroups, isLoaded]);
13405
- const nodeNamesMap = useMemo12(() => {
13164
+ const nodeNamesMap = useMemo11(() => {
13406
13165
  const map = /* @__PURE__ */ new Map();
13407
13166
  if (availableNodes && Array.isArray(availableNodes)) {
13408
13167
  availableNodes.forEach((node) => {
@@ -13413,41 +13172,52 @@ function AncestryBoard({
13413
13172
  }
13414
13173
  return map;
13415
13174
  }, [availableNodes]);
13416
- const availableIds = useMemo12(() => {
13417
- return new Set(availableAncestries.map((a) => String(a.ancestry_id)));
13418
- }, [availableAncestries]);
13419
- const availableMentionItems = useMemo12(() => {
13420
- const ancestries = availableAncestries.map((a) => ({
13421
- id: String(a.ancestry_id),
13422
- ancestry_id: a.ancestry_id,
13423
- name: a.name,
13424
- description: a.description,
13425
- type: "ancestry",
13426
- ancestral_node: a.ancestral_node,
13427
- is_private: a.is_private
13428
- }));
13429
- const nodes = availableNodes.map((n) => {
13175
+ const availableIds = useMemo11(() => {
13176
+ const ids = /* @__PURE__ */ new Set();
13177
+ availableAncestries.forEach((a) => ids.add(String(a.ancestry_id)));
13178
+ availableNodes.forEach((n) => ids.add(String(n.id)));
13179
+ return ids;
13180
+ }, [availableAncestries, availableNodes]);
13181
+ const allSearchableItems = useMemo11(() => {
13182
+ const items = [];
13183
+ availableAncestries.forEach((anc) => {
13184
+ items.push({
13185
+ ...anc,
13186
+ id: String(anc.ancestry_id),
13187
+ type: "ancestry",
13188
+ searchLabel: anc.name || "",
13189
+ searchDesc: anc.description || ""
13190
+ });
13191
+ });
13192
+ availableNodes.forEach((node) => {
13193
+ var _a;
13430
13194
  let type = "node";
13431
- if (n.is_quest) type = "quest";
13432
- else if (n.is_version) type = "version";
13433
- return {
13434
- id: String(n.id),
13435
- name: n.name,
13436
- description: n.description,
13195
+ if (node.is_quest) type = "quest";
13196
+ else if ((_a = node.version_node) == null ? void 0 : _a.is_version) type = "version";
13197
+ items.push({
13198
+ ...node,
13199
+ id: String(node.id),
13437
13200
  type,
13438
- raw_node: n
13439
- };
13201
+ searchLabel: node.name || node.raw_title || "",
13202
+ searchDesc: node.description || ""
13203
+ });
13440
13204
  });
13441
- return [...ancestries, ...nodes];
13205
+ return items;
13442
13206
  }, [availableAncestries, availableNodes]);
13443
13207
  const sanitizeGroups = (groupList) => {
13444
13208
  return groupList.map((g) => ({
13445
13209
  id: g.id,
13446
13210
  text: g.text || "",
13211
+ ancestries: (g.ancestries || []).map((a) => ({
13212
+ id: a.id || a.ancestry_id,
13213
+ ancestry_id: a.ancestry_id || a.id,
13214
+ name: a.name,
13215
+ type: a.type || "ancestry"
13216
+ })),
13447
13217
  children: sanitizeGroups(g.children || [])
13448
13218
  }));
13449
13219
  };
13450
- useEffect23(() => {
13220
+ useEffect21(() => {
13451
13221
  if (!isLoaded || !onSave) return;
13452
13222
  const timeoutId = setTimeout(async () => {
13453
13223
  setSaveStatus("saving");
@@ -13465,22 +13235,42 @@ function AncestryBoard({
13465
13235
  }, 3e3);
13466
13236
  return () => clearTimeout(timeoutId);
13467
13237
  }, [groups, isLoaded, onSave]);
13468
- useEffect23(() => {
13238
+ useEffect21(() => {
13469
13239
  if (!isOpen) return;
13470
13240
  const handleKeyDown = (e) => {
13471
13241
  if (e.key === "Escape") {
13472
- onClose();
13242
+ if (pickingGroupId) {
13243
+ setPickingGroupId(null);
13244
+ } else {
13245
+ onClose();
13246
+ }
13473
13247
  e.preventDefault();
13474
13248
  e.stopPropagation();
13475
13249
  }
13476
13250
  };
13477
13251
  window.addEventListener("keydown", handleKeyDown);
13478
13252
  return () => window.removeEventListener("keydown", handleKeyDown);
13479
- }, [isOpen, onClose]);
13253
+ }, [isOpen, onClose, pickingGroupId]);
13254
+ const filtered = useMemo11(() => {
13255
+ const term = searchTerm.toLowerCase().trim();
13256
+ return allSearchableItems.filter((item) => {
13257
+ var _a, _b;
13258
+ if (!term) return true;
13259
+ const labelMatch = (_a = item.searchLabel) == null ? void 0 : _a.toLowerCase().includes(term);
13260
+ const descMatch = (_b = item.searchDesc) == null ? void 0 : _b.toLowerCase().includes(term);
13261
+ let parentMatch = false;
13262
+ if (item.type === "ancestry") {
13263
+ const parentName = nodeNamesMap.get(String(item.ancestral_node)) || "";
13264
+ parentMatch = parentName.toLowerCase().includes(term);
13265
+ }
13266
+ return labelMatch || descMatch || parentMatch;
13267
+ });
13268
+ }, [allSearchableItems, searchTerm, nodeNamesMap]);
13480
13269
  const handleAddRootGroup = () => {
13481
13270
  const newGroup = {
13482
13271
  id: uuidv411(),
13483
13272
  text: "",
13273
+ ancestries: [],
13484
13274
  children: []
13485
13275
  };
13486
13276
  setGroups((prev) => [newGroup, ...prev]);
@@ -13489,6 +13279,7 @@ function AncestryBoard({
13489
13279
  const newGroup = {
13490
13280
  id: uuidv411(),
13491
13281
  text: "",
13282
+ ancestries: [],
13492
13283
  children: []
13493
13284
  };
13494
13285
  const addRecursive = (list) => {
@@ -13559,49 +13350,91 @@ function AncestryBoard({
13559
13350
  return newList;
13560
13351
  });
13561
13352
  };
13562
- const handlePlayFromGroup = (item) => {
13563
- let fullItem = item;
13564
- if (item.type === "ancestry" || !item.type) {
13565
- fullItem = availableAncestries.find(
13566
- (a) => String(a.ancestry_id) === String(item.id || item.ancestry_id)
13567
- ) || item;
13568
- } else {
13569
- fullItem = availableNodes.find(
13570
- (n) => String(n.id) === String(item.id)
13571
- ) || item;
13353
+ const handleRequestPick = (groupId) => {
13354
+ setPickingGroupId((prev) => prev === groupId ? null : groupId);
13355
+ };
13356
+ const handleSelectAncestry = (ancestry) => {
13357
+ if (pickingGroupId) {
13358
+ setGroups((prev) => {
13359
+ const addRecursive = (list) => {
13360
+ return list.map((g) => {
13361
+ if (g.id === pickingGroupId) {
13362
+ const exists = g.ancestries.some(
13363
+ (a) => String(a.id || a.ancestry_id) === String(ancestry.id)
13364
+ );
13365
+ if (exists) return g;
13366
+ return {
13367
+ ...g,
13368
+ ancestries: [
13369
+ ...g.ancestries,
13370
+ {
13371
+ id: ancestry.id,
13372
+ ancestry_id: ancestry.id,
13373
+ name: ancestry.searchLabel,
13374
+ type: ancestry.type
13375
+ }
13376
+ ]
13377
+ };
13378
+ }
13379
+ return { ...g, children: addRecursive(g.children) };
13380
+ });
13381
+ };
13382
+ return addRecursive(prev);
13383
+ });
13384
+ onSelect(ancestry);
13572
13385
  }
13573
- if (fullItem && onSelect) {
13574
- onSelect(fullItem);
13386
+ };
13387
+ const handlePlayFromGroup = (ancestry) => {
13388
+ if (ancestry && onSelect) {
13389
+ onSelect(ancestry);
13575
13390
  }
13576
13391
  };
13392
+ const handleRemoveAncestryFromGroup = (groupId, ancestryId) => {
13393
+ setGroups((prev) => {
13394
+ const removeRecursive = (list) => {
13395
+ return list.map((g) => {
13396
+ if (g.id === groupId) {
13397
+ return {
13398
+ ...g,
13399
+ ancestries: g.ancestries.filter(
13400
+ (a) => String(a.id || a.ancestry_id) !== String(ancestryId)
13401
+ )
13402
+ };
13403
+ }
13404
+ return { ...g, children: removeRecursive(g.children) };
13405
+ });
13406
+ };
13407
+ return removeRecursive(prev);
13408
+ });
13409
+ };
13577
13410
  if (!isOpen) return null;
13578
- return /* @__PURE__ */ React28.createElement(
13411
+ return /* @__PURE__ */ React26.createElement(
13579
13412
  "div",
13580
13413
  {
13581
13414
  className: "fixed inset-0 z-[2200] bg-black/80 backdrop-blur-sm flex items-center justify-center p-2",
13582
13415
  onClick: onClose
13583
13416
  },
13584
- /* @__PURE__ */ React28.createElement(
13417
+ /* @__PURE__ */ React26.createElement(
13585
13418
  "div",
13586
13419
  {
13587
- className: "bg-slate-950 border border-white/10 rounded-xl w-[90vw] max-w-[1200px] h-[90vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
13420
+ className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
13588
13421
  onClick: (e) => e.stopPropagation()
13589
13422
  },
13590
- /* @__PURE__ */ React28.createElement("div", { className: "h-14 px-6 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" }), "Ancestry Board"), 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(
13423
+ /* @__PURE__ */ React26.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React26.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React26.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React26.createElement(FiLayers6, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React26.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React26.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React26.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__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement(
13591
13424
  FiLoader5,
13592
13425
  {
13593
13426
  className: "animate-spin text-indigo-400",
13594
13427
  size: 12
13595
13428
  }
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(
13429
+ ), /* @__PURE__ */ React26.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React26.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React26.createElement(React26.Fragment, null, /* @__PURE__ */ React26.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React26.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React26.createElement("div", { className: "flex items-center gap-3" }, pickingGroupId && /* @__PURE__ */ React26.createElement("span", { className: "text-xs text-indigo-300 font-medium animate-pulse hidden sm:inline-block mr-2" }, "Selecione na lateral..."), canEdit && /* @__PURE__ */ React26.createElement(
13597
13430
  "button",
13598
13431
  {
13599
13432
  onClick: handleAddRootGroup,
13600
13433
  className: "\n flex items-center gap-2 px-3 py-1.5 \n bg-white/5 hover:bg-white/10 \n border border-white/10 hover:border-white/20\n backdrop-blur-sm\n text-slate-200 hover:text-white\n rounded-md transition-all duration-200\n text-xs font-medium shadow-sm\n "
13601
13434
  },
13602
- /* @__PURE__ */ React28.createElement(FiPlus10, { size: 14, className: "text-indigo-400" }),
13603
- /* @__PURE__ */ React28.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
13604
- ), /* @__PURE__ */ React28.createElement(
13435
+ /* @__PURE__ */ React26.createElement(FiPlus10, { size: 14, className: "text-indigo-400" }),
13436
+ /* @__PURE__ */ React26.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
13437
+ ), /* @__PURE__ */ React26.createElement(
13605
13438
  "button",
13606
13439
  {
13607
13440
  onClick: onClose,
@@ -13609,36 +13442,102 @@ function AncestryBoard({
13609
13442
  },
13610
13443
  "\xD7"
13611
13444
  ))),
13612
- /* @__PURE__ */ React28.createElement("div", { className: "flex flex-1 overflow-hidden bg-slate-900/20" }, /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col flex-1" }, /* @__PURE__ */ React28.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-8 max-w-[900px] mx-auto w-full space-y-6" }, groups.length === 0 ? /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-4 border-2 border-dashed border-white/5 rounded-2xl bg-slate-900/40 p-12" }, /* @__PURE__ */ React28.createElement(FiLayers7, { size: 40, className: "opacity-10 text-indigo-400" }), /* @__PURE__ */ React28.createElement("div", { className: "text-center space-y-1" }, /* @__PURE__ */ React28.createElement("p", { className: "text-sm font-medium text-slate-300" }, "Nenhum grupo criado"), /* @__PURE__ */ React28.createElement("p", { className: "text-xs text-slate-500 max-w-[200px]" }, canEdit ? "Comece organizando sua narrativa criando o primeiro grupo." : "Este board ainda n\xE3o possui conte\xFAdo.")), canEdit && /* @__PURE__ */ React28.createElement(
13613
- "button",
13445
+ /* @__PURE__ */ React26.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ React26.createElement(
13446
+ "div",
13614
13447
  {
13615
- onClick: handleAddRootGroup,
13616
- className: "mt-2 px-4 py-2 bg-indigo-500/10 hover:bg-indigo-500/20 text-indigo-400 rounded-lg border border-indigo-500/20 transition-all text-xs font-bold uppercase tracking-wider"
13448
+ className: `
13449
+ flex flex-col border-r border-white/10 transition-all duration-300 flex-none
13450
+ ${pickingGroupId ? "w-[25%] border-indigo-500/30" : "w-[20%]"}
13451
+ min-w-[280px] max-w-[500px] bg-slate-900
13452
+ `
13617
13453
  },
13618
- "Criar Primeiro Grupo"
13619
- )) : groups.map((group, index) => /* @__PURE__ */ React28.createElement(
13454
+ /* @__PURE__ */ React26.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React26.createElement("div", { className: "relative group" }, /* @__PURE__ */ React26.createElement(
13455
+ FiSearch8,
13456
+ {
13457
+ className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}`
13458
+ }
13459
+ ), /* @__PURE__ */ React26.createElement(
13460
+ "input",
13461
+ {
13462
+ type: "text",
13463
+ placeholder: pickingGroupId ? "Pesquise nodes ou ancestralidades..." : "Pesquisar no board...",
13464
+ className: `
13465
+ w-full rounded-md pl-9 pr-4 py-2 text-sm transition-all focus:outline-none focus:ring-1 focus:ring-indigo-500 border
13466
+ ${pickingGroupId ? "bg-indigo-950/30 border-indigo-500/30 text-white placeholder-indigo-300/50" : "bg-slate-950 border-white/10 text-slate-200 placeholder-slate-600"}
13467
+ `,
13468
+ value: searchTerm,
13469
+ onChange: (e) => setSearchTerm(e.target.value),
13470
+ autoFocus: !pickingGroupId
13471
+ }
13472
+ ))),
13473
+ /* @__PURE__ */ React26.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2" }, filtered.map((anc) => {
13474
+ const parentNodeName = nodeNamesMap.get(String(anc.ancestral_node)) || "Node Desconhecido";
13475
+ const isPicking = !!pickingGroupId;
13476
+ return /* @__PURE__ */ React26.createElement(
13477
+ "div",
13478
+ {
13479
+ key: anc.id,
13480
+ onClick: () => {
13481
+ if (isPicking) handleSelectAncestry(anc);
13482
+ },
13483
+ className: `
13484
+ group relative flex items-start gap-3 p-3 text-left rounded-lg border transition-all duration-200
13485
+ ${isPicking ? "border-indigo-500/30 bg-indigo-500/5 hover:bg-indigo-500/20 hover:border-indigo-400 cursor-pointer" : "border-white/5 bg-slate-800/40 hover:bg-indigo-600/10 hover:border-indigo-500/30 cursor-default"}
13486
+ `
13487
+ },
13488
+ /* @__PURE__ */ React26.createElement(
13489
+ "div",
13490
+ {
13491
+ className: `
13492
+ mt-0.5 w-8 h-8 rounded-md grid place-content-center shrink-0 border transition-all shadow-lg
13493
+ ${isPicking ? "bg-indigo-500 text-white border-indigo-400" : "bg-slate-800 text-indigo-400 border-white/5 group-hover:bg-indigo-500 group-hover:text-white"}
13494
+ ${anc.type === "quest" ? "text-emerald-400" : anc.type === "version" ? "text-amber-400" : anc.type === "node" ? "text-slate-400" : "text-indigo-400"}
13495
+ `
13496
+ },
13497
+ isPicking ? /* @__PURE__ */ React26.createElement(FiPlus10, { size: 16 }) : anc.type === "quest" ? /* @__PURE__ */ React26.createElement(FiCheckSquare3, { size: 14 }) : anc.type === "version" ? /* @__PURE__ */ React26.createElement(FiGitBranch3, { size: 14 }) : anc.type === "node" ? /* @__PURE__ */ React26.createElement(FiBox, { size: 14 }) : /* @__PURE__ */ React26.createElement(FiLayers6, { size: 14 })
13498
+ ),
13499
+ /* @__PURE__ */ React26.createElement("div", { className: "flex-1 min-w-0 pb-2" }, /* @__PURE__ */ React26.createElement("div", { className: "flex items-center justify-between gap-2" }, /* @__PURE__ */ React26.createElement("h4", { className: "text-sm font-medium text-slate-200 group-hover:text-white truncate transition-colors" }, anc.searchLabel || "Sem Nome"), /* @__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-tighter" }, anc.type)), anc.type === "ancestry" && /* @__PURE__ */ React26.createElement("div", { className: "flex items-center gap-1.5 mt-0.5 text-[11px] text-slate-500 group-hover:text-indigo-200/70 transition-colors" }, /* @__PURE__ */ React26.createElement(FiCornerUpRight4, { size: 10 }), /* @__PURE__ */ React26.createElement("span", { className: "truncate max-w-[120px]" }, parentNodeName)), anc.searchDesc && /* @__PURE__ */ React26.createElement("p", { className: "mt-1.5 text-[11px] text-slate-400 line-clamp-2 leading-relaxed opacity-80" }, anc.searchDesc)),
13500
+ !isPicking && /* @__PURE__ */ React26.createElement(
13501
+ "button",
13502
+ {
13503
+ onClick: (e) => {
13504
+ e.stopPropagation();
13505
+ handleSelectAncestry(anc);
13506
+ },
13507
+ className: "absolute right-2 bottom-2 opacity-0 group-hover:opacity-100 transition-all duration-300 transform translate-y-2 group-hover:translate-y-0 z-10",
13508
+ title: "Focar no cen\xE1rio"
13509
+ },
13510
+ /* @__PURE__ */ React26.createElement("div", { className: "bg-indigo-500 text-white p-2 rounded-full shadow-lg hover:bg-indigo-400 hover:scale-110 transition-all" }, /* @__PURE__ */ React26.createElement(FiPlay, { size: 14, className: "ml-0.5" }))
13511
+ )
13512
+ );
13513
+ }))
13514
+ ), /* @__PURE__ */ React26.createElement("div", { className: "flex flex-col flex-1 bg-slate-950/30" }, /* @__PURE__ */ React26.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React26.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React26.createElement(FiLayers6, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React26.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React26.createElement(React26.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React26.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React26.createElement(React26.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React26.createElement(
13620
13515
  GroupItem,
13621
13516
  {
13622
13517
  key: group.id,
13623
13518
  index,
13624
13519
  group,
13520
+ siblings: groups,
13625
13521
  onUpdate: handleUpdateGroup,
13626
13522
  onDelete: handleDeleteGroup,
13627
13523
  onAddSubgroup: handleAddSubgroup,
13628
13524
  onIndent: handleIndent,
13629
13525
  onOutdent: handleOutdent,
13526
+ onRemoveAncestry: handleRemoveAncestryFromGroup,
13527
+ onRequestPickAncestry: handleRequestPick,
13528
+ pickingGroupId,
13630
13529
  onPlayAncestry: handlePlayFromGroup,
13631
- availableMentionItems,
13530
+ availableIds,
13632
13531
  canEdit
13633
13532
  }
13634
13533
  ))))),
13635
- /* @__PURE__ */ React28.createElement("div", { className: "px-6 py-3 border-t border-white/10 bg-slate-950/50 text-[10px] uppercase tracking-widest font-bold text-slate-600 flex justify-between items-center flex-shrink-0" }, /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React28.createElement("span", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React28.createElement("div", { className: "w-1.5 h-1.5 rounded-full bg-indigo-500" }), " ", availableMentionItems.length, " RECURSOS DISPON\xCDVEIS"), /* @__PURE__ */ React28.createElement("span", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React28.createElement("div", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500" }), " ", groups.length, " GRUPOS PRINCIPAIS")), /* @__PURE__ */ React28.createElement("span", { className: "text-slate-700" }, "X.VIEW :: ANCESTRY BOARD ENGINE"))
13534
+ /* @__PURE__ */ React26.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-between flex-shrink-0" }, /* @__PURE__ */ React26.createElement("span", null, filtered.length, " itens encontrados"), /* @__PURE__ */ React26.createElement("span", null, groups.length, " grupos raiz"))
13636
13535
  )
13637
13536
  );
13638
13537
  }
13639
13538
 
13640
13539
  // src/components/MilestoneManager.jsx
13641
- import React29, { useState as useState27 } from "react";
13540
+ import React27, { useState as useState26 } from "react";
13642
13541
  import { FiTarget as FiTarget4, FiPlus as FiPlus11, FiTrash2 as FiTrash24, FiX as FiX9, FiCheck as FiCheck12, FiPauseCircle, FiPlayCircle } from "react-icons/fi";
13643
13542
  function MilestoneManager({
13644
13543
  isOpen,
@@ -13647,7 +13546,7 @@ function MilestoneManager({
13647
13546
  onUpdateMilestones = () => {
13648
13547
  }
13649
13548
  }) {
13650
- const [newMilestoneName, setNewMilestoneName] = useState27("");
13549
+ const [newMilestoneName, setNewMilestoneName] = useState26("");
13651
13550
  const handleAddMilestone = () => {
13652
13551
  if (!newMilestoneName.trim()) return;
13653
13552
  const newMilestone = {
@@ -13672,27 +13571,27 @@ function MilestoneManager({
13672
13571
  };
13673
13572
  if (!isOpen) return null;
13674
13573
  const swallow = (e) => e.stopPropagation();
13675
- return /* @__PURE__ */ React29.createElement(
13574
+ return /* @__PURE__ */ React27.createElement(
13676
13575
  "div",
13677
13576
  {
13678
13577
  className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-950/40 backdrop-blur-sm animate-in fade-in duration-300",
13679
13578
  onClick: onClose
13680
13579
  },
13681
- /* @__PURE__ */ React29.createElement(
13580
+ /* @__PURE__ */ React27.createElement(
13682
13581
  "div",
13683
13582
  {
13684
13583
  className: "w-full max-w-lg bg-slate-900/90 backdrop-blur-xl border border-white/10 rounded-2xl shadow-2xl flex flex-col max-h-[85vh] animate-in zoom-in-95 duration-300",
13685
13584
  onClick: swallow
13686
13585
  },
13687
- /* @__PURE__ */ React29.createElement("div", { className: "px-6 py-4 border-b border-white/10 flex items-center justify-between" }, /* @__PURE__ */ React29.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React29.createElement("div", { className: "p-2 rounded-lg bg-indigo-500/20 text-indigo-400" }, /* @__PURE__ */ React29.createElement(FiTarget4, { size: 20 })), /* @__PURE__ */ React29.createElement("div", null, /* @__PURE__ */ React29.createElement("h2", { className: "text-lg font-semibold text-slate-100" }, "Milestones"), /* @__PURE__ */ React29.createElement("p", { className: "text-xs text-slate-400" }, "Gerencie os marcos do seu cen\xE1rio"))), /* @__PURE__ */ React29.createElement(
13586
+ /* @__PURE__ */ React27.createElement("div", { className: "px-6 py-4 border-b border-white/10 flex items-center justify-between" }, /* @__PURE__ */ React27.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React27.createElement("div", { className: "p-2 rounded-lg bg-indigo-500/20 text-indigo-400" }, /* @__PURE__ */ React27.createElement(FiTarget4, { size: 20 })), /* @__PURE__ */ React27.createElement("div", null, /* @__PURE__ */ React27.createElement("h2", { className: "text-lg font-semibold text-slate-100" }, "Milestones"), /* @__PURE__ */ React27.createElement("p", { className: "text-xs text-slate-400" }, "Gerencie os marcos do seu cen\xE1rio"))), /* @__PURE__ */ React27.createElement(
13688
13587
  "button",
13689
13588
  {
13690
13589
  onClick: onClose,
13691
13590
  className: "p-2 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition-colors"
13692
13591
  },
13693
- /* @__PURE__ */ React29.createElement(FiX9, { size: 20 })
13592
+ /* @__PURE__ */ React27.createElement(FiX9, { size: 20 })
13694
13593
  )),
13695
- /* @__PURE__ */ React29.createElement("div", { className: "px-6 py-5 bg-white/5 border-b border-white/5" }, /* @__PURE__ */ React29.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React29.createElement(
13594
+ /* @__PURE__ */ React27.createElement("div", { className: "px-6 py-5 bg-white/5 border-b border-white/5" }, /* @__PURE__ */ React27.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React27.createElement(
13696
13595
  "input",
13697
13596
  {
13698
13597
  type: "text",
@@ -13702,47 +13601,47 @@ function MilestoneManager({
13702
13601
  placeholder: "Adicionar novo milestone...",
13703
13602
  className: "flex-1 bg-slate-800/50 border border-white/10 rounded-xl px-4 py-2.5 text-sm text-slate-100 placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500/40 focus:border-indigo-500/50 transition-all shadow-inner"
13704
13603
  }
13705
- ), /* @__PURE__ */ React29.createElement(
13604
+ ), /* @__PURE__ */ React27.createElement(
13706
13605
  "button",
13707
13606
  {
13708
13607
  onClick: handleAddMilestone,
13709
13608
  disabled: !newMilestoneName.trim(),
13710
13609
  className: "px-4 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 disabled:opacity-30 disabled:cursor-not-allowed text-white text-sm font-medium transition-all flex items-center gap-2 shadow-lg shadow-indigo-500/20 active:scale-95"
13711
13610
  },
13712
- /* @__PURE__ */ React29.createElement(FiPlus11, { size: 18 }),
13611
+ /* @__PURE__ */ React27.createElement(FiPlus11, { size: 18 }),
13713
13612
  "Adicionar"
13714
13613
  ))),
13715
- /* @__PURE__ */ React29.createElement("div", { className: "flex-1 overflow-y-auto px-6 py-4 custom-scrollbar" }, milestones.length > 0 ? /* @__PURE__ */ React29.createElement("div", { className: "space-y-3" }, milestones.map((ms) => /* @__PURE__ */ React29.createElement(
13614
+ /* @__PURE__ */ React27.createElement("div", { className: "flex-1 overflow-y-auto px-6 py-4 custom-scrollbar" }, milestones.length > 0 ? /* @__PURE__ */ React27.createElement("div", { className: "space-y-3" }, milestones.map((ms) => /* @__PURE__ */ React27.createElement(
13716
13615
  "div",
13717
13616
  {
13718
13617
  key: ms.id,
13719
13618
  className: `group flex items-center justify-between p-4 rounded-xl border transition-all duration-200 ${ms.status === "active" ? "bg-slate-800/40 border-indigo-500/20 hover:border-indigo-500/40" : "bg-slate-900/40 border-white/5 opacity-60 grayscale-[0.3]"}`
13720
13619
  },
13721
- /* @__PURE__ */ React29.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ React29.createElement(
13620
+ /* @__PURE__ */ React27.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ React27.createElement(
13722
13621
  "div",
13723
13622
  {
13724
13623
  className: `w-2 h-2 rounded-full shrink-0 ${ms.status === "active" ? "bg-indigo-400 shadow-[0_0_8px_rgba(129,140,248,0.6)]" : "bg-slate-600"}`
13725
13624
  }
13726
- ), /* @__PURE__ */ React29.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ React29.createElement("span", { className: `text-sm font-medium truncate ${ms.status === "active" ? "text-slate-100" : "text-slate-400 line-through"}` }, ms.name), /* @__PURE__ */ React29.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, ms.status === "active" ? "Ativo" : "Inativo"))),
13727
- /* @__PURE__ */ React29.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React29.createElement(
13625
+ ), /* @__PURE__ */ React27.createElement("div", { className: "flex flex-col min-w-0" }, /* @__PURE__ */ React27.createElement("span", { className: `text-sm font-medium truncate ${ms.status === "active" ? "text-slate-100" : "text-slate-400 line-through"}` }, ms.name), /* @__PURE__ */ React27.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider" }, ms.status === "active" ? "Ativo" : "Inativo"))),
13626
+ /* @__PURE__ */ React27.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React27.createElement(
13728
13627
  "button",
13729
13628
  {
13730
13629
  onClick: () => handleToggleMilestoneStatus(ms.id),
13731
13630
  className: `p-2 rounded-lg transition-all ${ms.status === "active" ? "hover:bg-slate-700 text-slate-400" : "hover:bg-indigo-500/20 text-indigo-400"}`,
13732
13631
  title: ms.status === "active" ? "Inativar" : "Ativar"
13733
13632
  },
13734
- ms.status === "active" ? /* @__PURE__ */ React29.createElement(FiPauseCircle, { size: 18 }) : /* @__PURE__ */ React29.createElement(FiPlayCircle, { size: 18 })
13735
- ), /* @__PURE__ */ React29.createElement(
13633
+ ms.status === "active" ? /* @__PURE__ */ React27.createElement(FiPauseCircle, { size: 18 }) : /* @__PURE__ */ React27.createElement(FiPlayCircle, { size: 18 })
13634
+ ), /* @__PURE__ */ React27.createElement(
13736
13635
  "button",
13737
13636
  {
13738
13637
  onClick: () => handleRemoveMilestone(ms.id),
13739
13638
  className: "p-2 rounded-lg hover:bg-red-500/20 text-slate-500 hover:text-red-400 transition-all",
13740
13639
  title: "Remover"
13741
13640
  },
13742
- /* @__PURE__ */ React29.createElement(FiTrash24, { size: 18 })
13641
+ /* @__PURE__ */ React27.createElement(FiTrash24, { size: 18 })
13743
13642
  ))
13744
- ))) : /* @__PURE__ */ React29.createElement("div", { className: "flex flex-col items-center justify-center py-12 text-center" }, /* @__PURE__ */ React29.createElement("div", { className: "p-4 rounded-full bg-slate-800/30 text-slate-600 mb-4" }, /* @__PURE__ */ React29.createElement(FiTarget4, { size: 40 })), /* @__PURE__ */ React29.createElement("h3", { className: "text-slate-400 font-medium" }, "Nenhum milestone definido"), /* @__PURE__ */ React29.createElement("p", { className: "text-xs text-slate-600 max-w-[200px] mt-1 italic" }, "Defina marcos importantes para orientar o progresso do projeto."))),
13745
- /* @__PURE__ */ React29.createElement("div", { className: "px-6 py-4 border-t border-white/5 bg-slate-900/50 flex items-center justify-between rounded-b-2xl" }, /* @__PURE__ */ React29.createElement("div", { className: "flex gap-4" }, /* @__PURE__ */ React29.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React29.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Total:"), /* @__PURE__ */ React29.createElement("span", { className: "text-xs font-bold text-slate-300" }, milestones.length)), /* @__PURE__ */ React29.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React29.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Ativos:"), /* @__PURE__ */ React29.createElement("span", { className: "text-xs font-bold text-indigo-400" }, milestones.filter((m) => m.status === "active").length))))
13643
+ ))) : /* @__PURE__ */ React27.createElement("div", { className: "flex flex-col items-center justify-center py-12 text-center" }, /* @__PURE__ */ React27.createElement("div", { className: "p-4 rounded-full bg-slate-800/30 text-slate-600 mb-4" }, /* @__PURE__ */ React27.createElement(FiTarget4, { size: 40 })), /* @__PURE__ */ React27.createElement("h3", { className: "text-slate-400 font-medium" }, "Nenhum milestone definido"), /* @__PURE__ */ React27.createElement("p", { className: "text-xs text-slate-600 max-w-[200px] mt-1 italic" }, "Defina marcos importantes para orientar o progresso do projeto."))),
13644
+ /* @__PURE__ */ React27.createElement("div", { className: "px-6 py-4 border-t border-white/5 bg-slate-900/50 flex items-center justify-between rounded-b-2xl" }, /* @__PURE__ */ React27.createElement("div", { className: "flex gap-4" }, /* @__PURE__ */ React27.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React27.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Total:"), /* @__PURE__ */ React27.createElement("span", { className: "text-xs font-bold text-slate-300" }, milestones.length)), /* @__PURE__ */ React27.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ React27.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-widest" }, "Ativos:"), /* @__PURE__ */ React27.createElement("span", { className: "text-xs font-bold text-indigo-400" }, milestones.filter((m) => m.status === "active").length))))
13746
13645
  )
13747
13646
  );
13748
13647
  }
@@ -13828,13 +13727,13 @@ function XViewScene({
13828
13727
  check_user_permission,
13829
13728
  get_view_members
13830
13729
  }) {
13831
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
13730
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
13832
13731
  const { data: session, status } = useSession();
13833
13732
  const router = useRouter();
13834
13733
  const searchParams = useSearchParams();
13835
13734
  const focusNodeId = searchParams == null ? void 0 : searchParams.get("focus");
13836
13735
  const focusAncestryId = searchParams == null ? void 0 : searchParams.get("ancestry");
13837
- const viewParams = useMemo13(() => {
13736
+ const viewParams = useMemo12(() => {
13838
13737
  if (encryptedConfig) {
13839
13738
  const data = decryptData(encryptedConfig);
13840
13739
  if (data) {
@@ -13843,7 +13742,7 @@ function XViewScene({
13843
13742
  }
13844
13743
  return null;
13845
13744
  }, [encryptedConfig, session]);
13846
- useEffect24(() => {
13745
+ useEffect22(() => {
13847
13746
  async function verifyPermission() {
13848
13747
  if (!viewParams || !session || !check_user_permission) return;
13849
13748
  const { id, type, owner_id } = viewParams;
@@ -13880,21 +13779,21 @@ function XViewScene({
13880
13779
  setIsLoading(false);
13881
13780
  }
13882
13781
  }, [viewParams, session, status, check_user_permission]);
13883
- const sceneConfigId = useMemo13(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
13884
- const ownerId = useMemo13(() => (viewParams == null ? void 0 : viewParams.owner_id) || null, [viewParams]);
13885
- const dbSaveUrl = useMemo13(() => {
13782
+ const sceneConfigId = useMemo12(() => (viewParams == null ? void 0 : viewParams.id) || null, [viewParams]);
13783
+ const ownerId = useMemo12(() => (viewParams == null ? void 0 : viewParams.owner_id) || null, [viewParams]);
13784
+ const dbSaveUrl = useMemo12(() => {
13886
13785
  if (ownerId && sceneConfigId) {
13887
13786
  return `x_view_dbs/${ownerId}/${sceneConfigId}`;
13888
13787
  }
13889
13788
  return null;
13890
13789
  }, [ownerId, sceneConfigId]);
13891
- const sceneSaveUrl = useMemo13(() => {
13790
+ const sceneSaveUrl = useMemo12(() => {
13892
13791
  if (ownerId && sceneConfigId) {
13893
13792
  return `x_view_scenes/${ownerId}/${sceneConfigId}`;
13894
13793
  }
13895
13794
  return null;
13896
13795
  }, [ownerId, sceneConfigId]);
13897
- const ancestry_save_url = useMemo13(() => {
13796
+ const ancestry_save_url = useMemo12(() => {
13898
13797
  if (ownerId && sceneConfigId) {
13899
13798
  return `x_view_ancestry/${ownerId}/${sceneConfigId}`;
13900
13799
  }
@@ -13903,42 +13802,42 @@ function XViewScene({
13903
13802
  const sceneDataRef = useRef19(null);
13904
13803
  const parentDataRef = useRef19(null);
13905
13804
  const ancestryDataRef = useRef19(null);
13906
- const [isLoading, setIsLoading] = useState28(true);
13907
- const [permissionStatus, setPermissionStatus] = useState28("loading");
13908
- const [userPermissionRole, setUserPermissionRole] = useState28(null);
13909
- const [viewMembers, setViewMembers] = useState28([]);
13910
- const [isInitialized, setIsInitialized] = useState28(false);
13911
- const [sceneVersion, setSceneVersion] = useState28(0);
13912
- const [contextMenu, setContextMenu] = useState28({
13805
+ const [isLoading, setIsLoading] = useState27(true);
13806
+ const [permissionStatus, setPermissionStatus] = useState27("loading");
13807
+ const [userPermissionRole, setUserPermissionRole] = useState27(null);
13808
+ const [viewMembers, setViewMembers] = useState27([]);
13809
+ const [isInitialized, setIsInitialized] = useState27(false);
13810
+ const [sceneVersion, setSceneVersion] = useState27(0);
13811
+ const [contextMenu, setContextMenu] = useState27({
13913
13812
  visible: false,
13914
13813
  x: 0,
13915
13814
  y: 0,
13916
13815
  nodeData: null
13917
13816
  });
13918
- const [multiContextMenu, setMultiContextMenu] = useState28({
13817
+ const [multiContextMenu, setMultiContextMenu] = useState27({
13919
13818
  visible: false,
13920
13819
  x: 0,
13921
13820
  y: 0,
13922
13821
  nodeIds: null
13923
13822
  });
13924
- const [relationshipMenu, setRelationshipMenu] = useState28({
13823
+ const [relationshipMenu, setRelationshipMenu] = useState27({
13925
13824
  visible: false,
13926
13825
  x: 0,
13927
13826
  y: 0,
13928
13827
  linkObject: null
13929
13828
  });
13930
- const [creationMode, setCreationMode] = useState28({
13829
+ const [creationMode, setCreationMode] = useState27({
13931
13830
  isActive: false,
13932
13831
  sourceNodeData: null
13933
13832
  });
13934
- const [versionMode, setVersionMode] = useState28({
13833
+ const [versionMode, setVersionMode] = useState27({
13935
13834
  isActive: false,
13936
13835
  sourceNodeData: null
13937
13836
  });
13938
- const [questMode, setQuestMode] = useState28({ isActive: false });
13939
- const [hasFocusedInitial, setHasFocusedInitial] = useState28(false);
13940
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState28(false);
13941
- const [ancestryMode, setAncestryMode] = useState28({
13837
+ const [questMode, setQuestMode] = useState27({ isActive: false });
13838
+ const [hasFocusedInitial, setHasFocusedInitial] = useState27(false);
13839
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState27(false);
13840
+ const [ancestryMode, setAncestryMode] = useState27({
13942
13841
  isActive: false,
13943
13842
  tree: null,
13944
13843
  selectedParentId: null,
@@ -13949,38 +13848,38 @@ function XViewScene({
13949
13848
  ancestryDescriptionSections: [],
13950
13849
  isAddingNodes: false
13951
13850
  });
13952
- const [readingMode, setReadingMode] = useState28({
13851
+ const [readingMode, setReadingMode] = useState27({
13953
13852
  isActive: false,
13954
13853
  ancestry: null,
13955
13854
  branchStack: [],
13956
13855
  autoAbstraction: false
13957
13856
  });
13958
- const [formPosition, setFormPosition] = useState28({
13857
+ const [formPosition, setFormPosition] = useState27({
13959
13858
  left: 16,
13960
13859
  top: 16,
13961
13860
  opacity: 0
13962
13861
  });
13963
- const [detailsNode, setDetailsNode] = useState28(null);
13964
- const [detailsLink, setDetailsLink] = useState28(null);
13965
- const [ancestryLinkDetails, setAncestryLinkDetails] = useState28(null);
13966
- const [imageViewer, setImageViewer] = useState28({
13862
+ const [detailsNode, setDetailsNode] = useState27(null);
13863
+ const [detailsLink, setDetailsLink] = useState27(null);
13864
+ const [ancestryLinkDetails, setAncestryLinkDetails] = useState27(null);
13865
+ const [imageViewer, setImageViewer] = useState27({
13967
13866
  visible: false,
13968
13867
  images: [],
13969
13868
  startIndex: 0
13970
13869
  });
13971
- const [editingAncestryRel, setEditingAncestryRel] = useState28({
13870
+ const [editingAncestryRel, setEditingAncestryRel] = useState27({
13972
13871
  visible: false,
13973
13872
  data: null,
13974
13873
  path: null
13975
13874
  });
13976
- const [isImportModalOpen, setIsImportModalOpen] = useState28(false);
13977
- const [importSuccessMessage, setImportSuccessMessage] = useState28("");
13978
- const [invalidTargetError, setInvalidTargetError] = useState28(null);
13979
- const [highlightedNodeId, setHighlightedNodeId] = useState28(null);
13980
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState28(false);
13981
- const [ancestryBoardData, setAncestryBoardData] = useState28([]);
13982
- const [isSidebarOpen, setIsSidebarOpen] = useState28(false);
13983
- const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] = useState28(false);
13875
+ const [isImportModalOpen, setIsImportModalOpen] = useState27(false);
13876
+ const [importSuccessMessage, setImportSuccessMessage] = useState27("");
13877
+ const [invalidTargetError, setInvalidTargetError] = useState27(null);
13878
+ const [highlightedNodeId, setHighlightedNodeId] = useState27(null);
13879
+ const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState27(false);
13880
+ const [ancestryBoardData, setAncestryBoardData] = useState27([]);
13881
+ const [isSidebarOpen, setIsSidebarOpen] = useState27(false);
13882
+ const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] = useState27(false);
13984
13883
  const mountRef = useRef19(null);
13985
13884
  const tooltipRef = useRef19(null);
13986
13885
  const formRef = useRef19(null);
@@ -14048,10 +13947,10 @@ function XViewScene({
14048
13947
  minWidth: 320,
14049
13948
  maxWidth: maxReadPanelW
14050
13949
  });
14051
- useEffect24(() => {
13950
+ useEffect22(() => {
14052
13951
  stateRef.current.ancestry = ancestryMode;
14053
13952
  }, [ancestryMode]);
14054
- useEffect24(() => {
13953
+ useEffect22(() => {
14055
13954
  var _a2;
14056
13955
  if (!isInitialized) return;
14057
13956
  const map = /* @__PURE__ */ new Map();
@@ -14613,7 +14512,7 @@ function XViewScene({
14613
14512
  }
14614
14513
  });
14615
14514
  }, []);
14616
- useEffect24(() => {
14515
+ useEffect22(() => {
14617
14516
  async function fetchAllData(configPath, ownerId2) {
14618
14517
  var _a2, _b2;
14619
14518
  if (!get_scene_view_data) {
@@ -14978,7 +14877,7 @@ function XViewScene({
14978
14877
  camTween.start();
14979
14878
  }
14980
14879
  }, [addOrUpdateNodeMesh]);
14981
- useEffect24(() => {
14880
+ useEffect22(() => {
14982
14881
  if (!isInitialized || !sceneDataRef.current) return;
14983
14882
  const currentMount = mountRef.current;
14984
14883
  if (!currentMount) return;
@@ -15982,7 +15881,7 @@ function XViewScene({
15982
15881
  };
15983
15882
  });
15984
15883
  }, []);
15985
- const actionHandlerContext = useMemo13(
15884
+ const actionHandlerContext = useMemo12(
15986
15885
  () => {
15987
15886
  var _a2;
15988
15887
  return {
@@ -16211,13 +16110,15 @@ function XViewScene({
16211
16110
  try {
16212
16111
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
16213
16112
  sceneDataRef2.current.quest_counter = currentCounter + 1;
16214
- sceneDataRef2.current.quest_nodes = sceneFileData.quest_nodes;
16215
- sceneDataRef2.current.quest_links = sceneFileData.quest_links;
16216
16113
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
16217
16114
  parentFileId: sceneConfigId2,
16218
16115
  ownerId: ownerId2,
16219
16116
  datasetName: "Quests Internas (View)"
16220
16117
  });
16118
+ sceneDataRef2.current.quest_nodes = [...graphDataRef.current[sceneConfigId2].nodes];
16119
+ if (parentDataRef.current[sceneConfigId2]) {
16120
+ parentDataRef.current[sceneConfigId2].nodes = [...graphDataRef.current[sceneConfigId2].nodes];
16121
+ }
16221
16122
  const finalPosition = stateRef2.current.ghostElements.node ? stateRef2.current.ghostElements.node.position.clone() : stateRef2.current.controls.target.clone();
16222
16123
  const { graphGroup, ghostElements } = stateRef2.current;
16223
16124
  if (ghostElements.node && graphGroup) {
@@ -17091,7 +16992,7 @@ function XViewScene({
17091
16992
  }
17092
16993
  setHighlightedNodeId(nodeId);
17093
16994
  }, []);
17094
- const activeNodeBranches = useMemo13(() => {
16995
+ const activeNodeBranches = useMemo12(() => {
17095
16996
  if (!highlightedNodeId || !readingMode.ancestry || !readingMode.ancestry.tree)
17096
16997
  return null;
17097
16998
  const fullTree = buildFullAncestryTree(
@@ -17135,7 +17036,7 @@ function XViewScene({
17135
17036
  readingMode.branchStack,
17136
17037
  ancestryDataRef.current
17137
17038
  ]);
17138
- const backNavigationInfo = useMemo13(() => {
17039
+ const backNavigationInfo = useMemo12(() => {
17139
17040
  const { branchStack } = readingMode;
17140
17041
  if (!branchStack || branchStack.length === 0) return null;
17141
17042
  const lastStep = branchStack[branchStack.length - 1];
@@ -17146,7 +17047,7 @@ function XViewScene({
17146
17047
  name: "Voltar para anterior"
17147
17048
  };
17148
17049
  }, [readingMode.branchStack]);
17149
- const getReadModeDisplayContext = useMemo13(() => {
17050
+ const getReadModeDisplayContext = useMemo12(() => {
17150
17051
  const { ancestry, branchStack } = readingMode;
17151
17052
  if (!ancestry) return null;
17152
17053
  if (branchStack.length === 0) {
@@ -17189,7 +17090,7 @@ function XViewScene({
17189
17090
  customProperties: branchProps
17190
17091
  };
17191
17092
  }, [readingMode, buildFullAncestryTree, ancestryDataRef.current]);
17192
- const readModeAbstractionTree = useMemo13(() => {
17093
+ const readModeAbstractionTree = useMemo12(() => {
17193
17094
  if (!readingMode.isActive || !readingMode.ancestry || !readingMode.ancestry.abstraction_tree) {
17194
17095
  return null;
17195
17096
  }
@@ -17806,19 +17707,13 @@ function XViewScene({
17806
17707
  (item) => {
17807
17708
  setIsAncestryBoardOpen(false);
17808
17709
  setIsSidebarOpen(false);
17809
- if (item.type === "ancestry" || !item.type) {
17710
+ if (item.type === "ancestry") {
17810
17711
  handleStartReadingAncestry(item);
17811
17712
  } else {
17812
- const nodeId = String(item.id);
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
- }
17713
+ handleOpenReference({ type: "node", id: item.id });
17819
17714
  }
17820
17715
  },
17821
- [handleStartReadingAncestry, tweenToTarget]
17716
+ [handleStartReadingAncestry, handleOpenReference]
17822
17717
  );
17823
17718
  const handleSaveAncestryBoard = useCallback4(
17824
17719
  async (groups) => {
@@ -17834,7 +17729,7 @@ function XViewScene({
17834
17729
  },
17835
17730
  [sceneConfigId, viewParams, session, save_ancestry_board_action, ownerId]
17836
17731
  );
17837
- const existingNodeTypes = useMemo13(() => {
17732
+ const existingNodeTypes = useMemo12(() => {
17838
17733
  if (!parentDataRef.current) {
17839
17734
  return [];
17840
17735
  }
@@ -17846,27 +17741,21 @@ function XViewScene({
17846
17741
  ).filter((t) => Boolean(t) && String(t).toLowerCase() !== "quest");
17847
17742
  return [...new Set(allTypes)];
17848
17743
  }, [parentDataRef.current, sceneVersion]);
17849
- const searchableDbNodes = useMemo13(() => {
17850
- var _a2;
17744
+ const searchableDbNodes = useMemo12(() => {
17851
17745
  if (!parentDataRef.current) {
17852
17746
  return [];
17853
17747
  }
17854
- const datasetsPool = Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
17748
+ return Object.entries(parentDataRef.current).flatMap(([dbId, fileData]) => {
17855
17749
  const datasetName = fileData.dataset_name || `Dataset #${dbId.substring(0, 6)}`;
17856
17750
  return (fileData.nodes || []).map((node) => ({
17857
17751
  ...node,
17858
17752
  dataset_name: datasetName
17859
17753
  }));
17754
+ }).filter((node) => {
17755
+ var _a2;
17756
+ return !((_a2 = node.version_node) == null ? void 0 : _a2.is_version);
17860
17757
  });
17861
- const questsPool = (((_a2 = sceneDataRef.current) == null ? void 0 : _a2.quest_nodes) || []).map((node) => ({
17862
- ...node,
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]);
17758
+ }, [parentDataRef.current, sceneVersion]);
17870
17759
  const handleAddExistingNode = useCallback4(
17871
17760
  (nodeId) => {
17872
17761
  return userActionHandlers.handleAddExistingNodeById(
@@ -17965,13 +17854,13 @@ function XViewScene({
17965
17854
  console.error("Erro na chamada de save_view_data:", error);
17966
17855
  }
17967
17856
  }, [sceneSaveUrl, save_view_data, sceneConfigId, viewParams == null ? void 0 : viewParams.type]);
17968
- const allAvailableNodes = useMemo13(() => {
17857
+ const allAvailableNodes = useMemo12(() => {
17969
17858
  if (!parentDataRef.current) return [];
17970
17859
  return Object.values(parentDataRef.current).flatMap(
17971
17860
  (fileData) => fileData.nodes || []
17972
17861
  );
17973
17862
  }, [sceneVersion, isInitialized]);
17974
- const allAvailableAncestries = useMemo13(() => {
17863
+ const allAvailableAncestries = useMemo12(() => {
17975
17864
  return ancestryDataRef.current || [];
17976
17865
  }, [sceneVersion, isInitialized]);
17977
17866
  const handleOpenReference = useCallback4(
@@ -18035,7 +17924,7 @@ function XViewScene({
18035
17924
  },
18036
17925
  [tweenToTarget]
18037
17926
  );
18038
- const availableDatasets = useMemo13(() => {
17927
+ const availableDatasets = useMemo12(() => {
18039
17928
  if (!sceneDataRef.current || !parentDataRef.current) return [];
18040
17929
  return sceneDataRef.current.parent_dbs.map((db) => {
18041
17930
  var _a2;
@@ -18045,11 +17934,11 @@ function XViewScene({
18045
17934
  };
18046
17935
  });
18047
17936
  }, [sceneVersion, isInitialized]);
18048
- const sourceNodeDatasetId = creationMode.sourceNodeData ? (_c = stateRef.current.nodeIdToParentFileMap.get(
17937
+ const sourceNodeDatasetId = creationMode.sourceNodeData ? (_b = stateRef.current.nodeIdToParentFileMap.get(
18049
17938
  String(creationMode.sourceNodeData.id)
18050
- )) == null ? void 0 : _c.parentFileId : null;
17939
+ )) == null ? void 0 : _b.parentFileId : null;
18051
17940
  const detailsNodeDatasetInfo = detailsNode ? stateRef.current.nodeIdToParentFileMap.get(String(detailsNode.id)) : null;
18052
- useEffect24(() => {
17941
+ useEffect22(() => {
18053
17942
  if (isInitialized && focusNodeId && !hasFocusedInitial) {
18054
17943
  const nodeObjects = stateRef.current.nodeObjects || {};
18055
17944
  const targetMesh = nodeObjects[String(focusNodeId)];
@@ -18072,7 +17961,7 @@ function XViewScene({
18072
17961
  hasFocusedInitial,
18073
17962
  tweenToTarget
18074
17963
  ]);
18075
- useEffect24(() => {
17964
+ useEffect22(() => {
18076
17965
  if (isInitialized && focusAncestryId && !hasOpenedInitialAncestry) {
18077
17966
  const ancestries = ancestryDataRef.current || [];
18078
17967
  const targetAncestry = ancestries.find(
@@ -18097,7 +17986,7 @@ function XViewScene({
18097
17986
  hasOpenedInitialAncestry,
18098
17987
  handleStartReadingAncestry
18099
17988
  ]);
18100
- useEffect24(() => {
17989
+ useEffect22(() => {
18101
17990
  function handleKeyDown(event) {
18102
17991
  var _a2, _b2, _c2;
18103
17992
  const context = actionHandlerContext;
@@ -18220,10 +18109,10 @@ function XViewScene({
18220
18109
  // <-- handleCancelQuest adicionado aqui
18221
18110
  ]);
18222
18111
  if (isLoading || status === "loading" || permissionStatus === "loading") {
18223
- return /* @__PURE__ */ React30.createElement(LoadingScreen, null);
18112
+ return /* @__PURE__ */ React28.createElement(LoadingScreen, null);
18224
18113
  }
18225
18114
  if (permissionStatus === "denied") {
18226
- return /* @__PURE__ */ React30.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React30.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React30.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React30.createElement(
18115
+ return /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React28.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React28.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React28.createElement(
18227
18116
  "svg",
18228
18117
  {
18229
18118
  xmlns: "http://www.w3.org/2000/svg",
@@ -18233,7 +18122,7 @@ function XViewScene({
18233
18122
  stroke: "currentColor",
18234
18123
  className: "w-16 h-16 mx-auto"
18235
18124
  },
18236
- /* @__PURE__ */ React30.createElement(
18125
+ /* @__PURE__ */ React28.createElement(
18237
18126
  "path",
18238
18127
  {
18239
18128
  strokeLinecap: "round",
@@ -18241,13 +18130,13 @@ function XViewScene({
18241
18130
  d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
18242
18131
  }
18243
18132
  )
18244
- )), /* @__PURE__ */ React30.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React30.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React30.createElement(
18133
+ )), /* @__PURE__ */ React28.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React28.createElement("p", { className: "text-slate-400 mb-6" }, "Voc\xEA n\xE3o tem permiss\xE3o para acessar este conte\xFAdo. Solicite acesso ao propriet\xE1rio ou verifique se est\xE1 na conta correta."), /* @__PURE__ */ React28.createElement(
18245
18134
  "button",
18246
18135
  {
18247
18136
  onClick: () => router.push("/dashboard/scenes"),
18248
18137
  className: "flex items-center justify-center gap-2 w-full py-3 px-4 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors font-medium"
18249
18138
  },
18250
- /* @__PURE__ */ React30.createElement(
18139
+ /* @__PURE__ */ React28.createElement(
18251
18140
  "svg",
18252
18141
  {
18253
18142
  xmlns: "http://www.w3.org/2000/svg",
@@ -18257,7 +18146,7 @@ function XViewScene({
18257
18146
  stroke: "currentColor",
18258
18147
  className: "w-5 h-5"
18259
18148
  },
18260
- /* @__PURE__ */ React30.createElement(
18149
+ /* @__PURE__ */ React28.createElement(
18261
18150
  "path",
18262
18151
  {
18263
18152
  strokeLinecap: "round",
@@ -18269,7 +18158,7 @@ function XViewScene({
18269
18158
  "Voltar para Scenes"
18270
18159
  )));
18271
18160
  }
18272
- return /* @__PURE__ */ React30.createElement(
18161
+ return /* @__PURE__ */ React28.createElement(
18273
18162
  "div",
18274
18163
  {
18275
18164
  ref: mountRef,
@@ -18281,7 +18170,7 @@ function XViewScene({
18281
18170
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
18282
18171
  }
18283
18172
  },
18284
- userPermissionRole !== "link_viewer" && /* @__PURE__ */ React30.createElement(
18173
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ React28.createElement(
18285
18174
  XViewSidebar,
18286
18175
  {
18287
18176
  dbNodes: searchableDbNodes,
@@ -18301,11 +18190,11 @@ function XViewScene({
18301
18190
  onToggle: setIsSidebarOpen,
18302
18191
  userRole: userPermissionRole,
18303
18192
  viewMembers,
18304
- milestones: ((_d = sceneDataRef.current) == null ? void 0 : _d.milestones) || [],
18193
+ milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
18305
18194
  onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
18306
18195
  }
18307
18196
  ),
18308
- creationMode.isActive && /* @__PURE__ */ React30.createElement(
18197
+ creationMode.isActive && /* @__PURE__ */ React28.createElement(
18309
18198
  InSceneCreationForm,
18310
18199
  {
18311
18200
  onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
@@ -18326,8 +18215,8 @@ function XViewScene({
18326
18215
  },
18327
18216
  refEl: formRef,
18328
18217
  existingTypes: existingNodeTypes,
18329
- initialColor: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.color,
18330
- sourceTypes: (_f = creationMode.sourceNodeData) == null ? void 0 : _f.type,
18218
+ initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
18219
+ sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
18331
18220
  onIntensityChange: handleGhostNodeIntensityChange,
18332
18221
  onUploadFile: upload_file_action,
18333
18222
  availableDatasets,
@@ -18337,7 +18226,7 @@ function XViewScene({
18337
18226
  availableAncestries: allAvailableAncestries
18338
18227
  }
18339
18228
  ),
18340
- versionMode.isActive && /* @__PURE__ */ React30.createElement(
18229
+ versionMode.isActive && /* @__PURE__ */ React28.createElement(
18341
18230
  InSceneVersionForm,
18342
18231
  {
18343
18232
  onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
@@ -18356,14 +18245,14 @@ function XViewScene({
18356
18245
  transition: "opacity 200ms ease-out"
18357
18246
  },
18358
18247
  refEl: formRef,
18359
- fixedType: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.type,
18360
- fixedColor: (_h = versionMode.sourceNodeData) == null ? void 0 : _h.color,
18248
+ fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
18249
+ fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
18361
18250
  onUploadFile: upload_file_action,
18362
18251
  availableNodes: allAvailableNodes,
18363
18252
  availableAncestries: allAvailableAncestries
18364
18253
  }
18365
18254
  ),
18366
- questMode.isActive && /* @__PURE__ */ React30.createElement(
18255
+ questMode.isActive && /* @__PURE__ */ React28.createElement(
18367
18256
  InSceneQuestForm,
18368
18257
  {
18369
18258
  onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
@@ -18385,13 +18274,13 @@ function XViewScene({
18385
18274
  availableNodes: allAvailableNodes,
18386
18275
  availableAncestries: allAvailableAncestries,
18387
18276
  viewName: viewParams == null ? void 0 : viewParams.name,
18388
- questCounter: ((_i = sceneDataRef.current) == null ? void 0 : _i.quest_counter) || 1,
18277
+ questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
18389
18278
  viewMembers,
18390
- milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18279
+ milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
18391
18280
  onUpdateMilestones: handleUpdateMilestones
18392
18281
  }
18393
18282
  ),
18394
- readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React30.createElement(
18283
+ readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React28.createElement(
18395
18284
  "div",
18396
18285
  {
18397
18286
  className: `ui-overlay absolute group rounded-2xl border border-white/10 bg-slate-950/70 backdrop-blur-xl shadow-[0_20px_80px_rgba(0,0,0,0.6)] ring-1 ring-white/10 text-white overflow-hidden flex flex-col ${isReadModeResizing ? "transition-none" : "transition-all duration-300 ease-out"}`,
@@ -18404,7 +18293,7 @@ function XViewScene({
18404
18293
  maxWidth: "92vw"
18405
18294
  }
18406
18295
  },
18407
- /* @__PURE__ */ React30.createElement(
18296
+ /* @__PURE__ */ React28.createElement(
18408
18297
  "div",
18409
18298
  {
18410
18299
  onPointerDown: (e) => {
@@ -18415,7 +18304,7 @@ function XViewScene({
18415
18304
  title: "Arraste para redimensionar"
18416
18305
  }
18417
18306
  ),
18418
- /* @__PURE__ */ React30.createElement(
18307
+ /* @__PURE__ */ React28.createElement(
18419
18308
  DescriptionReadModePanel,
18420
18309
  {
18421
18310
  key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
@@ -18450,7 +18339,7 @@ function XViewScene({
18450
18339
  }
18451
18340
  )
18452
18341
  ),
18453
- ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React30.createElement(
18342
+ ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React28.createElement(
18454
18343
  CreateAncestryPanel,
18455
18344
  {
18456
18345
  ancestryMode,
@@ -18486,7 +18375,7 @@ function XViewScene({
18486
18375
  onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
18487
18376
  }
18488
18377
  ),
18489
- editingAncestryRel.visible && /* @__PURE__ */ React30.createElement(
18378
+ editingAncestryRel.visible && /* @__PURE__ */ React28.createElement(
18490
18379
  AncestryRelationshipPanel,
18491
18380
  {
18492
18381
  data: editingAncestryRel.data,
@@ -18500,7 +18389,7 @@ function XViewScene({
18500
18389
  onUploadFile: upload_file_action
18501
18390
  }
18502
18391
  ),
18503
- detailsNode && detailsNode.is_quest && /* @__PURE__ */ React30.createElement(
18392
+ detailsNode && detailsNode.is_quest && /* @__PURE__ */ React28.createElement(
18504
18393
  QuestDetailsPanel,
18505
18394
  {
18506
18395
  node: detailsNode,
@@ -18522,11 +18411,11 @@ function XViewScene({
18522
18411
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
18523
18412
  viewMembers,
18524
18413
  currentUser: session == null ? void 0 : session.user,
18525
- milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18414
+ milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18526
18415
  onUpdateMilestones: handleUpdateMilestones
18527
18416
  }
18528
18417
  ),
18529
- detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React30.createElement(
18418
+ detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React28.createElement(
18530
18419
  NodeDetailsPanel,
18531
18420
  {
18532
18421
  node: detailsNode,
@@ -18558,7 +18447,7 @@ function XViewScene({
18558
18447
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
18559
18448
  }
18560
18449
  ),
18561
- detailsLink && /* @__PURE__ */ React30.createElement(
18450
+ detailsLink && /* @__PURE__ */ React28.createElement(
18562
18451
  RelationshipDetailsPanel,
18563
18452
  {
18564
18453
  link: detailsLink,
@@ -18572,7 +18461,7 @@ function XViewScene({
18572
18461
  userRole: userPermissionRole
18573
18462
  }
18574
18463
  ),
18575
- ancestryLinkDetails && /* @__PURE__ */ React30.createElement(
18464
+ ancestryLinkDetails && /* @__PURE__ */ React28.createElement(
18576
18465
  AncestryLinkDetailsPanel,
18577
18466
  {
18578
18467
  data: ancestryLinkDetails,
@@ -18583,7 +18472,7 @@ function XViewScene({
18583
18472
  onUploadFile: upload_file_action
18584
18473
  }
18585
18474
  ),
18586
- /* @__PURE__ */ React30.createElement(
18475
+ /* @__PURE__ */ React28.createElement(
18587
18476
  "div",
18588
18477
  {
18589
18478
  ref: tooltipRef,
@@ -18610,7 +18499,7 @@ function XViewScene({
18610
18499
  }
18611
18500
  }
18612
18501
  ),
18613
- /* @__PURE__ */ React30.createElement(
18502
+ /* @__PURE__ */ React28.createElement(
18614
18503
  ContextMenu,
18615
18504
  {
18616
18505
  data: contextMenu,
@@ -18643,7 +18532,7 @@ function XViewScene({
18643
18532
  onFinishQuest: handleFinishQuestQuick
18644
18533
  }
18645
18534
  ),
18646
- /* @__PURE__ */ React30.createElement(
18535
+ /* @__PURE__ */ React28.createElement(
18647
18536
  MultiNodeContextMenu,
18648
18537
  {
18649
18538
  data: multiContextMenu,
@@ -18663,7 +18552,7 @@ function XViewScene({
18663
18552
  )
18664
18553
  }
18665
18554
  ),
18666
- /* @__PURE__ */ React30.createElement(
18555
+ /* @__PURE__ */ React28.createElement(
18667
18556
  RelationshipContextMenu,
18668
18557
  {
18669
18558
  data: relationshipMenu,
@@ -18681,14 +18570,14 @@ function XViewScene({
18681
18570
  onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
18682
18571
  }
18683
18572
  ),
18684
- /* @__PURE__ */ React30.createElement(
18573
+ /* @__PURE__ */ React28.createElement(
18685
18574
  ImageViewer,
18686
18575
  {
18687
18576
  data: imageViewer,
18688
18577
  onClose: () => setImageViewer({ ...imageViewer, visible: false })
18689
18578
  }
18690
18579
  ),
18691
- /* @__PURE__ */ React30.createElement(
18580
+ /* @__PURE__ */ React28.createElement(
18692
18581
  AncestryBoard,
18693
18582
  {
18694
18583
  isOpen: isAncestryBoardOpen,
@@ -18701,29 +18590,29 @@ function XViewScene({
18701
18590
  userRole: userPermissionRole
18702
18591
  }
18703
18592
  ),
18704
- /* @__PURE__ */ React30.createElement(
18593
+ /* @__PURE__ */ React28.createElement(
18705
18594
  MilestoneManager,
18706
18595
  {
18707
18596
  isOpen: isMilestoneManagerOpen,
18708
18597
  onClose: () => setIsMilestoneManagerOpen(false),
18709
- milestones: ((_l = sceneDataRef.current) == null ? void 0 : _l.milestones) || [],
18598
+ milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18710
18599
  onUpdateMilestones: handleUpdateMilestones
18711
18600
  }
18712
18601
  ),
18713
- /* @__PURE__ */ React30.createElement(
18602
+ /* @__PURE__ */ React28.createElement(
18714
18603
  ImportParentFileModal,
18715
18604
  {
18716
18605
  isOpen: isImportModalOpen,
18717
18606
  onClose: () => setIsImportModalOpen(false),
18718
18607
  onConfirm: handleConfirmImport,
18719
18608
  session,
18720
- parentDbs: ((_m = sceneDataRef.current) == null ? void 0 : _m.parent_dbs) || [],
18609
+ parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
18721
18610
  onFetchAvailableFiles: import_parent_file_modal_get,
18722
18611
  currentViewName: viewParams == null ? void 0 : viewParams.name,
18723
18612
  currentAncestries: ancestryDataRef.current || []
18724
18613
  }
18725
18614
  ),
18726
- invalidTargetError && /* @__PURE__ */ React30.createElement(
18615
+ invalidTargetError && /* @__PURE__ */ React28.createElement(
18727
18616
  "div",
18728
18617
  {
18729
18618
  className: "ui-overlay",
@@ -18748,13 +18637,13 @@ function XViewScene({
18748
18637
  animation: "fadeInDown 0.5s cubic-bezier(0.16, 1, 0.3, 1)"
18749
18638
  }
18750
18639
  },
18751
- /* @__PURE__ */ React30.createElement("style", null, `
18640
+ /* @__PURE__ */ React28.createElement("style", null, `
18752
18641
  @keyframes fadeInDown {
18753
18642
  from { opacity: 0; transform: translate(-50%, -20px); }
18754
18643
  to { opacity: 1; transform: translate(-50%, 0); }
18755
18644
  }
18756
18645
  `),
18757
- /* @__PURE__ */ React30.createElement(
18646
+ /* @__PURE__ */ React28.createElement(
18758
18647
  "svg",
18759
18648
  {
18760
18649
  width: "20",
@@ -18766,12 +18655,12 @@ function XViewScene({
18766
18655
  strokeLinecap: "round",
18767
18656
  strokeLinejoin: "round"
18768
18657
  },
18769
- /* @__PURE__ */ React30.createElement("circle", { cx: "12", cy: "12", r: "10" }),
18770
- /* @__PURE__ */ React30.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
18771
- /* @__PURE__ */ React30.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
18658
+ /* @__PURE__ */ React28.createElement("circle", { cx: "12", cy: "12", r: "10" }),
18659
+ /* @__PURE__ */ React28.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
18660
+ /* @__PURE__ */ React28.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
18772
18661
  ),
18773
- /* @__PURE__ */ React30.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
18774
- /* @__PURE__ */ React30.createElement(
18662
+ /* @__PURE__ */ React28.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
18663
+ /* @__PURE__ */ React28.createElement(
18775
18664
  "button",
18776
18665
  {
18777
18666
  onClick: () => setInvalidTargetError(null),
@@ -18801,6 +18690,450 @@ function XViewScene({
18801
18690
  )
18802
18691
  );
18803
18692
  }
18693
+
18694
+ // src/x_view_server_logic.js
18695
+ async function save_view_data_logic(db_services, filename, data) {
18696
+ try {
18697
+ const saveResult = await db_services.save_file(filename, data);
18698
+ return saveResult;
18699
+ } catch (error) {
18700
+ console.error("catch (error) em save_view_data_logic:", error);
18701
+ return { success: false, error: error.message };
18702
+ }
18703
+ }
18704
+ async function get_scene_view_data_logic(db_services, scene_config, owner_id, type, session, focusNodeId = null, focusAncestryId = null) {
18705
+ var _a, _b;
18706
+ try {
18707
+ if (!session || !session.user) {
18708
+ return { success: false, error: "Usu\xE1rio n\xE3o autenticado." };
18709
+ }
18710
+ const membershipCheck = await db_services.check_membership(owner_id, type, scene_config, session.user.id);
18711
+ const isFullMember = membershipCheck.success && membershipCheck.isValidMember;
18712
+ if (!isFullMember && !focusNodeId && !focusAncestryId) {
18713
+ return { success: false, error: "Acesso Negado: Voc\xEA n\xE3o possui permiss\xE3o para acessar este cen\xE1rio." };
18714
+ }
18715
+ const sceneResponse = await db_services.get_file(`x_view_scenes/${owner_id}/${scene_config}`);
18716
+ if (!sceneResponse || !sceneResponse.success) {
18717
+ console.error("Falha ao buscar dados da cena:", sceneResponse == null ? void 0 : sceneResponse.error);
18718
+ return { success: false, error: `N\xE3o foi poss\xEDvel carregar o arquivo da cena: ${scene_config}` };
18719
+ }
18720
+ const sceneData = sceneResponse.data;
18721
+ const parentDbObjects = sceneData.parent_dbs || [];
18722
+ if (type && type.toLowerCase().includes("database")) {
18723
+ const selfExists = parentDbObjects.some((db) => String(db.db_id) === String(scene_config));
18724
+ if (!selfExists) {
18725
+ parentDbObjects.push({ db_id: scene_config, owner_id });
18726
+ }
18727
+ }
18728
+ const parentResponsesPromises = parentDbObjects.map(
18729
+ (db_info) => db_services.get_file(`x_view_dbs/${db_info.owner_id}/${db_info.db_id}`)
18730
+ );
18731
+ const parentResponsesResults = await Promise.allSettled(parentResponsesPromises);
18732
+ const parentData = {};
18733
+ for (let i = 0; i < parentResponsesResults.length; i++) {
18734
+ const result = parentResponsesResults[i];
18735
+ const db_info = parentDbObjects[i];
18736
+ if (result.status === "fulfilled" && ((_a = result.value) == null ? void 0 : _a.success)) {
18737
+ parentData[db_info.db_id] = result.value.data;
18738
+ } else {
18739
+ console.warn(
18740
+ `Arquivo pai n\xE3o carregado: ${db_info.db_id}. Pode ter sido deletado.`,
18741
+ result.status === "rejected" ? result.reason : (_b = result.value) == null ? void 0 : _b.error
18742
+ );
18743
+ }
18744
+ }
18745
+ if (type && type.toLowerCase() === "view") {
18746
+ parentData[scene_config] = {
18747
+ dataset_name: "Quests Internas (View)",
18748
+ nodes: sceneData.quest_nodes || [],
18749
+ links: sceneData.quest_links || []
18750
+ };
18751
+ }
18752
+ const allNodes = Object.values(parentData).flatMap((db) => db.nodes || []);
18753
+ const allLinks = Object.values(parentData).flatMap((db) => db.links || []);
18754
+ const parentNodeMap = new Map(allNodes.map((node) => [String(node.id), node]));
18755
+ const parentLinkMap = new Map(allLinks.map((link) => [`${link.source}-${link.target}`, link]));
18756
+ const validatedNodes = (sceneData.nodes || []).map((sceneNode) => {
18757
+ var _a2, _b2;
18758
+ const nodeTypes = Array.isArray(sceneNode.type) ? sceneNode.type : [sceneNode.type];
18759
+ if (nodeTypes.includes("quest")) {
18760
+ const dbQuestNode = (_b2 = (_a2 = parentData[scene_config]) == null ? void 0 : _a2.nodes) == null ? void 0 : _b2.find((qn) => String(qn.id) === String(sceneNode.id));
18761
+ if (dbQuestNode) {
18762
+ return { ...sceneNode, ...dbQuestNode };
18763
+ }
18764
+ return sceneNode;
18765
+ }
18766
+ const dbNode = parentNodeMap.get(String(sceneNode.id));
18767
+ if (dbNode) {
18768
+ return { ...sceneNode, ...dbNode };
18769
+ }
18770
+ return null;
18771
+ }).filter(Boolean);
18772
+ const validNodeIdsInScene = new Set(validatedNodes.map((node) => String(node.id)));
18773
+ const validatedLinks = (sceneData.links || []).filter((sceneLink) => {
18774
+ const linkExistsInParent = parentLinkMap.has(`${sceneLink.source}-${sceneLink.target}`);
18775
+ const nodesAreValidForScene = validNodeIdsInScene.has(String(sceneLink.source)) && validNodeIdsInScene.has(String(sceneLink.target));
18776
+ return linkExistsInParent && nodesAreValidForScene;
18777
+ }).map((sceneLink) => parentLinkMap.get(`${sceneLink.source}-${sceneLink.target}`));
18778
+ const validatedSceneData = {
18779
+ ...sceneData,
18780
+ nodes: validatedNodes,
18781
+ links: validatedLinks
18782
+ };
18783
+ const ancestryFilePaths = [];
18784
+ ancestryFilePaths.push({
18785
+ path: `x_view_ancestry/${owner_id}/${scene_config}`,
18786
+ source_id: scene_config,
18787
+ owner_id,
18788
+ isSceneFile: true
18789
+ });
18790
+ parentDbObjects.forEach((db_info) => {
18791
+ ancestryFilePaths.push({
18792
+ path: `x_view_ancestry/${db_info.owner_id}/${db_info.db_id}`,
18793
+ source_id: db_info.db_id,
18794
+ owner_id: db_info.owner_id,
18795
+ isSceneFile: false
18796
+ });
18797
+ });
18798
+ const ancestryPromises = ancestryFilePaths.map((file) => db_services.get_file(file.path));
18799
+ const ancestryResults = await Promise.allSettled(ancestryPromises);
18800
+ const ancestriesFromSceneFile = [];
18801
+ const ancestriesFromDbFiles = [];
18802
+ ancestryResults.forEach((result, index) => {
18803
+ var _a2;
18804
+ const fileInfo = ancestryFilePaths[index];
18805
+ if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
18806
+ const ancestriesFromFile = result.value.data.map((ancestry) => {
18807
+ const existingSource = ancestry._source_file_id;
18808
+ const existingOwner = ancestry._source_owner_id;
18809
+ const isImportedItem = existingSource && existingSource !== fileInfo.source_id;
18810
+ return {
18811
+ ...ancestry,
18812
+ _source_file_id: isImportedItem ? existingSource : fileInfo.source_id,
18813
+ _source_owner_id: isImportedItem ? existingOwner : fileInfo.owner_id
18814
+ };
18815
+ });
18816
+ if (fileInfo.isSceneFile) {
18817
+ ancestriesFromSceneFile.push(...ancestriesFromFile);
18818
+ } else {
18819
+ ancestriesFromDbFiles.push(...ancestriesFromFile);
18820
+ }
18821
+ }
18822
+ });
18823
+ const ancestryMap = /* @__PURE__ */ new Map();
18824
+ ancestriesFromDbFiles.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
18825
+ ancestriesFromSceneFile.forEach((anc) => ancestryMap.set(anc.ancestry_id, anc));
18826
+ let ancestryData = Array.from(ancestryMap.values());
18827
+ const externalSourcesToRefresh = /* @__PURE__ */ new Map();
18828
+ ancestryData.forEach((anc) => {
18829
+ const targetSourceId = anc._source_file_id || anc._imported_from_view_id;
18830
+ const targetOwnerId = anc._source_owner_id || anc._imported_from_view_owner_id;
18831
+ if (targetSourceId && targetSourceId !== scene_config && targetOwnerId) {
18832
+ const isAlreadyLoadedAsParent = parentDbObjects.some((db) => String(db.db_id) === String(targetSourceId));
18833
+ if (!isAlreadyLoadedAsParent) {
18834
+ const key = `${targetOwnerId}/${targetSourceId}`;
18835
+ externalSourcesToRefresh.set(key, {
18836
+ owner_id: targetOwnerId,
18837
+ source_id: targetSourceId,
18838
+ key
18839
+ });
18840
+ }
18841
+ }
18842
+ });
18843
+ const successfullyFetchedSources = /* @__PURE__ */ new Set();
18844
+ const failedSources = /* @__PURE__ */ new Set();
18845
+ if (externalSourcesToRefresh.size > 0) {
18846
+ const refreshPromises = Array.from(externalSourcesToRefresh.values()).map(
18847
+ (src) => db_services.get_file(`x_view_ancestry/${src.owner_id}/${src.source_id}`).then((res) => ({ ...res, _meta_key: src.key }))
18848
+ );
18849
+ const refreshResults = await Promise.allSettled(refreshPromises);
18850
+ const freshAncestryMap = /* @__PURE__ */ new Map();
18851
+ refreshResults.forEach((result) => {
18852
+ var _a2, _b2;
18853
+ if (result.status === "fulfilled" && ((_a2 = result.value) == null ? void 0 : _a2.success) && Array.isArray(result.value.data)) {
18854
+ successfullyFetchedSources.add(result.value._meta_key);
18855
+ result.value.data.forEach((freshAnc) => {
18856
+ if (!freshAnc.is_private) {
18857
+ freshAncestryMap.set(String(freshAnc.ancestry_id), freshAnc);
18858
+ }
18859
+ });
18860
+ } else if (result.status === "fulfilled" && !((_b2 = result.value) == null ? void 0 : _b2.success)) {
18861
+ failedSources.add(result.value._meta_key);
18862
+ }
18863
+ });
18864
+ ancestryData = ancestryData.filter((localAnc) => {
18865
+ const targetSourceId = localAnc._source_file_id || localAnc._imported_from_view_id;
18866
+ const targetOwnerId = localAnc._source_owner_id || localAnc._imported_from_view_owner_id;
18867
+ if (!targetSourceId || targetSourceId === scene_config) return true;
18868
+ const key = `${targetOwnerId}/${targetSourceId}`;
18869
+ if (failedSources.has(key)) {
18870
+ return false;
18871
+ }
18872
+ if (externalSourcesToRefresh.has(key) && successfullyFetchedSources.has(key)) {
18873
+ const stillExists = freshAncestryMap.has(String(localAnc.ancestry_id));
18874
+ return stillExists;
18875
+ }
18876
+ return true;
18877
+ }).map((localAnc) => {
18878
+ const freshVersion = freshAncestryMap.get(String(localAnc.ancestry_id));
18879
+ if (freshVersion) {
18880
+ return {
18881
+ ...freshVersion,
18882
+ _imported_from_view_id: localAnc._imported_from_view_id,
18883
+ _imported_from_view_owner_id: localAnc._imported_from_view_owner_id,
18884
+ _origin_db_ids: localAnc._origin_db_ids,
18885
+ _source_file_id: localAnc._source_file_id,
18886
+ _source_owner_id: localAnc._source_owner_id
18887
+ };
18888
+ }
18889
+ return localAnc;
18890
+ });
18891
+ }
18892
+ const ancestryFilePath = `x_view_ancestry/${owner_id}/${scene_config}`;
18893
+ const parentNodeIds = new Set(allNodes.map((node) => String(node.id)));
18894
+ const pruneTree = (node) => {
18895
+ if (!node) return null;
18896
+ if (node.is_section) {
18897
+ const validChildren2 = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
18898
+ return { ...node, children: validChildren2 };
18899
+ }
18900
+ if (!parentNodeIds.has(String(node.node_id))) {
18901
+ return null;
18902
+ }
18903
+ const validChildren = (node.children || []).map((child) => pruneTree(child)).filter(Boolean);
18904
+ let validBranches = [];
18905
+ if (node.parallel_branches) {
18906
+ validBranches = node.parallel_branches.map((branch) => ({
18907
+ ...branch,
18908
+ tree: pruneTree(branch.tree)
18909
+ })).filter((b) => b.tree !== null);
18910
+ }
18911
+ return {
18912
+ ...node,
18913
+ children: validChildren,
18914
+ parallel_branches: validBranches
18915
+ };
18916
+ };
18917
+ const originalAncestryDataString = JSON.stringify(Array.from(ancestryMap.values()));
18918
+ const cleanedAncestryData = ancestryData.map((ancestry) => {
18919
+ if (!parentNodeIds.has(String(ancestry.ancestral_node))) return null;
18920
+ const cleanedTree = pruneTree(ancestry.tree);
18921
+ if (!cleanedTree) return null;
18922
+ let cleanedAbstraction = null;
18923
+ if (ancestry.abstraction_tree) {
18924
+ cleanedAbstraction = pruneTree(ancestry.abstraction_tree);
18925
+ }
18926
+ return {
18927
+ ...ancestry,
18928
+ tree: cleanedTree,
18929
+ abstraction_tree: cleanedAbstraction
18930
+ };
18931
+ }).filter(Boolean);
18932
+ if (JSON.stringify(cleanedAncestryData) !== originalAncestryDataString) {
18933
+ ancestryData = cleanedAncestryData;
18934
+ try {
18935
+ await db_services.save_file(ancestryFilePath, ancestryData);
18936
+ } catch (saveError) {
18937
+ console.error("Falha ao salvar o arquivo de ancestralidade da cena atualizado:", saveError);
18938
+ }
18939
+ }
18940
+ if (!isFullMember) {
18941
+ const requiredNodeIds = /* @__PURE__ */ new Set();
18942
+ const requiredAncestryIds = /* @__PURE__ */ new Set();
18943
+ if (focusNodeId) requiredNodeIds.add(String(focusNodeId));
18944
+ if (focusAncestryId) requiredAncestryIds.add(String(focusAncestryId));
18945
+ const allNodesFromDb = Object.values(parentData).flatMap((db) => db.nodes || []);
18946
+ const extractDependenciesFromText = (text) => {
18947
+ if (!text) return;
18948
+ const mentionRegex = /\[\[MENTION:node:([a-zA-Z0-9\-_]+)\]\]/g;
18949
+ const refRegex = /\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]/g;
18950
+ let match;
18951
+ while ((match = mentionRegex.exec(text)) !== null) {
18952
+ requiredNodeIds.add(match[1]);
18953
+ }
18954
+ while ((match = refRegex.exec(text)) !== null) {
18955
+ if (match[1] === "node") requiredNodeIds.add(match[2]);
18956
+ if (match[1] === "ancestry") requiredAncestryIds.add(match[2]);
18957
+ }
18958
+ };
18959
+ const extractTreeDependencies = (treeItem) => {
18960
+ var _a2;
18961
+ if (!treeItem) return;
18962
+ if (treeItem.node_id) requiredNodeIds.add(String(treeItem.node_id));
18963
+ if ((_a2 = treeItem.node) == null ? void 0 : _a2.id) requiredNodeIds.add(String(treeItem.node.id));
18964
+ if (treeItem.children) {
18965
+ treeItem.children.forEach(extractTreeDependencies);
18966
+ }
18967
+ if (treeItem.parallel_branches) {
18968
+ treeItem.parallel_branches.forEach((branch) => {
18969
+ if (branch.linked_ancestry_id) {
18970
+ requiredAncestryIds.add(String(branch.linked_ancestry_id));
18971
+ }
18972
+ if (branch.description) extractDependenciesFromText(branch.description);
18973
+ if (branch.description_sections) {
18974
+ branch.description_sections.forEach((s) => extractDependenciesFromText(s.content));
18975
+ }
18976
+ extractTreeDependencies(branch.tree);
18977
+ });
18978
+ }
18979
+ };
18980
+ let previousSize;
18981
+ do {
18982
+ previousSize = requiredNodeIds.size + requiredAncestryIds.size;
18983
+ requiredAncestryIds.forEach((ancId) => {
18984
+ const anc = ancestryData.find((a) => String(a.ancestry_id) === ancId);
18985
+ if (anc && !anc.is_private) {
18986
+ if (anc.description) extractDependenciesFromText(anc.description);
18987
+ if (anc.description_sections) {
18988
+ anc.description_sections.forEach((s) => extractDependenciesFromText(s.content));
18989
+ }
18990
+ extractTreeDependencies(anc.tree);
18991
+ extractTreeDependencies(anc.abstraction_tree);
18992
+ }
18993
+ });
18994
+ requiredNodeIds.forEach((nodeId) => {
18995
+ const node = allNodesFromDb.find((n) => String(n.id) === nodeId);
18996
+ if (node) {
18997
+ if (node.description) extractDependenciesFromText(node.description);
18998
+ if (node.description_sections) {
18999
+ node.description_sections.forEach((s) => extractDependenciesFromText(s.content));
19000
+ }
19001
+ }
19002
+ });
19003
+ } while (requiredNodeIds.size + requiredAncestryIds.size > previousSize);
19004
+ const restrictedSceneData = { ...validatedSceneData, nodes: [], links: [] };
19005
+ const restrictedParentData = {};
19006
+ const restrictedAncestryData = ancestryData.filter((a) => requiredAncestryIds.has(String(a.ancestry_id)) && !a.is_private);
19007
+ for (const [dbId, dbContent] of Object.entries(parentData)) {
19008
+ const filteredNodes = (dbContent.nodes || []).filter((n) => requiredNodeIds.has(String(n.id)));
19009
+ if (filteredNodes.length > 0) {
19010
+ restrictedParentData[dbId] = { ...dbContent, nodes: filteredNodes, links: [] };
19011
+ }
19012
+ }
19013
+ if (focusNodeId) {
19014
+ const mainNode = allNodesFromDb.find((n) => String(n.id) === String(focusNodeId));
19015
+ if (mainNode) {
19016
+ restrictedSceneData.nodes = [mainNode];
19017
+ }
19018
+ }
19019
+ return {
19020
+ success: true,
19021
+ data: {
19022
+ scene: restrictedSceneData,
19023
+ parent: restrictedParentData,
19024
+ ancestry: restrictedAncestryData
19025
+ }
19026
+ };
19027
+ }
19028
+ return {
19029
+ success: true,
19030
+ data: { scene: validatedSceneData, parent: parentData, ancestry: ancestryData }
19031
+ };
19032
+ } catch (error) {
19033
+ console.error("Erro em get_scene_view_data_logic:", error);
19034
+ return { success: false, error: error.message };
19035
+ }
19036
+ }
19037
+ async function import_parent_file_modal_get_logic(db_services, session) {
19038
+ try {
19039
+ const call_firestore_get_x_view_data = await db_services.get_firestore_data(session);
19040
+ const x_view_databases = call_firestore_get_x_view_data.data.sub_collections.x_view_databases || [];
19041
+ const x_views = call_firestore_get_x_view_data.data.sub_collections.x_views || [];
19042
+ return {
19043
+ success: true,
19044
+ data: {
19045
+ databases: x_view_databases,
19046
+ views: x_views
19047
+ }
19048
+ };
19049
+ } catch (error) {
19050
+ console.error("catch (error) em import_parent_file_modal_get_logic:", error);
19051
+ return { success: false, error: error.message };
19052
+ }
19053
+ }
19054
+ async function get_single_parent_file_logic(db_services, file_id, session) {
19055
+ try {
19056
+ const call_GCP_cloud_storage_get_file = await db_services.get_file(`x_view_dbs/${session.user.id}/${file_id}`);
19057
+ return call_GCP_cloud_storage_get_file;
19058
+ } catch (error) {
19059
+ console.error("catch (error) em get_single_parent_file_logic:", error);
19060
+ return { success: false, error: error.message };
19061
+ }
19062
+ }
19063
+ async function x_view_add_new_parent_file_to_scene_at_firebase(file_id, session, new_parent, db_services) {
19064
+ try {
19065
+ const update_data = {
19066
+ scene_id: file_id,
19067
+ new_parent,
19068
+ session
19069
+ };
19070
+ const call_firestore_add_new_parent_file_to_scene_at_firebase = await db_services.add_new_parent_file_to_scene_at_firebase(update_data);
19071
+ return call_firestore_add_new_parent_file_to_scene_at_firebase;
19072
+ } catch (error) {
19073
+ console.error("catch (error) em get_single_parent_file_logic:", error);
19074
+ return { success: false, error: error.message };
19075
+ }
19076
+ }
19077
+ async function get_ancestry_file_logic(db_services, file_id, owner_id) {
19078
+ try {
19079
+ const path = `x_view_ancestry/${owner_id}/${file_id}`;
19080
+ const call_GCP_cloud_storage_get_file = await db_services.get_file(path);
19081
+ return call_GCP_cloud_storage_get_file;
19082
+ } catch (error) {
19083
+ console.error("catch (error) em get_ancestry_file_logic:", error);
19084
+ return { success: false, error: error.message };
19085
+ }
19086
+ }
19087
+ async function save_ancestry_board_logic(db_services, scene_id, type, groups, session, owner_id) {
19088
+ try {
19089
+ const targetOwnerId = owner_id || session.user.id;
19090
+ return await db_services.save_ancestry_board(session, scene_id, type, groups, targetOwnerId);
19091
+ } catch (error) {
19092
+ console.error("Erro em save_ancestry_board_logic:", error);
19093
+ return { success: false, error: error.message };
19094
+ }
19095
+ }
19096
+ async function get_ancestry_board_logic(db_services, scene_id, type, session, owner_id) {
19097
+ try {
19098
+ const targetOwnerId = owner_id || session.user.id;
19099
+ return await db_services.get_ancestry_board(session, scene_id, type, targetOwnerId);
19100
+ } catch (error) {
19101
+ console.error("Erro em get_ancestry_board_logic:", error);
19102
+ return { success: false, error: error.message };
19103
+ }
19104
+ }
19105
+ async function delete_uploaded_file_logic(db_services, fileUrl) {
19106
+ try {
19107
+ if (db_services.delete_public_file) {
19108
+ return await db_services.delete_public_file(fileUrl);
19109
+ }
19110
+ return { success: false, error: "Servi\xE7o de dele\xE7\xE3o n\xE3o configurado." };
19111
+ } catch (error) {
19112
+ console.error("Erro em delete_uploaded_file_logic:", error);
19113
+ return { success: false, error: error.message };
19114
+ }
19115
+ }
19116
+ async function get_view_members_logic(db_services, ownerId, type, itemId) {
19117
+ try {
19118
+ if (!db_services.get_view_members) {
19119
+ return { success: false, error: "Servi\xE7o de busca de membros n\xE3o configurado." };
19120
+ }
19121
+ return await db_services.get_view_members(ownerId, type, itemId);
19122
+ } catch (error) {
19123
+ console.error("Erro em get_view_members_logic:", error);
19124
+ return { success: false, error: error.message };
19125
+ }
19126
+ }
18804
19127
  export {
18805
- XViewScene
19128
+ XViewScene,
19129
+ delete_uploaded_file_logic,
19130
+ get_ancestry_board_logic,
19131
+ get_ancestry_file_logic,
19132
+ get_scene_view_data_logic,
19133
+ get_single_parent_file_logic,
19134
+ get_view_members_logic,
19135
+ import_parent_file_modal_get_logic,
19136
+ save_ancestry_board_logic,
19137
+ save_view_data_logic,
19138
+ x_view_add_new_parent_file_to_scene_at_firebase
18806
19139
  };