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

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 +412 -64
  2. package/dist/index.mjs +412 -64
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3893,7 +3893,24 @@ var CustomSelect = ({ value, onChange, options, placeholder }) => {
3893
3893
  ${isOpen ? "border-indigo-500/50 bg-slate-800" : "border-white/10 hover:bg-slate-800"}`
3894
3894
  },
3895
3895
  /* @__PURE__ */ import_react3.default.createElement("span", { className: "truncate" }, selectedOption ? selectedOption.label : placeholder),
3896
- /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }))
3896
+ /* @__PURE__ */ import_react3.default.createElement(
3897
+ "svg",
3898
+ {
3899
+ className: `w-4 h-4 text-slate-500 transition-transform flex-shrink-0 ${isOpen ? "rotate-180" : ""}`,
3900
+ fill: "none",
3901
+ viewBox: "0 0 24 24",
3902
+ stroke: "currentColor"
3903
+ },
3904
+ /* @__PURE__ */ import_react3.default.createElement(
3905
+ "path",
3906
+ {
3907
+ strokeLinecap: "round",
3908
+ strokeLinejoin: "round",
3909
+ strokeWidth: 2,
3910
+ d: "M19 9l-7 7-7-7"
3911
+ }
3912
+ )
3913
+ )
3897
3914
  ), isOpen && /* @__PURE__ */ import_react3.default.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) => {
3898
3915
  const isSelected = String(value) === String(opt.value);
3899
3916
  return /* @__PURE__ */ import_react3.default.createElement(
@@ -3983,7 +4000,10 @@ function XViewSidebar({
3983
4000
  }, [viewType, viewName]);
3984
4001
  const normalize = (str = "") => {
3985
4002
  if (str === void 0 || str === null) {
3986
- console.warn("XViewSidebar: normalize recebeu valor nulo/indefinido:", str);
4003
+ console.warn(
4004
+ "XViewSidebar: normalize recebeu valor nulo/indefinido:",
4005
+ str
4006
+ );
3987
4007
  }
3988
4008
  return String(str).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[._\-–—:,;!?'"()\[\]{}/\\]/g, " ").replace(/\s+/g, " ").trim();
3989
4009
  };
@@ -4035,7 +4055,9 @@ function XViewSidebar({
4035
4055
  return activeFilters.every((filter) => {
4036
4056
  if (filter.type === "Type") {
4037
4057
  const nodeTypes = Array.isArray(node.type) ? node.type : [node.type];
4038
- return nodeTypes.some((t) => String(t).toLowerCase() === String(filter.value).toLowerCase());
4058
+ return nodeTypes.some(
4059
+ (t) => String(t).toLowerCase() === String(filter.value).toLowerCase()
4060
+ );
4039
4061
  } else if (filter.type === "Color") {
4040
4062
  return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
4041
4063
  } else if (filter.type === "Dataset") {
@@ -4055,7 +4077,14 @@ function XViewSidebar({
4055
4077
  inView.sort(byName);
4056
4078
  const ordered = [...notInView, ...inView];
4057
4079
  return ordered.slice(0, 200);
4058
- }, [dbNodes, query, isNodeInView, viewVersion, activeFilters, filterCategory]);
4080
+ }, [
4081
+ dbNodes,
4082
+ query,
4083
+ isNodeInView,
4084
+ viewVersion,
4085
+ activeFilters,
4086
+ filterCategory
4087
+ ]);
4059
4088
  (0, import_react3.useEffect)(() => {
4060
4089
  const handleClickOutside = (event) => {
4061
4090
  if (filterMenuRef.current && !filterMenuRef.current.contains(event.target)) {
@@ -4174,7 +4203,24 @@ function XViewSidebar({
4174
4203
  },
4175
4204
  title: "Abrir painel"
4176
4205
  },
4177
- /* @__PURE__ */ import_react3.default.createElement("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ import_react3.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16m-7 6h7" }))
4206
+ /* @__PURE__ */ import_react3.default.createElement(
4207
+ "svg",
4208
+ {
4209
+ className: "h-6 w-6",
4210
+ fill: "none",
4211
+ viewBox: "0 0 24 24",
4212
+ stroke: "currentColor"
4213
+ },
4214
+ /* @__PURE__ */ import_react3.default.createElement(
4215
+ "path",
4216
+ {
4217
+ strokeLinecap: "round",
4218
+ strokeLinejoin: "round",
4219
+ strokeWidth: 2,
4220
+ d: "M4 6h16M4 12h16m-7 6h7"
4221
+ }
4222
+ )
4223
+ )
4178
4224
  );
4179
4225
  if (!isOpen) return ToggleButton;
4180
4226
  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";
@@ -4194,7 +4240,23 @@ function XViewSidebar({
4194
4240
  className: "p-1.5 -ml-1 rounded-md text-slate-400 hover:text-white hover:bg-white/10 md:hidden transition-colors",
4195
4241
  title: "Voltar"
4196
4242
  },
4197
- /* @__PURE__ */ import_react3.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ import_react3.default.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" }))
4243
+ /* @__PURE__ */ import_react3.default.createElement(
4244
+ "svg",
4245
+ {
4246
+ xmlns: "http://www.w3.org/2000/svg",
4247
+ className: "h-5 w-5",
4248
+ viewBox: "0 0 20 20",
4249
+ fill: "currentColor"
4250
+ },
4251
+ /* @__PURE__ */ import_react3.default.createElement(
4252
+ "path",
4253
+ {
4254
+ fillRule: "evenodd",
4255
+ 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",
4256
+ clipRule: "evenodd"
4257
+ }
4258
+ )
4259
+ )
4198
4260
  ), /* @__PURE__ */ import_react3.default.createElement("h3", { className: "text-sm font-semibold text-indigo-100 uppercase tracking-wider" }, activeSubMenu === "quest" ? "Quest Lens" : "Reshape Lens"), /* @__PURE__ */ import_react3.default.createElement(
4199
4261
  "button",
4200
4262
  {
@@ -4202,7 +4264,23 @@ function XViewSidebar({
4202
4264
  onClick: () => setActiveSubMenu(null),
4203
4265
  title: "Fechar Sub-menu"
4204
4266
  },
4205
- /* @__PURE__ */ import_react3.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ import_react3.default.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" }))
4267
+ /* @__PURE__ */ import_react3.default.createElement(
4268
+ "svg",
4269
+ {
4270
+ xmlns: "http://www.w3.org/2000/svg",
4271
+ className: "h-4 w-4",
4272
+ viewBox: "0 0 20 20",
4273
+ fill: "currentColor"
4274
+ },
4275
+ /* @__PURE__ */ import_react3.default.createElement(
4276
+ "path",
4277
+ {
4278
+ fillRule: "evenodd",
4279
+ 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",
4280
+ clipRule: "evenodd"
4281
+ }
4282
+ )
4283
+ )
4206
4284
  )),
4207
4285
  /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex-1 overflow-y-auto p-4 space-y-6" }, activeSubMenu === "quest" && /* @__PURE__ */ import_react3.default.createElement("div", { className: "space-y-6 animate-in fade-in slide-in-from-bottom-2 duration-500" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "space-y-2.5" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "text-[11px] uppercase text-slate-400 font-semibold tracking-wider ml-1 mb-1 block" }, "Respons\xE1vel"), /* @__PURE__ */ import_react3.default.createElement(
4208
4286
  CustomSelect,
@@ -4211,7 +4289,10 @@ function XViewSidebar({
4211
4289
  onChange: (val) => setQuestFilterAssignee(val),
4212
4290
  options: [
4213
4291
  { value: "", label: "Todos os Respons\xE1veis" },
4214
- ...viewMembers.map((m) => ({ value: m.id, label: m.name || m.email }))
4292
+ ...viewMembers.map((m) => ({
4293
+ value: m.id,
4294
+ label: m.name || m.email
4295
+ }))
4215
4296
  ],
4216
4297
  placeholder: "Selecione um Respons\xE1vel"
4217
4298
  }
@@ -4360,48 +4441,270 @@ function XViewSidebar({
4360
4441
  onClick: () => onToggle(false),
4361
4442
  title: "Fechar Painel"
4362
4443
  },
4363
- /* @__PURE__ */ import_react3.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor" }, /* @__PURE__ */ import_react3.default.createElement(
4364
- "path",
4444
+ /* @__PURE__ */ import_react3.default.createElement(
4445
+ "svg",
4365
4446
  {
4366
- fillRule: "evenodd",
4367
- 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",
4368
- clipRule: "evenodd"
4369
- }
4370
- ))
4447
+ xmlns: "http://www.w3.org/2000/svg",
4448
+ className: "h-5 w-5",
4449
+ viewBox: "0 0 20 20",
4450
+ fill: "currentColor"
4451
+ },
4452
+ /* @__PURE__ */ import_react3.default.createElement(
4453
+ "path",
4454
+ {
4455
+ fillRule: "evenodd",
4456
+ 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",
4457
+ clipRule: "evenodd"
4458
+ }
4459
+ )
4460
+ )
4371
4461
  ), /* @__PURE__ */ import_react3.default.createElement("div", { className: "absolute top-0 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-indigo-500/20 to-transparent" })),
4372
- /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex-1 overflow-y-auto px-5 py-6 space-y-8 custom-scrollbar relative" }, /* @__PURE__ */ import_react3.default.createElement("section", null, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mb-2" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Pesquisar Node")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react3.default.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: () => {
4373
- var _a;
4374
- return (_a = inputRef.current) == null ? void 0 : _a.focus();
4375
- } }, activeFilters.map((filter, idx) => /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("span", { className: "inline-block w-2.5 h-2.5 rounded-full border border-white/20", style: { backgroundColor: filter.value } }), /* @__PURE__ */ import_react3.default.createElement("span", { className: "truncate max-w-[120px]" }, filter.type, ": ", filter.value), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", onClick: (e) => {
4376
- e.stopPropagation();
4377
- handleRemoveFilter(idx);
4378
- }, className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ import_react3.default.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" }))))), /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.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__ */ import_react3.default.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__ */ import_react3.default.createElement("span", { className: `inline-block h-2 w-2 rounded-full flex-shrink-0 ${isNodeInView(n.id) ? "bg-emerald-400" : "bg-slate-500"}` }), /* @__PURE__ */ import_react3.default.createElement("span", { className: "truncate flex-1" }, n.name))) : /* @__PURE__ */ import_react3.default.createElement("li", { className: "px-3 py-2 text-sm text-slate-400" }, "Nenhum resultado"))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mt-3 flex items-center gap-2" }, /* @__PURE__ */ import_react3.default.createElement("button", { onClick: handleConfirm, disabled: !selectedNodeId, className: `flex-1 ${selectedNodeId ? buttonBaseClass : buttonDisabledClass}` }, /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("polygon", { points: "5 3 19 12 5 21 5 3" })), "Renderizar"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative", ref: filterMenuRef }, /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.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__ */ import_react3.default.createElement("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" })), "Filters"), isFilterMenuOpen && /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Filtro"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex bg-slate-800/50 p-1 rounded-md" }, ["Type", "Color", "Dataset"].map((opt) => /* @__PURE__ */ import_react3.default.createElement("button", { key: opt, onClick: () => {
4379
- setFilterCategory(opt);
4380
- setFilterValue("");
4381
- }, 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__ */ import_react3.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.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__ */ import_react3.default.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Lentes"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react3.default.createElement(
4462
+ /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex-1 overflow-y-auto px-5 py-6 space-y-8 custom-scrollbar relative" }, /* @__PURE__ */ import_react3.default.createElement("section", null, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mb-2" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Pesquisar Node")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react3.default.createElement(
4463
+ "div",
4464
+ {
4465
+ 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]",
4466
+ onClick: () => {
4467
+ var _a;
4468
+ return (_a = inputRef.current) == null ? void 0 : _a.focus();
4469
+ }
4470
+ },
4471
+ activeFilters.map((filter, idx) => /* @__PURE__ */ import_react3.default.createElement(
4472
+ "span",
4473
+ {
4474
+ key: idx,
4475
+ 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"
4476
+ },
4477
+ filter.type === "Color" && /* @__PURE__ */ import_react3.default.createElement(
4478
+ "span",
4479
+ {
4480
+ className: "inline-block w-2.5 h-2.5 rounded-full border border-white/20",
4481
+ style: { backgroundColor: filter.value }
4482
+ }
4483
+ ),
4484
+ /* @__PURE__ */ import_react3.default.createElement("span", { className: "truncate max-w-[120px]" }, filter.type, ": ", filter.value),
4485
+ /* @__PURE__ */ import_react3.default.createElement(
4486
+ "button",
4487
+ {
4488
+ type: "button",
4489
+ onClick: (e) => {
4490
+ e.stopPropagation();
4491
+ handleRemoveFilter(idx);
4492
+ },
4493
+ className: "hover:text-white transition-colors"
4494
+ },
4495
+ /* @__PURE__ */ import_react3.default.createElement(
4496
+ "svg",
4497
+ {
4498
+ xmlns: "http://www.w3.org/2000/svg",
4499
+ width: "12",
4500
+ height: "12",
4501
+ viewBox: "0 0 24 24",
4502
+ fill: "none",
4503
+ stroke: "currentColor",
4504
+ strokeWidth: "3",
4505
+ strokeLinecap: "round",
4506
+ strokeLinejoin: "round"
4507
+ },
4508
+ /* @__PURE__ */ import_react3.default.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4509
+ /* @__PURE__ */ import_react3.default.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4510
+ )
4511
+ )
4512
+ )),
4513
+ /* @__PURE__ */ import_react3.default.createElement(
4514
+ "input",
4515
+ {
4516
+ ref: inputRef,
4517
+ type: "text",
4518
+ value: query,
4519
+ onChange: (e) => setQuery(e.target.value),
4520
+ onFocus: () => setShowList(true),
4521
+ onBlur: () => setTimeout(() => setShowList(false), 120),
4522
+ onKeyDown: handleKeyDown,
4523
+ placeholder: activeFilters.length === 0 ? "Digite parte do nome..." : "",
4524
+ className: "bg-transparent border-none outline-none flex-1 min-w-[80px] text-sm text-slate-100 placeholder-slate-500",
4525
+ autoComplete: "off"
4526
+ }
4527
+ )
4528
+ ), showList && /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement(
4529
+ "li",
4530
+ {
4531
+ key: n.id,
4532
+ onMouseDown: () => handlePick(n),
4533
+ 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"}`,
4534
+ title: n.name
4535
+ },
4536
+ /* @__PURE__ */ import_react3.default.createElement(
4537
+ "span",
4538
+ {
4539
+ className: `inline-block h-2 w-2 rounded-full flex-shrink-0 ${isNodeInView(n.id) ? "bg-emerald-400" : "bg-slate-500"}`
4540
+ }
4541
+ ),
4542
+ /* @__PURE__ */ import_react3.default.createElement("span", { className: "truncate flex-1" }, n.name)
4543
+ )) : /* @__PURE__ */ import_react3.default.createElement("li", { className: "px-3 py-2 text-sm text-slate-400" }, "Nenhum resultado"))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mt-3 flex items-center gap-2" }, /* @__PURE__ */ import_react3.default.createElement(
4544
+ "button",
4545
+ {
4546
+ onClick: handleConfirm,
4547
+ disabled: !selectedNodeId,
4548
+ className: `flex-1 ${selectedNodeId ? buttonBaseClass : buttonDisabledClass}`
4549
+ },
4550
+ /* @__PURE__ */ import_react3.default.createElement(
4551
+ "svg",
4552
+ {
4553
+ xmlns: "http://www.w3.org/2000/svg",
4554
+ width: "16",
4555
+ height: "16",
4556
+ viewBox: "0 0 24 24",
4557
+ fill: "none",
4558
+ stroke: "currentColor",
4559
+ strokeWidth: "2",
4560
+ strokeLinecap: "round",
4561
+ strokeLinejoin: "round"
4562
+ },
4563
+ /* @__PURE__ */ import_react3.default.createElement("polygon", { points: "5 3 19 12 5 21 5 3" })
4564
+ ),
4565
+ "Renderizar"
4566
+ ), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative", ref: filterMenuRef }, /* @__PURE__ */ import_react3.default.createElement(
4567
+ "button",
4568
+ {
4569
+ onClick: () => setIsFilterMenuOpen(!isFilterMenuOpen),
4570
+ 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"}`
4571
+ },
4572
+ /* @__PURE__ */ import_react3.default.createElement(
4573
+ "svg",
4574
+ {
4575
+ xmlns: "http://www.w3.org/2000/svg",
4576
+ width: "16",
4577
+ height: "16",
4578
+ viewBox: "0 0 24 24",
4579
+ fill: "none",
4580
+ stroke: "currentColor",
4581
+ strokeWidth: "2",
4582
+ strokeLinecap: "round",
4583
+ strokeLinejoin: "round"
4584
+ },
4585
+ /* @__PURE__ */ import_react3.default.createElement("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" })
4586
+ ),
4587
+ "Filters"
4588
+ ), isFilterMenuOpen && /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Filtro"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex bg-slate-800/50 p-1 rounded-md" }, ["Type", "Color", "Dataset"].map((opt) => /* @__PURE__ */ import_react3.default.createElement(
4589
+ "button",
4590
+ {
4591
+ key: opt,
4592
+ onClick: () => {
4593
+ setFilterCategory(opt);
4594
+ setFilterValue("");
4595
+ },
4596
+ className: `flex-1 text-xs py-1 rounded transition-colors ${filterCategory === opt ? "bg-indigo-600 text-white" : "text-slate-400 hover:text-slate-200"}`
4597
+ },
4598
+ opt
4599
+ )))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), /* @__PURE__ */ import_react3.default.createElement(
4600
+ "input",
4601
+ {
4602
+ type: "text",
4603
+ value: filterValue,
4604
+ onChange: (e) => setFilterValue(e.target.value),
4605
+ 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"
4606
+ }
4607
+ )), /* @__PURE__ */ import_react3.default.createElement(
4608
+ "button",
4609
+ {
4610
+ onClick: handleAddFilter,
4611
+ disabled: !filterValue.trim(),
4612
+ 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"
4613
+ },
4614
+ "Aplicar Filtro"
4615
+ ))))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Lentes"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react3.default.createElement(
4382
4616
  "button",
