@v1ct0rbr/minivault-web 0.6.2 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +74 -74
  2. package/dist/minivault-web.js +113 -104
  3. package/package.json +72 -72
package/README.md CHANGED
@@ -1,75 +1,75 @@
1
- # minivault-web
2
-
3
- Módulo independente de **gestão de backups** (cliente do serviço
4
- [minivault](../minivault)). Consumível como pacote npm em qualquer app React,
5
- estilizado com Bootstrap. Comunica-se com a API REST do minivault — normalmente
6
- através de um **proxy autenticado** (ex.: `/minivault` no backend do Siga+), de
7
- modo que a `X-API-Key` do minivault jamais trafega no browser.
8
-
9
- ## Recursos
10
-
11
- - Lista de backups com paginação, status, tamanho e data.
12
- - Criação de backup (com origem de arquivos LOCAL ou S3, opcional).
13
- - Restauração de backup em um banco informado.
14
- - Importação de dump SQL em texto (`psql`/`mysql`) via upload.
15
- - Download e exclusão de backups.
16
- - Tema claro/escuro e auto-refresh.
17
-
18
- ## Instalação
19
-
20
- ```bash
21
- npm install @v1ct0rbr/minivault-web
22
- ```
23
-
24
- Como dependência local durante o desenvolvimento:
25
-
26
- ```bash
27
- npm install file:../minivault-web
28
- ```
29
-
30
- ## Uso no Siga+ (proxy autenticado)
31
-
32
- ```tsx
33
- import { MinivaultModule } from '@v1ct0rbr/minivault-web'
34
- import '@v1ct0rbr/minivault-web/style.css'
35
- import { useAuthStore } from '@/store/useAuthStore'
36
-
37
- const apiBase = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080'
38
-
39
- export function MinivaultPage() {
40
- const getToken = () => useAuthStore.getState().token
41
- return <MinivaultModule baseUrl={apiBase + '/minivault'} getToken={getToken} />
42
- }
43
- ```
44
-
45
- ## Uso standalone (desenvolvimento)
46
-
47
- ```tsx
48
- <MinivaultModule baseUrl="http://localhost:8081" token="api-key-do-minivault" />
49
- ```
50
-
51
- > Em produção o token do minivault deve ficar apenas no proxy do backend, nunca
52
- > no bundle do frontend.
53
-
54
- ## Desenvolvimento
55
-
56
- ```bash
57
- npm install
58
- npm run dev # playground standalone (porta 5176)
59
- npm run build:lib # gera dist/ (lib ES + types)
60
- npm test # vitest
61
- npm run typecheck # tsc --noEmit
62
- ```
63
-
64
- ### Playground standalone
65
-
66
- ```bash
67
- VITE_MINIVAULT_API_URL=http://localhost:8081 VITE_MINIVAULT_API_TOKEN=chave npm run dev
68
- ```
69
-
70
- ## Publicação
71
-
72
- ```bash
73
- npm run build:lib && npm test
74
- npm publish --access public
1
+ # minivault-web
2
+
3
+ Módulo independente de **gestão de backups** (cliente do serviço
4
+ [minivault](../minivault)). Consumível como pacote npm em qualquer app React,
5
+ estilizado com Bootstrap. Comunica-se com a API REST do minivault — normalmente
6
+ através de um **proxy autenticado** (ex.: `/minivault` no backend do Siga+), de
7
+ modo que a `X-API-Key` do minivault jamais trafega no browser.
8
+
9
+ ## Recursos
10
+
11
+ - Lista de backups com paginação, status, tamanho e data.
12
+ - Criação de backup (com origem de arquivos LOCAL ou S3, opcional).
13
+ - Restauração de backup em um banco informado.
14
+ - Importação de dump SQL em texto (`psql`/`mysql`) via upload.
15
+ - Download e exclusão de backups.
16
+ - Tema claro/escuro e auto-refresh.
17
+
18
+ ## Instalação
19
+
20
+ ```bash
21
+ npm install @v1ct0rbr/minivault-web
22
+ ```
23
+
24
+ Como dependência local durante o desenvolvimento:
25
+
26
+ ```bash
27
+ npm install file:../minivault-web
28
+ ```
29
+
30
+ ## Uso no Siga+ (proxy autenticado)
31
+
32
+ ```tsx
33
+ import { MinivaultModule } from '@v1ct0rbr/minivault-web'
34
+ import '@v1ct0rbr/minivault-web/style.css'
35
+ import { useAuthStore } from '@/store/useAuthStore'
36
+
37
+ const apiBase = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080'
38
+
39
+ export function MinivaultPage() {
40
+ const getToken = () => useAuthStore.getState().token
41
+ return <MinivaultModule baseUrl={apiBase + '/minivault'} getToken={getToken} />
42
+ }
43
+ ```
44
+
45
+ ## Uso standalone (desenvolvimento)
46
+
47
+ ```tsx
48
+ <MinivaultModule baseUrl="http://localhost:8081" token="api-key-do-minivault" />
49
+ ```
50
+
51
+ > Em produção o token do minivault deve ficar apenas no proxy do backend, nunca
52
+ > no bundle do frontend.
53
+
54
+ ## Desenvolvimento
55
+
56
+ ```bash
57
+ npm install
58
+ npm run dev # playground standalone (porta 5176)
59
+ npm run build:lib # gera dist/ (lib ES + types)
60
+ npm test # vitest
61
+ npm run typecheck # tsc --noEmit
62
+ ```
63
+
64
+ ### Playground standalone
65
+
66
+ ```bash
67
+ VITE_MINIVAULT_API_URL=http://localhost:8081 VITE_MINIVAULT_API_TOKEN=chave npm run dev
68
+ ```
69
+
70
+ ## Publicação
71
+
72
+ ```bash
73
+ npm run build:lib && npm test
74
+ npm publish --access public
75
75
  ```
@@ -207,8 +207,12 @@ var S = {
207
207
  all: ["minivault", "backups"],
208
208
  db: ["minivault", "db"],
209
209
  diagnostics: ["minivault", "diagnostics"]
210
- };
211
- function C(e = !0) {
210
+ }, C = /* @__PURE__ */ new Set([
211
+ "PENDING",
212
+ "IN_PROGRESS",
213
+ "RESTORING"
214
+ ]), w = 3e3;
215
+ function T(e = !0) {
212
216
  let t = x();
213
217
  return u({
214
218
  queryKey: S.diagnostics,
@@ -216,8 +220,8 @@ function C(e = !0) {
216
220
  enabled: e && !!t
217
221
  });
218
222
  }
219
- function w(e = 0, t = 10, n = !0) {
220
- let r = x();
223
+ function E(e = 0, t = 10, n = !0) {
224
+ let r = x(), i = d().getDefaultOptions().queries?.refetchInterval, a = typeof i == "number" ? i : 15e3;
221
225
  return u({
222
226
  queryKey: [
223
227
  ...S.all,
@@ -225,10 +229,11 @@ function w(e = 0, t = 10, n = !0) {
225
229
  t
226
230
  ],
227
231
  queryFn: () => r.listBackups(e, t),
228
- enabled: n && !!r
232
+ enabled: n && !!r,
233
+ refetchInterval: (e) => (e.state.data?.content)?.some((e) => C.has(e.status)) ? w : a
229
234
  });
230
235
  }
231
- function T(e = !0) {
236
+ function D(e = !0) {
232
237
  let t = x();
233
238
  return u({
234
239
  queryKey: [...S.db, "info"],
@@ -236,7 +241,7 @@ function T(e = !0) {
236
241
  enabled: e && !!t
237
242
  });
238
243
  }
239
- function E(e = !0) {
244
+ function O(e = !0) {
240
245
  let t = x();
241
246
  return u({
242
247
  queryKey: [...S.db, "tables"],
@@ -244,7 +249,7 @@ function E(e = !0) {
244
249
  enabled: e && !!t
245
250
  });
246
251
  }
247
- function D(e, t = !0) {
252
+ function k(e, t = !0) {
248
253
  let n = x();
249
254
  return u({
250
255
  queryKey: [
@@ -256,7 +261,7 @@ function D(e, t = !0) {
256
261
  enabled: t && !!n && !!e
257
262
  });
258
263
  }
259
- function O(e = !0) {
264
+ function A(e = !0) {
260
265
  let t = x();
261
266
  return u({
262
267
  queryKey: [...S.db, "relationships"],
@@ -264,74 +269,74 @@ function O(e = !0) {
264
269
  enabled: e && !!t
265
270
  });
266
271
  }
267
- function k() {
272
+ function j() {
268
273
  let e = b(), t = d();
269
274
  return l({
270
275
  mutationFn: (t) => e.createBackup(t.database, t.originStorage, t.dumpOptions, t.backupType),
271
276
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
272
277
  });
273
278
  }
274
- function A() {
279
+ function M() {
275
280
  let e = b(), t = d();
276
281
  return l({
277
282
  mutationFn: (t) => e.restoreBackup(t.id, t.database, t.originStorage),
278
283
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
279
284
  });
280
285
  }
281
- function j() {
286
+ function N() {
282
287
  let e = b(), t = d();
283
288
  return l({
284
289
  mutationFn: (t) => e.deleteBackup(t),
285
290
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
286
291
  });
287
292
  }
288
- function M() {
293
+ function P() {
289
294
  let e = b(), t = d();
290
295
  return l({
291
296
  mutationFn: (t) => e.verifyBackup(t),
292
297
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
293
298
  });
294
299
  }
295
- function N() {
300
+ function ee() {
296
301
  let e = b();
297
302
  return l({ mutationFn: (t) => e.downloadBackup(t.id) });
298
303
  }
299
- function P() {
304
+ function F() {
300
305
  let e = b();
301
306
  return l({ mutationFn: (t) => e.importDump(t.file, t.database) });
302
307
  }
303
- function F() {
308
+ function I() {
304
309
  let e = b();
305
310
  return l({ mutationFn: (t) => e.importFromStorage(t.storageType, t.storagePath, t.database, t.storageConfig) });
306
311
  }
307
312
  //#endregion
308
313
  //#region src/utils/format.ts
309
- var ee = new Intl.DateTimeFormat("pt-BR", {
314
+ var te = new Intl.DateTimeFormat("pt-BR", {
310
315
  day: "2-digit",
311
316
  month: "2-digit",
312
317
  year: "numeric",
313
318
  hour: "2-digit",
314
319
  minute: "2-digit"
315
- }), te = [
320
+ }), L = [
316
321
  "B",
317
322
  "KB",
318
323
  "MB",
319
324
  "GB",
320
325
  "TB"
321
326
  ];
322
- function I(e) {
327
+ function R(e) {
323
328
  if (e == null || e < 0) return "—";
324
329
  if (e < 1024) return `${e} B`;
325
330
  let t = e, n = 0;
326
- for (; t >= 1024 && n < te.length - 1;) t /= 1024, n += 1;
327
- return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${te[n]}`;
331
+ for (; t >= 1024 && n < L.length - 1;) t /= 1024, n += 1;
332
+ return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${L[n]}`;
328
333
  }
329
- function L(e) {
334
+ function z(e) {
330
335
  if (!e) return "—";
331
336
  let t = new Date(e);
332
- return Number.isNaN(t.getTime()) ? "—" : ee.format(t);
337
+ return Number.isNaN(t.getTime()) ? "—" : te.format(t);
333
338
  }
334
- var R = {
339
+ var B = {
335
340
  PENDING: "Pendente",
336
341
  IN_PROGRESS: "Em andamento",
337
342
  COMPLETED: "Concluído",
@@ -339,7 +344,7 @@ var R = {
339
344
  RESTORING: "Restaurando",
340
345
  RESTORED: "Restaurado",
341
346
  RESTORE_FAILED: "Falha na restauração"
342
- }, z = {
347
+ }, V = {
343
348
  PENDING: "text-bg-secondary",
344
349
  IN_PROGRESS: "text-bg-primary",
345
350
  COMPLETED: "text-bg-success",
@@ -347,7 +352,7 @@ var R = {
347
352
  RESTORING: "text-bg-warning",
348
353
  RESTORED: "text-bg-info",
349
354
  RESTORE_FAILED: "text-bg-danger"
350
- }, B = {
355
+ }, H = {
351
356
  postgresql: "PostgreSQL",
352
357
  postgres: "PostgreSQL",
353
358
  mysql: "MySQL",
@@ -364,8 +369,8 @@ var R = {
364
369
  };
365
370
  //#endregion
366
371
  //#region src/components/StatusBadge.tsx
367
- function V({ status: e }) {
368
- let t = z[e] ?? "text-bg-secondary", n = R[e] ?? e;
372
+ function U({ status: e }) {
373
+ let t = V[e] ?? "text-bg-secondary", n = B[e] ?? e;
369
374
  return /* @__PURE__ */ p("span", {
370
375
  className: `badge rounded-pill ${t}`,
371
376
  children: n
@@ -373,7 +378,7 @@ function V({ status: e }) {
373
378
  }
374
379
  //#endregion
375
380
  //#region src/components/DatabaseBanner.tsx
376
- function H({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
381
+ function W({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
377
382
  if (t) return /* @__PURE__ */ p("div", {
378
383
  className: "mb-3",
379
384
  children: /* @__PURE__ */ m("small", {
@@ -392,7 +397,7 @@ function H({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
392
397
  "aria-hidden": !0
393
398
  }),
394
399
  "Não foi possível consultar o banco configurado: ",
395
- W(n)
400
+ K(n)
396
401
  ]
397
402
  });
398
403
  if (!e || !e.configured) return i ? /* @__PURE__ */ m("div", {
@@ -414,7 +419,7 @@ function H({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
414
419
  "). A criação e a importação usam esse banco."
415
420
  ]
416
421
  });
417
- let a = B[e.databaseType ?? ""] ?? e.databaseType ?? "postgresql";
422
+ let a = H[e.databaseType ?? ""] ?? e.databaseType ?? "postgresql";
418
423
  return i ? /* @__PURE__ */ m("div", {
419
424
  className: "mb-3",
420
425
  children: [
@@ -532,8 +537,8 @@ function H({ dbInfo: e, isLoading: t, error: n, label: r, compact: i = !1 }) {
532
537
  }
533
538
  //#endregion
534
539
  //#region src/components/RestoreModal.tsx
535
- function U({ backup: e, onClose: t }) {
536
- let n = A(), r = T(), i = () => {
540
+ function G({ backup: e, onClose: t }) {
541
+ let n = M(), r = D(), i = () => {
537
542
  n.mutate({ id: e.id });
538
543
  }, a = n.isPending, o = e.backupType === "STORAGE";
539
544
  return /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", { className: "modal-backdrop show" }), /* @__PURE__ */ p("div", {
@@ -583,7 +588,7 @@ function U({ backup: e, onClose: t }) {
583
588
  " será aplicado no banco configurado abaixo."
584
589
  ] })
585
590
  }),
586
- !o && /* @__PURE__ */ p(H, {
591
+ !o && /* @__PURE__ */ p(W, {
587
592
  label: "Banco de destino",
588
593
  dbInfo: r.data,
589
594
  isLoading: r.isLoading,
@@ -594,7 +599,7 @@ function U({ backup: e, onClose: t }) {
594
599
  children: [/* @__PURE__ */ p("i", {
595
600
  className: "bi bi-x-circle me-2",
596
601
  "aria-hidden": !0
597
- }), W(n.error)]
602
+ }), K(n.error)]
598
603
  }),
599
604
  n.isSuccess && /* @__PURE__ */ m("div", {
600
605
  className: "alert alert-success mt-3 mb-0",
@@ -629,13 +634,13 @@ function U({ backup: e, onClose: t }) {
629
634
  })
630
635
  })] });
631
636
  }
632
- function W(e) {
637
+ function K(e) {
633
638
  return e instanceof Error ? e.message : String(e);
634
639
  }
635
640
  //#endregion
636
641
  //#region src/components/BackupsTab.tsx
637
- function G() {
638
- 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();
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();
639
644
  r(() => {
640
645
  if (!y.data || !y.variables) return;
641
646
  let e = URL.createObjectURL(y.data), t = document.createElement("a");
@@ -677,7 +682,7 @@ function G() {
677
682
  "aria-hidden": !0
678
683
  }),
679
684
  "Não foi possível carregar os backups: ",
680
- K(g)
685
+ J(g)
681
686
  ]
682
687
  }),
683
688
  y.isError && /* @__PURE__ */ m("div", {
@@ -688,7 +693,7 @@ function G() {
688
693
  "aria-hidden": !0
689
694
  }),
690
695
  "Falha no download: ",
691
- K(y.error)
696
+ J(y.error)
692
697
  ]
693
698
  }),
694
699
  b.isError && /* @__PURE__ */ m("div", {
@@ -699,7 +704,7 @@ function G() {
699
704
  "aria-hidden": !0
700
705
  }),
701
706
  "Falha ao excluir: ",
702
- K(b.error)
707
+ J(b.error)
703
708
  ]
704
709
  }),
705
710
  x.isError && /* @__PURE__ */ m("div", {
@@ -710,7 +715,7 @@ function G() {
710
715
  "aria-hidden": !0
711
716
  }),
712
717
  "Falha ao verificar: ",
713
- K(x.error)
718
+ J(x.error)
714
719
  ]
715
720
  }),
716
721
  Object.entries(l).map(([e, t]) => /* @__PURE__ */ m("div", {
@@ -809,12 +814,12 @@ function G() {
809
814
  className: "text-muted",
810
815
  children: "—"
811
816
  }) }),
812
- /* @__PURE__ */ p("td", { children: B[e.databaseType] ?? e.databaseType }),
817
+ /* @__PURE__ */ p("td", { children: H[e.databaseType] ?? e.databaseType }),
813
818
  /* @__PURE__ */ p("td", {
814
819
  className: "text-end",
815
- children: I(e.fileSize)
820
+ children: R(e.fileSize)
816
821
  }),
817
- /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(V, { status: e.status }) }),
822
+ /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(U, { status: e.status }) }),
818
823
  /* @__PURE__ */ p("td", { children: e.sha256 ? /* @__PURE__ */ m("code", {
819
824
  title: e.sha256,
820
825
  style: { fontSize: "0.8em" },
@@ -837,7 +842,7 @@ function G() {
837
842
  className: "text-muted",
838
843
  children: "—"
839
844
  }) }),
840
- /* @__PURE__ */ p("td", { children: L(e.createdAt) }),
845
+ /* @__PURE__ */ p("td", { children: z(e.createdAt) }),
841
846
  /* @__PURE__ */ m("td", {
842
847
  className: "text-end text-nowrap",
843
848
  children: [
@@ -930,7 +935,7 @@ function G() {
930
935
  })]
931
936
  })]
932
937
  }),
933
- n && /* @__PURE__ */ p(U, {
938
+ n && /* @__PURE__ */ p(G, {
934
939
  backup: n,
935
940
  onClose: () => a(null)
936
941
  }),
@@ -1010,13 +1015,13 @@ function ie(e) {
1010
1015
  })
1011
1016
  })] });
1012
1017
  }
1013
- function K(e) {
1018
+ function J(e) {
1014
1019
  return e instanceof Error ? e.message : String(e);
1015
1020
  }
1016
1021
  //#endregion
1017
1022
  //#region src/components/CreateBackupTab.tsx
1018
- function q() {
1019
- let e = k(), t = T(), n = E(t.data?.configured), [r, a] = o(!0), [s, c] = o({
1023
+ function Y() {
1024
+ let e = j(), t = D(), n = O(t.data?.configured), [r, a] = o(!0), [s, c] = o({
1020
1025
  format: "plain",
1021
1026
  includeData: !0,
1022
1027
  includeDropTable: !1,
@@ -1024,7 +1029,7 @@ function q() {
1024
1029
  includeIndexes: !0,
1025
1030
  includeConstraints: !0,
1026
1031
  includeRelatedTables: !1
1027
- }), [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(oe)), [t.data?.exportExcludedTables]), x = i(() => {
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(() => {
1028
1033
  let e = n.data ?? [], t = _.trim().toLowerCase();
1029
1034
  return t ? e.filter((e) => e.fullName.toLowerCase().includes(t)) : e;
1030
1035
  }, [n.data, _]), S = i(() => Object.values(h).reduce((e, t) => e + t.length, 0), [h]), C = (e) => {
@@ -1040,7 +1045,7 @@ function q() {
1040
1045
  [e]: i
1041
1046
  };
1042
1047
  });
1043
- }, O = () => {
1048
+ }, T = () => {
1044
1049
  let t;
1045
1050
  if (r) {
1046
1051
  t = { ...s }, l.size > 0 && (t.tables = [...l]);
@@ -1053,7 +1058,7 @@ function q() {
1053
1058
  backupType: "DATABASE",
1054
1059
  dumpOptions: t
1055
1060
  });
1056
- }, A = e.isPending, j = t.data?.configured && !A;
1061
+ }, E = e.isPending, A = t.data?.configured && !E;
1057
1062
  return /* @__PURE__ */ m("div", { children: [
1058
1063
  /* @__PURE__ */ m("div", {
1059
1064
  className: "mb-3",
@@ -1065,7 +1070,7 @@ function q() {
1065
1070
  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."
1066
1071
  })]
1067
1072
  }),
1068
- /* @__PURE__ */ p(H, {
1073
+ /* @__PURE__ */ p(W, {
1069
1074
  label: "Banco de destino",
1070
1075
  dbInfo: t.data,
1071
1076
  isLoading: t.isLoading,
@@ -1124,7 +1129,7 @@ function q() {
1124
1129
  "aria-hidden": !0
1125
1130
  }),
1126
1131
  "Falha ao listar tabelas: ",
1127
- W(n.error)
1132
+ K(n.error)
1128
1133
  ]
1129
1134
  }),
1130
1135
  x.length === 0 && !n.isLoading && /* @__PURE__ */ p("div", {
@@ -1301,7 +1306,7 @@ function q() {
1301
1306
  "aria-hidden": !0
1302
1307
  }),
1303
1308
  "Falha ao criar backup: ",
1304
- W(e.error)
1309
+ K(e.error)
1305
1310
  ]
1306
1311
  }),
1307
1312
  e.isSuccess && /* @__PURE__ */ m("div", {
@@ -1313,9 +1318,9 @@ function q() {
1313
1318
  }),
1314
1319
  "Backup #",
1315
1320
  e.data.id,
1316
- " criado (",
1321
+ " enfileirado (",
1317
1322
  e.data.filename,
1318
- ")."
1323
+ "). O progresso é exibido na aba Backups."
1319
1324
  ]
1320
1325
  }),
1321
1326
  /* @__PURE__ */ p("div", {
@@ -1323,10 +1328,10 @@ function q() {
1323
1328
  children: /* @__PURE__ */ m("button", {
1324
1329
  type: "button",
1325
1330
  className: "btn btn-primary",
1326
- onClick: O,
1327
- disabled: !j,
1331
+ onClick: T,
1332
+ disabled: !A,
1328
1333
  children: [
1329
- A && /* @__PURE__ */ p("span", {
1334
+ E && /* @__PURE__ */ p("span", {
1330
1335
  className: "spinner-border spinner-border-sm me-2",
1331
1336
  "aria-hidden": !0
1332
1337
  }),
@@ -1404,7 +1409,7 @@ function ae({ table: e, disabled: t, selected: n, expanded: r, excluded: i, deta
1404
1409
  }),
1405
1410
  a?.isError && /* @__PURE__ */ m("small", {
1406
1411
  className: "text-danger",
1407
- children: ["Erro: ", W(a.error)]
1412
+ children: ["Erro: ", K(a.error)]
1408
1413
  }),
1409
1414
  a?.data && /* @__PURE__ */ m(f, { children: [a.data.columns.map((e) => /* @__PURE__ */ m("div", {
1410
1415
  className: "d-flex align-items-center gap-2 py-1",
@@ -1461,8 +1466,8 @@ function oe(e) {
1461
1466
  }
1462
1467
  //#endregion
1463
1468
  //#region src/components/DiagnosticsTab.tsx
1464
- function J() {
1465
- let { data: e, isLoading: t, isError: n, error: r, refetch: a, isFetching: o } = C(), s = i(() => e ? {
1469
+ function X() {
1470
+ let { data: e, isLoading: t, isError: n, error: r, refetch: a, isFetching: o } = T(), s = i(() => e ? {
1466
1471
  total: e.length,
1467
1472
  okCount: e.filter((e) => e.ok).length,
1468
1473
  notConfigured: e.filter((e) => !e.configured).length
@@ -1502,7 +1507,7 @@ function J() {
1502
1507
  "aria-hidden": !0
1503
1508
  }),
1504
1509
  "Não foi possível executar as checagens: ",
1505
- W(r)
1510
+ K(r)
1506
1511
  ]
1507
1512
  }),
1508
1513
  s && /* @__PURE__ */ m("div", {
@@ -1583,7 +1588,7 @@ function se({ check: e }) {
1583
1588
  }
1584
1589
  //#endregion
1585
1590
  //#region src/components/StorageExplorerTab.tsx
1586
- function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1591
+ function Z({ storageType: e = "LOCAL", storageConfig: n }) {
1587
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({
1588
1593
  queryKey: [
1589
1594
  "storage-files",
@@ -1619,8 +1624,12 @@ function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1619
1624
  o.href = a, o.download = r, document.body.appendChild(o), o.click(), o.remove(), window.URL.revokeObjectURL(a);
1620
1625
  } catch {}
1621
1626
  }, N = async () => {
1622
- for (let e of v) await M(e);
1623
- }, P = (e) => e ? L(e) : "-";
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) : "-";
1624
1633
  return /* @__PURE__ */ m("div", {
1625
1634
  className: "space-y-3",
1626
1635
  children: [
@@ -1750,7 +1759,7 @@ function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1750
1759
  }) }),
1751
1760
  /* @__PURE__ */ p("td", {
1752
1761
  className: "text-muted small",
1753
- children: e.directory ? "-" : I(e.size)
1762
+ children: e.directory ? "-" : R(e.size)
1754
1763
  }),
1755
1764
  /* @__PURE__ */ p("td", {
1756
1765
  className: "text-muted small",
@@ -1855,8 +1864,8 @@ function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1855
1864
  }
1856
1865
  //#endregion
1857
1866
  //#region src/components/ImportDumpTab.tsx
1858
- function X() {
1859
- 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 = () => {
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 = () => {
1860
1869
  i === "upload" && c ? e.mutate({ file: c }) : i === "storage" && u && t.mutate({
1861
1870
  storageType: "LOCAL",
1862
1871
  storagePath: u
@@ -1978,7 +1987,7 @@ function X() {
1978
1987
  maxHeight: 350,
1979
1988
  overflow: "auto"
1980
1989
  },
1981
- children: /* @__PURE__ */ p(Y, {
1990
+ children: /* @__PURE__ */ p(Z, {
1982
1991
  storageType: "LOCAL",
1983
1992
  storageConfig: {
1984
1993
  type: "LOCAL",
@@ -2001,7 +2010,7 @@ function X() {
2001
2010
  children: [/* @__PURE__ */ p("p", {
2002
2011
  className: "small text-body-secondary mb-3",
2003
2012
  children: "O dump será aplicado no banco configurado no servidor. Tabelas bloqueadas por segurança são ignoradas automaticamente na importação."
2004
- }), /* @__PURE__ */ p(H, {
2013
+ }), /* @__PURE__ */ p(W, {
2005
2014
  label: "Banco de destino",
2006
2015
  dbInfo: n.data,
2007
2016
  isLoading: n.isLoading,
@@ -2017,7 +2026,7 @@ function X() {
2017
2026
  "aria-hidden": !0
2018
2027
  }),
2019
2028
  "Falha na importacao: ",
2020
- W(y)
2029
+ K(y)
2021
2030
  ]
2022
2031
  }),
2023
2032
  v && /* @__PURE__ */ m("div", {
@@ -2059,8 +2068,8 @@ function X() {
2059
2068
  }
2060
2069
  //#endregion
2061
2070
  //#region src/components/StorageBackupTab.tsx
2062
- function Z() {
2063
- 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;
2071
+ function ce() {
2072
+ let e = j(), t = T(), n = t.data?.find((e) => e.name === "ORIGIN_STORAGE"), r = t.data?.find((e) => e.name === "OUTPUT_STORAGE"), i = e.isPending;
2064
2073
  return /* @__PURE__ */ m("div", { children: [
2065
2074
  /* @__PURE__ */ m("div", {
2066
2075
  className: "mb-3",
@@ -2102,12 +2111,12 @@ function Z() {
2102
2111
  }),
2103
2112
  t.data && /* @__PURE__ */ m("div", {
2104
2113
  className: "d-flex flex-column gap-2",
2105
- children: [/* @__PURE__ */ p(Q, {
2114
+ children: [/* @__PURE__ */ p(le, {
2106
2115
  label: n?.label ?? "Storage de origem",
2107
2116
  configured: n?.configured,
2108
2117
  ok: n?.ok,
2109
2118
  message: n?.message
2110
- }), /* @__PURE__ */ p(Q, {
2119
+ }), /* @__PURE__ */ p(le, {
2111
2120
  label: r?.label ?? "Storage de destino",
2112
2121
  configured: r?.configured,
2113
2122
  ok: r?.ok,
@@ -2125,7 +2134,7 @@ function Z() {
2125
2134
  "aria-hidden": !0
2126
2135
  }),
2127
2136
  "Falha ao criar backup de storage: ",
2128
- W(e.error)
2137
+ K(e.error)
2129
2138
  ]
2130
2139
  }),
2131
2140
  e.isSuccess && /* @__PURE__ */ m("div", {
@@ -2137,9 +2146,9 @@ function Z() {
2137
2146
  }),
2138
2147
  "Backup de storage #",
2139
2148
  e.data.id,
2140
- " criado (",
2149
+ " enfileirado (",
2141
2150
  e.data.filename,
2142
- ")."
2151
+ "). O progresso é exibido na aba Backups."
2143
2152
  ]
2144
2153
  }),
2145
2154
  /* @__PURE__ */ p("div", {
@@ -2166,7 +2175,7 @@ function Z() {
2166
2175
  })
2167
2176
  ] });
2168
2177
  }
2169
- function Q({ label: e, configured: t, ok: n, message: r }) {
2178
+ function le({ label: e, configured: t, ok: n, message: r }) {
2170
2179
  return t === !1 ? /* @__PURE__ */ m("div", {
2171
2180
  className: "d-flex align-items-center gap-2 small text-muted",
2172
2181
  children: [/* @__PURE__ */ p("i", {
@@ -2190,7 +2199,7 @@ function Q({ label: e, configured: t, ok: n, message: r }) {
2190
2199
  function $() {
2191
2200
  return typeof document < "u" && document.documentElement.classList.contains("dark");
2192
2201
  }
2193
- function ce(e) {
2202
+ function ue(e) {
2194
2203
  let [t, n] = o($), [i, a] = o(() => typeof window < "u" && window.matchMedia?.("(prefers-color-scheme: dark)")?.matches === !0);
2195
2204
  return r(() => {
2196
2205
  let e = document.documentElement, t = new MutationObserver(() => n($()));
@@ -2206,8 +2215,8 @@ function ce(e) {
2206
2215
  }
2207
2216
  //#endregion
2208
2217
  //#region src/components/MinivaultModule.tsx
2209
- function le(e) {
2210
- let { companyAcronym: t = "Minivault", theme: n, refetchIntervalMs: r = 15e3, storageType: i = "LOCAL", ...a } = e, l = ce(n), [u] = o(() => new s({ defaultOptions: { queries: {
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: {
2211
2220
  refetchInterval: r,
2212
2221
  retry: 1
2213
2222
  } } }));
@@ -2218,15 +2227,15 @@ function le(e) {
2218
2227
  children: /* @__PURE__ */ m("div", {
2219
2228
  className: "minivault-module h-full w-full overflow-auto",
2220
2229
  "data-minivault-theme": l,
2221
- children: [/* @__PURE__ */ p(ue, {
2230
+ children: [/* @__PURE__ */ p(fe, {
2222
2231
  companyAcronym: t,
2223
2232
  theme: l
2224
- }), /* @__PURE__ */ p(de, { storageType: i })]
2233
+ }), /* @__PURE__ */ p(pe, { storageType: i })]
2225
2234
  })
2226
2235
  })
2227
2236
  });
2228
2237
  }
2229
- function ue({ companyAcronym: e, theme: t }) {
2238
+ function fe({ companyAcronym: e, theme: t }) {
2230
2239
  return /* @__PURE__ */ m("div", {
2231
2240
  className: "d-flex align-items-center justify-content-between flex-wrap gap-2 px-3 py-2 border-bottom",
2232
2241
  style: {
@@ -2255,7 +2264,7 @@ function ue({ companyAcronym: e, theme: t }) {
2255
2264
  })]
2256
2265
  });
2257
2266
  }
2258
- function de({ storageType: e }) {
2267
+ function pe({ storageType: e }) {
2259
2268
  let [t, n] = o("backups");
2260
2269
  return /* @__PURE__ */ m("div", {
2261
2270
  className: "p-3",
@@ -2337,23 +2346,23 @@ function de({ storageType: e }) {
2337
2346
  })
2338
2347
  ]
2339
2348
  }),
2340
- t === "backups" && /* @__PURE__ */ p(G, {}),
2341
- t === "create" && /* @__PURE__ */ p(q, {}),
2342
- t === "createStorage" && /* @__PURE__ */ p(Z, {}),
2343
- t === "import" && /* @__PURE__ */ p(X, {}),
2344
- t === "storage" && /* @__PURE__ */ p(Y, { storageType: e }),
2345
- t === "diagnostics" && /* @__PURE__ */ p(J, {})
2349
+ t === "backups" && /* @__PURE__ */ p(q, {}),
2350
+ t === "create" && /* @__PURE__ */ p(Y, {}),
2351
+ 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, {})
2346
2355
  ]
2347
2356
  });
2348
2357
  }
2349
2358
  //#endregion
2350
2359
  //#region src/components/CredentialsFields.tsx
2351
- var fe = [
2360
+ var me = [
2352
2361
  "postgresql",
2353
2362
  "mysql",
2354
2363
  "sqlserver"
2355
2364
  ];
2356
- function pe() {
2365
+ function he() {
2357
2366
  return {
2358
2367
  host: "localhost",
2359
2368
  port: 5432,
@@ -2363,19 +2372,19 @@ function pe() {
2363
2372
  databaseType: "postgresql"
2364
2373
  };
2365
2374
  }
2366
- function me(e) {
2375
+ function ge(e) {
2367
2376
  return e === "postgresql" || e === "postgres" ? 5432 : e === "mysql" ? 3306 : 1433;
2368
2377
  }
2369
- function he({ value: e, onChange: t, onValidatedChange: n }) {
2378
+ function _e({ value: e, onChange: t, onValidatedChange: n }) {
2370
2379
  let r = {
2371
- ...pe(),
2380
+ ...he(),
2372
2381
  ...e
2373
2382
  }, i = (e) => {
2374
2383
  let n = {
2375
2384
  ...r,
2376
2385
  databaseType: e
2377
2386
  };
2378
- (r.port === me(r.databaseType) || !r.port) && (n.port = me(e)), t(n);
2387
+ (r.port === ge(r.databaseType) || !r.port) && (n.port = ge(e)), t(n);
2379
2388
  }, a = (e) => {
2380
2389
  let i = {
2381
2390
  ...r,
@@ -2397,9 +2406,9 @@ function he({ value: e, onChange: t, onValidatedChange: n }) {
2397
2406
  className: "form-select",
2398
2407
  value: r.databaseType,
2399
2408
  onChange: (e) => i(e.target.value),
2400
- children: fe.map((e) => /* @__PURE__ */ p("option", {
2409
+ children: me.map((e) => /* @__PURE__ */ p("option", {
2401
2410
  value: e,
2402
- children: B[e] ?? e
2411
+ children: H[e] ?? e
2403
2412
  }, e))
2404
2413
  })]
2405
2414
  }),
@@ -2471,4 +2480,4 @@ function he({ value: e, onChange: t, onValidatedChange: n }) {
2471
2480
  });
2472
2481
  }
2473
2482
  //#endregion
2474
- export { G as BackupsTab, q as CreateBackupTab, he as CredentialsFields, B as DATABASE_TYPE_LABELS, H as DatabaseBanner, J as DiagnosticsTab, X as ImportDumpTab, g as MinivaultApi, h as MinivaultApiError, y as MinivaultApiProvider, le as MinivaultModule, U as RestoreModal, z as STATUS_BADGE, R as STATUS_LABELS, V as StatusBadge, Z as StorageBackupTab, Y as StorageExplorerTab, L as formatDate, I 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 };
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 };
package/package.json CHANGED
@@ -1,73 +1,73 @@
1
- {
2
- "name": "@v1ct0rbr/minivault-web",
3
- "version": "0.6.2",
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
- "author": "Victor Queiroga (https://www.linkedin.com/in/victor-queiroga)",
6
- "license": "MIT",
7
- "type": "module",
8
- "publishConfig": {
9
- "access": "public",
10
- "registry": "https://registry.npmjs.org/"
11
- },
12
- "files": [
13
- "dist",
14
- "README.md"
15
- ],
16
- "keywords": [
17
- "backup",
18
- "minivault",
19
- "der",
20
- "react",
21
- "bootstrap",
22
- "postgresql"
23
- ],
24
- "repository": {
25
- "type": "git",
26
- "url": "https://github.com/v1ct0rbr/minivault-web.git"
27
- },
28
- "main": "./dist/minivault-web.js",
29
- "module": "./dist/minivault-web.js",
30
- "types": "./dist/index.d.ts",
31
- "exports": {
32
- ".": {
33
- "types": "./dist/index.d.ts",
34
- "import": "./dist/minivault-web.js"
35
- },
36
- "./style.css": "./dist/minivault-web.css"
37
- },
38
- "scripts": {
39
- "dev": "vite --port 5176",
40
- "build": "vite build && tsc --noEmit",
41
- "build:lib": "vite build --config vite.lib.config.ts && tsc --noEmit",
42
- "prepublishOnly": "npm run build:lib && npm test",
43
- "prepack": "npm run build:lib",
44
- "preview": "vite preview",
45
- "test": "vitest run",
46
- "test:watch": "vitest",
47
- "typecheck": "tsc --noEmit",
48
- "lint": "eslint ."
49
- },
50
- "dependencies": {
51
- "bootstrap": "^5.3.3",
52
- "bootstrap-icons": "^1.11.3"
53
- },
54
- "peerDependencies": {
55
- "@tanstack/react-query": "^5.0.0",
56
- "react": "^19.0.0",
57
- "react-dom": "^19.0.0"
58
- },
59
- "devDependencies": {
60
- "@tanstack/react-query": "^5.66.5",
61
- "@types/node": "^22.10.2",
62
- "@types/react": "^19.2.0",
63
- "@types/react-dom": "^19.2.0",
64
- "@vitejs/plugin-react": "^5.0.4",
65
- "postcss-prefix-selector": "^2.1.1",
66
- "react": "^19.2.0",
67
- "react-dom": "^19.2.0",
68
- "typescript": "^5.7.2",
69
- "vite": "^8.0.16",
70
- "vite-plugin-dts": "^4.5.0",
71
- "vitest": "^4.1.8"
72
- }
1
+ {
2
+ "name": "@v1ct0rbr/minivault-web",
3
+ "version": "0.6.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
+ "author": "Victor Queiroga (https://www.linkedin.com/in/victor-queiroga)",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "publishConfig": {
9
+ "access": "public",
10
+ "registry": "https://registry.npmjs.org/"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md"
15
+ ],
16
+ "keywords": [
17
+ "backup",
18
+ "minivault",
19
+ "der",
20
+ "react",
21
+ "bootstrap",
22
+ "postgresql"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/v1ct0rbr/minivault-web.git"
27
+ },
28
+ "main": "./dist/minivault-web.js",
29
+ "module": "./dist/minivault-web.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/minivault-web.js"
35
+ },
36
+ "./style.css": "./dist/minivault-web.css"
37
+ },
38
+ "scripts": {
39
+ "dev": "vite --port 5176",
40
+ "build": "vite build && tsc --noEmit",
41
+ "build:lib": "vite build --config vite.lib.config.ts && tsc --noEmit",
42
+ "prepublishOnly": "npm run build:lib && npm test",
43
+ "prepack": "npm run build:lib",
44
+ "preview": "vite preview",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "typecheck": "tsc --noEmit",
48
+ "lint": "eslint ."
49
+ },
50
+ "dependencies": {
51
+ "bootstrap": "^5.3.3",
52
+ "bootstrap-icons": "^1.11.3"
53
+ },
54
+ "peerDependencies": {
55
+ "@tanstack/react-query": "^5.0.0",
56
+ "react": "^19.0.0",
57
+ "react-dom": "^19.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@tanstack/react-query": "^5.66.5",
61
+ "@types/node": "^22.10.2",
62
+ "@types/react": "^19.2.0",
63
+ "@types/react-dom": "^19.2.0",
64
+ "@vitejs/plugin-react": "^5.0.4",
65
+ "postcss-prefix-selector": "^2.1.1",
66
+ "react": "^19.2.0",
67
+ "react-dom": "^19.2.0",
68
+ "typescript": "^5.7.2",
69
+ "vite": "^8.0.16",
70
+ "vite-plugin-dts": "^4.5.0",
71
+ "vitest": "^4.1.8"
72
+ }
73
73
  }