@lv-x-software-house/x_view 1.2.6-dev.60 → 1.2.6-dev.61

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 +203 -15
  2. package/dist/index.mjs +203 -15
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8943,6 +8943,8 @@ function ColorPicker({ color, onChange, disabled, isCompact = false }) {
8943
8943
 
8944
8944
  // src/components/InSceneCreationForm.jsx
8945
8945
  var import_fi13 = require("react-icons/fi");
8946
+ var import_si = require("react-icons/si");
8947
+ var import_ai = require("react-icons/ai");
8946
8948
  function InSceneCreationForm({
8947
8949
  onSave,
8948
8950
  onCancel,
@@ -8963,7 +8965,8 @@ function InSceneCreationForm({
8963
8965
  onUploadFile,
8964
8966
  availableDatasets = [],
8965
8967
  sourceNodeDatasetId,
8966
- viewType
8968
+ viewType,
8969
+ create_google_doc_action
8967
8970
  }) {
8968
8971
  var _a;
8969
8972
  const [name, setName] = (0, import_react14.useState)("");
@@ -8983,6 +8986,7 @@ function InSceneCreationForm({
8983
8986
  sourceNodeDatasetId || ""
8984
8987
  );
8985
8988
  const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = (0, import_react14.useState)(false);
8989
+ const [isLoadingDocs, setIsLoadingDocs] = (0, import_react14.useState)(false);
8986
8990
  const datasetDropdownRef = (0, import_react14.useRef)(null);
8987
8991
  (0, import_react14.useEffect)(() => {
8988
8992
  if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
@@ -9121,6 +9125,33 @@ function InSceneCreationForm({
9121
9125
  setSelectedImageUrl(url);
9122
9126
  onImageChange == null ? void 0 : onImageChange(true, url);
9123
9127
  };
9128
+ const handleCreateGoogleDoc = async () => {
9129
+ if (!name.trim()) {
9130
+ alert("Por favor, insira um nome para o node antes de criar o documento.");
9131
+ return;
9132
+ }
9133
+ if (!create_google_doc_action) return;
9134
+ try {
9135
+ setIsLoadingDocs(true);
9136
+ const res = await create_google_doc_action(name);
9137
+ if (res.success) {
9138
+ const newProp = {
9139
+ id: (0, import_uuid5.v4)(),
9140
+ key: "Google Docs",
9141
+ type: "links",
9142
+ value: [{ id: (0, import_uuid5.v4)(), name: "Abrir Documento", value: res.link }]
9143
+ };
9144
+ setCustomProps((prev) => [...prev, newProp]);
9145
+ } else {
9146
+ alert("Erro ao criar documento: " + res.error);
9147
+ }
9148
+ } catch (error) {
9149
+ console.error(error);
9150
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
9151
+ } finally {
9152
+ setIsLoadingDocs(false);
9153
+ }
9154
+ };
9124
9155
  const handleSubmit = (e) => {
9125
9156
  e.preventDefault();
9126
9157
  if (!name.trim() || types.length === 0) {
@@ -9360,7 +9391,18 @@ function InSceneCreationForm({
9360
9391
  className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}`
9361
9392
  },
9362
9393
  useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Selecione a cor e ajuste o brilho."
9363
- )), /* @__PURE__ */ import_react14.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react14.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react14.default.createElement(
9394
+ )), /* @__PURE__ */ import_react14.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react14.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ import_react14.default.createElement(
9395
+ "button",
9396
+ {
9397
+ type: "button",
9398
+ onClick: handleCreateGoogleDoc,
9399
+ disabled: isLoadingDocs,
9400
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
9401
+ title: "Criar Documento no Google Docs"
9402
+ },
9403
+ isLoadingDocs ? /* @__PURE__ */ import_react14.default.createElement(import_ai.AiOutlineLoading3Quarters, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ import_react14.default.createElement(import_si.SiGoogledocs, { size: 14, className: "group-hover:scale-110 transition-transform" }),
9404
+ isLoadingDocs ? "Criando..." : "Google Doc"
9405
+ ), /* @__PURE__ */ import_react14.default.createElement(
9364
9406
  "button",
9365
9407
  {
9366
9408
  type: "button",
@@ -9369,7 +9411,7 @@ function InSceneCreationForm({
9369
9411
  },
9370
9412
  /* @__PURE__ */ import_react14.default.createElement(import_fi13.FiPlus, { size: 14 }),
9371
9413
  " Adicionar"
9372
- )), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ import_react14.default.createElement(
9414
+ ))), /* @__PURE__ */ import_react14.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ import_react14.default.createElement(
9373
9415
  CustomPropertyDisplay,
9374
9416
  {
9375
9417
  key: prop.id,
@@ -9738,6 +9780,8 @@ function InSceneVersionForm({
9738
9780
  var import_react17 = __toESM(require("react"));
9739
9781
  var import_uuid7 = require("uuid");
9740
9782
  var import_fi16 = require("react-icons/fi");
9783
+ var import_si2 = require("react-icons/si");
9784
+ var import_ai2 = require("react-icons/ai");
9741
9785
 
9742
9786
  // src/components/QuestReviewStackEditor.jsx
9743
9787
  var import_react16 = __toESM(require("react"));
@@ -9919,7 +9963,8 @@ function InSceneQuestForm({
9919
9963
  session = null,
9920
9964
  milestones = [],
9921
9965
  onUpdateMilestones = () => {
9922
- }
9966
+ },
9967
+ create_google_doc_action
9923
9968
  }) {
9924
9969
  var _a, _b;
9925
9970
  const [name, setName] = (0, import_react17.useState)("");
@@ -9947,6 +9992,7 @@ function InSceneQuestForm({
9947
9992
  const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = (0, import_react17.useState)(false);
9948
9993
  const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react17.useState)("");
9949
9994
  const [isNameCopied, setIsNameCopied] = (0, import_react17.useState)(false);
9995
+ const [isLoadingDocs, setIsLoadingDocs] = (0, import_react17.useState)(false);
9950
9996
  const [customProps, setCustomProps] = (0, import_react17.useState)([]);
9951
9997
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react17.useState)(false);
9952
9998
  const propsEndRef = (0, import_react17.useRef)(null);
@@ -10034,6 +10080,33 @@ function InSceneQuestForm({
10034
10080
  console.error("Erro ao copiar nome:", err);
10035
10081
  });
10036
10082
  };
10083
+ const handleCreateGoogleDoc = async () => {
10084
+ if (!name.trim()) {
10085
+ alert("Por favor, insira um t\xEDtulo para a quest antes de criar o documento.");
10086
+ return;
10087
+ }
10088
+ if (!create_google_doc_action) return;
10089
+ try {
10090
+ setIsLoadingDocs(true);
10091
+ const res = await create_google_doc_action(standardizedName);
10092
+ if (res.success) {
10093
+ const newProp = {
10094
+ id: (0, import_uuid7.v4)(),
10095
+ key: "Google Docs",
10096
+ type: "links",
10097
+ value: [{ id: (0, import_uuid7.v4)(), name: "Abrir Documento", value: res.link }]
10098
+ };
10099
+ setCustomProps((prev) => [...prev, newProp]);
10100
+ } else {
10101
+ alert("Erro ao criar documento: " + res.error);
10102
+ }
10103
+ } catch (error) {
10104
+ console.error(error);
10105
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
10106
+ } finally {
10107
+ setIsLoadingDocs(false);
10108
+ }
10109
+ };
10037
10110
  const handleAddProp = () => {
10038
10111
  const newProp = createNewCustomProperty(customProps);
10039
10112
  setCustomProps([...customProps, newProp]);
@@ -10552,7 +10625,18 @@ function InSceneQuestForm({
10552
10625
  className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
10553
10626
  },
10554
10627
  "Adicionar descri\xE7\xE3o..."
10555
- ))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react17.default.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react17.default.createElement(
10628
+ ))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react17.default.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ import_react17.default.createElement(
10629
+ "button",
10630
+ {
10631
+ type: "button",
10632
+ onClick: handleCreateGoogleDoc,
10633
+ disabled: isLoadingDocs,
10634
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
10635
+ title: "Criar Documento no Google Docs"
10636
+ },
10637
+ isLoadingDocs ? /* @__PURE__ */ import_react17.default.createElement(import_ai2.AiOutlineLoading3Quarters, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ import_react17.default.createElement(import_si2.SiGoogledocs, { size: 14, className: "group-hover:scale-110 transition-transform" }),
10638
+ isLoadingDocs ? "Criando..." : "Google Doc"
10639
+ ), /* @__PURE__ */ import_react17.default.createElement(
10556
10640
  "button",
10557
10641
  {
10558
10642
  type: "button",
@@ -10561,7 +10645,7 @@ function InSceneQuestForm({
10561
10645
  },
10562
10646
  /* @__PURE__ */ import_react17.default.createElement(import_fi16.FiPlus, { size: 14 }),
10563
10647
  " Adicionar"
10564
- )), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ import_react17.default.createElement(
10648
+ ))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ import_react17.default.createElement(
10565
10649
  CustomPropertyDisplay,
10566
10650
  {
10567
10651
  key: prop.id,
@@ -10663,6 +10747,8 @@ function InSceneQuestForm({
10663
10747
  var import_react18 = __toESM(require("react"));
10664
10748
  var import_uuid8 = require("uuid");
10665
10749
  var import_fi17 = require("react-icons/fi");
10750
+ var import_si3 = require("react-icons/si");
10751
+ var import_ai3 = require("react-icons/ai");
10666
10752
  function NodeDetailsPanel({
10667
10753
  node,
10668
10754
  onClose,
@@ -10681,7 +10767,8 @@ function NodeDetailsPanel({
10681
10767
  onIntensityChange,
10682
10768
  onUploadFile,
10683
10769
  userRole,
10684
- currentDatasetName
10770
+ currentDatasetName,
10771
+ create_google_doc_action
10685
10772
  }) {
10686
10773
  const [name, setName] = (0, import_react18.useState)((node == null ? void 0 : node.name) ?? "");
10687
10774
  const [types, setTypes] = (0, import_react18.useState)([]);
@@ -10697,6 +10784,7 @@ function NodeDetailsPanel({
10697
10784
  const [isReadMode, setIsReadMode] = (0, import_react18.useState)(false);
10698
10785
  const [existingSections, setExistingSections] = (0, import_react18.useState)((node == null ? void 0 : node.description_sections) || []);
10699
10786
  const [isSaving, setIsSaving] = (0, import_react18.useState)(false);
10787
+ const [isLoadingDocs, setIsLoadingDocs] = (0, import_react18.useState)(false);
10700
10788
  const [isLinkCopied, setIsLinkCopied] = (0, import_react18.useState)(false);
10701
10789
  const [useImageAsTexture, setUseImageAsTexture] = (0, import_react18.useState)(() => {
10702
10790
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
@@ -10851,6 +10939,36 @@ function NodeDetailsPanel({
10851
10939
  triggerAutoSave({ customProps: newProps });
10852
10940
  }
10853
10941
  };
10942
+ const handleCreateGoogleDoc = async () => {
10943
+ if (!name.trim()) {
10944
+ alert("Por favor, insira um nome para o node antes de criar o documento.");
10945
+ return;
10946
+ }
10947
+ if (!create_google_doc_action) return;
10948
+ try {
10949
+ setIsLoadingDocs(true);
10950
+ const res = await create_google_doc_action(name);
10951
+ if (res.success) {
10952
+ const newProp = {
10953
+ id: (0, import_uuid8.v4)(),
10954
+ key: "Google Docs",
10955
+ type: "links",
10956
+ value: [{ id: (0, import_uuid8.v4)(), name: "Abrir Documento", value: res.link }]
10957
+ };
10958
+ const updatedProps = [...customProps, newProp];
10959
+ setCustomProps(updatedProps);
10960
+ setHasUnsavedChanges(true);
10961
+ triggerAutoSave({ customProps: updatedProps });
10962
+ } else {
10963
+ alert("Erro ao criar documento: " + res.error);
10964
+ }
10965
+ } catch (error) {
10966
+ console.error(error);
10967
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
10968
+ } finally {
10969
+ setIsLoadingDocs(false);
10970
+ }
10971
+ };
10854
10972
  const handleToggleImageMode = () => {
10855
10973
  setUseImageAsTexture(newValue);
10856
10974
  setHasUnsavedChanges(true);
@@ -11127,7 +11245,27 @@ function NodeDetailsPanel({
11127
11245
  className: `w-full h-1.5 bg-slate-700 rounded-lg appearance-none ${canEdit ? "cursor-pointer accent-indigo-500 hover:accent-indigo-400" : "cursor-default accent-slate-500"}`,
11128
11246
  title: `Intensidade do brilho: ${intensity}`
11129
11247
  }
11130
- ), /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ import_react18.default.createElement("span", { className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}` }, useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Ajuste a cor e a intensidade do brilho.")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react18.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(import_fi17.FiPlus, { size: 14 }), " Adicionar")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react18.default.createElement(
11248
+ ), /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ import_react18.default.createElement("span", { className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}` }, useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Ajuste a cor e a intensidade do brilho.")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react18.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ import_react18.default.createElement(
11249
+ "button",
11250
+ {
11251
+ type: "button",
11252
+ onClick: handleCreateGoogleDoc,
11253
+ disabled: isLoadingDocs,
11254
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
11255
+ title: "Criar Documento no Google Docs"
11256
+ },
11257
+ isLoadingDocs ? /* @__PURE__ */ import_react18.default.createElement(import_ai3.AiOutlineLoading3Quarters, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ import_react18.default.createElement(import_si3.SiGoogledocs, { size: 14, className: "group-hover:scale-110 transition-transform" }),
11258
+ isLoadingDocs ? "Criando..." : "Google Doc"
11259
+ ), canEdit && /* @__PURE__ */ import_react18.default.createElement(
11260
+ "button",
11261
+ {
11262
+ type: "button",
11263
+ onClick: handleAddProp,
11264
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors"
11265
+ },
11266
+ /* @__PURE__ */ import_react18.default.createElement(import_fi17.FiPlus, { size: 14 }),
11267
+ " Adicionar"
11268
+ ))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react18.default.createElement(
11131
11269
  CustomPropertyDisplay,
11132
11270
  {
11133
11271
  key: prop.id,
@@ -11251,6 +11389,8 @@ function QuestTimeline({
11251
11389
  }
11252
11390
 
11253
11391
  // src/components/QuestDetailsPanel.jsx
11392
+ var import_si4 = require("react-icons/si");
11393
+ var import_ai4 = require("react-icons/ai");
11254
11394
  var QUEST_STATUS_COLORS3 = {
11255
11395
  "Backlog": "#64748b",
11256
11396
  "In Progress": "#eab308",
@@ -11279,7 +11419,8 @@ function QuestDetailsPanel({
11279
11419
  milestones = [],
11280
11420
  onUpdateMilestones = () => {
11281
11421
  },
11282
- onFocusNode
11422
+ onFocusNode,
11423
+ create_google_doc_action
11283
11424
  }) {
11284
11425
  var _a, _b;
11285
11426
  const initialRawTitle = (node == null ? void 0 : node.raw_title) || (((_a = node == null ? void 0 : node.name) == null ? void 0 : _a.includes(" - \xBB ")) ? node.name.split(" - \xBB ")[1] : node == null ? void 0 : node.name) || "";
@@ -11313,6 +11454,7 @@ function QuestDetailsPanel({
11313
11454
  const [isSaving, setIsSaving] = (0, import_react20.useState)(false);
11314
11455
  const [isLinkCopied, setIsLinkCopied] = (0, import_react20.useState)(false);
11315
11456
  const [isNameCopied, setIsNameCopied] = (0, import_react20.useState)(false);
11457
+ const [isLoadingDocs, setIsLoadingDocs] = (0, import_react20.useState)(false);
11316
11458
  const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react20.useState)(false);
11317
11459
  const [questDate, setQuestDate] = (0, import_react20.useState)((node == null ? void 0 : node.Date) || null);
11318
11460
  const [noteText, setNoteText] = (0, import_react20.useState)("");
@@ -11713,6 +11855,36 @@ ${noteText}` : noteText : entry.notes,
11713
11855
  triggerAutoSave({ customProps: newProps });
11714
11856
  }
11715
11857
  };
11858
+ const handleCreateGoogleDoc = async () => {
11859
+ if (!rawTitle.trim()) {
11860
+ alert("Por favor, insira um t\xEDtulo para a quest antes de criar o documento.");
11861
+ return;
11862
+ }
11863
+ if (!create_google_doc_action) return;
11864
+ try {
11865
+ setIsLoadingDocs(true);
11866
+ const res = await create_google_doc_action(standardizedName);
11867
+ if (res.success) {
11868
+ const newProp = {
11869
+ id: (0, import_uuid9.v4)(),
11870
+ key: "Google Docs",
11871
+ type: "links",
11872
+ value: [{ id: (0, import_uuid9.v4)(), name: "Abrir Documento", value: res.link }]
11873
+ };
11874
+ const updatedProps = [...customProps, newProp];
11875
+ setCustomProps(updatedProps);
11876
+ setHasUnsavedChanges(true);
11877
+ triggerAutoSave({ customProps: updatedProps });
11878
+ } else {
11879
+ alert("Erro ao criar documento: " + res.error);
11880
+ }
11881
+ } catch (error) {
11882
+ console.error(error);
11883
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
11884
+ } finally {
11885
+ setIsLoadingDocs(false);
11886
+ }
11887
+ };
11716
11888
  const handleSaveDescriptionInline = (newDescription) => {
11717
11889
  setDescription(newDescription);
11718
11890
  setHasUnsavedChanges(true);
@@ -12318,7 +12490,18 @@ ${noteText}` : noteText : entry.notes,
12318
12490
  },
12319
12491
  /* @__PURE__ */ import_react20.default.createElement("span", { className: "truncate" }, q.raw_title || q.name),
12320
12492
  /* @__PURE__ */ import_react20.default.createElement("span", { className: `text-[10px] px-1.5 py-0.5 rounded border ${q.status === "Done" ? "text-green-400 border-green-500/30" : "text-slate-500 border-white/5"}` }, q.status || "Backlog")
12321
- )) : /* @__PURE__ */ import_react20.default.createElement("li", { className: "px-3 py-3 text-[10px] text-slate-500 italic text-center" }, "Nenhuma outra quest dispon\xEDvel")))), blockedStatus.isBlocked && /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2 px-3 py-2 bg-amber-500/5 rounded-lg border border-amber-500/10 animate-in fade-in slide-in-from-top-1" }, /* @__PURE__ */ import_react20.default.createElement(import_fi19.FiRepeat, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-[10px] text-amber-200/80 font-medium" }, "Esta quest est\xE1 bloqueada por ", blockedStatus.pendingDependencies.length, " tarefa(s) pendente(s)."))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react20.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ import_react20.default.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ import_react20.default.createElement(import_fi19.FiPlus, { size: 14 }), " Adicionar")), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react20.default.createElement(CustomPropertyDisplay, { key: prop.id, prop, onUpdate: canEdit ? (updatedProp) => handleUpdateProp(idx, updatedProp) : void 0, onRemove: canEdit ? () => handleRemoveProp(idx) : void 0, onOpenImageViewer, unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type), isTextureMode: false, onUploadFile: canEdit ? onUploadFile : void 0, readOnly: !canEdit })), /* @__PURE__ */ import_react20.default.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ import_react20.default.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ import_react20.default.createElement(
12493
+ )) : /* @__PURE__ */ import_react20.default.createElement("li", { className: "px-3 py-3 text-[10px] text-slate-500 italic text-center" }, "Nenhuma outra quest dispon\xEDvel")))), blockedStatus.isBlocked && /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2 px-3 py-2 bg-amber-500/5 rounded-lg border border-amber-500/10 animate-in fade-in slide-in-from-top-1" }, /* @__PURE__ */ import_react20.default.createElement(import_fi19.FiRepeat, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ import_react20.default.createElement("p", { className: "text-[10px] text-amber-200/80 font-medium" }, "Esta quest est\xE1 bloqueada por ", blockedStatus.pendingDependencies.length, " tarefa(s) pendente(s)."))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react20.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ import_react20.default.createElement(
12494
+ "button",
12495
+ {
12496
+ type: "button",
12497
+ onClick: handleCreateGoogleDoc,
12498
+ disabled: isLoadingDocs,
12499
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
12500
+ title: "Criar Documento no Google Docs"
12501
+ },
12502
+ isLoadingDocs ? /* @__PURE__ */ import_react20.default.createElement(import_ai4.AiOutlineLoading3Quarters, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ import_react20.default.createElement(import_si4.SiGoogledocs, { size: 14, className: "group-hover:scale-110 transition-transform" }),
12503
+ isLoadingDocs ? "Criando..." : "Google Doc"
12504
+ ), canEdit && /* @__PURE__ */ import_react20.default.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ import_react20.default.createElement(import_fi19.FiPlus, { size: 14 }), " Adicionar"))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react20.default.createElement(CustomPropertyDisplay, { key: prop.id, prop, onUpdate: canEdit ? (updatedProp) => handleUpdateProp(idx, updatedProp) : void 0, onRemove: canEdit ? () => handleRemoveProp(idx) : void 0, onOpenImageViewer, unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type), isTextureMode: false, onUploadFile: canEdit ? onUploadFile : void 0, readOnly: !canEdit })), /* @__PURE__ */ import_react20.default.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ import_react20.default.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ import_react20.default.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ import_react20.default.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ import_react20.default.createElement(
12322
12505
  "button",
12323
12506
  {
12324
12507
  type: "button",
@@ -14556,7 +14739,8 @@ function XViewScene({
14556
14739
  upload_file_action,
14557
14740
  delete_file_action,
14558
14741
  check_user_permission,
14559
- get_view_members
14742
+ get_view_members,
14743
+ create_google_doc_action
14560
14744
  }) {
14561
14745
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
14562
14746
  const { data: session, status } = (0, import_react32.useSession)();
@@ -19276,7 +19460,8 @@ function XViewScene({
19276
19460
  sourceNodeDatasetId,
19277
19461
  viewType: viewParams == null ? void 0 : viewParams.type,
19278
19462
  availableNodes: allAvailableNodes,
19279
- availableAncestries: allAvailableAncestries
19463
+ availableAncestries: allAvailableAncestries,
19464
+ create_google_doc_action
19280
19465
  }
19281
19466
  ),
19282
19467
  versionMode.isActive && /* @__PURE__ */ import_react31.default.createElement(
@@ -19330,7 +19515,8 @@ function XViewScene({
19330
19515
  questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
19331
19516
  viewMembers,
19332
19517
  milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
19333
- onUpdateMilestones: handleUpdateMilestones
19518
+ onUpdateMilestones: handleUpdateMilestones,
19519
+ create_google_doc_action
19334
19520
  }
19335
19521
  ),
19336
19522
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react31.default.createElement(
@@ -19465,7 +19651,8 @@ function XViewScene({
19465
19651
  viewMembers,
19466
19652
  currentUser: session == null ? void 0 : session.user,
19467
19653
  milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
19468
- onUpdateMilestones: handleUpdateMilestones
19654
+ onUpdateMilestones: handleUpdateMilestones,
19655
+ create_google_doc_action
19469
19656
  }
19470
19657
  ),
19471
19658
  detailsNode && !detailsNode.is_quest && /* @__PURE__ */ import_react31.default.createElement(
@@ -19497,7 +19684,8 @@ function XViewScene({
19497
19684
  onIntensityChange: handleDetailNodeIntensityChange,
19498
19685
  onUploadFile: upload_file_action,
19499
19686
  userRole: userPermissionRole,
19500
- currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
19687
+ currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
19688
+ create_google_doc_action
19501
19689
  }
19502
19690
  ),
19503
19691
  detailsLink && /* @__PURE__ */ import_react31.default.createElement(
package/dist/index.mjs CHANGED
@@ -8943,6 +8943,8 @@ import {
8943
8943
  FiSun,
8944
8944
  FiChevronDown as FiChevronDown4
8945
8945
  } from "react-icons/fi";
8946
+ import { SiGoogledocs } from "react-icons/si";
8947
+ import { AiOutlineLoading3Quarters } from "react-icons/ai";
8946
8948
  function InSceneCreationForm({
8947
8949
  onSave,
8948
8950
  onCancel,
@@ -8963,7 +8965,8 @@ function InSceneCreationForm({
8963
8965
  onUploadFile,
8964
8966
  availableDatasets = [],
8965
8967
  sourceNodeDatasetId,
8966
- viewType
8968
+ viewType,
8969
+ create_google_doc_action
8967
8970
  }) {
8968
8971
  var _a;
8969
8972
  const [name, setName] = useState14("");
@@ -8983,6 +8986,7 @@ function InSceneCreationForm({
8983
8986
  sourceNodeDatasetId || ""
8984
8987
  );
8985
8988
  const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
8989
+ const [isLoadingDocs, setIsLoadingDocs] = useState14(false);
8986
8990
  const datasetDropdownRef = useRef10(null);
8987
8991
  useEffect13(() => {
8988
8992
  if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
@@ -9121,6 +9125,33 @@ function InSceneCreationForm({
9121
9125
  setSelectedImageUrl(url);
9122
9126
  onImageChange == null ? void 0 : onImageChange(true, url);
9123
9127
  };
9128
+ const handleCreateGoogleDoc = async () => {
9129
+ if (!name.trim()) {
9130
+ alert("Por favor, insira um nome para o node antes de criar o documento.");
9131
+ return;
9132
+ }
9133
+ if (!create_google_doc_action) return;
9134
+ try {
9135
+ setIsLoadingDocs(true);
9136
+ const res = await create_google_doc_action(name);
9137
+ if (res.success) {
9138
+ const newProp = {
9139
+ id: uuidv45(),
9140
+ key: "Google Docs",
9141
+ type: "links",
9142
+ value: [{ id: uuidv45(), name: "Abrir Documento", value: res.link }]
9143
+ };
9144
+ setCustomProps((prev) => [...prev, newProp]);
9145
+ } else {
9146
+ alert("Erro ao criar documento: " + res.error);
9147
+ }
9148
+ } catch (error) {
9149
+ console.error(error);
9150
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
9151
+ } finally {
9152
+ setIsLoadingDocs(false);
9153
+ }
9154
+ };
9124
9155
  const handleSubmit = (e) => {
9125
9156
  e.preventDefault();
9126
9157
  if (!name.trim() || types.length === 0) {
@@ -9360,7 +9391,18 @@ function InSceneCreationForm({
9360
9391
  className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}`
9361
9392
  },
9362
9393
  useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Selecione a cor e ajuste o brilho."
9363
- )), /* @__PURE__ */ React13.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React13.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React13.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React13.createElement(
9394
+ )), /* @__PURE__ */ React13.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React13.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React13.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React13.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ React13.createElement(
9395
+ "button",
9396
+ {
9397
+ type: "button",
9398
+ onClick: handleCreateGoogleDoc,
9399
+ disabled: isLoadingDocs,
9400
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
9401
+ title: "Criar Documento no Google Docs"
9402
+ },
9403
+ isLoadingDocs ? /* @__PURE__ */ React13.createElement(AiOutlineLoading3Quarters, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ React13.createElement(SiGoogledocs, { size: 14, className: "group-hover:scale-110 transition-transform" }),
9404
+ isLoadingDocs ? "Criando..." : "Google Doc"
9405
+ ), /* @__PURE__ */ React13.createElement(
9364
9406
  "button",
9365
9407
  {
9366
9408
  type: "button",
@@ -9369,7 +9411,7 @@ function InSceneCreationForm({
9369
9411
  },
9370
9412
  /* @__PURE__ */ React13.createElement(FiPlus3, { size: 14 }),
9371
9413
  " Adicionar"
9372
- )), /* @__PURE__ */ React13.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React13.createElement(
9414
+ ))), /* @__PURE__ */ React13.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React13.createElement(
9373
9415
  CustomPropertyDisplay,
9374
9416
  {
9375
9417
  key: prop.id,
@@ -9750,6 +9792,8 @@ import {
9750
9792
  FiRepeat,
9751
9793
  FiCopy as FiCopy3
9752
9794
  } from "react-icons/fi";
9795
+ import { SiGoogledocs as SiGoogledocs2 } from "react-icons/si";
9796
+ import { AiOutlineLoading3Quarters as AiOutlineLoading3Quarters2 } from "react-icons/ai";
9753
9797
 
9754
9798
  // src/components/QuestReviewStackEditor.jsx
9755
9799
  import React15, { useState as useState16 } from "react";
@@ -9939,7 +9983,8 @@ function InSceneQuestForm({
9939
9983
  session = null,
9940
9984
  milestones = [],
9941
9985
  onUpdateMilestones = () => {
9942
- }
9986
+ },
9987
+ create_google_doc_action
9943
9988
  }) {
9944
9989
  var _a, _b;
9945
9990
  const [name, setName] = useState17("");
@@ -9967,6 +10012,7 @@ function InSceneQuestForm({
9967
10012
  const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = useState17(false);
9968
10013
  const [assigneeSearchQuery, setAssigneeSearchQuery] = useState17("");
9969
10014
  const [isNameCopied, setIsNameCopied] = useState17(false);
10015
+ const [isLoadingDocs, setIsLoadingDocs] = useState17(false);
9970
10016
  const [customProps, setCustomProps] = useState17([]);
9971
10017
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState17(false);
9972
10018
  const propsEndRef = useRef12(null);
@@ -10054,6 +10100,33 @@ function InSceneQuestForm({
10054
10100
  console.error("Erro ao copiar nome:", err);
10055
10101
  });
10056
10102
  };
10103
+ const handleCreateGoogleDoc = async () => {
10104
+ if (!name.trim()) {
10105
+ alert("Por favor, insira um t\xEDtulo para a quest antes de criar o documento.");
10106
+ return;
10107
+ }
10108
+ if (!create_google_doc_action) return;
10109
+ try {
10110
+ setIsLoadingDocs(true);
10111
+ const res = await create_google_doc_action(standardizedName);
10112
+ if (res.success) {
10113
+ const newProp = {
10114
+ id: uuidv47(),
10115
+ key: "Google Docs",
10116
+ type: "links",
10117
+ value: [{ id: uuidv47(), name: "Abrir Documento", value: res.link }]
10118
+ };
10119
+ setCustomProps((prev) => [...prev, newProp]);
10120
+ } else {
10121
+ alert("Erro ao criar documento: " + res.error);
10122
+ }
10123
+ } catch (error) {
10124
+ console.error(error);
10125
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
10126
+ } finally {
10127
+ setIsLoadingDocs(false);
10128
+ }
10129
+ };
10057
10130
  const handleAddProp = () => {
10058
10131
  const newProp = createNewCustomProperty(customProps);
10059
10132
  setCustomProps([...customProps, newProp]);
@@ -10572,7 +10645,18 @@ function InSceneQuestForm({
10572
10645
  className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
10573
10646
  },
10574
10647
  "Adicionar descri\xE7\xE3o..."
10575
- ))), /* @__PURE__ */ React16.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React16.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ React16.createElement(
10648
+ ))), /* @__PURE__ */ React16.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React16.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React16.createElement("h3", { className: "text-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ React16.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ React16.createElement(
10649
+ "button",
10650
+ {
10651
+ type: "button",
10652
+ onClick: handleCreateGoogleDoc,
10653
+ disabled: isLoadingDocs,
10654
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
10655
+ title: "Criar Documento no Google Docs"
10656
+ },
10657
+ isLoadingDocs ? /* @__PURE__ */ React16.createElement(AiOutlineLoading3Quarters2, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ React16.createElement(SiGoogledocs2, { size: 14, className: "group-hover:scale-110 transition-transform" }),
10658
+ isLoadingDocs ? "Criando..." : "Google Doc"
10659
+ ), /* @__PURE__ */ React16.createElement(
10576
10660
  "button",
10577
10661
  {
10578
10662
  type: "button",
@@ -10581,7 +10665,7 @@ function InSceneQuestForm({
10581
10665
  },
10582
10666
  /* @__PURE__ */ React16.createElement(FiPlus6, { size: 14 }),
10583
10667
  " Adicionar"
10584
- )), /* @__PURE__ */ React16.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React16.createElement(
10668
+ ))), /* @__PURE__ */ React16.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, index) => /* @__PURE__ */ React16.createElement(
10585
10669
  CustomPropertyDisplay,
10586
10670
  {
10587
10671
  key: prop.id,
@@ -10683,6 +10767,8 @@ function InSceneQuestForm({
10683
10767
  import React17, { useState as useState18, useEffect as useEffect15, useRef as useRef13 } from "react";
10684
10768
  import { v4 as uuidv48 } from "uuid";
10685
10769
  import { FiPlus as FiPlus7, FiMaximize2 as FiMaximize23, FiX as FiX6, FiCheck as FiCheck10, FiImage as FiImage3, FiEdit2 as FiEdit27, FiLoader as FiLoader2, FiBookOpen as FiBookOpen3, FiSun as FiSun2, FiLink as FiLink5, FiDatabase } from "react-icons/fi";
10770
+ import { SiGoogledocs as SiGoogledocs3 } from "react-icons/si";
10771
+ import { AiOutlineLoading3Quarters as AiOutlineLoading3Quarters3 } from "react-icons/ai";
10686
10772
  function NodeDetailsPanel({
10687
10773
  node,
10688
10774
  onClose,
@@ -10701,7 +10787,8 @@ function NodeDetailsPanel({
10701
10787
  onIntensityChange,
10702
10788
  onUploadFile,
10703
10789
  userRole,
10704
- currentDatasetName
10790
+ currentDatasetName,
10791
+ create_google_doc_action
10705
10792
  }) {
10706
10793
  const [name, setName] = useState18((node == null ? void 0 : node.name) ?? "");
10707
10794
  const [types, setTypes] = useState18([]);
@@ -10717,6 +10804,7 @@ function NodeDetailsPanel({
10717
10804
  const [isReadMode, setIsReadMode] = useState18(false);
10718
10805
  const [existingSections, setExistingSections] = useState18((node == null ? void 0 : node.description_sections) || []);
10719
10806
  const [isSaving, setIsSaving] = useState18(false);
10807
+ const [isLoadingDocs, setIsLoadingDocs] = useState18(false);
10720
10808
  const [isLinkCopied, setIsLinkCopied] = useState18(false);
10721
10809
  const [useImageAsTexture, setUseImageAsTexture] = useState18(() => {
10722
10810
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
@@ -10871,6 +10959,36 @@ function NodeDetailsPanel({
10871
10959
  triggerAutoSave({ customProps: newProps });
10872
10960
  }
10873
10961
  };
10962
+ const handleCreateGoogleDoc = async () => {
10963
+ if (!name.trim()) {
10964
+ alert("Por favor, insira um nome para o node antes de criar o documento.");
10965
+ return;
10966
+ }
10967
+ if (!create_google_doc_action) return;
10968
+ try {
10969
+ setIsLoadingDocs(true);
10970
+ const res = await create_google_doc_action(name);
10971
+ if (res.success) {
10972
+ const newProp = {
10973
+ id: uuidv48(),
10974
+ key: "Google Docs",
10975
+ type: "links",
10976
+ value: [{ id: uuidv48(), name: "Abrir Documento", value: res.link }]
10977
+ };
10978
+ const updatedProps = [...customProps, newProp];
10979
+ setCustomProps(updatedProps);
10980
+ setHasUnsavedChanges(true);
10981
+ triggerAutoSave({ customProps: updatedProps });
10982
+ } else {
10983
+ alert("Erro ao criar documento: " + res.error);
10984
+ }
10985
+ } catch (error) {
10986
+ console.error(error);
10987
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
10988
+ } finally {
10989
+ setIsLoadingDocs(false);
10990
+ }
10991
+ };
10874
10992
  const handleToggleImageMode = () => {
10875
10993
  setUseImageAsTexture(newValue);
10876
10994
  setHasUnsavedChanges(true);
@@ -11147,7 +11265,27 @@ function NodeDetailsPanel({
11147
11265
  className: `w-full h-1.5 bg-slate-700 rounded-lg appearance-none ${canEdit ? "cursor-pointer accent-indigo-500 hover:accent-indigo-400" : "cursor-default accent-slate-500"}`,
11148
11266
  title: `Intensidade do brilho: ${intensity}`
11149
11267
  }
11150
- ), /* @__PURE__ */ React17.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ React17.createElement("span", { className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}` }, useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Ajuste a cor e a intensidade do brilho.")), /* @__PURE__ */ React17.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React17.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React17.createElement(FiPlus7, { size: 14 }), " Adicionar")), /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React17.createElement(
11268
+ ), /* @__PURE__ */ React17.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ React17.createElement("span", { className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}` }, useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Ajuste a cor e a intensidade do brilho.")), /* @__PURE__ */ React17.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React17.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React17.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ React17.createElement(
11269
+ "button",
11270
+ {
11271
+ type: "button",
11272
+ onClick: handleCreateGoogleDoc,
11273
+ disabled: isLoadingDocs,
11274
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
11275
+ title: "Criar Documento no Google Docs"
11276
+ },
11277
+ isLoadingDocs ? /* @__PURE__ */ React17.createElement(AiOutlineLoading3Quarters3, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ React17.createElement(SiGoogledocs3, { size: 14, className: "group-hover:scale-110 transition-transform" }),
11278
+ isLoadingDocs ? "Criando..." : "Google Doc"
11279
+ ), canEdit && /* @__PURE__ */ React17.createElement(
11280
+ "button",
11281
+ {
11282
+ type: "button",
11283
+ onClick: handleAddProp,
11284
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors"
11285
+ },
11286
+ /* @__PURE__ */ React17.createElement(FiPlus7, { size: 14 }),
11287
+ " Adicionar"
11288
+ ))), /* @__PURE__ */ React17.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React17.createElement(
11151
11289
  CustomPropertyDisplay,
11152
11290
  {
11153
11291
  key: prop.id,
@@ -11283,6 +11421,8 @@ function QuestTimeline({
11283
11421
  }
11284
11422
 
11285
11423
  // src/components/QuestDetailsPanel.jsx
11424
+ import { SiGoogledocs as SiGoogledocs4 } from "react-icons/si";
11425
+ import { AiOutlineLoading3Quarters as AiOutlineLoading3Quarters4 } from "react-icons/ai";
11286
11426
  var QUEST_STATUS_COLORS3 = {
11287
11427
  "Backlog": "#64748b",
11288
11428
  "In Progress": "#eab308",
@@ -11311,7 +11451,8 @@ function QuestDetailsPanel({
11311
11451
  milestones = [],
11312
11452
  onUpdateMilestones = () => {
11313
11453
  },
11314
- onFocusNode
11454
+ onFocusNode,
11455
+ create_google_doc_action
11315
11456
  }) {
11316
11457
  var _a, _b;
11317
11458
  const initialRawTitle = (node == null ? void 0 : node.raw_title) || (((_a = node == null ? void 0 : node.name) == null ? void 0 : _a.includes(" - \xBB ")) ? node.name.split(" - \xBB ")[1] : node == null ? void 0 : node.name) || "";
@@ -11345,6 +11486,7 @@ function QuestDetailsPanel({
11345
11486
  const [isSaving, setIsSaving] = useState19(false);
11346
11487
  const [isLinkCopied, setIsLinkCopied] = useState19(false);
11347
11488
  const [isNameCopied, setIsNameCopied] = useState19(false);
11489
+ const [isLoadingDocs, setIsLoadingDocs] = useState19(false);
11348
11490
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState19(false);
11349
11491
  const [questDate, setQuestDate] = useState19((node == null ? void 0 : node.Date) || null);
11350
11492
  const [noteText, setNoteText] = useState19("");
@@ -11745,6 +11887,36 @@ ${noteText}` : noteText : entry.notes,
11745
11887
  triggerAutoSave({ customProps: newProps });
11746
11888
  }
11747
11889
  };
11890
+ const handleCreateGoogleDoc = async () => {
11891
+ if (!rawTitle.trim()) {
11892
+ alert("Por favor, insira um t\xEDtulo para a quest antes de criar o documento.");
11893
+ return;
11894
+ }
11895
+ if (!create_google_doc_action) return;
11896
+ try {
11897
+ setIsLoadingDocs(true);
11898
+ const res = await create_google_doc_action(standardizedName);
11899
+ if (res.success) {
11900
+ const newProp = {
11901
+ id: uuidv49(),
11902
+ key: "Google Docs",
11903
+ type: "links",
11904
+ value: [{ id: uuidv49(), name: "Abrir Documento", value: res.link }]
11905
+ };
11906
+ const updatedProps = [...customProps, newProp];
11907
+ setCustomProps(updatedProps);
11908
+ setHasUnsavedChanges(true);
11909
+ triggerAutoSave({ customProps: updatedProps });
11910
+ } else {
11911
+ alert("Erro ao criar documento: " + res.error);
11912
+ }
11913
+ } catch (error) {
11914
+ console.error(error);
11915
+ alert("Erro ao processar cria\xE7\xE3o do documento.");
11916
+ } finally {
11917
+ setIsLoadingDocs(false);
11918
+ }
11919
+ };
11748
11920
  const handleSaveDescriptionInline = (newDescription) => {
11749
11921
  setDescription(newDescription);
11750
11922
  setHasUnsavedChanges(true);
@@ -12350,7 +12522,18 @@ ${noteText}` : noteText : entry.notes,
12350
12522
  },
12351
12523
  /* @__PURE__ */ React19.createElement("span", { className: "truncate" }, q.raw_title || q.name),
12352
12524
  /* @__PURE__ */ React19.createElement("span", { className: `text-[10px] px-1.5 py-0.5 rounded border ${q.status === "Done" ? "text-green-400 border-green-500/30" : "text-slate-500 border-white/5"}` }, q.status || "Backlog")
12353
- )) : /* @__PURE__ */ React19.createElement("li", { className: "px-3 py-3 text-[10px] text-slate-500 italic text-center" }, "Nenhuma outra quest dispon\xEDvel")))), blockedStatus.isBlocked && /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2 px-3 py-2 bg-amber-500/5 rounded-lg border border-amber-500/10 animate-in fade-in slide-in-from-top-1" }, /* @__PURE__ */ React19.createElement(FiRepeat2, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ React19.createElement("p", { className: "text-[10px] text-amber-200/80 font-medium" }, "Esta quest est\xE1 bloqueada por ", blockedStatus.pendingDependencies.length, " tarefa(s) pendente(s)."))), /* @__PURE__ */ React19.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React19.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), canEdit && /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React19.createElement(FiPlus8, { size: 14 }), " Adicionar")), /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React19.createElement(CustomPropertyDisplay, { key: prop.id, prop, onUpdate: canEdit ? (updatedProp) => handleUpdateProp(idx, updatedProp) : void 0, onRemove: canEdit ? () => handleRemoveProp(idx) : void 0, onOpenImageViewer, unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type), isTextureMode: false, onUploadFile: canEdit ? onUploadFile : void 0, readOnly: !canEdit })), /* @__PURE__ */ React19.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ React19.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ React19.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ React19.createElement(
12525
+ )) : /* @__PURE__ */ React19.createElement("li", { className: "px-3 py-3 text-[10px] text-slate-500 italic text-center" }, "Nenhuma outra quest dispon\xEDvel")))), blockedStatus.isBlocked && /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2 px-3 py-2 bg-amber-500/5 rounded-lg border border-amber-500/10 animate-in fade-in slide-in-from-top-1" }, /* @__PURE__ */ React19.createElement(FiRepeat2, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ React19.createElement("p", { className: "text-[10px] text-amber-200/80 font-medium" }, "Esta quest est\xE1 bloqueada por ", blockedStatus.pendingDependencies.length, " tarefa(s) pendente(s)."))), /* @__PURE__ */ React19.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React19.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React19.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ React19.createElement(
12526
+ "button",
12527
+ {
12528
+ type: "button",
12529
+ onClick: handleCreateGoogleDoc,
12530
+ disabled: isLoadingDocs,
12531
+ className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-indigo-600/20 hover:bg-indigo-600/30 text-indigo-300 border border-indigo-500/30 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
12532
+ title: "Criar Documento no Google Docs"
12533
+ },
12534
+ isLoadingDocs ? /* @__PURE__ */ React19.createElement(AiOutlineLoading3Quarters4, { className: "animate-spin", size: 14 }) : /* @__PURE__ */ React19.createElement(SiGoogledocs4, { size: 14, className: "group-hover:scale-110 transition-transform" }),
12535
+ isLoadingDocs ? "Criando..." : "Google Doc"
12536
+ ), canEdit && /* @__PURE__ */ React19.createElement("button", { type: "button", onClick: handleAddProp, className: "flex items-center gap-1.5 px-2.5 py-1.5 text-xs rounded-md bg-slate-800/70 hover:bg-slate-700/70 border border-white/10 transition-colors" }, /* @__PURE__ */ React19.createElement(FiPlus8, { size: 14 }), " Adicionar"))), /* @__PURE__ */ React19.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React19.createElement(CustomPropertyDisplay, { key: prop.id, prop, onUpdate: canEdit ? (updatedProp) => handleUpdateProp(idx, updatedProp) : void 0, onRemove: canEdit ? () => handleRemoveProp(idx) : void 0, onOpenImageViewer, unavailableTypes: currentUsedTypes.filter((t) => t !== prop.type), isTextureMode: false, onUploadFile: canEdit ? onUploadFile : void 0, readOnly: !canEdit })), /* @__PURE__ */ React19.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ React19.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ React19.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ React19.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ React19.createElement(
12354
12537
  "button",
12355
12538
  {
12356
12539
  type: "button",
@@ -14613,7 +14796,8 @@ function XViewScene({
14613
14796
  upload_file_action,
14614
14797
  delete_file_action,
14615
14798
  check_user_permission,
14616
- get_view_members
14799
+ get_view_members,
14800
+ create_google_doc_action
14617
14801
  }) {
14618
14802
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
14619
14803
  const { data: session, status } = useSession();
@@ -19333,7 +19517,8 @@ function XViewScene({
19333
19517
  sourceNodeDatasetId,
19334
19518
  viewType: viewParams == null ? void 0 : viewParams.type,
19335
19519
  availableNodes: allAvailableNodes,
19336
- availableAncestries: allAvailableAncestries
19520
+ availableAncestries: allAvailableAncestries,
19521
+ create_google_doc_action
19337
19522
  }
19338
19523
  ),
19339
19524
  versionMode.isActive && /* @__PURE__ */ React30.createElement(
@@ -19387,7 +19572,8 @@ function XViewScene({
19387
19572
  questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
19388
19573
  viewMembers,
19389
19574
  milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
19390
- onUpdateMilestones: handleUpdateMilestones
19575
+ onUpdateMilestones: handleUpdateMilestones,
19576
+ create_google_doc_action
19391
19577
  }
19392
19578
  ),
19393
19579
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React30.createElement(
@@ -19522,7 +19708,8 @@ function XViewScene({
19522
19708
  viewMembers,
19523
19709
  currentUser: session == null ? void 0 : session.user,
19524
19710
  milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
19525
- onUpdateMilestones: handleUpdateMilestones
19711
+ onUpdateMilestones: handleUpdateMilestones,
19712
+ create_google_doc_action
19526
19713
  }
19527
19714
  ),
19528
19715
  detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React30.createElement(
@@ -19554,7 +19741,8 @@ function XViewScene({
19554
19741
  onIntensityChange: handleDetailNodeIntensityChange,
19555
19742
  onUploadFile: upload_file_action,
19556
19743
  userRole: userPermissionRole,
19557
- currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName
19744
+ currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
19745
+ create_google_doc_action
19558
19746
  }
19559
19747
  ),
19560
19748
  detailsLink && /* @__PURE__ */ React30.createElement(
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.60",
3
+ "version": "1.2.6-dev.61",
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",