4383
4617
  {
4384
4618
  onClick: () => setActiveSubMenu(activeSubMenu === "quest" ? null : "quest"),
4385
4619
  className: `${buttonBaseClass} lens-button ${activeSubMenu === "quest" || questFilterAssignee || questFilterStatus || questFilterMilestone ? "bg-indigo-500/30 border-indigo-400" : ""}`
4386
4620
  },
4387
- /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }), /* @__PURE__ */ import_react3.default.createElement("path", { d: "M9 12l2 2 4-4" })),
4388
- "Quest Lens"
4621
+ /* @__PURE__ */ import_react3.default.createElement(
4622
+ "svg",
4623
+ {
4624
+ xmlns: "http://www.w3.org/2000/svg",
4625
+ width: "16",
4626
+ height: "16",
4627
+ viewBox: "0 0 24 24",
4628
+ fill: "none",
4629
+ stroke: "currentColor",
4630
+ strokeWidth: "2",
4631
+ strokeLinecap: "round",
4632
+ strokeLinejoin: "round"
4633
+ },
4634
+ /* @__PURE__ */ import_react3.default.createElement("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }),
4635
+ /* @__PURE__ */ import_react3.default.createElement("path", { d: "M9 12l2 2 4-4" })
4636
+ ),
4637
+ "Quests"
4389
4638
  )), /* @__PURE__ */ import_react3.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react3.default.createElement(
4390
4639
  "button",
4391
4640
  {
4392
- onClick: () => setActiveSubMenu(activeSubMenu === "reshape" ? null : "reshape"),
4641
+ onClick: () => setActiveSubMenu(
4642
+ activeSubMenu === "reshape" ? null : "reshape"
4643
+ ),
4393
4644
  className: `${buttonBaseClass} lens-button ${activeSubMenu === "reshape" ? "bg-indigo-500/30 border-indigo-400" : ""}`
4394
4645
  },
4395
- /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }), /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "2 17 12 22 22 17" }), /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "2 12 12 17 22 12" })),
4396
- "Reshape Lens"
4397
- )), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: onActivateTimeline, className: buttonBaseClass }, /* @__PURE__ */ import_react3.default.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__ */ import_react3.default.createElement("circle", { cx: "12", cy: "12", r: "10" }), /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "12 6 12 12 16 14" })), "Timeline"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: onOpenBoards, className: buttonBaseClass }, /* @__PURE__ */ import_react3.default.createElement(import_fi2.FiLayers, { size: 16 }), "Boards")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-3" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Milestones"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: onOpenMilestoneManager, className: buttonBaseClass }, "Gerenciar Milestones"))),
4398
- /* @__PURE__ */ import_react3.default.createElement("div", { className: "px-4 py-3 border-t border-white/10 bg-slate-900/30" }, /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o"), ability.can("update", "Scene") && /* @__PURE__ */ import_react3.default.createElement("button", { onClick: handleSaveClick, disabled: isSaving, className: isSaving ? buttonDisabledClass : buttonBaseClass }, isSaving ? "Salvando..." : "Atualizar cen\xE1rio inicial"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: onNavigateBack, className: buttonBaseClass }, "Voltar \xE0 p\xE1gina de cen\xE1rios"))),
4646
+ /* @__PURE__ */ import_react3.default.createElement(
4647
+ "svg",
4648
+ {
4649
+ xmlns: "http://www.w3.org/2000/svg",
4650
+ width: "16",
4651
+ height: "16",
4652
+ viewBox: "0 0 24 24",
4653
+ fill: "none",
4654
+ stroke: "currentColor",
4655
+ strokeWidth: "2",
4656
+ strokeLinecap: "round",
4657
+ strokeLinejoin: "round"
4658
+ },
4659
+ /* @__PURE__ */ import_react3.default.createElement("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
4660
+ /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "2 17 12 22 22 17" }),
4661
+ /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "2 12 12 17 22 12" })
4662
+ ),
4663
+ "Reshape"
4664
+ )), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: onActivateTimeline, className: buttonBaseClass }, /* @__PURE__ */ import_react3.default.createElement(
4665
+ "svg",
4666
+ {
4667
+ xmlns: "http://www.w3.org/2000/svg",
4668
+ width: "16",
4669
+ height: "16",
4670
+ viewBox: "0 0 24 24",
4671
+ fill: "none",
4672
+ stroke: "currentColor",
4673
+ strokeWidth: "2",
4674
+ strokeLinecap: "round",
4675
+ strokeLinejoin: "round"
4676
+ },
4677
+ /* @__PURE__ */ import_react3.default.createElement("circle", { cx: "12", cy: "12", r: "10" }),
4678
+ /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "12 6 12 12 16 14" })
4679
+ ), "Timeline"), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: onOpenBoards, className: buttonBaseClass }, /* @__PURE__ */ import_react3.default.createElement(import_fi2.FiLayers, { size: 16 }), "Boards")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-3" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Milestones"), /* @__PURE__ */ import_react3.default.createElement(
4680
+ "button",
4681
+ {
4682
+ onClick: onOpenMilestoneManager,
4683
+ className: buttonBaseClass
4684
+ },
4685
+ "Gerenciar Milestones"
4686
+ ))),
4687
+ /* @__PURE__ */ import_react3.default.createElement("div", { className: "px-4 py-3 border-t border-white/10 bg-slate-900/30" }, /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o"), ability.can("update", "Scene") && /* @__PURE__ */ import_react3.default.createElement(
4688
+ "button",
4689
+ {
4690
+ onClick: handleSaveClick,
4691
+ disabled: isSaving,
4692
+ className: isSaving ? buttonDisabledClass : buttonBaseClass
4693
+ },
4694
+ isSaving ? "Salvando..." : "Atualizar cen\xE1rio inicial"
4695
+ ), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: onNavigateBack, className: buttonBaseClass }, "Voltar ao Dashboard"))),
4399
4696
  contextLabel && /* @__PURE__ */ import_react3.default.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),
