@lv-x-software-house/x_view 1.2.6-dev.54 → 1.2.6-dev.56

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 +431 -70
  2. package/dist/index.mjs +431 -70
  3. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -3348,9 +3348,11 @@ function ContextMenu({
3348
3348
  viewMembers,
3349
3349
  currentUser,
3350
3350
  onStartQuest,
3351
- onFinishQuest
3351
+ onFinishQuest,
3352
+ renderedNodeIds = [],
3353
+ renderedLinkIds = []
3352
3354
  }) {
3353
- var _a, _b, _c;
3355
+ var _a, _b;
3354
3356
  const menuRef = useRef(null);
3355
3357
  const [menuPos, setMenuPos] = useState2({ left: 0, top: 0 });
3356
3358
  const [menuView, setMenuView] = useState2("main");
@@ -3411,7 +3413,13 @@ function ContextMenu({
3411
3413
  }
3412
3414
  return -Infinity;
3413
3415
  };
3414
- const visibleLinkIds = new Set(((_b = sceneData == null ? void 0 : sceneData.links) == null ? void 0 : _b.map((link) => String(link.id))) ?? []);
3416
+ const visibleLinkIds = useMemo(() => {
3417
+ var _a2;
3418
+ return /* @__PURE__ */ new Set([
3419
+ ...((_a2 = sceneData == null ? void 0 : sceneData.links) == null ? void 0 : _a2.map((link) => String(link.id))) ?? [],
3420
+ ...renderedLinkIds.map((id) => String(id))
3421
+ ]);
3422
+ }, [sceneData == null ? void 0 : sceneData.links, renderedLinkIds]);
3415
3423
  const allParentLinks = Object.values(parentData).flatMap((fileData) => fileData.links || []);
3416
3424
  const nodeMap = new Map(allParentNodes.map((node) => [String(node.id), node]));
3417
3425
  const connections = allParentLinks.filter((link) => {
@@ -3428,7 +3436,7 @@ function ContextMenu({
3428
3436
  var _a2;
3429
3437
  return c.targetNode && !(((_a2 = c.targetNode.version_node) == null ? void 0 : _a2.is_version) && String(c.targetNode.version_node.parent_node) === String(data.nodeData.id));
3430
3438
  });
3431
- const isCurrentNodeQuest = ((_c = data.nodeData) == null ? void 0 : _c.is_quest) === true;
3439
+ const isCurrentNodeQuest = ((_b = data.nodeData) == null ? void 0 : _b.is_quest) === true;
3432
3440
  const commonConnections = isCurrentNodeQuest ? connections : connections.filter((c) => {
3433
3441
  var _a2;
3434
3442
  return !((_a2 = c.targetNode) == null ? void 0 : _a2.is_quest);
@@ -3553,14 +3561,14 @@ function ContextMenu({
3553
3561
  });
3554
3562
  };
3555
3563
  const renderMainView = () => {
3556
- var _a2, _b2, _c2, _d, _e, _f, _g, _h;
3564
+ var _a2, _b2, _c, _d, _e, _f, _g, _h;
3557
3565
  const hasVersions = computedVersions.length > 0;
3558
3566
  const canCreateVersion = ability.can("create", "Versioning");
3559
3567
  const canReadVersion = ability.can("read", "Versioning");
3560
3568
  const shouldShowVersioningBtn = canCreateVersion || canReadVersion && hasVersions;
3561
3569
  const canStartQuest = isCurrentNodeQuest && (((_a2 = data.nodeData) == null ? void 0 : _a2.status) === "Backlog" || !((_b2 = data.nodeData) == null ? void 0 : _b2.status));
3562
3570
  const isQuestActuallyBlocked = canStartQuest && blockedStatus.isBlocked;
3563
- const canFinishQuest = isCurrentNodeQuest && ((_c2 = data.nodeData) == null ? void 0 : _c2.assignee_id) === (currentUser == null ? void 0 : currentUser.id) && ((_d = data.nodeData) == null ? void 0 : _d.status) !== "Backlog" && ((_e = data.nodeData) == null ? void 0 : _e.status) !== "Done";
3571
+ const canFinishQuest = isCurrentNodeQuest && ((_c = data.nodeData) == null ? void 0 : _c.assignee_id) === (currentUser == null ? void 0 : currentUser.id) && ((_d = data.nodeData) == null ? void 0 : _d.status) !== "Backlog" && ((_e = data.nodeData) == null ? void 0 : _e.status) !== "Done";
3564
3572
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 px-2 pt-1 pb-2" }, /* @__PURE__ */ React.createElement("span", { className: "inline-flex h-2 w-2 rounded-full bg-indigo-400/80 shadow-[0_0_12px_1px_rgba(99,102,241,0.5)]" }), /* @__PURE__ */ React.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "A\xE7\xF5es R\xE1pidas")), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-1" }, canStartQuest && /* @__PURE__ */ React.createElement(
3565
3573
  "button",
3566
3574
  {
@@ -3854,7 +3862,24 @@ var CustomSelect = ({ value, onChange, options, placeholder }) => {
3854
3862
  ${isOpen ? "border-indigo-500/50 bg-slate-800" : "border-white/10 hover:bg-slate-800"}`
3855
3863
  },
3856
3864
  /* @__PURE__ */ React2.createElement("span", { className: "truncate" }, selectedOption ? selectedOption.label : placeholder),
3857
- /* @__PURE__ */ React2.createElement("svg", { className: `w-4 h-4 text-slate-500 transition-transform flex-shrink-0 ${isOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ React2.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }))
3865
+ /* @__PURE__ */ React2.createElement(
3866
+ "svg",
3867
+ {
3868
+ className: `w-4 h-4 text-slate-500 transition-transform flex-shrink-0 ${isOpen ? "rotate-180" : ""}`,
3869
+ fill: "none",
3870
+ viewBox: "0 0 24 24",
3871
+ stroke: "currentColor"
3872
+ },
3873
+ /* @__PURE__ */ React2.createElement(
3874
+ "path",
3875
+ {
3876
+ strokeLinecap: "round",
3877
+ strokeLinejoin: "round",
3878
+ strokeWidth: 2,
3879
+ d: "M19 9l-7 7-7-7"
3880
+ }
3881
+ )
3882
+ )
3858
3883
  ), isOpen && /* @__PURE__ */ React2.createElement("div", { className: "absolute z-50 w-full mt-2 bg-slate-800 border border-white/10 rounded-lg shadow-2xl max-h-56 overflow-y-auto custom-scrollbar animate-in fade-in zoom-in-95 duration-100 py-1" }, options.map((opt, idx) => {
3859
3884
  const isSelected = String(value) === String(opt.value);
3860
3885
  return /* @__PURE__ */ React2.createElement(
@@ -3944,7 +3969,10 @@ function XViewSidebar({
3944
3969
  }, [viewType, viewName]);
3945
3970
  const normalize = (str = "") => {
3946
3971
  if (str === void 0 || str === null) {
3947
- console.warn("XViewSidebar: normalize recebeu valor nulo/indefinido:", str);
3972
+ console.warn(
3973
+ "XViewSidebar: normalize recebeu valor nulo/indefinido:",
3974
+ str
3975
+ );
3948
3976
  }
3949
3977
  return String(str).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[._\-–—:,;!?'"()\[\]{}/\\]/g, " ").replace(/\s+/g, " ").trim();
3950
3978
  };
@@ -3996,7 +4024,9 @@ function XViewSidebar({
3996
4024
  return activeFilters.every((filter) => {
3997
4025
  if (filter.type === "Type") {
3998
4026
  const nodeTypes = Array.isArray(node.type) ? node.type : [node.type];
3999
- return nodeTypes.some((t) => String(t).toLowerCase() === String(filter.value).toLowerCase());
4027
+ return nodeTypes.some(
4028
+ (t) => String(t).toLowerCase() === String(filter.value).toLowerCase()
4029
+ );
4000
4030
  } else if (filter.type === "Color") {
4001
4031
  return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
4002
4032
  } else if (filter.type === "Dataset") {
@@ -4016,7 +4046,14 @@ function XViewSidebar({
4016
4046
  inView.sort(byName);
4017
4047
  const ordered = [...notInView, ...inView];
4018
4048
  return ordered.slice(0, 200);
4019
- }, [dbNodes, query, isNodeInView, viewVersion, activeFilters, filterCategory]);
4049
+ }, [
4050
+ dbNodes,
4051
+ query,
4052
+ isNodeInView,
4053
+ viewVersion,
4054
+ activeFilters,
4055
+ filterCategory
4056
+ ]);
4020
4057
  useEffect2(() => {
4021
4058
  const handleClickOutside = (event) => {
4022
4059
  if (filterMenuRef.current && !filterMenuRef.current.contains(event.target)) {
@@ -4135,7 +4172,24 @@ function XViewSidebar({
4135
4172
  },
4136
4173
  title: "Abrir painel"
4137
4174
  },
4138
- /* @__PURE__ */ React2.createElement("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ React2.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16m-7 6h7" }))
4175
+ /* @__PURE__ */ React2.createElement(
4176
+ "svg",
4177
+ {
4178
+ className: "h-6 w-6",
4179
+ fill: "none",
4180
+ viewBox: "0 0 24 24",
4181
+ stroke: "currentColor"
4182
+ },
4183
+ /* @__PURE__ */ React2.createElement(
4184
+ "path",
4185
+ {
4186
+ strokeLinecap: "round",
4187
+ strokeLinejoin: "round",
4188
+ strokeWidth: 2,
4189
+ d: "M4 6h16M4 12h16m-7 6h7"
4190
+ }
4191
+ )
4192
+ )
4139
4193
  );
4140
4194
  if (!isOpen) return ToggleButton;
4141
4195
  const buttonBaseClass = "w-full px-3 py-2 rounded-md bg-indigo-500/10 hover:bg-indigo-500/20 border border-indigo-500/30 text-sm text-indigo-200 transition-colors flex items-center justify-center gap-2";
@@ -4155,7 +4209,23 @@ function XViewSidebar({
4155
4209
  className: "p-1.5 -ml-1 rounded-md text-slate-400 hover:text-white hover:bg-white/10 md:hidden transition-colors",
4156
4210
  title: "Voltar"
4157
4211
  },
4158
- /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React2.createElement("path", { fillRule: "evenodd", d: "M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z", clipRule: "evenodd" }))
4212
+ /* @__PURE__ */ React2.createElement(
4213
+ "svg",
4214
+ {
4215
+ xmlns: "http://www.w3.org/2000/svg",
4216
+ className: "h-5 w-5",
4217
+ viewBox: "0 0 20 20",
4218
+ fill: "currentColor"
4219
+ },
4220
+ /* @__PURE__ */ React2.createElement(
4221
+ "path",
4222
+ {
4223
+ fillRule: "evenodd",
4224
+ d: "M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z",
4225
+ clipRule: "evenodd"
4226
+ }
4227
+ )
4228
+ )
4159
4229
  ), /* @__PURE__ */ React2.createElement("h3", { className: "text-sm font-semibold text-indigo-100 uppercase tracking-wider" }, activeSubMenu === "quest" ? "Quest Lens" : "Reshape Lens"), /* @__PURE__ */ React2.createElement(
4160
4230
  "button",
4161
4231
  {
@@ -4163,7 +4233,23 @@ function XViewSidebar({
4163
4233
  onClick: () => setActiveSubMenu(null),
4164
4234
  title: "Fechar Sub-menu"
4165
4235
  },
4166
- /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React2.createElement("path", { fillRule: "evenodd", d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z", clipRule: "evenodd" }))
4236
+ /* @__PURE__ */ React2.createElement(
4237
+ "svg",
4238
+ {
4239
+ xmlns: "http://www.w3.org/2000/svg",
4240
+ className: "h-4 w-4",
4241
+ viewBox: "0 0 20 20",
4242
+ fill: "currentColor"
4243
+ },
4244
+ /* @__PURE__ */ React2.createElement(
4245
+ "path",
4246
+ {
4247
+ fillRule: "evenodd",
4248
+ d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
4249
+ clipRule: "evenodd"
4250
+ }
4251
+ )
4252
+ )
4167
4253
  )),
4168
4254
  /* @__PURE__ */ React2.createElement("div", { className: "flex-1 overflow-y-auto p-4 space-y-6" }, activeSubMenu === "quest" && /* @__PURE__ */ React2.createElement("div", { className: "space-y-6 animate-in fade-in slide-in-from-bottom-2 duration-500" }, /* @__PURE__ */ React2.createElement("div", { className: "space-y-2.5" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[11px] uppercase text-slate-400 font-semibold tracking-wider ml-1 mb-1 block" }, "Respons\xE1vel"), /* @__PURE__ */ React2.createElement(
4169
4255
  CustomSelect,
@@ -4172,7 +4258,10 @@ function XViewSidebar({
4172
4258
  onChange: (val) => setQuestFilterAssignee(val),
4173
4259
  options: [
4174
4260
  { value: "", label: "Todos os Respons\xE1veis" },
4175
- ...viewMembers.map((m) => ({ value: m.id, label: m.name || m.email }))
4261
+ ...viewMembers.map((m) => ({
4262
+ value: m.id,
4263
+ label: m.name || m.email
4264
+ }))
4176
4265
  ],
4177
4266
  placeholder: "Selecione um Respons\xE1vel"
4178
4267
  }
@@ -4321,48 +4410,270 @@ function XViewSidebar({
4321
4410
  onClick: () => onToggle(false),
4322
4411
  title: "Fechar Painel"
4323
4412
  },
4324
- /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ React2.createElement(
4325
- "path",
4413
+ /* @__PURE__ */ React2.createElement(
4414
+ "svg",
4326
4415
  {
4327
- fillRule: "evenodd",
4328
- d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
4329
- clipRule: "evenodd"
4330
- }
4331
- ))
4416
+ xmlns: "http://www.w3.org/2000/svg",
4417
+ className: "h-5 w-5",
4418
+ viewBox: "0 0 20 20",
4419
+ fill: "currentColor"
4420
+ },
4421
+ /* @__PURE__ */ React2.createElement(
4422
+ "path",
4423
+ {
4424
+ fillRule: "evenodd",
4425
+ d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
4426
+ clipRule: "evenodd"
4427
+ }
4428
+ )
4429
+ )
4332
4430
  ), /* @__PURE__ */ React2.createElement("div", { className: "absolute top-0 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-indigo-500/20 to-transparent" })),
4333
- /* @__PURE__ */ React2.createElement("div", { className: "flex-1 overflow-y-auto px-5 py-6 space-y-8 custom-scrollbar relative" }, /* @__PURE__ */ React2.createElement("section", null, /* @__PURE__ */ React2.createElement("div", { className: "mb-2" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Pesquisar Node")), /* @__PURE__ */ React2.createElement("div", { className: "relative" }, /* @__PURE__ */ React2.createElement("div", { className: "w-full bg-slate-800/70 p-1.5 flex flex-wrap items-center gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all cursor-text min-h-[42px]", onClick: () => {
4334
- var _a;
4335
- return (_a = inputRef.current) == null ? void 0 : _a.focus();
4336
- } }, activeFilters.map((filter, idx) => /* @__PURE__ */ React2.createElement("span", { key: idx, className: "flex items-center gap-1.5 bg-indigo-500/20 text-indigo-200 border border-indigo-500/30 px-2 py-0.5 rounded text-xs font-medium max-w-full" }, filter.type === "Color" && /* @__PURE__ */ React2.createElement("span", { className: "inline-block w-2.5 h-2.5 rounded-full border border-white/20", style: { backgroundColor: filter.value } }), /* @__PURE__ */ React2.createElement("span", { className: "truncate max-w-[120px]" }, filter.type, ": ", filter.value), /* @__PURE__ */ React2.createElement("button", { type: "button", onClick: (e) => {
4337
- e.stopPropagation();
4338
- handleRemoveFilter(idx);
4339
- }, className: "hover:text-white transition-colors" }, /* @__PURE__ */ React2.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React2.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ React2.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" }))))), /* @__PURE__ */ React2.createElement("input", { ref: inputRef, type: "text", value: query, onChange: (e) => setQuery(e.target.value), onFocus: () => setShowList(true), onBlur: () => setTimeout(() => setShowList(false), 120), onKeyDown: handleKeyDown, placeholder: activeFilters.length === 0 ? "Digite parte do nome..." : "", className: "bg-transparent border-none outline-none flex-1 min-w-[80px] text-sm text-slate-100 placeholder-slate-500", autoComplete: "off" })), showList && /* @__PURE__ */ React2.createElement("ul", { className: "custom-scrollbar absolute mt-1 z-10 w-full max-h-[min(448px,50dvh)] overflow-y-auto rounded-lg bg-slate-900/95 border border-white/10 shadow-xl" }, filteredAndSorted.length > 0 ? filteredAndSorted.map((n) => /* @__PURE__ */ React2.createElement("li", { key: n.id, onMouseDown: () => handlePick(n), className: `px-3 py-2 text-sm flex items-center gap-2 cursor-pointer ${selectedNodeId === n.id ? "bg-indigo-600/60 text-white" : "text-slate-200 hover:bg-indigo-500/30"}`, title: n.name }, /* @__PURE__ */ React2.createElement("span", { className: `inline-block h-2 w-2 rounded-full flex-shrink-0 ${isNodeInView(n.id) ? "bg-emerald-400" : "bg-slate-500"}` }), /* @__PURE__ */ React2.createElement("span", { className: "truncate flex-1" }, n.name))) : /* @__PURE__ */ React2.createElement("li", { className: "px-3 py-2 text-sm text-slate-400" }, "Nenhum resultado"))), /* @__PURE__ */ React2.createElement("div", { className: "mt-3 flex items-center gap-2" }, /* @__PURE__ */ React2.createElement("button", { onClick: handleConfirm, disabled: !selectedNodeId, className: `flex-1 ${selectedNodeId ? buttonBaseClass : buttonDisabledClass}` }, /* @__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: "5 3 19 12 5 21 5 3" })), "Renderizar"), /* @__PURE__ */ React2.createElement("div", { className: "relative", ref: filterMenuRef }, /* @__PURE__ */ React2.createElement("button", { onClick: () => setIsFilterMenuOpen(!isFilterMenuOpen), className: `px-3 py-2 rounded-md text-sm font-medium border transition-colors flex items-center gap-2 ${isFilterMenuOpen || activeFilters.length > 0 ? "bg-indigo-500/30 text-indigo-200 border-indigo-500/40" : "bg-indigo-500/10 text-indigo-200 border-indigo-500/30 hover:bg-indigo-500/20"}` }, /* @__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: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" })), "Filters"), isFilterMenuOpen && /* @__PURE__ */ React2.createElement("div", { className: "absolute right-0 top-full mt-2 w-56 p-3 rounded-lg bg-slate-900 border border-white/10 shadow-xl z-50 flex flex-col gap-3 animate-in fade-in zoom-in-95 duration-100" }, /* @__PURE__ */ React2.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Filtro"), /* @__PURE__ */ React2.createElement("div", { className: "flex bg-slate-800/50 p-1 rounded-md" }, ["Type", "Color", "Dataset"].map((opt) => /* @__PURE__ */ React2.createElement("button", { key: opt, onClick: () => {
4340
- setFilterCategory(opt);
4341
- setFilterValue("");
4342
- }, className: `flex-1 text-xs py-1 rounded transition-colors ${filterCategory === opt ? "bg-indigo-600 text-white" : "text-slate-400 hover:text-slate-200"}` }, opt)))), /* @__PURE__ */ React2.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), /* @__PURE__ */ React2.createElement("input", { type: "text", value: filterValue, onChange: (e) => setFilterValue(e.target.value), className: "w-full bg-slate-800 p-2 text-xs rounded border border-white/10 focus:outline-none focus:border-indigo-500/50 text-white" })), /* @__PURE__ */ React2.createElement("button", { onClick: handleAddFilter, disabled: !filterValue.trim(), className: "w-full py-1.5 bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white text-xs font-medium rounded transition-colors" }, "Aplicar Filtro"))))), /* @__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" }, /* @__PURE__ */ React2.createElement(
4431
+ /* @__PURE__ */ React2.createElement("div", { className: "flex-1 overflow-y-auto px-5 py-6 space-y-8 custom-scrollbar relative" }, /* @__PURE__ */ React2.createElement("section", null, /* @__PURE__ */ React2.createElement("div", { className: "mb-2" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Pesquisar Node")), /* @__PURE__ */ React2.createElement("div", { className: "relative" }, /* @__PURE__ */ React2.createElement(
4432
+ "div",
4433
+ {
4434
+ className: "w-full bg-slate-800/70 p-1.5 flex flex-wrap items-center gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all cursor-text min-h-[42px]",
4435
+ onClick: () => {
4436
+ var _a;
4437
+ return (_a = inputRef.current) == null ? void 0 : _a.focus();
4438
+ }
4439
+ },
4440
+ activeFilters.map((filter, idx) => /* @__PURE__ */ React2.createElement(
4441
+ "span",
4442
+ {
4443
+ key: idx,
4444
+ className: "flex items-center gap-1.5 bg-indigo-500/20 text-indigo-200 border border-indigo-500/30 px-2 py-0.5 rounded text-xs font-medium max-w-full"
4445
+ },
4446
+ filter.type === "Color" && /* @__PURE__ */ React2.createElement(
4447
+ "span",
4448
+ {
4449
+ className: "inline-block w-2.5 h-2.5 rounded-full border border-white/20",
4450
+ style: { backgroundColor: filter.value }
4451
+ }
4452
+ ),
4453
+ /* @__PURE__ */ React2.createElement("span", { className: "truncate max-w-[120px]" }, filter.type, ": ", filter.value),
4454
+ /* @__PURE__ */ React2.createElement(
4455
+ "button",
4456
+ {
4457
+ type: "button",
4458
+ onClick: (e) => {
4459
+ e.stopPropagation();
4460
+ handleRemoveFilter(idx);
4461
+ },
4462
+ className: "hover:text-white transition-colors"
4463
+ },
4464
+ /* @__PURE__ */ React2.createElement(
4465
+ "svg",
4466
+ {
4467
+ xmlns: "http://www.w3.org/2000/svg",
4468
+ width: "12",
4469
+ height: "12",
4470
+ viewBox: "0 0 24 24",
4471
+ fill: "none",
4472
+ stroke: "currentColor",
4473
+ strokeWidth: "3",
4474
+ strokeLinecap: "round",
4475
+ strokeLinejoin: "round"
4476
+ },
4477
+ /* @__PURE__ */ React2.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4478
+ /* @__PURE__ */ React2.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4479
+ )
4480
+ )
4481
+ )),
4482
+ /* @__PURE__ */ React2.createElement(
4483
+ "input",
4484
+ {
4485
+ ref: inputRef,
4486
+ type: "text",
4487
+ value: query,
4488
+ onChange: (e) => setQuery(e.target.value),
4489
+ onFocus: () => setShowList(true),
4490
+ onBlur: () => setTimeout(() => setShowList(false), 120),
4491
+ onKeyDown: handleKeyDown,
4492
+ placeholder: activeFilters.length === 0 ? "Digite parte do nome..." : "",
4493
+ className: "bg-transparent border-none outline-none flex-1 min-w-[80px] text-sm text-slate-100 placeholder-slate-500",
4494
+ autoComplete: "off"
4495
+ }
4496
+ )
4497
+ ), showList && /* @__PURE__ */ React2.createElement("ul", { className: "custom-scrollbar absolute mt-1 z-10 w-full max-h-[min(448px,50dvh)] overflow-y-auto rounded-lg bg-slate-900/95 border border-white/10 shadow-xl" }, filteredAndSorted.length > 0 ? filteredAndSorted.map((n) => /* @__PURE__ */ React2.createElement(
4498
+ "li",
4499
+ {
4500
+ key: n.id,
4501
+ onMouseDown: () => handlePick(n),
4502
+ className: `px-3 py-2 text-sm flex items-center gap-2 cursor-pointer ${selectedNodeId === n.id ? "bg-indigo-600/60 text-white" : "text-slate-200 hover:bg-indigo-500/30"}`,
4503
+ title: n.name
4504
+ },
4505
+ /* @__PURE__ */ React2.createElement(
4506
+ "span",
4507
+ {
4508
+ className: `inline-block h-2 w-2 rounded-full flex-shrink-0 ${isNodeInView(n.id) ? "bg-emerald-400" : "bg-slate-500"}`
4509
+ }
4510
+ ),
4511
+ /* @__PURE__ */ React2.createElement("span", { className: "truncate flex-1" }, n.name)
4512
+ )) : /* @__PURE__ */ React2.createElement("li", { className: "px-3 py-2 text-sm text-slate-400" }, "Nenhum resultado"))), /* @__PURE__ */ React2.createElement("div", { className: "mt-3 flex items-center gap-2" }, /* @__PURE__ */ React2.createElement(
4513
+ "button",
4514
+ {
4515
+ onClick: handleConfirm,
4516
+ disabled: !selectedNodeId,
4517
+ className: `flex-1 ${selectedNodeId ? buttonBaseClass : buttonDisabledClass}`
4518
+ },
4519
+ /* @__PURE__ */ React2.createElement(
4520
+ "svg",
4521
+ {
4522
+ xmlns: "http://www.w3.org/2000/svg",
4523
+ width: "16",
4524
+ height: "16",
4525
+ viewBox: "0 0 24 24",
4526
+ fill: "none",
4527
+ stroke: "currentColor",
4528
+ strokeWidth: "2",
4529
+ strokeLinecap: "round",
4530
+ strokeLinejoin: "round"
4531
+ },
4532
+ /* @__PURE__ */ React2.createElement("polygon", { points: "5 3 19 12 5 21 5 3" })
4533
+ ),
4534
+ "Renderizar"
4535
+ ), /* @__PURE__ */ React2.createElement("div", { className: "relative", ref: filterMenuRef }, /* @__PURE__ */ React2.createElement(
4536
+ "button",
4537
+ {
4538
+ onClick: () => setIsFilterMenuOpen(!isFilterMenuOpen),
4539
+ className: `px-3 py-2 rounded-md text-sm font-medium border transition-colors flex items-center gap-2 ${isFilterMenuOpen || activeFilters.length > 0 ? "bg-indigo-500/30 text-indigo-200 border-indigo-500/40" : "bg-indigo-500/10 text-indigo-200 border-indigo-500/30 hover:bg-indigo-500/20"}`
4540
+ },
4541
+ /* @__PURE__ */ React2.createElement(
4542
+ "svg",
4543
+ {
4544
+ xmlns: "http://www.w3.org/2000/svg",
4545
+ width: "16",
4546
+ height: "16",
4547
+ viewBox: "0 0 24 24",
4548
+ fill: "none",
4549
+ stroke: "currentColor",
4550
+ strokeWidth: "2",
4551
+ strokeLinecap: "round",
4552
+ strokeLinejoin: "round"
4553
+ },
4554
+ /* @__PURE__ */ React2.createElement("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" })
4555
+ ),
4556
+ "Filters"
4557
+ ), isFilterMenuOpen && /* @__PURE__ */ React2.createElement("div", { className: "absolute right-0 top-full mt-2 w-56 p-3 rounded-lg bg-slate-900 border border-white/10 shadow-xl z-50 flex flex-col gap-3 animate-in fade-in zoom-in-95 duration-100" }, /* @__PURE__ */ React2.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Filtro"), /* @__PURE__ */ React2.createElement("div", { className: "flex bg-slate-800/50 p-1 rounded-md" }, ["Type", "Color", "Dataset"].map((opt) => /* @__PURE__ */ React2.createElement(
4558
+ "button",
4559
+ {
4560
+ key: opt,
4561
+ onClick: () => {
4562
+ setFilterCategory(opt);
4563
+ setFilterValue("");
4564
+ },
4565
+ className: `flex-1 text-xs py-1 rounded transition-colors ${filterCategory === opt ? "bg-indigo-600 text-white" : "text-slate-400 hover:text-slate-200"}`
4566
+ },
4567
+ opt
4568
+ )))), /* @__PURE__ */ React2.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), /* @__PURE__ */ React2.createElement(
4569
+ "input",
4570
+ {
4571
+ type: "text",
4572
+ value: filterValue,
4573
+ onChange: (e) => setFilterValue(e.target.value),
4574
+ className: "w-full bg-slate-800 p-2 text-xs rounded border border-white/10 focus:outline-none focus:border-indigo-500/50 text-white"
4575
+ }
4576
+ )), /* @__PURE__ */ React2.createElement(
4577
+ "button",
4578
+ {
4579
+ onClick: handleAddFilter,
4580
+ disabled: !filterValue.trim(),
4581
+ className: "w-full py-1.5 bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white text-xs font-medium rounded transition-colors"
4582
+ },
4583
+ "Aplicar Filtro"
4584
+ ))))), /* @__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" }, /* @__PURE__ */ React2.createElement(
4343
4585
  "button",
4344
4586
  {
4345
4587
  onClick: () => setActiveSubMenu(activeSubMenu === "quest" ? null : "quest"),
4346
4588
  className: `${buttonBaseClass} lens-button ${activeSubMenu === "quest" || questFilterAssignee || questFilterStatus || questFilterMilestone ? "bg-indigo-500/30 border-indigo-400" : ""}`
4347
4589
  },
4348
- /* @__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: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }), /* @__PURE__ */ React2.createElement("path", { d: "M9 12l2 2 4-4" })),
4349
- "Quest Lens"
4590
+ /* @__PURE__ */ React2.createElement(
4591
+ "svg",
4592
+ {
4593
+ xmlns: "http://www.w3.org/2000/svg",
4594
+ width: "16",
4595
+ height: "16",
4596
+ viewBox: "0 0 24 24",
4597
+ fill: "none",
4598
+ stroke: "currentColor",
4599
+ strokeWidth: "2",
4600
+ strokeLinecap: "round",
4601
+ strokeLinejoin: "round"
4602
+ },
4603
+ /* @__PURE__ */ React2.createElement("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }),
4604
+ /* @__PURE__ */ React2.createElement("path", { d: "M9 12l2 2 4-4" })
4605
+ ),
4606
+ "Quests"
4350
4607
  )), /* @__PURE__ */ React2.createElement("div", { className: "relative" }, /* @__PURE__ */ React2.createElement(
4351
4608
  "button",
4352
4609
  {
4353
- onClick: () => setActiveSubMenu(activeSubMenu === "reshape" ? null : "reshape"),
4610
+ onClick: () => setActiveSubMenu(
4611
+ activeSubMenu === "reshape" ? null : "reshape"
4612
+ ),
4354
4613
  className: `${buttonBaseClass} lens-button ${activeSubMenu === "reshape" ? "bg-indigo-500/30 border-indigo-400" : ""}`
4355
4614
  },
4356
- /* @__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" })),
4357
- "Reshape Lens"
4358
- )), /* @__PURE__ */ React2.createElement("button", { onClick: onActivateTimeline, className: buttonBaseClass }, /* @__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" })), "Timeline"), /* @__PURE__ */ React2.createElement("button", { onClick: onOpenBoards, className: buttonBaseClass }, /* @__PURE__ */ React2.createElement(FiLayers, { size: 16 }), "Boards")), /* @__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("button", { onClick: onOpenMilestoneManager, className: buttonBaseClass }, "Gerenciar Milestones"))),
4359
- /* @__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("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o"), ability.can("update", "Scene") && /* @__PURE__ */ React2.createElement("button", { onClick: handleSaveClick, disabled: isSaving, className: isSaving ? buttonDisabledClass : buttonBaseClass }, isSaving ? "Salvando..." : "Atualizar cen\xE1rio inicial"), /* @__PURE__ */ React2.createElement("button", { onClick: onNavigateBack, className: buttonBaseClass }, "Voltar \xE0 p\xE1gina de cen\xE1rios"))),
4615
+ /* @__PURE__ */ React2.createElement(
4616
+ "svg",
4617
+ {
4618
+ xmlns: "http://www.w3.org/2000/svg",
4619
+ width: "16",
4620
+ height: "16",
4621
+ viewBox: "0 0 24 24",
4622
+ fill: "none",
4623
+ stroke: "currentColor",
4624
+ strokeWidth: "2",
4625
+ strokeLinecap: "round",
4626
+ strokeLinejoin: "round"
4627
+ },
4628
+ /* @__PURE__ */ React2.createElement("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
4629
+ /* @__PURE__ */ React2.createElement("polyline", { points: "2 17 12 22 22 17" }),
4630
+ /* @__PURE__ */ React2.createElement("polyline", { points: "2 12 12 17 22 12" })
4631
+ ),
4632
+ "Reshape"
4633
+ )), /* @__PURE__ */ React2.createElement("button", { onClick: onActivateTimeline, className: buttonBaseClass }, /* @__PURE__ */ React2.createElement(
4634
+ "svg",
4635
+ {
4636
+ xmlns: "http://www.w3.org/2000/svg",
4637
+ width: "16",
4638
+ height: "16",
4639
+ viewBox: "0 0 24 24",
4640
+ fill: "none",
4641
+ stroke: "currentColor",
4642
+ strokeWidth: "2",
4643
+ strokeLinecap: "round",
4644
+ strokeLinejoin: "round"
4645
+ },
4646
+ /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "12", r: "10" }),
4647
+ /* @__PURE__ */ React2.createElement("polyline", { points: "12 6 12 12 16 14" })
4648
+ ), "Timeline"), /* @__PURE__ */ React2.createElement("button", { onClick: onOpenBoards, className: buttonBaseClass }, /* @__PURE__ */ React2.createElement(FiLayers, { size: 16 }), "Boards")), /* @__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(
4649
+ "button",
4650
+ {
4651
+ onClick: onOpenMilestoneManager,
4652
+ className: buttonBaseClass
4653
+ },
4654
+ "Gerenciar Milestones"
4655
+ ))),
4656
+ /* @__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("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o"), ability.can("update", "Scene") && /* @__PURE__ */ React2.createElement(
4657
+ "button",
4658
+ {
4659
+ onClick: handleSaveClick,
4660
+ disabled: isSaving,
4661
+ className: isSaving ? buttonDisabledClass : buttonBaseClass
4662
+ },
4663
+ isSaving ? "Salvando..." : "Atualizar cen\xE1rio inicial"
4664
+ ), /* @__PURE__ */ React2.createElement("button", { onClick: onNavigateBack, className: buttonBaseClass }, "Voltar ao Dashboard"))),
4360
4665
  contextLabel && /* @__PURE__ */ React2.createElement("div", { className: "px-4 py-3 border-t border-white/10 bg-slate-900/50 truncate text-sm font-medium text-slate-200" }, contextLabel),
