@v1ct0rbr/minivault-web 0.6.4 → 0.6.5

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.
@@ -1,4 +1,4 @@
1
- import { Backup, BackupType, ConnectionCheck, DatabaseCredentials, DbInfo, DumpOptions, ImportResult, OriginStorageConfig, PageResponse, RelationshipInfo, StorageFileItem, TableDetail, TableInfo, VerifyResult } from '../types/minivault';
1
+ import { Backup, BackupType, ConnectionCheck, DatabaseCredentials, DbInfo, DumpOptions, ImportResult, OriginStorageConfig, PageResponse, RelationshipInfo, StorageFileItem, StorageTarget, StorageZipRequest, TableDetail, TableInfo, VerifyResult, ZipJobStatus } from '../types/minivault';
2
2
  export interface MinivaultApiOptions {
3
3
  /**
4
4
  * URL base da API. Exemplos:
@@ -45,7 +45,11 @@ export declare class MinivaultApi {
45
45
  getDbTable(ref: string): Promise<TableDetail>;
46
46
  listDbRelationships(): Promise<RelationshipInfo[]>;
47
47
  getDiagnostics(): Promise<ConnectionCheck[]>;
48
- listStorageFiles(type: string, prefix?: string, storageConfig?: OriginStorageConfig): Promise<StorageFileItem[]>;
49
- downloadStorageFile(key: string, type: string, storageConfig?: OriginStorageConfig): Promise<Blob>;
50
- deleteStorageFile(key: string, type: string, storageConfig?: OriginStorageConfig): Promise<void>;
48
+ private storageQuery;
49
+ listStorageFiles(type: string, prefix?: string, storageConfig?: OriginStorageConfig, storage?: StorageTarget): Promise<StorageFileItem[]>;
50
+ downloadStorageFile(key: string, type: string, storageConfig?: OriginStorageConfig, storage?: StorageTarget): Promise<Blob>;
51
+ deleteStorageFile(key: string, type: string, storageConfig?: OriginStorageConfig, storage?: StorageTarget): Promise<void>;
52
+ createStorageZip(request: StorageZipRequest): Promise<ZipJobStatus>;
53
+ getStorageZipStatus(jobId: string): Promise<ZipJobStatus>;
54
+ downloadStorageZip(jobId: string): Promise<Blob>;
51
55
  }
@@ -1,7 +1,10 @@
1
- import { OriginStorageConfig } from '../types/minivault';
1
+ import { OriginStorageConfig, StorageTarget } from '../types/minivault';
2
2
  interface StorageExplorerTabProps {
3
+ /** Qual storage o explorador manipula (origem ou destino). */
4
+ target?: StorageTarget;
5
+ title?: string;
3
6
  storageType?: string;
4
7
  storageConfig?: OriginStorageConfig;
5
8
  }
6
- export declare function StorageExplorerTab({ storageType, storageConfig }: StorageExplorerTabProps): import("react").JSX.Element;
9
+ export declare function StorageExplorerTab({ target, title, storageType, storageConfig, }: StorageExplorerTabProps): import("react").JSX.Element;
7
10
  export {};
