@hienlh/ppm 0.13.48 → 0.13.49
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/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/{audio-preview-BFc4v5Tx.js → audio-preview-CQ-l5P8I.js} +2 -2
- package/dist/web/assets/{audio-preview-BFc4v5Tx.js.map → audio-preview-CQ-l5P8I.js.map} +1 -1
- package/dist/web/assets/{chat-tab-x1rBGHj5.js → chat-tab-DbuBr2ax.js} +4 -4
- package/dist/web/assets/{chat-tab-x1rBGHj5.js.map → chat-tab-DbuBr2ax.js.map} +1 -1
- package/dist/web/assets/{code-editor-BgyAZcQX.js → code-editor-DEa0t62y.js} +3 -3
- package/dist/web/assets/{code-editor-BgyAZcQX.js.map → code-editor-DEa0t62y.js.map} +1 -1
- package/dist/web/assets/{conflict-editor-Dhc1lem7.js → conflict-editor-D5H9urYy.js} +2 -2
- package/dist/web/assets/{conflict-editor-Dhc1lem7.js.map → conflict-editor-D5H9urYy.js.map} +1 -1
- package/dist/web/assets/{database-viewer-DnnjO38W.js → database-viewer-CW60ytCl.js} +2 -2
- package/dist/web/assets/{database-viewer-DnnjO38W.js.map → database-viewer-CW60ytCl.js.map} +1 -1
- package/dist/web/assets/{diff-viewer-B6q9wXD6.js → diff-viewer-BfatMgWw.js} +2 -2
- package/dist/web/assets/{diff-viewer-B6q9wXD6.js.map → diff-viewer-BfatMgWw.js.map} +1 -1
- package/dist/web/assets/{extension-webview-CMBEb4FF.js → extension-webview-DKSDoW_g.js} +2 -2
- package/dist/web/assets/{extension-webview-CMBEb4FF.js.map → extension-webview-DKSDoW_g.js.map} +1 -1
- package/dist/web/assets/{glide-data-grid-BLcBAxgp.js → glide-data-grid-Bx48618B.js} +2 -2
- package/dist/web/assets/{glide-data-grid-BLcBAxgp.js.map → glide-data-grid-Bx48618B.js.map} +1 -1
- package/dist/web/assets/{image-preview-YpWk7AOb.js → image-preview-ClY2xl1B.js} +2 -2
- package/dist/web/assets/{image-preview-YpWk7AOb.js.map → image-preview-ClY2xl1B.js.map} +1 -1
- package/dist/web/assets/{index-hxAGD2rx.js → index-DkQ6jVSH.js} +5 -5
- package/dist/web/assets/{index-hxAGD2rx.js.map → index-DkQ6jVSH.js.map} +1 -1
- package/dist/web/assets/keybindings-store-DrAeg6Gw.js +1 -0
- package/dist/web/assets/{markdown-renderer-BAAmsTL9.js → markdown-renderer-BmMmo0F-.js} +2 -2
- package/dist/web/assets/{markdown-renderer-BAAmsTL9.js.map → markdown-renderer-BmMmo0F-.js.map} +1 -1
- package/dist/web/assets/notification-store-Bukl8bKo.js +1 -0
- package/dist/web/assets/{pdf-preview-DWe7ARXI.js → pdf-preview-YylEP_Su.js} +2 -2
- package/dist/web/assets/{pdf-preview-DWe7ARXI.js.map → pdf-preview-YylEP_Su.js.map} +1 -1
- package/dist/web/assets/{port-forwarding-tab-R5V7zkKO.js → port-forwarding-tab-COdo70kU.js} +2 -2
- package/dist/web/assets/{port-forwarding-tab-R5V7zkKO.js.map → port-forwarding-tab-COdo70kU.js.map} +1 -1
- package/dist/web/assets/{postgres-viewer-AxCUyDQP.js → postgres-viewer-3y9VshZZ.js} +2 -2
- package/dist/web/assets/{postgres-viewer-AxCUyDQP.js.map → postgres-viewer-3y9VshZZ.js.map} +1 -1
- package/dist/web/assets/{settings-tab-CJ6w6q2s.js → settings-tab-sYavdJk-.js} +1 -1
- package/dist/web/assets/{sql-query-editor-DhZvNbKv.js → sql-query-editor-DlBYx1Ye.js} +2 -2
- package/dist/web/assets/{sql-query-editor-DhZvNbKv.js.map → sql-query-editor-DlBYx1Ye.js.map} +1 -1
- package/dist/web/assets/{sqlite-viewer-Qv8TlhPb.js → sqlite-viewer-Bj8oPYho.js} +2 -2
- package/dist/web/assets/{sqlite-viewer-Qv8TlhPb.js.map → sqlite-viewer-Bj8oPYho.js.map} +1 -1
- package/dist/web/assets/{terminal-tab-9hLQtUUT.js → terminal-tab-B7ECmf95.js} +2 -2
- package/dist/web/assets/{terminal-tab-9hLQtUUT.js.map → terminal-tab-B7ECmf95.js.map} +1 -1
- package/dist/web/assets/{video-preview-C-tj7tok.js → video-preview-CT78iZBo.js} +2 -2
- package/dist/web/assets/{video-preview-C-tj7tok.js.map → video-preview-CT78iZBo.js.map} +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/src/services/db.service.ts +28 -0
- package/src/types/extension.ts +1 -1
- package/src/web/components/settings/extension-manager-section.tsx +2 -2
- package/dist/web/assets/keybindings-store-Dn9ANcCK.js +0 -1
- package/dist/web/assets/notification-store-DyVQiPv9.js +0 -1
- package/packages/ext-database/package.json +0 -48
- package/packages/ext-database/src/connection-tree.ts +0 -201
- package/packages/ext-database/src/extension.ts +0 -578
- package/packages/ext-database/src/query-panel.ts +0 -133
- package/packages/ext-database/src/table-viewer-panel.ts +0 -420
- package/packages/ext-database/tsconfig.json +0 -8
|
@@ -97,7 +97,7 @@ export function ExtensionManagerSection() {
|
|
|
97
97
|
value={installName}
|
|
98
98
|
onChange={(e) => setInstallName(e.target.value)}
|
|
99
99
|
onKeyDown={(e) => { if (e.key === "Enter") handleInstall(); }}
|
|
100
|
-
placeholder="npm package name (e.g. @ppm/ext-
|
|
100
|
+
placeholder="npm package name (e.g. @ppm/ext-myext)"
|
|
101
101
|
className="h-8 text-xs flex-1"
|
|
102
102
|
/>
|
|
103
103
|
<Button
|
|
@@ -122,7 +122,7 @@ export function ExtensionManagerSection() {
|
|
|
122
122
|
<Input
|
|
123
123
|
value={devPath}
|
|
124
124
|
onChange={(e) => setDevPath(e.target.value)}
|
|
125
|
-
placeholder="Local path (e.g. ./packages/ext-
|
|
125
|
+
placeholder="Local path (e.g. ./packages/ext-myext)"
|
|
126
126
|
className="h-8 text-xs flex-1"
|
|
127
127
|
/>
|
|
128
128
|
<Button
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-0Mxgxy0L.js";import"./api-client-DIhJ5qVW.js";import{T as e}from"./index-hxAGD2rx.js";export{e as useKeybindingsStore};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-0Mxgxy0L.js";import"./api-client-DIhJ5qVW.js";import{j as e}from"./index-hxAGD2rx.js";export{e as useNotificationStore};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@ppm/ext-database",
|
|
3
|
-
"version": "0.1.0",
|
|
4
|
-
"main": "src/extension.ts",
|
|
5
|
-
"engines": { "ppm": ">=0.9.0" },
|
|
6
|
-
"activationEvents": ["onCommand:ppm-db.openViewer", "onView:ppm-db.connections"],
|
|
7
|
-
"contributes": {
|
|
8
|
-
"commands": [
|
|
9
|
-
{ "command": "ppm-db.openViewer", "title": "Database: Open Viewer" },
|
|
10
|
-
{ "command": "ppm-db.runQuery", "title": "Database: Run SQL Query" },
|
|
11
|
-
{ "command": "ppm-db.refreshConnections", "title": "Database: Refresh Connections", "icon": "refresh" },
|
|
12
|
-
{ "command": "ppm-db.addConnection", "title": "Add connection", "icon": "plus" },
|
|
13
|
-
{ "command": "ppm-db.editConnection", "title": "Database: Edit Connection" },
|
|
14
|
-
{ "command": "ppm-db.deleteConnection", "title": "Database: Delete Connection" },
|
|
15
|
-
{ "command": "ppm-db.testConnection", "title": "Database: Test Connection" },
|
|
16
|
-
{ "command": "ppm-db.exportConnections", "title": "Database: Export Connections" },
|
|
17
|
-
{ "command": "ppm-db.importConnections", "title": "Database: Import Connections" }
|
|
18
|
-
],
|
|
19
|
-
"views": {
|
|
20
|
-
"sidebar": [
|
|
21
|
-
{ "id": "ppm-db.connections", "name": "DB Connections", "type": "tree" }
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
"menus": {
|
|
25
|
-
"commandPalette": [
|
|
26
|
-
{ "command": "ppm-db.openViewer" },
|
|
27
|
-
{ "command": "ppm-db.runQuery" },
|
|
28
|
-
{ "command": "ppm-db.exportConnections" },
|
|
29
|
-
{ "command": "ppm-db.importConnections" }
|
|
30
|
-
],
|
|
31
|
-
"view/title": [
|
|
32
|
-
{ "command": "ppm-db.refreshConnections", "when": "view == ppm-db.connections", "group": "navigation" },
|
|
33
|
-
{ "command": "ppm-db.addConnection", "when": "view == ppm-db.connections", "group": "navigation" }
|
|
34
|
-
]
|
|
35
|
-
},
|
|
36
|
-
"configuration": {
|
|
37
|
-
"properties": {
|
|
38
|
-
"ppm-db.maxRows": { "type": "number", "default": 100, "description": "Max rows to display" },
|
|
39
|
-
"ppm-db.autoConnect": { "type": "boolean", "default": true, "description": "Auto-connect on open" }
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
"ppm": {
|
|
44
|
-
"displayName": "Database Viewer",
|
|
45
|
-
"icon": "database",
|
|
46
|
-
"webviewDir": "webview"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TreeDataProvider for database connections → tables → columns.
|
|
3
|
-
* Fetches data from PPM REST API (/api/db/*).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
interface ConnectionNode {
|
|
7
|
-
id: string;
|
|
8
|
-
name: string;
|
|
9
|
-
type: "connection" | "group" | "table" | "column";
|
|
10
|
-
connectionId?: number;
|
|
11
|
-
connectionName?: string;
|
|
12
|
-
connectionType?: string;
|
|
13
|
-
connectionColor?: string | null;
|
|
14
|
-
connectionReadonly?: number;
|
|
15
|
-
groupName?: string | null;
|
|
16
|
-
schemaName?: string;
|
|
17
|
-
dataType?: string;
|
|
18
|
-
rowCount?: number;
|
|
19
|
-
children?: ConnectionNode[];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface ApiConnection {
|
|
23
|
-
id: number;
|
|
24
|
-
name: string;
|
|
25
|
-
type: string;
|
|
26
|
-
color: string | null;
|
|
27
|
-
readonly: number;
|
|
28
|
-
group_name: string | null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface ApiTable {
|
|
32
|
-
name: string;
|
|
33
|
-
schema: string;
|
|
34
|
-
rowCount: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface ApiColumn {
|
|
38
|
-
name: string;
|
|
39
|
-
type: string;
|
|
40
|
-
nullable: boolean;
|
|
41
|
-
pk: boolean;
|
|
42
|
-
defaultValue: string | null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export class ConnectionTreeProvider {
|
|
46
|
-
private _onDidChange: { fire: (el?: ConnectionNode) => void; event: unknown };
|
|
47
|
-
private baseUrl: string;
|
|
48
|
-
|
|
49
|
-
constructor(eventEmitter: { fire: (el?: ConnectionNode) => void; event: unknown }, baseUrl = "") {
|
|
50
|
-
this._onDidChange = eventEmitter;
|
|
51
|
-
this.baseUrl = baseUrl;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
get onDidChangeTreeData() {
|
|
55
|
-
return this._onDidChange.event;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
refresh(): void {
|
|
59
|
-
this._onDidChange.fire(undefined);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async getChildren(element?: ConnectionNode): Promise<ConnectionNode[]> {
|
|
63
|
-
if (!element) return this.getRootNodes();
|
|
64
|
-
if (element.type === "group") return element.children ?? [];
|
|
65
|
-
if (element.type === "connection") return this.getTables(element);
|
|
66
|
-
if (element.type === "table") return this.getColumns(element);
|
|
67
|
-
return [];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
getTreeItem(element: ConnectionNode): Record<string, unknown> {
|
|
71
|
-
const isConn = element.type === "connection";
|
|
72
|
-
const isGroup = element.type === "group";
|
|
73
|
-
const isTable = element.type === "table";
|
|
74
|
-
const isCol = element.type === "column";
|
|
75
|
-
|
|
76
|
-
// Table description: row count
|
|
77
|
-
let description: string | undefined;
|
|
78
|
-
if (isCol) description = element.dataType;
|
|
79
|
-
else if (isTable && element.rowCount !== undefined) description = `${element.rowCount.toLocaleString()} rows`;
|
|
80
|
-
|
|
81
|
-
// Connection badge: type + readonly
|
|
82
|
-
let badge: string | undefined;
|
|
83
|
-
if (isConn) {
|
|
84
|
-
badge = element.connectionType === "postgres" ? "PG" : "DB";
|
|
85
|
-
if (element.connectionReadonly === 1) badge += " 🔒";
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
id: element.id,
|
|
90
|
-
label: element.name,
|
|
91
|
-
description,
|
|
92
|
-
collapsibleState: isCol ? "none" : "collapsed",
|
|
93
|
-
contextValue: element.type,
|
|
94
|
-
command: isTable ? "ppm-db.openViewer" : undefined,
|
|
95
|
-
commandArgs: isTable
|
|
96
|
-
? [element.connectionId, element.connectionName ?? "Database", element.name, element.schemaName ?? "public"]
|
|
97
|
-
: undefined,
|
|
98
|
-
color: isConn ? (element.connectionColor ?? undefined) : undefined,
|
|
99
|
-
badge,
|
|
100
|
-
actions: isConn ? [
|
|
101
|
-
{ icon: "refresh", tooltip: "Refresh tables", command: "ppm-db.refreshConnection", commandArgs: [element.connectionId] },
|
|
102
|
-
{ icon: "edit", tooltip: "Edit connection", command: "ppm-db.editConnection", commandArgs: [element.connectionId] },
|
|
103
|
-
{ icon: "trash", tooltip: "Delete connection", command: "ppm-db.deleteConnection", commandArgs: [element.connectionId, element.name] },
|
|
104
|
-
] : isGroup ? [] : undefined,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** Build root tree: group nodes wrapping connection nodes, or flat if no groups */
|
|
109
|
-
private async getRootNodes(): Promise<ConnectionNode[]> {
|
|
110
|
-
const connections = await this.getConnections();
|
|
111
|
-
// Group by group_name
|
|
112
|
-
const groups = new Map<string, ConnectionNode[]>();
|
|
113
|
-
for (const conn of connections) {
|
|
114
|
-
const key = conn.groupName ?? "__ungrouped__";
|
|
115
|
-
const list = groups.get(key) ?? [];
|
|
116
|
-
list.push(conn);
|
|
117
|
-
groups.set(key, list);
|
|
118
|
-
}
|
|
119
|
-
// If only one group (ungrouped), return connections flat
|
|
120
|
-
if (groups.size <= 1 && groups.has("__ungrouped__")) {
|
|
121
|
-
return connections;
|
|
122
|
-
}
|
|
123
|
-
// Build group nodes
|
|
124
|
-
const result: ConnectionNode[] = [];
|
|
125
|
-
const sortedKeys = Array.from(groups.keys()).sort((a, b) => {
|
|
126
|
-
if (a === "__ungrouped__") return 1;
|
|
127
|
-
if (b === "__ungrouped__") return -1;
|
|
128
|
-
return a.localeCompare(b);
|
|
129
|
-
});
|
|
130
|
-
for (const key of sortedKeys) {
|
|
131
|
-
const label = key === "__ungrouped__" ? "Ungrouped" : key;
|
|
132
|
-
result.push({
|
|
133
|
-
id: `group:${key}`,
|
|
134
|
-
name: label,
|
|
135
|
-
type: "group",
|
|
136
|
-
children: groups.get(key) ?? [],
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private async getConnections(): Promise<ConnectionNode[]> {
|
|
143
|
-
try {
|
|
144
|
-
const res = await fetch(`${this.baseUrl}/api/db/connections`);
|
|
145
|
-
const json = await res.json() as { ok: boolean; data?: ApiConnection[] };
|
|
146
|
-
if (!json.ok || !json.data) return [];
|
|
147
|
-
return json.data.map((c) => ({
|
|
148
|
-
id: `conn:${c.id}`,
|
|
149
|
-
name: c.name,
|
|
150
|
-
type: "connection" as const,
|
|
151
|
-
connectionId: c.id,
|
|
152
|
-
connectionType: c.type,
|
|
153
|
-
connectionColor: c.color,
|
|
154
|
-
connectionReadonly: c.readonly,
|
|
155
|
-
groupName: c.group_name,
|
|
156
|
-
}));
|
|
157
|
-
} catch {
|
|
158
|
-
return [];
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
private async getTables(conn: ConnectionNode): Promise<ConnectionNode[]> {
|
|
163
|
-
try {
|
|
164
|
-
const res = await fetch(`${this.baseUrl}/api/db/connections/${conn.connectionId}/tables`);
|
|
165
|
-
const json = await res.json() as { ok: boolean; data?: ApiTable[] };
|
|
166
|
-
if (!json.ok || !json.data) return [];
|
|
167
|
-
return json.data.map((t) => ({
|
|
168
|
-
id: `table:${conn.connectionId}:${t.schema}.${t.name}`,
|
|
169
|
-
name: t.name,
|
|
170
|
-
type: "table" as const,
|
|
171
|
-
connectionId: conn.connectionId,
|
|
172
|
-
connectionName: conn.name,
|
|
173
|
-
connectionType: conn.connectionType,
|
|
174
|
-
schemaName: t.schema,
|
|
175
|
-
rowCount: t.rowCount,
|
|
176
|
-
}));
|
|
177
|
-
} catch {
|
|
178
|
-
return [];
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
private async getColumns(table: ConnectionNode): Promise<ConnectionNode[]> {
|
|
183
|
-
try {
|
|
184
|
-
const schema = table.schemaName ?? "public";
|
|
185
|
-
const res = await fetch(
|
|
186
|
-
`${this.baseUrl}/api/db/connections/${table.connectionId}/schema?table=${encodeURIComponent(table.name)}&schema=${schema}`,
|
|
187
|
-
);
|
|
188
|
-
const json = await res.json() as { ok: boolean; data?: ApiColumn[] };
|
|
189
|
-
if (!json.ok || !json.data) return [];
|
|
190
|
-
return json.data.map((c) => ({
|
|
191
|
-
id: `col:${table.connectionId}:${table.name}.${c.name}`,
|
|
192
|
-
name: c.name,
|
|
193
|
-
type: "column" as const,
|
|
194
|
-
connectionId: table.connectionId,
|
|
195
|
-
dataType: c.type + (c.pk ? " PK" : ""),
|
|
196
|
-
}));
|
|
197
|
-
} catch {
|
|
198
|
-
return [];
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|