4361
4666
  /* @__PURE__ */ React2.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" })
4362
4667
  ),
4363
- /* @__PURE__ */ React2.createElement("div", { className: `h-full pointer-events-auto transition-all duration-500 ease-out absolute md:relative left-0 top-0 z-30 md:z-10 flex-shrink-0 overflow-hidden
4668
+ /* @__PURE__ */ React2.createElement(
4669
+ "div",
4670
+ {
4671
+ className: `h-full pointer-events-auto transition-all duration-500 ease-out absolute md:relative left-0 top-0 z-30 md:z-10 flex-shrink-0 overflow-hidden
4364
4672
  ${activeSubMenu ? "translate-x-0 md:translate-x-0 w-[100vw] md:w-[280px] opacity-100" : "-translate-x-full md:translate-x-0 w-[100vw] md:w-0 opacity-0 md:opacity-100"}
4365
- ` }, renderAnnexedPanel())
4673
+ `
4674
+ },
4675
+ renderAnnexedPanel()
4676
+ )
4366
4677
  );
4367
4678
  }
4368
4679
 
@@ -18214,6 +18525,20 @@ function XViewScene({
18214
18525
  masterAncestryList.push(ancestryObjectToSave);
18215
18526
  }
18216
18527
  const result = await save_view_data(finalSaveUrl, masterAncestryList);
18528
+ if (result.success && isExternalSave && isEditMode && currentAncestryId && ancestry_save_url && get_ancestry_file) {
18529
+ try {
18530
+ const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
18531
+ if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
18532
+ const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(currentAncestryId));
18533
+ if (hasInViewDb) {
18534
+ const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(currentAncestryId));
18535
+ await save_view_data(ancestry_save_url, updatedViewDb);
18536
+ }
18537
+ }
18538
+ } catch (fallbackErr) {
18539
+ console.error("Falha ao limpar c\xF3pia residual na edi\xE7\xE3o:", fallbackErr);
18540
+ }
18541
+ }
18217
18542
  if (result.success) {
18218
18543
  const localList = [...ancestryDataRef.current || []];
18219
18544
  const localIndex = localList.findIndex(
@@ -18316,45 +18641,76 @@ function XViewScene({
18316
18641
  return;
18317
18642
  }
18318
18643
  const finalSaveUrl = `x_view_ancestry/${sourceOwnerId}/${sourceFileId}`;
18319
- const updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18320
- (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18321
- );
18644
+ const isExternalSave = sourceFileId !== sceneConfigId;
18645
+ let success = false;
18646
+ let deletionError = null;
18322
18647
  try {
18323
- const result = await save_view_data(
18324
- finalSaveUrl,
18325
- updatedAncestriesForFile
18326
- );
18327
- if (result.success) {
18328
- ancestryDataRef.current = (ancestryDataRef.current || []).filter(
18329
- (ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
18330
- );
18331
- const { renderedAncestries, ancestryGroup } = stateRef.current;
18332
- const renderIndex = renderedAncestries.findIndex(
18333
- (a) => String(a.id) === String(ancestryIdToDelete)
18334
- );
18335
- if (renderIndex !== -1) {
18336
- const toRemove = renderedAncestries[renderIndex];
18337
- toRemove.lines.forEach((line) => {
18338
- ancestryGroup.remove(line);
18339
- if (line.geometry) line.geometry.dispose();
18340
- if (line.material) line.material.dispose();
18341
- });
18342
- renderedAncestries.splice(renderIndex, 1);
18343
- stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18344
- (a) => a.lines
18648
+ let updatedAncestriesForFile;
18649
+ if (get_ancestry_file && isExternalSave) {
18650
+ const remoteResponse = await get_ancestry_file(sourceFileId, sourceOwnerId);
18651
+ if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
18652
+ updatedAncestriesForFile = remoteResponse.data.filter(
18653
+ (anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete)
18654
+ );
18655
+ } else {
18656
+ updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18657
+ (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18345
18658
  );
18346
18659
  }
18347
- setSceneVersion((v) => v + 1);
18348
18660
  } else {
18349
- throw new Error(
18350
- result.error || "Ocorreu um erro desconhecido ao excluir."
18661
+ updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18662
+ (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18351
18663
  );
18352
18664
  }
18665
+ const result = await save_view_data(finalSaveUrl, updatedAncestriesForFile);
18666
+ if (result.success) {
18667
+ success = true;
18668
+ } else {
18669
+ throw new Error(result.error || "Ocorreu um erro desconhecido ao excluir.");
18670
+ }
18353
18671
  } catch (error) {
18354
- console.error("Falha ao excluir a ancestralidade:", error);
18355
- alert(`Erro ao excluir a ancestralidade: ${error.message}`);
18672
+ deletionError = error;
18673
+ }
18674
+ if (ancestry_save_url && isExternalSave && get_ancestry_file) {
18675
+ try {
18676
+ const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
18677
+ if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
18678
+ const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(ancestryIdToDelete));
18679
+ if (hasInViewDb) {
18680
+ const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete));
18681
+ const fallbackResult = await save_view_data(ancestry_save_url, updatedViewDb);
18682
+ if (fallbackResult.success) success = true;
18683
+ }
18684
+ }
18685
+ } catch (fallbackErr) {
18686
+ console.error("Falha ao limpar c\xF3pia residual da View DB:", fallbackErr);
18687
+ }
18688
+ }
18689
+ if (!success && deletionError) {
18690
+ console.error("Falha ao excluir a ancestralidade:", deletionError);
18691
+ alert(`Erro ao excluir a ancestralidade: ${deletionError.message}`);
18356
18692
  return;
18357
18693
  }
18694
+ ancestryDataRef.current = (ancestryDataRef.current || []).filter(
18695
+ (ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
18696
+ );
18697
+ const { renderedAncestries, ancestryGroup } = stateRef.current;
18698
+ const renderIndex = renderedAncestries.findIndex(
18699
+ (a) => String(a.id) === String(ancestryIdToDelete)
18700
+ );
18701
+ if (renderIndex !== -1) {
18702
+ const toRemove = renderedAncestries[renderIndex];
18703
+ toRemove.lines.forEach((line) => {
18704
+ ancestryGroup.remove(line);
18705
+ if (line.geometry) line.geometry.dispose();
18706
+ if (line.material) line.material.dispose();
18707
+ });
18708
+ renderedAncestries.splice(renderIndex, 1);
18709
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18710
+ (a) => a.lines
18711
+ );
18712
+ }
18713
+ setSceneVersion((v) => v + 1);
18358
18714
  setAncestryMode({
18359
18715
  isActive: false,
18360
18716
  tree: null,
@@ -19193,6 +19549,11 @@ function XViewScene({
19193
19549
  parentData: parentDataRef.current,
19194
19550
  sceneData: sceneDataRef.current,
19195
19551
  ancestryData: ancestryDataRef.current,
19552
+ renderedNodeIds: Object.keys(stateRef.current.nodeObjects || {}),
19553
+ renderedLinkIds: (stateRef.current.allLinks || []).map((l) => {
19554
+ var _a2;
19555
+ return String((_a2 = l.userData) == null ? void 0 : _a2.id);
19556
+ }).filter((id) => id !== "undefined"),
19196
19557
  onClose: () => setContextMenu(
19197
19558
  (prev) => prev.visible ? { ...prev, visible: false } : prev
19198
19559
  ),