@@ -138,37 +138,60 @@ var h = class extends Error {
138
138
  getDiagnostics() {
139
139
  return this.request("/api/diagnostics");
140
140
  }
141
- listStorageFiles(e, t, n) {
142
- let r = new URLSearchParams({ type: e });
143
- return t && r.set("prefix", t), n && (n.endpoint && r.set("endpoint", n.endpoint), n.bucketName && r.set("bucketName", n.bucketName), n.accessKey && r.set("accessKey", n.accessKey), n.secretKey && r.set("secretKey", n.secretKey), n.region && r.set("region", n.region), n.pathStyleEnabled && r.set("pathStyleEnabled", "true"), n.localPath && r.set("localPath", n.localPath)), this.request(`/api/storage/files?${r.toString()}`);
141
+ storageQuery(e, t) {
142
+ let n = new URLSearchParams({ storage: e });
143
+ return t && (t.type && n.set("type", t.type), t.endpoint && n.set("endpoint", t.endpoint), t.bucketName && n.set("bucketName", t.bucketName), t.accessKey && n.set("accessKey", t.accessKey), t.secretKey && n.set("secretKey", t.secretKey), t.region && n.set("region", t.region), t.pathStyleEnabled && n.set("pathStyleEnabled", "true"), t.localPath && n.set("localPath", t.localPath)), n;
144
144
  }
145
- async downloadStorageFile(e, t, n) {
146
- let r = await this.resolveToken(), i = new URLSearchParams({
147
- key: e,
148
- type: t
149
- });
150
- n && (n.endpoint && i.set("endpoint", n.endpoint), n.bucketName && i.set("bucketName", n.bucketName), n.accessKey && i.set("accessKey", n.accessKey), n.secretKey && i.set("secretKey", n.secretKey), n.region && i.set("region", n.region), n.pathStyleEnabled && i.set("pathStyleEnabled", "true"), n.localPath && i.set("localPath", n.localPath));
151
- let a = { Accept: "application/octet-stream" };
152
- r && (a.Authorization = `Bearer ${r}`);
153
- let o = new AbortController(), s = setTimeout(() => o.abort(), this.timeoutMs);
145
+ listStorageFiles(e, t, n, r = "origin") {
146
+ let i = this.storageQuery(r, n);
147
+ return i.set("type", e), t && i.set("prefix", t), this.request(`/api/storage/files?${i.toString()}`);
148
+ }
149
+ async downloadStorageFile(e, t, n, r = "origin") {
150
+ let i = await this.resolveToken(), a = this.storageQuery(r, n);
151
+ a.set("key", e), a.set("type", t);
152
+ let o = { Accept: "application/octet-stream" };
153
+ i && (o.Authorization = `Bearer ${i}`);
154
+ let s = new AbortController(), c = setTimeout(() => s.abort(), this.timeoutMs);
154
155
  try {
155
- let e = await this.fetchFn(`${this.baseUrl}/api/storage/files/download?${i.toString()}`, {
156
+ let e = await this.fetchFn(`${this.baseUrl}/api/storage/files/download?${a.toString()}`, {
156
157
  method: "GET",
157
- headers: a,
158
- signal: o.signal
158
+ headers: o,
159
+ signal: s.signal
159
160
  });
160
161
  if (!e.ok) throw new h(`Minivault API GET /api/storage/files/download falhou (HTTP ${e.status})`, e.status);
161
162
  return await e.blob();
162
163
  } finally {
163
- clearTimeout(s);
164
+ clearTimeout(c);
164
165
  }
165
166
  }
166
- async deleteStorageFile(e, t, n) {
167
- let r = new URLSearchParams({
168
- key: e,
169
- type: t
167
+ async deleteStorageFile(e, t, n, r = "origin") {
168
+ let i = this.storageQuery(r, n);
169
+ i.set("key", e), i.set("type", t), await this.request(`/api/storage/files?${i.toString()}`, { method: "DELETE" });
170
+ }
171
+ createStorageZip(e) {
172
+ return this.request("/api/storage/download/zip", {
173
+ method: "POST",
174
+ body: JSON.stringify(e)
170
175
  });
171
- n && (n.endpoint && r.set("endpoint", n.endpoint), n.bucketName && r.set("bucketName", n.bucketName), n.accessKey && r.set("accessKey", n.accessKey), n.secretKey && r.set("secretKey", n.secretKey), n.region && r.set("region", n.region), n.pathStyleEnabled && r.set("pathStyleEnabled", "true"), n.localPath && r.set("localPath", n.localPath)), await this.request(`/api/storage/files?${r.toString()}`, { method: "DELETE" });
176
+ }
177
+ getStorageZipStatus(e) {
178
+ return this.request(`/api/storage/download/zip/${encodeURIComponent(e)}`);
179
+ }
180
+ async downloadStorageZip(e) {
181
+ let t = await this.resolveToken(), n = { Accept: "application/octet-stream" };
182
+ t && (n.Authorization = `Bearer ${t}`);
183
+ let r = new AbortController(), i = setTimeout(() => r.abort(), this.timeoutMs);
184
+ try {
185
+ let t = await this.fetchFn(`${this.baseUrl}/api/storage/download/zip/${encodeURIComponent(e)}/content`, {
186
+ method: "GET",
187
+ headers: n,
188
+ signal: r.signal
189
+ });
190
+ if (!t.ok) throw new h(`Minivault API GET /api/storage/download/zip/${e}/content falhou (HTTP ${t.status})`, t.status);
191
+ return await t.blob();
192
+ } finally {
193
+ clearTimeout(i);
194
+ }
172
195
  }
173
196
  };
174
197
  function _(e) {
@@ -297,46 +320,46 @@ function P() {
297
320
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
298
321
  });
299
322
  }
300
- function ee() {
323
+ function F() {
301
324
  let e = b();
302
325
  return l({ mutationFn: (t) => e.downloadBackup(t.id) });
303
326
  }
304
- function F() {
327
+ function I() {
305
328
  let e = b();
306
329
  return l({ mutationFn: (t) => e.importDump(t.file, t.database) });
307
330
  }
308
- function I() {
331
+ function L() {
309
332
  let e = b();
310
333
  return l({ mutationFn: (t) => e.importFromStorage(t.storageType, t.storagePath, t.database, t.storageConfig) });
311
334
  }
312
335
  //#endregion
313
336
  //#region src/utils/format.ts
314
- var te = new Intl.DateTimeFormat("pt-BR", {
337
+ var R = new Intl.DateTimeFormat("pt-BR", {
315
338
  day: "2-digit",
316
339
  month: "2-digit",
317
340
  year: "numeric",
318
341
  hour: "2-digit",
319
342
  minute: "2-digit"
320
- }), L = [
343
+ }), z = [
321
344
  "B",
322
345
  "KB",
323
346
  "MB",
324
347
  "GB",
325
348
  "TB"
326
349
  ];
327
- function R(e) {
350
+ function B(e) {
328
351
  if (e == null || e < 0) return "—";
329
352
  if (e < 1024) return `${e} B`;
330
353
  let t = e, n = 0;
331
- for (; t >= 1024 && n < L.length - 1;) t /= 1024, n += 1;
332
- return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${L[n]}`;
354
+ for (; t >= 1024 && n < z.length - 1;) t /= 1024, n += 1;
355
+ return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${z[n]}`;
333
356
  }
334
- function z(e) {
357
+ function V(e) {
335
358
  if (!e) return "—";
336
359
  let t = new Date(e);
337
- return Number.isNaN(t.getTime()) ? "—" : te.format(t);
360
+ return Number.isNaN(t.getTime()) ? "—" : R.format(t);
338
361
  }
339
- var B = {
362
+ var H = {
340
363
  PENDING: "Pendente",
341
364
  IN_PROGRESS: "Em andamento",
342
365
  COMPLETED: "Concluído",
@@ -344,7 +367,7 @@ var B = {
344
367
  RESTORING: "Restaurando",
345
368
  RESTORED: "Restaurado",
346
369
  RESTORE_FAILED: "Falha na restauração"
347
- }, V = {
370
+ }, U = {
348
371
  PENDING: "text-bg-secondary",
349
372
  IN_PROGRESS: "text-bg-primary",
350
373
  COMPLETED: "text-bg-success",
@@ -352,25 +375,25 @@ var B = {
352
375
  RESTORING: "text-bg-warning",
353
376
  RESTORED: "text-bg-info",
354
377
  RESTORE_FAILED: "text-bg-danger"
355
- }, H = {
378
+ }, W = {
356
379
  postgresql: "PostgreSQL",
357
380
  postgres: "PostgreSQL",
358
381
  mysql: "MySQL",
359
382
  sqlserver: "SQL Server",
360
383
  mssql: "SQL Server"
361
- }, ne = {
384
+ }, G = {
362
385
  DATABASE: "Banco de dados",
363
386
  STORAGE: "Storage",
364
387
  FULL: "Completo"
365
- }, re = {
388
+ }, K = {
366
389
  DATABASE: "text-bg-primary",
367
390
  STORAGE: "text-bg-info",
368
391
  FULL: "text-bg-secondary"
369
392
  };
370
393
  //#endregion
371
394
  //#region src/components/StatusBadge.tsx
372
- function U({ status: e }) {
373
- let t = V[e] ?? "text-bg-secondary", n = B[e] ?? e;
395
+ function q({ status: e }) {
396
+ let t = U[e] ?? "text-bg-secondary", n = H[e] ?? e;
374
397
  return /* @__PURE__ */ p("span", {
375
398
  className: `badge rounded-pill ${t}`,
376
399
  children: n
@@ -378,7 +401,7 @@ function U({ status: e }) {
378
401
  }
379
402
  //#endregion
380
403
  //#region src/components/DatabaseBanner.tsx
381
- function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
404
+ function J({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
382
405
  if (t) return /* @__PURE__ */ p("div", {
383
406
  className: "mb-3",
384
407
  children: /* @__PURE__ */ m("small", {
@@ -397,7 +420,7 @@ function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
397
420
  "aria-hidden": !0
398
421
  }),
399
422
  "Não foi possível consultar o banco configurado: ",
400
- K(n)
423
+ X(n)
401
424
  ]
402
425
  });
403
426
  if (!e || !e.configured) return i ? /* @__PURE__ */ m("div", {
@@ -419,7 +442,7 @@ function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
419
442
  "). A criação e a importação usam esse banco."
420
443
  ]
421
444
  });
422
- let a = H[e.databaseType ?? ""] ?? e.databaseType ?? "postgresql";
445
+ let a = W[e.databaseType ?? ""] ?? e.databaseType ?? "postgresql";
423
446
  return i ? /* @__PURE__ */ m("div", {
424
447
  className: "mb-3",
425
448
  children: [
@@ -537,7 +560,7 @@ function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
537
560
  }
538
561
  //#endregion
539
562
  //#region src/components/RestoreModal.tsx
540
- function G({ backup: e, onClose: t }) {
563
+ function Y({ backup: e, onClose: t }) {
541
564
  let n = M(), r = D(), i = () => {
542
565
  n.mutate({ id: e.id });
543
566
  }, a = n.isPending, o = e.backupType === "STORAGE";
@@ -588,7 +611,7 @@ function G({ backup: e, onClose: t }) {
588
611
  " será aplicado no banco configurado abaixo."
589
612
  ] })
590
613
  }),
591
- !o && /* @__PURE__ */ p(W, {
614
+ !o && /* @__PURE__ */ p(J, {
592
615
  label: "Banco de destino",
593
616
  dbInfo: r.data,
594
617
  isLoading: r.isLoading,
@@ -599,7 +622,7 @@ function G({ backup: e, onClose: t }) {
599
622
  children: [/* @__PURE__ */ p("i", {
600
623
  className: "bi bi-x-circle me-2",
601
624
  "aria-hidden": !0
602
- }), K(n.error)]
625
+ }), X(n.error)]
603
626
  }),
604
627
  n.isSuccess && /* @__PURE__ */ m("div", {
605
628
  className: "alert alert-success mt-3 mb-0",
@@ -634,13 +657,13 @@ function G({ backup: e, onClose: t }) {
634
657
  })
635
658
  })] });
636
659
  }
637
- function K(e) {
660
+ function X(e) {
638
661
  return e instanceof Error ? e.message : String(e);
639
662
  }
640
663
  //#endregion
641
664
  //#region src/components/BackupsTab.tsx
642
- function q() {
643
- let [e, t] = o(0), [n, a] = o(null), [s, c] = o(null), [l, u] = o({}), { data: d, isLoading: f, isError: h, error: g, refetch: _, isFetching: v } = E(e, 10, !0), y = ee(), b = N(), x = P();
665
+ function Z() {
666
+ let [e, t] = o(0), [n, a] = o(null), [s, c] = o(null), [l, u] = o({}), { data: d, isLoading: f, isError: h, error: g, refetch: _, isFetching: v } = E(e, 10, !0), y = F(), b = N(), x = P();
644
667
  r(() => {
645
668
  if (!y.data || !y.variables) return;
646
669
  let e = URL.createObjectURL(y.data), t = document.createElement("a");
@@ -682,7 +705,7 @@ function q() {
682
705
  "aria-hidden": !0
683
706
  }),
684
707
  "Não foi possível carregar os backups: ",
685
- J(g)
708
+ Q(g)
686
709
  ]
687
710
  }),
688
711
  y.isError && /* @__PURE__ */ m("div", {
@@ -693,7 +716,7 @@ function q() {
693
716
  "aria-hidden": !0
694
717
  }),
695
718
  "Falha no download: ",
696
- J(y.error)
719
+ Q(y.error)
697
720
  ]
698
721
  }),
699
722
  b.isError && /* @__PURE__ */ m("div", {
@@ -704,7 +727,7 @@ function q() {
704
727
  "aria-hidden": !0
705
728
  }),
706
729
  "Falha ao excluir: ",
707
- J(b.error)
730
+ Q(b.error)
708
731
  ]
709
732
  }),
710
733
  x.isError && /* @__PURE__ */ m("div", {
@@ -715,7 +738,7 @@ function q() {
715
738
  "aria-hidden": !0
716
739
  }),
717
740
  "Falha ao verificar: ",
718
- J(x.error)
741
+ Q(x.error)
719
742
  ]
720
743
  }),
721
744
  Object.entries(l).map(([e, t]) => /* @__PURE__ */ m("div", {
@@ -808,18 +831,18 @@ function q() {
808
831
  }), e.filename]
809
832
  }),
810
833
  /* @__PURE__ */ p("td", { children: e.backupType ? /* @__PURE__ */ p("span", {
811
- className: `badge ${re[e.backupType] ?? "text-bg-secondary"}`,
812
- children: ne[e.backupType] ?? e.backupType
834
+ className: `badge ${K[e.backupType] ?? "text-bg-secondary"}`,
835
+ children: G[e.backupType] ?? e.backupType
813
836
  }) : /* @__PURE__ */ p("span", {
814
837
  className: "text-muted",
815
838
  children: "—"
816
839
  }) }),
817
- /* @__PURE__ */ p("td", { children: H[e.databaseType] ?? e.databaseType }),
840
+ /* @__PURE__ */ p("td", { children: W[e.databaseType] ?? e.databaseType }),
818
841
  /* @__PURE__ */ p("td", {
819
842
  className: "text-end",
820
- children: R(e.fileSize)
843
+ children: B(e.fileSize)
821
844
  }),
822
- /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(U, { status: e.status }) }),
845
+ /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(q, { status: e.status }) }),
823
846
  /* @__PURE__ */ p("td", { children: e.sha256 ? /* @__PURE__ */ m("code", {
824
847
  title: e.sha256,
825
848
  style: { fontSize: "0.8em" },
@@ -842,7 +865,7 @@ function q() {
842
865
  className: "text-muted",
843
866
  children: "—"
844
867
  }) }),
845
- /* @__PURE__ */ p("td", { children: z(e.createdAt) }),
868
+ /* @__PURE__ */ p("td", { children: V(e.createdAt) }),
846
869
  /* @__PURE__ */ m("td", {
847
870
  className: "text-end text-nowrap",
848
871
  children: [
@@ -935,11 +958,11 @@ function q() {
935
958
  })]
936
959
  })]
937
960
  }),
938
- n && /* @__PURE__ */ p(G, {
961
+ n && /* @__PURE__ */ p(Y, {
939
962
  backup: n,
940
963
  onClose: () => a(null)
941
964
  }),
942
- s && /* @__PURE__ */ p(ie, {
965
+ s && /* @__PURE__ */ p(ee, {
943
966
  backup: s,
944
967
  busy: b.isPending,
945
968
  onCancel: () => c(null),
@@ -949,7 +972,7 @@ function q() {
949
972
  })
950
973
  ] });
951
974
  }
952
- function ie(e) {
975
+ function ee(e) {
953
976
  let { backup: t, busy: n, onCancel: r, onConfirm: i } = e;
954
977
  return /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", { className: "modal-backdrop show" }), /* @__PURE__ */ p("div", {
955
978
  className: "modal show d-block",
@@ -1015,12 +1038,12 @@ function ie(e) {
1015
1038
  })
1016
1039
  })] });
