admindb 1.1.0 → 1.2.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.
@@ -803,7 +803,14 @@
803
803
  pop.style.visibility = 'visible';
804
804
  refOpenBtn = btn;
805
805
 
806
- const onViewChange = () => closeRefPop();
806
+ // Close when the page behind the popover scrolls or the window resizes,
807
+ // but NOT when the nested table's own scroll container is scrolled — the
808
+ // capture-phase listener fires for every scroll target, including the
809
+ // mini-table inside the popover, which would otherwise close it instantly.
810
+ const onViewChange = (e) => {
811
+ if (e && e.target && pop.contains(e.target)) return;
812
+ closeRefPop();
813
+ };
807
814
  window.addEventListener('scroll', onViewChange, true);
808
815
  window.addEventListener('resize', onViewChange);
809
816
  const onClickOutside = (e) => {
@@ -1,4 +1,5 @@
1
- /* Databases landing page: create and delete SQLite database files. */
1
+ /* Databases landing page: create/delete database files, and a filesystem
2
+ * browser for opening existing SQLite files. */
2
3
  (function () {
3
4
  'use strict';
4
5
  const nameInput = document.getElementById('new-db-name');
@@ -8,6 +9,18 @@
8
9
  return (window.UI && UI.escapeHtml) ? UI.escapeHtml(s) : String(s == null ? '' : s);
9
10
  }
10
11
 
12
+ function fmtSize(n) {
13
+ if (!Number.isFinite(n) || n <= 0) return '0 B';
14
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
15
+ let v = n;
16
+ let u = 0;
17
+ while (v >= 1024 && u < units.length - 1) {
18
+ v /= 1024;
19
+ u += 1;
20
+ }
21
+ return (u === 0 ? Math.round(v) : v.toFixed(1)) + ' ' + units[u];
22
+ }
23
+
11
24
  async function createDb() {
12
25
  const name = (nameInput.value || '').trim();
13
26
  if (!name) return UI.showError('Enter a database name.');
@@ -42,4 +55,89 @@
42
55
  .catch((e) => UI.showError(e.message));
43
56
  });
44
57
  });