4400
4697
  /* @__PURE__ */ import_react3.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" })
4401
4698
  ),
4402
- /* @__PURE__ */ import_react3.default.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
4699
+ /* @__PURE__ */ import_react3.default.createElement(
4700
+ "div",
4701
+ {
4702
+ 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
4403
4703
  ${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"}
4404
- ` }, renderAnnexedPanel())
4704
+ `
4705
+ },
4706
+ renderAnnexedPanel()
4707
+ )
4405
4708
  );
4406
4709
  }
4407
4710
 
@@ -18158,6 +18461,20 @@ function XViewScene({
18158
18461
  masterAncestryList.push(ancestryObjectToSave);
18159
18462
  }
18160
18463
  const result = await save_view_data(finalSaveUrl, masterAncestryList);
18464
+ if (result.success && isExternalSave && isEditMode && currentAncestryId && ancestry_save_url && get_ancestry_file) {
18465
+ try {
18466
+ const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
18467
+ if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
18468
+ const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(currentAncestryId));
18469
+ if (hasInViewDb) {
18470
+ const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(currentAncestryId));
18471
+ await save_view_data(ancestry_save_url, updatedViewDb);
18472
+ }
18473
+ }
18474
+ } catch (fallbackErr) {
18475
+ console.error("Falha ao limpar c\xF3pia residual na edi\xE7\xE3o:", fallbackErr);
18476
+ }
18477
+ }
18161
18478
  if (result.success) {
18162
18479
  const localList = [...ancestryDataRef.current || []];
18163
18480
  const localIndex = localList.findIndex(
@@ -18260,45 +18577,76 @@ function XViewScene({
18260
18577
  return;
18261
18578
  }
18262
18579
  const finalSaveUrl = `x_view_ancestry/${sourceOwnerId}/${sourceFileId}`;
18263
- const updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18264
- (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18265
- );
18580
+ const isExternalSave = sourceFileId !== sceneConfigId;
18581
+ let success = false;
18582
+ let deletionError = null;
18266
18583
  try {
18267
- const result = await save_view_data(
18268
- finalSaveUrl,
18269
- updatedAncestriesForFile
18270
- );
18271
- if (result.success) {
18272
- ancestryDataRef.current = (ancestryDataRef.current || []).filter(
18273
- (ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
18274
- );
18275
- const { renderedAncestries, ancestryGroup } = stateRef.current;
18276
- const renderIndex = renderedAncestries.findIndex(
18277
- (a) => String(a.id) === String(ancestryIdToDelete)
18278
- );
18279
- if (renderIndex !== -1) {
18280
- const toRemove = renderedAncestries[renderIndex];
18281
- toRemove.lines.forEach((line) => {
18282
- ancestryGroup.remove(line);
18283
- if (line.geometry) line.geometry.dispose();
18284
- if (line.material) line.material.dispose();
18285
- });
18286
- renderedAncestries.splice(renderIndex, 1);
18287
- stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18288
- (a) => a.lines
18584
+ let updatedAncestriesForFile;
18585
+ if (get_ancestry_file && isExternalSave) {
18586
+ const remoteResponse = await get_ancestry_file(sourceFileId, sourceOwnerId);
18587
+ if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
18588
+ updatedAncestriesForFile = remoteResponse.data.filter(
18589
+ (anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete)
18590
+ );
18591
+ } else {
18592
+ updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18593
+ (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18289
18594
  );
18290
18595
  }
18291
- setSceneVersion((v) => v + 1);
18292
18596
  } else {
18293
- throw new Error(
18294
- result.error || "Ocorreu um erro desconhecido ao excluir."
18597
+ updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18598
+ (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18295
18599
  );
18296
18600
  }
18601
+ const result = await save_view_data(finalSaveUrl, updatedAncestriesForFile);
18602
+ if (result.success) {
18603
+ success = true;
18604
+ } else {
18605
+ throw new Error(result.error || "Ocorreu um erro desconhecido ao excluir.");
18606
+ }
18297
18607
  } catch (error) {
18298
- console.error("Falha ao excluir a ancestralidade:", error);
18299
- alert(`Erro ao excluir a ancestralidade: ${error.message}`);
18608
+ deletionError = error;
18609
+ }
18610
+ if (ancestry_save_url && isExternalSave && get_ancestry_file) {
18611
+ try {
18612
+ const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
18613
+ if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
18614
+ const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(ancestryIdToDelete));
18615
+ if (hasInViewDb) {
18616
+ const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete));
18617
+ const fallbackResult = await save_view_data(ancestry_save_url, updatedViewDb);
18618
+ if (fallbackResult.success) success = true;
18619
+ }
18620
+ }
18621
+ } catch (fallbackErr) {
18622
+ console.error("Falha ao limpar c\xF3pia residual da View DB:", fallbackErr);
18623
+ }
18624
+ }
18625
+ if (!success && deletionError) {
18626
+ console.error("Falha ao excluir a ancestralidade:", deletionError);
18627
+ alert(`Erro ao excluir a ancestralidade: ${deletionError.message}`);
18300
18628
  return;
18301
18629
  }
18630
+ ancestryDataRef.current = (ancestryDataRef.current || []).filter(
18631
+ (ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
18632
+ );
18633
+ const { renderedAncestries, ancestryGroup } = stateRef.current;
18634
+ const renderIndex = renderedAncestries.findIndex(
18635
+ (a) => String(a.id) === String(ancestryIdToDelete)
18636
+ );
18637
+ if (renderIndex !== -1) {
18638
+ const toRemove = renderedAncestries[renderIndex];
18639
+ toRemove.lines.forEach((line) => {
18640
+ ancestryGroup.remove(line);
18641
+ if (line.geometry) line.geometry.dispose();
18642
+ if (line.material) line.material.dispose();
18643
+ });
18644
+ renderedAncestries.splice(renderIndex, 1);
18645
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18646
+ (a) => a.lines
18647
+ );
18648
+ }
18649
+ setSceneVersion((v) => v + 1);
18302
18650
  setAncestryMode({
18303
18651
  isActive: false,
18304
18652
  tree: null,
package/dist/index.mjs CHANGED
@@ -3854,7 +3854,24 @@ var CustomSelect = ({ value, onChange, options, placeholder }) => {
3854
3854
  ${isOpen ? "border-indigo-500/50 bg-slate-800" : "border-white/10 hover:bg-slate-800"}`
3855
3855
  },
3856
3856
  /* @__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" }))
3857
+ /* @__PURE__ */ React2.createElement(
3858
+ "svg",
3859
+ {
3860
+ className: `w-4 h-4 text-slate-500 transition-transform flex-shrink-0 ${isOpen ? "rotate-180" : ""}`,
3861
+ fill: "none",
3862
+ viewBox: "0 0 24 24",
3863
+ stroke: "currentColor"
3864
+ },
3865
+ /* @__PURE__ */ React2.createElement(
3866
+ "path",
3867
+ {
3868
+ strokeLinecap: "round",
3869
+ strokeLinejoin: "round",
3870
+ strokeWidth: 2,
3871
+ d: "M19 9l-7 7-7-7"
3872
+ }
3873
+ )
3874
+ )
3858
3875
  ), 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
3876
  const isSelected = String(value) === String(opt.value);
3860
3877
  return /* @__PURE__ */ React2.createElement(
@@ -3944,7 +3961,10 @@ function XViewSidebar({
3944
3961
  }, [viewType, viewName]);
3945
3962
  const normalize = (str = "") => {
3946
3963
  if (str === void 0 || str === null) {
3947
- console.warn("XViewSidebar: normalize recebeu valor nulo/indefinido:", str);
3964
+ console.warn(
3965
+ "XViewSidebar: normalize recebeu valor nulo/indefinido:",
3966
+ str
3967
+ );
3948
3968
  }
3949
3969
  return String(str).toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[._\-–—:,;!?'"()\[\]{}/\\]/g, " ").replace(/\s+/g, " ").trim();
3950
3970
  };
@@ -3996,7 +4016,9 @@ function XViewSidebar({
3996
4016
  return activeFilters.every((filter) => {
3997
4017
  if (filter.type === "Type") {
3998
4018
  const nodeTypes = Array.isArray(node.type) ? node.type : [node.type];
3999
- return nodeTypes.some((t) => String(t).toLowerCase() === String(filter.value).toLowerCase());
4019
+ return nodeTypes.some(
4020
+ (t) => String(t).toLowerCase() === String(filter.value).toLowerCase()
4021
+ );
4000
4022
  } else if (filter.type === "Color") {
4001
4023
  return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
4002
4024
  } else if (filter.type === "Dataset") {
@@ -4016,7 +4038,14 @@ function XViewSidebar({
4016
4038
  inView.sort(byName);
4017
4039
  const ordered = [...notInView, ...inView];
4018
4040
  return ordered.slice(0, 200);
4019
- }, [dbNodes, query, isNodeInView, viewVersion, activeFilters, filterCategory]);
4041
+ }, [
4042
+ dbNodes,
4043
+ query,
4044
+ isNodeInView,
4045
+ viewVersion,
4046
+ activeFilters,
4047
+ filterCategory
4048
+ ]);
4020
4049
  useEffect2(() => {
4021
4050
  const handleClickOutside = (event) => {
4022
4051
  if (filterMenuRef.current && !filterMenuRef.current.contains(event.target)) {
@@ -4135,7 +4164,24 @@ function XViewSidebar({
4135
4164
  },
4136
4165
  title: "Abrir painel"
4137
4166
  },
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" }))
4167
+ /* @__PURE__ */ React2.createElement(
4168
+ "svg",
4169
+ {
4170
+ className: "h-6 w-6",
4171
+ fill: "none",
4172
+ viewBox: "0 0 24 24",
4173
+ stroke: "currentColor"
4174
+ },
4175
+ /* @__PURE__ */ React2.createElement(
4176
+ "path",
4177
+ {
4178
+ strokeLinecap: "round",
4179
+ strokeLinejoin: "round",
4180
+ strokeWidth: 2,
4181
+ d: "M4 6h16M4 12h16m-7 6h7"
4182
+ }
4183
+ )
4184
+ )
4139
4185
  );
4140
4186
  if (!isOpen) return ToggleButton;
4141
4187
  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 +4201,23 @@ function XViewSidebar({
4155
4201
  className: "p-1.5 -ml-1 rounded-md text-slate-400 hover:text-white hover:bg-white/10 md:hidden transition-colors",
4156
4202
  title: "Voltar"
4157
4203
  },
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" }))
4204
+ /* @__PURE__ */ React2.createElement(
4205
+ "svg",
4206
+ {
4207
+ xmlns: "http://www.w3.org/2000/svg",
4208
+ className: "h-5 w-5",
4209
+ viewBox: "0 0 20 20",
4210
+ fill: "currentColor"
4211
+ },
4212
+ /* @__PURE__ */ React2.createElement(
4213
+ "path",
4214
+ {
4215
+ fillRule: "evenodd",
4216
+ 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",
4217
+ clipRule: "evenodd"
4218
+ }
4219
+ )
4220
+ )
4159
4221
  ), /* @__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
4222
  "button",
4161
4223
  {
@@ -4163,7 +4225,23 @@ function XViewSidebar({
4163
4225
  onClick: () => setActiveSubMenu(null),
4164
4226
  title: "Fechar Sub-menu"
4165
4227
  },
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" }))
4228
+ /* @__PURE__ */ React2.createElement(
4229
+ "svg",
4230
+ {
4231
+ xmlns: "http://www.w3.org/2000/svg",
4232
+ className: "h-4 w-4",
4233
+ viewBox: "0 0 20 20",
4234
+ fill: "currentColor"
4235
+ },
4236
+ /* @__PURE__ */ React2.createElement(
4237
+ "path",
4238
+ {
4239
+ fillRule: "evenodd",
4240
+ 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",
4241
+ clipRule: "evenodd"
4242
+ }
4243
+ )
4244
+ )
4167
4245
  )),
4168
4246
  /* @__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
4247
  CustomSelect,
@@ -4172,7 +4250,10 @@ function XViewSidebar({
4172
4250
  onChange: (val) => setQuestFilterAssignee(val),
4173
4251
  options: [
4174
4252
  { value: "", label: "Todos os Respons\xE1veis" },
4175
- ...viewMembers.map((m) => ({ value: m.id, label: m.name || m.email }))
4253
+ ...viewMembers.map((m) => ({
4254
+ value: m.id,
4255
+ label: m.name || m.email
4256
+ }))
4176
4257
  ],
4177
4258
  placeholder: "Selecione um Respons\xE1vel"
4178
4259
  }
@@ -4321,48 +4402,270 @@ function XViewSidebar({
4321
4402
  onClick: () => onToggle(false),
4322
4403
  title: "Fechar Painel"
4323
4404
  },
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",
4405
+ /* @__PURE__ */ React2.createElement(
4406
+ "svg",
4326
4407
  {
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
- ))
4408
+ xmlns: "http://www.w3.org/2000/svg",
4409
+ className: "h-5 w-5",
4410
+ viewBox: "0 0 20 20",
4411
+ fill: "currentColor"
4412
+ },
4413
+ /* @__PURE__ */ React2.createElement(
4414
+ "path",
4415
+ {
4416
+ fillRule: "evenodd",
4417
+ 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",
4418
+ clipRule: "evenodd"
4419
+ }
4420
+ )
4421
+ )
4332
4422
  ), /* @__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(
4423
+ /* @__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(
4424
+ "div",
4425
+ {
4426
+ 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]",
4427
+ onClick: () => {
4428
+ var _a;
4429
+ return (_a = inputRef.current) == null ? void 0 : _a.focus();
4430
+ }
4431
+ },
4432
+ activeFilters.map((filter, idx) => /* @__PURE__ */ React2.createElement(
4433
+ "span",
4434
+ {
4435
+ key: idx,
4436
+ 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"
4437
+ },
4438
+ filter.type === "Color" && /* @__PURE__ */ React2.createElement(
4439
+ "span",
4440
+ {
4441
+ className: "inline-block w-2.5 h-2.5 rounded-full border border-white/20",
4442
+ style: { backgroundColor: filter.value }
4443
+ }
4444
+ ),
4445
+ /* @__PURE__ */ React2.createElement("span", { className: "truncate max-w-[120px]" }, filter.type, ": ", filter.value),
4446
+ /* @__PURE__ */ React2.createElement(
4447
+ "button",
4448
+ {
4449
+ type: "button",
4450
+ onClick: (e) => {
4451
+ e.stopPropagation();
4452
+ handleRemoveFilter(idx);
4453
+ },
4454
+ className: "hover:text-white transition-colors"
4455
+ },
4456
+ /* @__PURE__ */ React2.createElement(
4457
+ "svg",
4458
+ {
4459
+ xmlns: "http://www.w3.org/2000/svg",
4460
+ width: "12",
4461
+ height: "12",
4462
+ viewBox: "0 0 24 24",
4463
+ fill: "none",
4464
+ stroke: "currentColor",
4465
+ strokeWidth: "3",
4466
+ strokeLinecap: "round",
4467
+ strokeLinejoin: "round"
4468
+ },
4469
+ /* @__PURE__ */ React2.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4470
+ /* @__PURE__ */ React2.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4471
+ )
4472
+ )
4473
+ )),
4474
+ /* @__PURE__ */ React2.createElement(
4475
+ "input",
4476
+ {
4477
+ ref: inputRef,
4478
+ type: "text",
4479
+ value: query,
4480
+ onChange: (e) => setQuery(e.target.value),
4481
+ onFocus: () => setShowList(true),
4482
+ onBlur: () => setTimeout(() => setShowList(false), 120),
4483
+ onKeyDown: handleKeyDown,
4484
+ placeholder: activeFilters.length === 0 ? "Digite parte do nome..." : "",
4485
+ className: "bg-transparent border-none outline-none flex-1 min-w-[80px] text-sm text-slate-100 placeholder-slate-500",
4486
+ autoComplete: "off"
4487
+ }
4488
+ )
4489
+ ), 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(
4490
+ "li",
4491
+ {
4492
+ key: n.id,
4493
+ onMouseDown: () => handlePick(n),
4494
+ 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"}`,
4495
+ title: n.name
4496
+ },
4497
+ /* @__PURE__ */ React2.createElement(
4498
+ "span",
4499
+ {
4500
+ className: `inline-block h-2 w-2 rounded-full flex-shrink-0 ${isNodeInView(n.id) ? "bg-emerald-400" : "bg-slate-500"}`
4501
+ }
4502
+ ),
4503
+ /* @__PURE__ */ React2.createElement("span", { className: "truncate flex-1" }, n.name)
4504
+ )) : /* @__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(
4505
+ "button",
4506
+ {
4507
+ onClick: handleConfirm,
4508
+ disabled: !selectedNodeId,
4509
+ className: `flex-1 ${selectedNodeId ? buttonBaseClass : buttonDisabledClass}`
4510
+ },
4511
+ /* @__PURE__ */ React2.createElement(
4512
+ "svg",
4513
+ {
4514
+ xmlns: "http://www.w3.org/2000/svg",
4515
+ width: "16",
4516
+ height: "16",
4517
+ viewBox: "0 0 24 24",
4518
+ fill: "none",
4519
+ stroke: "currentColor",
4520
+ strokeWidth: "2",
4521
+ strokeLinecap: "round",
4522
+ strokeLinejoin: "round"
4523
+ },
4524
+ /* @__PURE__ */ React2.createElement("polygon", { points: "5 3 19 12 5 21 5 3" })
4525
+ ),
4526
+ "Renderizar"
4527
+ ), /* @__PURE__ */ React2.createElement("div", { className: "relative", ref: filterMenuRef }, /* @__PURE__ */ React2.createElement(
4528
+ "button",
4529
+ {
4530
+ onClick: () => setIsFilterMenuOpen(!isFilterMenuOpen),
4531
+ 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"}`
4532
+ },
4533
+ /* @__PURE__ */ React2.createElement(
4534
+ "svg",
4535
+ {
4536
+ xmlns: "http://www.w3.org/2000/svg",
4537
+ width: "16",
4538
+ height: "16",
4539
+ viewBox: "0 0 24 24",
4540
+ fill: "none",
4541
+ stroke: "currentColor",
4542
+ strokeWidth: "2",
4543
+ strokeLinecap: "round",
4544
+ strokeLinejoin: "round"
4545
+ },
4546
+ /* @__PURE__ */ React2.createElement("polygon", { points: "22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" })
4547
+ ),
4548
+ "Filters"
4549
+ ), 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(
4550
+ "button",
4551
+ {
4552
+ key: opt,
4553
+ onClick: () => {
4554
+ setFilterCategory(opt);
4555
+ setFilterValue("");
4556
+ },
4557
+ className: `flex-1 text-xs py-1 rounded transition-colors ${filterCategory === opt ? "bg-indigo-600 text-white" : "text-slate-400 hover:text-slate-200"}`
4558
+ },
4559
+ opt
4560
+ )))), /* @__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(
4561
+ "input",
4562
+ {
4563
+ type: "text",
4564
+ value: filterValue,
4565
+ onChange: (e) => setFilterValue(e.target.value),
4566
+ 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"
4567
+ }
4568
+ )), /* @__PURE__ */ React2.createElement(
4569
+ "button",
4570
+ {
4571
+ onClick: handleAddFilter,
4572
+ disabled: !filterValue.trim(),
4573
+ 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"
4574
+ },
4575
+ "Aplicar Filtro"
4576
+ ))))), /* @__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
4577
  "button",
4344
4578
  {
4345
4579
  onClick: () => setActiveSubMenu(activeSubMenu === "quest" ? null : "quest"),
4346
4580
  className: `${buttonBaseClass} lens-button ${activeSubMenu === "quest" || questFilterAssignee || questFilterStatus || questFilterMilestone ? "bg-indigo-500/30 border-indigo-400" : ""}`
4347
4581
  },
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"
4582
+ /* @__PURE__ */ React2.createElement(
4583
+ "svg",
4584
+ {
4585
+ xmlns: "http://www.w3.org/2000/svg",
4586
+ width: "16",
4587
+ height: "16",
4588
+ viewBox: "0 0 24 24",
4589
+ fill: "none",
4590
+ stroke: "currentColor",
4591
+ strokeWidth: "2",
4592
+ strokeLinecap: "round",
4593
+ strokeLinejoin: "round"
4594
+ },
4595
+ /* @__PURE__ */ React2.createElement("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }),
4596
+ /* @__PURE__ */ React2.createElement("path", { d: "M9 12l2 2 4-4" })
4597
+ ),
4598
+ "Quests"
4350
4599
  )), /* @__PURE__ */ React2.createElement("div", { className: "relative" }, /* @__PURE__ */ React2.createElement(
4351
4600
  "button",
4352
4601
  {
4353
- onClick: () => setActiveSubMenu(activeSubMenu === "reshape" ? null : "reshape"),
4602
+ onClick: () => setActiveSubMenu(
4603
+ activeSubMenu === "reshape" ? null : "reshape"
4604
+ ),
4354
4605
  className: `${buttonBaseClass} lens-button ${activeSubMenu === "reshape" ? "bg-indigo-500/30 border-indigo-400" : ""}`
4355
4606
  },
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"))),
4607
+ /* @__PURE__ */ React2.createElement(
4608
+ "svg",
4609
+ {
4610
+ xmlns: "http://www.w3.org/2000/svg",
4611
+ width: "16",
4612
+ height: "16",
4613
+ viewBox: "0 0 24 24",
4614
+ fill: "none",
4615
+ stroke: "currentColor",
4616
+ strokeWidth: "2",
4617
+ strokeLinecap: "round",
4618
+ strokeLinejoin: "round"
4619
+ },
4620
+ /* @__PURE__ */ React2.createElement("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
4621
+ /* @__PURE__ */ React2.createElement("polyline", { points: "2 17 12 22 22 17" }),
4622
+ /* @__PURE__ */ React2.createElement("polyline", { points: "2 12 12 17 22 12" })
4623
+ ),
4624
+ "Reshape"
4625
+ )), /* @__PURE__ */ React2.createElement("button", { onClick: onActivateTimeline, className: buttonBaseClass }, /* @__PURE__ */ React2.createElement(
4626
+ "svg",
4627
+ {
4628
+ xmlns: "http://www.w3.org/2000/svg",
4629
+ width: "16",
4630
+ height: "16",
4631
+ viewBox: "0 0 24 24",
4632
+ fill: "none",
4633
+ stroke: "currentColor",
4634
+ strokeWidth: "2",
4635
+ strokeLinecap: "round",
4636
+ strokeLinejoin: "round"
4637
+ },
4638
+ /* @__PURE__ */ React2.createElement("circle", { cx: "12", cy: "12", r: "10" }),
4639
+ /* @__PURE__ */ React2.createElement("polyline", { points: "12 6 12 12 16 14" })
4640
+ ), "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(
4641
+ "button",
4642
+ {
4643
+ onClick: onOpenMilestoneManager,
4644
+ className: buttonBaseClass
4645
+ },
4646
+ "Gerenciar Milestones"
4647
+ ))),
4648
+ /* @__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(
4649
+ "button",
4650
+ {
4651
+ onClick: handleSaveClick,
4652
+ disabled: isSaving,
4653
+ className: isSaving ? buttonDisabledClass : buttonBaseClass
4654
+ },
4655
+ isSaving ? "Salvando..." : "Atualizar cen\xE1rio inicial"
4656
+ ), /* @__PURE__ */ React2.createElement("button", { onClick: onNavigateBack, className: buttonBaseClass }, "Voltar ao Dashboard"))),
4360
4657
  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
