@v1ct0rbr/minivault-web 0.2.0 → 0.3.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.
@@ -55,18 +55,15 @@ var h = class extends Error {
55
55
  return this.request(`/api/backups/${e}`);
56
56
  }
57
57
  createBackup(e, t, n) {
58
- let r = { database: e };
59
- return t && (r.originStorage = t), n && (r.dumpOptions = n), this.request("/api/backups", {
58
+ let r = {};
59
+ return e && (r.database = e), t && (r.originStorage = t), n && (r.dumpOptions = n), this.request("/api/backups", {
60
60
  method: "POST",
61
61
  body: JSON.stringify(r)
62
62
  });
63
63
  }
64
64
  restoreBackup(e, t, n) {
65
- let r = n ? {
66
- database: t,
67
- originStorage: n
68
- } : { database: t };
69
- return this.request(`/api/backups/${e}/restore`, {
65
+ let r = {};
66
+ return t && (r.database = t), n && (r.originStorage = n), this.request(`/api/backups/${e}/restore`, {
70
67
  method: "POST",
71
68
  body: JSON.stringify(r)
72
69
  });
@@ -95,7 +92,7 @@ var h = class extends Error {
95
92
  }
96
93
  async importDump(e, t) {
97
94
  let n = await this.resolveToken(), r = new FormData();
98
- r.append("file", e), r.append("database", new Blob([JSON.stringify(t)], { type: "application/json" }));
95
+ r.append("file", e), t && r.append("database", new Blob([JSON.stringify(t)], { type: "application/json" }));
99
96
  let i = {};
100
97
  n && (i.Authorization = `Bearer ${n}`);
101
98
  let a = new AbortController(), o = setTimeout(() => a.abort(), this.timeoutMs);
@@ -117,14 +114,25 @@ var h = class extends Error {
117
114
  async importFromStorage(e, t, n, r) {
118
115
  let i = {
119
116
  storageType: e,
120
- storagePath: t,
121
- database: n
117
+ storagePath: t
122
118
  };
123
- return r && (i.storageConfig = r), this.request("/api/backups/import-from-storage", {
119
+ return n && (i.database = n), r && (i.storageConfig = r), this.request("/api/backups/import-from-storage", {
124
120
  method: "POST",
125
121
  body: JSON.stringify(i)
126
122
  });
127
123
  }
124
+ getDbInfo() {
125
+ return this.request("/api/db");
126
+ }
127
+ listDbTables() {
128
+ return this.request("/api/db/tables");
129
+ }
130
+ getDbTable(e) {
131
+ return this.request(`/api/db/tables/${encodeURIComponent(e)}`);
132
+ }
133
+ listDbRelationships() {
134
+ return this.request("/api/db/relationships");
135
+ }
128
136
  listStorageFiles(e, t, n) {
129
137
  let r = new URLSearchParams({ type: e });
130
138
  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()}`);
@@ -190,7 +198,10 @@ function x() {
190
198
  }
191
199
  //#endregion
192
200
  //#region src/hooks/useBackups.ts
193
- var S = { all: ["minivault", "backups"] };
201
+ var S = {
202
+ all: ["minivault", "backups"],
203
+ db: ["minivault", "db"]
204
+ };
194
205
  function C(e = 0, t = 10, n = !0) {
195
206
  let r = x();
196
207
  return u({
@@ -203,74 +214,110 @@ function C(e = 0, t = 10, n = !0) {
203
214
  enabled: n && !!r
204
215
  });
205
216
  }
206
- function w() {
217
+ function w(e = !0) {
218
+ let t = x();
219
+ return u({
220
+ queryKey: [...S.db, "info"],
221
+ queryFn: () => t.getDbInfo(),
222
+ enabled: e && !!t
223
+ });
224
+ }
225
+ function T(e = !0) {
226
+ let t = x();
227
+ return u({
228
+ queryKey: [...S.db, "tables"],
229
+ queryFn: () => t.listDbTables(),
230
+ enabled: e && !!t
231
+ });
232
+ }
233
+ function E(e, t = !0) {
234
+ let n = x();
235
+ return u({
236
+ queryKey: [
237
+ ...S.db,
238
+ "table",
239
+ e
240
+ ],
241
+ queryFn: () => n.getDbTable(e),
242
+ enabled: t && !!n && !!e
243
+ });
244
+ }
245
+ function D(e = !0) {
246
+ let t = x();
247
+ return u({
248
+ queryKey: [...S.db, "relationships"],
249
+ queryFn: () => t.listDbRelationships(),
250
+ enabled: e && !!t
251
+ });
252
+ }
253
+ function O() {
207
254
  let e = b(), t = d();
208
255
  return l({
209
256
  mutationFn: (t) => e.createBackup(t.database, t.originStorage, t.dumpOptions),
210
257
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
211
258
  });
212
259
  }
213
- function T() {
260
+ function k() {
214
261
  let e = b(), t = d();
215
262
  return l({
216
263
  mutationFn: (t) => e.restoreBackup(t.id, t.database, t.originStorage),
217
264
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
218
265
  });
219
266
  }
220
- function E() {
267
+ function A() {
221
268
  let e = b(), t = d();
222
269
  return l({
223
270
  mutationFn: (t) => e.deleteBackup(t),
224
271
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
225
272
  });
226
273
  }
227
- function D() {
274
+ function j() {
228
275
  let e = b(), t = d();
229
276
  return l({
230
277
  mutationFn: (t) => e.verifyBackup(t),
231
278
  onSuccess: () => t.invalidateQueries({ queryKey: S.all })
232
279
  });
233
280
  }
234
- function O() {
281
+ function M() {
235
282
  let e = b();
236
283
  return l({ mutationFn: (t) => e.downloadBackup(t.id) });
237
284
  }
238
- function k() {
285
+ function N() {
239
286
  let e = b();
240
287
  return l({ mutationFn: (t) => e.importDump(t.file, t.database) });
241
288
  }
242
- function A() {
289
+ function P() {
243
290
  let e = b();
244
291
  return l({ mutationFn: (t) => e.importFromStorage(t.storageType, t.storagePath, t.database, t.storageConfig) });
245
292
  }
246
293
  //#endregion
247
294
  //#region src/utils/format.ts
248
- var j = new Intl.DateTimeFormat("pt-BR", {
295
+ var F = new Intl.DateTimeFormat("pt-BR", {
249
296
  day: "2-digit",
250
297
  month: "2-digit",
251
298
  year: "numeric",
252
299
  hour: "2-digit",
253
300
  minute: "2-digit"
254
- }), M = [
301
+ }), I = [
255
302
  "B",
256
303
  "KB",
257
304
  "MB",
258
305
  "GB",
259
306
  "TB"
260
307
  ];
261
- function N(e) {
308
+ function L(e) {
262
309
  if (e == null || e < 0) return "—";
263
310
  if (e < 1024) return `${e} B`;
264
311
  let t = e, n = 0;
265
- for (; t >= 1024 && n < M.length - 1;) t /= 1024, n += 1;
266
- return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${M[n]}`;
312
+ for (; t >= 1024 && n < I.length - 1;) t /= 1024, n += 1;
313
+ return `${Number.isInteger(t) ? t : Number(t.toFixed(1))} ${I[n]}`;
267
314
  }
268
- function P(e) {
315
+ function R(e) {
269
316
  if (!e) return "—";
270
317
  let t = new Date(e);
271
- return Number.isNaN(t.getTime()) ? "—" : j.format(t);
318
+ return Number.isNaN(t.getTime()) ? "—" : F.format(t);
272
319
  }
273
- var F = {
320
+ var z = {
274
321
  PENDING: "Pendente",
275
322
  IN_PROGRESS: "Em andamento",
276
323
  COMPLETED: "Concluído",
@@ -278,7 +325,7 @@ var F = {
278
325
  RESTORING: "Restaurando",
279
326
  RESTORED: "Restaurado",
280
327
  RESTORE_FAILED: "Falha na restauração"
281
- }, I = {
328
+ }, B = {
282
329
  PENDING: "text-bg-secondary",
283
330
  IN_PROGRESS: "text-bg-primary",
284
331
  COMPLETED: "text-bg-success",
@@ -286,7 +333,7 @@ var F = {
286
333
  RESTORING: "text-bg-warning",
287
334
  RESTORED: "text-bg-info",
288
335
  RESTORE_FAILED: "text-bg-danger"
289
- }, L = {
336
+ }, V = {
290
337
  postgresql: "PostgreSQL",
291
338
  postgres: "PostgreSQL",
292
339
  mysql: "MySQL",
@@ -295,146 +342,123 @@ var F = {
295
342
  };
296
343
  //#endregion
297
344
  //#region src/components/StatusBadge.tsx
298
- function R({ status: e }) {
299
- let t = I[e] ?? "text-bg-secondary", n = F[e] ?? e;
345
+ function H({ status: e }) {
346
+ let t = B[e] ?? "text-bg-secondary", n = z[e] ?? e;
300
347
  return /* @__PURE__ */ p("span", {
301
348
  className: `badge rounded-pill ${t}`,
302
349
  children: n
303
350
  });
304
351
  }
305
352
  //#endregion
306
- //#region src/components/CredentialsFields.tsx
307
- var z = [
308
- "postgresql",
309
- "mysql",
310
- "sqlserver"
311
- ];
312
- function B() {
313
- return {
314
- host: "localhost",
315
- port: 5432,
316
- databaseName: "",
317
- username: "",
318
- password: "",
319
- databaseType: "postgresql"
320
- };
321
- }
322
- function V(e) {
323
- return e === "postgresql" || e === "postgres" ? 5432 : e === "mysql" ? 3306 : 1433;
324
- }
325
- function H({ value: e, onChange: t, onValidatedChange: n }) {
326
- let r = {
327
- ...B(),
328
- ...e
329
- }, i = (e) => {
330
- let n = {
331
- ...r,
332
- databaseType: e
333
- };
334
- (r.port === V(r.databaseType) || !r.port) && (n.port = V(e)), t(n);
335
- }, a = (e) => {
336
- let i = {
337
- ...r,
338
- ...e
339
- };
340
- t(i);
341
- let a = !!(i.host.trim() && i.port > 0 && i.databaseName.trim() && i.username.trim() && i.password.length > 0);
342
- n?.(a);
343
- };
344
- return /* @__PURE__ */ m("div", {
345
- className: "row g-3",
353
+ //#region src/components/DatabaseBanner.tsx
354
+ function U({ dbInfo: e, isLoading: t, error: n, label: r }) {
355
+ if (t) return /* @__PURE__ */ p("div", {
356
+ className: "mb-3",
357
+ children: /* @__PURE__ */ m("small", {
358
+ className: "text-muted",
359
+ children: [/* @__PURE__ */ p("span", {
360
+ className: "spinner-border spinner-border-sm me-2",
361
+ "aria-hidden": !0
362
+ }), "Consultando banco configurado..."]
363
+ })
364
+ });
365
+ if (n) return /* @__PURE__ */ m("div", {
366
+ className: "alert alert-warning mb-3 py-2 small",
346
367
  children: [
347
- /* @__PURE__ */ m("div", {
348
- className: "col-md-6",
349
- children: [/* @__PURE__ */ p("label", {
350
- className: "form-label",
351
- children: "Tipo de banco"
352
- }), /* @__PURE__ */ p("select", {
353
- className: "form-select",
354
- value: r.databaseType,
355
- onChange: (e) => i(e.target.value),
356
- children: z.map((e) => /* @__PURE__ */ p("option", {
357
- value: e,
358
- children: L[e] ?? e
359
- }, e))
360
- })]
361
- }),
362
- /* @__PURE__ */ m("div", {
363
- className: "col-md-6",
364
- children: [/* @__PURE__ */ p("label", {
365
- className: "form-label",
366
- children: "Host"
367
- }), /* @__PURE__ */ p("input", {
368
- className: "form-control",
369
- value: r.host,
370
- placeholder: "localhost",
371
- onChange: (e) => a({ host: e.target.value })
372
- })]
368
+ /* @__PURE__ */ p("i", {
369
+ className: "bi bi-exclamation-triangle me-2",
370
+ "aria-hidden": !0
373
371
  }),
374
- /* @__PURE__ */ m("div", {
375
- className: "col-md-4",
376
- children: [/* @__PURE__ */ p("label", {
377
- className: "form-label",
378
- children: "Porta"
379
- }), /* @__PURE__ */ p("input", {
380
- className: "form-control",
381
- type: "number",
382
- min: 1,
383
- max: 65535,
384
- value: r.port,
385
- onChange: (e) => a({ port: Number(e.target.value) })
386
- })]
372
+ "Não foi possível consultar o banco configurado: ",
373
+ G(n)
374
+ ]
375
+ });
376
+ if (!e || !e.configured) return /* @__PURE__ */ m("div", {
377
+ className: "alert alert-danger mb-3 py-2 small",
378
+ children: [
379
+ /* @__PURE__ */ p("i", {
380
+ className: "bi bi-x-octagon me-2",
381
+ "aria-hidden": !0
387
382
  }),
383
+ "Banco padrão não configurado no servidor minivault (variáveis",
384
+ " ",
385
+ /* @__PURE__ */ p("code", { children: "MINIVAULT_DB_*" }),
386
+ "). A criação e a importação usam esse banco."
387
+ ]
388
+ });
389
+ let i = V[e.databaseType ?? ""] ?? e.databaseType ?? "postgresql";
390
+ return /* @__PURE__ */ m("div", {
391
+ className: "mb-3",
392
+ children: [
388
393
  /* @__PURE__ */ m("div", {
389
- className: "col-md-8",
390
- children: [/* @__PURE__ */ p("label", {
391
- className: "form-label",
392
- children: "Nome do banco"
393
- }), /* @__PURE__ */ p("input", {
394
- className: "form-control",
395
- value: r.databaseName,
396
- placeholder: "sigamais",
397
- onChange: (e) => a({ databaseName: e.target.value })
398
- })]
394
+ className: "d-flex flex-wrap align-items-center gap-2 small text-body-secondary",
395
+ children: [
396
+ /* @__PURE__ */ p("i", {
397
+ className: "bi bi-database-fill",
398
+ "aria-hidden": !0
399
+ }),
400
+ /* @__PURE__ */ m("span", { children: [
401
+ r,
402
+ ": ",
403
+ /* @__PURE__ */ p("strong", { children: i }),
404
+ " em ",
405
+ /* @__PURE__ */ m("code", { children: [
406
+ e.host,
407
+ ":",
408
+ e.port,
409
+ "/",
410
+ e.databaseName
411
+ ] })
412
+ ] }),
413
+ /* @__PURE__ */ p("span", {
414
+ className: "badge text-bg-info",
415
+ children: "configurado por env"
416
+ })
417
+ ]
399
418
  }),
400
- /* @__PURE__ */ m("div", {
401
- className: "col-md-6",
402
- children: [/* @__PURE__ */ p("label", {
403
- className: "form-label",
404
- children: "Usuário"
405
- }), /* @__PURE__ */ p("input", {
406
- className: "form-control",
407
- value: r.username,
408
- placeholder: "postgres",
409
- autoComplete: "off",
410
- onChange: (e) => a({ username: e.target.value })
411
- })]
419
+ e.exportExcludedTables.length > 0 && /* @__PURE__ */ m("div", {
420
+ className: "mt-1 small",
421
+ children: [
422
+ /* @__PURE__ */ p("i", {
423
+ className: "bi bi-shield-lock me-1",
424
+ "aria-hidden": !0
425
+ }),
426
+ /* @__PURE__ */ p("span", {
427
+ className: "text-body-secondary",
428
+ children: "Exportação sempre ignora: "
429
+ }),
430
+ e.exportExcludedTables.map((e) => /* @__PURE__ */ p("span", {
431
+ className: "badge text-bg-secondary me-1",
432
+ children: e
433
+ }, `ex-${e}`))
434
+ ]
412
435
  }),
413
- /* @__PURE__ */ m("div", {
414
- className: "col-md-6",
415
- children: [/* @__PURE__ */ p("label", {
416
- className: "form-label",
417
- children: "Senha"
418
- }), /* @__PURE__ */ p("input", {
419
- className: "form-control",
420
- type: "password",
421
- value: r.password,
422
- autoComplete: "new-password",
423
- onChange: (e) => a({ password: e.target.value })
424
- })]
436
+ e.importExcludedTables.length > 0 && /* @__PURE__ */ m("div", {
437
+ className: "mt-1 small",
438
+ children: [
439
+ /* @__PURE__ */ p("i", {
440
+ className: "bi bi-shield-lock me-1",
441
+ "aria-hidden": !0
442
+ }),
443
+ /* @__PURE__ */ p("span", {
444
+ className: "text-body-secondary",
445
+ children: "Importação sempre ignora: "
446
+ }),
447
+ e.importExcludedTables.map((e) => /* @__PURE__ */ p("span", {
448
+ className: "badge text-bg-secondary me-1",
449
+ children: e
450
+ }, `im-${e}`))
451
+ ]
425
452
  })
426
453
  ]
427
454
  });
428
455
  }
429
456
  //#endregion
430
457
  //#region src/components/RestoreModal.tsx
431
- function U({ backup: e, onClose: t }) {
432
- let n = T(), [r, i] = o(), [a, s] = o(!1), c = () => {
433
- r && n.mutate({
434
- id: e.id,
435
- database: r
436
- });
437
- }, l = n.isPending;
458
+ function W({ backup: e, onClose: t }) {
459
+ let n = k(), r = w(), i = () => {
460
+ n.mutate({ id: e.id });
461
+ }, a = n.isPending;
438
462
  return /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", { className: "modal-backdrop show" }), /* @__PURE__ */ p("div", {
439
463
  className: "modal show d-block",
440
464
  tabIndex: -1,
@@ -475,19 +499,21 @@ function U({ backup: e, onClose: t }) {
475
499
  children: [
476
500
  "O arquivo ",
477
501
  /* @__PURE__ */ p("code", { children: e.filename }),
478
- " será aplicado no banco informado abaixo."
502
+ " será aplicado no banco configurado abaixo."
479
503
  ]
480
504
  }),
481
- /* @__PURE__ */ p(H, {
482
- onChange: i,
483
- onValidatedChange: s
505
+ /* @__PURE__ */ p(U, {
506
+ label: "Banco de destino",
507
+ dbInfo: r.data,
508
+ isLoading: r.isLoading,
509
+ error: r.error
484
510
  }),
485
511
  n.isError && /* @__PURE__ */ m("div", {
486
512
  className: "alert alert-danger mt-3 mb-0",
487
513
  children: [/* @__PURE__ */ p("i", {
488
514
  className: "bi bi-x-circle me-2",
489
515
  "aria-hidden": !0
490
- }), W(n.error)]
516
+ }), G(n.error)]
491
517
  }),
492
518
  n.isSuccess && /* @__PURE__ */ m("div", {
493
519
  className: "alert alert-success mt-3 mb-0",
@@ -504,14 +530,14 @@ function U({ backup: e, onClose: t }) {
504
530
  type: "button",
505
531
  className: "btn btn-secondary",
506
532
  onClick: t,
507
- disabled: l,
533
+ disabled: a,
508
534
  children: "Fechar"
509
535
  }), /* @__PURE__ */ m("button", {
510
536
  type: "button",
511
537
  className: "btn btn-primary",
512
- onClick: c,
513
- disabled: l || !a,
514
- children: [l && /* @__PURE__ */ p(f, { children: /* @__PURE__ */ p("span", {
538
+ onClick: i,
539
+ disabled: a || !r.data?.configured,
540
+ children: [a && /* @__PURE__ */ p(f, { children: /* @__PURE__ */ p("span", {
515
541
  className: "spinner-border spinner-border-sm me-2",
516
542
  "aria-hidden": !0
517
543
  }) }), "Restaurar"]
@@ -522,13 +548,13 @@ function U({ backup: e, onClose: t }) {
522
548
  })
523
549
  })] });
524
550
  }
525
- function W(e) {
551
+ function G(e) {
526
552
  return e instanceof Error ? e.message : String(e);
527
553
  }
528
554
  //#endregion
529
555
  //#region src/components/BackupsTab.tsx
530
- function G() {
531
- 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 } = C(e, 10, !0), y = O(), b = E(), x = D();
556
+ function K() {
557
+ 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 } = C(e, 10, !0), y = M(), b = A(), x = j();
532
558
  r(() => {
533
559
  if (!y.data || !y.variables) return;
534
560
  let e = URL.createObjectURL(y.data), t = document.createElement("a");
@@ -570,7 +596,7 @@ function G() {
570
596
  "aria-hidden": !0
571
597
  }),
572
598
  "Não foi possível carregar os backups: ",
573
- q(g)
599
+ J(g)
574
600
  ]
575
601
  }),
576
602
  y.isError && /* @__PURE__ */ m("div", {
@@ -581,7 +607,7 @@ function G() {
581
607
  "aria-hidden": !0
582
608
  }),
583
609
  "Falha no download: ",
584
- q(y.error)
610
+ J(y.error)
585
611
  ]
586
612
  }),
587
613
  b.isError && /* @__PURE__ */ m("div", {
@@ -592,7 +618,7 @@ function G() {
592
618
  "aria-hidden": !0
593
619
  }),
594
620
  "Falha ao excluir: ",
595
- q(b.error)
621
+ J(b.error)
596
622
  ]
597
623
  }),
598
624
  x.isError && /* @__PURE__ */ m("div", {
@@ -603,7 +629,7 @@ function G() {
603
629
  "aria-hidden": !0
604
630
  }),
605
631
  "Falha ao verificar: ",
606
- q(x.error)
632
+ J(x.error)
607
633
  ]
608
634
  }),
609
635
  Object.entries(l).map(([e, t]) => /* @__PURE__ */ m("div", {
@@ -691,12 +717,12 @@ function G() {
691
717
  "aria-hidden": !0
692
718
  }), e.filename]
693
719
  }),
694
- /* @__PURE__ */ p("td", { children: L[e.databaseType] ?? e.databaseType }),
720
+ /* @__PURE__ */ p("td", { children: V[e.databaseType] ?? e.databaseType }),
695
721
  /* @__PURE__ */ p("td", {
696
722
  className: "text-end",
697
- children: N(e.fileSize)
723
+ children: L(e.fileSize)
698
724
  }),
699
- /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(R, { status: e.status }) }),
725
+ /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p(H, { status: e.status }) }),
700
726
  /* @__PURE__ */ p("td", { children: e.sha256 ? /* @__PURE__ */ m("code", {
701
727
  title: e.sha256,
702
728
  style: { fontSize: "0.8em" },
@@ -719,7 +745,7 @@ function G() {
719
745
  className: "text-muted",
720
746
  children: "—"
721
747
  }) }),
722
- /* @__PURE__ */ p("td", { children: P(e.createdAt) }),
748
+ /* @__PURE__ */ p("td", { children: R(e.createdAt) }),
723
749
  /* @__PURE__ */ m("td", {
724
750
  className: "text-end text-nowrap",
725
751
  children: [
@@ -812,11 +838,11 @@ function G() {
812
838
  })]
813
839
  })]
814
840
  }),
815
- n && /* @__PURE__ */ p(U, {
841
+ n && /* @__PURE__ */ p(W, {
816
842
  backup: n,
817
843
  onClose: () => a(null)
818
844
  }),
819
- s && /* @__PURE__ */ p(K, {
845
+ s && /* @__PURE__ */ p(q, {
820
846
  backup: s,
821
847
  busy: b.isPending,
822
848
  onCancel: () => c(null),
@@ -826,7 +852,7 @@ function G() {
826
852
  })
827
853
  ] });
828
854
  }
829
- function K(e) {
855
+ function q(e) {
830
856
  let { backup: t, busy: n, onCancel: r, onConfirm: i } = e;
831
857
  return /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", { className: "modal-backdrop show" }), /* @__PURE__ */ p("div", {
832
858
  className: "modal show d-block",
@@ -892,16 +918,16 @@ function K(e) {
892
918
  })
893
919
  })] });
894
920
  }
895
- function q(e) {
921
+ function J(e) {
896
922
  return e instanceof Error ? e.message : String(e);
897
923
  }
898
924
  //#endregion
899
925
  //#region src/components/CreateBackupTab.tsx
900
- function J() {
901
- let e = w(), [t, n] = o(void 0), [r, i] = o(!1), [a, s] = o(!1), [c, l] = o(() => ({
926
+ function Y() {
927
+ let e = O(), t = w(), n = T(t.data?.configured), [r, a] = o(!1), [s, c] = o(() => ({
902
928
  type: "LOCAL",
903
929
  localPath: ""
904
- })), [u, d] = o(!1), [h, g] = o({
930
+ })), [l, u] = o(!1), [d, h] = o({
905
931
  format: "custom",
906
932
  includeData: !0,
907
933
  includeDropTable: !1,
@@ -909,22 +935,36 @@ function J() {
909
935
  includeIndexes: !0,
910
936
  includeConstraints: !0,
911
937
  includeRelatedTables: !1
912
- }), [_, v] = o(""), [y, b] = o(""), x = () => {
913
- if (!t) return;
914
- let n;
915
- if (u && (n = { ...h }, _.trim() && (n.tables = _.split(",").map((e) => e.trim()).filter(Boolean)), y.trim())) {
938
+ }), [g, _] = o(() => /* @__PURE__ */ new Set()), [v, y] = o(null), [b, x] = o({}), [S, C] = o(""), D = E(v, t.data?.configured), k = i(() => new Set((t.data?.exportExcludedTables ?? []).map(te)), [t.data?.exportExcludedTables]), A = i(() => {
939
+ let e = n.data ?? [], t = S.trim().toLowerCase();
940
+ return t ? e.filter((e) => e.fullName.toLowerCase().includes(t)) : e;
941
+ }, [n.data, S]), j = (e) => {
942
+ _((t) => {
943
+ let n = new Set(t);
944
+ return n.has(e) ? n.delete(e) : n.add(e), n;
945
+ });
946
+ }, M = (e, t) => {
947
+ x((n) => {
948
+ let r = n[e] ?? [], i = r.includes(t) ? r.filter((e) => e !== t) : [...r, t];
949
+ return {
950
+ ...n,
951
+ [e]: i
952
+ };
953
+ });
954
+ }, N = () => {
955
+ let t;
956
+ if (l) {
957
+ t = { ...d }, g.size > 0 && (t.tables = [...g]);
916
958
  let e = {};
917
- y.split(";").forEach((t) => {
918
- let [n, r] = t.split(":").map((e) => e.trim());
919
- n && r && (e[n] = r.split(",").map((e) => e.trim()).filter(Boolean));
920
- }), Object.keys(e).length > 0 && (n.excludeColumnsPerTable = e);
959
+ Object.entries(b).forEach(([t, n]) => {
960
+ n.length > 0 && (e[t] = n);
961
+ }), Object.keys(e).length > 0 && (t.excludeColumnsPerTable = e);
921
962
  }
922
963
  e.mutate({
923
- database: t,
924
- originStorage: a ? c : void 0,
925
- dumpOptions: n
964
+ originStorage: r ? s : void 0,
965
+ dumpOptions: t
926
966
  });
927
- }, S = e.isPending;
967
+ }, P = e.isPending, F = t.data?.configured && !P;
928
968
  return /* @__PURE__ */ m("div", { children: [
929
969
  /* @__PURE__ */ m("div", {
930
970
  className: "mb-3",
@@ -933,23 +973,98 @@ function J() {
933
973
  children: "Criar novo backup"
934
974
  }), /* @__PURE__ */ p("p", {
935
975
  className: "text-muted small mb-0",
936
- children: "Informe a conexao do banco a ser copiado. O minivault gera o dump e empacota em ZIP."
976
+ children: "O minivault usa o banco configurado no servidor (via variáveis de ambiente). Selecione tabelas e colunas a incluir/omitir no dump."
937
977
  })]
938
978
  }),
979
+ /* @__PURE__ */ p(U, {
980
+ label: "Banco de origem",
981
+ dbInfo: t.data,
982
+ isLoading: t.isLoading,
983
+ error: t.error
984
+ }),
939
985
  /* @__PURE__ */ m("div", {
940
986
  className: "card mb-3",
941
987
  children: [/* @__PURE__ */ m("div", {
942
- className: "card-header d-flex align-items-center gap-2",
943
- children: [/* @__PURE__ */ p("i", {
944
- className: "bi bi-database",
945
- "aria-hidden": !0
946
- }), "Conexao do banco de origem"]
947
- }), /* @__PURE__ */ p("div", {
948
- className: "card-body",
949
- children: /* @__PURE__ */ p(H, {
950
- onChange: n,
951
- onValidatedChange: i
952
- })
988
+ className: "card-header d-flex flex-wrap align-items-center justify-content-between gap-2",
989
+ children: [/* @__PURE__ */ m("div", {
990
+ className: "d-flex align-items-center gap-2",
991
+ children: [
992
+ /* @__PURE__ */ p("i", {
993
+ className: "bi bi-table",
994
+ "aria-hidden": !0
995
+ }),
996
+ "Tabelas do banco (",
997
+ n.data?.filter((e) => !k.has(e.fullName)).length ?? 0,
998
+ " disponíveis)"
999
+ ]
1000
+ }), /* @__PURE__ */ m("div", {
1001
+ className: "d-flex align-items-center gap-2",
1002
+ children: [/* @__PURE__ */ p("input", {
1003
+ className: "form-control form-control-sm",
1004
+ placeholder: "Filtrar tabelas...",
1005
+ value: S,
1006
+ onChange: (e) => C(e.target.value),
1007
+ style: { width: 200 }
1008
+ }), g.size > 0 && /* @__PURE__ */ m("button", {
1009
+ type: "button",
1010
+ className: "btn btn-sm btn-outline-secondary",
1011
+ onClick: () => _(/* @__PURE__ */ new Set()),
1012
+ children: [
1013
+ "Limpar seleção (",
1014
+ g.size,
1015
+ ")"
1016
+ ]
1017
+ })]
1018
+ })]
1019
+ }), /* @__PURE__ */ m("div", {
1020
+ className: "card-body p-0",
1021
+ children: [
1022
+ n.isLoading && /* @__PURE__ */ m("div", {
1023
+ className: "p-3 text-muted",
1024
+ children: [/* @__PURE__ */ p("span", {
1025
+ className: "spinner-border spinner-border-sm me-2",
1026
+ "aria-hidden": !0
1027
+ }), "Carregando tabelas..."]
1028
+ }),
1029
+ n.isError && /* @__PURE__ */ m("div", {
1030
+ className: "alert alert-danger m-3 py-2 small",
1031
+ children: [
1032
+ /* @__PURE__ */ p("i", {
1033
+ className: "bi bi-x-circle me-2",
1034
+ "aria-hidden": !0
1035
+ }),
1036
+ "Falha ao listar tabelas: ",
1037
+ G(n.error)
1038
+ ]
1039
+ }),
1040
+ A.length === 0 && !n.isLoading && /* @__PURE__ */ p("div", {
1041
+ className: "p-3 text-muted small",
1042
+ children: "Nenhuma tabela encontrada."
1043
+ }),
1044
+ /* @__PURE__ */ p("div", {
1045
+ className: "list-group list-group-flush",
1046
+ style: {
1047
+ maxHeight: 380,
1048
+ overflow: "auto"
1049
+ },
1050
+ children: A.map((e) => /* @__PURE__ */ p(ee, {
1051
+ table: e,
1052
+ disabled: k.has(e.fullName),
1053
+ selected: g.has(e.fullName),
1054
+ expanded: v === e.fullName,
1055
+ showColumnsToggle: d.format === "plain",
1056
+ excluded: b[e.fullName] ?? [],
1057
+ onToggleTable: () => j(e.fullName),
1058
+ onToggleExpand: () => y(v === e.fullName ? null : e.fullName),
1059
+ onToggleColumn: (t) => M(e.fullName, t),
1060
+ detail: v === e.fullName ? D : void 0
1061
+ }, e.fullName))
1062
+ }),
1063
+ /* @__PURE__ */ p("div", {
1064
+ className: "p-2 small text-muted border-top",
1065
+ children: "Deixe tudo desmarcado para incluir todas as tabelas (exceto as bloqueadas por segurança)."
1066
+ })
1067
+ ]
953
1068
  })]
954
1069
  }),
955
1070
  /* @__PURE__ */ m("div", {
@@ -959,15 +1074,15 @@ function J() {
959
1074
  type: "checkbox",
960
1075
  role: "switch",
961
1076
  id: "minivault-with-dump-options",
962
- checked: u,
963
- onChange: (e) => d(e.target.checked)
1077
+ checked: l,
1078
+ onChange: (e) => u(e.target.checked)
964
1079
  }), /* @__PURE__ */ p("label", {
965
1080
  className: "form-check-label",
966
1081
  htmlFor: "minivault-with-dump-options",
967
- children: "Configurar opcoes do dump (tabelas, colunas, formato)"
1082
+ children: "Configurar opcoes do dump (formato, dados, indices)"
968
1083
  })]
969
1084
  }),
970
- u && /* @__PURE__ */ m("div", {
1085
+ l && /* @__PURE__ */ m("div", {
971
1086
  className: "card mb-3",
972
1087
  children: [/* @__PURE__ */ m("div", {
973
1088
  className: "card-header d-flex align-items-center gap-2",
@@ -977,125 +1092,84 @@ function J() {
977
1092
  }), "Opcoes de dump"]
978
1093
  }), /* @__PURE__ */ m("div", {
979
1094
  className: "card-body",
980
- children: [
981
- /* @__PURE__ */ p("div", {
982
- className: "row g-3 mb-3",
1095
+ children: [/* @__PURE__ */ p("div", {
1096
+ className: "row g-3 mb-3",
1097
+ children: /* @__PURE__ */ m("div", {
1098
+ className: "col-md-4",
1099
+ children: [/* @__PURE__ */ p("label", {
1100
+ className: "form-label",
1101
+ children: "Formato"
1102
+ }), /* @__PURE__ */ m("select", {
1103
+ className: "form-select",
1104
+ value: d.format,
1105
+ onChange: (e) => h((t) => ({
1106
+ ...t,
1107
+ format: e.target.value
1108
+ })),
1109
+ children: [
1110
+ /* @__PURE__ */ p("option", {
1111
+ value: "custom",
1112
+ children: "Custom (-Fc, recomendado)"
1113
+ }),
1114
+ /* @__PURE__ */ p("option", {
1115
+ value: "plain",
1116
+ children: "Plain SQL (texto)"
1117
+ }),
1118
+ /* @__PURE__ */ p("option", {
1119
+ value: "tar",
1120
+ children: "Tar (-Ft)"
1121
+ })
1122
+ ]
1123
+ })]
1124
+ })
1125
+ }), /* @__PURE__ */ p("div", {
1126
+ className: "row g-3",
1127
+ children: [
1128
+ {
1129
+ key: "includeData",
1130
+ label: "Incluir dados"
1131
+ },
1132
+ {
1133
+ key: "includeDropTable",
1134
+ label: "Incluir DROP TABLE"
1135
+ },
1136
+ {
1137
+ key: "includeCreateTable",
1138
+ label: "Incluir CREATE TABLE"
1139
+ },
1140
+ {
1141
+ key: "includeIndexes",
1142
+ label: "Incluir indices"
1143
+ },
1144
+ {
1145
+ key: "includeConstraints",
1146
+ label: "Incluir constraints"
1147
+ },
1148
+ {
1149
+ key: "includeRelatedTables",
1150
+ label: "Incluir tabelas relacionadas"
1151
+ }
1152
+ ].map(({ key: e, label: t }) => /* @__PURE__ */ p("div", {
1153
+ className: "col-md-4",
983
1154
  children: /* @__PURE__ */ m("div", {
984
- className: "col-md-4",
985
- children: [/* @__PURE__ */ p("label", {
986
- className: "form-label",
987
- children: "Formato"
988
- }), /* @__PURE__ */ m("select", {
989
- className: "form-select",
990
- value: h.format,
991
- onChange: (e) => g((t) => ({
992
- ...t,
993
- format: e.target.value
994
- })),
995
- children: [
996
- /* @__PURE__ */ p("option", {
997
- value: "custom",
998
- children: "Custom (-Fc, recomendado)"
999
- }),
1000
- /* @__PURE__ */ p("option", {
1001
- value: "plain",
1002
- children: "Plain SQL (texto)"
1003
- }),
1004
- /* @__PURE__ */ p("option", {
1005
- value: "tar",
1006
- children: "Tar (-Ft)"
1007
- })
1008
- ]
1155
+ className: "form-check",
1156
+ children: [/* @__PURE__ */ p("input", {
1157
+ className: "form-check-input",
1158
+ type: "checkbox",
1159
+ id: `dump-opt-${e}`,
1160
+ checked: !!d[e],
1161
+ onChange: (t) => h((n) => ({
1162
+ ...n,
1163
+ [e]: t.target.checked
1164
+ }))
1165
+ }), /* @__PURE__ */ p("label", {
1166
+ className: "form-check-label",
1167
+ htmlFor: `dump-opt-${e}`,
1168
+ children: t
1009
1169
  })]
1010
1170
  })
1011
- }),
1012
- /* @__PURE__ */ m("div", {
1013
- className: "mb-3",
1014
- children: [
1015
- /* @__PURE__ */ p("label", {
1016
- className: "form-label",
1017
- children: "Tabelas (separadas por virgula)"
1018
- }),
1019
- /* @__PURE__ */ p("input", {
1020
- className: "form-control font-monospace",
1021
- value: _,
1022
- placeholder: "public.users, public.os, auth.user_groups",
1023
- onChange: (e) => v(e.target.value)
1024
- }),
1025
- /* @__PURE__ */ p("small", {
1026
- className: "text-muted",
1027
- children: "Deixe vazio para incluir todas as tabelas"
1028
- })
1029
- ]
1030
- }),
1031
- h.format === "plain" && /* @__PURE__ */ m("div", {
1032
- className: "mb-3",
1033
- children: [
1034
- /* @__PURE__ */ p("label", {
1035
- className: "form-label",
1036
- children: "Colunas a omitir (formato: tabela:col1,col2)"
1037
- }),
1038
- /* @__PURE__ */ p("input", {
1039
- className: "form-control font-monospace",
1040
- value: y,
1041
- placeholder: "public.users:password_hash,sensitive_data; public.os:internal_notes",
1042
- onChange: (e) => b(e.target.value)
1043
- }),
1044
- /* @__PURE__ */ p("small", {
1045
- className: "text-muted",
1046
- children: "Separado por ponto e virgula entre tabelas. Apenas para formato Plain SQL."
1047
- })
1048
- ]
1049
- }),
1050
- /* @__PURE__ */ p("div", {
1051
- className: "row g-3",
1052
- children: [
1053
- {
1054
- key: "includeData",
1055
- label: "Incluir dados (INSERTs)"
1056
- },
1057
- {
1058
- key: "includeDropTable",
1059
- label: "Incluir DROP TABLE"
1060
- },
1061
- {
1062
- key: "includeCreateTable",
1063
- label: "Incluir CREATE TABLE"
1064
- },
1065
- {
1066
- key: "includeIndexes",
1067
- label: "Incluir indices"
1068
- },
1069
- {
1070
- key: "includeConstraints",
1071
- label: "Incluir constraints"
1072
- },
1073
- {
1074
- key: "includeRelatedTables",
1075
- label: "Incluir tabelas relacionadas"
1076
- }
1077
- ].map(({ key: e, label: t }) => /* @__PURE__ */ p("div", {
1078
- className: "col-md-4",
1079
- children: /* @__PURE__ */ m("div", {
1080
- className: "form-check",
1081
- children: [/* @__PURE__ */ p("input", {
1082
- className: "form-check-input",
1083
- type: "checkbox",
1084
- id: `dump-opt-${e}`,
1085
- checked: !!h[e],
1086
- onChange: (t) => g((n) => ({
1087
- ...n,
1088
- [e]: t.target.checked
1089
- }))
1090
- }), /* @__PURE__ */ p("label", {
1091
- className: "form-check-label",
1092
- htmlFor: `dump-opt-${e}`,
1093
- children: t
1094
- })]
1095
- })
1096
- }, e))
1097
- })
1098
- ]
1171
+ }, e))
1172
+ })]
1099
1173
  })]
1100
1174
  }),
1101
1175
  /* @__PURE__ */ m("div", {
@@ -1105,15 +1179,15 @@ function J() {
1105
1179
  type: "checkbox",
1106
1180
  role: "switch",
1107
1181
  id: "minivault-with-origin",
1108
- checked: a,
1109
- onChange: (e) => s(e.target.checked)
1182
+ checked: r,
1183
+ onChange: (e) => a(e.target.checked)
1110
1184
  }), /* @__PURE__ */ p("label", {
1111
1185
  className: "form-check-label",
1112
1186
  htmlFor: "minivault-with-origin",
1113
1187
  children: "Incluir arquivos de origem no backup (armazenamento do sistema)"
1114
1188
  })]
1115
1189
  }),
1116
- a && /* @__PURE__ */ m("div", {
1190
+ r && /* @__PURE__ */ m("div", {
1117
1191
  className: "card mb-3",
1118
1192
  children: [/* @__PURE__ */ m("div", {
1119
1193
  className: "card-header d-flex align-items-center gap-2",
@@ -1132,8 +1206,8 @@ function J() {
1132
1206
  children: "Tipo"
1133
1207
  }), /* @__PURE__ */ m("select", {
1134
1208
  className: "form-select",
1135
- value: c.type,
1136
- onChange: (e) => l((t) => ({
1209
+ value: s.type,
1210
+ onChange: (e) => c((t) => ({
1137
1211
  ...t,
1138
1212
  type: e.target.value
1139
1213
  })),
@@ -1145,16 +1219,16 @@ function J() {
1145
1219
  children: "S3 (MinIO/S3)"
1146
1220
  })]
1147
1221
  })]
1148
- }), c.type === "LOCAL" ? /* @__PURE__ */ m("div", {
1222
+ }), s.type === "LOCAL" ? /* @__PURE__ */ m("div", {
1149
1223
  className: "col-md-8",
1150
1224
  children: [/* @__PURE__ */ p("label", {
1151
1225
  className: "form-label",
1152
1226
  children: "Caminho local"
1153
1227
  }), /* @__PURE__ */ p("input", {
1154
1228
  className: "form-control",
1155
- value: c.localPath,
1229
+ value: s.localPath,
1156
1230
  placeholder: "/dados/sistema",
1157
- onChange: (e) => l((t) => ({
1231
+ onChange: (e) => c((t) => ({
1158
1232
  ...t,
1159
1233
  localPath: e.target.value
1160
1234
  }))
@@ -1167,9 +1241,9 @@ function J() {
1167
1241
  children: "Endpoint"
1168
1242
  }), /* @__PURE__ */ p("input", {
1169
1243
  className: "form-control",
1170
- value: c.endpoint,
1244
+ value: s.endpoint,
1171
1245
  placeholder: "http://192.168.0.10:9000",
1172
- onChange: (e) => l((t) => ({
1246
+ onChange: (e) => c((t) => ({
1173
1247
  ...t,
1174
1248
  endpoint: e.target.value
1175
1249
  }))
@@ -1182,9 +1256,9 @@ function J() {
1182
1256
  children: "Bucket"
1183
1257
  }), /* @__PURE__ */ p("input", {
1184
1258
  className: "form-control",
1185
- value: c.bucketName,
1259
+ value: s.bucketName,
1186
1260
  placeholder: "storage",
1187
- onChange: (e) => l((t) => ({
1261
+ onChange: (e) => c((t) => ({
1188
1262
  ...t,
1189
1263
  bucketName: e.target.value
1190
1264
  }))
@@ -1197,8 +1271,8 @@ function J() {
1197
1271
  children: "Access key"
1198
1272
  }), /* @__PURE__ */ p("input", {
1199
1273
  className: "form-control",
1200
- value: c.accessKey,
1201
- onChange: (e) => l((t) => ({
1274
+ value: s.accessKey,
1275
+ onChange: (e) => c((t) => ({
1202
1276
  ...t,
1203
1277
  accessKey: e.target.value
1204
1278
  }))
@@ -1212,8 +1286,8 @@ function J() {
1212
1286
  }), /* @__PURE__ */ p("input", {
1213
1287
  className: "form-control",
1214
1288
  type: "password",
1215
- value: c.secretKey,
1216
- onChange: (e) => l((t) => ({
1289
+ value: s.secretKey,
1290
+ onChange: (e) => c((t) => ({
1217
1291
  ...t,
1218
1292
  secretKey: e.target.value
1219
1293
  }))
@@ -1226,9 +1300,9 @@ function J() {
1226
1300
  children: "Regiao"
1227
1301
  }), /* @__PURE__ */ p("input", {
1228
1302
  className: "form-control",
1229
- value: c.region,
1303
+ value: s.region,
1230
1304
  placeholder: "us-east-1",
1231
- onChange: (e) => l((t) => ({
1305
+ onChange: (e) => c((t) => ({
1232
1306
  ...t,
1233
1307
  region: e.target.value
1234
1308
  }))
@@ -1243,8 +1317,8 @@ function J() {
1243
1317
  type: "checkbox",
1244
1318
  role: "switch",
1245
1319
  id: "minivault-origin-pathstyle",
1246
- checked: !!c.pathStyleEnabled,
1247
- onChange: (e) => l((t) => ({
1320
+ checked: !!s.pathStyleEnabled,
1321
+ onChange: (e) => c((t) => ({
1248
1322
  ...t,
1249
1323
  pathStyleEnabled: e.target.checked
1250
1324
  }))
@@ -1267,7 +1341,7 @@ function J() {
1267
1341
  "aria-hidden": !0
1268
1342
  }),
1269
1343
  "Falha ao criar backup: ",
1270
- W(e.error)
1344
+ G(e.error)
1271
1345
  ]
1272
1346
  }),
1273
1347
  e.isSuccess && /* @__PURE__ */ m("div", {
@@ -1289,10 +1363,10 @@ function J() {
1289
1363
  children: /* @__PURE__ */ m("button", {
1290
1364
  type: "button",
1291
1365
  className: "btn btn-primary",
1292
- onClick: x,
1293
- disabled: S || !r,
1366
+ onClick: N,
1367
+ disabled: !F,
1294
1368
  children: [
1295
- S && /* @__PURE__ */ p("span", {
1369
+ P && /* @__PURE__ */ p("span", {
1296
1370
  className: "spinner-border spinner-border-sm me-2",
1297
1371
  "aria-hidden": !0
1298
1372
  }),
@@ -1306,9 +1380,113 @@ function J() {
1306
1380
  })
1307
1381
  ] });
1308
1382
  }
1383
+ function ee({ table: e, disabled: t, selected: n, expanded: r, showColumnsToggle: i, excluded: a, detail: o, onToggleTable: s, onToggleExpand: c, onToggleColumn: l }) {
1384
+ return /* @__PURE__ */ m("div", {
1385
+ className: "list-group-item px-3 py-2",
1386
+ children: [/* @__PURE__ */ m("div", {
1387
+ className: "d-flex align-items-center gap-2",
1388
+ children: [
1389
+ /* @__PURE__ */ p("input", {
1390
+ className: "form-check-input",
1391
+ type: "checkbox",
1392
+ checked: n,
1393
+ disabled: t,
1394
+ title: t ? "Bloqueada por segurança (MINIVAULT_EXPORT_EXCLUDED_TABLES)" : void 0,
1395
+ onChange: s
1396
+ }),
1397
+ /* @__PURE__ */ m("span", {
1398
+ className: "font-monospace small",
1399
+ children: [e.fullName, e.type === "VIEW" && /* @__PURE__ */ p("span", {
1400
+ className: "badge text-bg-light ms-1",
1401
+ children: "view"
1402
+ })]
1403
+ }),
1404
+ t && /* @__PURE__ */ m("span", {
1405
+ className: "badge text-bg-secondary ms-auto",
1406
+ title: "Exportação sempre ignora esta tabela",
1407
+ children: [/* @__PURE__ */ p("i", {
1408
+ className: "bi bi-shield-lock me-1",
1409
+ "aria-hidden": !0
1410
+ }), "excluída"]
1411
+ }),
1412
+ !t && /* @__PURE__ */ m("button", {
1413
+ type: "button",
1414
+ className: "btn btn-sm btn-outline-secondary ms-auto",
1415
+ onClick: c,
1416
+ "aria-expanded": r,
1417
+ children: [/* @__PURE__ */ p("i", {
1418
+ className: `bi ${r ? "bi-chevron-up" : "bi-chevron-down"} me-1`,
1419
+ "aria-hidden": !0
1420
+ }), r ? "Ocultar" : "Colunas"]
1421
+ })
1422
+ ]
1423
+ }), r && /* @__PURE__ */ m("div", {
1424
+ className: "mt-2 ps-3",
1425
+ children: [
1426
+ o?.isLoading && /* @__PURE__ */ p("small", {
1427
+ className: "text-muted",
1428
+ children: "Carregando colunas..."
1429
+ }),
1430
+ o?.isError && /* @__PURE__ */ m("small", {
1431
+ className: "text-danger",
1432
+ children: ["Erro: ", G(o.error)]
1433
+ }),
1434
+ o?.data && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ m("table", {
1435
+ className: "table table-sm small mb-2",
1436
+ children: [/* @__PURE__ */ p("thead", { children: /* @__PURE__ */ m("tr", { children: [
1437
+ i && /* @__PURE__ */ p("th", { style: { width: 30 } }),
1438
+ /* @__PURE__ */ p("th", { children: "Coluna" }),
1439
+ /* @__PURE__ */ p("th", { children: "Tipo" }),
1440
+ /* @__PURE__ */ p("th", { children: "Null" })
1441
+ ] }) }), /* @__PURE__ */ p("tbody", { children: o.data.columns.map((e) => /* @__PURE__ */ m("tr", { children: [
1442
+ i && /* @__PURE__ */ p("td", { children: /* @__PURE__ */ p("input", {
1443
+ className: "form-check-input",
1444
+ type: "checkbox",
1445
+ title: "Omitir esta coluna na exportação",
1446
+ checked: a.includes(e.name),
1447
+ onChange: () => l(e.name)
1448
+ }) }),
1449
+ /* @__PURE__ */ m("td", { children: [
1450
+ /* @__PURE__ */ p("span", {
1451
+ className: "font-monospace",
1452
+ children: e.name
1453
+ }),
1454
+ e.primaryKey && /* @__PURE__ */ p("span", {
1455
+ className: "badge text-bg-warning ms-1",
1456
+ children: "PK"
1457
+ }),
1458
+ e.generated && /* @__PURE__ */ p("span", {
1459
+ className: "badge text-bg-info ms-1",
1460
+ children: "auto"
1461
+ })
1462
+ ] }),
1463
+ /* @__PURE__ */ p("td", {
1464
+ className: "text-body-secondary",
1465
+ children: e.dataType
1466
+ }),
1467
+ /* @__PURE__ */ p("td", { children: e.nullable ? "sim" : "não" })
1468
+ ] }, e.name)) })]
1469
+ }), o.data.relationships.length > 0 && /* @__PURE__ */ m("div", {
1470
+ className: "small text-body-secondary",
1471
+ children: [/* @__PURE__ */ p("i", {
1472
+ className: "bi bi-diagram-3 me-1",
1473
+ "aria-hidden": !0
1474
+ }), o.data.relationships.map((e) => /* @__PURE__ */ p("div", {
1475
+ className: "ms-4 font-monospace",
1476
+ children: e.summary
1477
+ }, `${e.constraintName}-${e.fromTable}-${e.toTable}`))]
1478
+ })] })
1479
+ ]
1480
+ })]
1481
+ });
1482
+ }
1483
+ function te(e) {
1484
+ let t = e.trim();
1485
+ return t.includes(".") ? t : `public.${t}`;
1486
+ }
1309
1487
  //#endregion
1310
1488
  //#region src/components/StorageExplorerTab.tsx
1311
- function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1489
+ function X({ storageType: e = "LOCAL", storageConfig: n }) {
1312
1490
  let i = b(), a = d(), [s, c] = o(""), [h, g] = o([]), [_, v] = o(/* @__PURE__ */ new Set()), [y, x] = o(null), S = n?.type ?? e, { data: C, isLoading: w } = u({
1313
1491
  queryKey: [
1314
1492
  "storage-files",
@@ -1345,7 +1523,7 @@ function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1345
1523
  } catch {}
1346
1524
  }, j = async () => {
1347
1525
  for (let e of _) await A(e);
1348
- }, M = (e) => e ? P(e) : "-";
1526
+ }, M = (e) => e ? R(e) : "-";
1349
1527
  return /* @__PURE__ */ m("div", {
1350
1528
  className: "space-y-3",
1351
1529
  children: [
@@ -1475,7 +1653,7 @@ function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1475
1653
  }) }),
1476
1654
  /* @__PURE__ */ p("td", {
1477
1655
  className: "text-muted small",
1478
- children: e.directory ? "-" : N(e.size)
1656
+ children: e.directory ? "-" : L(e.size)
1479
1657
  }),
1480
1658
  /* @__PURE__ */ p("td", {
1481
1659
  className: "text-muted small",
@@ -1558,17 +1736,13 @@ function Y({ storageType: e = "LOCAL", storageConfig: n }) {
1558
1736
  }
1559
1737
  //#endregion
1560
1738
  //#region src/components/ImportDumpTab.tsx
1561
- function X() {
1562
- let e = k(), t = A(), n = a(null), [r, i] = o("upload"), [s, c] = o(null), [l, u] = o(void 0), [d, f] = o(!1), [h, g] = o(""), [_, v] = o(!1), y = () => {
1563
- l && (r === "upload" && s ? e.mutate({
1564
- file: s,
1565
- database: l
1566
- }) : r === "storage" && h && t.mutate({
1739
+ function Z() {
1740
+ let e = N(), t = P(), n = w(), r = a(null), [i, s] = o("upload"), [c, l] = o(null), [u, d] = o(""), [f, h] = o(!1), g = () => {
1741
+ i === "upload" && c ? e.mutate({ file: c }) : i === "storage" && u && t.mutate({
1567
1742
  storageType: "LOCAL",
1568
- storagePath: h,
1569
- database: l
1570
- }));
1571
- }, b = e.isPending || t.isPending, x = e.data ?? t.data, S = e.error ?? t.error;
1743
+ storagePath: u
1744
+ });
1745
+ }, _ = e.isPending || t.isPending, v = e.data ?? t.data, y = e.error ?? t.error;
1572
1746
  return /* @__PURE__ */ m("div", { children: [
1573
1747
  /* @__PURE__ */ m("div", {
1574
1748
  className: "mb-3",
@@ -1589,8 +1763,8 @@ function X() {
1589
1763
  className: "btn-check",
1590
1764
  name: "importMode",
1591
1765
  id: "importModeUpload",
1592
- checked: r === "upload",
1593
- onChange: () => i("upload")
1766
+ checked: i === "upload",
1767
+ onChange: () => s("upload")
1594
1768
  }),
1595
1769
  /* @__PURE__ */ m("label", {
1596
1770
  className: "btn btn-outline-primary",
@@ -1602,8 +1776,8 @@ function X() {
1602
1776
  className: "btn-check",
1603
1777
  name: "importMode",
1604
1778
  id: "importModeStorage",
1605
- checked: r === "storage",
1606
- onChange: () => i("storage")
1779
+ checked: i === "storage",
1780
+ onChange: () => s("storage")
1607
1781
  }),
1608
1782
  /* @__PURE__ */ m("label", {
1609
1783
  className: "btn btn-outline-primary",
@@ -1612,7 +1786,7 @@ function X() {
1612
1786
  })
1613
1787
  ]
1614
1788
  }),
1615
- r === "upload" && /* @__PURE__ */ m("div", {
1789
+ i === "upload" && /* @__PURE__ */ m("div", {
1616
1790
  className: "card mb-3",
1617
1791
  children: [/* @__PURE__ */ m("div", {
1618
1792
  className: "card-header d-flex align-items-center gap-2",
@@ -1623,23 +1797,23 @@ function X() {
1623
1797
  }), /* @__PURE__ */ m("div", {
1624
1798
  className: "card-body",
1625
1799
  children: [/* @__PURE__ */ p("input", {
1626
- ref: n,
1800
+ ref: r,
1627
1801
  type: "file",
1628
1802
  accept: ".sql,.txt,text/plain,application/sql,.Fc,.dump,application/octet-stream",
1629
1803
  className: "form-control",
1630
- onChange: (e) => c(e.target.files?.[0] ?? null)
1631
- }), s && /* @__PURE__ */ m("small", {
1804
+ onChange: (e) => l(e.target.files?.[0] ?? null)
1805
+ }), c && /* @__PURE__ */ m("small", {
1632
1806
  className: "text-muted",
1633
1807
  children: [
1634
- s.name,
1808
+ c.name,
1635
1809
  " · ",
1636
- (s.size / 1024 / 1024).toFixed(2),
1810
+ (c.size / 1024 / 1024).toFixed(2),
1637
1811
  " MB"
1638
1812
  ]
1639
1813
  })]
1640
1814
  })]
1641
1815
  }),
1642
- r === "storage" && /* @__PURE__ */ m("div", {
1816
+ i === "storage" && /* @__PURE__ */ m("div", {
1643
1817
  className: "card mb-3",
1644
1818
  children: [/* @__PURE__ */ m("div", {
1645
1819
  className: "card-header d-flex align-items-center justify-content-between",
@@ -1652,8 +1826,8 @@ function X() {
1652
1826
  }), /* @__PURE__ */ m("button", {
1653
1827
  className: "btn btn-sm btn-outline-secondary",
1654
1828
  type: "button",
1655
- onClick: () => v(!_),
1656
- children: [/* @__PURE__ */ p("i", { className: "bi bi-search me-1" }), _ ? "Fechar" : "Explorar"]
1829
+ onClick: () => h(!f),
1830
+ children: [/* @__PURE__ */ p("i", { className: "bi bi-search me-1" }), f ? "Fechar" : "Explorar"]
1657
1831
  })]
1658
1832
  }), /* @__PURE__ */ m("div", {
1659
1833
  className: "card-body",
@@ -1666,9 +1840,9 @@ function X() {
1666
1840
  }),
1667
1841
  /* @__PURE__ */ p("input", {
1668
1842
  className: "form-control font-monospace",
1669
- value: h,
1843
+ value: u,
1670
1844
  placeholder: "backups/backup_postgresql_20240101_120000.zip",
1671
- onChange: (e) => g(e.target.value)
1845
+ onChange: (e) => d(e.target.value)
1672
1846
  }),
1673
1847
  /* @__PURE__ */ m("small", {
1674
1848
  className: "text-muted",
@@ -1679,13 +1853,13 @@ function X() {
1679
1853
  ]
1680
1854
  })
1681
1855
  ]
1682
- }), _ && /* @__PURE__ */ p("div", {
1856
+ }), f && /* @__PURE__ */ p("div", {
1683
1857
  className: "border rounded p-2",
1684
1858
  style: {
1685
1859
  maxHeight: 350,
1686
1860
  overflow: "auto"
1687
1861
  },
1688
- children: /* @__PURE__ */ p(Y, {
1862
+ children: /* @__PURE__ */ p(X, {
1689
1863
  storageType: "LOCAL",
1690
1864
  storageConfig: {
1691
1865
  type: "LOCAL",
@@ -1703,15 +1877,20 @@ function X() {
1703
1877
  className: "bi bi-database",
1704
1878
  "aria-hidden": !0
1705
1879
  }), "Banco de destino"]
1706
- }), /* @__PURE__ */ p("div", {
1880
+ }), /* @__PURE__ */ m("div", {
1707
1881
  className: "card-body",
1708
- children: /* @__PURE__ */ p(H, {
1709
- onChange: u,
1710
- onValidatedChange: f
1711
- })
1882
+ children: [/* @__PURE__ */ p("p", {
1883
+ className: "small text-body-secondary mb-3",
1884
+ children: "O dump será aplicado no banco configurado no servidor. Tabelas bloqueadas por segurança são ignoradas automaticamente na importação."
1885
+ }), /* @__PURE__ */ p(U, {
1886
+ label: "Banco de destino",
1887
+ dbInfo: n.data,
1888
+ isLoading: n.isLoading,
1889
+ error: n.error
1890
+ })]
1712
1891
  })]
1713
1892
  }),
1714
- S && /* @__PURE__ */ m("div", {
1893
+ y && /* @__PURE__ */ m("div", {
1715
1894
  className: "alert alert-danger",
1716
1895
  children: [
1717
1896
  /* @__PURE__ */ p("i", {
@@ -1719,21 +1898,21 @@ function X() {
1719
1898
  "aria-hidden": !0
1720
1899
  }),
1721
1900
  "Falha na importacao: ",
1722
- W(S)
1901
+ G(y)
1723
1902
  ]
1724
1903
  }),
1725
- x && /* @__PURE__ */ m("div", {
1726
- className: `alert ${x.success ? "alert-success" : "alert-danger"}`,
1904
+ v && /* @__PURE__ */ m("div", {
1905
+ className: `alert ${v.success ? "alert-success" : "alert-danger"}`,
1727
1906
  children: [
1728
1907
  /* @__PURE__ */ p("i", {
1729
- className: `bi ${x.success ? "bi-check-circle" : "bi-x-circle"} me-2`,
1908
+ className: `bi ${v.success ? "bi-check-circle" : "bi-x-circle"} me-2`,
1730
1909
  "aria-hidden": !0
1731
1910
  }),
1732
- x.message,
1733
- x.log && /* @__PURE__ */ p("pre", {
1911
+ v.message,
1912
+ v.log && /* @__PURE__ */ p("pre", {
1734
1913
  className: "mt-3 mb-0 p-2 bg-body-tertiary rounded small overflow-auto",
1735
1914
  style: { maxHeight: 260 },
1736
- children: x.log
1915
+ children: v.log
1737
1916
  })
1738
1917
  ]
1739
1918
  }),
@@ -1742,10 +1921,10 @@ function X() {
1742
1921
  children: /* @__PURE__ */ m("button", {
1743
1922
  type: "button",
1744
1923
  className: "btn btn-primary",
1745
- onClick: y,
1746
- disabled: b || !d || (r === "upload" ? !s : !h),
1924
+ onClick: g,
1925
+ disabled: _ || !n.data?.configured || (i === "upload" ? !c : !u),
1747
1926
  children: [
1748
- b && /* @__PURE__ */ p("span", {
1927
+ _ && /* @__PURE__ */ p("span", {
1749
1928
  className: "spinner-border spinner-border-sm me-2",
1750
1929
  "aria-hidden": !0
1751
1930
  }),
@@ -1761,13 +1940,13 @@ function X() {
1761
1940
  }
1762
1941
  //#endregion
1763
1942
  //#region src/hooks/useAutoTheme.ts
1764
- function Z() {
1943
+ function Q() {
1765
1944
  return typeof document < "u" && document.documentElement.classList.contains("dark");
1766
1945
  }
1767
- function Q(e) {
1768
- let [t, n] = o(Z), [i, a] = o(() => typeof window < "u" && window.matchMedia?.("(prefers-color-scheme: dark)")?.matches === !0);
1946
+ function ne(e) {
1947
+ let [t, n] = o(Q), [i, a] = o(() => typeof window < "u" && window.matchMedia?.("(prefers-color-scheme: dark)")?.matches === !0);
1769
1948
  return r(() => {
1770
- let e = document.documentElement, t = new MutationObserver(() => n(Z()));
1949
+ let e = document.documentElement, t = new MutationObserver(() => n(Q()));
1771
1950
  return t.observe(e, {
1772
1951
  attributes: !0,
1773
1952
  attributeFilter: ["class"]
@@ -1780,8 +1959,8 @@ function Q(e) {
1780
1959
  }
1781
1960
  //#endregion
1782
1961
  //#region src/components/MinivaultModule.tsx
1783
- function $(e) {
1784
- let { companyAcronym: t = "Minivault", theme: n, refetchIntervalMs: r = 15e3, storageType: i = "LOCAL", ...a } = e, l = Q(n), [u] = o(() => new s({ defaultOptions: { queries: {
1962
+ function re(e) {
1963
+ let { companyAcronym: t = "Minivault", theme: n, refetchIntervalMs: r = 15e3, storageType: i = "LOCAL", ...a } = e, l = ne(n), [u] = o(() => new s({ defaultOptions: { queries: {
1785
1964
  refetchInterval: r,
1786
1965
  retry: 1
1787
1966
  } } }));
@@ -1792,15 +1971,15 @@ function $(e) {
1792
1971
  children: /* @__PURE__ */ m("div", {
1793
1972
  className: "minivault-module h-full w-full overflow-auto",
1794
1973
  "data-minivault-theme": l,
1795
- children: [/* @__PURE__ */ p(ee, {
1974
+ children: [/* @__PURE__ */ p(ie, {
1796
1975
  companyAcronym: t,
1797
1976
  theme: l
1798
- }), /* @__PURE__ */ p(te, { storageType: i })]
1977
+ }), /* @__PURE__ */ p(ae, { storageType: i })]
1799
1978
  })
1800
1979
  })
1801
1980
  });
1802
1981
  }
1803
- function ee({ companyAcronym: e, theme: t }) {
1982
+ function ie({ companyAcronym: e, theme: t }) {
1804
1983
  return /* @__PURE__ */ m("div", {
1805
1984
  className: "d-flex align-items-center justify-content-between flex-wrap gap-2 px-3 py-2 border-bottom",
1806
1985
  style: {
@@ -1829,7 +2008,7 @@ function ee({ companyAcronym: e, theme: t }) {
1829
2008
  })]
1830
2009
  });
1831
2010
  }
1832
- function te({ storageType: e }) {
2011
+ function ae({ storageType: e }) {
1833
2012
  let [t, n] = o("backups");
1834
2013
  return /* @__PURE__ */ m("div", {
1835
2014
  className: "p-3",
@@ -1887,12 +2066,136 @@ function te({ storageType: e }) {
1887
2066
  })
1888
2067
  ]
1889
2068
  }),
1890
- t === "backups" && /* @__PURE__ */ p(G, {}),
1891
- t === "create" && /* @__PURE__ */ p(J, {}),
1892
- t === "import" && /* @__PURE__ */ p(X, {}),
1893
- t === "storage" && /* @__PURE__ */ p(Y, { storageType: e })
2069
+ t === "backups" && /* @__PURE__ */ p(K, {}),
2070
+ t === "create" && /* @__PURE__ */ p(Y, {}),
2071
+ t === "import" && /* @__PURE__ */ p(Z, {}),
2072
+ t === "storage" && /* @__PURE__ */ p(X, { storageType: e })
2073
+ ]
2074
+ });
2075
+ }
2076
+ //#endregion
2077
+ //#region src/components/CredentialsFields.tsx
2078
+ var oe = [
2079
+ "postgresql",
2080
+ "mysql",
2081
+ "sqlserver"
2082
+ ];
2083
+ function se() {
2084
+ return {
2085
+ host: "localhost",
2086
+ port: 5432,
2087
+ databaseName: "",
2088
+ username: "",
2089
+ password: "",
2090
+ databaseType: "postgresql"
2091
+ };
2092
+ }
2093
+ function $(e) {
2094
+ return e === "postgresql" || e === "postgres" ? 5432 : e === "mysql" ? 3306 : 1433;
2095
+ }
2096
+ function ce({ value: e, onChange: t, onValidatedChange: n }) {
2097
+ let r = {
2098
+ ...se(),
2099
+ ...e
2100
+ }, i = (e) => {
2101
+ let n = {
2102
+ ...r,
2103
+ databaseType: e
2104
+ };
2105
+ (r.port === $(r.databaseType) || !r.port) && (n.port = $(e)), t(n);
2106
+ }, a = (e) => {
2107
+ let i = {
2108
+ ...r,
2109
+ ...e
2110
+ };
2111
+ t(i);
2112
+ let a = !!(i.host.trim() && i.port > 0 && i.databaseName.trim() && i.username.trim() && i.password.length > 0);
2113
+ n?.(a);
2114
+ };
2115
+ return /* @__PURE__ */ m("div", {
2116
+ className: "row g-3",
2117
+ children: [
2118
+ /* @__PURE__ */ m("div", {
2119
+ className: "col-md-6",
2120
+ children: [/* @__PURE__ */ p("label", {
2121
+ className: "form-label",
2122
+ children: "Tipo de banco"
2123
+ }), /* @__PURE__ */ p("select", {
2124
+ className: "form-select",
2125
+ value: r.databaseType,
2126
+ onChange: (e) => i(e.target.value),
2127
+ children: oe.map((e) => /* @__PURE__ */ p("option", {
2128
+ value: e,
2129
+ children: V[e] ?? e
2130
+ }, e))
2131
+ })]
2132
+ }),
2133
+ /* @__PURE__ */ m("div", {
2134
+ className: "col-md-6",
2135
+ children: [/* @__PURE__ */ p("label", {
2136
+ className: "form-label",
2137
+ children: "Host"
2138
+ }), /* @__PURE__ */ p("input", {
2139
+ className: "form-control",
2140
+ value: r.host,
2141
+ placeholder: "localhost",
2142
+ onChange: (e) => a({ host: e.target.value })
2143
+ })]
2144
+ }),
2145
+ /* @__PURE__ */ m("div", {
2146
+ className: "col-md-4",
2147
+ children: [/* @__PURE__ */ p("label", {
2148
+ className: "form-label",
2149
+ children: "Porta"
2150
+ }), /* @__PURE__ */ p("input", {
2151
+ className: "form-control",
2152
+ type: "number",
2153
+ min: 1,
2154
+ max: 65535,
2155
+ value: r.port,
2156
+ onChange: (e) => a({ port: Number(e.target.value) })
2157
+ })]
2158
+ }),
2159
+ /* @__PURE__ */ m("div", {
2160
+ className: "col-md-8",
2161
+ children: [/* @__PURE__ */ p("label", {
2162
+ className: "form-label",
2163
+ children: "Nome do banco"
2164
+ }), /* @__PURE__ */ p("input", {
2165
+ className: "form-control",
2166
+ value: r.databaseName,
2167
+ placeholder: "sigamais",
2168
+ onChange: (e) => a({ databaseName: e.target.value })
2169
+ })]
2170
+ }),
2171
+ /* @__PURE__ */ m("div", {
2172
+ className: "col-md-6",
2173
+ children: [/* @__PURE__ */ p("label", {
2174
+ className: "form-label",
2175
+ children: "Usuário"
2176
+ }), /* @__PURE__ */ p("input", {
2177
+ className: "form-control",
2178
+ value: r.username,
2179
+ placeholder: "postgres",
2180
+ autoComplete: "off",
2181
+ onChange: (e) => a({ username: e.target.value })
2182
+ })]
2183
+ }),
2184
+ /* @__PURE__ */ m("div", {
2185
+ className: "col-md-6",
2186
+ children: [/* @__PURE__ */ p("label", {
2187
+ className: "form-label",
2188
+ children: "Senha"
2189
+ }), /* @__PURE__ */ p("input", {
2190
+ className: "form-control",
2191
+ type: "password",
2192
+ value: r.password,
2193
+ autoComplete: "new-password",
2194
+ onChange: (e) => a({ password: e.target.value })
2195
+ })]
2196
+ })
1894
2197
  ]
1895
2198
  });
1896
2199
  }
1897
2200
  //#endregion
1898
- export { G as BackupsTab, J as CreateBackupTab, H as CredentialsFields, L as DATABASE_TYPE_LABELS, X as ImportDumpTab, g as MinivaultApi, h as MinivaultApiError, y as MinivaultApiProvider, $ as MinivaultModule, U as RestoreModal, I as STATUS_BADGE, F as STATUS_LABELS, R as StatusBadge, Y as StorageExplorerTab, P as formatDate, N as formatFileSize, C as useBackups, w as useCreateBackup, E as useDeleteBackup, O as useDownloadBackup, k as useImportDump, A as useImportFromStorage, b as useMinivaultApi, T as useRestoreBackup };
2201
+ export { K as BackupsTab, Y as CreateBackupTab, ce as CredentialsFields, V as DATABASE_TYPE_LABELS, U as DatabaseBanner, Z as ImportDumpTab, g as MinivaultApi, h as MinivaultApiError, y as MinivaultApiProvider, re as MinivaultModule, W as RestoreModal, B as STATUS_BADGE, z as STATUS_LABELS, H as StatusBadge, X as StorageExplorerTab, R as formatDate, L as formatFileSize, C as useBackups, O as useCreateBackup, w as useDbInfo, D as useDbRelationships, E as useDbTableDetail, T as useDbTables, A as useDeleteBackup, M as useDownloadBackup, N as useImportDump, P as useImportFromStorage, b as useMinivaultApi, k as useRestoreBackup };