58
+
59
+ // ---- Filesystem browser --------------------------------------------------
60
+
61
+ const fsPathInput = document.getElementById('fs-path');
62
+ const fsGoBtn = document.getElementById('fs-go');
63
+ const fsUpBtn = document.getElementById('fs-up');
64
+ const fsCurrent = document.getElementById('fs-current');
65
+ const fsListing = document.getElementById('fs-listing');
66
+
67
+ const FOLDER_ICON =
68
+ '<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 7a2 2 0 012-2h4l2 2h8a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2V7z" /></svg>';
69
+ const DB_ICON =
70
+ '<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 7v10c0 1.1.9 2 2 2h12a2 2 0 002-2V7M4 7c0-1.1.9-2 2-2h12a2 2 0 012 2M4 7c0 1.1.9 2 2 2h12a2 2 0 002-2" /></svg>';
71
+
72
+ let fsState = { path: '', parent: null };
73
+
74
+ function renderFs(data) {
75
+ fsState = { path: data.path, parent: data.parent };
76
+ if (fsCurrent) fsCurrent.textContent = data.path;
77
+ if (fsPathInput) fsPathInput.value = data.path;
78
+ if (fsUpBtn) fsUpBtn.disabled = !data.parent;
79
+ if (!fsListing) return;
80
+ fsListing.innerHTML = '';
81
+ if (!data.entries.length) {
82
+ fsListing.innerHTML = '<div class="px-4 py-6 text-center text-sm text-base-content/40">No folders or database files here.</div>';
83
+ return;
84
+ }
85
+ data.entries.forEach((e) => {
86
+ const row = document.createElement('button');
87
+ row.type = 'button';
88
+ row.className = 'flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm transition hover:bg-primary/[0.06]';
89
+ row.title = e.path;
90
+ if (e.isDir) {
91
+ row.innerHTML =
92
+ '<span class="grid h-6 w-6 shrink-0 place-items-center rounded-md bg-base-200 text-base-content/50">' + FOLDER_ICON + '</span>' +
93
+ '<span class="min-w-0 flex-1 truncate font-medium text-base-content/80">' + escapeHtml(e.name) + '</span>' +
94
+ '<span class="text-xs text-base-content/35">folder</span>';
95
+ row.addEventListener('click', () => loadFs(e.path));
96
+ } else {
97
+ row.innerHTML =
98
+ '<span class="grid h-6 w-6 shrink-0 place-items-center rounded-md bg-primary/10 text-primary">' + DB_ICON + '</span>' +
99
+ '<span class="min-w-0 flex-1 truncate font-mono text-[13px] text-base-content/85">' + escapeHtml(e.name) + '</span>' +
100
+ '<span class="text-xs text-base-content/40">' + fmtSize(e.size) + '</span>';
101
+ row.addEventListener('click', () => openDb(e.path));
102
+ }
103
+ fsListing.appendChild(row);
104
+ });
105
+ }
106
+
107
+ async function loadFs(p) {
108
+ try {
109
+ const data = await Api.get('/api/fs/list' + (p ? '?path=' + encodeURIComponent(p) : ''));
110
+ renderFs(data);
111
+ } catch (e) {
112
+ UI.showError(e.message);
113
+ }
114
+ }
115
+
116
+ function goUp() {
117
+ if (fsState.parent) loadFs(fsState.parent);
118
+ }
119
+
120
+ async function openDb(p) {
121
+ try {
122
+ const data = await Api.post('/api/databases/open', { path: p });
123
+ UI.showToast(data.message || 'Database opened.', 'success');
124
+ window.location.href = Api.basePath + '/' + encodeURIComponent(data.id);
125
+ } catch (e) {
126
+ UI.showError(e.message);
127
+ }
128
+ }
129
+
130
+ if (fsListing) {
131
+ loadFs('');
132
+ if (fsGoBtn) {
133
+ fsGoBtn.addEventListener('click', () => loadFs((fsPathInput.value || '').trim() || ''));
134
+ }
135
+ if (fsPathInput) {
136
+ fsPathInput.addEventListener('keydown', (e) => {
137
+ if (e.key === 'Enter') loadFs((fsPathInput.value || '').trim() || '');
138
+ });
139
+ }
140
+ if (fsUpBtn) fsUpBtn.addEventListener('click', goUp);
141
+ }
45
142
  })();
143
+
@@ -7,6 +7,16 @@ interface DatabasesContext {
7
7
  basePath: string;
8
8
  /** Read-only mode: database create/delete are disabled. */
9
9
  readonly?: boolean;
10
+ /**
11
+ * Show the filesystem file-browser (default `true`). When `false` — e.g. the
12
+ * server was started with specific database files — browsing is disabled.
13
+ */
14
+ allowBrowse?: boolean;
15
+ /**
16
+ * Restrict the file-browser to this folder (absolute). When set, the browser
17
+ * cannot navigate above it and only databases inside it can be opened.
18
+ */
19
+ browseRoot?: string;
10
20
  /** Called before a database is deleted so cached per-db apps are dropped. */
11
21
  invalidate?: (id: string) => void;
12
22
  }
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.registerDatabasesRoutes = registerDatabasesRoutes;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
4
9
  const util_1 = require("../util");
5
10
  function formatBytes(n) {
6
11
  if (!Number.isFinite(n) || n <= 0)
@@ -26,6 +31,8 @@ function formatDate(iso) {
26
31
  }
27
32
  function registerDatabasesRoutes(router, ctx) {
28
33
  const { manager } = ctx;
34
+ const allowBrowse = ctx.allowBrowse ?? true;
35
+ const browseRoot = ctx.browseRoot ? node_path_1.default.resolve(ctx.browseRoot) : undefined;
29
36
  const wrap = (fn) => async (req, res) => {
30
37
  try {
31
38
  await fn(req, res);
@@ -49,6 +56,8 @@ function registerDatabasesRoutes(router, ctx) {
49
56
  databases,
50
57
  dbDir: manager.directory,
51
58
  readonly: !!ctx.readonly,
59
+ allowBrowse,
60
+ browseRoot,
52
61
  config: { basePath: ctx.basePath },
53
62
  });
54
63
  }
@@ -66,6 +75,94 @@ function registerDatabasesRoutes(router, ctx) {
66
75
  })));
