@lv-x-software-house/x_view 1.2.4-dev.23 → 1.2.4-dev.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1 @@
1
- X View - from ŀv.x - Software House
1
+ x.view - from ŀv.x - Software Engineering
package/dist/index.js CHANGED
@@ -2893,7 +2893,9 @@ var IGNORED_KEYS = [
2893
2893
  "is_private",
2894
2894
  "abstraction_tree",
2895
2895
  "selectedAbstractionParentId",
2896
- "isAddingAbstractionNodes"
2896
+ "isAddingAbstractionNodes",
2897
+ "status",
2898
+ "is_quest"
2897
2899
  ];
2898
2900
  function extractCustomPropsFromNode(node) {
2899
2901
  const customPropTypes = node._customPropTypes || {};
@@ -7969,10 +7971,13 @@ function InSceneQuestForm({
7969
7971
  availableAncestries = [],
7970
7972
  onMentionClick,
7971
7973
  onUploadFile,
7972
- // NOVAS PROPS PARA O GHOST NODE
7973
7974
  onNameChange,
7974
7975
  onColorChange,
7975
- onSizeChange
7976
+ onSizeChange,
7977
+ viewName = "Projeto",
7978
+ // NOVA PROP
7979
+ questCounter = 1
7980
+ // NOVA PROP
7976
7981
  }) {
7977
7982
  const [name, setName] = (0, import_react16.useState)("");
7978
7983
  const [types, setTypes] = (0, import_react16.useState)(["quest"]);
@@ -7985,6 +7990,7 @@ function InSceneQuestForm({
7985
7990
  const [customProps, setCustomProps] = (0, import_react16.useState)([]);
7986
7991
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react16.useState)(false);
7987
7992
  const propsEndRef = (0, import_react16.useRef)(null);
7993
+ const standardizedName = `${viewName} - ${questCounter} - \xBB ${name || "Nova Quest"}`;
7988
7994
  const handleAddProp = () => {
7989
7995
  const newProp = createNewCustomProperty(customProps);
7990
7996
  setCustomProps([...customProps, newProp]);
@@ -8021,7 +8027,7 @@ function InSceneQuestForm({
8021
8027
  const handleSubmit = (e) => {
8022
8028
  e.preventDefault();
8023
8029
  if (!name.trim()) {
8024
- alert("O campo 'Nome' \xE9 obrigat\xF3rio.");
8030
+ alert("O campo 'T\xEDtulo' \xE9 obrigat\xF3rio.");
8025
8031
  return;
8026
8032
  }
8027
8033
  const additionalData = toObjectFromCustomProps(
@@ -8029,7 +8035,10 @@ function InSceneQuestForm({
8029
8035
  );
8030
8036
  const processedSections = processDescriptionForSave(description, []);
8031
8037
  onSave({
8032
- name: name.trim(),
8038
+ name: standardizedName,
8039
+ // SALVA O NOME FORMATADO
8040
+ raw_title: name.trim(),
8041
+ // Salva o título puro como fallback ou metadado útil
8033
8042
  type: types,
8034
8043
  color: QUEST_STATUS_COLORS[status],
8035
8044
  status,
@@ -8068,7 +8077,21 @@ function InSceneQuestForm({
8068
8077
  },
8069
8078
  "\xD7"
8070
8079
  )),
8071
- /* @__PURE__ */ import_react16.default.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react16.default.createElement(
8080
+ /* @__PURE__ */ import_react16.default.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ import_react16.default.createElement(
8081
+ "input",
8082
+ {
8083
+ required: true,
8084
+ type: "text",
8085
+ placeholder: "Ex.: Refatorar M\xF3dulo X",
8086
+ value: name,
8087
+ onChange: (e) => {
8088
+ const val = e.target.value;
8089
+ setName(val);
8090
+ onNameChange == null ? void 0 : onNameChange(`${viewName} - ${questCounter} - \xBB ${val || "Nova Quest"}`);
8091
+ },
8092
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
8093
+ }
8094
+ ), /* @__PURE__ */ import_react16.default.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }, "Preview:"), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react16.default.createElement(
8072
8095
  "button",
8073
8096
  {
8074
8097
  type: "button",
@@ -8090,20 +8113,7 @@ function InSceneQuestForm({
8090
8113
  },
8091
8114
  /* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS[s] } }),
8092
8115
  s
8093
- )))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ import_react16.default.createElement(
8094
- "input",
8095
- {
8096
- required: true,
8097
- type: "text",
8098
- placeholder: "Ex.: Refatorar M\xF3dulo X",
8099
- value: name,
8100
- onChange: (e) => {
8101
- setName(e.target.value);
8102
- onNameChange == null ? void 0 : onNameChange(e.target.value);
8103
- },
8104
- className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
8105
- }
8106
- )), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ import_react16.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiX, { size: 12 })))), /* @__PURE__ */ import_react16.default.createElement(
8116
+ )))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ import_react16.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiX, { size: 12 })))), /* @__PURE__ */ import_react16.default.createElement(
8107
8117
  "input",
8108
8118
  {
8109
8119
  type: "text",
@@ -8925,15 +8935,28 @@ function QuestDetailsPanel({
8925
8935
  },
8926
8936
  /* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
8927
8937
  s
8928
- )))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome"), /* @__PURE__ */ import_react18.default.createElement("input", { type: "text", value: name, onChange: handleNameChange, readOnly: !canEdit, className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none ${canEdit ? "focus:ring-2 focus:ring-indigo-400/60" : "cursor-default text-slate-400"}` })), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ import_react18.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiX, { size: 12 })))), canEdit && /* @__PURE__ */ import_react18.default.createElement("input", { type: "text", value: typeInput, onChange: (e) => {
8929
- setTypeInput(e.target.value);
8930
- setShowTypeSuggestions(true);
8931
- }, onKeyDown: handleTypeInputKeyDown, onClick: () => setShowTypeSuggestions(true), onBlur: () => {
8932
- if (typeInput.trim()) {
8933
- handleAddType(typeInput);
8934
- }
8935
- setTimeout(() => setShowTypeSuggestions(false), 150);
8936
- }, className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200", placeholder: types.length === 1 ? "Ex.: Client" : "", autoComplete: "off" }), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ import_react18.default.createElement("ul", { className: "custom-scrollbar absolute top-full left-0 z-10 w-full mt-1 max-h-40 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-lg" }, filteredTypes.map((suggestedType, index) => /* @__PURE__ */ import_react18.default.createElement("li", { key: index, className: "px-3 py-2 text-sm text-slate-200 cursor-pointer hover:bg-indigo-600/50", onMouseDown: (e) => {
8938
+ )))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Nome"), /* @__PURE__ */ import_react18.default.createElement("input", { type: "text", value: name, onChange: handleNameChange, readOnly: !canEdit, className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none ${canEdit ? "focus:ring-2 focus:ring-indigo-400/60" : "cursor-default text-slate-400"}` })), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ import_react18.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiX, { size: 12 })))), canEdit && /* @__PURE__ */ import_react18.default.createElement(
8939
+ "input",
8940
+ {
8941
+ type: "text",
8942
+ value: typeInput,
8943
+ onChange: (e) => {
8944
+ setTypeInput(e.target.value);
8945
+ setShowTypeSuggestions(true);
8946
+ },
8947
+ onKeyDown: handleTypeInputKeyDown,
8948
+ onClick: () => setShowTypeSuggestions(true),
8949
+ onBlur: () => {
8950
+ if (typeInput.trim()) {
8951
+ handleAddType(typeInput);
8952
+ }
8953
+ setTimeout(() => setShowTypeSuggestions(false), 150);
8954
+ },
8955
+ className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200",
8956
+ placeholder: "",
8957
+ autoComplete: "off"
8958
+ }
8959
+ ), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ import_react18.default.createElement("ul", { className: "custom-scrollbar absolute top-full left-0 z-10 w-full mt-1 max-h-40 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-lg" }, filteredTypes.map((suggestedType, index) => /* @__PURE__ */ import_react18.default.createElement("li", { key: index, className: "px-3 py-2 text-sm text-slate-200 cursor-pointer hover:bg-indigo-600/50", onMouseDown: (e) => {
8937
8960
  e.preventDefault();
8938
8961
  handleAddType(suggestedType);
8939
8962
  } }, suggestedType))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ import_react18.default.createElement("div", { className: "relative group min-h-[60px] bg-slate-800/40 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(DescriptionDisplay, { description, savedSections: existingSections, availableNodes, availableAncestries, onOpenReference, onMentionClick, onImageClick: handleImageClickFromText, onSaveDescription: handleSaveDescriptionInline }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: () => setIsReadMode(true), className: `p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors ${canEdit ? "border-r border-white/5" : ""}`, title: "Modo de Leitura" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiBookOpen, { size: 14 })), canEdit && /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors", title: "Editar descri\xE7\xE3o (Modo de Escrita)" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiEdit2, { size: 14 }))), canEdit && !description && /* @__PURE__ */ import_react18.default.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
@@ -10288,7 +10311,7 @@ function XViewScene({
10288
10311
  delete_file_action,
10289
10312
  check_user_permission
10290
10313
  }) {
10291
- var _a, _b, _c, _d, _e, _f, _g;
10314
+ var _a, _b, _c, _d, _e, _f, _g, _h;
10292
10315
  const { data: session, status } = (0, import_react27.useSession)();
10293
10316
  const router = (0, import_navigation.useRouter)();
10294
10317
  const searchParams = (0, import_navigation.useSearchParams)();
@@ -11963,6 +11986,7 @@ function XViewScene({
11963
11986
  const handleSaveQuestNode = async (context, newQuestData) => {
11964
11987
  const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
11965
11988
  if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
11989
+ const currentCounter = sceneDataRef2.current.quest_counter || 1;
11966
11990
  const newNode = {
11967
11991
  id: import_short_uuid2.default.generate(),
11968
11992
  ...newQuestData,
@@ -11978,10 +12002,13 @@ function XViewScene({
11978
12002
  nodes: sceneDataRef2.current.nodes,
11979
12003
  links: sceneDataRef2.current.links,
11980
12004
  quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
11981
- quest_links: graphDataRef.current[sceneConfigId2].links
12005
+ quest_links: graphDataRef.current[sceneConfigId2].links,
12006
+ quest_counter: currentCounter + 1
12007
+ // NOVO: Incrementa o contador nos metadados
11982
12008
  };
11983
12009
  try {
11984
12010
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
12011
+ sceneDataRef2.current.quest_counter = currentCounter + 1;
11985
12012
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
11986
12013
  parentFileId: sceneConfigId2,
11987
12014
  ownerId: ownerId2,
@@ -13643,7 +13670,9 @@ function XViewScene({
13643
13670
  onMentionClick: handleAddExistingNode,
13644
13671
  onUploadFile: upload_file_action,
13645
13672
  availableNodes: allAvailableNodes,
13646
- availableAncestries: allAvailableAncestries
13673
+ availableAncestries: allAvailableAncestries,
13674
+ viewName: viewParams == null ? void 0 : viewParams.name,
13675
+ questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1
13647
13676
  }
13648
13677
  ),
13649
13678
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react26.default.createElement(
@@ -13912,7 +13941,7 @@ function XViewScene({
13912
13941
  onClose: () => setIsImportModalOpen(false),
13913
13942
  onConfirm: handleConfirmImport,
13914
13943
  session,
13915
- parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
13944
+ parentDbs: ((_h = sceneDataRef.current) == null ? void 0 : _h.parent_dbs) || [],
13916
13945
  onFetchAvailableFiles: import_parent_file_modal_get,
13917
13946
  currentViewName: viewParams == null ? void 0 : viewParams.name,
13918
13947
  currentAncestries: ancestryDataRef.current || []
package/dist/index.mjs CHANGED
@@ -2849,7 +2849,9 @@ var IGNORED_KEYS = [
2849
2849
  "is_private",
2850
2850
  "abstraction_tree",
2851
2851
  "selectedAbstractionParentId",
2852
- "isAddingAbstractionNodes"
2852
+ "isAddingAbstractionNodes",
2853
+ "status",
2854
+ "is_quest"
2853
2855
  ];
2854
2856
  function extractCustomPropsFromNode(node) {
2855
2857
  const customPropTypes = node._customPropTypes || {};
@@ -7956,10 +7958,13 @@ function InSceneQuestForm({
7956
7958
  availableAncestries = [],
7957
7959
  onMentionClick,
7958
7960
  onUploadFile,
7959
- // NOVAS PROPS PARA O GHOST NODE
7960
7961
  onNameChange,
7961
7962
  onColorChange,
7962
- onSizeChange
7963
+ onSizeChange,
7964
+ viewName = "Projeto",
7965
+ // NOVA PROP
7966
+ questCounter = 1
7967
+ // NOVA PROP
7963
7968
  }) {
7964
7969
  const [name, setName] = useState16("");
7965
7970
  const [types, setTypes] = useState16(["quest"]);
@@ -7972,6 +7977,7 @@ function InSceneQuestForm({
7972
7977
  const [customProps, setCustomProps] = useState16([]);
7973
7978
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
7974
7979
  const propsEndRef = useRef12(null);
7980
+ const standardizedName = `${viewName} - ${questCounter} - \xBB ${name || "Nova Quest"}`;
7975
7981
  const handleAddProp = () => {
7976
7982
  const newProp = createNewCustomProperty(customProps);
7977
7983
  setCustomProps([...customProps, newProp]);
@@ -8008,7 +8014,7 @@ function InSceneQuestForm({
8008
8014
  const handleSubmit = (e) => {
8009
8015
  e.preventDefault();
8010
8016
  if (!name.trim()) {
8011
- alert("O campo 'Nome' \xE9 obrigat\xF3rio.");
8017
+ alert("O campo 'T\xEDtulo' \xE9 obrigat\xF3rio.");
8012
8018
  return;
8013
8019
  }
8014
8020
  const additionalData = toObjectFromCustomProps(
@@ -8016,7 +8022,10 @@ function InSceneQuestForm({
8016
8022
  );
8017
8023
  const processedSections = processDescriptionForSave(description, []);
8018
8024
  onSave({
8019
- name: name.trim(),
8025
+ name: standardizedName,
8026
+ // SALVA O NOME FORMATADO
8027
+ raw_title: name.trim(),
8028
+ // Salva o título puro como fallback ou metadado útil
8020
8029
  type: types,
8021
8030
  color: QUEST_STATUS_COLORS[status],
8022
8031
  status,
@@ -8055,7 +8064,21 @@ function InSceneQuestForm({
8055
8064
  },
8056
8065
  "\xD7"
8057
8066
  )),
8058
- /* @__PURE__ */ React15.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ React15.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React15.createElement("div", { className: "relative" }, /* @__PURE__ */ React15.createElement(
8067
+ /* @__PURE__ */ React15.createElement("form", { onSubmit: handleSubmit, className: "flex flex-col max-h-[68vh]" }, /* @__PURE__ */ React15.createElement("div", { className: "px-6 pb-28 overflow-y-auto overscroll-contain space-y-4 custom-scrollbar" }, /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "T\xEDtulo da Quest"), /* @__PURE__ */ React15.createElement(
8068
+ "input",
8069
+ {
8070
+ required: true,
8071
+ type: "text",
8072
+ placeholder: "Ex.: Refatorar M\xF3dulo X",
8073
+ value: name,
8074
+ onChange: (e) => {
8075
+ const val = e.target.value;
8076
+ setName(val);
8077
+ onNameChange == null ? void 0 : onNameChange(`${viewName} - ${questCounter} - \xBB ${val || "Nova Quest"}`);
8078
+ },
8079
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
8080
+ }
8081
+ ), /* @__PURE__ */ React15.createElement("div", { className: "pt-1 flex items-center gap-1.5" }, /* @__PURE__ */ React15.createElement("span", { className: "text-[10px] uppercase font-bold text-slate-500 tracking-wider" }, "Preview:"), /* @__PURE__ */ React15.createElement("p", { className: "text-xs text-indigo-300 font-medium truncate", title: standardizedName }, standardizedName))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Status da Quest"), /* @__PURE__ */ React15.createElement("div", { className: "relative" }, /* @__PURE__ */ React15.createElement(
8059
8082
  "button",
8060
8083
  {
8061
8084
  type: "button",
@@ -8077,20 +8100,7 @@ function InSceneQuestForm({
8077
8100
  },
8078
8101
  /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS[s] } }),
8079
8102
  s
8080
- )))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Nome da Quest"), /* @__PURE__ */ React15.createElement(
8081
- "input",
8082
- {
8083
- required: true,
8084
- type: "text",
8085
- placeholder: "Ex.: Refatorar M\xF3dulo X",
8086
- value: name,
8087
- onChange: (e) => {
8088
- setName(e.target.value);
8089
- onNameChange == null ? void 0 : onNameChange(e.target.value);
8090
- },
8091
- className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
8092
- }
8093
- )), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
8103
+ )))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
8094
8104
  "input",
8095
8105
  {
8096
8106
  type: "text",
@@ -8912,15 +8922,28 @@ function QuestDetailsPanel({
8912
8922
  },
8913
8923
  /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
8914
8924
  s
8915
- )))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Nome"), /* @__PURE__ */ React17.createElement("input", { type: "text", value: name, onChange: handleNameChange, readOnly: !canEdit, className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none ${canEdit ? "focus:ring-2 focus:ring-indigo-400/60" : "cursor-default text-slate-400"}` })), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ React17.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React17.createElement(FiX6, { size: 12 })))), canEdit && /* @__PURE__ */ React17.createElement("input", { type: "text", value: typeInput, onChange: (e) => {
8916
- setTypeInput(e.target.value);
8917
- setShowTypeSuggestions(true);
8918
- }, onKeyDown: handleTypeInputKeyDown, onClick: () => setShowTypeSuggestions(true), onBlur: () => {
8919
- if (typeInput.trim()) {
8920
- handleAddType(typeInput);
8921
- }
8922
- setTimeout(() => setShowTypeSuggestions(false), 150);
8923
- }, className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200", placeholder: types.length === 1 ? "Ex.: Client" : "", autoComplete: "off" }), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ React17.createElement("ul", { className: "custom-scrollbar absolute top-full left-0 z-10 w-full mt-1 max-h-40 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-lg" }, filteredTypes.map((suggestedType, index) => /* @__PURE__ */ React17.createElement("li", { key: index, className: "px-3 py-2 text-sm text-slate-200 cursor-pointer hover:bg-indigo-600/50", onMouseDown: (e) => {
8925
+ )))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Nome"), /* @__PURE__ */ React17.createElement("input", { type: "text", value: name, onChange: handleNameChange, readOnly: !canEdit, className: `w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 focus:outline-none ${canEdit ? "focus:ring-2 focus:ring-indigo-400/60" : "cursor-default text-slate-400"}` })), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ React17.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React17.createElement(FiX6, { size: 12 })))), canEdit && /* @__PURE__ */ React17.createElement(
8926
+ "input",
8927
+ {
8928
+ type: "text",
8929
+ value: typeInput,
8930
+ onChange: (e) => {
8931
+ setTypeInput(e.target.value);
8932
+ setShowTypeSuggestions(true);
8933
+ },
8934
+ onKeyDown: handleTypeInputKeyDown,
8935
+ onClick: () => setShowTypeSuggestions(true),
8936
+ onBlur: () => {
8937
+ if (typeInput.trim()) {
8938
+ handleAddType(typeInput);
8939
+ }
8940
+ setTimeout(() => setShowTypeSuggestions(false), 150);
8941
+ },
8942
+ className: "flex-1 bg-transparent text-sm min-w-[80px] focus:outline-none text-slate-200",
8943
+ placeholder: "",
8944
+ autoComplete: "off"
8945
+ }
8946
+ ), canEdit && showTypeSuggestions && filteredTypes.length > 0 && /* @__PURE__ */ React17.createElement("ul", { className: "custom-scrollbar absolute top-full left-0 z-10 w-full mt-1 max-h-40 overflow-y-auto rounded-lg bg-slate-800 border border-white/10 shadow-lg" }, filteredTypes.map((suggestedType, index) => /* @__PURE__ */ React17.createElement("li", { key: index, className: "px-3 py-2 text-sm text-slate-200 cursor-pointer hover:bg-indigo-600/50", onMouseDown: (e) => {
8924
8947
  e.preventDefault();
8925
8948
  handleAddType(suggestedType);
8926
8949
  } }, suggestedType))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5 relative" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Descri\xE7\xE3o"), /* @__PURE__ */ React17.createElement("div", { className: "relative group min-h-[60px] bg-slate-800/40 rounded-lg border border-white/10 hover:border-white/20 transition-colors" }, /* @__PURE__ */ React17.createElement(DescriptionDisplay, { description, savedSections: existingSections, availableNodes, availableAncestries, onOpenReference, onMentionClick, onImageClick: handleImageClickFromText, onSaveDescription: handleSaveDescriptionInline }), /* @__PURE__ */ React17.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => setIsReadMode(true), className: `p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors ${canEdit ? "border-r border-white/5" : ""}`, title: "Modo de Leitura" }, /* @__PURE__ */ React17.createElement(FiBookOpen4, { size: 14 })), canEdit && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => setIsDescriptionModalOpen(true), className: "p-2 text-slate-400 hover:text-white hover:bg-white/10 transition-colors", title: "Editar descri\xE7\xE3o (Modo de Escrita)" }, /* @__PURE__ */ React17.createElement(FiEdit28, { size: 14 }))), canEdit && !description && /* @__PURE__ */ React17.createElement("div", { onClick: () => setIsDescriptionModalOpen(true), className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text" }, "Adicionar descri\xE7\xE3o..."))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tamanho no Node (Size)"), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-5" }, ["small", "medium", "large"].map((s) => {
@@ -10288,7 +10311,7 @@ function XViewScene({
10288
10311
  delete_file_action,
10289
10312
  check_user_permission
10290
10313
  }) {
10291
- var _a, _b, _c, _d, _e, _f, _g;
10314
+ var _a, _b, _c, _d, _e, _f, _g, _h;
10292
10315
  const { data: session, status } = useSession();
10293
10316
  const router = useRouter();
10294
10317
  const searchParams = useSearchParams();
@@ -11963,6 +11986,7 @@ function XViewScene({
11963
11986
  const handleSaveQuestNode = async (context, newQuestData) => {
11964
11987
  const { graphDataRef, sceneDataRef: sceneDataRef2, stateRef: stateRef2, setters, actions, sceneSaveUrl: sceneSaveUrl2, viewType, sceneConfigId: sceneConfigId2, ownerId: ownerId2 } = context;
11965
11988
  if (!graphDataRef.current || (viewType == null ? void 0 : viewType.toLowerCase()) !== "view") return;
11989
+ const currentCounter = sceneDataRef2.current.quest_counter || 1;
11966
11990
  const newNode = {
11967
11991
  id: short2.generate(),
11968
11992
  ...newQuestData,
@@ -11978,10 +12002,13 @@ function XViewScene({
11978
12002
  nodes: sceneDataRef2.current.nodes,
11979
12003
  links: sceneDataRef2.current.links,
11980
12004
  quest_nodes: graphDataRef.current[sceneConfigId2].nodes,
11981
- quest_links: graphDataRef.current[sceneConfigId2].links
12005
+ quest_links: graphDataRef.current[sceneConfigId2].links,
12006
+ quest_counter: currentCounter + 1
12007
+ // NOVO: Incrementa o contador nos metadados
11982
12008
  };
11983
12009
  try {
11984
12010
  await actions.save_view_data(sceneSaveUrl2, sceneFileData);
12011
+ sceneDataRef2.current.quest_counter = currentCounter + 1;
11985
12012
  stateRef2.current.nodeIdToParentFileMap.set(String(newNode.id), {
11986
12013
  parentFileId: sceneConfigId2,
11987
12014
  ownerId: ownerId2,
@@ -13643,7 +13670,9 @@ function XViewScene({
13643
13670
  onMentionClick: handleAddExistingNode,
13644
13671
  onUploadFile: upload_file_action,
13645
13672
  availableNodes: allAvailableNodes,
13646
- availableAncestries: allAvailableAncestries
13673
+ availableAncestries: allAvailableAncestries,
13674
+ viewName: viewParams == null ? void 0 : viewParams.name,
13675
+ questCounter: ((_g = sceneDataRef.current) == null ? void 0 : _g.quest_counter) || 1
13647
13676
  }
13648
13677
  ),
13649
13678
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React25.createElement(
@@ -13912,7 +13941,7 @@ function XViewScene({
13912
13941
  onClose: () => setIsImportModalOpen(false),
13913
13942
  onConfirm: handleConfirmImport,
13914
13943
  session,
13915
- parentDbs: ((_g = sceneDataRef.current) == null ? void 0 : _g.parent_dbs) || [],
13944
+ parentDbs: ((_h = sceneDataRef.current) == null ? void 0 : _h.parent_dbs) || [],
13916
13945
  onFetchAvailableFiles: import_parent_file_modal_get,
13917
13946
  currentViewName: viewParams == null ? void 0 : viewParams.name,
13918
13947
  currentAncestries: ancestryDataRef.current || []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.4-dev.23",
3
+ "version": "1.2.4-dev.25",
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",