@v1ct0rbr/minivault-web 0.5.0 → 0.6.0

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, 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, TableDetail, TableInfo, VerifyResult } from '../types/minivault';
2
2
  export interface MinivaultApiOptions {
3
3
  /**
4
4
  * URL base da API. Exemplos:
@@ -33,7 +33,7 @@ export declare class MinivaultApi {
33
33
  private request;
34
34
  listBackups(page?: number, size?: number): Promise<PageResponse<Backup>>;
35
35
  getBackup(id: number): Promise<Backup>;
36
- createBackup(database?: DatabaseCredentials, originStorage?: OriginStorageConfig, dumpOptions?: DumpOptions): Promise<Backup>;
36
+ createBackup(database?: DatabaseCredentials, originStorage?: OriginStorageConfig, dumpOptions?: DumpOptions, backupType?: BackupType): Promise<Backup>;
37
37
  restoreBackup(id: number, database?: DatabaseCredentials, originStorage?: OriginStorageConfig): Promise<void>;
38
38
  deleteBackup(id: number): Promise<void>;
39
39
  verifyBackup(id: number): Promise<VerifyResult>;
@@ -1,10 +1,5 @@
1
1
  import { MinivaultApiProviderProps } from './MinivaultApiProvider';
2
2
  export interface MinivaultModuleProps extends Omit<MinivaultApiProviderProps, 'children'> {
3
- /**
4
- * Força o tema ('light' | 'dark'). Quando omitido, o módulo segue
5
- * automaticamente o tema do host (classe `.dark` no <html> ou
6
- * prefers-color-scheme do sistema).
7
- */
8
3
  theme?: 'light' | 'dark';
9
4
  refetchIntervalMs?: number;
10
5
  companyAcronym?: string;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Aba de backup apenas de storage: envia o storage de origem (ORIGIN_STORAGE_*)
3
+ * para o storage de destino (OUTPUT_STORAGE_*). Ambos são configurados no
4
+ * servidor via variáveis de ambiente — não é necessário informar dados aqui.
5
+ */
6
+ export declare function StorageBackupTab(): import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- import { DatabaseCredentials, DumpOptions, OriginStorageConfig } from '../types/minivault';
1
+ import { BackupType, DatabaseCredentials, DumpOptions, OriginStorageConfig } from '../types/minivault';
2
2
  export declare const backupsKeys: {
3
3
  all: readonly ["minivault", "backups"];
4
4
  db: readonly ["minivault", "db"];
@@ -14,6 +14,7 @@ export declare function useCreateBackup(): import('@tanstack/react-query').UseMu
14
14
  database?: DatabaseCredentials;
15
15
  originStorage?: OriginStorageConfig;
16
16
  dumpOptions?: DumpOptions;
17
+ backupType?: BackupType;
17
18
  }, unknown>;
18
19
  export declare function useRestoreBackup(): import('@tanstack/react-query').UseMutationResult<void, Error, {
19
20
  id: number;
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export { BackupsTab } from './components/BackupsTab';
7
7
  export { CreateBackupTab } from './components/CreateBackupTab';
8
8
  export { DiagnosticsTab } from './components/DiagnosticsTab';
9
9
  export { ImportDumpTab } from './components/ImportDumpTab';
10
+ export { StorageBackupTab } from './components/StorageBackupTab';
10
11
  export { StorageExplorerTab } from './components/StorageExplorerTab';
11
12
  export { RestoreModal } from './components/RestoreModal';
12
13
  export { CredentialsFields } from './components/CredentialsFields';
@@ -14,4 +15,4 @@ export { DatabaseBanner } from './components/DatabaseBanner';
14
15
  export { StatusBadge } from './components/StatusBadge';
15
16
  export { useBackups, useCreateBackup, useRestoreBackup, useDeleteBackup, useDownloadBackup, useImportDump, useImportFromStorage, useDbInfo, useDbTables, useDbTableDetail, useDbRelationships, useDiagnostics, } from './hooks/useBackups';
16
17
  export { formatFileSize, formatDate, STATUS_LABELS, STATUS_BADGE, DATABASE_TYPE_LABELS } from './utils/format';
17
- export type { Backup, BackupRequest, BackupStatus, ColumnInfo, ConnectionCheck, DatabaseCredentials, DatabaseType, DbInfo, DumpOptions, DumpFormat, ImportResult, ImportFromStorageRequest, OriginStorageConfig, PageResponse, RelationshipInfo, RestoreRequest, StorageFileItem, TableDetail, TableInfo, VerifyResult, } from './types/minivault';
18
+ export type { Backup, BackupRequest, BackupStatus, BackupType, ColumnInfo, ConnectionCheck, DatabaseCredentials, DatabaseType, DbInfo, DumpOptions, DumpFormat, ImportResult, ImportFromStorageRequest, OriginStorageConfig, PageResponse, RelationshipInfo, RestoreRequest, StorageFileItem, TableDetail, TableInfo, VerifyResult, } from './types/minivault';
@@ -56,11 +56,11 @@ var h = class extends Error {
56
56
  getBackup(e) {
57
57
  return this.request(`/api/backups/${e}`);
58
58
  }
59
- createBackup(e, t, n) {
60
- let r = {};
61
- return e && (r.database = e), t && (r.originStorage = t), n && (r.dumpOptions = n), this.request("/api/backups", {
59
+ createBackup(e, t, n, r) {
60
+ let i = {};
61
+ return r && (i.backupType = r), e && (i.database = e), t && (i.originStorage = t), n && (i.dumpOptions = n), this.request("/api/backups", {
62
62
  method: "POST",
63
- body: JSON.stringify(r)
63
+ body: JSON.stringify(i)
64
64
  });
65
65
  }
66
66
  restoreBackup(e, t, n) {
@@ -267,7 +267,7 @@ function O(e = !0) {
267
267
  function k() {
268
268
  let e = b(), t = d();
269
269
  return l({
270
- mutationFn: (t) => e.createBackup(t.database, t.originStorage, t.dumpOptions),
270
+ mutationFn: (t) => e.createBackup(t.database, t.originStorage, t.dumpOptions, t.backupType),
271
271
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
272
272
  });
273
273
  }
@@ -306,32 +306,32 @@ function F() {
306
306
  }
307
307
  //#endregion
308
308
  //#region src/utils/format.ts
309
- var I = new Intl.DateTimeFormat("pt-BR", {
309
+ var ee = new Intl.DateTimeFormat("pt-BR", {
310
310
  day: "2-digit",
311
311
  month: "2-digit",
312
312
  year: "numeric",
313
313
  hour: "2-digit",
314
314
  minute: "2-digit"
315
- }), L = [
315
+ }), I = [
316
316
  "B",
317
317
  "KB",
318
318
  "MB",
319
319
  "GB",
320
320
  "TB"
321
321
  ];
322
- function R(e) {
322
+ function L(e) {
323
323
  if (e == null || e < 0) return "—";
324
324
  if (e < 1024) return `${e} B`;
325
325
  let t = e, n = 0;
326
- for (; t >= 1024 && n < L.length - 1;) t /= 1024, n += 1;
327
- return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${L[n]}`;
326
+ for (; t >= 1024 && n < I.length - 1;) t /= 1024, n += 1;
327
+ return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${I[n]}`;
328
328
  }
329
- function z(e) {
329
+ function R(e) {
330
330
  if (!e) return "—";
331
331
  let t = new Date(e);
332
- return Number.isNaN(t.getTime()) ? "—" : I.format(t);
332
+ return Number.isNaN(t.getTime()) ? "—" : ee.format(t);
333
333
  }
334
- var B = {
334
+ var z = {
335
335
  PENDING: "Pendente",
336
336
  IN_PROGRESS: "Em andamento",
337
337
  COMPLETED: "Concluído",
@@ -339,7 +339,7 @@ var B = {
339
339
  RESTORING: "Restaurando",
340
340
  RESTORED: "Restaurado",
341
341
  RESTORE_FAILED: "Falha na restauração"
342
- }, V = {
342
+ }, B = {
343
343
  PENDING: "text-bg-secondary",
344
344
  IN_PROGRESS: "text-bg-primary",
345
345
  COMPLETED: "text-bg-success",
@@ -347,7 +347,7 @@ var B = {
347
347
  RESTORING: "text-bg-warning",
348
348
  RESTORED: "text-bg-info",
349
349
  RESTORE_FAILED: "text-bg-danger"
350
- }, H = {
350
+ }, V = {
351
351
  postgresql: "PostgreSQL",
352
352
  postgres: "PostgreSQL",
353
353
  mysql: "MySQL",
@@ -356,8 +356,8 @@ var B = {
356
356
  };
357
357
  //#endregion
358
358
  //#region src/components/StatusBadge.tsx
359
- function U({ status: e }) {
360
- let t = V[e] ?? "text-bg-secondary", n = B[e] ?? e;
359
+ function H({ status: e }) {
360
+ let t = B[e] ?? "text-bg-secondary", n = z[e] ?? e;
361
361
  return /* @__PURE__ */ p("span", {
362
362
  className: `badge rounded-pill ${t}`,
363
363
  children: n
@@ -365,7 +365,7 @@ function U({ status: e }) {
365
365
  }
366
366
  //#endregion
367
367
  //#region src/components/DatabaseBanner.tsx
368
- function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
368
+ function U({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
369
369
  if (t) return /* @__PURE__ */ p("div", {
370
370
  className: "mb-3",
371
371
  children: /* @__PURE__ */ m("small", {
@@ -384,7 +384,7 @@ function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
384
384
  "aria-hidden": !0
385
385
  }),
386
386
  "Não foi possível consultar o banco configurado: ",
387
- K(n)
387
+ G(n)
388
388
  ]
389
389
  });
390
390
  if (!e || !e.configured) return i ? /* @__PURE__ */ m("div", {
@@ -406,7 +406,7 @@ function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
406
406
  "). A criação e a importação usam esse banco."
407
407
  ]
408
408
  });
409
- let a = H[e.databaseType ?? ""] ?? e.databaseType ?? "postgresql";
409
+ let a = V[e.databaseType ?? ""] ?? e.databaseType ?? "postgresql";
410
410
  return i ? /* @__PURE__ */ m("div", {
411
411
  className: "mb-3",
412
412
  children: [
@@ -524,7 +524,7 @@ function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
524
524
  }
525
525
  //#endregion
526
526
  //#region src/components/RestoreModal.tsx
527
- function G({ backup: e, onClose: t }) {
527
+ function W({ backup: e, onClose: t }) {
528
528
  let n = A(), r = T(), i = () => {
529
529
  n.mutate({ id: e.id });
530
530
  }, a = n.isPending;
@@ -571,7 +571,7 @@ function G({ backup: e, onClose: t }) {
571
571
  " será aplicado no banco configurado abaixo."
572
572
  ]
573
573
  }),
574
- /* @__PURE__ */ p(W, {
574
+ /* @__PURE__ */ p(U, {
575
575
  label: "Banco de destino",
576
576
  dbInfo: r.data,
577
577
  isLoading: r.isLoading,
@@ -582,7 +582,7 @@ function G({ backup: e, onClose: t }) {
582
582
  children: [/* @__PURE__ */ p("i", {
583
583
  className: "bi bi-x-circle me-2",
584
584
  "aria-hidden": !0
585
- }), K(n.error)]
585
+ }), G(n.error)]
586
586
  }),
587
587
  n.isSuccess && /* @__PURE__ */ m("div", {
588
588
  className: "alert alert-success mt-3 mb-0",
@@ -617,12 +617,12 @@ function G({ backup: e, onClose: t }) {
617
617
  })
618
618
  })] });
619
619
  }
620
- function K(e) {
620
+ function G(e) {
621
621
  return e instanceof Error ? e.message : String(e);
622
622
  }
623
623
  //#endregion
624
624
  //#region src/components/BackupsTab.tsx
625
- function q() {
625
+ function K() {
626
626
  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 } = w(e, 10, !0), y = N(), b = j(), x = M();
627
627
  r(() => {
628
628
  if (!y.data || !y.variables) return;
@@ -665,7 +665,7 @@ function q() {
665
665
  "aria-hidden": !0
666
666
  }),
667
667
  "Não foi possível carregar os backups: ",
668
- J(g)
668
+ q(g)
669
669
  ]
670
670
  }),
671
671
  y.isError && /* @__PURE__ */ m("div", {
@@ -676,7 +676,7 @@ function q() {
676
676
  "aria-hidden": !0
677
677
  }),
678
678
  "Falha no download: ",
679
- J(y.error)
679
+ q(y.error)
680
680
  ]
681
681
  }),
682
682
  b.isError && /* @__PURE__ */ m("div", {
@@ -687,7 +687,7 @@ function q() {
687
687
  "aria-hidden": !0
688
688
  }),
689
689
  "Falha ao excluir: ",
690
- J(b.error)
690
+ q(b.error)
691
691
  ]
692
692
  }),
693
693
  x.isError && /* @__PURE__ */ m("div", {
@@ -698,7 +698,7 @@ function q() {
698
698
  "aria-hidden": !0
699
699
  }),
700
700
  "Falha ao verificar: ",
701
- J(x.error)
701
+ q(x.error)
702
702
  ]
703
703
  }),
704
704
  Object.entries(l).map(([e, t]) => /* @__PURE__ */ m("div", {
@@ -786,12 +786,12 @@ function q() {
786
786
  "aria-hidden": !0
787
787
  }), e.filename]
788
788
  }),
789
- /* @__PURE__ */ p("td", { children: H[e.databaseType] ?? e.databaseType }),
789
+ /* @__PURE__ */ p("td", { children: V[e.databaseType] ?? e.databaseType }),
790
790
  /* @__PURE__ */ p("td", {
791
791
  className: "text-end",
792
- children: R(e.fileSize)
792
+ children: L(e.fileSize)
793
793
  }),
794
- /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(U, { status: e.status }) }),
794
+ /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(H, { status: e.status }) }),
795
795
  /* @__PURE__ */ p("td", { children: e.sha256 ? /* @__PURE__ */ m("code", {
796
796
  title: e.sha256,
797
797
  style: { fontSize: "0.8em" },
@@ -814,7 +814,7 @@ function q() {
814
814
  className: "text-muted",
815
815
  children: "—"
816
816
  }) }),
817
- /* @__PURE__ */ p("td", { children: z(e.createdAt) }),
817
+ /* @__PURE__ */ p("td", { children: R(e.createdAt) }),
818
818
  /* @__PURE__ */ m("td", {
819
819
  className: "text-end text-nowrap",
820
820
  children: [
@@ -907,11 +907,11 @@ function q() {
907
907
  })]
908
908
  })]
909
909
  }),
910
- n && /* @__PURE__ */ p(G, {
910
+ n && /* @__PURE__ */ p(W, {
911
911
  backup: n,
912
912
  onClose: () => a(null)
913
913
  }),
914
- s && /* @__PURE__ */ p(ee, {
914
+ s && /* @__PURE__ */ p(te, {
915
915
  backup: s,
916
916
  busy: b.isPending,
917
917
  onCancel: () => c(null),
@@ -921,7 +921,7 @@ function q() {
921
921
  })
922
922
  ] });
923
923
  }
924
- function ee(e) {
924
+ function te(e) {
925
925
  let { backup: t, busy: n, onCancel: r, onConfirm: i } = e;
926
926
  return /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", { className: "modal-backdrop show" }), /* @__PURE__ */ p("div", {
927
927
  className: "modal show d-block",
@@ -987,16 +987,13 @@ function ee(e) {
987
987
  })
988
988
  })] });
