@hienlh/ppm 0.11.16 → 0.11.17
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.
- package/CHANGELOG.md +11 -0
- package/dist/web/assets/{ai-settings-section-C6FDY8qE.js → ai-settings-section-L6XAmZEP.js} +1 -1
- package/dist/web/assets/{api-client-Bn-Pi9k5.js → api-client-CwbMRXYl.js} +1 -1
- package/dist/web/assets/{api-settings-C__hxGX2.js → api-settings-ByUGHhTB.js} +1 -1
- package/dist/web/assets/{audio-preview-DjLLuzUD.js → audio-preview-VMboGrIH.js} +1 -1
- package/dist/web/assets/{chat-tab-CL9_hlGE.js → chat-tab-DfO2rHO8.js} +4 -4
- package/dist/web/assets/{code-editor-YaQFb5Db.js → code-editor-BU7NX_SZ.js} +2 -2
- package/dist/web/assets/{conflict-editor-Dk6MS9pE.js → conflict-editor-943WUefe.js} +1 -1
- package/dist/web/assets/database-viewer-BV0Ebp0z.js +2 -0
- package/dist/web/assets/{diff-viewer-DPgNFO4j.js → diff-viewer-B3gAWXgA.js} +1 -1
- package/dist/web/assets/{extension-webview-B8361xT-.js → extension-webview-C8rdBYLl.js} +1 -1
- package/dist/web/assets/{image-preview-B8oAGvHG.js → image-preview-BEiYtg6_.js} +1 -1
- package/dist/web/assets/{index-Bl3W1FYm.js → index-CBsOxcqb.js} +6 -6
- package/dist/web/assets/keybindings-store-BIQHClUy.js +1 -0
- package/dist/web/assets/{keybindings-store-C9KsBH7z.js → keybindings-store-CThBg3hS.js} +1 -1
- package/dist/web/assets/{markdown-renderer-B8Gp0FKa.js → markdown-renderer-t1ZBKbXZ.js} +1 -1
- package/dist/web/assets/{pdf-preview-D7JrByDM.js → pdf-preview-CjfQxXE5.js} +1 -1
- package/dist/web/assets/{port-forwarding-tab-D2w0zW8n.js → port-forwarding-tab-BZmfg410.js} +1 -1
- package/dist/web/assets/{postgres-viewer-ei8XhyiT.js → postgres-viewer-CSTO0jc2.js} +1 -1
- package/dist/web/assets/{project-store-BYmQ0fDC.js → project-store-IB6pAGQh.js} +1 -1
- package/dist/web/assets/{settings-store-B9axDbuA.js → settings-store-fDOEursg.js} +2 -2
- package/dist/web/assets/settings-tab-b3AbZg6I.js +1 -0
- package/dist/web/assets/{sql-query-editor-BnpKNGG0.js → sql-query-editor-JwymAmuK.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-BNkPwKNL.js → sqlite-viewer-D0oWgepE.js} +1 -1
- package/dist/web/assets/{terminal-tab-DwYueV8K.js → terminal-tab-WBPZXu12.js} +1 -1
- package/dist/web/assets/{use-blob-url-BSltfg79.js → use-blob-url-BU9hYOj9.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-BERjR8IA.js → use-monaco-theme-o7Ip-BDL.js} +1 -1
- package/dist/web/assets/{video-preview-BnZt6xtr.js → video-preview-BcMa4tim.js} +1 -1
- package/dist/web/index.html +7 -7
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/server/routes/database.ts +11 -3
- package/src/services/postgres.service.ts +1 -1
- package/src/web/components/database/connection-list.tsx +7 -2
- package/src/web/components/database/data-grid.tsx +1 -1
- package/src/web/components/database/database-sidebar.tsx +2 -1
- package/src/web/components/database/use-connections.ts +24 -11
- package/src/web/lib/api-client.ts +6 -1
- package/dist/web/assets/database-viewer-BO58nGFL.js +0 -2
- package/dist/web/assets/keybindings-store-BkZjvU9J.js +0 -1
- package/dist/web/assets/settings-tab-Dd4mGQHq.js +0 -1
package/package.json
CHANGED
|
@@ -9,6 +9,14 @@ import { syncTables, searchTables, getTablesFromCache } from "../../services/tab
|
|
|
9
9
|
import { isReadOnlyQuery } from "../../services/database/readonly-check.ts";
|
|
10
10
|
import { ok, err } from "../../types/api.ts";
|
|
11
11
|
|
|
12
|
+
/** Race a promise against a timeout — ensures routes always respond */
|
|
13
|
+
function withTimeout<T>(promise: Promise<T>, ms: number, message = "Connection timed out"): Promise<T> {
|
|
14
|
+
return Promise.race([
|
|
15
|
+
promise,
|
|
16
|
+
new Promise<never>((_, reject) => setTimeout(() => reject(new Error(message)), ms)),
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
export const databaseRoutes = new Hono();
|
|
13
21
|
|
|
14
22
|
/** Strip sensitive connection_config from connection responses */
|
|
@@ -190,7 +198,7 @@ databaseRoutes.post("/test", async (c) => {
|
|
|
190
198
|
const body = await c.req.json<{ type: "sqlite" | "postgres"; connectionConfig: { type: string; path?: string; connectionString?: string } }>();
|
|
191
199
|
if (!body.type || !body.connectionConfig) return c.json(err("type and connectionConfig required"), 400);
|
|
192
200
|
const adapter = getAdapter(body.type);
|
|
193
|
-
const result = await adapter.testConnection(body.connectionConfig as import("../../types/database.ts").DbConnectionConfig);
|
|
201
|
+
const result = await withTimeout(adapter.testConnection(body.connectionConfig as import("../../types/database.ts").DbConnectionConfig), 15_000);
|
|
194
202
|
return c.json(ok(result));
|
|
195
203
|
} catch (e) {
|
|
196
204
|
return c.json(err((e as Error).message), 500);
|
|
@@ -204,7 +212,7 @@ databaseRoutes.post("/connections/:id/test", async (c) => {
|
|
|
204
212
|
if (!conn) return c.json(err("Connection not found"), 404);
|
|
205
213
|
const config = decryptConfig(conn.connection_config);
|
|
206
214
|
const adapter = getAdapter(conn.type);
|
|
207
|
-
const result = await adapter.testConnection(config);
|
|
215
|
+
const result = await withTimeout(adapter.testConnection(config), 15_000);
|
|
208
216
|
return c.json(ok(result));
|
|
209
217
|
} catch (e) {
|
|
210
218
|
return c.json(err((e as Error).message), 500);
|
|
@@ -217,7 +225,7 @@ databaseRoutes.get("/connections/:id/tables", async (c) => {
|
|
|
217
225
|
const conn = resolveConn(c.req.param("id"));
|
|
218
226
|
if (!conn) return c.json(err("Connection not found"), 404);
|
|
219
227
|
const useCached = c.req.query("cached") === "1";
|
|
220
|
-
const result = useCached ? getTablesFromCache(conn.id) : await syncTables(conn.id);
|
|
228
|
+
const result = useCached ? getTablesFromCache(conn.id) : await withTimeout(syncTables(conn.id), 15_000);
|
|
221
229
|
const tables = result.map((t) => ({ name: t.tableName, schema: t.schemaName, rowCount: t.rowCount }));
|
|
222
230
|
return c.json(ok(tables));
|
|
223
231
|
} catch (e) {
|
|
@@ -48,7 +48,7 @@ class PostgresService {
|
|
|
48
48
|
const sslOpts = sslmode === "no-verify" || sslmode === "require"
|
|
49
49
|
? { rejectUnauthorized: false }
|
|
50
50
|
: sslmode === "disable" ? false : undefined;
|
|
51
|
-
const sql = postgres(connectionString, { max: 3, idle_timeout: 60, ssl: sslOpts as any });
|
|
51
|
+
const sql = postgres(connectionString, { max: 3, idle_timeout: 60, connect_timeout: 10, ssl: sslOpts as any });
|
|
52
52
|
const timer = setTimeout(() => this.disconnect(connectionString), IDLE_TIMEOUT_MS);
|
|
53
53
|
this.cache.set(connectionString, { sql, timer });
|
|
54
54
|
return sql;
|
|
@@ -14,6 +14,7 @@ interface ColumnInfo {
|
|
|
14
14
|
interface ConnectionListProps {
|
|
15
15
|
connections: Connection[];
|
|
16
16
|
cachedTables: Map<number, CachedTable[]>;
|
|
17
|
+
refreshErrors?: Map<number, string>;
|
|
17
18
|
onOpenTable: (conn: Connection, tableName: string, schemaName: string) => void;
|
|
18
19
|
onRefreshTables: (id: number) => Promise<void>;
|
|
19
20
|
onEdit: (conn: Connection) => void;
|
|
@@ -27,7 +28,7 @@ interface GroupMap {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export function ConnectionList({
|
|
30
|
-
connections, cachedTables,
|
|
31
|
+
connections, cachedTables, refreshErrors,
|
|
31
32
|
onOpenTable, onRefreshTables, onEdit, onDelete,
|
|
32
33
|
onFetchColumns, columnCache,
|
|
33
34
|
}: ConnectionListProps) {
|
|
@@ -186,7 +187,11 @@ export function ConnectionList({
|
|
|
186
187
|
{isExpanded && (
|
|
187
188
|
<div className="ml-[11px] border-l border-dashed border-border pl-1">
|
|
188
189
|
{isRefreshing && tables.length === 0 && <p className="text-[10px] text-text-subtle px-2 py-1">Loading…</p>}
|
|
189
|
-
{!isRefreshing && tables.length === 0 &&
|
|
190
|
+
{!isRefreshing && tables.length === 0 && (
|
|
191
|
+
refreshErrors?.get(conn.id)
|
|
192
|
+
? <p className="text-[10px] text-red-500 px-2 py-1 break-all">{refreshErrors.get(conn.id)}</p>
|
|
193
|
+
: <p className="text-[10px] text-text-subtle px-2 py-1">No tables cached</p>
|
|
194
|
+
)}
|
|
190
195
|
{tables.length > 0 && (
|
|
191
196
|
<>
|
|
192
197
|
{tables.length > 5 && (
|
|
@@ -331,7 +331,7 @@ export function DataGrid({
|
|
|
331
331
|
if (pc !== col) stickyWidth = Math.max(stickyWidth, offset + (colWidths.get(pc) ?? 0));
|
|
332
332
|
}
|
|
333
333
|
const targetLeft = th.offsetLeft - stickyWidth;
|
|
334
|
-
container.scrollTo({ left: targetLeft, behavior: "
|
|
334
|
+
container.scrollTo({ left: targetLeft, behavior: "instant" });
|
|
335
335
|
setColSearchOpen(false);
|
|
336
336
|
}, [pinnedColOffsets, colWidths]);
|
|
337
337
|
|
|
@@ -7,7 +7,7 @@ import { ConnectionImportExport } from "./connection-import-export";
|
|
|
7
7
|
import { useConnections, type Connection, type CreateConnectionData, type UpdateConnectionData } from "./use-connections";
|
|
8
8
|
|
|
9
9
|
export function DatabaseSidebar() {
|
|
10
|
-
const { connections, loading, cachedTables, columnCache, createConnection, updateConnection, deleteConnection, testConnection, testRawConnection, refreshTables, fetchColumns, exportConnections, importConnections } = useConnections();
|
|
10
|
+
const { connections, loading, cachedTables, refreshErrors, columnCache, createConnection, updateConnection, deleteConnection, testConnection, testRawConnection, refreshTables, fetchColumns, exportConnections, importConnections } = useConnections();
|
|
11
11
|
const openTab = useTabStore((s) => s.openTab);
|
|
12
12
|
const [addOpen, setAddOpen] = useState(false);
|
|
13
13
|
const [editConn, setEditConn] = useState<Connection | null>(null);
|
|
@@ -62,6 +62,7 @@ export function DatabaseSidebar() {
|
|
|
62
62
|
<ConnectionList
|
|
63
63
|
connections={connections}
|
|
64
64
|
cachedTables={cachedTables}
|
|
65
|
+
refreshErrors={refreshErrors}
|
|
65
66
|
onOpenTable={handleOpenTable}
|
|
66
67
|
onRefreshTables={refreshTables}
|
|
67
68
|
onEdit={setEditConn}
|
|
@@ -41,6 +41,7 @@ export function useConnections() {
|
|
|
41
41
|
const [connections, setConnections] = useState<Connection[]>([]);
|
|
42
42
|
const [loading, setLoading] = useState(true);
|
|
43
43
|
const [cachedTables, setCachedTables] = useState<Map<number, CachedTable[]>>(new Map());
|
|
44
|
+
const [refreshErrors, setRefreshErrors] = useState<Map<number, string>>(new Map());
|
|
44
45
|
|
|
45
46
|
const fetchConnections = useCallback(async () => {
|
|
46
47
|
try {
|
|
@@ -84,15 +85,22 @@ export function useConnections() {
|
|
|
84
85
|
}, []);
|
|
85
86
|
|
|
86
87
|
const refreshTables = useCallback(async (id: number): Promise<void> => {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
setRefreshErrors((prev) => { const m = new Map(prev); m.delete(id); return m; });
|
|
89
|
+
try {
|
|
90
|
+
const raw = await api.get<{ name: string; schema: string; rowCount: number }[]>(`/api/db/connections/${id}/tables`);
|
|
91
|
+
const tables: CachedTable[] = raw.map((t) => ({
|
|
92
|
+
connectionId: id,
|
|
93
|
+
tableName: t.name,
|
|
94
|
+
schemaName: t.schema,
|
|
95
|
+
rowCount: t.rowCount,
|
|
96
|
+
cachedAt: new Date().toISOString(),
|
|
97
|
+
}));
|
|
98
|
+
setCachedTables((prev) => new Map(prev).set(id, tables));
|
|
99
|
+
} catch (e) {
|
|
100
|
+
const msg = (e as Error).message || "Connection failed";
|
|
101
|
+
setRefreshErrors((prev) => new Map(prev).set(id, msg));
|
|
102
|
+
throw e; // re-throw so callers know it failed
|
|
103
|
+
}
|
|
96
104
|
}, []);
|
|
97
105
|
|
|
98
106
|
/** Fetch column metadata for a table (lazy loaded for schema tree) */
|
|
@@ -117,8 +125,13 @@ export function useConnections() {
|
|
|
117
125
|
"/api/db/connections/import", data,
|
|
118
126
|
);
|
|
119
127
|
await fetchConnections();
|
|
128
|
+
// Auto-refresh table cache for newly imported connections (fire-and-forget)
|
|
129
|
+
const imported = result.connections ?? [];
|
|
130
|
+
if (imported.length > 0) {
|
|
131
|
+
Promise.all(imported.map((c) => refreshTables(c.id).catch(() => {})));
|
|
132
|
+
}
|
|
120
133
|
return result;
|
|
121
|
-
}, [fetchConnections]);
|
|
134
|
+
}, [fetchConnections, refreshTables]);
|
|
122
135
|
|
|
123
|
-
return { connections, loading, cachedTables, columnCache, createConnection, updateConnection, deleteConnection, testConnection, testRawConnection, refreshTables, fetchColumns, exportConnections, importConnections };
|
|
136
|
+
return { connections, loading, cachedTables, refreshErrors, columnCache, createConnection, updateConnection, deleteConnection, testConnection, testRawConnection, refreshTables, fetchColumns, exportConnections, importConnections };
|
|
124
137
|
}
|
|
@@ -75,7 +75,12 @@ class ApiClient {
|
|
|
75
75
|
throw new Error("Unauthorized");
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
let json: any;
|
|
79
|
+
try {
|
|
80
|
+
json = await res.json();
|
|
81
|
+
} catch {
|
|
82
|
+
throw new Error(res.ok ? "Empty response from server" : `Server error (HTTP ${res.status})`);
|
|
83
|
+
}
|
|
79
84
|
|
|
80
85
|
if (json.ok === false) {
|
|
81
86
|
throw new Error(json.error ?? `HTTP ${res.status}`);
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{o as e}from"./rolldown-runtime-FhOqtrmT.js";import{b as t,x as n}from"./vendor-markdown-0Mxgxy0L.js";import{t as r}from"./createLucideIcon-BjHrJDVb.js";import{n as i,r as a,t as o}from"./plus-51UQ45rf.js";import{t as s}from"./chevron-right-BzAdxJRG.js";import{t as c}from"./database-D4DIhgi-.js";import{n as l,r as u,t as d}from"./x-DlFGzN8d.js";import{t as f}from"./refresh-cw-LlbZDJpO.js";import{t as p}from"./trash-2-CJYoLw7Q.js";import{t as m}from"./api-client-Bn-Pi9k5.js";import"./vendor-mermaid-BlWh9BJO.js";import"./settings-store-B9axDbuA.js";import{t as h}from"./tab-store-B3M9hjho.js";import{E as g,K as _,N as v,O as y,P as b,h as x,k as S}from"./index-Bl3W1FYm.js";import"./use-monaco-theme-BERjR8IA.js";import{t as C}from"./sql-query-editor-BnpKNGG0.js";import{n as w}from"./csv-parser--2WJNgS7.js";var T=r(`columns-3`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}],[`path`,{d:`M15 3v18`,key:`14nvp0`}]]),E=r(`funnel`,[[`path`,{d:`M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z`,key:`sc7q7i`}]]),D=e(n(),1);function O(e,t,n,r){return`ppm-db-${e}-${n}.${t}-p${r}`}function ee(e,t,n,r){try{let i=sessionStorage.getItem(O(e,t,n,r));return i?JSON.parse(i):null}catch{return null}}function te(e,t,n,r,i,a){try{sessionStorage.setItem(O(e,t,n,r),JSON.stringify({data:i,cols:a}))}catch{}}function ne(e){let t=`/api/db/connections/${e}`,[n,r]=(0,D.useState)(null),[i,a]=(0,D.useState)(`public`),[o,s]=(0,D.useState)(null),[c,l]=(0,D.useState)([]),[u,d]=(0,D.useState)(!1),[f,p]=(0,D.useState)(null),[h,g]=(0,D.useState)(1),[_,v]=(0,D.useState)(null),[y,b]=(0,D.useState)(null),[x,S]=(0,D.useState)(!1),[C,w]=(0,D.useState)(null),[T,E]=(0,D.useState)(`ASC`),O=(0,D.useCallback)(async(r,a,o,c,u)=>{let f=r??n,g=a??i;if(!f)return;d(!0);let _=c===void 0?C:c,v=u??T;try{let n=_?`&orderBy=${encodeURIComponent(_)}&orderDir=${v}`:``,[r,i]=await Promise.all([m.get(`${t}/data?table=${encodeURIComponent(f)}&schema=${g}&page=${o??h}&limit=100${n}`),m.get(`${t}/schema?table=${encodeURIComponent(f)}&schema=${g}`)]);s(r),l(i),te(e,f,g,o??h,r,i)}catch(e){p(e.message)}finally{d(!1)}},[t,e,n,i,h,C,T]),ne=(0,D.useCallback)((t,n=`public`)=>{r(t),a(n),g(1),v(null);let i=ee(e,t,n,1);i?(s(i.data),l(i.cols),d(!1),O(t,n,1)):O(t,n,1)},[e,O]),k=(0,D.useCallback)(e=>{g(e),O(void 0,void 0,e)},[O]),A=(0,D.useCallback)(async e=>{S(!0),b(null);try{let r=await m.post(`${t}/query`,{sql:e});v(r),r.changeType===`modify`&&O(n??void 0,i)}catch(e){b(e.message)}finally{S(!1)}},[t,n,i,O]),re=(0,D.useCallback)(async(e,r,a,o)=>{if(!n)return;let s=n,c=i;try{await m.put(`${t}/cell`,{table:s,schema:c,pkColumn:e,pkValue:r,column:a,value:o}),O(s,c)}catch(e){p(e.message)}},[t,n,i,O]),j=(0,D.useCallback)(async(e,r)=>{if(!n)return;let a=n,o=i;try{await m.del(`${t}/row`,{table:a,schema:o,pkColumn:e,pkValue:r}),O(a,o)}catch(e){p(e.message)}},[t,n,i,O]);return{selectedTable:n,selectedSchema:i,selectTable:ne,tableData:o,schema:c,loading:u,error:f,page:h,setPage:k,orderBy:C,orderDir:T,toggleSort:(0,D.useCallback)(e=>{let t,n=`ASC`;C===e?T===`ASC`?(t=e,n=`DESC`):(t=null,n=`ASC`):(t=e,n=`ASC`),w(t),E(n),g(1),O(void 0,void 0,1,t,n)},[C,T,O]),queryResult:_,queryError:y,queryLoading:x,executeQuery:A,updateCell:re,deleteRow:j,bulkDelete:(0,D.useCallback)(async(e,r)=>{if(!n)return;let a=n,o=i;try{await m.post(`${t}/rows/delete`,{table:a,schema:o,pkColumn:e,pkValues:r}),O(a,o)}catch(e){p(e.message)}},[t,n,i,O]),insertRow:(0,D.useCallback)(async e=>{if(!n)return;let r=n,a=i;try{await m.post(`${t}/row`,{table:r,schema:a,values:e}),O(r,a)}catch(e){throw p(e.message),e}},[t,n,i,O]),refreshData:O,queryAsTable:(0,D.useCallback)(async e=>{d(!0);try{let n=await m.post(`${t}/query`,{sql:e});n.changeType===`select`&&s({columns:n.columns,rows:n.rows,total:n.rows.length,page:1,limit:n.rows.length})}catch(e){p(e.message)}finally{d(!1)}},[t])}}var k=t();function A(e,t,n){let r=new Blob([t],{type:n}),i=URL.createObjectURL(r),a=document.createElement(`a`);a.href=i,a.download=e,a.click(),URL.revokeObjectURL(i)}function re({columns:e,rows:t,filename:n=`export`,exportAllUrl:r}){let[i,a]=(0,D.useState)(!1),[o,s]=(0,D.useState)(!1),c=(0,D.useRef)(null);(0,D.useEffect)(()=>{if(!i)return;let e=e=>{c.current&&!c.current.contains(e.target)&&a(!1)};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[i]);let l=()=>{let r=w(e,t.map(t=>e.map(e=>String(t[e]??``))));A(`${n}.csv`,r,`text/csv`),a(!1)},d=()=>{let e=JSON.stringify(t,null,2);A(`${n}.json`,e,`application/json`),a(!1)},f=async e=>{if(r){s(!0);try{let t=await(await fetch(`${r}&format=${e}&limit=10000`)).text(),i=e===`csv`?`text/csv`:`application/json`;A(`${n}-all.${e}`,t,i)}catch{}s(!1),a(!1)}};return e.length===0||t.length===0?null:(0,k.jsxs)(`div`,{className:`relative`,ref:c,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`p-1 rounded text-muted-foreground hover:text-foreground transition-colors`,title:`Export`,children:(0,k.jsx)(u,{className:`size-3.5`})}),i&&(0,k.jsxs)(`div`,{className:`absolute right-0 top-full mt-1 z-50 bg-popover border border-border rounded-md shadow-md py-1 min-w-[160px] text-xs`,children:[(0,k.jsx)(`button`,{onClick:l,className:`w-full text-left px-3 py-1.5 hover:bg-muted transition-colors`,children:`Export Page (CSV)`}),(0,k.jsx)(`button`,{onClick:d,className:`w-full text-left px-3 py-1.5 hover:bg-muted transition-colors`,children:`Export Page (JSON)`}),r&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:`border-t border-border my-1`}),(0,k.jsx)(`button`,{onClick:()=>f(`csv`),disabled:o,className:`w-full text-left px-3 py-1.5 hover:bg-muted transition-colors disabled:opacity-50`,children:o?`Exporting…`:`Export All (CSV)`}),(0,k.jsx)(`button`,{onClick:()=>f(`json`),disabled:o,className:`w-full text-left px-3 py-1.5 hover:bg-muted transition-colors disabled:opacity-50`,children:o?`Exporting…`:`Export All (JSON)`})]})]})]})}function j({tableData:e,schema:t,loading:n,page:r,onPageChange:c,onCellUpdate:l,onRowDelete:u,orderBy:f,orderDir:m,onToggleSort:b,onBulkDelete:C,onInsertRow:w,connectionId:O,selectedTable:ee,selectedSchema:te,connectionName:ne,columnFilters:A={},onColumnFilter:j}){let[M,N]=(0,D.useState)(null),[P,F]=(0,D.useState)(``),[I,L]=(0,D.useState)(null),[R,se]=(0,D.useState)(``),[z,B]=(0,D.useState)(new Set),[ce,le]=(0,D.useState)(!1),[ue,de]=(0,D.useState)({}),[fe,V]=(0,D.useState)(null),[pe,me]=(0,D.useState)(!1),{openTab:H}=h(x(e=>({openTab:e.openTab}))),he=(0,D.useCallback)(e=>{H({type:`editor`,title:e.col,projectId:null,closable:!0,metadata:{inlineContent:e.value,inlineLanguage:ie(e.value)}})},[H]),[U,ge]=(0,D.useState)(new Set),[_e,ve]=(0,D.useState)(new Set),[ye,be]=(0,D.useState)(null),[xe,W]=(0,D.useState)(!1),Se=(0,D.useRef)(null),G=(0,D.useMemo)(()=>t.find(e=>e.pk)?.name||(t.find(e=>e.name.toLowerCase()===`id`)?.name??null),[t]),Ce=(0,D.useCallback)(e=>{let t=JSON.stringify(e,null,2),n=G?String(e[G]??``):``;H({type:`editor`,title:n?`Row ${n}`:`Row`,projectId:null,closable:!0,metadata:{inlineContent:t,inlineLanguage:`json`}})},[H,G]),we=(0,D.useRef)(M);we.current=M;let K=(0,D.useRef)(P);K.current=P;let Te=(0,D.useRef)(z);Te.current=z;let Ee=(0,D.useRef)(I);Ee.current=I;let De=(0,D.useCallback)((e,t,n)=>{N({rowIdx:e,col:t}),F(n==null?``:typeof n==`object`?JSON.stringify(n):String(n))},[]),Oe=(0,D.useCallback)(()=>{let t=we.current;if(!t||!e||!G)return;let n=e.rows[t.rowIdx];if(!n)return;let r=n[t.col];String(r??``)!==K.current&&l(G,n[G],t.col,K.current===``?null:K.current),N(null)},[e,G,l]),ke=(0,D.useCallback)(()=>N(null),[]),Ae=(0,D.useCallback)(t=>{if(!e||!G||!u)return;let n=e.rows[t];n&&(u(G,n[G]),L(null))},[e,G,u]),je=(0,D.useCallback)(e=>{ge(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),Me=(0,D.useCallback)(e=>{ve(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),Ne=(0,D.useCallback)((e,t)=>{let n={...A};t?n[e]=t:delete n[e],j?.(n)},[A,j]),Pe=(0,D.useCallback)(e=>{B(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),Fe=(0,D.useCallback)(()=>{e&&B(t=>t.size===e.rows.length?new Set:new Set(e.rows.map((e,t)=>t)))},[e]),Ie=(0,D.useCallback)(()=>{!e||!G||!C||(C(G,Array.from(z).map(t=>e.rows[t]?.[G]).filter(e=>e!=null)),B(new Set),me(!1))},[e,G,C,z]),Le=(0,D.useCallback)(async()=>{if(w){V(null);try{let e={};for(let[t,n]of Object.entries(ue))n!==``&&(e[t]=n);await w(e),le(!1),de({})}catch(e){V(e.message)}}},[w,ue]),q=(0,D.useMemo)(()=>{if(!e||!R)return e?.rows??[];let t=R.toLowerCase();return e.rows.filter(n=>e.columns.some(e=>String(n[e]??``).toLowerCase().includes(t)))},[e,R]),Re=(0,D.useRef)(null);(0,D.useEffect)(()=>{let t=Re.current;if(!t)return;let n=t=>{if(t.key===`Escape`){W(!1);return}let n=t.target?.tagName;if(!(n===`INPUT`||n===`TEXTAREA`)){if(t.key===`/`){t.preventDefault(),W(!0);return}if(!(!(t.metaKey||t.ctrlKey)||!e)&&(t.key===`a`&&(t.preventDefault(),B(new Set(e.rows.map((e,t)=>t)))),t.key===`c`&&z.size>0)){t.preventDefault();let n=e.columns,r=n.join(` `),i=Array.from(z).sort((e,t)=>e-t).map(t=>n.map(n=>{let r=e.rows[t]?.[n];return r==null?``:typeof r==`object`?JSON.stringify(r):String(r)}).join(` `));navigator.clipboard.writeText([r,...i].join(`
|
|
2
|
-
`))}}};return t.addEventListener(`keydown`,n),()=>t.removeEventListener(`keydown`,n)},[e,z]);let J=(0,D.useMemo)(()=>{if(!e)return[];let t=e.columns.filter(e=>U.has(e)),n=e.columns.filter(e=>!U.has(e));return[...t,...n]},[e?.columns,U]),ze=(0,D.useRef)(null),[Be,Ve]=(0,D.useState)(0),[Y,He]=(0,D.useState)(new Map);(0,D.useEffect)(()=>{let e=ze.current;if(!e)return;let t=()=>{Ve(e.offsetHeight);let t=new Map;e.querySelectorAll(`th[data-col]`).forEach(e=>{t.set(e.dataset.col,e.offsetWidth)});let n=e.querySelector(`th[data-col='_cb']`);n&&t.set(`_cb`,n.offsetWidth),He(t)};t();let n=new ResizeObserver(t);return n.observe(e),()=>n.disconnect()},[e?.columns,U]);let X=(0,D.useMemo)(()=>{let e=new Map,t=Y.get(`_cb`)??(G?40:0);for(let n of J){if(!U.has(n))break;e.set(n,t),t+=Y.get(n)??100}return e},[J,U,G,Y]),Z=(0,D.useMemo)(()=>Array.from(_e).sort((e,t)=>e-t).map(e=>({idx:e,row:q[e]})).filter(e=>e.row),[_e,q]),Q=(0,D.useRef)(new Map),[$,Ue]=(0,D.useState)(new Map),We=(0,D.useCallback)((e,t)=>{t?Q.current.set(e,t):Q.current.delete(e)},[]);(0,D.useEffect)(()=>{if(Z.length===0){$.size>0&&Ue(new Map);return}let e=requestAnimationFrame(()=>{let e=new Map;for(let{idx:t}of Z){let n=Q.current.get(t);n&&e.set(t,n.offsetHeight)}Ue(e)});return()=>cancelAnimationFrame(e)},[Z,e]);let Ge=(0,D.useMemo)(()=>{let e=new Map,t=Be;for(let{idx:n}of Z)e.set(n,t),t+=$.get(n)??28;return e},[Be,Z,$]),Ke=(0,D.useCallback)(e=>{let t=Se.current,n=t?.querySelector(`th[data-col="${e}"]`);if(!t||!n)return;let r=0,i=t.querySelector(`th[data-col="_cb"]`);i&&(r+=i.offsetWidth);for(let[t,n]of X)t!==e&&(r=Math.max(r,n+(Y.get(t)??0)));let a=n.offsetLeft-r;t.scrollTo({left:a,behavior:`smooth`}),W(!1)},[X,Y]);if(!e)return(0,k.jsx)(`div`,{className:`flex items-center justify-center h-full text-xs text-muted-foreground`,children:n?(0,k.jsx)(v,{className:`size-4 animate-spin`}):`Select a table`});let qe=Math.ceil(e.total/e.limit)||1,Je=z.size>0,Ye=z.size===e.rows.length&&e.rows.length>0;return(0,k.jsxs)(`div`,{ref:Re,tabIndex:0,className:`flex flex-col h-full overflow-hidden outline-none`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-2 py-1 border-b border-border bg-background shrink-0`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-1 flex-1`,children:[(0,k.jsx)(g,{className:`size-3 text-muted-foreground`}),(0,k.jsx)(`input`,{type:`text`,value:R,onChange:e=>se(e.target.value),placeholder:`Search current page…`,className:`flex-1 text-xs bg-transparent outline-none text-foreground placeholder:text-muted-foreground`}),R&&(0,k.jsx)(`button`,{type:`button`,onClick:()=>se(``),className:`text-muted-foreground hover:text-foreground`,children:(0,k.jsx)(d,{className:`size-3`})})]}),(0,k.jsxs)(`div`,{className:`relative`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>W(!xe),className:`p-0.5 rounded transition-colors ${xe?`text-primary`:`text-muted-foreground hover:text-foreground`}`,title:`Jump to column ( / )`,children:(0,k.jsx)(T,{className:`size-3.5`})}),xe&&(0,k.jsx)(ae,{columns:e.columns,onSelect:Ke,onClose:()=>W(!1)})]}),Je&&(0,k.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs`,children:[(0,k.jsxs)(`span`,{className:`text-muted-foreground`,children:[z.size,` selected`]}),C&&G&&(pe?(0,k.jsxs)(`span`,{className:`flex items-center gap-1`,children:[(0,k.jsxs)(`button`,{type:`button`,onClick:Ie,className:`text-destructive text-[10px] font-medium hover:underline`,children:[`Delete `,z.size,`?`]}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>me(!1),className:`text-muted-foreground text-[10px] hover:underline`,children:`Cancel`})]}):(0,k.jsx)(`button`,{type:`button`,onClick:()=>me(!0),className:`p-0.5 text-muted-foreground hover:text-destructive`,children:(0,k.jsx)(p,{className:`size-3`})})),(0,k.jsx)(re,{columns:e.columns,rows:Array.from(z).map(t=>e.rows[t]).filter(Boolean),filename:`${ne??`db`}-selected`})]}),w&&(0,k.jsx)(`button`,{type:`button`,onClick:()=>{le(!0),de({}),V(null)},className:`p-0.5 rounded text-muted-foreground hover:text-primary transition-colors`,title:`Insert row`,children:(0,k.jsx)(o,{className:`size-3.5`})})]}),ce&&(0,k.jsxs)(`div`,{className:`px-2 py-1.5 border-b border-border bg-muted/30 text-xs space-y-1`,children:[(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.filter(e=>!e.pk).map(e=>(0,k.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,k.jsx)(`label`,{className:`text-muted-foreground text-[10px] w-16 truncate`,title:e.name,children:e.name}),(0,k.jsx)(`input`,{value:ue[e.name]??``,onChange:t=>de(n=>({...n,[e.name]:t.target.value})),placeholder:e.defaultValue??(e.nullable?`NULL`:``),className:`h-5 w-24 text-[11px] px-1 rounded border border-border bg-background outline-none focus:border-primary`})]},e.name))}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:Le,className:`text-[10px] px-2 py-0.5 rounded bg-primary text-primary-foreground hover:bg-primary/90`,children:`Save`}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>le(!1),className:`text-[10px] text-muted-foreground hover:underline`,children:`Cancel`}),fe&&(0,k.jsx)(`span`,{className:`text-[10px] text-destructive`,children:fe})]})]}),(0,k.jsxs)(`div`,{ref:Se,className:`flex-1 overflow-auto relative`,children:[n&&(0,k.jsx)(`div`,{className:`absolute inset-0 z-30 flex items-center justify-center bg-background/60`,children:(0,k.jsx)(v,{className:`size-5 animate-spin text-primary`})}),(0,k.jsxs)(`table`,{className:`w-full text-xs`,style:{borderCollapse:`separate`,borderSpacing:0},children:[(0,k.jsx)(`thead`,{ref:ze,className:`sticky top-0 z-20 bg-muted`,children:(0,k.jsxs)(`tr`,{children:[G&&(0,k.jsx)(`th`,{"data-col":`_cb`,className:`px-2 py-1.5 text-left font-medium text-muted-foreground border-b border-border w-10 bg-muted`,style:{position:`sticky`,left:0,zIndex:30},children:(0,k.jsx)(`input`,{type:`checkbox`,checked:Ye,onChange:Fe,className:`size-3 accent-primary`})}),J.map(e=>{let n=t.find(t=>t.name===e)?.pk,r=f===e,o=U.has(e),s=!!A[e],c=ye===e,l=X.get(e);return(0,k.jsxs)(`th`,{"data-col":e,className:`group/th px-2 py-1.5 text-left font-medium text-muted-foreground border-b border-border whitespace-nowrap bg-muted ${o?`border-r border-r-primary/20`:``}`,style:l==null?void 0:{position:`sticky`,left:l,zIndex:25},children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-0.5`,children:[(0,k.jsxs)(`button`,{type:`button`,onClick:()=>b(e),className:`flex items-center gap-0.5 ${n?`font-bold`:``} hover:text-foreground transition-colors`,children:[e,r&&m===`ASC`&&(0,k.jsx)(i,{className:`size-3`}),r&&m===`DESC`&&(0,k.jsx)(a,{className:`size-3`})]}),j&&(0,k.jsx)(`button`,{type:`button`,title:`Filter column`,onClick:()=>be(c?null:e),className:`p-0.5 rounded transition-colors ${s||c?`text-primary`:`text-muted-foreground/40 md:opacity-0 md:group-hover/th:opacity-100 hover:text-foreground`}`,children:(0,k.jsx)(E,{className:`size-2.5`})}),(0,k.jsx)(`button`,{type:`button`,title:o?`Unpin column`:`Pin column`,onClick:()=>je(e),className:`p-0.5 rounded transition-colors ${o?`text-primary`:`text-muted-foreground/40 md:opacity-0 md:group-hover/th:opacity-100 hover:text-foreground`}`,children:o?(0,k.jsx)(S,{className:`size-2.5`}):(0,k.jsx)(y,{className:`size-2.5`})})]}),c&&(0,k.jsxs)(`div`,{className:`mt-1 flex items-center gap-1`,children:[(0,k.jsx)(`input`,{autoFocus:!0,type:`text`,value:A[e]??``,placeholder:`ILIKE filter…`,onChange:t=>Ne(e,t.target.value),onKeyDown:e=>{e.key===`Escape`&&be(null)},className:`w-full h-5 text-[10px] px-1 rounded border border-border bg-background outline-none focus:border-primary`}),s&&(0,k.jsx)(`button`,{type:`button`,onClick:()=>Ne(e,``),className:`text-muted-foreground hover:text-foreground`,children:(0,k.jsx)(d,{className:`size-2.5`})})]})]},e)}),u&&G&&(0,k.jsx)(`th`,{className:`px-2 py-1.5 border-b border-border w-14 bg-muted`})]})}),(0,k.jsxs)(`tbody`,{children:[Z.map(({idx:e,row:t})=>(0,k.jsx)(oe,{row:t,rowIdx:e,columns:J,selected:z.has(e),onToggleSelect:Pe,pkCol:G,editingCell:M,editValue:P,onStartEdit:De,onCommitEdit:Oe,onCancelEdit:ke,onSetEditValue:F,showDelete:!!u,confirmingDelete:I===e,onDelete:Ae,onConfirmDelete:L,onViewCell:he,onViewRow:Ce,pinned:!0,onTogglePin:Me,pinnedCols:U,pinnedColOffsets:X,stickyTop:Ge.get(e)??Be,trRef:t=>We(e,t)},`pin-${e}`)),q.map((e,t)=>_e.has(t)?null:(0,k.jsx)(oe,{row:e,rowIdx:t,columns:J,selected:z.has(t),onToggleSelect:Pe,pkCol:G,editingCell:M,editValue:P,onStartEdit:De,onCommitEdit:Oe,onCancelEdit:ke,onSetEditValue:F,showDelete:!!u,confirmingDelete:I===t,onDelete:Ae,onConfirmDelete:L,onViewCell:he,onViewRow:Ce,pinned:!1,onTogglePin:Me,pinnedCols:U,pinnedColOffsets:X},t)),q.length===0&&(0,k.jsx)(`tr`,{children:(0,k.jsx)(`td`,{colSpan:J.length+2,className:`px-2 py-8 text-center text-muted-foreground`,children:`No data`})})]})]})]}),(0,k.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-1.5 border-t border-border bg-background shrink-0 text-xs text-muted-foreground`,children:[(0,k.jsxs)(`span`,{children:[e.total.toLocaleString(),` rows`]}),(0,k.jsxs)(`div`,{className:`hidden md:flex items-center gap-2 text-[10px] text-muted-foreground/50`,children:[(0,k.jsxs)(`span`,{children:[(0,k.jsx)(`kbd`,{className:`px-1 py-0.5 rounded bg-muted text-[9px]`,children:`/`}),` columns`]}),(0,k.jsxs)(`span`,{children:[(0,k.jsxs)(`kbd`,{className:`px-1 py-0.5 rounded bg-muted text-[9px]`,children:[`⌘`,`A`]}),` select all`]}),(0,k.jsxs)(`span`,{children:[(0,k.jsxs)(`kbd`,{className:`px-1 py-0.5 rounded bg-muted text-[9px]`,children:[`⌘`,`C`]}),` copy`]})]}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(`button`,{type:`button`,disabled:r<=1,onClick:()=>c(r-1),className:`p-0.5 rounded hover:bg-muted disabled:opacity-30`,children:(0,k.jsx)(_,{className:`size-3.5`})}),(0,k.jsxs)(`span`,{children:[r,` / `,qe]}),(0,k.jsx)(`button`,{type:`button`,disabled:r>=qe,onClick:()=>c(r+1),className:`p-0.5 rounded hover:bg-muted disabled:opacity-30`,children:(0,k.jsx)(s,{className:`size-3.5`})})]})]})]})}function M(e){return e==null?`NULL`:typeof e==`object`?JSON.stringify(e):String(e)}var N=200;function P(e){if(e==null)return!1;if(typeof e==`object`)return!0;let t=String(e);if(t.length>=N)return!0;let n=t.trimStart();return!!((n[0]===`{`||n[0]===`[`)&&(n.endsWith(`}`)||n.endsWith(`]`))||n.startsWith(`<?xml`)||n.startsWith(`<`)&&n.endsWith(`>`))}function ie(e){let t=e.trimStart();if(t[0]===`{`||t[0]===`[`)try{return JSON.parse(t),`json`}catch{}return t.startsWith(`<?xml`)||t.startsWith(`<`)&&/<\/\w+>/.test(t)?`xml`:t.startsWith(`---`)||/^\w+:\s/m.test(t)?`yaml`:`plaintext`}function ae({columns:e,onSelect:t,onClose:n}){let[r,i]=(0,D.useState)(``),[a,o]=(0,D.useState)(0),s=(0,D.useMemo)(()=>{if(!r)return e;let t=r.toLowerCase();return e.filter(e=>e.toLowerCase().includes(t))},[e,r]),c=(0,D.useRef)(null);return(0,D.useEffect)(()=>{c.current?.scrollIntoView({block:`nearest`})},[a]),(0,k.jsxs)(`div`,{className:`absolute top-full right-0 mt-1 z-50 w-52 max-h-56 bg-popover border border-border rounded-md shadow-lg overflow-hidden flex flex-col`,children:[(0,k.jsx)(`input`,{autoFocus:!0,type:`text`,value:r,onChange:e=>{i(e.target.value),o(0)},onKeyDown:e=>{e.key===`Escape`?n():e.key===`ArrowDown`?(e.preventDefault(),o(e=>Math.min(e+1,s.length-1))):e.key===`ArrowUp`?(e.preventDefault(),o(e=>Math.max(e-1,0))):e.key===`Enter`&&s[a]&&t(s[a])},placeholder:`Search columns…`,className:`px-2 py-1.5 text-xs bg-transparent outline-none border-b border-border text-foreground placeholder:text-muted-foreground`}),(0,k.jsx)(`div`,{className:`overflow-auto flex-1`,children:s.map((e,n)=>(0,k.jsx)(`button`,{type:`button`,onClick:()=>t(e),ref:n===a?c:void 0,className:`w-full text-left px-2 py-1 text-xs truncate ${n===a?`bg-primary/10 text-primary`:`text-foreground hover:bg-muted`}`,children:e},e))})]})}var oe=(0,D.memo)(function({row:e,rowIdx:t,columns:n,selected:r,onToggleSelect:i,pkCol:a,editingCell:o,editValue:s,onStartEdit:c,onCommitEdit:u,onCancelEdit:d,onSetEditValue:f,showDelete:m,confirmingDelete:h,onDelete:g,onConfirmDelete:_,onViewCell:v,onViewRow:b,pinned:x,onTogglePin:C,pinnedCols:w,pinnedColOffsets:T,stickyTop:E,trRef:D}){let O=x?`bg-muted`:r?`bg-primary/5`:`bg-background`;return(0,k.jsxs)(`tr`,{ref:D,className:`group ${x?``:`hover:bg-muted/30`}`,style:x?{position:`sticky`,top:E,zIndex:15}:void 0,children:[a&&(0,k.jsx)(`td`,{className:`px-2 py-1 border-b border-border/50 ${O}`,style:{position:`sticky`,left:0,zIndex:12},children:(0,k.jsxs)(`span`,{className:`flex items-center gap-0.5`,children:[(0,k.jsx)(`input`,{type:`checkbox`,checked:r,onChange:()=>i(t),className:`size-3 accent-primary`}),(0,k.jsx)(`button`,{type:`button`,title:`View row as JSON`,onClick:()=>b(e),className:`p-0.5 rounded transition-colors text-muted-foreground/30 md:opacity-0 md:group-hover:opacity-100 hover:text-foreground`,children:(0,k.jsx)(l,{className:`size-2.5`})}),(0,k.jsx)(`button`,{type:`button`,title:x?`Unpin row`:`Pin row`,onClick:()=>C(t),className:`p-0.5 rounded transition-colors ${x?`text-primary`:`text-muted-foreground/30 md:opacity-0 md:group-hover:opacity-100 hover:text-foreground`}`,children:x?(0,k.jsx)(S,{className:`size-2.5`}):(0,k.jsx)(y,{className:`size-2.5`})})]})}),n.map(n=>{let r=o?.rowIdx===t&&o?.col===n,i=e[n],p=!r&&P(i),m=w.has(n),h=T.get(n);return(0,k.jsx)(`td`,{className:`px-2 py-1 max-w-[300px] border-b border-border/50 ${m?`border-r border-r-primary/20`:``} ${m||x?O:``}`,style:h==null?void 0:{position:`sticky`,left:h,zIndex:10},children:r?(0,k.jsx)(`input`,{autoFocus:!0,className:`w-full bg-transparent border border-primary/50 rounded px-1 py-0 text-xs outline-none`,value:s,onChange:e=>f(e.target.value),onBlur:u,onKeyDown:e=>{e.key===`Enter`&&u(),e.key===`Escape`&&d()}}):(0,k.jsxs)(`span`,{className:`flex items-center gap-0.5`,children:[(0,k.jsx)(`span`,{className:`cursor-pointer truncate flex-1 ${i==null?`text-muted-foreground/40 italic`:``}`,onDoubleClick:()=>a&&c(t,n,i),title:M(i),children:M(i)}),p&&(0,k.jsx)(`button`,{type:`button`,title:`View full content`,onClick:()=>v({col:n,value:M(i)}),className:`shrink-0 p-0.5 rounded text-muted-foreground/50 hover:text-foreground transition-colors`,children:(0,k.jsx)(l,{className:`size-3`})})]})},n)}),m&&a&&(0,k.jsx)(`td`,{className:`px-2 py-1 border-b border-border/50 ${x?O:``}`,children:h?(0,k.jsxs)(`span`,{className:`flex items-center gap-1 whitespace-nowrap`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>g(t),className:`text-destructive text-[10px] font-medium hover:underline`,children:`Confirm`}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>_(null),className:`text-muted-foreground text-[10px] hover:underline`,children:`Cancel`})]}):(0,k.jsx)(`button`,{type:`button`,onClick:()=>_(t),className:`p-0.5 rounded md:opacity-0 md:group-hover:opacity-100 hover:bg-destructive/10 hover:text-destructive transition-opacity`,title:`Delete row`,children:(0,k.jsx)(p,{className:`size-3`})})})]})});function F(e){let t={},n=/"(\w+)"\s+ILIKE\s+'%([^']*?)%'/gi,r;for(;(r=n.exec(e))!==null;)t[r[1]]=r[2].replace(/''/g,`'`);return t}function I({metadata:e}){let t=e?.connectionId,n=e?.connectionName,r=e?.tableName,i=e?.schemaName??`public`,a=e?.initialSql,o=ne(t),[s,l]=(0,D.useState)([]),[u,d]=(0,D.useState)(180),p=(0,D.useRef)(null),[h,g]=(0,D.useState)({}),_=(0,D.useMemo)(()=>{if(a&&!o.selectedTable)return a;if(o.selectedTable){let e=`SELECT * FROM "${o.selectedTable}"`,t=Object.entries(h).filter(([,e])=>e.trim()).map(([e,t])=>`"${e}" ILIKE '%${t.replace(/'/g,`''`)}%'`);t.length>0&&(e+=` WHERE ${t.join(` AND `)}`),o.orderBy&&(e+=` ORDER BY "${o.orderBy}" ${o.orderDir}`);let n=(o.page-1)*100;return e+=` LIMIT 100`,n>0&&(e+=` OFFSET ${n}`),e}return`SELECT * FROM `},[a,o.selectedTable,o.orderBy,o.orderDir,o.page,h]),v=(0,D.useCallback)(e=>{g(e)},[]),y=(0,D.useRef)(void 0);(0,D.useEffect)(()=>{if(!(!o.selectedTable||Object.keys(h).length===0))return clearTimeout(y.current),y.current=setTimeout(()=>{o.queryAsTable(_)},500),()=>clearTimeout(y.current)},[h]);let x=(0,D.useCallback)(e=>{e.preventDefault();let t=e.clientY,n=u,r=e=>{let r=e.clientY-t;d(Math.max(80,Math.min(n+r,(p.current?.clientHeight??600)-100)))},i=()=>{document.removeEventListener(`mousemove`,r),document.removeEventListener(`mouseup`,i)};document.addEventListener(`mousemove`,r),document.addEventListener(`mouseup`,i)},[u]);(0,D.useEffect)(()=>{m.get(`/api/db/connections/${t}/tables?cached=1`).then(e=>l(e.map(e=>({name:e.name,schema:e.schema})))).catch(()=>{})},[t]);let S=(0,D.useMemo)(()=>{if(s.length!==0)return{tables:s,getColumns:async(e,n)=>await m.get(`/api/db/connections/${t}/schema?table=${encodeURIComponent(e)}${n?`&schema=${encodeURIComponent(n)}`:``}`)}},[t,s]),w=(0,D.useRef)(!1);(0,D.useEffect)(()=>{w.current||(w.current=!0,a?o.executeQuery(a):r&&o.selectTable(r,i))},[r,i,a]);let[T,E]=(0,D.useState)(!!a),O=(0,D.useCallback)(e=>{let t=e.trim();if(o.selectedTable&&RegExp(`^SELECT\\s+\\*\\s+FROM\\s+"?${o.selectedTable.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}"?\\b`,`i`).test(t)){g(F(t)),o.queryAsTable(t);return}E(!0),o.executeQuery(e)},[o.executeQuery,o.queryAsTable,o.selectedTable]),ee=(0,D.useCallback)(e=>{E(!1),o.toggleSort(e)},[o.toggleSort]),te=(0,D.useCallback)(e=>{E(!1),o.setPage(e)},[o.setPage]),A=o.queryResult,M=T&&!!(A||o.queryError),N=o.selectedTable&&!M;return(0,k.jsx)(`div`,{ref:p,className:`flex h-full w-full overflow-hidden`,children:(0,k.jsxs)(`div`,{className:`flex-1 flex flex-col overflow-hidden`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-1.5 border-b border-border bg-background shrink-0`,children:[(0,k.jsx)(c,{className:`size-3.5 text-muted-foreground`}),(0,k.jsx)(`span`,{className:`text-xs text-muted-foreground truncate`,children:n??`Database`}),o.selectedTable&&(0,k.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`/ `,o.selectedTable]}),(0,k.jsxs)(`div`,{className:`ml-auto flex items-center gap-1`,children:[o.tableData&&(0,k.jsx)(re,{columns:o.tableData.columns,rows:o.tableData.rows,filename:n?`${n}-${o.selectedTable??`data`}`:o.selectedTable??`data`,exportAllUrl:o.selectedTable?`/api/db/connections/${t}/export?table=${encodeURIComponent(o.selectedTable)}&schema=${o.selectedSchema}`:void 0}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>o.refreshData(),title:`Reload data`,className:`p-1 rounded text-muted-foreground hover:text-foreground transition-colors`,children:(0,k.jsx)(f,{className:`size-3 ${o.loading?`animate-spin`:``}`})})]})]}),(0,k.jsx)(`div`,{className:`shrink-0 border-b border-border`,style:{height:u},children:(0,k.jsx)(C,{onExecute:O,loading:o.queryLoading,defaultValue:_,schemaInfo:S})}),(0,k.jsx)(`div`,{onMouseDown:x,className:`shrink-0 h-1.5 cursor-row-resize bg-border/50 hover:bg-primary/30 flex items-center justify-center transition-colors`,children:(0,k.jsx)(b,{className:`size-3 text-muted-foreground/50`})}),(0,k.jsxs)(`div`,{className:`flex-1 overflow-hidden`,children:[N&&(0,k.jsx)(j,{tableData:o.tableData,schema:o.schema,loading:o.loading,page:o.page,onPageChange:te,onCellUpdate:o.updateCell,onRowDelete:o.deleteRow,orderBy:o.orderBy,orderDir:o.orderDir,onToggleSort:ee,onBulkDelete:o.bulkDelete,onInsertRow:o.insertRow,connectionId:t,selectedTable:o.selectedTable,selectedSchema:o.selectedSchema,connectionName:n,columnFilters:h,onColumnFilter:v}),M&&(0,k.jsx)(R,{result:A,error:o.queryError,loading:o.queryLoading,schema:o.schema,connectionName:n})]})]})})}var L=()=>{};function R({result:e,error:t,loading:n,schema:r,connectionName:i}){let a=(0,D.useMemo)(()=>e?.changeType===`select`&&e.rows.length>0?{columns:e.columns,rows:e.rows,total:e.rows.length,limit:e.rows.length}:null,[e]),o=(0,D.useMemo)(()=>r?.length?r:(e?.columns??[]).map(e=>({name:e,type:`text`,nullable:!0,pk:!1,defaultValue:null})),[r,e?.columns]);return(0,k.jsxs)(`div`,{className:`flex flex-col h-full overflow-hidden text-xs`,children:[t&&(0,k.jsx)(`div`,{className:`px-3 py-2 text-destructive bg-destructive/5 shrink-0`,children:t}),e?.changeType===`modify`&&(0,k.jsxs)(`div`,{className:`px-3 py-2 text-green-500 shrink-0`,children:[e.rowsAffected,` row(s) affected`,e.executionTimeMs!=null&&(0,k.jsxs)(`span`,{className:`text-muted-foreground ml-2`,children:[e.executionTimeMs,`ms`]})]}),a&&(0,k.jsxs)(`div`,{className:`flex-1 overflow-hidden`,children:[(0,k.jsx)(j,{tableData:a,schema:o,loading:!!n,page:1,onPageChange:L,onCellUpdate:L,orderBy:null,orderDir:`ASC`,onToggleSort:L,connectionName:i}),e?.executionTimeMs!=null&&(0,k.jsxs)(`div`,{className:`px-3 py-0.5 border-t border-border text-[10px] text-muted-foreground shrink-0`,children:[e.rows.length,` rows · `,e.executionTimeMs,`ms`]})]}),e?.changeType===`select`&&e.rows.length===0&&(0,k.jsxs)(`div`,{className:`px-3 py-2 text-muted-foreground shrink-0`,children:[`No results`,e.executionTimeMs!=null&&(0,k.jsxs)(`span`,{className:`ml-2 text-muted-foreground/60`,children:[e.executionTimeMs,`ms`]})]}),!e&&!t&&(0,k.jsx)(`div`,{className:`flex items-center justify-center h-full text-muted-foreground`,children:n?(0,k.jsx)(v,{className:`size-4 animate-spin`}):`Run a query to see results`})]})}export{I as DatabaseViewer};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-0Mxgxy0L.js";import"./api-client-Bn-Pi9k5.js";import{o as e}from"./keybindings-store-C9KsBH7z.js";export{e as useKeybindingsStore};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-0Mxgxy0L.js";import"./vendor-ui-B-T_damt.js";import"./scroll-area-DW7L4Gnc.js";import"./ai-settings-section-C6FDY8qE.js";import"./dist-C5IgeqrV.js";import"./input-ClhO__YM.js";import"./api-client-Bn-Pi9k5.js";import"./vendor-mermaid-BlWh9BJO.js";import"./settings-store-B9axDbuA.js";import"./keybindings-store-C9KsBH7z.js";import"./extension-store-3yZYn07W.js";import"./api-settings-C__hxGX2.js";import{s as e}from"./index-Bl3W1FYm.js";export{e as SettingsTab};
|