@lv-x-software-house/x_view 1.2.6-dev.65 → 1.2.6-dev.66

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 +218 -44
  2. package/dist/index.mjs +218 -44
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3966,6 +3966,9 @@ function XViewSidebar({
3966
3966
  onOpenMilestoneManager = () => {
3967
3967
  },
3968
3968
  onActivateReshapeLens = () => {
3969
+ },
3970
+ view_google_folder_id,
3971
+ onSaveConfig = () => {
3969
3972
  }
3970
3973
  }) {
3971
3974
  const [query, setQuery] = (0, import_react3.useState)("");
@@ -3986,6 +3989,12 @@ function XViewSidebar({
3986
3989
  const [reshapeCenterNodeId, setReshapeCenterNodeId] = (0, import_react3.useState)("");
3987
3990
  const [isTypeDropdownOpen, setIsTypeDropdownOpen] = (0, import_react3.useState)(false);
3988
3991
  const [highlightedTypeIndex, setHighlightedTypeIndex] = (0, import_react3.useState)(-1);
3992
+ const [folderId, setFolderId] = (0, import_react3.useState)(view_google_folder_id || "");
3993
+ (0, import_react3.useEffect)(() => {
3994
+ if (view_google_folder_id !== void 0) {
3995
+ setFolderId(view_google_folder_id || "");
3996
+ }
3997
+ }, [view_google_folder_id]);
3989
3998
  const containerRef = (0, import_react3.useRef)(null);
3990
3999
  const inputRef = (0, import_react3.useRef)(null);
3991
4000
  const filterMenuRef = (0, import_react3.useRef)(null);
@@ -4691,7 +4700,21 @@ function XViewSidebar({
4691
4700
  className: buttonBaseClass
4692
4701
  },
4693
4702
  "Gerenciar Milestones"
4694
- ))),
4703
+ )), userRole === "owner" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-3" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Google Drive"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "text-[10px] uppercase text-slate-500 font-bold tracking-tight" }, "Folder ID da View"), /* @__PURE__ */ import_react3.default.createElement(
4704
+ "input",
4705
+ {
4706
+ type: "text",
4707
+ value: folderId,
4708
+ onChange: (e) => setFolderId(e.target.value),
4709
+ onBlur: () => {
4710
+ if (folderId !== view_google_folder_id) {
4711
+ onSaveConfig({ view_google_folder_id: folderId });
4712
+ }
4713
+ },
4714
+ placeholder: "ID da pasta no Drive",
4715
+ className: "w-full bg-slate-900/80 px-3 py-2 text-sm rounded-md border border-white/10 focus:outline-none focus:border-indigo-500/50 text-white hover:bg-slate-800/50 transition-all"
4716
+ }
4717
+ ), /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[9px] text-slate-500 italic" }, "Documentos criados nesta View ser\xE3o salvos nesta pasta."))))),
4695
4718
  /* @__PURE__ */ import_react3.default.createElement("div", { className: "px-4 py-3 border-t border-white/10 bg-slate-900/30" }, /* @__PURE__ */ import_react3.default.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o"), ability.can("update", "Scene") && /* @__PURE__ */ import_react3.default.createElement(
4696
4719
  "button",
4697
4720
  {
@@ -8987,7 +9010,8 @@ function InSceneCreationForm({
8987
9010
  availableDatasets = [],
8988
9011
  sourceNodeDatasetId,
8989
9012
  viewType,
8990
- create_google_doc_action
9013
+ create_google_doc_action,
9014
+ view_google_folder_id
8991
9015
  }) {
8992
9016
  var _a;
8993
9017
  const [name, setName] = (0, import_react15.useState)("");
@@ -9008,6 +9032,7 @@ function InSceneCreationForm({
9008
9032
  );
9009
9033
  const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = (0, import_react15.useState)(false);
9010
9034
  const [isLoadingDocs, setIsLoadingDocs] = (0, import_react15.useState)(false);
9035
+ const [docError, setDocError] = (0, import_react15.useState)(null);
9011
9036
  const datasetDropdownRef = (0, import_react15.useRef)(null);
9012
9037
  (0, import_react15.useEffect)(() => {
9013
9038
  if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
@@ -9154,7 +9179,8 @@ function InSceneCreationForm({
9154
9179
  if (!create_google_doc_action) return;
9155
9180
  try {
9156
9181
  setIsLoadingDocs(true);
9157
- const res = await create_google_doc_action(name);
9182
+ setDocError(null);
9183
+ const res = await create_google_doc_action(name, view_google_folder_id);
9158
9184
  if (res.success) {
9159
9185
  const existingLinksPropIndex = customProps.findIndex(
9160
9186
  (p) => p.type === "links" && p.key === "Links"
@@ -9181,11 +9207,21 @@ function InSceneCreationForm({
9181
9207
  window.open(res.link, "_blank");
9182
9208
  }
9183
9209
  } else {
9184
- alert("Erro ao criar documento: " + res.error);
9210
+ if (res.errorType === "PERMISSIONS_ERROR") {
9211
+ setDocError(
9212
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
9213
+ );
9214
+ } else {
9215
+ setDocError(
9216
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
9217
+ );
9218
+ }
9185
9219
  }
9186
9220
  } catch (error) {
9187
9221
  console.error(error);
9188
- alert("Erro ao processar cria\xE7\xE3o do documento.");
9222
+ setDocError(
9223
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
9224
+ );
9189
9225
  } finally {
9190
9226
  setIsLoadingDocs(false);
9191
9227
  }
@@ -9429,7 +9465,14 @@ function InSceneCreationForm({
9429
9465
  className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}`
9430
9466
  },
9431
9467
  useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Selecione a cor e ajuste o brilho."
9432
- )), /* @__PURE__ */ import_react15.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react15.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ import_react15.default.createElement(
9468
+ )), /* @__PURE__ */ import_react15.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react15.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ import_react15.default.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ import_react15.default.createElement(
9469
+ "p",
9470
+ {
9471
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
9472
+ title: docError
9473
+ },
9474
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
9475
+ ) : /* @__PURE__ */ import_react15.default.createElement(
9433
9476
  "button",
9434
9477
  {
9435
9478
  type: "button",
@@ -9438,8 +9481,20 @@ function InSceneCreationForm({
9438
9481
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
9439
9482
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
9440
9483
  },
9441
- isLoadingDocs ? /* @__PURE__ */ import_react15.default.createElement(import_ai.AiOutlineLoading3Quarters, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ import_react15.default.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
9442
- ), /* @__PURE__ */ import_react15.default.createElement(
9484
+ isLoadingDocs ? /* @__PURE__ */ import_react15.default.createElement(
9485
+ import_ai.AiOutlineLoading3Quarters,
9486
+ {
9487
+ className: "animate-spin",
9488
+ size: 18
9489
+ }
9490
+ ) : /* @__PURE__ */ import_react15.default.createElement(
9491
+ GoogleDocsIcon_default,
9492
+ {
9493
+ size: 18,
9494
+ className: "group-hover:scale-110 transition-transform"
9495
+ }
9496
+ )
9497
+ )), /* @__PURE__ */ import_react15.default.createElement(
9443
9498
  "button",
9444
9499
  {
9445
9500
  type: "button",
@@ -10000,7 +10055,8 @@ function InSceneQuestForm({
10000
10055
  milestones = [],
10001
10056
  onUpdateMilestones = () => {
10002
10057
  },
10003
- create_google_doc_action
10058
+ create_google_doc_action,
10059
+ view_google_folder_id
10004
10060
  }) {
10005
10061
  var _a, _b;
10006
10062
  const [name, setName] = (0, import_react18.useState)("");
@@ -10029,6 +10085,7 @@ function InSceneQuestForm({
10029
10085
  const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react18.useState)("");
10030
10086
  const [isNameCopied, setIsNameCopied] = (0, import_react18.useState)(false);
10031
10087
  const [isLoadingDocs, setIsLoadingDocs] = (0, import_react18.useState)(false);
10088
+ const [docError, setDocError] = (0, import_react18.useState)(null);
10032
10089
  const [customProps, setCustomProps] = (0, import_react18.useState)([]);
10033
10090
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react18.useState)(false);
10034
10091
  const propsEndRef = (0, import_react18.useRef)(null);
@@ -10124,7 +10181,8 @@ function InSceneQuestForm({
10124
10181
  if (!create_google_doc_action) return;
10125
10182
  try {
10126
10183
  setIsLoadingDocs(true);
10127
- const res = await create_google_doc_action(standardizedName);
10184
+ setDocError(null);
10185
+ const res = await create_google_doc_action(standardizedName, view_google_folder_id);
10128
10186
  if (res.success) {
10129
10187
  const existingLinksPropIndex = customProps.findIndex(
10130
10188
  (p) => p.type === "links" && p.key === "Links"
@@ -10151,11 +10209,21 @@ function InSceneQuestForm({
10151
10209
  window.open(res.link, "_blank");
10152
10210
  }
10153
10211
  } else {
10154
- alert("Erro ao criar documento: " + res.error);
10212
+ if (res.errorType === "PERMISSIONS_ERROR") {
10213
+ setDocError(
10214
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
10215
+ );
10216
+ } else {
10217
+ setDocError(
10218
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
10219
+ );
10220
+ }
10155
10221
  }
10156
10222
  } catch (error) {
10157
10223
  console.error(error);
10158
- alert("Erro ao processar cria\xE7\xE3o do documento.");
10224
+ setDocError(
10225
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
10226
+ );
10159
10227
  } finally {
10160
10228
  setIsLoadingDocs(false);
10161
10229
  }
@@ -10678,7 +10746,14 @@ function InSceneQuestForm({
10678
10746
  className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
10679
10747
  },
10680
10748
  "Adicionar descri\xE7\xE3o..."
10681
- ))), /* @__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-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ import_react18.default.createElement(
10749
+ ))), /* @__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-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ import_react18.default.createElement(
10750
+ "p",
10751
+ {
10752
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
10753
+ title: docError
10754
+ },
10755
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
10756
+ ) : /* @__PURE__ */ import_react18.default.createElement(
10682
10757
  "button",
10683
10758
  {
10684
10759
  type: "button",
@@ -10687,8 +10762,20 @@ function InSceneQuestForm({
10687
10762
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
10688
10763
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
10689
10764
  },
10690
- isLoadingDocs ? /* @__PURE__ */ import_react18.default.createElement(import_ai2.AiOutlineLoading3Quarters, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ import_react18.default.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
10691
- ), /* @__PURE__ */ import_react18.default.createElement(
10765
+ isLoadingDocs ? /* @__PURE__ */ import_react18.default.createElement(
10766
+ import_ai2.AiOutlineLoading3Quarters,
10767
+ {
10768
+ className: "animate-spin",
10769
+ size: 18
10770
+ }
10771
+ ) : /* @__PURE__ */ import_react18.default.createElement(
10772
+ GoogleDocsIcon_default,
10773
+ {
10774
+ size: 18,
10775
+ className: "group-hover:scale-110 transition-transform"
10776
+ }
10777
+ )
10778
+ )), /* @__PURE__ */ import_react18.default.createElement(
10692
10779
  "button",
10693
10780
  {
10694
10781
  type: "button",
@@ -10819,7 +10906,8 @@ function NodeDetailsPanel({
10819
10906
  onUploadFile,
10820
10907
  userRole,
10821
10908
  currentDatasetName,
10822
- create_google_doc_action
10909
+ create_google_doc_action,
10910
+ view_google_folder_id
10823
10911
  }) {
10824
10912
  const [name, setName] = (0, import_react19.useState)((node == null ? void 0 : node.name) ?? "");
10825
10913
  const [types, setTypes] = (0, import_react19.useState)([]);
@@ -10836,6 +10924,7 @@ function NodeDetailsPanel({
10836
10924
  const [existingSections, setExistingSections] = (0, import_react19.useState)((node == null ? void 0 : node.description_sections) || []);
10837
10925
  const [isSaving, setIsSaving] = (0, import_react19.useState)(false);
10838
10926
  const [isLoadingDocs, setIsLoadingDocs] = (0, import_react19.useState)(false);
10927
+ const [docError, setDocError] = (0, import_react19.useState)(null);
10839
10928
  const [isLinkCopied, setIsLinkCopied] = (0, import_react19.useState)(false);
10840
10929
  const [useImageAsTexture, setUseImageAsTexture] = (0, import_react19.useState)(() => {
10841
10930
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
@@ -10998,7 +11087,8 @@ function NodeDetailsPanel({
10998
11087
  if (!create_google_doc_action) return;
10999
11088
  try {
11000
11089
  setIsLoadingDocs(true);
11001
- const res = await create_google_doc_action(name);
11090
+ setDocError(null);
11091
+ const res = await create_google_doc_action(name, view_google_folder_id);
11002
11092
  if (res.success) {
11003
11093
  const existingLinksPropIndex = customProps.findIndex(
11004
11094
  (p) => p.type === "links" && p.key === "Links"
@@ -11028,11 +11118,21 @@ function NodeDetailsPanel({
11028
11118
  window.open(res.link, "_blank");
11029
11119
  }
11030
11120
  } else {
11031
- alert("Erro ao criar documento: " + res.error);
11121
+ if (res.errorType === "PERMISSIONS_ERROR") {
11122
+ setDocError(
11123
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
11124
+ );
11125
+ } else {
11126
+ setDocError(
11127
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
11128
+ );
11129
+ }
11032
11130
  }
11033
11131
  } catch (error) {
11034
11132
  console.error(error);
11035
- alert("Erro ao processar cria\xE7\xE3o do documento.");
11133
+ setDocError(
11134
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
11135
+ );
11036
11136
  } finally {
11037
11137
  setIsLoadingDocs(false);
11038
11138
  }
@@ -11313,7 +11413,14 @@ function NodeDetailsPanel({
11313
11413
  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"}`,
11314
11414
  title: `Intensidade do brilho: ${intensity}`
11315
11415
  }
11316
- ), /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ import_react19.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_react19.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react19.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ import_react19.default.createElement(
11416
+ ), /* @__PURE__ */ import_react19.default.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ import_react19.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_react19.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react19.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ import_react19.default.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ import_react19.default.createElement(
11417
+ "p",
11418
+ {
11419
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
11420
+ title: docError
11421
+ },
11422
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
11423
+ ) : /* @__PURE__ */ import_react19.default.createElement(
11317
11424
  "button",
11318
11425
  {
11319
11426
  type: "button",
@@ -11322,8 +11429,20 @@ function NodeDetailsPanel({
11322
11429
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
11323
11430
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
11324
11431
  },
11325
- isLoadingDocs ? /* @__PURE__ */ import_react19.default.createElement(import_ai3.AiOutlineLoading3Quarters, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ import_react19.default.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
11326
- ), canEdit && /* @__PURE__ */ import_react19.default.createElement(
11432
+ isLoadingDocs ? /* @__PURE__ */ import_react19.default.createElement(
11433
+ import_ai3.AiOutlineLoading3Quarters,
11434
+ {
11435
+ className: "animate-spin",
11436
+ size: 18
11437
+ }
11438
+ ) : /* @__PURE__ */ import_react19.default.createElement(
11439
+ GoogleDocsIcon_default,
11440
+ {
11441
+ size: 18,
11442
+ className: "group-hover:scale-110 transition-transform"
11443
+ }
11444
+ )
11445
+ )), canEdit && /* @__PURE__ */ import_react19.default.createElement(
11327
11446
  "button",
11328
11447
  {
11329
11448
  type: "button",
@@ -11486,7 +11605,8 @@ function QuestDetailsPanel({
11486
11605
  onUpdateMilestones = () => {
11487
11606
  },
11488
11607
  onFocusNode,
11489
- create_google_doc_action
11608
+ create_google_doc_action,
11609
+ view_google_folder_id
11490
11610
  }) {
11491
11611
  var _a, _b;
11492
11612
  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) || "";
@@ -11521,6 +11641,7 @@ function QuestDetailsPanel({
11521
11641
  const [isLinkCopied, setIsLinkCopied] = (0, import_react21.useState)(false);
11522
11642
  const [isNameCopied, setIsNameCopied] = (0, import_react21.useState)(false);
11523
11643
  const [isLoadingDocs, setIsLoadingDocs] = (0, import_react21.useState)(false);
11644
+ const [docError, setDocError] = (0, import_react21.useState)(null);
11524
11645
  const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react21.useState)(false);
11525
11646
  const [questDate, setQuestDate] = (0, import_react21.useState)((node == null ? void 0 : node.Date) || null);
11526
11647
  const [noteText, setNoteText] = (0, import_react21.useState)("");
@@ -11929,7 +12050,8 @@ ${noteText}` : noteText : entry.notes,
11929
12050
  if (!create_google_doc_action) return;
11930
12051
  try {
11931
12052
  setIsLoadingDocs(true);
11932
- const res = await create_google_doc_action(standardizedName);
12053
+ setDocError(null);
12054
+ const res = await create_google_doc_action(standardizedName, view_google_folder_id);
11933
12055
  if (res.success) {
11934
12056
  const existingLinksPropIndex = customProps.findIndex(
11935
12057
  (p) => p.type === "links" && p.key === "Links"
@@ -11959,11 +12081,21 @@ ${noteText}` : noteText : entry.notes,
11959
12081
  window.open(res.link, "_blank");
11960
12082
  }
11961
12083
  } else {
11962
- alert("Erro ao criar documento: " + res.error);
12084
+ if (res.errorType === "PERMISSIONS_ERROR") {
12085
+ setDocError(
12086
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
12087
+ );
12088
+ } else {
12089
+ setDocError(
12090
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
12091
+ );
12092
+ }
11963
12093
  }
11964
12094
  } catch (error) {
11965
12095
  console.error(error);
11966
- alert("Erro ao processar cria\xE7\xE3o do documento.");
12096
+ setDocError(
12097
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
12098
+ );
11967
12099
  } finally {
11968
12100
  setIsLoadingDocs(false);
11969
12101
  }
@@ -12573,7 +12705,14 @@ ${noteText}` : noteText : entry.notes,
12573
12705
  },
12574
12706
  /* @__PURE__ */ import_react21.default.createElement("span", { className: "truncate" }, q.raw_title || q.name),
12575
12707
  /* @__PURE__ */ import_react21.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")
12576
- )) : /* @__PURE__ */ import_react21.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_react21.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_react21.default.createElement(import_fi19.FiRepeat, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ import_react21.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_react21.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react21.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ import_react21.default.createElement(
12708
+ )) : /* @__PURE__ */ import_react21.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_react21.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_react21.default.createElement(import_fi19.FiRepeat, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ import_react21.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_react21.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ import_react21.default.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ import_react21.default.createElement(
12709
+ "p",
12710
+ {
12711
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
12712
+ title: docError
12713
+ },
12714
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
12715
+ ) : /* @__PURE__ */ import_react21.default.createElement(
12577
12716
  "button",
12578
12717
  {
12579
12718
  type: "button",
@@ -12582,8 +12721,20 @@ ${noteText}` : noteText : entry.notes,
12582
12721
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
12583
12722
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
12584
12723
  },
12585
- isLoadingDocs ? /* @__PURE__ */ import_react21.default.createElement(import_ai4.AiOutlineLoading3Quarters, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ import_react21.default.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
12586
- ), canEdit && /* @__PURE__ */ import_react21.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_react21.default.createElement(import_fi19.FiPlus, { size: 14 }), " Adicionar"))), /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react21.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_react21.default.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ import_react21.default.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ import_react21.default.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ import_react21.default.createElement(
12724
+ isLoadingDocs ? /* @__PURE__ */ import_react21.default.createElement(
12725
+ import_ai4.AiOutlineLoading3Quarters,
12726
+ {
12727
+ className: "animate-spin",
12728
+ size: 18
12729
+ }
12730
+ ) : /* @__PURE__ */ import_react21.default.createElement(
12731
+ GoogleDocsIcon_default,
12732
+ {
12733
+ size: 18,
12734
+ className: "group-hover:scale-110 transition-transform"
12735
+ }
12736
+ )
12737
+ )), canEdit && /* @__PURE__ */ import_react21.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_react21.default.createElement(import_fi19.FiPlus, { size: 14 }), " Adicionar"))), /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ import_react21.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_react21.default.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ import_react21.default.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ import_react21.default.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ import_react21.default.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ import_react21.default.createElement(
12587
12738
  "button",
12588
12739
  {
12589
12740
  type: "button",
@@ -14824,7 +14975,7 @@ function XViewScene({
14824
14975
  get_view_members,
14825
14976
  create_google_doc_action
14826
14977
  }) {
14827
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
14978
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
14828
14979
  const { data: session, status } = (0, import_react33.useSession)();
14829
14980
  const router = (0, import_navigation.useRouter)();
14830
14981
  const searchParams = (0, import_navigation.useSearchParams)();
@@ -15201,6 +15352,23 @@ function XViewScene({
15201
15352
  add_new_parent_file_to_scene_at_firebase_action
15202
15353
  ]
15203
15354
  );
15355
+ const handleSaveConfig = (0, import_react32.useCallback)(
15356
+ async (newConfig) => {
15357
+ if (!sceneDataRef.current || !save_view_data || !sceneSaveUrl) return;
15358
+ const updatedData = {
15359
+ ...sceneDataRef.current,
15360
+ ...newConfig
15361
+ };
15362
+ sceneDataRef.current = updatedData;
15363
+ try {
15364
+ await save_view_data(sceneSaveUrl, updatedData);
15365
+ setSceneVersion((v) => v + 1);
15366
+ } catch (error) {
15367
+ console.error("Erro ao salvar configura\xE7\xE3o da View:", error);
15368
+ }
15369
+ },
15370
+ [save_view_data, sceneSaveUrl]
15371
+ );
15204
15372
  const handleOpenImageViewer = (images, startIndex) => {
15205
15373
  setImageViewer({ visible: true, images, startIndex });
15206
15374
  };
@@ -19510,7 +19678,9 @@ function XViewScene({
19510
19678
  userRole: userPermissionRole,
19511
19679
  viewMembers,
19512
19680
  milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
19513
- onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
19681
+ onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true),
19682
+ view_google_folder_id: (_d = sceneDataRef.current) == null ? void 0 : _d.view_google_folder_id,
19683
+ onSaveConfig: handleSaveConfig
19514
19684
  }
19515
19685
  ),
19516
19686
  creationMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
@@ -19534,8 +19704,8 @@ function XViewScene({
19534
19704
  },
19535
19705
  refEl: formRef,
19536
19706
  existingTypes: existingNodeTypes,
19537
- initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
19538
- sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
19707
+ initialColor: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.color,
19708
+ sourceTypes: (_f = creationMode.sourceNodeData) == null ? void 0 : _f.type,
19539
19709
  onIntensityChange: handleGhostNodeIntensityChange,
19540
19710
  onUploadFile: upload_file_action,
19541
19711
  availableDatasets,
@@ -19543,7 +19713,8 @@ function XViewScene({
19543
19713
  viewType: viewParams == null ? void 0 : viewParams.type,
19544
19714
  availableNodes: allAvailableNodes,
19545
19715
  availableAncestries: allAvailableAncestries,
19546
- create_google_doc_action
19716
+ create_google_doc_action,
19717
+ view_google_folder_id: (_g = sceneDataRef.current) == null ? void 0 : _g.view_google_folder_id
19547
19718
  }
19548
19719
  ),
19549
19720
  versionMode.isActive && /* @__PURE__ */ import_react32.default.createElement(
@@ -19565,8 +19736,8 @@ function XViewScene({
19565
19736
  transition: "opacity 200ms ease-out"
19566
19737
  },
19567
19738
  refEl: formRef,
19568
- fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
19569
- fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
19739
+ fixedType: (_h = versionMode.sourceNodeData) == null ? void 0 : _h.type,
19740
+ fixedColor: (_i = versionMode.sourceNodeData) == null ? void 0 : _i.color,
19570
19741
  onUploadFile: upload_file_action,
19571
19742
  availableNodes: allAvailableNodes,
19572
19743
  availableAncestries: allAvailableAncestries
@@ -19594,11 +19765,12 @@ function XViewScene({
19594
19765
  availableNodes: allAvailableNodes,
19595
19766
  availableAncestries: allAvailableAncestries,
19596
19767
  viewName: viewParams == null ? void 0 : viewParams.name,
19597
- questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
19768
+ questCounter: ((_j = sceneDataRef.current) == null ? void 0 : _j.quest_counter) || 1,
19598
19769
  viewMembers,
19599
- milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
19770
+ milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
19600
19771
  onUpdateMilestones: handleUpdateMilestones,
19601
- create_google_doc_action
19772
+ create_google_doc_action,
19773
+ view_google_folder_id: (_l = sceneDataRef.current) == null ? void 0 : _l.view_google_folder_id
19602
19774
  }
19603
19775
  ),
19604
19776
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ import_react32.default.createElement(
@@ -19732,9 +19904,10 @@ function XViewScene({
19732
19904
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
19733
19905
  viewMembers,
19734
19906
  currentUser: session == null ? void 0 : session.user,
19735
- milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
19907
+ milestones: ((_m = sceneDataRef.current) == null ? void 0 : _m.milestones) || [],
19736
19908
  onUpdateMilestones: handleUpdateMilestones,
19737
- create_google_doc_action
19909
+ create_google_doc_action,
19910
+ view_google_folder_id: (_n = sceneDataRef.current) == null ? void 0 : _n.view_google_folder_id
19738
19911
  }
19739
19912
  ),
19740
19913
  detailsNode && !detailsNode.is_quest && /* @__PURE__ */ import_react32.default.createElement(
@@ -19767,7 +19940,8 @@ function XViewScene({
19767
19940
  onUploadFile: upload_file_action,
19768
19941
  userRole: userPermissionRole,
19769
19942
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
19770
- create_google_doc_action
19943
+ create_google_doc_action,
19944
+ view_google_folder_id: (_o = sceneDataRef.current) == null ? void 0 : _o.view_google_folder_id
19771
19945
  }
19772
19946
  ),
19773
19947
  detailsLink && /* @__PURE__ */ import_react32.default.createElement(
@@ -19925,7 +20099,7 @@ function XViewScene({
19925
20099
  {
19926
20100
  isOpen: isMilestoneManagerOpen,
19927
20101
  onClose: () => setIsMilestoneManagerOpen(false),
19928
- milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
20102
+ milestones: ((_p = sceneDataRef.current) == null ? void 0 : _p.milestones) || [],
19929
20103
  onUpdateMilestones: handleUpdateMilestones
19930
20104
  }
19931
20105
  ),
@@ -19936,7 +20110,7 @@ function XViewScene({
19936
20110
  onClose: () => setIsImportModalOpen(false),
19937
20111
  onConfirm: handleConfirmImport,
19938
20112
  session,
19939
- parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
20113
+ parentDbs: ((_q = sceneDataRef.current) == null ? void 0 : _q.parent_dbs) || [],
19940
20114
  onFetchAvailableFiles: import_parent_file_modal_get,
19941
20115
  currentViewName: viewParams == null ? void 0 : viewParams.name,
19942
20116
  currentAncestries: ancestryDataRef.current || []
package/dist/index.mjs CHANGED
@@ -3927,6 +3927,9 @@ function XViewSidebar({
3927
3927
  onOpenMilestoneManager = () => {
3928
3928
  },
3929
3929
  onActivateReshapeLens = () => {
3930
+ },
3931
+ view_google_folder_id,
3932
+ onSaveConfig = () => {
3930
3933
  }
3931
3934
  }) {
3932
3935
  const [query, setQuery] = useState3("");
@@ -3947,6 +3950,12 @@ function XViewSidebar({
3947
3950
  const [reshapeCenterNodeId, setReshapeCenterNodeId] = useState3("");
3948
3951
  const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState3(false);
3949
3952
  const [highlightedTypeIndex, setHighlightedTypeIndex] = useState3(-1);
3953
+ const [folderId, setFolderId] = useState3(view_google_folder_id || "");
3954
+ useEffect2(() => {
3955
+ if (view_google_folder_id !== void 0) {
3956
+ setFolderId(view_google_folder_id || "");
3957
+ }
3958
+ }, [view_google_folder_id]);
3950
3959
  const containerRef = useRef2(null);
3951
3960
  const inputRef = useRef2(null);
3952
3961
  const filterMenuRef = useRef2(null);
@@ -4652,7 +4661,21 @@ function XViewSidebar({
4652
4661
  className: buttonBaseClass
4653
4662
  },
4654
4663
  "Gerenciar Milestones"
4655
- ))),
4664
+ )), userRole === "owner" && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("div", { className: "h-px bg-white/10" }), /* @__PURE__ */ React2.createElement("section", { className: "space-y-3" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Google Drive"), /* @__PURE__ */ React2.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[10px] uppercase text-slate-500 font-bold tracking-tight" }, "Folder ID da View"), /* @__PURE__ */ React2.createElement(
4665
+ "input",
4666
+ {
4667
+ type: "text",
4668
+ value: folderId,
4669
+ onChange: (e) => setFolderId(e.target.value),
4670
+ onBlur: () => {
4671
+ if (folderId !== view_google_folder_id) {
4672
+ onSaveConfig({ view_google_folder_id: folderId });
4673
+ }
4674
+ },
4675
+ placeholder: "ID da pasta no Drive",
4676
+ className: "w-full bg-slate-900/80 px-3 py-2 text-sm rounded-md border border-white/10 focus:outline-none focus:border-indigo-500/50 text-white hover:bg-slate-800/50 transition-all"
4677
+ }
4678
+ ), /* @__PURE__ */ React2.createElement("p", { className: "text-[9px] text-slate-500 italic" }, "Documentos criados nesta View ser\xE3o salvos nesta pasta."))))),
4656
4679
  /* @__PURE__ */ React2.createElement("div", { className: "px-4 py-3 border-t border-white/10 bg-slate-900/30" }, /* @__PURE__ */ React2.createElement("section", { className: "space-y-2" }, /* @__PURE__ */ React2.createElement("p", { className: "text-[11px] uppercase tracking-wider text-slate-400" }, "Navega\xE7\xE3o"), ability.can("update", "Scene") && /* @__PURE__ */ React2.createElement(
4657
4680
  "button",
4658
4681
  {
@@ -8987,7 +9010,8 @@ function InSceneCreationForm({
8987
9010
  availableDatasets = [],
8988
9011
  sourceNodeDatasetId,
8989
9012
  viewType,
8990
- create_google_doc_action
9013
+ create_google_doc_action,
9014
+ view_google_folder_id
8991
9015
  }) {
8992
9016
  var _a;
8993
9017
  const [name, setName] = useState14("");
@@ -9008,6 +9032,7 @@ function InSceneCreationForm({
9008
9032
  );
9009
9033
  const [isDatasetDropdownOpen, setIsDatasetDropdownOpen] = useState14(false);
9010
9034
  const [isLoadingDocs, setIsLoadingDocs] = useState14(false);
9035
+ const [docError, setDocError] = useState14(null);
9011
9036
  const datasetDropdownRef = useRef10(null);
9012
9037
  useEffect13(() => {
9013
9038
  if (sourceNodeDatasetId) setTargetDatasetId(sourceNodeDatasetId);
@@ -9154,7 +9179,8 @@ function InSceneCreationForm({
9154
9179
  if (!create_google_doc_action) return;
9155
9180
  try {
9156
9181
  setIsLoadingDocs(true);
9157
- const res = await create_google_doc_action(name);
9182
+ setDocError(null);
9183
+ const res = await create_google_doc_action(name, view_google_folder_id);
9158
9184
  if (res.success) {
9159
9185
  const existingLinksPropIndex = customProps.findIndex(
9160
9186
  (p) => p.type === "links" && p.key === "Links"
@@ -9181,11 +9207,21 @@ function InSceneCreationForm({
9181
9207
  window.open(res.link, "_blank");
9182
9208
  }
9183
9209
  } else {
9184
- alert("Erro ao criar documento: " + res.error);
9210
+ if (res.errorType === "PERMISSIONS_ERROR") {
9211
+ setDocError(
9212
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
9213
+ );
9214
+ } else {
9215
+ setDocError(
9216
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
9217
+ );
9218
+ }
9185
9219
  }
9186
9220
  } catch (error) {
9187
9221
  console.error(error);
9188
- alert("Erro ao processar cria\xE7\xE3o do documento.");
9222
+ setDocError(
9223
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
9224
+ );
9189
9225
  } finally {
9190
9226
  setIsLoadingDocs(false);
9191
9227
  }
@@ -9429,7 +9465,14 @@ function InSceneCreationForm({
9429
9465
  className: `text-xs block mt-1 transition-opacity ${useImageAsTexture ? "opacity-40" : "text-slate-400"}`
9430
9466
  },
9431
9467
  useImageAsTexture ? "Cor da borda (definida pela imagem)" : "Selecione a cor e ajuste o brilho."
9432
- )), /* @__PURE__ */ React14.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React14.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React14.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React14.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ React14.createElement(
9468
+ )), /* @__PURE__ */ React14.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React14.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React14.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React14.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ React14.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ React14.createElement(
9469
+ "p",
9470
+ {
9471
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
9472
+ title: docError
9473
+ },
9474
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
9475
+ ) : /* @__PURE__ */ React14.createElement(
9433
9476
  "button",
9434
9477
  {
9435
9478
  type: "button",
@@ -9438,8 +9481,20 @@ function InSceneCreationForm({
9438
9481
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
9439
9482
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
9440
9483
  },
9441
- isLoadingDocs ? /* @__PURE__ */ React14.createElement(AiOutlineLoading3Quarters, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ React14.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
9442
- ), /* @__PURE__ */ React14.createElement(
9484
+ isLoadingDocs ? /* @__PURE__ */ React14.createElement(
9485
+ AiOutlineLoading3Quarters,
9486
+ {
9487
+ className: "animate-spin",
9488
+ size: 18
9489
+ }
9490
+ ) : /* @__PURE__ */ React14.createElement(
9491
+ GoogleDocsIcon_default,
9492
+ {
9493
+ size: 18,
9494
+ className: "group-hover:scale-110 transition-transform"
9495
+ }
9496
+ )
9497
+ )), /* @__PURE__ */ React14.createElement(
9443
9498
  "button",
9444
9499
  {
9445
9500
  type: "button",
@@ -10020,7 +10075,8 @@ function InSceneQuestForm({
10020
10075
  milestones = [],
10021
10076
  onUpdateMilestones = () => {
10022
10077
  },
10023
- create_google_doc_action
10078
+ create_google_doc_action,
10079
+ view_google_folder_id
10024
10080
  }) {
10025
10081
  var _a, _b;
10026
10082
  const [name, setName] = useState17("");
@@ -10049,6 +10105,7 @@ function InSceneQuestForm({
10049
10105
  const [assigneeSearchQuery, setAssigneeSearchQuery] = useState17("");
10050
10106
  const [isNameCopied, setIsNameCopied] = useState17(false);
10051
10107
  const [isLoadingDocs, setIsLoadingDocs] = useState17(false);
10108
+ const [docError, setDocError] = useState17(null);
10052
10109
  const [customProps, setCustomProps] = useState17([]);
10053
10110
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState17(false);
10054
10111
  const propsEndRef = useRef12(null);
@@ -10144,7 +10201,8 @@ function InSceneQuestForm({
10144
10201
  if (!create_google_doc_action) return;
10145
10202
  try {
10146
10203
  setIsLoadingDocs(true);
10147
- const res = await create_google_doc_action(standardizedName);
10204
+ setDocError(null);
10205
+ const res = await create_google_doc_action(standardizedName, view_google_folder_id);
10148
10206
  if (res.success) {
10149
10207
  const existingLinksPropIndex = customProps.findIndex(
10150
10208
  (p) => p.type === "links" && p.key === "Links"
@@ -10171,11 +10229,21 @@ function InSceneQuestForm({
10171
10229
  window.open(res.link, "_blank");
10172
10230
  }
10173
10231
  } else {
10174
- alert("Erro ao criar documento: " + res.error);
10232
+ if (res.errorType === "PERMISSIONS_ERROR") {
10233
+ setDocError(
10234
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
10235
+ );
10236
+ } else {
10237
+ setDocError(
10238
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
10239
+ );
10240
+ }
10175
10241
  }
10176
10242
  } catch (error) {
10177
10243
  console.error(error);
10178
- alert("Erro ao processar cria\xE7\xE3o do documento.");
10244
+ setDocError(
10245
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
10246
+ );
10179
10247
  } finally {
10180
10248
  setIsLoadingDocs(false);
10181
10249
  }
@@ -10698,7 +10766,14 @@ function InSceneQuestForm({
10698
10766
  className: "absolute inset-0 flex items-center justify-center text-xs text-slate-500 cursor-text"
10699
10767
  },
10700
10768
  "Adicionar descri\xE7\xE3o..."
10701
- ))), /* @__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-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ React17.createElement(
10769
+ ))), /* @__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-xs text-slate-400 font-medium uppercase tracking-wider" }, "Propriedades Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, create_google_doc_action && /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ React17.createElement(
10770
+ "p",
10771
+ {
10772
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
10773
+ title: docError
10774
+ },
10775
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
10776
+ ) : /* @__PURE__ */ React17.createElement(
10702
10777
  "button",
10703
10778
  {
10704
10779
  type: "button",
@@ -10707,8 +10782,20 @@ function InSceneQuestForm({
10707
10782
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
10708
10783
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
10709
10784
  },
10710
- isLoadingDocs ? /* @__PURE__ */ React17.createElement(AiOutlineLoading3Quarters2, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ React17.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
10711
- ), /* @__PURE__ */ React17.createElement(
10785
+ isLoadingDocs ? /* @__PURE__ */ React17.createElement(
10786
+ AiOutlineLoading3Quarters2,
10787
+ {
10788
+ className: "animate-spin",
10789
+ size: 18
10790
+ }
10791
+ ) : /* @__PURE__ */ React17.createElement(
10792
+ GoogleDocsIcon_default,
10793
+ {
10794
+ size: 18,
10795
+ className: "group-hover:scale-110 transition-transform"
10796
+ }
10797
+ )
10798
+ )), /* @__PURE__ */ React17.createElement(
10712
10799
  "button",
10713
10800
  {
10714
10801
  type: "button",
@@ -10839,7 +10926,8 @@ function NodeDetailsPanel({
10839
10926
  onUploadFile,
10840
10927
  userRole,
10841
10928
  currentDatasetName,
10842
- create_google_doc_action
10929
+ create_google_doc_action,
10930
+ view_google_folder_id
10843
10931
  }) {
10844
10932
  const [name, setName] = useState18((node == null ? void 0 : node.name) ?? "");
10845
10933
  const [types, setTypes] = useState18([]);
@@ -10856,6 +10944,7 @@ function NodeDetailsPanel({
10856
10944
  const [existingSections, setExistingSections] = useState18((node == null ? void 0 : node.description_sections) || []);
10857
10945
  const [isSaving, setIsSaving] = useState18(false);
10858
10946
  const [isLoadingDocs, setIsLoadingDocs] = useState18(false);
10947
+ const [docError, setDocError] = useState18(null);
10859
10948
  const [isLinkCopied, setIsLinkCopied] = useState18(false);
10860
10949
  const [useImageAsTexture, setUseImageAsTexture] = useState18(() => {
10861
10950
  if ((node == null ? void 0 : node.useImageAsTexture) === "true") return true;
@@ -11018,7 +11107,8 @@ function NodeDetailsPanel({
11018
11107
  if (!create_google_doc_action) return;
11019
11108
  try {
11020
11109
  setIsLoadingDocs(true);
11021
- const res = await create_google_doc_action(name);
11110
+ setDocError(null);
11111
+ const res = await create_google_doc_action(name, view_google_folder_id);
11022
11112
  if (res.success) {
11023
11113
  const existingLinksPropIndex = customProps.findIndex(
11024
11114
  (p) => p.type === "links" && p.key === "Links"
@@ -11048,11 +11138,21 @@ function NodeDetailsPanel({
11048
11138
  window.open(res.link, "_blank");
11049
11139
  }
11050
11140
  } else {
11051
- alert("Erro ao criar documento: " + res.error);
11141
+ if (res.errorType === "PERMISSIONS_ERROR") {
11142
+ setDocError(
11143
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
11144
+ );
11145
+ } else {
11146
+ setDocError(
11147
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
11148
+ );
11149
+ }
11052
11150
  }
11053
11151
  } catch (error) {
11054
11152
  console.error(error);
11055
- alert("Erro ao processar cria\xE7\xE3o do documento.");
11153
+ setDocError(
11154
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
11155
+ );
11056
11156
  } finally {
11057
11157
  setIsLoadingDocs(false);
11058
11158
  }
@@ -11333,7 +11433,14 @@ function NodeDetailsPanel({
11333
11433
  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"}`,
11334
11434
  title: `Intensidade do brilho: ${intensity}`
11335
11435
  }
11336
- ), /* @__PURE__ */ React18.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ React18.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__ */ React18.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React18.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ React18.createElement(
11436
+ ), /* @__PURE__ */ React18.createElement("span", { className: "text-xs text-slate-400 w-6 text-right" }, intensity)), /* @__PURE__ */ React18.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__ */ React18.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React18.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React18.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ React18.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ React18.createElement(
11437
+ "p",
11438
+ {
11439
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
11440
+ title: docError
11441
+ },
11442
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
11443
+ ) : /* @__PURE__ */ React18.createElement(
11337
11444
  "button",
11338
11445
  {
11339
11446
  type: "button",
@@ -11342,8 +11449,20 @@ function NodeDetailsPanel({
11342
11449
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
11343
11450
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
11344
11451
  },
11345
- isLoadingDocs ? /* @__PURE__ */ React18.createElement(AiOutlineLoading3Quarters3, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ React18.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
11346
- ), canEdit && /* @__PURE__ */ React18.createElement(
11452
+ isLoadingDocs ? /* @__PURE__ */ React18.createElement(
11453
+ AiOutlineLoading3Quarters3,
11454
+ {
11455
+ className: "animate-spin",
11456
+ size: 18
11457
+ }
11458
+ ) : /* @__PURE__ */ React18.createElement(
11459
+ GoogleDocsIcon_default,
11460
+ {
11461
+ size: 18,
11462
+ className: "group-hover:scale-110 transition-transform"
11463
+ }
11464
+ )
11465
+ )), canEdit && /* @__PURE__ */ React18.createElement(
11347
11466
  "button",
11348
11467
  {
11349
11468
  type: "button",
@@ -11518,7 +11637,8 @@ function QuestDetailsPanel({
11518
11637
  onUpdateMilestones = () => {
11519
11638
  },
11520
11639
  onFocusNode,
11521
- create_google_doc_action
11640
+ create_google_doc_action,
11641
+ view_google_folder_id
11522
11642
  }) {
11523
11643
  var _a, _b;
11524
11644
  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) || "";
@@ -11553,6 +11673,7 @@ function QuestDetailsPanel({
11553
11673
  const [isLinkCopied, setIsLinkCopied] = useState19(false);
11554
11674
  const [isNameCopied, setIsNameCopied] = useState19(false);
11555
11675
  const [isLoadingDocs, setIsLoadingDocs] = useState19(false);
11676
+ const [docError, setDocError] = useState19(null);
11556
11677
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState19(false);
11557
11678
  const [questDate, setQuestDate] = useState19((node == null ? void 0 : node.Date) || null);
11558
11679
  const [noteText, setNoteText] = useState19("");
@@ -11961,7 +12082,8 @@ ${noteText}` : noteText : entry.notes,
11961
12082
  if (!create_google_doc_action) return;
11962
12083
  try {
11963
12084
  setIsLoadingDocs(true);
11964
- const res = await create_google_doc_action(standardizedName);
12085
+ setDocError(null);
12086
+ const res = await create_google_doc_action(standardizedName, view_google_folder_id);
11965
12087
  if (res.success) {
11966
12088
  const existingLinksPropIndex = customProps.findIndex(
11967
12089
  (p) => p.type === "links" && p.key === "Links"
@@ -11991,11 +12113,21 @@ ${noteText}` : noteText : entry.notes,
11991
12113
  window.open(res.link, "_blank");
11992
12114
  }
11993
12115
  } else {
11994
- alert("Erro ao criar documento: " + res.error);
12116
+ if (res.errorType === "PERMISSIONS_ERROR") {
12117
+ setDocError(
12118
+ "Erro: Voc\xEA n\xE3o possui permiss\xE3o de escrita na pasta configurada pela View. Solicite acesso ao Owner."
12119
+ );
12120
+ } else {
12121
+ setDocError(
12122
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
12123
+ );
12124
+ }
11995
12125
  }
11996
12126
  } catch (error) {
11997
12127
  console.error(error);
11998
- alert("Erro ao processar cria\xE7\xE3o do documento.");
12128
+ setDocError(
12129
+ "Falha ao conectar com seu Google Drive. Verifique a integra\xE7\xE3o na sua conta."
12130
+ );
11999
12131
  } finally {
12000
12132
  setIsLoadingDocs(false);
12001
12133
  }
@@ -12605,7 +12737,14 @@ ${noteText}` : noteText : entry.notes,
12605
12737
  },
12606
12738
  /* @__PURE__ */ React20.createElement("span", { className: "truncate" }, q.raw_title || q.name),
12607
12739
  /* @__PURE__ */ React20.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")
12608
- )) : /* @__PURE__ */ React20.createElement("li", { className: "px-3 py-3 text-[10px] text-slate-500 italic text-center" }, "Nenhuma outra quest dispon\xEDvel")))), blockedStatus.isBlocked && /* @__PURE__ */ React20.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__ */ React20.createElement(FiRepeat2, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ React20.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__ */ React20.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React20.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React20.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React20.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ React20.createElement(
12740
+ )) : /* @__PURE__ */ React20.createElement("li", { className: "px-3 py-3 text-[10px] text-slate-500 italic text-center" }, "Nenhuma outra quest dispon\xEDvel")))), blockedStatus.isBlocked && /* @__PURE__ */ React20.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__ */ React20.createElement(FiRepeat2, { className: "text-amber-400 animate-spin-slow", size: 12 }), /* @__PURE__ */ React20.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__ */ React20.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React20.createElement("div", { className: "flex items-center justify-between mb-2" }, /* @__PURE__ */ React20.createElement("h3", { className: "text-sm font-medium" }, "Propriedades Adicionais"), /* @__PURE__ */ React20.createElement("div", { className: "flex items-center gap-2" }, canEdit && create_google_doc_action && /* @__PURE__ */ React20.createElement("div", { className: "flex items-center gap-2" }, docError ? /* @__PURE__ */ React20.createElement(
12741
+ "p",
12742
+ {
12743
+ className: "text-[10px] text-red-400 bg-red-400/10 px-2 py-1 rounded border border-red-400/20 max-w-[200px]",
12744
+ title: docError
12745
+ },
12746
+ docError.length > 50 ? docError.substring(0, 47) + "..." : docError
12747
+ ) : /* @__PURE__ */ React20.createElement(
12609
12748
  "button",
12610
12749
  {
12611
12750
  type: "button",
@@ -12614,8 +12753,20 @@ ${noteText}` : noteText : entry.notes,
12614
12753
  className: "flex items-center justify-center text-slate-300 transition-all disabled:opacity-50 disabled:cursor-not-allowed group",
12615
12754
  title: isLoadingDocs ? "Criando Documento..." : "Criar Documento no Google Docs"
12616
12755
  },
12617
- isLoadingDocs ? /* @__PURE__ */ React20.createElement(AiOutlineLoading3Quarters4, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ React20.createElement(GoogleDocsIcon_default, { size: 18, className: "group-hover:scale-110 transition-transform" })
12618
- ), canEdit && /* @__PURE__ */ React20.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__ */ React20.createElement(FiPlus8, { size: 14 }), " Adicionar"))), /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React20.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__ */ React20.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ React20.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ React20.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ React20.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ React20.createElement(
12756
+ isLoadingDocs ? /* @__PURE__ */ React20.createElement(
12757
+ AiOutlineLoading3Quarters4,
12758
+ {
12759
+ className: "animate-spin",
12760
+ size: 18
12761
+ }
12762
+ ) : /* @__PURE__ */ React20.createElement(
12763
+ GoogleDocsIcon_default,
12764
+ {
12765
+ size: 18,
12766
+ className: "group-hover:scale-110 transition-transform"
12767
+ }
12768
+ )
12769
+ )), canEdit && /* @__PURE__ */ React20.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__ */ React20.createElement(FiPlus8, { size: 14 }), " Adicionar"))), /* @__PURE__ */ React20.createElement("div", { className: "flex flex-col gap-3" }, customProps.map((prop, idx) => /* @__PURE__ */ React20.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__ */ React20.createElement("div", { ref: propsEndRef }))), /* @__PURE__ */ React20.createElement("div", { className: "pt-6 border-t border-white/10 mt-6" }, /* @__PURE__ */ React20.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ React20.createElement("h3", { className: "text-[11px] uppercase font-bold text-slate-500 tracking-wider" }, "Hist\xF3rico & Notas"), /* @__PURE__ */ React20.createElement(
12619
12770
  "button",
12620
12771
  {
12621
12772
  type: "button",
@@ -14881,7 +15032,7 @@ function XViewScene({
14881
15032
  get_view_members,
14882
15033
  create_google_doc_action
14883
15034
  }) {
14884
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
15035
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
14885
15036
  const { data: session, status } = useSession();
14886
15037
  const router = useRouter();
14887
15038
  const searchParams = useSearchParams();
@@ -15258,6 +15409,23 @@ function XViewScene({
15258
15409
  add_new_parent_file_to_scene_at_firebase_action
15259
15410
  ]
15260
15411
  );
15412
+ const handleSaveConfig = useCallback6(
15413
+ async (newConfig) => {
15414
+ if (!sceneDataRef.current || !save_view_data || !sceneSaveUrl) return;
15415
+ const updatedData = {
15416
+ ...sceneDataRef.current,
15417
+ ...newConfig
15418
+ };
15419
+ sceneDataRef.current = updatedData;
15420
+ try {
15421
+ await save_view_data(sceneSaveUrl, updatedData);
15422
+ setSceneVersion((v) => v + 1);
15423
+ } catch (error) {
15424
+ console.error("Erro ao salvar configura\xE7\xE3o da View:", error);
15425
+ }
15426
+ },
15427
+ [save_view_data, sceneSaveUrl]
15428
+ );
15261
15429
  const handleOpenImageViewer = (images, startIndex) => {
15262
15430
  setImageViewer({ visible: true, images, startIndex });
15263
15431
  };
@@ -19567,7 +19735,9 @@ function XViewScene({
19567
19735
  userRole: userPermissionRole,
19568
19736
  viewMembers,
19569
19737
  milestones: ((_c = sceneDataRef.current) == null ? void 0 : _c.milestones) || [],
19570
- onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true)
19738
+ onOpenMilestoneManager: () => setIsMilestoneManagerOpen(true),
19739
+ view_google_folder_id: (_d = sceneDataRef.current) == null ? void 0 : _d.view_google_folder_id,
19740
+ onSaveConfig: handleSaveConfig
19571
19741
  }
19572
19742
  ),
19573
19743
  creationMode.isActive && /* @__PURE__ */ React31.createElement(
@@ -19591,8 +19761,8 @@ function XViewScene({
19591
19761
  },
19592
19762
  refEl: formRef,
19593
19763
  existingTypes: existingNodeTypes,
19594
- initialColor: (_d = creationMode.sourceNodeData) == null ? void 0 : _d.color,
19595
- sourceTypes: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.type,
19764
+ initialColor: (_e = creationMode.sourceNodeData) == null ? void 0 : _e.color,
19765
+ sourceTypes: (_f = creationMode.sourceNodeData) == null ? void 0 : _f.type,
19596
19766
  onIntensityChange: handleGhostNodeIntensityChange,
19597
19767
  onUploadFile: upload_file_action,
19598
19768
  availableDatasets,
@@ -19600,7 +19770,8 @@ function XViewScene({
19600
19770
  viewType: viewParams == null ? void 0 : viewParams.type,
19601
19771
  availableNodes: allAvailableNodes,
19602
19772
  availableAncestries: allAvailableAncestries,
19603
- create_google_doc_action
19773
+ create_google_doc_action,
19774
+ view_google_folder_id: (_g = sceneDataRef.current) == null ? void 0 : _g.view_google_folder_id
19604
19775
  }
19605
19776
  ),
19606
19777
  versionMode.isActive && /* @__PURE__ */ React31.createElement(
@@ -19622,8 +19793,8 @@ function XViewScene({
19622
19793
  transition: "opacity 200ms ease-out"
19623
19794
  },
19624
19795
  refEl: formRef,
19625
- fixedType: (_f = versionMode.sourceNodeData) == null ? void 0 : _f.type,
19626
- fixedColor: (_g = versionMode.sourceNodeData) == null ? void 0 : _g.color,
19796
+ fixedType: (_h = versionMode.sourceNodeData) == null ? void 0 : _h.type,
19797
+ fixedColor: (_i = versionMode.sourceNodeData) == null ? void 0 : _i.color,
19627
19798
  onUploadFile: upload_file_action,
19628
19799
  availableNodes: allAvailableNodes,
19629
19800
  availableAncestries: allAvailableAncestries
@@ -19651,11 +19822,12 @@ function XViewScene({
19651
19822
  availableNodes: allAvailableNodes,
19652
19823
  availableAncestries: allAvailableAncestries,
19653
19824
  viewName: viewParams == null ? void 0 : viewParams.name,
19654
- questCounter: ((_h = sceneDataRef.current) == null ? void 0 : _h.quest_counter) || 1,
19825
+ questCounter: ((_j = sceneDataRef.current) == null ? void 0 : _j.quest_counter) || 1,
19655
19826
  viewMembers,
19656
- milestones: ((_i = sceneDataRef.current) == null ? void 0 : _i.milestones) || [],
19827
+ milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
19657
19828
  onUpdateMilestones: handleUpdateMilestones,
19658
- create_google_doc_action
19829
+ create_google_doc_action,
19830
+ view_google_folder_id: (_l = sceneDataRef.current) == null ? void 0 : _l.view_google_folder_id
19659
19831
  }
19660
19832
  ),
19661
19833
  readingMode.isActive && readingMode.ancestry && /* @__PURE__ */ React31.createElement(
@@ -19789,9 +19961,10 @@ function XViewScene({
19789
19961
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
19790
19962
  viewMembers,
19791
19963
  currentUser: session == null ? void 0 : session.user,
19792
- milestones: ((_j = sceneDataRef.current) == null ? void 0 : _j.milestones) || [],
19964
+ milestones: ((_m = sceneDataRef.current) == null ? void 0 : _m.milestones) || [],
19793
19965
  onUpdateMilestones: handleUpdateMilestones,
19794
- create_google_doc_action
19966
+ create_google_doc_action,
19967
+ view_google_folder_id: (_n = sceneDataRef.current) == null ? void 0 : _n.view_google_folder_id
19795
19968
  }
19796
19969
  ),
19797
19970
  detailsNode && !detailsNode.is_quest && /* @__PURE__ */ React31.createElement(
@@ -19824,7 +19997,8 @@ function XViewScene({
19824
19997
  onUploadFile: upload_file_action,
19825
19998
  userRole: userPermissionRole,
19826
19999
  currentDatasetName: detailsNodeDatasetInfo == null ? void 0 : detailsNodeDatasetInfo.datasetName,
19827
- create_google_doc_action
20000
+ create_google_doc_action,
20001
+ view_google_folder_id: (_o = sceneDataRef.current) == null ? void 0 : _o.view_google_folder_id
19828
20002
  }
19829
20003
  ),
19830
20004
  detailsLink && /* @__PURE__ */ React31.createElement(
@@ -19982,7 +20156,7 @@ function XViewScene({
19982
20156
  {
19983
20157
  isOpen: isMilestoneManagerOpen,
19984
20158
  onClose: () => setIsMilestoneManagerOpen(false),
19985
- milestones: ((_k = sceneDataRef.current) == null ? void 0 : _k.milestones) || [],
20159
+ milestones: ((_p = sceneDataRef.current) == null ? void 0 : _p.milestones) || [],
19986
20160
  onUpdateMilestones: handleUpdateMilestones
19987
20161
  }
19988
20162
  ),
@@ -19993,7 +20167,7 @@ function XViewScene({
19993
20167
  onClose: () => setIsImportModalOpen(false),
19994
20168
  onConfirm: handleConfirmImport,
19995
20169
  session,
19996
- parentDbs: ((_l = sceneDataRef.current) == null ? void 0 : _l.parent_dbs) || [],
20170
+ parentDbs: ((_q = sceneDataRef.current) == null ? void 0 : _q.parent_dbs) || [],
19997
20171
  onFetchAvailableFiles: import_parent_file_modal_get,
19998
20172
  currentViewName: viewParams == null ? void 0 : viewParams.name,
19999
20173
  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.6-dev.65",
3
+ "version": "1.2.6-dev.66",
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",