4658
  /* @__PURE__ */ React2.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" })
4362
4659
  ),
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
4660
+ /* @__PURE__ */ React2.createElement(
4661
+ "div",
4662
+ {
4663
+ 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
4664
  ${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())
4665
+ `
4666
+ },
4667
+ renderAnnexedPanel()
4668
+ )
4366
4669
  );
4367
4670
  }
4368
4671
 
@@ -18214,6 +18517,20 @@ function XViewScene({
18214
18517
  masterAncestryList.push(ancestryObjectToSave);
18215
18518
  }
18216
18519
  const result = await save_view_data(finalSaveUrl, masterAncestryList);
18520
+ if (result.success && isExternalSave && isEditMode && currentAncestryId && ancestry_save_url && get_ancestry_file) {
18521
+ try {
18522
+ const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
18523
+ if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
18524
+ const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(currentAncestryId));
18525
+ if (hasInViewDb) {
18526
+ const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(currentAncestryId));
18527
+ await save_view_data(ancestry_save_url, updatedViewDb);
18528
+ }
18529
+ }
18530
+ } catch (fallbackErr) {
18531
+ console.error("Falha ao limpar c\xF3pia residual na edi\xE7\xE3o:", fallbackErr);
18532
+ }
18533
+ }
18217
18534
  if (result.success) {
18218
18535
  const localList = [...ancestryDataRef.current || []];
18219
18536
  const localIndex = localList.findIndex(
@@ -18316,45 +18633,76 @@ function XViewScene({
18316
18633
  return;
18317
18634
  }
18318
18635
  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
- );
18636
+ const isExternalSave = sourceFileId !== sceneConfigId;
18637
+ let success = false;
18638
+ let deletionError = null;
18322
18639
  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
18640
+ let updatedAncestriesForFile;
18641
+ if (get_ancestry_file && isExternalSave) {
18642
+ const remoteResponse = await get_ancestry_file(sourceFileId, sourceOwnerId);
18643
+ if (remoteResponse.success && Array.isArray(remoteResponse.data)) {
18644
+ updatedAncestriesForFile = remoteResponse.data.filter(
18645
+ (anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete)
18646
+ );
18647
+ } else {
18648
+ updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18649
+ (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18345
18650
  );
18346
18651
  }
18347
- setSceneVersion((v) => v + 1);
18348
18652
  } else {
18349
- throw new Error(
18350
- result.error || "Ocorreu um erro desconhecido ao excluir."
18653
+ updatedAncestriesForFile = (ancestryDataRef.current || []).filter(
18654
+ (anc) => anc._source_file_id === sourceFileId && String(anc.ancestry_id) !== String(ancestryIdToDelete)
18351
18655
  );
18352
18656
  }
18657
+ const result = await save_view_data(finalSaveUrl, updatedAncestriesForFile);
18658
+ if (result.success) {
18659
+ success = true;
18660
+ } else {
18661
+ throw new Error(result.error || "Ocorreu um erro desconhecido ao excluir.");
18662
+ }
18353
18663
  } catch (error) {
18354
- console.error("Falha ao excluir a ancestralidade:", error);
18355
- alert(`Erro ao excluir a ancestralidade: ${error.message}`);
18664
+ deletionError = error;
18665
+ }
18666
+ if (ancestry_save_url && isExternalSave && get_ancestry_file) {
18667
+ try {
18668
+ const viewDbResponse = await get_ancestry_file(sceneConfigId, ownerId);
18669
+ if (viewDbResponse.success && Array.isArray(viewDbResponse.data)) {
18670
+ const hasInViewDb = viewDbResponse.data.some((anc) => String(anc.ancestry_id) === String(ancestryIdToDelete));
18671
+ if (hasInViewDb) {
18672
+ const updatedViewDb = viewDbResponse.data.filter((anc) => String(anc.ancestry_id) !== String(ancestryIdToDelete));
18673
+ const fallbackResult = await save_view_data(ancestry_save_url, updatedViewDb);
18674
+ if (fallbackResult.success) success = true;
18675
+ }
18676
+ }
18677
+ } catch (fallbackErr) {
18678
+ console.error("Falha ao limpar c\xF3pia residual da View DB:", fallbackErr);
18679
+ }
18680
+ }
18681
+ if (!success && deletionError) {
18682
+ console.error("Falha ao excluir a ancestralidade:", deletionError);
18683
+ alert(`Erro ao excluir a ancestralidade: ${deletionError.message}`);
18356
18684
  return;
18357
18685
  }
18686
+ ancestryDataRef.current = (ancestryDataRef.current || []).filter(
18687
+ (ancestry) => String(ancestry.ancestry_id) !== String(ancestryIdToDelete)
18688
+ );
18689
+ const { renderedAncestries, ancestryGroup } = stateRef.current;
18690
+ const renderIndex = renderedAncestries.findIndex(
18691
+ (a) => String(a.id) === String(ancestryIdToDelete)
18692
+ );
18693
+ if (renderIndex !== -1) {
18694
+ const toRemove = renderedAncestries[renderIndex];
18695
+ toRemove.lines.forEach((line) => {
18696
+ ancestryGroup.remove(line);
18697
+ if (line.geometry) line.geometry.dispose();
18698
+ if (line.material) line.material.dispose();
18699
+ });
18700
+ renderedAncestries.splice(renderIndex, 1);
18701
+ stateRef.current.ancestryLinks = renderedAncestries.flatMap(
18702
+ (a) => a.lines
18703
+ );
18704
+ }
18705
+ setSceneVersion((v) => v + 1);
18358
18706
  setAncestryMode({
18359
18707
  isActive: false,
18360
18708
  tree: null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.6-dev.54",
3
+ "version": "1.2.6-dev.55",
4
4
  "description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
5
5
  "author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
6
6
  "license": "UNLICENSED",