989
989
  }
990
- function J(e) {
990
+ function q(e) {
991
991
  return e instanceof Error ? e.message : String(e);
992
992
  }
993
993
  //#endregion
994
994
  //#region src/components/CreateBackupTab.tsx
995
- function Y() {
996
- let e = k(), t = T(), n = E(t.data?.configured), [r, a] = o(!1), [s, c] = o(() => ({
997
- type: "LOCAL",
998
- localPath: ""
999
- })), [l, u] = o(!0), [d, h] = o({
995
+ function J() {
996
+ let e = k(), t = T(), n = E(t.data?.configured), [r, a] = o(!0), [s, c] = o({
1000
997
  format: "plain",
1001
998
  includeData: !0,
1002
999
  includeDropTable: !1,
@@ -1004,49 +1001,49 @@ function Y() {
1004
1001
  includeIndexes: !0,
1005
1002
  includeConstraints: !0,
1006
1003
  includeRelatedTables: !1
1007
- }), [g, _] = o(() => /* @__PURE__ */ new Set()), [v, y] = o(null), [b, x] = o({}), [S, C] = o(""), w = D(v, t.data?.configured), O = i(() => new Set((t.data?.exportExcludedTables ?? []).map(ne)), [t.data?.exportExcludedTables]), A = i(() => {
1008
- let e = n.data ?? [], t = S.trim().toLowerCase();
1004
+ }), [l, u] = o(() => /* @__PURE__ */ new Set()), [d, f] = o(null), [h, g] = o({}), [_, v] = o(""), y = D(d, t.data?.configured), b = i(() => new Set((t.data?.exportExcludedTables ?? []).map(re)), [t.data?.exportExcludedTables]), x = i(() => {
1005
+ let e = n.data ?? [], t = _.trim().toLowerCase();
1009
1006
  return t ? e.filter((e) => e.fullName.toLowerCase().includes(t)) : e;
1010
- }, [n.data, S]), j = i(() => Object.values(b).reduce((e, t) => e + t.length, 0), [b]), M = (e) => {
1011
- _((t) => {
1007
+ }, [n.data, _]), S = i(() => Object.values(h).reduce((e, t) => e + t.length, 0), [h]), C = (e) => {
1008
+ u((t) => {
1012
1009
  let n = new Set(t);
1013
1010
  return n.has(e) ? n.delete(e) : n.add(e), n;
1014
1011
  });
1015
- }, N = (e, t) => {
1016
- x((n) => {
1012
+ }, w = (e, t) => {
1013
+ g((n) => {
1017
1014
  let r = n[e] ?? [], i = r.includes(t) ? r.filter((e) => e !== t) : [...r, t];
1018
1015
  return {
1019
1016
  ...n,
1020
1017
  [e]: i
1021
1018
  };
1022
1019
  });
1023
- }, P = () => {
1020
+ }, O = () => {
1024
1021
  let t;
1025
- if (l) {
1026
- t = { ...d }, g.size > 0 && (t.tables = [...g]);
1022
+ if (r) {
1023
+ t = { ...s }, l.size > 0 && (t.tables = [...l]);
1027
1024
  let e = {};
1028
- Object.entries(b).forEach(([t, n]) => {
1025
+ Object.entries(h).forEach(([t, n]) => {
1029
1026
  n.length > 0 && (e[t] = n);
1030
1027
  }), Object.keys(e).length > 0 && (t.excludeColumnsPerTable = e);
1031
1028
  }
1032
1029
  e.mutate({
1033
- originStorage: r ? s : void 0,
1030
+ backupType: "DATABASE",
1034
1031
  dumpOptions: t
1035
1032
  });
1036
- }, F = e.isPending, I = t.data?.configured && !F;
1033
+ }, A = e.isPending, j = t.data?.configured && !A;
1037
1034
  return /* @__PURE__ */ m("div", { children: [
1038
1035
  /* @__PURE__ */ m("div", {
1039
1036
  className: "mb-3",
1040
1037
  children: [/* @__PURE__ */ p("h5", {
1041
1038
  className: "mb-1",
1042
- children: "Criar novo backup"
1039
+ children: "Backup de banco de dados"
1043
1040
  }), /* @__PURE__ */ p("p", {
1044
1041
  className: "text-muted small mb-0",
1045
- children: "Selecione as tabelas no grid e expanda um card para marcar colunas cujo conteúdo será nulificado na exportação."
1042
+ 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."
1046
1043
  })]
1047
1044
  }),
1048
- /* @__PURE__ */ p(W, {
1049
- label: "Banco de origem",
1045
+ /* @__PURE__ */ p(U, {
1046
+ label: "Banco de destino",
1050
1047
  dbInfo: t.data,
1051
1048
  isLoading: t.isLoading,
1052
1049
  error: t.error,
@@ -1064,7 +1061,7 @@ function Y() {
1064
1061
  "aria-hidden": !0
1065
1062
  }),
1066
1063
  "Tabelas do banco (",
1067
- n.data?.filter((e) => !O.has(e.fullName)).length ?? 0,
1064
+ n.data?.filter((e) => !b.has(e.fullName)).length ?? 0,
1068
1065
  " disponíveis)"
1069
1066
  ]
1070
1067
  }), /* @__PURE__ */ m("div", {
@@ -1072,16 +1069,16 @@ function Y() {
1072
1069
  children: [/* @__PURE__ */ p("input", {
1073
1070
  className: "form-control form-control-sm",
1074
1071
  placeholder: "Filtrar tabelas...",
1075
- value: S,
1076
- onChange: (e) => C(e.target.value),
1072
+ value: _,
1073
+ onChange: (e) => v(e.target.value),
1077
1074
  style: { width: 200 }
1078
- }), g.size > 0 && /* @__PURE__ */ m("button", {
1075
+ }), l.size > 0 && /* @__PURE__ */ m("button", {
1079
1076
  type: "button",
1080
1077
  className: "btn btn-sm btn-outline-secondary",
1081
- onClick: () => _(/* @__PURE__ */ new Set()),
1078
+ onClick: () => u(/* @__PURE__ */ new Set()),
1082
1079
  children: [
1083
1080
  "Limpar seleção (",
1084
- g.size,
1081
+ l.size,
1085
1082
  ")"
1086
1083
  ]
1087
1084
  })]
@@ -1104,10 +1101,10 @@ function Y() {
1104
1101
  "aria-hidden": !0
1105
1102
  }),
1106
1103
  "Falha ao listar tabelas: ",
1107
- K(n.error)
1104
+ G(n.error)
1108
1105
  ]
1109
1106
  }),
1110
- A.length === 0 && !n.isLoading && /* @__PURE__ */ p("div", {
1107
+ x.length === 0 && !n.isLoading && /* @__PURE__ */ p("div", {
1111
1108
  className: "p-3 text-muted small",
1112
1109
  children: "Nenhuma tabela encontrada."
1113
1110
  }),
@@ -1120,16 +1117,16 @@ function Y() {
1120
1117
  maxHeight: 420,
1121
1118
  overflow: "auto"
1122
1119
  },
1123
- children: A.map((e) => /* @__PURE__ */ p(te, {
1120
+ children: x.map((e) => /* @__PURE__ */ p(ne, {
1124
1121
  table: e,
1125
- disabled: O.has(e.fullName),
1126
- selected: g.has(e.fullName),
1127
- expanded: v === e.fullName,
1128
- excluded: b[e.fullName] ?? [],
1129
- onToggleTable: () => M(e.fullName),
1130
- onToggleExpand: () => y(v === e.fullName ? null : e.fullName),
1131
- onToggleColumn: (t) => N(e.fullName, t),
1132
- detail: v === e.fullName ? w : void 0
1122
+ disabled: b.has(e.fullName),
1123
+ selected: l.has(e.fullName),
1124
+ expanded: d === e.fullName,
1125
+ excluded: h[e.fullName] ?? [],
1126
+ onToggleTable: () => C(e.fullName),
1127
+ onToggleExpand: () => f(d === e.fullName ? null : e.fullName),
1128
+ onToggleColumn: (t) => w(e.fullName, t),
1129
+ detail: d === e.fullName ? y : void 0
1133
1130
  }, e.fullName))
1134
1131
  }),
1135
1132
  /* @__PURE__ */ m("div", {
@@ -1140,14 +1137,14 @@ function Y() {
1140
1137
  className: "bi bi-info-circle me-1",
1141
1138
  "aria-hidden": !0
1142
1139
  }), "Deixe tudo desmarcado para incluir todas as tabelas (exceto as bloqueadas por segurança)."]
1143
- }), j > 0 && d.format !== "plain" && /* @__PURE__ */ m("span", {
1140
+ }), S > 0 && s.format !== "plain" && /* @__PURE__ */ m("span", {
1144
1141
  className: "badge text-bg-warning ms-auto text-wrap text-start",
1145
1142
  children: [
1146
1143
  /* @__PURE__ */ p("i", {
1147
1144
  className: "bi bi-exclamation-triangle me-1",
1148
1145
  "aria-hidden": !0
1149
1146
  }),
1150
- j,
1147
+ S,
1151
1148
  " coluna(s) marcada(s) serão nulificadas apenas com formato Plain SQL (texto)"
1152
1149
  ]
1153
1150
  })]
@@ -1162,15 +1159,15 @@ function Y() {
1162
1159
  type: "checkbox",
1163
1160
  role: "switch",
1164
1161
  id: "minivault-with-dump-options",
1165
- checked: l,
1166
- onChange: (e) => u(e.target.checked)
1162
+ checked: r,
1163
+ onChange: (e) => a(e.target.checked)
1167
1164
  }), /* @__PURE__ */ p("label", {
1168
1165
  className: "form-check-label",
1169
1166
  htmlFor: "minivault-with-dump-options",
1170
1167
  children: "Configurar opcoes do dump (formato, dados, indices) — desmarcar envia sem opcoes (formato padrão custom/binary no servidor)"
1171
1168
  })]
1172
1169
  }),
1173
- l && /* @__PURE__ */ m("div", {
1170
+ r && /* @__PURE__ */ m("div", {
1174
1171
  className: "card mb-3",
1175
1172
  children: [/* @__PURE__ */ m("div", {
1176
1173
  className: "card-header d-flex align-items-center gap-2",
@@ -1191,8 +1188,8 @@ function Y() {
1191
1188
  }),
1192
1189
  /* @__PURE__ */ m("select", {
1193
1190
  className: "form-select",
1194
- value: d.format,
1195
- onChange: (e) => h((t) => ({
1191
+ value: s.format,
1192
+ onChange: (e) => c((t) => ({
1196
1193
  ...t,
1197
1194
  format: e.target.value
1198
1195
  })),
@@ -1258,8 +1255,8 @@ function Y() {
1258
1255
  className: "form-check-input",
1259
1256
  type: "checkbox",
1260
1257
  id: `dump-opt-${e}`,
1261
- checked: !!d[e],
1262
- onChange: (t) => h((n) => ({
1258
+ checked: !!s[e],
1259
+ onChange: (t) => c((n) => ({
1263
1260
  ...n,
1264
1261
  [e]: t.target.checked
1265
1262
  }))
@@ -1273,167 +1270,6 @@ function Y() {
1273
1270
  })]
1274
1271
  })]
1275
1272
  }),
1276
- /* @__PURE__ */ m("div", {
1277
- className: "form-check form-switch mb-3",
1278
- children: [/* @__PURE__ */ p("input", {
1279
- className: "form-check-input",
1280
- type: "checkbox",
1281
- role: "switch",
1282
- id: "minivault-with-origin",
1283
- checked: r,
1284
- onChange: (e) => a(e.target.checked)
1285
- }), /* @__PURE__ */ p("label", {
1286
- className: "form-check-label",
1287
- htmlFor: "minivault-with-origin",
1288
- children: "Incluir arquivos de origem no backup (armazenamento do sistema)"
1289
- })]
1290
- }),
1291
- r && /* @__PURE__ */ m("div", {
1292
- className: "card mb-3",
1293
- children: [/* @__PURE__ */ m("div", {
1294
- className: "card-header d-flex align-items-center gap-2",
1295
- children: [/* @__PURE__ */ p("i", {
1296
- className: "bi bi-folder2-open",
1297
- "aria-hidden": !0
1298
- }), "Origem dos arquivos"]
1299
- }), /* @__PURE__ */ p("div", {
1300
- className: "card-body",
1301
- children: /* @__PURE__ */ m("div", {
1302
- className: "row g-3",
1303
- children: [/* @__PURE__ */ m("div", {
1304
- className: "col-md-4",
1305
- children: [/* @__PURE__ */ p("label", {
1306
- className: "form-label",
1307
- children: "Tipo"
1308
- }), /* @__PURE__ */ m("select", {
1309
- className: "form-select",
1310
- value: s.type,
1311
- onChange: (e) => c((t) => ({
1312
- ...t,
1313
- type: e.target.value
1314
- })),
1315
- children: [/* @__PURE__ */ p("option", {
1316
- value: "LOCAL",
1317
- children: "Local (diretorio)"
1318
- }), /* @__PURE__ */ p("option", {
1319
- value: "S3",
1320
- children: "S3 (MinIO/S3)"
1321
- })]
1322
- })]
1323
- }), s.type === "LOCAL" ? /* @__PURE__ */ m("div", {
1324
- className: "col-md-8",
1325
- children: [/* @__PURE__ */ p("label", {
1326
- className: "form-label",
1327
- children: "Caminho local"
1328
- }), /* @__PURE__ */ p("input", {
1329
- className: "form-control",
1330
- value: s.localPath,
1331
- placeholder: "/dados/sistema",
1332
- onChange: (e) => c((t) => ({
1333
- ...t,
1334
- localPath: e.target.value
1335
- }))
1336
- })]
1337
- }) : /* @__PURE__ */ m(f, { children: [
1338
- /* @__PURE__ */ m("div", {
1339
- className: "col-md-6",
1340
- children: [/* @__PURE__ */ p("label", {
1341
- className: "form-label",
1342
- children: "Endpoint"
1343
- }), /* @__PURE__ */ p("input", {
1344
- className: "form-control",
1345
- value: s.endpoint,
1346
- placeholder: "http://192.168.0.10:9000",
1347
- onChange: (e) => c((t) => ({
1348
- ...t,
1349
- endpoint: e.target.value
1350
- }))
1351
- })]
1352
- }),
1353
- /* @__PURE__ */ m("div", {
1354
- className: "col-md-6",
1355
- children: [/* @__PURE__ */ p("label", {
1356
- className: "form-label",
1357
- children: "Bucket"
1358
- }), /* @__PURE__ */ p("input", {
1359
- className: "form-control",
1360
- value: s.bucketName,
1361
- placeholder: "storage",
1362
- onChange: (e) => c((t) => ({
1363
- ...t,
1364
- bucketName: e.target.value
1365
- }))
1366
- })]
1367
- }),
1368
- /* @__PURE__ */ m("div", {
1369
- className: "col-md-6",
1370
- children: [/* @__PURE__ */ p("label", {
1371
- className: "form-label",
1372
- children: "Access key"
1373
- }), /* @__PURE__ */ p("input", {
1374
- className: "form-control",
1375
- value: s.accessKey,
1376
- onChange: (e) => c((t) => ({
1377
- ...t,
1378
- accessKey: e.target.value
1379
- }))
1380
- })]
1381
- }),
1382
- /* @__PURE__ */ m("div", {
1383
- className: "col-md-6",
1384
- children: [/* @__PURE__ */ p("label", {
1385
- className: "form-label",
1386
- children: "Secret key"
1387
- }), /* @__PURE__ */ p("input", {
1388
- className: "form-control",
1389
- type: "password",
1390
- value: s.secretKey,
1391
- onChange: (e) => c((t) => ({
1392
- ...t,
1393
- secretKey: e.target.value
1394
- }))
1395
- })]
1396
- }),
1397
- /* @__PURE__ */ m("div", {
1398
- className: "col-md-6",
1399
- children: [/* @__PURE__ */ p("label", {
1400
- className: "form-label",
1401
- children: "Regiao"
1402
- }), /* @__PURE__ */ p("input", {
1403
- className: "form-control",
1404
- value: s.region,
1405
- placeholder: "us-east-1",
1406
- onChange: (e) => c((t) => ({
1407
- ...t,
1408
- region: e.target.value
1409
- }))
1410
- })]
1411
- }),
1412
- /* @__PURE__ */ p("div", {
1413
- className: "col-md-6 d-flex align-items-end pb-1",
1414
- children: /* @__PURE__ */ m("div", {
1415
- className: "form-check form-switch",
1416
- children: [/* @__PURE__ */ p("input", {
1417
- className: "form-check-input",
1418
- type: "checkbox",
1419
- role: "switch",
1420
- id: "minivault-origin-pathstyle",
1421
- checked: !!s.pathStyleEnabled,
1422
- onChange: (e) => c((t) => ({
1423
- ...t,
1424
- pathStyleEnabled: e.target.checked
1425
- }))
1426
- }), /* @__PURE__ */ p("label", {
1427
- className: "form-check-label",
1428
- htmlFor: "minivault-origin-pathstyle",
1429
- children: "Path-style (MinIO)"
1430
- })]
1431
- })
1432
- })
1433
- ] })]
1434
- })
1435
- })]
1436
- }),
1437
1273
  e.isError && /* @__PURE__ */ m("div", {
1438
1274
  className: "alert alert-danger",
1439
1275
  children: [
@@ -1442,7 +1278,7 @@ function Y() {
1442
1278
  "aria-hidden": !0
1443
1279
  }),
1444
1280
  "Falha ao criar backup: ",
1445
- K(e.error)
1281
+ G(e.error)
1446
1282
  ]
1447
1283
  }),
1448
1284
  e.isSuccess && /* @__PURE__ */ m("div", {
@@ -1464,10 +1300,10 @@ function Y() {
1464
1300
  children: /* @__PURE__ */ m("button", {
1465
1301
  type: "button",
1466
1302
  className: "btn btn-primary",
1467
- onClick: P,
1468
- disabled: !I,
1303
+ onClick: O,
1304
+ disabled: !j,
1469
1305
  children: [
1470
- F && /* @__PURE__ */ p("span", {
1306
+ A && /* @__PURE__ */ p("span", {
1471
1307
  className: "spinner-border spinner-border-sm me-2",
1472
1308
  "aria-hidden": !0
1473
1309
  }),
@@ -1475,13 +1311,13 @@ function Y() {
1475
1311
  className: "bi bi-plus-lg me-1",
1476
1312
  "aria-hidden": !0
1477
1313
  }),
1478
- "Iniciar backup"
1314
+ "Iniciar backup de banco"
1479
1315
  ]
1480
1316
  })
1481
1317
  })
1482
1318
  ] });
1483
1319
  }
1484
- function te({ table: e, disabled: t, selected: n, expanded: r, excluded: i, detail: a, onToggleTable: o, onToggleExpand: s, onToggleColumn: c }) {
1320
+ function ne({ table: e, disabled: t, selected: n, expanded: r, excluded: i, detail: a, onToggleTable: o, onToggleExpand: s, onToggleColumn: c }) {
1485
1321
  return /* @__PURE__ */ p("div", {
1486
1322
  className: `card h-100 ${n ? "border-primary" : ""}`,
1487
1323
  style: { minWidth: 0 },
@@ -1545,7 +1381,7 @@ function te({ table: e, disabled: t, selected: n, expanded: r, excluded: i, deta
1545
1381
  }),
1546
1382
  a?.isError && /* @__PURE__ */ m("small", {
1547
1383
  className: "text-danger",
1548
- children: ["Erro: ", K(a.error)]
1384
+ children: ["Erro: ", G(a.error)]
1549
1385
  }),
1550
1386
  a?.data && /* @__PURE__ */ m(f, { children: [a.data.columns.map((e) => /* @__PURE__ */ m("div", {
1551
1387
  className: "d-flex align-items-center gap-2 py-1",
@@ -1596,13 +1432,13 @@ function te({ table: e, disabled: t, selected: n, expanded: r, excluded: i, deta
1596
1432
  })
1597
1433
  });
1598
1434
  }
1599
- function ne(e) {
1435
+ function re(e) {
1600
1436
  let t = e.trim();
1601
1437
  return t.includes(".") ? t : `public.${t}`;
1602
1438
  }
1603
1439
  //#endregion
1604
1440
  //#region src/components/DiagnosticsTab.tsx
1605
- function X() {
1441
+ function Y() {
1606
1442
  let { data: e, isLoading: t, isError: n, error: r, refetch: a, isFetching: o } = C(), s = i(() => e ? {
1607
1443
  total: e.length,
1608
1444
  okCount: e.filter((e) => e.ok).length,
@@ -1643,7 +1479,7 @@ function X() {
1643
1479
  "aria-hidden": !0
1644
1480
  }),
1645
1481
  "Não foi possível executar as checagens: ",
1646
- K(r)
1482
+ G(r)
1647
1483
  ]
1648
1484
  }),
1649
1485
  s && /* @__PURE__ */ m("div", {
@@ -1680,7 +1516,7 @@ function X() {
1680
1516
  className: "card",
1681
1517
  children: /* @__PURE__ */ m("ul", {
1682
1518
  className: "list-group list-group-flush",
1683
- children: [(e ?? []).map((e) => /* @__PURE__ */ p(re, { check: e }, e.name)), e && e.length === 0 && /* @__PURE__ */ p("li", {
1519
+ children: [(e ?? []).map((e) => /* @__PURE__ */ p(ie, { check: e }, e.name)), e && e.length === 0 && /* @__PURE__ */ p("li", {
1684
1520
  className: "list-group-item text-center text-muted py-4",
1685
1521
  children: "Nenhuma checagem retornada."
1686
1522
  })]
@@ -1688,7 +1524,7 @@ function X() {
1688
1524
  })
1689
1525
  ] });
1690
1526
  }
1691
- function re({ check: e }) {
1527
+ function ie({ check: e }) {
1692
1528
  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";
1693
1529
  return /* @__PURE__ */ m("li", {
1694
1530
  className: "list-group-item d-flex align-items-start gap-3",
@@ -1724,7 +1560,7 @@ function re({ check: e }) {
1724
1560
  }
1725
1561
  //#endregion
1726
1562
  //#region src/components/StorageExplorerTab.tsx
1727
- function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1563
+ function X({ storageType: e = "LOCAL", storageConfig: n }) {
1728
1564
  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({
1729
1565
  queryKey: [
1730
1566
  "storage-files",
@@ -1761,7 +1597,7 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1761
1597
  } catch {}
1762
1598
  }, N = async () => {
1763
1599
  for (let e of v) await M(e);
1764
- }, P = (e) => e ? z(e) : "-";
1600
+ }, P = (e) => e ? R(e) : "-";
1765
1601
  return /* @__PURE__ */ m("div", {
1766
1602
  className: "space-y-3",
1767
1603
  children: [
@@ -1891,7 +1727,7 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1891
1727
  }) }),
1892
1728
  /* @__PURE__ */ p("td", {
1893
1729
  className: "text-muted small",
1894
- children: e.directory ? "-" : R(e.size)
1730
+ children: e.directory ? "-" : L(e.size)
1895
1731
  }),
1896
1732
  /* @__PURE__ */ p("td", {
1897
1733
  className: "text-muted small",
@@ -1996,7 +1832,7 @@ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1996
1832
  }
1997
1833
  //#endregion
1998
1834
  //#region src/components/ImportDumpTab.tsx
1999
- function Q() {
1835
+ function Z() {
2000
1836
  let e = P(), t = F(), n = T(), r = a(null), [i, s] = o("upload"), [c, l] = o(null), [u, d] = o(""), [f, h] = o(!1), g = () => {
2001
1837
  i === "upload" && c ? e.mutate({ file: c }) : i === "storage" && u && t.mutate({
2002
1838
  storageType: "LOCAL",
@@ -2119,7 +1955,7 @@ function Q() {
2119
1955
  maxHeight: 350,
2120
1956
  overflow: "auto"
2121
1957
  },
2122
- children: /* @__PURE__ */ p(Z, {
1958
+ children: /* @__PURE__ */ p(X, {
2123
1959
  storageType: "LOCAL",
2124
1960
  storageConfig: {
2125
1961
  type: "LOCAL",
@@ -2142,7 +1978,7 @@ function Q() {
2142
1978
  children: [/* @__PURE__ */ p("p", {
2143
1979
  className: "small text-body-secondary mb-3",
2144
1980
  children: "O dump será aplicado no banco configurado no servidor. Tabelas bloqueadas por segurança são ignoradas automaticamente na importação."
2145
- }), /* @__PURE__ */ p(W, {
1981
+ }), /* @__PURE__ */ p(U, {
2146
1982
  label: "Banco de destino",
2147
1983
  dbInfo: n.data,
2148
1984
  isLoading: n.isLoading,
@@ -2158,7 +1994,7 @@ function Q() {
2158
1994
  "aria-hidden": !0
2159
1995
  }),
2160
1996
  "Falha na importacao: ",
2161
- K(y)
1997
+ G(y)
2162
1998
  ]
2163
1999
  }),
2164
2000
  v && /* @__PURE__ */ m("div", {
@@ -2199,14 +2035,142 @@ function Q() {
2199
2035
  ] });
2200
2036
  }
2201
2037
  //#endregion
2038
+ //#region src/components/StorageBackupTab.tsx
2039
+ function Q() {
2040
+ let e = k(), t = C(), n = t.data?.find((e) => e.name === "ORIGIN_STORAGE"), r = t.data?.find((e) => e.name === "OUTPUT_STORAGE"), i = e.isPending;
2041
+ return /* @__PURE__ */ m("div", { children: [
2042
+ /* @__PURE__ */ m("div", {
2043
+ className: "mb-3",
2044
+ children: [/* @__PURE__ */ p("h5", {
2045
+ className: "mb-1",
2046
+ children: "Backup de storage"
2047
+ }), /* @__PURE__ */ m("p", {
2048
+ className: "text-muted small mb-0",
2049
+ children: [
2050
+ "Faz backup dos arquivos do storage de origem para o storage de destino. Origem e destino são configurados no servidor via variáveis de ambiente (",
2051
+ /* @__PURE__ */ p("code", { children: "ORIGIN_STORAGE_*" }),
2052
+ " e ",
2053
+ /* @__PURE__ */ p("code", { children: "OUTPUT_STORAGE_*" }),
2054
+ ")."
2055
+ ]
2056
+ })]
2057
+ }),
2058
+ /* @__PURE__ */ m("div", {
2059
+ className: "card mb-3",
2060
+ children: [/* @__PURE__ */ m("div", {
2061
+ className: "card-header d-flex align-items-center gap-2",
2062
+ children: [/* @__PURE__ */ p("i", {
2063
+ className: "bi bi-heart-pulse",
2064
+ "aria-hidden": !0
2065
+ }), "Status das conexões"]
2066
+ }), /* @__PURE__ */ m("div", {
2067
+ className: "card-body",
2068
+ children: [
2069
+ t.isLoading && /* @__PURE__ */ m("div", {
2070
+ className: "text-muted small",
2071
+ children: [/* @__PURE__ */ p("span", {
2072
+ className: "spinner-border spinner-border-sm me-2",
2073
+ "aria-hidden": !0
2074
+ }), "Verificando conexões..."]
2075
+ }),
2076
+ t.isError && /* @__PURE__ */ p("div", {
2077
+ className: "text-muted small",
2078
+ children: "Não foi possível verificar o status. O backup pode ser executado mesmo assim."
2079
+ }),
2080
+ t.data && /* @__PURE__ */ m("div", {
2081
+ className: "d-flex flex-column gap-2",
2082
+ children: [/* @__PURE__ */ p($, {
2083
+ label: n?.label ?? "Storage de origem",
2084
+ configured: n?.configured,
2085
+ ok: n?.ok,
2086
+ message: n?.message
2087
+ }), /* @__PURE__ */ p($, {
2088
+ label: r?.label ?? "Storage de destino",
2089
+ configured: r?.configured,
2090
+ ok: r?.ok,
2091
+ message: r?.message
2092
+ })]
2093
+ })
2094
+ ]
2095
+ })]
2096
+ }),
2097
+ e.isError && /* @__PURE__ */ m("div", {
2098
+ className: "alert alert-danger",
2099
+ children: [
2100
+ /* @__PURE__ */ p("i", {
2101
+ className: "bi bi-x-circle me-2",
2102
+ "aria-hidden": !0
2103
+ }),
2104
+ "Falha ao criar backup de storage: ",
2105
+ G(e.error)
2106
+ ]
2107
+ }),
2108
+ e.isSuccess && /* @__PURE__ */ m("div", {
2109
+ className: "alert alert-success",
2110
+ children: [
2111
+ /* @__PURE__ */ p("i", {
2112
+ className: "bi bi-check-circle me-2",
2113
+ "aria-hidden": !0
2114
+ }),
2115
+ "Backup de storage #",
2116
+ e.data.id,
2117
+ " criado (",
2118
+ e.data.filename,
2119
+ ")."
2120
+ ]
2121
+ }),
2122
+ /* @__PURE__ */ p("div", {
2123
+ className: "d-flex justify-content-end",
2124
+ children: /* @__PURE__ */ m("button", {
2125
+ type: "button",
2126
+ className: "btn btn-primary",
2127
+ onClick: () => {
2128
+ e.mutate({ backupType: "STORAGE" });
2129
+ },
2130
+ disabled: i || t.data != null && n?.configured === !1,
2131
+ children: [
2132
+ i && /* @__PURE__ */ p("span", {
2133
+ className: "spinner-border spinner-border-sm me-2",
2134
+ "aria-hidden": !0
2135
+ }),
2136
+ /* @__PURE__ */ p("i", {
2137
+ className: "bi bi-plus-lg me-1",
2138
+ "aria-hidden": !0
2139
+ }),
2140
+ "Iniciar backup de storage"
2141
+ ]
2142
+ })
2143
+ })
2144
+ ] });
2145
+ }
2146
+ function $({ label: e, configured: t, ok: n, message: r }) {
2147
+ return t === !1 ? /* @__PURE__ */ m("div", {
2148
+ className: "d-flex align-items-center gap-2 small text-muted",
2149
+ children: [/* @__PURE__ */ p("i", {
2150
+ className: "bi bi-dash-circle text-secondary",
2151
+ "aria-hidden": !0
2152
+ }), /* @__PURE__ */ m("span", { children: [/* @__PURE__ */ m("strong", { children: [e, ":"] }), " não configurado no servidor"] })]
2153
+ }) : /* @__PURE__ */ m("div", {
2154
+ className: `d-flex align-items-center gap-2 small ${n ? "text-success" : "text-danger"}`,
2155
+ children: [/* @__PURE__ */ p("i", {
2156
+ className: `bi ${n ? "bi-check-circle-fill" : "bi-x-circle-fill"}`,
2157
+ "aria-hidden": !0
2158
+ }), /* @__PURE__ */ m("span", { children: [
2159
+ /* @__PURE__ */ m("strong", { children: [e, ":"] }),
2160
+ " ",
2161
+ r ?? (n ? "ok" : "falha")
2162
+ ] })]
2163
+ });
2164
+ }
2165
+ //#endregion
2202
2166
  //#region src/hooks/useAutoTheme.ts
2203
- function $() {
2167
+ function ae() {
2204
2168
  return typeof document < "u" && document.documentElement.classList.contains("dark");
2205
2169
  }
2206
- function ie(e) {
2207
- let [t, n] = o($), [i, a] = o(() => typeof window < "u" && window.matchMedia?.("(prefers-color-scheme: dark)")?.matches === !0);
2170
+ function oe(e) {
2171
+ let [t, n] = o(ae), [i, a] = o(() => typeof window < "u" && window.matchMedia?.("(prefers-color-scheme: dark)")?.matches === !0);
2208
2172
  return r(() => {
2209
- let e = document.documentElement, t = new MutationObserver(() => n($()));
2173
+ let e = document.documentElement, t = new MutationObserver(() => n(ae()));
2210
2174
  return t.observe(e, {
2211
2175
  attributes: !0,
2212
2176
  attributeFilter: ["class"]
@@ -2219,8 +2183,8 @@ function ie(e) {
2219
2183
  }
2220
2184
  //#endregion
2221
2185
  //#region src/components/MinivaultModule.tsx
2222
- function ae(e) {
2223
- let { companyAcronym: t = "Minivault", theme: n, refetchIntervalMs: r = 15e3, storageType: i = "LOCAL", ...a } = e, l = ie(n), [u] = o(() => new s({ defaultOptions: { queries: {
2186
+ function se(e) {
2187
+ let { companyAcronym: t = "Minivault", theme: n, refetchIntervalMs: r = 15e3, storageType: i = "LOCAL", ...a } = e, l = oe(n), [u] = o(() => new s({ defaultOptions: { queries: {
2224
2188
  refetchInterval: r,
2225
2189
  retry: 1
2226
2190
  } } }));
@@ -2231,15 +2195,15 @@ function ae(e) {
2231
2195
  children: /* @__PURE__ */ m("div", {
2232
2196
  className: "minivault-module h-full w-full overflow-auto",
2233
2197
  "data-minivault-theme": l,
2234
- children: [/* @__PURE__ */ p(oe, {
2198
+ children: [/* @__PURE__ */ p(ce, {
2235
2199
  companyAcronym: t,
2236
2200
  theme: l
2237
- }), /* @__PURE__ */ p(se, { storageType: i })]
2201
+ }), /* @__PURE__ */ p(le, { storageType: i })]
2238
2202
  })
2239
2203
  })
2240
2204
  });
2241
2205
  }
2242
- function oe({ companyAcronym: e, theme: t }) {
2206
+ function ce({ companyAcronym: e, theme: t }) {
2243
2207
  return /* @__PURE__ */ m("div", {
2244
2208
  className: "d-flex align-items-center justify-content-between flex-wrap gap-2 px-3 py-2 border-bottom",
2245
2209
  style: {
@@ -2257,7 +2221,7 @@ function oe({ companyAcronym: e, theme: t }) {
2257
2221
  })
2258
2222
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("strong", { children: [e, " · Backups"] }), /* @__PURE__ */ p("div", {
2259
2223
  className: "small text-muted",
2260
- children: "Gerenciamento de backups de banco de dados"
2224
+ children: "Gerenciamento de backups de banco de dados e storage"
2261
2225
  })] })]
2262
2226
  }), /* @__PURE__ */ p("div", {
2263
2227
  className: "d-flex align-items-center gap-2",
@@ -2268,7 +2232,7 @@ function oe({ companyAcronym: e, theme: t }) {
2268
2232
  })]
2269
2233
  });
2270
2234
  }
2271
- function se({ storageType: e }) {
2235
+ function le({ storageType: e }) {
2272
2236
  let [t, n] = o("backups");
2273
2237
  return /* @__PURE__ */ m("div", {
2274
2238
  className: "p-3",
@@ -2297,7 +2261,19 @@ function se({ storageType: e }) {
2297
2261
  children: [/* @__PURE__ */ p("i", {
2298
2262
  className: "bi bi-plus-circle me-1",
2299
2263
  "aria-hidden": !0
2300
- }), "Novo backup"]
2264
+ }), "Backup de BD"]
2265
+ })
2266
+ }),
2267
+ /* @__PURE__ */ p("li", {
2268
+ className: "nav-item",
2269
+ children: /* @__PURE__ */ m("button", {
2270
+ type: "button",
2271
+ className: `nav-link ${t === "createStorage" ? "active" : ""}`,
2272
+ onClick: () => n("createStorage"),
2273
+ children: [/* @__PURE__ */ p("i", {
2274
+ className: "bi bi-plus-circle me-1",
2275
+ "aria-hidden": !0
2276
+ }), "Backup de storage"]
2301
2277
  })
2302
2278
  }),
2303
2279
  /* @__PURE__ */ p("li", {
@@ -2338,22 +2314,23 @@ function se({ storageType: e }) {
2338
2314
  })
2339
2315
  ]
2340
2316
  }),
2341
- t === "backups" && /* @__PURE__ */ p(q, {}),
2342
- t === "create" && /* @__PURE__ */ p(Y, {}),
2343
- t === "import" && /* @__PURE__ */ p(Q, {}),
2344
- t === "storage" && /* @__PURE__ */ p(Z, { storageType: e }),
2345
- t === "diagnostics" && /* @__PURE__ */ p(X, {})
2317
+ t === "backups" && /* @__PURE__ */ p(K, {}),
2318
+ t === "create" && /* @__PURE__ */ p(J, {}),
2319
+ t === "createStorage" && /* @__PURE__ */ p(Q, {}),
2320
+ t === "import" && /* @__PURE__ */ p(Z, {}),
2321
+ t === "storage" && /* @__PURE__ */ p(X, { storageType: e }),
2322
+ t === "diagnostics" && /* @__PURE__ */ p(Y, {})
2346
2323
  ]
2347
2324
  });
2348
2325
  }
2349
2326
  //#endregion
2350
2327
  //#region src/components/CredentialsFields.tsx
2351
- var ce = [
2328
+ var ue = [
2352
2329
  "postgresql",
2353
2330
  "mysql",
2354
2331
  "sqlserver"
2355
2332
  ];
2356
- function le() {
2333
+ function de() {
2357
2334
  return {
2358
2335
  host: "localhost",
2359
2336
  port: 5432,
@@ -2363,19 +2340,19 @@ function le() {
2363
2340
  databaseType: "postgresql"
2364
2341
  };
2365
2342
  }
2366
- function ue(e) {
2343
+ function fe(e) {
2367
2344
  return e === "postgresql" || e === "postgres" ? 5432 : e === "mysql" ? 3306 : 1433;
2368
2345
  }
2369
- function de({ value: e, onChange: t, onValidatedChange: n }) {
2346
+ function pe({ value: e, onChange: t, onValidatedChange: n }) {
2370
2347
  let r = {
2371
- ...le(),
2348
+ ...de(),
2372
2349
  ...e
2373
2350
  }, i = (e) => {
2374
2351
  let n = {
2375
2352
  ...r,
2376
2353
  databaseType: e
2377
2354
  };
2378
- (r.port === ue(r.databaseType) || !r.port) && (n.port = ue(e)), t(n);
2355
+ (r.port === fe(r.databaseType) || !r.port) && (n.port = fe(e)), t(n);
2379
2356
  }, a = (e) => {
2380
2357
  let i = {
2381
2358
  ...r,
@@ -2397,9 +2374,9 @@ function de({ value: e, onChange: t, onValidatedChange: n }) {
2397
2374
  className: "form-select",
2398
2375
  value: r.databaseType,
2399
2376
  onChange: (e) => i(e.target.value),
2400
- children: ce.map((e) => /* @__PURE__ */ p("option", {
2377
+ children: ue.map((e) => /* @__PURE__ */ p("option", {
2401
2378
  value: e,
2402
- children: H[e] ?? e
2379
+ children: V[e] ?? e
2403
2380
  }, e))
2404
2381
  })]
2405
2382
  }),
@@ -2471,4 +2448,4 @@ function de({ value: e, onChange: t, onValidatedChange: n }) {
2471
2448
  });
2472
2449
  }
2473
2450
  //#endregion
2474
- export { q as BackupsTab, Y as CreateBackupTab, de 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, ae as MinivaultModule, G as RestoreModal, V as STATUS_BADGE, B as STATUS_LABELS, U as StatusBadge, Z as StorageExplorerTab, z as formatDate, R as formatFileSize, w as useBackups, k as useCreateBackup, T as useDbInfo, O as useDbRelationships, D as useDbTableDetail, E as useDbTables, j as useDeleteBackup, C as useDiagnostics, N as useDownloadBackup, P as useImportDump, F as useImportFromStorage, b as useMinivaultApi, A as useRestoreBackup };
2451
+ export { K as BackupsTab, J as CreateBackupTab, pe as CredentialsFields, V as DATABASE_TYPE_LABELS, U as DatabaseBanner, Y as DiagnosticsTab, Z as ImportDumpTab, g as MinivaultApi, h as MinivaultApiError, y as MinivaultApiProvider, se as MinivaultModule, W as RestoreModal, B as STATUS_BADGE, z as STATUS_LABELS, H as StatusBadge, Q as StorageBackupTab, X as StorageExplorerTab, R as formatDate, L as formatFileSize, w as useBackups, k as useCreateBackup, T as useDbInfo, O as useDbRelationships, D as useDbTableDetail, E as useDbTables, j as useDeleteBackup, C as useDiagnostics, N as useDownloadBackup, P as useImportDump, F as useImportFromStorage, b as useMinivaultApi, A as useRestoreBackup };
@@ -1,4 +1,5 @@
1
1
  export type BackupStatus = 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'RESTORING' | 'RESTORED' | 'RESTORE_FAILED';
2
+ export type BackupType = 'DATABASE' | 'STORAGE' | 'FULL';
2
3
  export type DatabaseType = 'postgresql' | 'postgres' | 'mysql' | 'sqlserver' | 'mssql';
3
4
  export type DumpFormat = 'custom' | 'plain' | 'tar';
4
5
  export interface Backup {
@@ -67,6 +68,8 @@ export interface DumpOptions {
67
68
  includeRelatedTables?: boolean;
68
69
  }
69
70
  export interface BackupRequest {
71
+ /** Tipo do backup: DATABASE (apenas banco), STORAGE (apenas arquivos) ou FULL (padrão legado). */
72
+ backupType?: BackupType;
70
73
  /** Opcional: usa o banco padrão configurado no servidor (env) quando ausente. */
71
74
  database?: DatabaseCredentials;
72
75
  originStorage?: OriginStorageConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v1ct0rbr/minivault-web",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
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",