@lv-x-software-house/x_view 1.2.5-dev.46 → 1.2.5-dev.48

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 +546 -183
  2. package/dist/index.mjs +477 -114
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  // src/XViewScene.jsx
2
- import React27, {
2
+ import React28, {
3
3
  useCallback as useCallback4,
4
4
  useEffect as useEffect22,
5
5
  useRef as useRef19,
6
- useState as useState26,
6
+ useState as useState27,
7
7
  useMemo as useMemo12
8
8
  } from "react";
9
9
  import { useRouter, useSearchParams } from "next/navigation";
@@ -586,6 +586,9 @@ function XViewSidebar({
586
586
  userRole,
587
587
  viewMembers = [],
588
588
  onActivateQuestLens = () => {
589
+ },
590
+ milestones = [],
591
+ onOpenMilestoneManager = () => {
589
592
  }
590
593
  }) {
591
594
  const [query, setQuery] = useState2("");
@@ -994,25 +997,7 @@ function XViewSidebar({
994
997
  },
995
998
  /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React2.createElement("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), /* @__PURE__ */ React2.createElement("polyline", { points: "17 8 12 3 7 8" }), /* @__PURE__ */ React2.createElement("line", { x1: "12", y1: "3", x2: "12", y2: "15" })),
996
999
  "Importar arquivo"
997
- ), /* @__PURE__ */ React2.createElement("p", { className: "mt-1.5 text-xs text-slate-400 text-center px-1 leading-tight" }, "Importar datasets ou ancestralidades das views."), /* @__PURE__ */ React2.createElement("div", { className: "h-9 mt-1 flex items-center justify-center" }, importSuccessMessage && /* @__PURE__ */ React2.createElement("p", { className: "w-full text-center text-xs font-medium text-indigo-300 bg-indigo-500/10 border border-indigo-500/20 rounded-md py-1.5 px-2" }, importSuccessMessage)))), /* @__PURE__ */ React2.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ React2.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Lentes"), /* @__PURE__ */ React2.createElement(
998
- "button",
999
- {
1000
- onClick: onActivateTimeline,
1001
- className: buttonBaseClass,
1002
- title: "Ativar a visualiza\xE7\xE3o de Timeline"
1003
- },
1004
- /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React2.createElement("polyline", { points: "12 6 12 12 16 14" })),
1005
- "Timeline"
1006
- ), /* @__PURE__ */ React2.createElement(
1007
- "button",
1008
- {
1009
- onClick: onOpenAncestryBoard,
1010
- className: buttonBaseClass,
1011
- title: "Abrir painel de Ancestralidades"
1012
- },
1013
- /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React2.createElement("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }), /* @__PURE__ */ React2.createElement("polyline", { points: "2 17 12 22 22 17" }), /* @__PURE__ */ React2.createElement("polyline", { points: "2 12 12 17 22 12" })),
1014
- "Ancestry Board"
1015
- ), /* @__PURE__ */ React2.createElement("div", { className: "relative", ref: questLensRef }, /* @__PURE__ */ React2.createElement(
1000
+ ), /* @__PURE__ */ React2.createElement("p", { className: "mt-1.5 text-xs text-slate-400 text-center px-1 leading-tight" }, "Importar datasets ou ancestralidades das views."), /* @__PURE__ */ React2.createElement("div", { className: "h-9 mt-1 flex items-center justify-center" }, importSuccessMessage && /* @__PURE__ */ React2.createElement("p", { className: "w-full text-center text-xs font-medium text-indigo-300 bg-indigo-500/10 border border-indigo-500/20 rounded-md py-1.5 px-2" }, importSuccessMessage)))), /* @__PURE__ */ React2.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ React2.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Lentes"), /* @__PURE__ */ React2.createElement("div", { className: "relative", ref: questLensRef }, /* @__PURE__ */ React2.createElement(
1016
1001
  "button",