1017
1040
  }
1018
- function J(e) {
1041
+ function Q(e) {
1019
1042
  return e instanceof Error ? e.message : String(e);
1020
1043
  }
1021
1044
  //#endregion
1022
1045
  //#region src/components/CreateBackupTab.tsx
1023
- function Y() {
1046
+ function te() {
1024
1047
  let e = j(), t = D(), n = O(t.data?.configured), [r, a] = o(!0), [s, c] = o({
1025
1048
  format: "plain",
1026
1049
  includeData: !0,
@@ -1029,7 +1052,7 @@ function Y() {
1029
1052
  includeIndexes: !0,
1030
1053
  includeConstraints: !0,
1031
1054
  includeRelatedTables: !1
1032
- }), [l, u] = o(() => /* @__PURE__ */ new Set()), [d, f] = o(null), [h, g] = o({}), [_, v] = o(""), y = k(d, t.data?.configured), b = i(() => new Set((t.data?.exportExcludedTables ?? []).map(oe)), [t.data?.exportExcludedTables]), x = i(() => {
1055
+ }), [l, u] = o(() => /* @__PURE__ */ new Set()), [d, f] = o(null), [h, g] = o({}), [_, v] = o(""), y = k(d, t.data?.configured), b = i(() => new Set((t.data?.exportExcludedTables ?? []).map(re)), [t.data?.exportExcludedTables]), x = i(() => {
1033
1056
  let e = n.data ?? [], t = _.trim().toLowerCase();
1034
1057
  return t ? e.filter((e) => e.fullName.toLowerCase().includes(t)) : e;
1035
1058
  }, [n.data, _]), S = i(() => Object.values(h).reduce((e, t) => e + t.length, 0), [h]), C = (e) => {
@@ -1070,7 +1093,7 @@ function Y() {
1070
1093
  children: "Selecione as tabelas no grid e expanda um card para marcar colunas cujo conteúdo será nulificado na exportação. Apenas o dump do banco é enviado ao storage de destino."
1071
1094
  })]
1072
1095
  }),
1073
- /* @__PURE__ */ p(W, {
1096
+ /* @__PURE__ */ p(J, {
1074
1097
  label: "Banco de destino",
1075
1098
  dbInfo: t.data,
1076
1099
  isLoading: t.isLoading,
@@ -1129,7 +1152,7 @@ function Y() {
1129
1152
  "aria-hidden": !0
1130
1153
  }),
1131
1154
  "Falha ao listar tabelas: ",
1132
- K(n.error)
1155
+ X(n.error)
1133
1156
  ]
1134
1157
  }),
1135
1158
  x.length === 0 && !n.isLoading && /* @__PURE__ */ p("div", {
@@ -1145,7 +1168,7 @@ function Y() {
1145
1168
  maxHeight: 420,
1146
1169
  overflow: "auto"
1147
1170
  },
1148
- children: x.map((e) => /* @__PURE__ */ p(ae, {
1171
+ children: x.map((e) => /* @__PURE__ */ p(ne, {
1149
1172
  table: e,
1150
1173
  disabled: b.has(e.fullName),
1151
1174
  selected: l.has(e.fullName),
@@ -1306,7 +1329,7 @@ function Y() {
1306
1329
  "aria-hidden": !0
1307
1330
  }),
1308
1331
  "Falha ao criar backup: ",
1309
- K(e.error)
1332
+ X(e.error)
1310
1333
  ]
1311
1334
  }),
1312
1335
  e.isSuccess && /* @__PURE__ */ m("div", {
@@ -1345,7 +1368,7 @@ function Y() {
1345
1368
  })
1346
1369
  ] });
1347
1370
  }
1348
- function ae({ table: e, disabled: t, selected: n, expanded: r, excluded: i, detail: a, onToggleTable: o, onToggleExpand: s, onToggleColumn: c }) {
1371
+ function ne({ table: e, disabled: t, selected: n, expanded: r, excluded: i, detail: a, onToggleTable: o, onToggleExpand: s, onToggleColumn: c }) {
1349
1372
  return /* @__PURE__ */ p("div", {
1350
1373
  className: `card h-100 ${n ? "border-primary" : ""}`,
1351
1374
  style: { minWidth: 0 },
@@ -1409,7 +1432,7 @@ function ae({ table: e, disabled: t, selected: n, expanded: r, excluded: i, deta
1409
1432
  }),
1410
1433
  a?.isError && /* @__PURE__ */ m("small", {
1411
1434
  className: "text-danger",
1412
- children: ["Erro: ", K(a.error)]
1435
+ children: ["Erro: ", X(a.error)]
1413
1436
  }),
1414
1437
  a?.data && /* @__PURE__ */ m(f, { children: [a.data.columns.map((e) => /* @__PURE__ */ m("div", {
1415
1438
  className: "d-flex align-items-center gap-2 py-1",
@@ -1460,13 +1483,13 @@ function ae({ table: e, disabled: t, selected: n, expanded: r, excluded: i, deta
1460
1483
  })
1461
1484
  });
1462
1485
  }
1463
- function oe(e) {
1486
+ function re(e) {
1464
1487
  let t = e.trim();
1465
1488
  return t.includes(".") ? t : `public.${t}`;
1466
1489
  }
1467
1490
  //#endregion
1468
1491
  //#region src/components/DiagnosticsTab.tsx
1469
- function X() {
1492
+ function ie() {
1470
1493
  let { data: e, isLoading: t, isError: n, error: r, refetch: a, isFetching: o } = T(), s = i(() => e ? {
1471
1494
  total: e.length,
1472
1495
  okCount: e.filter((e) => e.ok).length,
@@ -1507,7 +1530,7 @@ function X() {
1507
1530
  "aria-hidden": !0
1508
1531
  }),
1509
1532
  "Não foi possível executar as checagens: ",
1510
- K(r)
1533
+ X(r)
1511
1534
  ]
1512
1535
  }),
1513
1536
  s && /* @__PURE__ */ m("div", {
@@ -1544,7 +1567,7 @@ function X() {
1544
1567
  className: "card",
1545
1568
  children: /* @__PURE__ */ m("ul", {
1546
1569
  className: "list-group list-group-flush",
1547
- children: [(e ?? []).map((e) => /* @__PURE__ */ p(se, { check: e }, e.name)), e && e.length === 0 && /* @__PURE__ */ p("li", {
1570
+ children: [(e ?? []).map((e) => /* @__PURE__ */ p(ae, { check: e }, e.name)), e && e.length === 0 && /* @__PURE__ */ p("li", {
1548
1571
  className: "list-group-item text-center text-muted py-4",
1549
1572
  children: "Nenhuma checagem retornada."
1550
1573
  })]
@@ -1552,7 +1575,7 @@ function X() {
1552
1575
  })
1553
1576
  ] });
1554
1577
  }
1555
- function se({ check: e }) {
1578
+ function ae({ check: e }) {
1556
1579
  let t = e.configured ? e.ok ? "bi-check-circle-fill text-success" : "bi-x-octagon-fill text-danger" : "bi-dash-circle text-secondary", n = e.configured ? e.ok ? "text-bg-success" : "text-bg-danger" : "text-bg-secondary", r = e.configured ? e.ok ? "OK" : "Falha" : "Não configurado";
1557
1580
  return /* @__PURE__ */ m("li", {
1558
1581
  className: "list-group-item d-flex align-items-start gap-3",
@@ -1588,48 +1611,87 @@ function se({ check: e }) {
1588
1611
  }
1589
1612
  //#endregion
1590
1613
  //#region src/components/StorageExplorerTab.tsx
1591
- function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1592
- let i = b(), s = d(), [c, h] = o(""), [g, _] = o([]), [v, y] = o(/* @__PURE__ */ new Set()), [x, S] = o(null), C = n?.type ?? e, { data: w, isLoading: T } = u({
1614
+ var oe = 1500;
1615
+ function $({ target: e = "origin", title: n = "Explorador de Storage", storageType: i = "LOCAL", storageConfig: a }) {
1616
+ let s = b(), c = d(), [h, g] = o(""), [_, v] = o([]), [y, x] = o(/* @__PURE__ */ new Set()), [S, C] = o(null), [w, T] = o(null), [E, D] = o(null), [O, k] = o(!1), A = a?.type ?? i, j = e === "destination" ? "Destino" : "Origem", { data: M, isLoading: N } = u({
1593
1617
  queryKey: [
1594
1618
  "storage-files",
1595
- C,
1596
- c,
1597
- n
1619
+ e,
1620
+ A,
1621
+ h,
1622
+ a
1598
1623
  ],
1599
- queryFn: () => i.listStorageFiles(C, c || void 0, n)
1600
- }), E = l({
1601
- mutationFn: (e) => i.deleteStorageFile(e, C, n),
1624
+ queryFn: () => s.listStorageFiles(A, h || void 0, a, e)
1625
+ }), P = l({
1626
+ mutationFn: (t) => s.deleteStorageFile(t, A, a, e),
1602
1627
  onSuccess: () => {
1603
- s.invalidateQueries({ queryKey: ["storage-files"] }), S(null);
1628
+ c.invalidateQueries({ queryKey: ["storage-files"] }), C(null);
1604
1629
  }
1605
- }), D = a(!1), O = t((e) => {
1606
- h(e), _(e ? e.split("/").filter(Boolean) : []), y(/* @__PURE__ */ new Set());
1607
- }, []), k = t((e) => {
1608
- let t = g.slice(0, e + 1).join("/");
1609
- O(t);
1610
- }, [g, O]);
1630
+ }), F = t((e) => {
1631
+ g(e), v(e ? e.split("/").filter(Boolean) : []), x(/* @__PURE__ */ new Set());
1632
+ }, []), I = t((e) => {
1633
+ let t = _.slice(0, e + 1).join("/");
1634
+ F(t);
1635
+ }, [_, F]);
1611
1636
  r(() => {
1612
- _(c ? c.split("/").filter(Boolean) : []);
1613
- }, [c]);
1614
- let A = (e) => {
1615
- y((t) => {
1637
+ v(h ? h.split("/").filter(Boolean) : []);
1638
+ }, [h]);
1639
+ let L = (e) => {
1640
+ x((t) => {
1616
1641
  let n = new Set(t);
1617
1642
  return n.has(e) ? n.delete(e) : n.add(e), n;
1618
1643
  });
1619
- }, j = () => {
1620
- w && (v.size === w.length ? y(/* @__PURE__ */ new Set()) : y(new Set(w.map((e) => e.path))));
1621
- }, M = async (e) => {
1644
+ }, R = () => {
1645
+ M && x((e) => e.size === M.length ? /* @__PURE__ */ new Set() : new Set(M.map((e) => e.path)));
1646
+ }, z = (e, t) => {
1647
+ let n = window.URL.createObjectURL(e), r = document.createElement("a");
1648
+ r.href = n, r.download = t, document.body.appendChild(r), r.click(), r.remove(), window.URL.revokeObjectURL(n);
1649
+ }, H = async (t, n) => {
1650
+ let r = {
1651
+ storage: e,
1652
+ type: A,
1653
+ mode: t,
1654
+ keys: n
1655
+ };
1656
+ a?.localPath && (r.localPath = a.localPath), a?.endpoint && (r.endpoint = a.endpoint), a?.bucketName && (r.bucketName = a.bucketName), a?.accessKey && (r.accessKey = a.accessKey), a?.secretKey && (r.secretKey = a.secretKey), a?.region && (r.region = a.region), a?.pathStyleEnabled && (r.pathStyleEnabled = !0), D(null);
1657
+ let i = await s.createStorageZip(r);
1658
+ T(i);
1659
+ }, U = async (e) => {
1660
+ await H("file", [e]);
1661
+ }, W = async () => {
1662
+ await H("zip", [...y]);
1663
+ }, G = async (e) => {
1622
1664
  try {
1623
- let t = await i.downloadStorageFile(e, C, n), r = e.split("/").pop() ?? e, a = window.URL.createObjectURL(t), o = document.createElement("a");
1624
- o.href = a, o.download = r, document.body.appendChild(o), o.click(), o.remove(), window.URL.revokeObjectURL(a);
1625
- } catch {}
1626
- }, N = async () => {
1627
- let e = [...v].filter((e) => {
1628
- let t = w?.find((t) => t.path === e);
1629
- return t != null && !t.directory;
1630
- });
1631
- for (let t of e) await M(t);
1632
- }, P = (e) => e ? z(e) : "-";
1665
+ k(!0);
1666
+ let t = await s.downloadStorageZip(e.jobId);
1667
+ z(t, e.fileName ?? `storage_${j.toLowerCase()}.zip`);
1668
+ } catch (e) {
1669
+ D(e instanceof Error ? e.message : String(e));
1670
+ } finally {
1671
+ k(!1), T(null);
1672
+ }
1673
+ };
1674
+ r(() => {
1675
+ let e = w?.jobId;
1676
+ if (!e) return;
1677
+ let t = !1, n;
1678
+ return n = window.setInterval(async () => {
1679
+ let r;
1680
+ try {
1681
+ r = await s.getStorageZipStatus(e);
1682
+ } catch (e) {
1683
+ if (window.clearInterval(n), t) return;
1684
+ D(e instanceof Error ? e.message : String(e)), T(null);
1685
+ return;
1686
+ }
1687
+ t || (T(r), r.status === "DONE" ? (window.clearInterval(n), await G(r)) : r.status === "FAILED" && (window.clearInterval(n), D(r.message)));
1688
+ }, oe), () => {
1689
+ t = !0, window.clearInterval(n);
1690
+ };
1691
+ }, [w?.jobId]);
1692
+ let K = () => {
1693
+ T(null), D(null);
1694
+ }, q = (e) => e ? V(e) : "-";
1633
1695
  return /* @__PURE__ */ m("div", {
1634
1696
  className: "space-y-3",
1635
1697
  children: [
@@ -1639,30 +1701,34 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1639
1701
  className: "mb-0",
1640
1702
  children: [
1641
1703
  /* @__PURE__ */ p("i", { className: "bi bi-folder2-open me-2" }),
1642
- "Explorador de Storage",
1704
+ n,
1643
1705
  /* @__PURE__ */ p("span", {
1644
1706
  className: "badge bg-secondary ms-2",
1645
- children: C
1707
+ children: j
1708
+ }),
1709
+ /* @__PURE__ */ p("span", {
1710
+ className: "badge bg-light text-dark border ms-1",
1711
+ children: A
1646
1712
  })
1647
1713
  ]
1648
1714
  }), /* @__PURE__ */ p("div", {
1649
1715
  className: "d-flex gap-2",
1650
- children: v.size > 0 && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ m("button", {
1716
+ children: y.size > 0 && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ m("button", {
1651
1717
  className: "btn btn-sm btn-outline-primary",
1652
- onClick: N,
1718
+ onClick: W,
1653
1719
  children: [
1654
1720
  /* @__PURE__ */ p("i", { className: "bi bi-download me-1" }),
1655
- "Baixar (",
1656
- v.size,
1721
+ "Baixar seleção (",
1722
+ y.size,
1657
1723
  ")"
1658
1724
  ]
1659
1725
  }), /* @__PURE__ */ m("button", {
1660
1726
  className: "btn btn-sm btn-outline-danger",
1661
- onClick: () => S("multiple"),
1727
+ onClick: () => C("multiple"),
1662
1728
  children: [
1663
1729
  /* @__PURE__ */ p("i", { className: "bi bi-trash me-1" }),
1664
1730
  "Excluir (",
1665
- v.size,
1731
+ y.size,
1666
1732
  ")"
1667
1733
  ]
1668
1734
  })] })
@@ -1673,19 +1739,19 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1673
1739
  children: /* @__PURE__ */ m("ol", {
1674
1740
  className: "breadcrumb mb-0 small",
1675
1741
  children: [/* @__PURE__ */ p("li", {
1676
- className: `breadcrumb-item ${g.length === 0 ? "active" : ""}`,
1677
- style: { cursor: g.length > 0 ? "pointer" : "default" },
1678
- onClick: () => O(""),
1742
+ className: `breadcrumb-item ${_.length === 0 ? "active" : ""}`,
1743
+ style: { cursor: _.length > 0 ? "pointer" : "default" },
1744
+ onClick: () => F(""),
1679
1745
  children: /* @__PURE__ */ p("i", { className: "bi bi-house" })
1680
- }), g.map((e, t) => /* @__PURE__ */ p("li", {
1681
- className: `breadcrumb-item ${t === g.length - 1 ? "active" : ""}`,
1682
- style: { cursor: t < g.length - 1 ? "pointer" : "default" },
1683
- onClick: () => t < g.length - 1 && k(t),
1746
+ }), _.map((e, t) => /* @__PURE__ */ p("li", {
1747
+ className: `breadcrumb-item ${t === _.length - 1 ? "active" : ""}`,
1748
+ style: { cursor: t < _.length - 1 ? "pointer" : "default" },
1749
+ onClick: () => t < _.length - 1 && I(t),
1684
1750
  children: e
1685
1751
  }, t))]
1686
1752
  })
1687
1753
  }),
1688
- T ? /* @__PURE__ */ m("div", {
1754
+ N ? /* @__PURE__ */ m("div", {
1689
1755
  className: "text-center py-5",
1690
1756
  children: [/* @__PURE__ */ p("div", {
1691
1757
  className: "spinner-border text-primary",
@@ -1694,14 +1760,14 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1694
1760
  className: "mt-2 small text-muted",
1695
1761
  children: "Carregando arquivos..."
1696
1762
  })]
1697
- }) : !w || w.length === 0 ? /* @__PURE__ */ m("div", {
1763
+ }) : !M || M.length === 0 ? /* @__PURE__ */ m("div", {
1698
1764
  className: "text-center py-5 text-muted",
1699
1765
  children: [
1700
1766
  /* @__PURE__ */ p("i", { className: "bi bi-folder-x fs-1 d-block mb-2" }),
1701
1767
  "Nenhum arquivo encontrado",
1702
- c && /* @__PURE__ */ p("button", {
1768
+ h && /* @__PURE__ */ p("button", {
1703
1769
  className: "btn btn-sm btn-link mt-2",
1704
- onClick: () => O(""),
1770
+ onClick: () => F(""),
1705
1771
  children: "Voltar ao inicio"
1706
1772
  })
1707
1773
  ]
@@ -1709,11 +1775,11 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1709
1775
  className: "d-flex align-items-center gap-2 mb-2",
1710
1776
  children: [/* @__PURE__ */ m("button", {
1711
1777
  className: "btn btn-sm btn-outline-secondary",
1712
- onClick: j,
1713
- children: [v.size === w.length ? "Desmarcar" : "Selecionar", " Todos"]
1778
+ onClick: R,
1779
+ children: [y.size === M.length ? "Desmarcar" : "Selecionar", " Todos"]
1714
1780
  }), /* @__PURE__ */ m("span", {
1715
1781
  className: "small text-muted",
1716
- children: [w.length, " item(ns)"]
1782
+ children: [M.length, " item(ns)"]
1717
1783
  })]
1718
1784
  }), /* @__PURE__ */ p("div", {
1719
1785
  className: "table-responsive",
@@ -1737,18 +1803,18 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1737
1803
  children: "Acoes"
1738
1804
  })
1739
1805
  ] })
1740
- }), /* @__PURE__ */ p("tbody", { children: w.map((e) => /* @__PURE__ */ m("tr", {
1741
- className: v.has(e.path) ? "table-active" : "",
1806
+ }), /* @__PURE__ */ p("tbody", { children: M.map((e) => /* @__PURE__ */ m("tr", {
1807
+ className: y.has(e.path) ? "table-active" : "",
1742
1808
  children: [
1743
1809
  /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p("input", {
1744
1810
  type: "checkbox",
1745
1811
  className: "form-check-input",
1746
- checked: v.has(e.path),
1747
- onChange: () => A(e.path)
1812
+ checked: y.has(e.path),
1813
+ onChange: () => L(e.path)
1748
1814
  }) }),
1749
1815
  /* @__PURE__ */ p("td", { children: e.directory ? /* @__PURE__ */ m("button", {
1750
1816
  className: "btn btn-sm btn-link text-decoration-none p-0 text-start",
1751
- onClick: () => O(e.path),
1817
+ onClick: () => F(e.path),
1752
1818
  children: [/* @__PURE__ */ p("i", { className: "bi bi-folder-fill text-warning me-2" }), /* @__PURE__ */ p("span", {
1753
1819
  className: "font-monospace",
1754
1820
  children: e.name
@@ -1759,23 +1825,23 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1759
1825
  }) }),
1760
1826
  /* @__PURE__ */ p("td", {
1761
1827
  className: "text-muted small",
1762
- children: e.directory ? "-" : R(e.size)
1828
+ children: e.directory ? "-" : B(e.size)
1763
1829
  }),
1764
1830
  /* @__PURE__ */ p("td", {
1765
1831
  className: "text-muted small",
1766
- children: P(e.lastModified)
1832
+ children: q(e.lastModified)
1767
1833
  }),
1768
1834
  /* @__PURE__ */ p("td", { children: !e.directory && /* @__PURE__ */ m("div", {
1769
1835
  className: "d-flex gap-1",
1770
1836
  children: [/* @__PURE__ */ p("button", {
1771
1837
  className: "btn btn-sm btn-outline-primary py-0",
1772
1838
  title: "Baixar",
1773
- onClick: () => M(e.path),
1839
+ onClick: () => U(e.path),
1774
1840
  children: /* @__PURE__ */ p("i", { className: "bi bi-download" })
1775
1841
  }), /* @__PURE__ */ p("button", {
1776
1842
  className: "btn btn-sm btn-outline-danger py-0",
1777
1843
  title: "Excluir",
1778
- onClick: () => S(e.path),
1844
+ onClick: () => C(e.path),
1779
1845
  children: /* @__PURE__ */ p("i", { className: "bi bi-trash" })
1780
1846
  })]
1781
1847
  }) })
@@ -1783,7 +1849,139 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1783
1849
  }, e.path)) })]
1784
1850
  })
1785
1851
  })] }),
1786
- x && /* @__PURE__ */ p("div", {
1852
+ w && /* @__PURE__ */ p("div", {
1853
+ className: "modal d-block",
1854
+ tabIndex: -1,
1855
+ style: { background: "rgba(0,0,0,.5)" },
1856
+ children: /* @__PURE__ */ p("div", {
1857
+ className: "modal-dialog modal-dialog-centered",
1858
+ children: /* @__PURE__ */ m("div", {
1859
+ className: "modal-content",
1860
+ children: [
1861
+ /* @__PURE__ */ m("div", {
1862
+ className: "modal-header",
1863
+ children: [/* @__PURE__ */ m("h6", {
1864
+ className: "modal-title",
1865
+ children: [/* @__PURE__ */ p("i", { className: "bi bi-box-arrow-down me-2" }), w.mode === "ZIP" ? "Compactando e baixando" : "Baixando arquivo"]
1866
+ }), /* @__PURE__ */ p("button", {
1867
+ className: "btn-close",
1868
+ onClick: K
1869
+ })]
1870
+ }),
1871
+ /* @__PURE__ */ m("div", {
1872
+ className: "modal-body",
1873
+ children: [
1874
+ /* @__PURE__ */ m("div", {
1875
+ className: "d-flex align-items-center gap-3 mb-3",
1876
+ children: [/* @__PURE__ */ p("div", {
1877
+ className: "spinner-border text-primary flex-shrink-0",
1878
+ style: {
1879
+ width: "1.5rem",
1880
+ height: "1.5rem"
1881
+ },
1882
+ role: "status"
1883
+ }), /* @__PURE__ */ m("div", {
1884
+ className: "w-100",
1885
+ children: [/* @__PURE__ */ m("div", {
1886
+ className: "d-flex justify-content-between small mb-1",
1887
+ children: [/* @__PURE__ */ p("span", { children: ((e) => e.mode === "FILE" ? e.phase === "DOWNLOADING" ? e.totalBytes > 0 ? `Baixando arquivo... ${B(e.processedBytes)} / ${B(e.totalBytes)}` : "Baixando arquivo..." : e.message || "Preparando download..." : e.phase === "PREPARING" ? `Preparando ${e.processedItems}/${e.totalItems} arquivo(s)...` : e.phase === "COMPRESSING" ? `Compactando... ${e.percent}%` : e.message || "Processando...")(w) }), /* @__PURE__ */ m("span", {
1888
+ className: "text-muted",
1889
+ children: [w.percent, "%"]
1890
+ })]
1891
+ }), /* @__PURE__ */ p("div", {
1892
+ className: "progress",
1893
+ style: { height: 8 },
1894
+ children: /* @__PURE__ */ p("div", {
1895
+ className: "progress-bar progress-bar-striped progress-bar-animated",
1896
+ role: "progressbar",
1897
+ style: { width: `${Math.max(w.percent, 3)}%` }
1898
+ })
1899
+ })]
1900
+ })]
1901
+ }),
1902
+ w.currentItem && /* @__PURE__ */ m("div", {
1903
+ className: "small text-muted",
1904
+ title: w.currentItem,
1905
+ children: [/* @__PURE__ */ p("i", {
1906
+ className: "bi bi-file-earmark-text me-1",
1907
+ "aria-hidden": !0
1908
+ }), /* @__PURE__ */ p("span", {
1909
+ className: "font-monospace",
1910
+ children: w.currentItem
1911
+ })]
1912
+ }),
1913
+ w.mode === "FILE" && w.totalBytes > 0 || w.mode === "ZIP" ? /* @__PURE__ */ m("div", {
1914
+ className: "small text-muted mt-1",
1915
+ children: [
1916
+ /* @__PURE__ */ p("i", {
1917
+ className: "bi bi-hdd me-1",
1918
+ "aria-hidden": !0
1919
+ }),
1920
+ B(w.processedBytes),
1921
+ w.totalBytes > 0 ? ` / ${B(w.totalBytes)}` : ""
1922
+ ]
1923
+ }) : null,
1924
+ w.status === "FAILED" && /* @__PURE__ */ m("div", {
1925
+ className: "alert alert-danger small mt-2 mb-0 py-1",
1926
+ children: [/* @__PURE__ */ p("i", {
1927
+ className: "bi bi-exclamation-triangle me-1",
1928
+ "aria-hidden": !0
1929
+ }), w.message || "Falha ao preparar o download."]
1930
+ })
1931
+ ]
1932
+ }),
1933
+ /* @__PURE__ */ p("div", {
1934
+ className: "modal-footer",
1935
+ children: /* @__PURE__ */ p("button", {
1936
+ className: "btn btn-sm btn-secondary",
1937
+ onClick: K,
1938
+ disabled: O,
1939
+ children: O ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("span", { className: "spinner-border spinner-border-sm me-1" }), "Baixando..."] }) : w.status === "DONE" || w.status === "FAILED" ? "Fechar" : "Fechar (continua em 2º plano)"
1940
+ })
1941
+ })
1942
+ ]
1943
+ })
1944
+ })
1945
+ }),
1946
+ E && !w && /* @__PURE__ */ p("div", {
1947
+ className: "modal d-block",
1948
+ tabIndex: -1,
1949
+ style: { background: "rgba(0,0,0,.5)" },
1950
+ children: /* @__PURE__ */ p("div", {
1951
+ className: "modal-dialog modal-dialog-centered",
1952
+ children: /* @__PURE__ */ m("div", {
1953
+ className: "modal-content",
1954
+ children: [
1955
+ /* @__PURE__ */ m("div", {
1956
+ className: "modal-header",
1957
+ children: [/* @__PURE__ */ m("h6", {
1958
+ className: "modal-title",
1959
+ children: [/* @__PURE__ */ p("i", { className: "bi bi-exclamation-triangle me-2 text-danger" }), "Falha no download"]
1960
+ }), /* @__PURE__ */ p("button", {
1961
+ className: "btn-close",
1962
+ onClick: () => D(null)
1963
+ })]
1964
+ }),
1965
+ /* @__PURE__ */ p("div", {
1966
+ className: "modal-body",
1967
+ children: /* @__PURE__ */ p("p", {
1968
+ className: "mb-0 text-danger small",
1969
+ children: E
1970
+ })
1971
+ }),
1972
+ /* @__PURE__ */ p("div", {
1973
+ className: "modal-footer",
1974
+ children: /* @__PURE__ */ p("button", {
1975
+ className: "btn btn-sm btn-secondary",
1976
+ onClick: () => D(null),
1977
+ children: "Fechar"
1978
+ })
1979
+ })
1980
+ ]
1981
+ })
1982
+ })
1983
+ }),
1984
+ S && /* @__PURE__ */ p("div", {
1787
1985
  className: "modal d-block",
1788
1986
  tabIndex: -1,
1789
1987
  style: { background: "rgba(0,0,0,.5)" },
@@ -1799,26 +1997,26 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1799
1997
  children: "Confirmar exclusao"
1800
1998
  }), /* @__PURE__ */ p("button", {
1801
1999
  className: "btn-close",
1802
- onClick: () => S(null)
2000
+ onClick: () => C(null)
1803
2001
  })]
1804
2002
  }),
1805
2003
  /* @__PURE__ */ m("div", {
1806
2004
  className: "modal-body",
1807
2005
  children: [
1808
- x === "multiple" ? /* @__PURE__ */ m("p", { children: [
2006
+ S === "multiple" ? /* @__PURE__ */ m("p", { children: [
1809
2007
  "Excluir ",
1810
- v.size,
2008
+ y.size,
1811
2009
  " arquivo(s) selecionado(s)?"
1812
2010
  ] }) : /* @__PURE__ */ m("p", { children: [
1813
2011
  "Excluir ",
1814
- /* @__PURE__ */ p("code", { children: x.split("/").pop() }),
2012
+ /* @__PURE__ */ p("code", { children: S.split("/").pop() }),
1815
2013
  "?"
1816
2014
  ] }),
1817
2015
  /* @__PURE__ */ p("p", {
1818
2016
  className: "text-danger small mb-0",
1819
2017
  children: "Esta acao nao pode ser desfeita."
1820
2018
  }),
1821
- E.isError && /* @__PURE__ */ m("div", {
2019
+ P.isError && /* @__PURE__ */ m("div", {
1822
2020
  className: "alert alert-danger small mt-2 mb-0 py-1",
1823
2021
  children: [
1824
2022
  /* @__PURE__ */ p("i", {
@@ -1827,7 +2025,7 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1827
2025
  }),
1828
2026
  "Falha ao excluir:",
1829
2027
  " ",
1830
- E.error instanceof Error ? E.error.message : String(E.error)
2028
+ P.error instanceof Error ? P.error.message : String(P.error)
1831
2029
  ]
1832
2030
  })
1833
2031
  ]
@@ -1836,23 +2034,16 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1836
2034
  className: "modal-footer",
1837
2035
  children: [/* @__PURE__ */ p("button", {
1838
2036
  className: "btn btn-sm btn-secondary",
1839
- onClick: () => S(null),
2037
+ onClick: () => C(null),
1840
2038
  children: "Cancelar"
1841
2039
  }), /* @__PURE__ */ p("button", {
1842
2040
  className: "btn btn-sm btn-danger",
1843
- disabled: E.isPending,
2041
+ disabled: P.isPending,
1844
2042
  onClick: async () => {
1845
- if (!D.current) {
1846
- D.current = !0;
1847
- try {
1848
- if (x === "multiple") for (let e of v) await E.mutateAsync(e);
1849
- else await E.mutateAsync(x);
1850
- } finally {
1851
- D.current = !1;
1852
- }
1853
- }
2043
+ if (S === "multiple") for (let e of y) await P.mutateAsync(e);
2044
+ else await P.mutateAsync(S);
1854
2045
  },
1855
- children: E.isPending ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("span", { className: "spinner-border spinner-border-sm me-1" }), "Excluindo..."] }) : "Excluir"
2046
+ children: P.isPending ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("span", { className: "spinner-border spinner-border-sm me-1" }), "Excluindo..."] }) : "Excluir"
1856
2047
  })]
1857
2048
  })
1858
2049
  ]
@@ -1864,8 +2055,8 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1864
2055
  }
1865
2056
  //#endregion
1866
2057
  //#region src/components/ImportDumpTab.tsx
1867
- function Q() {
1868
- let e = F(), t = I(), n = D(), r = a(null), [i, s] = o("upload"), [c, l] = o(null), [u, d] = o(""), [f, h] = o(!1), g = () => {
2058
+ function se() {
2059
+ let e = I(), t = L(), n = D(), r = a(null), [i, s] = o("upload"), [c, l] = o(null), [u, d] = o(""), [f, h] = o(!1), g = () => {
1869
2060
  i === "upload" && c ? e.mutate({ file: c }) : i === "storage" && u && t.mutate({
1870
2061
  storageType: "LOCAL",
1871
2062
  storagePath: u
@@ -1987,7 +2178,7 @@ function Q() {
1987
2178
  maxHeight: 350,
1988
2179
  overflow: "auto"
1989
2180
  },
1990
- children: /* @__PURE__ */ p(Z, {
2181
+ children: /* @__PURE__ */ p($, {
1991
2182
  storageType: "LOCAL",
1992
2183
  storageConfig: {
1993
2184
  type: "LOCAL",
@@ -2010,7 +2201,7 @@ function Q() {
2010
2201
  children: [/* @__PURE__ */ p("p", {
2011
2202
  className: "small text-body-secondary mb-3",
2012
2203
  children: "O dump será aplicado no banco configurado no servidor. Tabelas bloqueadas por segurança são ignoradas automaticamente na importação."
2013
- }), /* @__PURE__ */ p(W, {
2204
+ }), /* @__PURE__ */ p(J, {
2014
2205
  label: "Banco de destino",
2015
2206
  dbInfo: n.data,
2016
2207
  isLoading: n.isLoading,
@@ -2026,7 +2217,7 @@ function Q() {
2026
2217
  "aria-hidden": !0
2027
2218
  }),
2028
2219
  "Falha na importacao: ",
2029
- K(y)
2220
+ X(y)
2030
2221
  ]
2031
2222
  }),
2032
2223
  v && /* @__PURE__ */ m("div", {
@@ -2134,7 +2325,7 @@ function ce() {
2134
2325
  "aria-hidden": !0
2135
2326
  }),
2136
2327
  "Falha ao criar backup de storage: ",
2137
- K(e.error)
2328
+ X(e.error)
2138
2329
  ]
2139
2330
  }),
2140
2331
  e.isSuccess && /* @__PURE__ */ m("div", {
@@ -2196,13 +2387,13 @@ function le({ label: e, configured: t, ok: n, message: r }) {
2196
2387
  }
2197
2388
  //#endregion
2198
2389
  //#region src/hooks/useAutoTheme.ts
2199
- function $() {
2390
+ function ue() {
2200
2391
  return typeof document < "u" && document.documentElement.classList.contains("dark");
2201
2392
  }
2202
- function ue(e) {
2203
- let [t, n] = o($), [i, a] = o(() => typeof window < "u" && window.matchMedia?.("(prefers-color-scheme: dark)")?.matches === !0);
2393
+ function de(e) {
2394
+ let [t, n] = o(ue), [i, a] = o(() => typeof window < "u" && window.matchMedia?.("(prefers-color-scheme: dark)")?.matches === !0);
2204
2395
  return r(() => {
2205
- let e = document.documentElement, t = new MutationObserver(() => n($()));
2396
+ let e = document.documentElement, t = new MutationObserver(() => n(ue()));
2206
2397
  return t.observe(e, {
2207
2398
  attributes: !0,
2208
2399
  attributeFilter: ["class"]
@@ -2215,8 +2406,8 @@ function ue(e) {
2215
2406
  }
2216
2407
  //#endregion
2217
2408
  //#region src/components/MinivaultModule.tsx
2218
- function de(e) {
2219
- let { companyAcronym: t = "Minivault", theme: n, refetchIntervalMs: r = 15e3, storageType: i = "LOCAL", ...a } = e, l = ue(n), [u] = o(() => new s({ defaultOptions: { queries: {
2409
+ function fe(e) {
2410
+ let { companyAcronym: t = "Minivault", theme: n, refetchIntervalMs: r = 15e3, storageType: i = "LOCAL", ...a } = e, l = de(n), [u] = o(() => new s({ defaultOptions: { queries: {
2220
2411
  refetchInterval: r,
2221
2412
  retry: 1
2222
2413
  } } }));
@@ -2227,15 +2418,15 @@ function de(e) {
2227
2418
  children: /* @__PURE__ */ m("div", {
2228
2419
  className: "minivault-module h-full w-full overflow-auto",
2229
2420
  "data-minivault-theme": l,
2230
- children: [/* @__PURE__ */ p(fe, {
2421
+ children: [/* @__PURE__ */ p(pe, {
2231
2422
  companyAcronym: t,
2232
2423
  theme: l
2233
- }), /* @__PURE__ */ p(pe, { storageType: i })]
2424
+ }), /* @__PURE__ */ p(me, { storageType: i })]
2234
2425
  })
2235
2426
  })
2236
2427
  });
2237
2428
  }
2238
- function fe({ companyAcronym: e, theme: t }) {
2429
+ function pe({ companyAcronym: e, theme: t }) {
2239
2430
  return /* @__PURE__ */ m("div", {
2240
2431
  className: "d-flex align-items-center justify-content-between flex-wrap gap-2 px-3 py-2 border-bottom",
2241
2432
  style: {
@@ -2264,7 +2455,7 @@ function fe({ companyAcronym: e, theme: t }) {
2264
2455
  })]
2265
2456
  });
2266
2457
  }
2267
- function pe({ storageType: e }) {
2458
+ function me({ storageType: e }) {
2268
2459
  let [t, n] = o("backups");
2269
2460
  return /* @__PURE__ */ m("div", {
2270
2461
  className: "p-3",
@@ -2346,23 +2537,40 @@ function pe({ storageType: e }) {
2346
2537
  })
2347
2538
  ]
2348
2539
  }),
2349
- t === "backups" && /* @__PURE__ */ p(q, {}),
2350
- t === "create" && /* @__PURE__ */ p(Y, {}),
2540
+ t === "backups" && /* @__PURE__ */ p(Z, {}),
2541
+ t === "create" && /* @__PURE__ */ p(te, {}),
2351
2542
  t === "createStorage" && /* @__PURE__ */ p(ce, {}),
2352
- t === "import" && /* @__PURE__ */ p(Q, {}),
2353
- t === "storage" && /* @__PURE__ */ p(Z, { storageType: e }),
2354
- t === "diagnostics" && /* @__PURE__ */ p(X, {})
2543
+ t === "import" && /* @__PURE__ */ p(se, {}),
2544
+ t === "storage" && /* @__PURE__ */ m("div", {
2545
+ className: "row g-3",
2546
+ children: [/* @__PURE__ */ p("div", {
2547
+ className: "col-lg-6",
2548
+ children: /* @__PURE__ */ p($, {
2549
+ target: "origin",
2550
+ storageType: e,
2551
+ title: "Storage de Origem"
2552
+ })
2553
+ }), /* @__PURE__ */ p("div", {
2554
+ className: "col-lg-6",
2555
+ children: /* @__PURE__ */ p($, {
2556
+ target: "destination",
2557
+ storageType: e,
2558
+ title: "Storage de Destino"
2559
+ })
2560
+ })]
2561
+ }),
2562
+ t === "diagnostics" && /* @__PURE__ */ p(ie, {})
2355
2563
  ]
2356
2564
  });
2357
2565
  }
2358
2566
  //#endregion
2359
2567
  //#region src/components/CredentialsFields.tsx
2360
- var me = [
2568
+ var he = [
2361
2569
  "postgresql",
2362
2570
  "mysql",
2363
2571
  "sqlserver"
2364
2572
  ];
2365
- function he() {
2573
+ function ge() {
2366
2574
  return {
2367
2575
  host: "localhost",
2368
2576
  port: 5432,
@@ -2372,19 +2580,19 @@ function he() {
2372
2580
  databaseType: "postgresql"
2373
2581
  };
2374
2582
  }
2375
- function ge(e) {
2583
+ function _e(e) {
2376
2584
  return e === "postgresql" || e === "postgres" ? 5432 : e === "mysql" ? 3306 : 1433;
2377
2585
  }
2378
- function _e({ value: e, onChange: t, onValidatedChange: n }) {
2586
+ function ve({ value: e, onChange: t, onValidatedChange: n }) {
2379
2587
  let r = {
2380
- ...he(),
2588
+ ...ge(),
2381
2589
  ...e
2382
2590
  }, i = (e) => {
2383
2591
  let n = {
2384
2592
  ...r,
2385
2593
  databaseType: e
2386
2594
  };
2387
- (r.port === ge(r.databaseType) || !r.port) && (n.port = ge(e)), t(n);
2595
+ (r.port === _e(r.databaseType) || !r.port) && (n.port = _e(e)), t(n);
2388
2596
  }, a = (e) => {
2389
2597
  let i = {
2390
2598
  ...r,
@@ -2406,9 +2614,9 @@ function _e({ value: e, onChange: t, onValidatedChange: n }) {
2406
2614
  className: "form-select",
2407
2615
  value: r.databaseType,
2408
2616
  onChange: (e) => i(e.target.value),
2409
- children: me.map((e) => /* @__PURE__ */ p("option", {
2617
+ children: he.map((e) => /* @__PURE__ */ p("option", {
2410
2618
  value: e,
2411
- children: H[e] ?? e
2619
+ children: W[e] ?? e
2412
2620
  }, e))
2413
2621
  })]
2414
2622
  }),
@@ -2480,4 +2688,4 @@ function _e({ value: e, onChange: t, onValidatedChange: n }) {
2480
2688
  });
2481
2689
  }
2482
2690
  //#endregion
2483
- export { q as BackupsTab, Y as CreateBackupTab, _e as CredentialsFields, H as DATABASE_TYPE_LABELS, W as DatabaseBanner, X as DiagnosticsTab, Q as ImportDumpTab, g as MinivaultApi, h as MinivaultApiError, y as MinivaultApiProvider, de as MinivaultModule, G as RestoreModal, V as STATUS_BADGE, B as STATUS_LABELS, U as StatusBadge, ce as StorageBackupTab, Z as StorageExplorerTab, z as formatDate, R as formatFileSize, E as useBackups, j as useCreateBackup, D as useDbInfo, A as useDbRelationships, k as useDbTableDetail, O as useDbTables, N as useDeleteBackup, T as useDiagnostics, ee as useDownloadBackup, F as useImportDump, I as useImportFromStorage, b as useMinivaultApi, M as useRestoreBackup };
2691
+ export { Z as BackupsTab, te as CreateBackupTab, ve as CredentialsFields, W as DATABASE_TYPE_LABELS, J as DatabaseBanner, ie as DiagnosticsTab, se as ImportDumpTab, g as MinivaultApi, h as MinivaultApiError, y as MinivaultApiProvider, fe as MinivaultModule, Y as RestoreModal, U as STATUS_BADGE, H as STATUS_LABELS, q as StatusBadge, ce as StorageBackupTab, $ as StorageExplorerTab, V as formatDate, B as formatFileSize, E as useBackups, j as useCreateBackup, D as useDbInfo, A as useDbRelationships, k as useDbTableDetail, O as useDbTables, N as useDeleteBackup, T as useDiagnostics, F as useDownloadBackup, I as useImportDump, L as useImportFromStorage, b as useMinivaultApi, M as useRestoreBackup };
@@ -138,6 +138,42 @@ export interface StorageFileItem {
138
138
  lastModified: string | null;
139
139
  directory: boolean;
140
140
  }
141
+ /** Qual storage o explorador manipula: origem (ORIGIN_STORAGE_*) ou destino (OUTPUT_STORAGE_*). */
142
+ export type StorageTarget = 'origin' | 'destination';
143
+ export type ZipJobStatusName = 'PENDING' | 'RUNNING' | 'DONE' | 'FAILED';
144
+ export type ZipJobMode = 'ZIP' | 'FILE';
145
+ export type ZipJobPhase = 'PREPARING' | 'COMPRESSING' | 'DOWNLOADING';
146
+ export interface ZipJobStatus {
147
+ jobId: string;
148
+ status: ZipJobStatusName;
149
+ mode: ZipJobMode;
150
+ phase: ZipJobPhase | null;
151
+ message: string;
152
+ fileName: string | null;
153
+ fileSize: number | null;
154
+ totalItems: number;
155
+ processedItems: number;
156
+ processedBytes: number;
157
+ totalBytes: number;
158
+ percent: number;
159
+ currentItem: string | null;
160
+ createdAt: string;
161
+ completedAt: string | null;
162
+ }
163
+ export type StorageDownloadMode = 'zip' | 'file';
164
+ export interface StorageZipRequest {
165
+ storage: StorageTarget;
166
+ type?: string;
167
+ mode?: StorageDownloadMode;
168
+ keys: string[];
169
+ localPath?: string;
170
+ endpoint?: string;
171
+ bucketName?: string;
172
+ region?: string;
173
+ accessKey?: string;
174
+ secretKey?: string;
175
+ pathStyleEnabled?: boolean;
176
+ }
141
177
  export interface ApiErrorBody {
142
178
  timestamp?: string;
143
179
  status?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v1ct0rbr/minivault-web",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "description": "Módulo independente de gerenciamento de backups (minivault). Consumível como pacote npm em qualquer app React. Cliente do minivault REST API (acesso tipicamente via proxy autenticado).",
5
5
  "author": "Victor Queiroga (https://www.linkedin.com/in/victor-queiroga)",
6
6
  "license": "MIT",