67
76
  res.json({ success: true, data });
68
77
  }));
78
+ function listDirectory(abs) {
79
+ const entries = [];
80
+ for (const name of (0, node_fs_1.readdirSync)(abs)) {
81
+ if (name.startsWith('.'))
82
+ continue;
83
+ const full = node_path_1.default.join(abs, name);
84
+ let isDir = false;
85
+ let size = 0;
86
+ try {
87
+ const st = (0, node_fs_1.statSync)(full);
88
+ isDir = st.isDirectory();
89
+ size = isDir ? 0 : st.size;
90
+ }
91
+ catch {
92
+ continue; // unreadable entries are skipped
93
+ }
94
+ if (!isDir && !manager.isDbFile(name))
95
+ continue;
96
+ entries.push({ name, path: full, isDir, isDb: !isDir, size });
97
+ }
98
+ entries.sort((a, b) => a.isDir === b.isDir
99
+ ? a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })
100
+ : a.isDir
101
+ ? -1
102
+ : 1);
103
+ return entries;
104
+ }
105
+ // List subfolders and SQLite database files under a path.
106
+ router.get('/api/fs/list', wrap(async (req, res) => {
107
+ if (!allowBrowse) {
108
+ return res
109
+ .status(403)
110
+ .json({ success: false, error: 'File browsing is disabled — this server was started with specific database files.' });
111
+ }
112
+ const raw = String(req.query.path ?? '').trim();
113
+ const base = raw ? node_path_1.default.resolve(raw) : manager.directory;
114
+ if (browseRoot && !(0, util_1.isPathWithinRoot)(browseRoot, base)) {
115
+ return res.status(403).json({ success: false, error: `Path is outside the allowed folder: ${browseRoot}` });
116
+ }
117
+ if (!(0, node_fs_1.existsSync)(base)) {
118
+ return res.status(404).json({ success: false, error: `Path does not exist: ${base}` });
119
+ }
120
+ if (!(0, node_fs_1.statSync)(base).isDirectory()) {
121
+ return res.status(400).json({ success: false, error: `Not a directory: ${base}` });
122
+ }
123
+ let entries;
124
+ try {
125
+ entries = listDirectory(base);
126
+ }
127
+ catch (err) {
128
+ return res.status(400).json({ success: false, error: `Could not list "${base}": ${(0, util_1.errorMessage)(err)}` });
129
+ }
130
+ const parent = node_path_1.default.dirname(base) === base ? null : node_path_1.default.dirname(base);
131
+ // Never allow the browser to navigate above the browse root.
132
+ const effectiveParent = parent && (!browseRoot || (0, util_1.isPathWithinRoot)(browseRoot, parent)) ? parent : null;
133
+ res.json({
134
+ success: true,
135
+ data: {
136
+ path: base,
137
+ name: node_path_1.default.basename(base) || base,
138
+ parent: effectiveParent,
139
+ entries,
140
+ },
141
+ });
142
+ }));
143
+ // Open an existing database file and register it with the manager.
144
+ router.post('/api/databases/open', wrap(async (req, res) => {
145
+ if (!allowBrowse) {
146
+ return res
147
+ .status(403)
148
+ .json({ success: false, error: 'File browsing is disabled — this server was started with specific database files.' });
149
+ }
150
+ const p = String(req.body?.path ?? '').trim();
151
+ if (!p)
152
+ return res.status(400).json({ success: false, error: 'Database path is required.' });
153
+ const abs = node_path_1.default.resolve(p);
154
+ if (browseRoot && !(0, util_1.isPathWithinRoot)(browseRoot, abs)) {
155
+ return res.status(403).json({ success: false, error: `Cannot open a database outside the allowed folder: ${browseRoot}` });
156
+ }
157
+ let id;
158
+ try {
159
+ id = manager.openFile(p);
160
+ }
161
+ catch (err) {
162
+ return res.status(400).json({ success: false, error: (0, util_1.errorMessage)(err) });
163
+ }
164
+ res.json({ success: true, data: { id, message: `Opened "${id}".` } });
165
+ }));
69
166
  router.post('/api/databases', wrap(async (req, res) => {
70
167
  if (ctx.readonly) {
71
168
  return res.status(403).json({ success: false, error: 'Read-only mode — creating databases is disabled.' });
@@ -1 +1 @@
1
- {"version":3,"file":"databases.js","sourceRoot":"","sources":["../../src/routes/databases.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"databases.js","sourceRoot":"","sources":["../../src/routes/databases.ts"],"names":[],"mappings":"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"}
package/dist/util.d.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  /** Small shared helpers used across the server. */
2
2
  export declare function errorMessage(err: unknown): string;
3
+ /**
4
+ * True when `p` is equal to `root` or lives inside it (both treated as
5
+ * absolute). Used to sandbox the filesystem file-browser to an allowed folder.
6
+ */
7
+ export declare function isPathWithinRoot(root: string, p: string): boolean;
3
8
  /** Operators understood by the structured (type-aware) filter conditions. */
4
9
  export type FilterOp = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'prefix' | 'between' | 'null' | 'notnull';
5
10
  /** A single structured filter condition produced by the type-aware filter form. */
package/dist/util.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  /** Small shared helpers used across the server. */
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
3
6
  Object.defineProperty(exports, "__esModule", { value: true });
4
7
  exports.errorMessage = errorMessage;
8
+ exports.isPathWithinRoot = isPathWithinRoot;
5
9
  exports.parseFilters = parseFilters;
6
10
  exports.filtersToQS = filtersToQS;
7
11
  exports.isInternalTable = isInternalTable;
@@ -10,11 +14,20 @@ exports.decodePk = decodePk;
10
14
  exports.normalizeCell = normalizeCell;
11
15
  exports.normalizeRow = normalizeRow;
12
16
  exports.coerceFormValue = coerceFormValue;
17
+ const node_path_1 = __importDefault(require("node:path"));
13
18
  function errorMessage(err) {
14
19
  if (err instanceof Error)
15
20
  return err.message;
16
21
  return String(err);
17
22
  }
23
+ /**
24
+ * True when `p` is equal to `root` or lives inside it (both treated as
25
+ * absolute). Used to sandbox the filesystem file-browser to an allowed folder.
26
+ */
27
+ function isPathWithinRoot(root, p) {
28
+ const rel = node_path_1.default.relative(node_path_1.default.resolve(root), node_path_1.default.resolve(p));
29
+ return rel === '' || (!rel.startsWith('..') && !node_path_1.default.isAbsolute(rel));
30
+ }
18
31
  /** Parse the `f` query parameter (URL-encoded JSON object) into row filters. */
19
32
  function parseFilters(raw) {
20
33
  const out = {};
package/dist/util.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";AAAA,mDAAmD;;AAEnD,oCAGC;AAyBD,oCA0BC;AAGD,kCAiBC;AAGD,0CAEC;AAGD,4BAEC;AAGD,4BAUC;AAGD,sCAMC;AAGD,oCAIC;AAUD,0CA0BC;AArJD,SAAgB,YAAY,CAAC,GAAY;IACvC,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAwBD,gFAAgF;AAChF,SAAgB,YAAY,CAAC,GAAY;IACvC,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,CAAC,GAAY,EAAQ,EAAE;QACjC,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACnC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,EAAE,CAAC;gBACpE,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE;oBAAE,SAAS;gBACxD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrB,IAAI,CAAC,CAAC,MAAM;wBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAsB,CAAC;gBAChD,CAAC;qBAAM,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;oBACjC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAoB,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,GAAG,CAAC,CAAC;IACX,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6EAA6E;AAC7E,SAAgB,WAAW,CAAC,OAA+B;IACzD,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,SAAS;QAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,CAAC,MAAM;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACtC,SAAS;QACX,CAAC;QACD,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAC5B,OAAO,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,kFAAkF;AAClF,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED,4FAA4F;AAC5F,SAAgB,QAAQ,CAAC,MAAiB;IACxC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACrF,CAAC;AAED,qEAAqE;AACrE,SAAgB,QAAQ,CAAC,OAAe;IACtC,OAAO,MAAM,CAAC,OAAO,CAAC;SACnB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,IAAI,CAAC;YACH,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,2FAA2F;AAC3F,SAAgB,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IACnD,CAAC;IACD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,qCAAqC;AACrC,SAAgB,YAAY,CAAC,GAA4B;IACvD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IAC1E,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,eAAe,CAAC,GAAY,EAAE,UAAkB;IAC9D,MAAM,IAAI,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEnD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;QAC1B,OAAO,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QAClD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACpE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAC1B,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
@@ -36,7 +36,7 @@
36
36
  {{{body}}}
37
37
  </main>
38
38
  <footer class="border-t border-base-300 px-6 py-4 text-center text-xs text-base-content/40">
39
- AdminDB · a browser tool for SQLite databases
39
+ AdminDB{{#if version}} v{{version}}{{/if}} · a browser tool for SQLite databases
40
40
  </footer>
41
41
  </div>
42
42
  <div class="drawer-side z-40">
@@ -28,6 +28,47 @@
28
28
  </p>
29
29
  </div>
30
30
 
31
+ <!-- Open an existing database file -->
32
+ {{#if allowBrowse}}
33
+ <div class="app-card p-5">
34
+ <div class="mb-3 flex flex-wrap items-center justify-between gap-2">
35
+ <h2 class="text-sm font-semibold uppercase tracking-wide text-base-content/45">Open an existing database</h2>
36
+ <span class="text-xs text-base-content/40">.db · .sqlite · .sqlite3</span>
37
+ </div>
38
+ <div class="flex flex-wrap items-center gap-2">
39
+ <input id="fs-path" class="field-input font-mono sm:!w-96" placeholder="Absolute path to a folder, e.g. C:\data" autocomplete="off" spellcheck="false" />
40
+ <button id="fs-go" type="button" class="btn btn-outline btn-sm gap-1.5">
41
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /></svg>
42
+ Go
43
+ </button>
44
+ <button id="fs-up" type="button" class="btn btn-ghost btn-sm gap-1.5">
45
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3 10h13M3 10l4-4m-4 4l4 4" /></svg>
46
+ Up
47
+ </button>
48
+ </div>
49
+ <div class="mt-3 overflow-hidden rounded-xl border border-base-300">
50
+ <div id="fs-current" class="border-b border-base-200 bg-base-200/50 px-3 py-2 font-mono text-xs text-base-content/60"></div>
51
+ <div id="fs-listing" class="max-h-80 divide-y divide-base-200/70 overflow-auto"></div>
52
+ </div>
53
+ <p class="mt-2.5 text-xs text-base-content/45">
54
+ Browse the filesystem to select an existing database; opening it adds it to the list above so you can
55
+ switch between databases freely.
56
+ {{#if browseRoot}}
57
+ <span class="font-medium text-base-content/60">Browsing is limited to <code class="font-mono">{{browseRoot}}</code>.</span>
58
+ {{/if}}
59
+ <span class="font-medium text-warning">This server has no authentication — treat it like a remote filesystem &amp; database shell.</span>
60
+ </p>
61
+ </div>
62
+ {{else}}
63
+ <div class="app-card p-5">
64
+ <p class="text-sm text-base-content/60">
65
+ <b class="text-base-content/80">File browsing is disabled.</b>
66
+ This server was started with specific database files, so the filesystem browser is turned off — use the
67
+ list of available databases below.
68
+ </p>
69
+ </div>
70
+ {{/if}}
71
+
31
72
  <!-- List -->
32
73
  <div>
33
74
  <div class="mb-3 flex items-center justify-between">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "admindb",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Browser-based SQLite database administration tool — embed it in your Express app or run it standalone.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",