1017
1002
  {
1018
1003
  onClick: () => setIsQuestLensMenuOpen(!isQuestLensMenuOpen),
@@ -1064,7 +1049,35 @@ function XViewSidebar({
1064
1049
  className: "flex-[2] py-2 bg-indigo-600 hover:bg-indigo-500 text-white text-[11px] font-bold rounded-lg shadow-lg shadow-indigo-500/20 transition-all hover:scale-[1.02] active:scale-95"
1065
1050
  },
1066
1051
  "Aplicar Lente"
1067
- )))))), /* @__PURE__ */ React2.createElement("div", { className: "px-4 py-3 border-t border-white/10 bg-slate-900/30" }, /* @__PURE__ */ React2.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ React2.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o")), ability.can("update", "Scene") && /* @__PURE__ */ React2.createElement(
1052
+ )))), /* @__PURE__ */ React2.createElement(
1053
+ "button",
1054
+ {
1055
+ onClick: onActivateTimeline,
1056
+ className: buttonBaseClass,
1057
+ title: "Ativar a visualiza\xE7\xE3o de Timeline"
1058
+ },
1059
+ /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React2.createElement("polyline", { points: "12 6 12 12 16 14" })),
1060
+ "Timeline"
1061
+ ), /* @__PURE__ */ React2.createElement(
1062
+ "button",
1063
+ {
1064
+ onClick: onOpenAncestryBoard,
1065
+ className: buttonBaseClass,
1066
+ title: "Abrir painel de Ancestralidades"
1067
+ },
1068
+ /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React2.createElement("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }), /* @__PURE__ */ React2.createElement("polyline", { points: "2 17 12 22 22 17" }), /* @__PURE__ */ React2.createElement("polyline", { points: "2 12 12 17 22 12" })),
1069
+ "Ancestry Board"
1070
+ )), /* @__PURE__ */ React2.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ React2.createElement("section", { className: "space-y-3" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Milestones"), /* @__PURE__ */ React2.createElement(
1071
+ "button",
1072
+ {
1073
+ onClick: onOpenMilestoneManager,
1074
+ className: buttonBaseClass,
1075
+ title: "Gerenciar os milestones deste cen\xE1rio"
1076
+ },
1077
+ /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "12", r: "6" }), /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "12", r: "2" })),
1078
+ "Gerenciar Milestones",
1079
+ milestones.length > 0 && /* @__PURE__ */ React2.createElement("span", { className: "ml-1.5 px-1.5 py-0.5 rounded-full bg-indigo-500/30 text-[10px] font-bold border border-indigo-400/30" }, milestones.length)
1080
+ ))), /* @__PURE__ */ React2.createElement("div", { className: "px-4 py-3 border-t border-white/10 bg-slate-900/30" }, /* @__PURE__ */ React2.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ React2.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o")), ability.can("update", "Scene") && /* @__PURE__ */ React2.createElement(
1068
1081
  "button",
1069
1082
  {
1070
1083
  onClick: handleSaveClick,
@@ -2293,7 +2306,8 @@ var userActionHandlers = {
2293
2306
  nodes: sceneDataRef.current.nodes,
2294
2307
  links: sceneDataRef.current.links,
2295
2308
  quest_nodes: specificParentData.nodes,
2296
- quest_links: specificParentData.links
2309
+ quest_links: specificParentData.links,
2310
+ milestones: sceneDataRef.current.milestones || []
2297
2311
  };
2298
2312
  await context.actions.save_view_data(
2299
2313
  context.sceneSaveUrl,
@@ -2551,7 +2565,8 @@ var userActionHandlers = {
2551
2565
  nodes: sceneDataRef.current.nodes,
2552
2566
  links: sceneDataRef.current.links,
2553
2567
  quest_nodes: specificParentData.nodes,
2554
- quest_links: specificParentData.links
2568
+ quest_links: specificParentData.links,
2569
+ milestones: sceneDataRef.current.milestones || []
2555
2570
  };
2556
2571
  await context.actions.save_view_data(
2557
2572
  context.sceneSaveUrl,
@@ -2707,7 +2722,8 @@ var userActionHandlers = {
2707
2722
  nodes: sceneDataRef.current.nodes,
2708
2723
  links: sceneDataRef.current.links,
2709
2724
  quest_nodes: data.nodes,
2710
- quest_links: data.links
2725
+ quest_links: data.links,
2726
+ milestones: sceneDataRef.current.milestones || []
2711
2727
  };
2712
2728
  return context.actions.save_view_data(
2713
2729
  context.sceneSaveUrl,
@@ -3321,6 +3337,7 @@ var userActionHandlers = {
3321
3337
  links: sceneDataRef.current.links,
3322
3338
  quest_nodes: specificParentData.nodes,
3323
3339
  quest_links: specificParentData.links,
3340
+ milestones: sceneDataRef.current.milestones || [],
3324
3341
  quest_counter: sceneDataRef.current.quest_counter || 1
3325
3342
  };
3326
3343
  await context.actions.save_view_data(
@@ -3393,7 +3410,8 @@ var userActionHandlers = {
3393
3410
  links: sceneDataRef.current.links,
3394
3411
  quest_nodes: specificParentData.nodes,
3395
3412
  quest_links: specificParentData.links,
3396
- quest_counter: sceneDataRef.current.quest_counter || 1
3413
+ quest_counter: sceneDataRef.current.quest_counter || 1,
3414
+ milestones: sceneDataRef.current.milestones || []
3397
3415
  };
3398
3416
  await context.actions.save_view_data(
3399
3417
  context.sceneSaveUrl,
@@ -9487,11 +9505,15 @@ function InSceneQuestForm({
9487
9505
  questCounter = 1,
9488
9506
  // NOVA PROP
9489
9507
  viewMembers = [],
9490
- session = null
9508
+ session = null,
9509
+ milestones = [],
9510
+ onUpdateMilestones = () => {
9511
+ }
9491
9512
  }) {
9492
- var _a, _b;
9513
+ var _a, _b, _c;
9493
9514
  const [name, setName] = useState17("");
9494
9515
  const [assigneeId, setAssigneeId] = useState17("");
9516
+ const [milestoneId, setMilestoneId] = useState17("");
9495
9517
  const [types, setTypes] = useState17(["quest"]);
9496
9518
  const [typeInput, setTypeInput] = useState17("");
9497
9519
  const [status, setStatus] = useState17("Backlog");
@@ -9513,6 +9535,32 @@ function InSceneQuestForm({
9513
9535
  const [customProps, setCustomProps] = useState17([]);
9514
9536
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState17(false);
9515
9537
  const propsEndRef = useRef12(null);
9538
+ const [isMilestoneDropdownOpen, setIsMilestoneDropdownOpen] = useState17(false);
9539
+ const [milestoneSearchQuery, setMilestoneSearchQuery] = useState17("");
9540
+ const activeMilestones = React16.useMemo(
9541
+ () => (milestones || []).filter((ms) => ms.status === "active"),
9542
+ [milestones]
9543
+ );
9544
+ const filteredMilestones = React16.useMemo(() => {
9545
+ if (!milestoneSearchQuery.trim()) return activeMilestones;
9546
+ return activeMilestones.filter(
9547
+ (ms) => ms.name.toLowerCase().includes(milestoneSearchQuery.toLowerCase())
9548
+ );
9549
+ }, [activeMilestones, milestoneSearchQuery]);
9550
+ const handleSelectMilestone = (id) => {
9551
+ setMilestoneId(id);
9552
+ setIsMilestoneDropdownOpen(false);
9553
+ setMilestoneSearchQuery("");
9554
+ };
9555
+ const handleCreateMilestone = async (name2) => {
9556
+ if (!name2.trim()) return;
9557
+ const newId = `ms_${Date.now()}`;
9558
+ const newMs = { id: newId, name: name2.trim(), status: "active" };
9559
+ await onUpdateMilestones([...milestones, newMs]);
9560
+ setMilestoneId(newId);
9561
+ setIsMilestoneDropdownOpen(false);
9562
+ setMilestoneSearchQuery("");
9563
+ };
9516
9564
  const standardizedName = `${viewName} - ${questCounter} - \xBB ${name || "Nova Quest"}`;
9517
9565
  const handleAddProp = () => {
9518
9566
  const newProp = createNewCustomProperty(customProps);
@@ -9580,6 +9628,7 @@ function InSceneQuestForm({
9580
9628
  timeline: initialTimeline,
9581
9629
  Date: questDate ? { ...questDate, confirmed: true } : null,
9582
9630
  recurrence_config: recurrenceConfig,
9631
+ milestone_id: milestoneId || null,
9583
9632
  ...additionalData
9584
9633
  });
9585
9634
  };
@@ -9683,6 +9732,63 @@ function InSceneQuestForm({
9683
9732
  }
9684
9733
  ),
9685
9734
  s
9735
+ )))))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300 font-medium uppercase tracking-wider" }, "Milestone"), /* @__PURE__ */ React16.createElement("div", { className: "relative" }, /* @__PURE__ */ React16.createElement(
9736
+ "button",
9737
+ {
9738
+ type: "button",
9739
+ onClick: () => setIsMilestoneDropdownOpen(!isMilestoneDropdownOpen),
9740
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
9741
+ },
9742
+ /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React16.createElement(FiTarget, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React16.createElement("span", { className: "text-slate-200 font-medium" }, ((_a = (milestones || []).find((m) => m.id === milestoneId)) == null ? void 0 : _a.name) || "Nenhum")),
9743
+ /* @__PURE__ */ React16.createElement(
9744
+ FiChevronDown6,
9745
+ {
9746
+ className: `text-slate-400 transition-transform duration-200 ${isMilestoneDropdownOpen ? "rotate-180" : ""}`
9747
+ }
9748
+ )
9749
+ ), isMilestoneDropdownOpen && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
9750
+ "div",
9751
+ {
9752
+ className: "fixed inset-0 z-40",
9753
+ onClick: () => {
9754
+ setIsMilestoneDropdownOpen(false);
9755
+ setMilestoneSearchQuery("");
9756
+ }
9757
+ }
9758
+ ), /* @__PURE__ */ React16.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ React16.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ React16.createElement(FiSearch5, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ React16.createElement(
9759
+ "input",
9760
+ {
9761
+ type: "text",
9762
+ autoFocus: true,
9763
+ placeholder: "Buscar ou criar milestone...",
9764
+ value: milestoneSearchQuery,
9765
+ onChange: (e) => setMilestoneSearchQuery(e.target.value),
9766
+ className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
9767
+ onClick: (e) => e.stopPropagation()
9768
+ }
9769
+ )), /* @__PURE__ */ React16.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ React16.createElement(
9770
+ "li",
9771
+ {
9772
+ onClick: () => handleSelectMilestone(""),
9773
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!milestoneId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
9774
+ },
9775
+ "Nenhum"
9776
+ ), filteredMilestones.map((ms) => /* @__PURE__ */ React16.createElement(
9777
+ "li",
9778
+ {
9779
+ key: ms.id,
9780
+ onClick: () => handleSelectMilestone(ms.id),
9781
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${milestoneId === ms.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
9782
+ },
9783
+ ms.name
9784
+ )), milestoneSearchQuery.trim() && !filteredMilestones.some((ms) => ms.name.toLowerCase() === milestoneSearchQuery.toLowerCase().trim()) && /* @__PURE__ */ React16.createElement(
9785
+ "li",
9786
+ {
9787
+ onClick: () => handleCreateMilestone(milestoneSearchQuery),
9788
+ className: "px-3 py-3 text-sm cursor-pointer bg-indigo-600/20 text-indigo-200 hover:bg-indigo-600/40 transition-colors flex flex-col gap-0.5"
9789
+ },
9790
+ /* @__PURE__ */ React16.createElement("span", { className: "text-[10px] uppercase font-bold opacity-60" }, "Criar Novo Milestone"),
9791
+ /* @__PURE__ */ React16.createElement("span", { className: "font-medium" }, '"', milestoneSearchQuery, '"')
9686
9792
  )))))), /* @__PURE__ */ React16.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React16.createElement("label", { className: "text-xs text-slate-300 font-medium uppercase tracking-wider" }, "Assignee (Respons\xE1vel)"), /* @__PURE__ */ React16.createElement("div", { className: "relative" }, /* @__PURE__ */ React16.createElement(
9687
9793
  "button",
9688
9794
  {
@@ -9690,7 +9796,7 @@ function InSceneQuestForm({
9690
9796
  onClick: () => setIsAssigneeDropdownOpen(!isAssigneeDropdownOpen),
9691
9797
  className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
9692
9798
  },
9693
- /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React16.createElement(FiUser2, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React16.createElement("span", { className: "text-slate-200 font-medium" }, ((_a = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _a.name) || ((_b = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _b.email) || "Nenhum")),
9799
+ /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React16.createElement(FiUser2, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React16.createElement("span", { className: "text-slate-200 font-medium" }, ((_b = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _b.name) || ((_c = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _c.email) || "Nenhum")),
9694
9800
  /* @__PURE__ */ React16.createElement(
9695
9801
  FiChevronDown6,
9696
9802
  {
@@ -10674,9 +10780,12 @@ function QuestDetailsPanel({
10674
10780
  userRole,
10675
10781
  currentDatasetName,
10676
10782
  viewMembers = [],
10677
- currentUser
10783
+ currentUser,
10784
+ milestones = [],
10785
+ onUpdateMilestones = () => {
10786
+ }
10678
10787
  }) {
10679
- var _a, _b;
10788
+ var _a, _b, _c;
10680
10789
  const initialRawTitle = (node == null ? void 0 : node.raw_title) || (((_a = node == null ? void 0 : node.name) == null ? void 0 : _a.includes(" - \xBB ")) ? node.name.split(" - \xBB ")[1] : node == null ? void 0 : node.name) || "";
10681
10790
  const [rawTitle, setRawTitle] = useState19(initialRawTitle);
10682
10791
  const prefixParts = ((node == null ? void 0 : node.name) || "").split(" - \xBB ");
@@ -10689,6 +10798,7 @@ function QuestDetailsPanel({
10689
10798
  const [assigneeId, setAssigneeId] = useState19((node == null ? void 0 : node.assignee_id) || "");
10690
10799
  const [description, setDescription] = useState19((node == null ? void 0 : node.description) ?? "");
10691
10800
  const [intensity, setIntensity] = useState19((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
10801
+ const [milestoneId, setMilestoneId] = useState19((node == null ? void 0 : node.milestone_id) || "");
10692
10802
  const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState19(false);
10693
10803
  const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = useState19(false);
10694
10804
  const [assigneeSearchQuery, setAssigneeSearchQuery] = useState19("");
@@ -10726,6 +10836,35 @@ function QuestDetailsPanel({
10726
10836
  minWidth: 320,
10727
10837
  maxWidth: maxPanelW
10728
10838
  });
10839
+ const [isMilestoneDropdownOpen, setIsMilestoneDropdownOpen] = useState19(false);
10840
+ const [milestoneSearchQuery, setMilestoneSearchQuery] = useState19("");
10841
+ const activeMilestones = React19.useMemo(
10842
+ () => (milestones || []).filter((ms) => ms.status === "active"),
10843
+ [milestones]
10844
+ );
10845
+ const filteredMilestones = React19.useMemo(() => {
10846
+ const search = milestoneSearchQuery.toLowerCase().trim();
10847
+ if (!search) return activeMilestones;
10848
+ return activeMilestones.filter(
10849
+ (ms) => ms.name.toLowerCase().includes(search)
10850
+ );
10851
+ }, [activeMilestones, milestoneSearchQuery]);
10852
+ const handleSelectMilestone = (id) => {
10853
+ setMilestoneId(id);
10854
+ setIsMilestoneDropdownOpen(false);
10855
+ setMilestoneSearchQuery("");
10856
+ setHasUnsavedChanges(true);
10857
+ };
10858
+ const handleCreateMilestone = async (name) => {
10859
+ if (!name.trim()) return;
10860
+ const newId = `ms_${Date.now()}`;
10861
+ const newMs = { id: newId, name: name.trim(), status: "active" };
10862
+ await onUpdateMilestones([...milestones, newMs]);
10863
+ setMilestoneId(newId);
10864
+ setIsMilestoneDropdownOpen(false);
10865
+ setMilestoneSearchQuery("");
10866
+ setHasUnsavedChanges(true);
10867
+ };
10729
10868
  useEffect16(() => {
10730
10869
  setWidth(isReadMode ? 700 : 440);
10731
10870
  }, [isReadMode, setWidth]);
@@ -10751,6 +10890,7 @@ function QuestDetailsPanel({
10751
10890
  setReturnAssigneeId("");
10752
10891
  setDescription((node == null ? void 0 : node.description) ?? "");
10753
10892
  setIntensity((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
10893
+ setMilestoneId((node == null ? void 0 : node.milestone_id) || "");
10754
10894
  setExistingSections((node == null ? void 0 : node.description_sections) || []);
10755
10895
  setCustomProps(extractCustomPropsFromNode(node || {}));
10756
10896
  setReviewStack((node == null ? void 0 : node.reviewStack) || []);
@@ -10763,6 +10903,7 @@ function QuestDetailsPanel({
10763
10903
  custom_date: "",
10764
10904
  next_assignee_id: ""
10765
10905
  });
10906
+ setMilestoneId((node == null ? void 0 : node.milestone_id) || "");
10766
10907
  setHasUnsavedChanges(false);
10767
10908
  }
10768
10909
  }, [node]);
@@ -11061,7 +11202,8 @@ ${noteText}` : noteText : entry.notes,
11061
11202
  reviewStack: currentReviewStack,
11062
11203
  timeline: currentTimeline,
11063
11204
  ...extrasObj,
11064
- version_node: node.version_node
11205
+ version_node: node.version_node,
11206
+ milestone_id: milestoneId || null
11065
11207
  };
11066
11208
  await onSave(dataToSave, keepOpen);
11067
11209
  onDataUpdate(dataToSave);
@@ -11263,7 +11405,51 @@ ${noteText}` : noteText : entry.notes,
11263
11405
  maxLength: "10",
11264
11406
  className: "flex-1 bg-slate-800/70 p-2 text-xs rounded-lg border border-white/10 focus:outline-none focus:ring-1 focus:ring-indigo-400/60"
11265
11407
  }
11266
- ))))), /* @__PURE__ */ React19.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React19.createElement("div", { className: "relative" }, /* @__PURE__ */ React19.createElement(
11408
+ ))))), /* @__PURE__ */ React19.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Milestone"), /* @__PURE__ */ React19.createElement("div", { className: "relative" }, /* @__PURE__ */ React19.createElement(
11409
+ "button",
11410
+ {
11411
+ type: "button",
11412
+ onClick: () => canEdit && setIsMilestoneDropdownOpen(!isMilestoneDropdownOpen),
11413
+ disabled: !canEdit,
11414
+ className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 transition-colors flex items-center justify-between ${canEdit ? "hover:border-white/20 focus:ring-2 focus:ring-indigo-400/60 cursor-pointer" : "cursor-default opacity-80"}`
11415
+ },
11416
+ /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React19.createElement(FiTarget3, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React19.createElement("span", { className: "text-slate-200 font-medium" }, ((_b = (milestones || []).find((m) => m.id === milestoneId)) == null ? void 0 : _b.name) || "Nenhum")),
11417
+ canEdit && /* @__PURE__ */ React19.createElement(FiChevronDown7, { className: `text-slate-400 transition-transform duration-200 ${isMilestoneDropdownOpen ? "rotate-180" : ""}` })
11418
+ ), isMilestoneDropdownOpen && canEdit && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "fixed inset-0 z-40", onClick: () => setIsMilestoneDropdownOpen(false) }), /* @__PURE__ */ React19.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ React19.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ React19.createElement(FiSearch7, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ React19.createElement(
11419
+ "input",
11420
+ {
11421
+ type: "text",
11422
+ autoFocus: true,
11423
+ placeholder: "Buscar ou criar milestone...",
11424
+ value: milestoneSearchQuery,
11425
+ onChange: (e) => setMilestoneSearchQuery(e.target.value),
11426
+ className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
11427
+ onClick: (e) => e.stopPropagation()
11428
+ }
11429
+ )), /* @__PURE__ */ React19.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ React19.createElement(
11430
+ "li",
11431
+ {
11432
+ onClick: () => handleSelectMilestone(""),
11433
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!milestoneId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
11434
+ },
11435
+ "Nenhum"
11436
+ ), filteredMilestones.map((ms) => /* @__PURE__ */ React19.createElement(
11437
+ "li",
11438
+ {
11439
+ key: ms.id,
11440
+ onClick: () => handleSelectMilestone(ms.id),
11441
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${milestoneId === ms.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
11442
+ },
11443
+ ms.name
11444
+ )), milestoneSearchQuery.trim() && !filteredMilestones.some((ms) => ms.name.toLowerCase() === milestoneSearchQuery.toLowerCase().trim()) && /* @__PURE__ */ React19.createElement(
11445
+ "li",
11446
+ {
11447
+ onClick: () => handleCreateMilestone(milestoneSearchQuery),
11448
+ className: "px-3 py-3 text-sm cursor-pointer bg-indigo-600/20 text-indigo-200 hover:bg-indigo-600/40 transition-colors flex flex-col gap-0.5"
11449
+ },
11450
+ /* @__PURE__ */ React19.createElement("span", { className: "text-[10px] uppercase font-bold opacity-60" }, "Criar Novo Milestone"),
11451
+ /* @__PURE__ */ React19.createElement("span", { className: "font-medium" }, '"', milestoneSearchQuery, '"')
11452
+ )))))), /* @__PURE__ */ React19.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React19.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React19.createElement("div", { className: "relative" }, /* @__PURE__ */ React19.createElement(
11267
11453
  "button",
11268
11454
  {
11269
11455
  type: "button",
@@ -11449,7 +11635,7 @@ ${noteText}` : noteText : entry.notes,
11449
11635
  onClick: () => setIsReturnDropdownOpen(!isReturnDropdownOpen),
11450
11636
  className: "w-full bg-slate-800/80 p-2 text-xs rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-1 focus:ring-purple-400/50 transition-colors flex items-center justify-between"
11451
11637
  },
11452
- /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React19.createElement(FiUser3, { className: "text-slate-400", size: 12 }), /* @__PURE__ */ React19.createElement("span", { className: "text-slate-200 font-medium" }, ((_b = viewMembers.find((m) => String(m.id) === String(returnAssigneeId))) == null ? void 0 : _b.name) || "Selecionar respons\xE1vel...")),
11638
+ /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React19.createElement(FiUser3, { className: "text-slate-400", size: 12 }), /* @__PURE__ */ React19.createElement("span", { className: "text-slate-200 font-medium" }, ((_c = viewMembers.find((m) => String(m.id) === String(returnAssigneeId))) == null ? void 0 : _c.name) || "Selecionar respons\xE1vel...")),
11453
11639
  /* @__PURE__ */ React19.createElement(FiChevronDown7, { className: `text-slate-400 transition-transform duration-200 ${isReturnDropdownOpen ? "rotate-180" : ""}`, size: 14 })
11454
11640
  ), isReturnDropdownOpen && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement("div", { className: "fixed inset-0 z-40", onClick: () => {
11455
11641
  setIsReturnDropdownOpen(false);
@@ -13049,6 +13235,116 @@ function AncestryBoard({
13049
13235
  );
13050
13236
  }
13051
13237
 
13238
+ // src/components/MilestoneManager.jsx
13239
+ import React27, { useState as useState26 } from "react";
13240
+ import { FiTarget as FiTarget4, FiPlus as FiPlus11, FiTrash2 as FiTrash24, FiX as FiX9, FiCheck as FiCheck12, FiPauseCircle, FiPlayCircle } from "react-icons/fi";
13241
+ function MilestoneManager({
13242
+ isOpen,
13243
+ onClose,
13244
+ milestones = [],
13245
+ onUpdateMilestones = () => {
13246
+ }
13247
+ }) {
13248
+ const [newMilestoneName, setNewMilestoneName] = useState26("");
13249
+ const handleAddMilestone = () => {
13250
+ if (!newMilestoneName.trim()) return;
13251
+ const newMilestone = {
13252
+ id: `ms_${Date.now()}`,
13253
+ name: newMilestoneName.trim(),
13254
+ status: "active"
13255
+ };
13256
+ onUpdateMilestones([...milestones, newMilestone]);
13257
+ setNewMilestoneName("");
13258
+ };
13259
+ const handleToggleMilestoneStatus = (id) => {
13260
+ const updated = milestones.map(
13261
+ (ms) => ms.id === id ? { ...ms, status: ms.status === "active" ? "inactive" : "active" } : ms
13262
+ );
13263
+ onUpdateMilestones(updated);
13264
+ };
13265
+ const handleRemoveMilestone = (id) => {
13266
+ var _a;
13267
+ if (!confirm(`Deseja remover o milestone "${(_a = milestones.find((m) => m.id === id)) == null ? void 0 : _a.name}"?`)) return;
13268
+ const updated = milestones.filter((ms) => ms.id !== id);
13269
+ onUpdateMilestones(updated);
13270
+ };
13271
+ if (!isOpen) return null;
13272
+ const swallow = (e) => e.stopPropagation();
13273
+ return /* @__PURE__ */ React27.createElement(
13274
+ "div",
13275
+ {
13276
+ 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",
13277
+ onClick: onClose
13278
+ },
13279
+ /* @__PURE__ */ React27.createElement(
13280
+ "div",
13281
+ {
13282
+ 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",
13283
+ onClick: swallow
13284
+ },
13285
+ /* @__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(
13286
+ "button",
13287
+ {
13288
+ onClick: onClose,
13289
+ className: "p-2 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition-colors"
13290
+ },
13291
+ /* @__PURE__ */ React27.createElement(FiX9, { size: 20 })
13292
+ )),
13293
+ /* @__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(
13294
+ "input",
13295
+ {
13296
+ type: "text",
13297
+ value: newMilestoneName,
13298
+ onChange: (e) => setNewMilestoneName(e.target.value),
13299
+ onKeyDown: (e) => e.key === "Enter" && handleAddMilestone(),
13300
+ placeholder: "Adicionar novo milestone...",
13301
+ 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"
13302
+ }
13303
+ ), /* @__PURE__ */ React27.createElement(
13304
+ "button",
13305
+ {
13306
+ onClick: handleAddMilestone,
13307
+ disabled: !newMilestoneName.trim(),
13308
+ 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"
13309
+ },
13310
+ /* @__PURE__ */ React27.createElement(FiPlus11, { size: 18 }),
13311
+ "Adicionar"
13312
+ ))),
13313
+ /* @__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(
13314
+ "div",
13315
+ {
13316
+ key: ms.id,
13317
+ 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]"}`
13318
+ },
13319
+ /* @__PURE__ */ React27.createElement("div", { className: "flex items-center gap-3 min-w-0" }, /* @__PURE__ */ React27.createElement(
13320
+ "div",
13321
+ {
13322
+ 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"}`
13323
+ }
13324
+ ), /* @__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"))),
13325
+ /* @__PURE__ */ React27.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React27.createElement(
13326
+ "button",
13327
+ {
13328
+ onClick: () => handleToggleMilestoneStatus(ms.id),
13329
+ 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"}`,
13330
+ title: ms.status === "active" ? "Inativar" : "Ativar"
13331
+ },
13332
+ ms.status === "active" ? /* @__PURE__ */ React27.createElement(FiPauseCircle, { size: 18 }) : /* @__PURE__ */ React27.createElement(FiPlayCircle, { size: 18 })
13333
+ ), /* @__PURE__ */ React27.createElement(
13334
+ "button",
13335
+ {
13336
+ onClick: () => handleRemoveMilestone(ms.id),
13337
+ className: "p-2 rounded-lg hover:bg-red-500/20 text-slate-500 hover:text-red-400 transition-all",
13338
+ title: "Remover"
13339
+ },
13340
+ /* @__PURE__ */ React27.createElement(FiTrash24, { size: 18 })
13341
+ ))
13342
+ ))) : /* @__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."))),
13343
+ /* @__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))))
13344
+ )
13345
+ );
13346
+ }
13347
+
13052
13348
  // src/XViewScene.jsx
13053
13349
  import short2 from "short-uuid";
13054
13350
  var secretKey = process.env.NEXT_PUBLIC_CRYPTO_KEY;
@@ -13130,7 +13426,7 @@ function XViewScene({
13130
13426
  check_user_permission,
13131
13427
  get_view_members
13132
13428
  }) {
13133
- var _a, _b, _c, _d, _e, _f, _g, _h;
13429
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
13134
13430
  const { data: session, status } = useSession();
13135
13431
  const router = useRouter();
13136
13432
  const searchParams = useSearchParams();
@@ -13205,42 +13501,42 @@ function XViewScene({
13205
13501
  const sceneDataRef = useRef19(null);
13206
13502
  const parentDataRef = useRef19(null);
13207
13503
  const ancestryDataRef = useRef19(null);
13208
- const [isLoading, setIsLoading] = useState26(true);
13209
- const [permissionStatus, setPermissionStatus] = useState26("loading");
13210
- const [userPermissionRole, setUserPermissionRole] = useState26(null);
13211
- const [viewMembers, setViewMembers] = useState26([]);
13212
- const [isInitialized, setIsInitialized] = useState26(false);
13213
- const [sceneVersion, setSceneVersion] = useState26(0);
13214
- const [contextMenu, setContextMenu] = useState26({
13504
+ const [isLoading, setIsLoading] = useState27(true);
13505
+ const [permissionStatus, setPermissionStatus] = useState27("loading");
13506
+ const [userPermissionRole, setUserPermissionRole] = useState27(null);
13507
+ const [viewMembers, setViewMembers] = useState27([]);
13508
+ const [isInitialized, setIsInitialized] = useState27(false);
13509
+ const [sceneVersion, setSceneVersion] = useState27(0);
13510
+ const [contextMenu, setContextMenu] = useState27({
13215
13511
  visible: false,
13216
13512
  x: 0,
13217
13513
  y: 0,
13218
13514
  nodeData: null
13219
13515
  });
13220
- const [multiContextMenu, setMultiContextMenu] = useState26({
13516
+ const [multiContextMenu, setMultiContextMenu] = useState27({
13221
13517
  visible: false,
13222
13518
  x: 0,
13223
13519
  y: 0,
13224
13520
  nodeIds: null
13225
13521
  });
13226
- const [relationshipMenu, setRelationshipMenu] = useState26({
13522
+ const [relationshipMenu, setRelationshipMenu] = useState27({
13227
13523
  visible: false,
13228
13524
  x: 0,
13229
13525
  y: 0,
13230
13526
  linkObject: null
13231
13527
  });
13232
- const [creationMode, setCreationMode] = useState26({
13528
+ const [creationMode, setCreationMode] = useState27({
13233
13529
  isActive: false,
13234
13530
  sourceNodeData: null
13235
13531
  });
13236
- const [versionMode, setVersionMode] = useState26({
13532
+ const [versionMode, setVersionMode] = useState27({
13237
13533
  isActive: false,
13238
13534
  sourceNodeData: null
13239
13535
  });
13240
- const [questMode, setQuestMode] = useState26({ isActive: false });
13241
- const [hasFocusedInitial, setHasFocusedInitial] = useState26(false);
13242
- const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState26(false);
13243
- const [ancestryMode, setAncestryMode] = useState26({
13536
+ const [questMode, setQuestMode] = useState27({ isActive: false });
13537
+ const [hasFocusedInitial, setHasFocusedInitial] = useState27(false);
13538
+ const [hasOpenedInitialAncestry, setHasOpenedInitialAncestry] = useState27(false);
13539
+ const [ancestryMode, setAncestryMode] = useState27({
13244
13540
  isActive: false,
13245
13541
  tree: null,
13246
13542
  selectedParentId: null,
@@ -13251,37 +13547,38 @@ function XViewScene({
13251
13547
  ancestryDescriptionSections: [],
13252
13548
  isAddingNodes: false
13253
13549
  });
13254
- const [readingMode, setReadingMode] = useState26({
13550
+ const [readingMode, setReadingMode] = useState27({
13255
13551
  isActive: false,
13256
13552
  ancestry: null,
13257
13553
  branchStack: [],
13258
13554
  autoAbstraction: false
13259
13555
  });
13260
- const [formPosition, setFormPosition] = useState26({
13556
+ const [formPosition, setFormPosition] = useState27({
13261
13557
  left: 16,
13262
13558
  top: 16,
13263
13559
  opacity: 0
13264
13560
  });
13265
- const [detailsNode, setDetailsNode] = useState26(null);
13266
- const [detailsLink, setDetailsLink] = useState26(null);
13267
- const [ancestryLinkDetails, setAncestryLinkDetails] = useState26(null);
13268
- const [imageViewer, setImageViewer] = useState26({
13561
+ const [detailsNode, setDetailsNode] = useState27(null);
13562
+ const [detailsLink, setDetailsLink] = useState27(null);
13563
+ const [ancestryLinkDetails, setAncestryLinkDetails] = useState27(null);
13564
+ const [imageViewer, setImageViewer] = useState27({
13269
13565
  visible: false,
13270
13566
  images: [],
13271
13567
  startIndex: 0
13272
13568
  });
13273
- const [editingAncestryRel, setEditingAncestryRel] = useState26({
13569
+ const [editingAncestryRel, setEditingAncestryRel] = useState27({
13274
13570
  visible: false,
13275
13571
  data: null,
13276
13572
  path: null
13277
13573
  });
13278
- const [isImportModalOpen, setIsImportModalOpen] = useState26(false);
13279
- const [importSuccessMessage, setImportSuccessMessage] = useState26("");
13280
- const [invalidTargetError, setInvalidTargetError] = useState26(null);
13281
- const [highlightedNodeId, setHighlightedNodeId] = useState26(null);
13282
- const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState26(false);
13283
- const [ancestryBoardData, setAncestryBoardData] = useState26([]);
13284
- const [isSidebarOpen, setIsSidebarOpen] = useState26(false);
13574
+ const [isImportModalOpen, setIsImportModalOpen] = useState27(false);
13575
+ const [importSuccessMessage, setImportSuccessMessage] = useState27("");
13576
+ const [invalidTargetError, setInvalidTargetError] = useState27(null);
13577
+ const [highlightedNodeId, setHighlightedNodeId] = useState27(null);
13578
+ const [isAncestryBoardOpen, setIsAncestryBoardOpen] = useState27(false);
13579
+ const [ancestryBoardData, setAncestryBoardData] = useState27([]);
13580
+ const [isSidebarOpen, setIsSidebarOpen] = useState27(false);
13581
+ const [isMilestoneManagerOpen, setIsMilestoneManagerOpen] = useState27(false);
13285
13582
  const mountRef = useRef19(null);
13286
13583
  const tooltipRef = useRef19(null);
13287
13584
  const formRef = useRef19(null);
@@ -13959,20 +14256,23 @@ function XViewScene({
13959
14256
  sceneResponse.data.scene.nodes = [];
13960
14257
  sceneResponse.data.scene.links = [];
13961
14258
  }
13962
- sceneDataRef.current = sceneResponse.data.scene;
14259
+ sceneDataRef.current = {
14260
+ ...sceneResponse.data.scene,
14261
+ milestones: sceneResponse.data.scene.milestones || []
14262
+ };
13963
14263
  parentDataRef.current = sceneResponse.data.parent;
13964
14264
  ancestryDataRef.current = sceneResponse.data.ancestry;
13965
14265
  console.log(
13966
14266
  "Console de sceneResponse.data.scene:",
13967
- sceneResponse.data.scene
14267
+ sceneDataRef.current
13968
14268
  );
13969
14269
  console.log(
13970
14270
  "Console de sceneResponse.data.parent:",
13971
- sceneResponse.data.parent
14271
+ parentDataRef.current
13972
14272
  );
13973
14273
  console.log(
13974
14274
  "Console de sceneResponse.data.ancestry:",
13975
- sceneResponse.data.ancestry
14275
+ ancestryDataRef.current
13976
14276
  );
13977
14277
  setIsInitialized(true);
13978
14278
  } else {
@@ -15495,7 +15795,8 @@ function XViewScene({
15495
15795
  links: sceneDataRef2.current.links,
15496
15796
  quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
15497
15797
  quest_links: graphDataRef.current[sceneConfigId2].links,
15498
- quest_counter: currentCounter + 1
15798
+ quest_counter: currentCounter + 1,
15799
+ milestones: sceneDataRef2.current.milestones || []
15499
15800
  };
15500
15801
  try {
15501
15802
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
@@ -17147,6 +17448,52 @@ function XViewScene({
17147
17448
  },
17148
17449
  [actionHandlerContext]
17149
17450
  );
17451
+ const handleUpdateMilestones = useCallback4(
17452
+ async (newMilestones) => {
17453
+ var _a2, _b2, _c2;
17454
+ if (!sceneDataRef.current) return;
17455
+ sceneDataRef.current.milestones = newMilestones;
17456
+ setSceneVersion((v) => v + 1);
17457
+ const isView = ((_a2 = viewParams == null ? void 0 : viewParams.type) == null ? void 0 : _a2.toLowerCase()) === "view";
17458
+ if (!isView || !save_view_data || !sceneSaveUrl) return;
17459
+ const { nodeObjects, allLinks } = stateRef.current;
17460
+ const currentNodes = Object.values(nodeObjects || {}).map((mesh) => {
17461
+ const {
17462
+ _baseEmissiveIntensity,
17463
+ labelObject,
17464
+ labelOffset,
17465
+ timelineIntervalBar,
17466
+ timelineEndLabel,
17467
+ ...serializableNodeData
17468
+ } = mesh.userData;
17469
+ return serializableNodeData;
17470
+ });
17471
+ const currentLinks = (allLinks || []).map((line) => {
17472
+ const { sourceNode, targetNode, ...serializableLinkData } = line.userData;
17473
+ return serializableLinkData;
17474
+ });
17475
+ const sceneFileData = {
17476
+ parent_dbs: sceneDataRef.current.parent_dbs,
17477
+ nodes: currentNodes,
17478
+ links: currentLinks,
17479
+ quest_nodes: ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || sceneDataRef.current.quest_nodes || [],
17480
+ quest_links: ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || sceneDataRef.current.quest_links || [],
17481
+ quest_counter: sceneDataRef.current.quest_counter || 1,
17482
+ milestones: newMilestones
17483
+ };
17484
+ try {
17485
+ await save_view_data(sceneSaveUrl, sceneFileData);
17486
+ } catch (error) {
17487
+ console.error("Erro ao salvar milestones:", error);
17488
+ }
17489
+ },
17490
+ [
17491
+ sceneConfigId,
17492
+ sceneSaveUrl,
17493
+ save_view_data,
17494
+ viewParams == null ? void 0 : viewParams.type
17495
+ ]
17496
+ );
17150
17497
  const handleSaveCurrentView = useCallback4(async () => {
17151
17498
  var _a2, _b2, _c2;
17152
17499
  const { nodeObjects, allLinks } = stateRef.current;
@@ -17181,7 +17528,8 @@ function XViewScene({
17181
17528
  links: currentLinks,
17182
17529
  quest_nodes: isView ? ((_b2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _b2.nodes) || [] : sceneDataRef.current.quest_nodes || [],
17183
17530
  quest_links: isView ? ((_c2 = parentDataRef.current[sceneConfigId]) == null ? void 0 : _c2.links) || [] : sceneDataRef.current.quest_links || [],
17184
- quest_counter: sceneDataRef.current.quest_counter || 1
17531
+ quest_counter: sceneDataRef.current.quest_counter || 1,
17532
+ milestones: sceneDataRef.current.milestones || []
17185
17533
  };
17186
17534
  try {
17187
17535
  await save_view_data(sceneSaveUrl, sceneFileData);
@@ -17438,10 +17786,10 @@ function XViewScene({
17438
17786
  // <-- handleCancelQuest adicionado aqui
17439
17787
  ]);
17440
17788
  if (isLoading || status === "loading" || permissionStatus === "loading") {
17441
- return /* @__PURE__ */ React27.createElement(LoadingScreen, null);
17789
+ return /* @__PURE__ */ React28.createElement(LoadingScreen, null);
17442
17790
  }
17443
17791
  if (permissionStatus === "denied") {
17444
- return /* @__PURE__ */ React27.createElement("div", { className: "flex flex-col items-center justify-center min-h-screen w-full bg-slate-950 text-white" }, /* @__PURE__ */ React27.createElement("div", { className: "bg-slate-900/50 p-8 rounded-2xl border border-slate-800 shadow-2xl text-center max-w-md" }, /* @__PURE__ */ React27.createElement("div", { className: "mb-4 text-red-500" }, /* @__PURE__ */ React27.createElement(
17792
+ 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(
17445
17793
  "svg",
17446
17794
  {
17447
17795
  xmlns: "http://www.w3.org/2000/svg",
@@ -17451,7 +17799,7 @@ function XViewScene({
17451
17799
  stroke: "currentColor",
17452
17800
  className: "w-16 h-16 mx-auto"
17453
17801
  },
17454
- /* @__PURE__ */ React27.createElement(
17802
+ /* @__PURE__ */ React28.createElement(
17455
17803
  "path",
17456
17804
  {
17457
17805
  strokeLinecap: "round",
@@ -17459,13 +17807,13 @@ function XViewScene({
17459
17807
  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"
17460
17808
  }
17461
17809
  )
17462
- )), /* @__PURE__ */ React27.createElement("h2", { className: "text-2xl font-bold mb-2" }, "Acesso Negado"), /* @__PURE__ */ React27.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__ */ React27.createElement(
17810
+ )), /* @__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(
17463
17811
  "button",
17464
17812
  {
17465
17813
  onClick: () => router.push("/dashboard/scenes"),
17466
17814
  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"
17467
17815
  },
17468
- /* @__PURE__ */ React27.createElement(
17816
+ /* @__PURE__ */ React28.createElement(
17469
17817
  "svg",
17470
17818
  {
17471
17819
  xmlns: "http://www.w3.org/2000/svg",
@@ -17475,7 +17823,7 @@ function XViewScene({
17475
17823
  stroke: "currentColor",
17476
17824
  className: "w-5 h-5"
17477
17825
  },
17478
- /* @__PURE__ */ React27.createElement(
17826
+ /* @__PURE__ */ React28.createElement(
17479
17827
  "path",
17480
17828
  {
17481
17829
  strokeLinecap: "round",
@@ -17487,7 +17835,7 @@ function XViewScene({
17487
17835
  "Voltar para Scenes"
17488
17836
  )));
17489
17837
  }
17490
- return /* @__PURE__ */ React27.createElement(
17838
+ return /* @__PURE__ */ React28.createElement(
17491
17839
  "div",
17492
17840
  {
17493
17841
  ref: mountRef,
@@ -17499,7 +17847,7 @@ function XViewScene({
17499
17847
  cursor: stateRef.current.connection.isActive || stateRef.current.relink.isActive || ancestryMode.isActive ? "crosshair" : creationMode.isActive ? "default" : "grab"
17500
17848
  }
17501
17849
  },
17502
- userPermissionRole !== "link_viewer" && /* @__PURE__ */ React27.createElement(
17850
+ userPermissionRole !== "link_viewer" && /* @__PURE__ */ React28.createElement(
17503
17851
  XViewSidebar,
17504
17852
  {
17505
17853
  dbNodes: searchableDbNodes,
@@ -17518,10 +17866,12 @@ function XViewScene({
17518
17866
  isOpen: isSidebarOpen,
17519
17867
  onToggle: setIsSidebarOpen,
17520
17868
  userRole: userPermissionRole,
17521
- viewMembers
17869
+ viewMembers,
17870
+ milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
17871
+ onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
17522
17872
  }
17523
17873
  ),
17524
- creationMode.isActive && /* @__PURE__ */ React27.createElement(
17874
+ creationMode.isActive && /* @__PURE__ */ React28.createElement(
17525
17875
  InSceneCreationForm,
17526
17876
  {
17527
17877
  onSave: (data) => userActionHandlers.handleSaveNode(actionHandlerContext, data),
@@ -17542,8 +17892,8 @@ function XViewScene({
17542
17892
  },
17543
17893
  refEl: formRef,
17544
17894
  existingTypes: existingNodeTypes,
17545
- initialColor: (_c = creationMode.sourceNodeData) == null ? void 0 : _c.color,
17546
- sourceTypes: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.type,
17895
+ initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
17896
+ sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
17547
17897
  onIntensityChange: handleGhostNodeIntensityChange,
17548
17898
  onUploadFile: upload_file_action,
17549
17899
  availableDatasets,
@@ -17553,7 +17903,7 @@ function XViewScene({
17553
17903
  availableAncestries: allAvailableAncestries
17554
17904
  }
17555
17905
  ),
17556
- versionMode.isActive && /* @__PURE__ */ React27.createElement(
17906
+ versionMode.isActive && /* @__PURE__ */ React28.createElement(
17557
17907
  InSceneVersionForm,
17558
17908
  {
17559
17909
  onSave: (data) => userActionHandlers.handleSaveVersionNode(actionHandlerContext, data),
@@ -17572,14 +17922,14 @@ function XViewScene({
17572
17922
  transition: "opacity 200ms ease-out"
17573
17923
  },
17574
17924
  refEl: formRef,
17575
- fixedType: (_e = versionMode.sourceNodeData) == null ? void 0 : _e.type,
17576
- fixedColor: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.color,
17925
+ fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
17926
+ fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
17577
17927
  onUploadFile: upload_file_action,
17578
17928
  availableNodes: allAvailableNodes,
17579
17929
  availableAncestries: allAvailableAncestries
17580
17930
  }
17581
17931
  ),
17582
- questMode.isActive && /* @__PURE__ */ React27.createElement(
17932
+ questMode.isActive && /* @__PURE__ */ React28.createElement(
17583
17933
  InSceneQuestForm,
17584
17934
  {
17585
17935
  onSave: (data) => handleSaveQuestNode(actionHandlerContext, data),
@@ -17601,11 +17951,13 @@ function XViewScene({
17601
17951
  availableNodes: allAvailableNodes,
17602
17952
  availableAncestries: allAvailableAncestries,
17603
17953
  viewName: viewParams == null ? void 0 : viewParams.name,
17604
- questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1,
17605
- viewMembers
17954
+ questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
17955
+ viewMembers,
17956
+ milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
17957
+ onUpdateMilestones: handleUpdateMilestones
17606
17958
  }
17607
17959
  ),
17608
- readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React27.createElement(
17960
+ readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React28.createElement(
17609
17961
  "div",
17610
17962
  {
17611
17963
  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"}`,
@@ -17618,7 +17970,7 @@ function XViewScene({
17618
17970
  maxWidth: "92vw"
17619
17971
  }
17620
17972
  },
17621
- /* @__PURE__ */ React27.createElement(
17973
+ /* @__PURE__ */ React28.createElement(
17622
17974
  "div",
17623
17975
  {
17624
17976
  onPointerDown: (e) => {
@@ -17629,7 +17981,7 @@ function XViewScene({
17629
17981
  title: "Arraste para redimensionar"
17630
17982
  }
17631
17983
  ),
17632
- /* @__PURE__ */ React27.createElement(
17984
+ /* @__PURE__ */ React28.createElement(
17633
17985
  DescriptionReadModePanel,
17634
17986
  {
17635
17987
  key: readingMode.branchStack.length > 0 ? readingMode.branchStack[readingMode.branchStack.length - 1].branchId : readingMode.ancestry.ancestry_id,
@@ -17664,7 +18016,7 @@ function XViewScene({
17664
18016
  }
17665
18017
  )
17666
18018
  ),
17667
- ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React27.createElement(
18019
+ ancestryMode.isActive && ancestryMode.tree && /* @__PURE__ */ React28.createElement(
17668
18020
  CreateAncestryPanel,
17669
18021
  {
17670
18022
  ancestryMode,
@@ -17700,7 +18052,7 @@ function XViewScene({
17700
18052
  onRenderAbstractionTree: (data, targetId) => handleRenderAbstractionTree(data, targetId)
17701
18053
  }
17702
18054
  ),
17703
- editingAncestryRel.visible && /* @__PURE__ */ React27.createElement(
18055
+ editingAncestryRel.visible && /* @__PURE__ */ React28.createElement(
17704
18056
  AncestryRelationshipPanel,
17705
18057
  {
17706
18058
  data: editingAncestryRel.data,
@@ -17714,7 +18066,7 @@ function XViewScene({
17714
18066
  onUploadFile: upload_file_action
17715
18067
  }
17716
18068
  ),
17717
- detailsNode && detailsNode.is_quest && /* @__PURE__ */ React27.createElement(
18069
+ detailsNode && detailsNode.is_quest && /* @__PURE__ */ React28.createElement(
17718
18070
  QuestDetailsPanel,
17719
18071
  {
17720
18072
  node: detailsNode,
@@ -17734,10 +18086,12 @@ function XViewScene({
17734
18086
  userRole: userPermissionRole,
17735
18087
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
17736
18088
  viewMembers,
17737
- currentUser: session == null ? void 0 : session.user
18089
+ currentUser: session == null ? void 0 : session.user,
18090
+ milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
18091
+ onUpdateMilestones: handleUpdateMilestones
17738
18092
  }
17739
18093
  ),
17740
- detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React27.createElement(
18094
+ detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React28.createElement(
17741
18095
  NodeDetailsPanel,
17742
18096
  {
17743
18097
  node: detailsNode,
@@ -17769,7 +18123,7 @@ function XViewScene({
17769
18123
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
17770
18124
  }
17771
18125
  ),
17772
- detailsLink && /* @__PURE__ */ React27.createElement(
18126
+ detailsLink && /* @__PURE__ */ React28.createElement(
17773
18127
  RelationshipDetailsPanel,
17774
18128
  {
17775
18129
  link: detailsLink,
@@ -17783,7 +18137,7 @@ function XViewScene({
17783
18137
  userRole: userPermissionRole
17784
18138
  }
17785
18139
  ),
17786
- ancestryLinkDetails && /* @__PURE__ */ React27.createElement(
18140
+ ancestryLinkDetails && /* @__PURE__ */ React28.createElement(
17787
18141
  AncestryLinkDetailsPanel,
17788
18142
  {
17789
18143
  data: ancestryLinkDetails,
@@ -17794,7 +18148,7 @@ function XViewScene({
17794
18148
  onUploadFile: upload_file_action
17795
18149
  }
17796
18150
  ),
17797
- /* @__PURE__ */ React27.createElement(
18151
+ /* @__PURE__ */ React28.createElement(
17798
18152
  "div",
17799
18153
  {
17800
18154
  ref: tooltipRef,
@@ -17821,7 +18175,7 @@ function XViewScene({
17821
18175
  }
17822
18176
  }
17823
18177
  ),
17824
- /* @__PURE__ */ React27.createElement(
18178
+ /* @__PURE__ */ React28.createElement(
17825
18179
  ContextMenu,
17826
18180
  {
17827
18181
  data: contextMenu,
@@ -17854,7 +18208,7 @@ function XViewScene({
17854
18208
  onFinishQuest: handleFinishQuestQuick
17855
18209
  }
17856
18210
  ),
17857
- /* @__PURE__ */ React27.createElement(
18211
+ /* @__PURE__ */ React28.createElement(
17858
18212
  MultiNodeContextMenu,
17859
18213
  {
17860
18214
  data: multiContextMenu,
@@ -17874,7 +18228,7 @@ function XViewScene({
17874
18228
  )
17875
18229
  }
17876
18230
  ),
17877
- /* @__PURE__ */ React27.createElement(
18231
+ /* @__PURE__ */ React28.createElement(
17878
18232
  RelationshipContextMenu,
17879
18233
  {
17880
18234
  data: relationshipMenu,
@@ -17892,14 +18246,14 @@ function XViewScene({
17892
18246
  onDelete: (data) => userActionHandlers.handleDeleteLink(actionHandlerContext, data)
17893
18247
  }
17894
18248
  ),
17895
- /* @__PURE__ */ React27.createElement(
18249
+ /* @__PURE__ */ React28.createElement(
17896
18250
  ImageViewer,
17897
18251
  {
17898
18252
  data: imageViewer,
17899
18253
  onClose: () => setImageViewer({ ...imageViewer, visible: false })
17900
18254
  }
17901
18255
  ),
17902
- /* @__PURE__ */ React27.createElement(
18256
+ /* @__PURE__ */ React28.createElement(
17903
18257
  AncestryBoard,
17904
18258
  {
17905
18259
  isOpen: isAncestryBoardOpen,
@@ -17912,20 +18266,29 @@ function XViewScene({
17912
18266
  userRole: userPermissionRole
17913
18267
  }
17914
18268
  ),
17915
- /* @__PURE__ */ React27.createElement(
18269
+ /* @__PURE__ */ React28.createElement(
18270
+ MilestoneManager,
18271
+ {
18272
+ isOpen: isMilestoneManagerOpen,
18273
+ onClose: () => setIsMilestoneManagerOpen(false),
18274
+ milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
18275
+ onUpdateMilestones: handleUpdateMilestones
18276
+ }
18277
+ ),
18278
+ /* @__PURE__ */ React28.createElement(
17916
18279
  ImportParentFileModal,
17917
18280
  {
17918
18281
  isOpen: isImportModalOpen,
17919
18282
  onClose: () => setIsImportModalOpen(false),
17920
18283
  onConfirm: handleConfirmImport,
17921
18284
  session,
17922
- parentDbs: ((_h = sceneDataRef.current) == null ? void 0 : _h.parent_dbs) || [],
18285
+ parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
17923
18286
  onFetchAvailableFiles: import_parent_file_modal_get,
17924
18287
  currentViewName: viewParams == null ? void 0 : viewParams.name,
17925
18288
  currentAncestries: ancestryDataRef.current || []
17926
18289
  }
17927
18290
  ),
17928
- invalidTargetError && /* @__PURE__ */ React27.createElement(
18291
+ invalidTargetError && /* @__PURE__ */ React28.createElement(
17929
18292
  "div",
17930
18293
  {
17931
18294
  className: "ui-overlay",
@@ -17950,13 +18313,13 @@ function XViewScene({
17950
18313
  animation: "fadeInDown 0.5s cubic-bezier(0.16, 1, 0.3, 1)"
17951
18314
  }
17952
18315
  },
17953
- /* @__PURE__ */ React27.createElement("style", null, `
18316
+ /* @__PURE__ */ React28.createElement("style", null, `
17954
18317
  @keyframes fadeInDown {
17955
18318
  from { opacity: 0; transform: translate(-50%, -20px); }
17956
18319
  to { opacity: 1; transform: translate(-50%, 0); }
17957
18320
  }
17958
18321
  `),
17959
- /* @__PURE__ */ React27.createElement(
18322
+ /* @__PURE__ */ React28.createElement(
17960
18323
  "svg",
17961
18324
  {
17962
18325
  width: "20",
@@ -17968,12 +18331,12 @@ function XViewScene({
17968
18331
  strokeLinecap: "round",
17969
18332
  strokeLinejoin: "round"
17970
18333
  },
17971
- /* @__PURE__ */ React27.createElement("circle", { cx: "12", cy: "12", r: "10" }),
17972
- /* @__PURE__ */ React27.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
17973
- /* @__PURE__ */ React27.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
18334
+ /* @__PURE__ */ React28.createElement("circle", { cx: "12", cy: "12", r: "10" }),
18335
+ /* @__PURE__ */ React28.createElement("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
18336
+ /* @__PURE__ */ React28.createElement("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
17974
18337
  ),
17975
- /* @__PURE__ */ React27.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
17976
- /* @__PURE__ */ React27.createElement(
18338
+ /* @__PURE__ */ React28.createElement("span", { style: { fontSize: "14px", fontWeight: 500 } }, invalidTargetError),
18339
+ /* @__PURE__ */ React28.createElement(
17977
18340
  "button",
17978
18341
  {
17979
18342
  onClick: () => setInvalidTargetError(null),