Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package: build
vsce package

# publish the extension to VS Code Marketplace and Open VSX Registry
publish: package
publish: package git-tag
@echo "Publishing to VS Code Marketplace..."
test -f ./pat || (echo "Error: pat file not found" && exit 1)
vsce publish -p $(shell cat ./pat)
Expand All @@ -32,13 +32,13 @@ publish: package
@echo "Publishing to Open VSX Registry..."

# Publish the extension to VS Code Marketplace
publish-vsx: package
publish-vsx: package git-tag
@echo "Publishing to VS Code Marketplace..."
test -f ./pat || (echo "Error: pat file not found" && exit 1)
vsce publish -p $(shell cat ./pat)

# Publish the extension to Open VSX Registry
publish-ovsx: package
publish-ovsx: package git-tag
@echo "Publishing to Open VSX Registry..."
test -f ./pat-open-vsx || (echo "Error: pat-open-vsx file not found" && exit 1)
ovsx publish -p $(shell cat ./pat-open-vsx)
Expand All @@ -47,6 +47,16 @@ publish-ovsx: package
watch:
yarn run watch

git-tag:
@echo "Creating a new git tag..."
@read -p "Enter the version number (e.g., 1.0.0): " version; \
git tag -a "$$version" -m "Release $$version"; \
git push origin "$$version"; \
echo "Git tag $$version created and pushed."
@echo "Updating package.json version to $$version..."
@jq --arg version "$$version" '.version = $$version' package.json > tmp.json && mv tmp.json package.json
@echo "package.json version updated to $$version."

# Help target
help:
@echo "Available targets:"
Expand Down
31 changes: 8 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "postgres-explorer",
"displayName": "PostgreSQL Explorer",
"version": "0.0.11",
"version": "0.1.3",
"description": "PostgreSQL database explorer for VS Code with notebook support",
"publisher": "ric-v",
"private": false,
Expand Down Expand Up @@ -111,11 +111,6 @@
"title": "Drop Function",
"icon": "$(trash)"
},
{
"command": "postgres-explorer.editTableDefinition",
"title": "Edit Table Definition",
"icon": "$(edit)"
},
{
"command": "postgres-explorer.viewTableData",
"title": "View Table Data",
Expand Down Expand Up @@ -523,7 +518,7 @@
},
{
"command": "postgres-explorer.newNotebook",
"when": "view == postgresExplorer && viewItem =~ /(database|schema|table)/",
"when": "view == postgresExplorer && viewItem =~ /(schema|table)/",
"group": "inline@1"
},
{
Expand Down Expand Up @@ -566,11 +561,6 @@
"when": "view == postgresExplorer && viewItem == function",
"group": "1_actions@3"
},
{
"command": "postgres-explorer.editTableDefinition",
"when": "view == postgresExplorer && viewItem == table",
"group": "inline@1"
},
{
"command": "postgres-explorer.viewTableData",
"when": "view == postgresExplorer && viewItem == table",
Expand Down Expand Up @@ -803,23 +793,18 @@
{
"command": "postgres-explorer.createInDatabase",
"when": "view == postgresExplorer && viewItem == database",
"group": "inline@1"
},
{
"command": "postgres-explorer.databaseOperations",
"when": "view == postgresExplorer && viewItem == database",
"group": "inline@2"
"group": "inline@1",
"icon": "$(add)"
},
{
"command": "postgres-explorer.showDashboard",
"when": "view == postgresExplorer && viewItem == database",
"group": "inline@0",
"icon": "$(graph)"
"group": "1_operations@1"
},
{
"command": "postgres-explorer.editTable",
"when": "view == postgresExplorer && viewItem == table",
"group": "inline@1"
"command": "postgres-explorer.databaseOperations",
"when": "view == postgresExplorer && viewItem == database",
"group": "1_operations@3"
}
]
}
Expand Down
79 changes: 46 additions & 33 deletions src/databaseTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export class DatabaseTreeProvider implements vscode.TreeDataProvider<DatabaseTre
this._onDidChangeTreeData.fire();
}

collapseAll(): void {
// This will trigger a refresh of the tree view with all items collapsed
this._onDidChangeTreeData.fire();
}

getTreeItem(element: DatabaseTreeItem): vscode.TreeItem {
return element;
}
Expand Down Expand Up @@ -102,6 +107,14 @@ export class DatabaseTreeProvider implements vscode.TreeDataProvider<DatabaseTre

switch (element.type) {
case 'connection':
// At connection level, show Databases group and Users & Roles
return [
new DatabaseTreeItem('Databases', vscode.TreeItemCollapsibleState.Collapsed, 'databases-group', element.connectionId),
new DatabaseTreeItem('Users & Roles', vscode.TreeItemCollapsibleState.Collapsed, 'category', element.connectionId)
];

case 'databases-group':
// Show all databases under the Databases group
const dbResult = await client.query(
"SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres' ORDER BY datname"
);
Expand All @@ -117,12 +130,41 @@ export class DatabaseTreeProvider implements vscode.TreeDataProvider<DatabaseTre
// Return just the categories at database level
return [
new DatabaseTreeItem('Schemas', vscode.TreeItemCollapsibleState.Collapsed, 'category', element.connectionId, element.databaseName),
new DatabaseTreeItem('Extensions', vscode.TreeItemCollapsibleState.Collapsed, 'category', element.connectionId, element.databaseName),
new DatabaseTreeItem('Users & Roles', vscode.TreeItemCollapsibleState.Collapsed, 'category', element.connectionId, element.databaseName)
new DatabaseTreeItem('Extensions', vscode.TreeItemCollapsibleState.Collapsed, 'category', element.connectionId, element.databaseName)
];

case 'category':
switch (element.label) {
case 'Users & Roles':
const roleResult = await client.query(
`SELECT r.rolname,
r.rolsuper,
r.rolcreatedb,
r.rolcreaterole,
r.rolcanlogin
FROM pg_roles r
ORDER BY r.rolname`
);
return roleResult.rows.map(row => new DatabaseTreeItem(
row.rolname,
vscode.TreeItemCollapsibleState.None,
'role',
element.connectionId,
element.databaseName,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
{
rolsuper: row.rolsuper,
rolcreatedb: row.rolcreatedb,
rolcreaterole: row.rolcreaterole,
rolcanlogin: row.rolcanlogin
}
));

case 'Schemas':
const schemaResult = await client.query(
`SELECT nspname as schema_name
Expand Down Expand Up @@ -164,36 +206,6 @@ export class DatabaseTreeProvider implements vscode.TreeDataProvider<DatabaseTre
row.installed_version
));

case 'Users & Roles':
const roleResult = await client.query(
`SELECT r.rolname,
r.rolsuper,
r.rolcreatedb,
r.rolcreaterole,
r.rolcanlogin
FROM pg_roles r
ORDER BY r.rolname`
);
return roleResult.rows.map(row => new DatabaseTreeItem(
row.rolname,
vscode.TreeItemCollapsibleState.None,
'role',
element.connectionId,
element.databaseName,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
{
rolsuper: row.rolsuper,
rolcreatedb: row.rolcreatedb,
rolcreaterole: row.rolcreaterole,
rolcanlogin: row.rolcanlogin
}
));

// Existing category cases for schema level items
case 'Tables':
const tableResult = await client.query(
Expand Down Expand Up @@ -334,7 +346,7 @@ export class DatabaseTreeItem extends vscode.TreeItem {
constructor(
public readonly label: string,
public readonly collapsibleState: vscode.TreeItemCollapsibleState,
public readonly type: 'connection' | 'database' | 'schema' | 'table' | 'view' | 'function' | 'column' | 'category' | 'materialized-view' | 'type' | 'foreign-table' | 'extension' | 'role',
public readonly type: 'connection' | 'database' | 'schema' | 'table' | 'view' | 'function' | 'column' | 'category' | 'materialized-view' | 'type' | 'foreign-table' | 'extension' | 'role' | 'databases-group',
public readonly connectionId?: string,
public readonly databaseName?: string,
public readonly schema?: string,
Expand All @@ -352,6 +364,7 @@ export class DatabaseTreeItem extends vscode.TreeItem {
this.iconPath = {
connection: new vscode.ThemeIcon('plug'),
database: new vscode.ThemeIcon('database'),
'databases-group': new vscode.ThemeIcon('database'),
schema: new vscode.ThemeIcon('symbol-namespace'),
table: new vscode.ThemeIcon('table'),
view: new vscode.ThemeIcon('type-hierarchy-sub'),
Expand Down
46 changes: 21 additions & 25 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { cmdTableOperations, cmdDropTable, cmdEditTable, cmdInsertTable, cmdShow
import { cmdAllOperationsTypes, cmdDropType, cmdEditTypes, cmdShowTypeProperties } from './subscriptions/types';
import { cmdAddRole, cmdAddUser, cmdRoleOperations, cmdDropRole, cmdEditRole, cmdGrantRevokeRole, cmdShowRoleProperties } from './subscriptions/usersRoles';
import { cmdViewOperations, cmdDropView, cmdEditView, cmdShowViewProperties, cmdViewData } from './subscriptions/views';
import { cmdDisconnectDatabase, cmdDisconnectConnection, cmdConnectDatabase } from './subscriptions/connection';

export async function activate(context: vscode.ExtensionContext) {
console.log('postgres-explorer: Activating extension');
Expand All @@ -26,10 +27,12 @@ export async function activate(context: vscode.ExtensionContext) {
// Create database tree provider instance
const databaseTreeProvider = new DatabaseTreeProvider(context);

// Register tree data provider
context.subscriptions.push(
vscode.window.registerTreeDataProvider('postgresExplorer', databaseTreeProvider)
);
// Register tree data provider and create tree view
const treeView = vscode.window.createTreeView('postgresExplorer', {
treeDataProvider: databaseTreeProvider,
showCollapseAll: true
});
context.subscriptions.push(treeView);

// Create kernel with message handler
const kernel = new PostgresKernel(context, async (message: { type: string; command: string; format?: string; content?: string; filename?: string }) => {
Expand Down Expand Up @@ -68,27 +71,7 @@ export async function activate(context: vscode.ExtensionContext) {
},
{
command: 'postgres-explorer.connect',
callback: async () => {
try {
const connectionString = await vscode.window.showInputBox({
prompt: 'Enter PostgreSQL connection string',
placeHolder: 'postgresql://user:password@localhost:5432/dbname'
});

if (!connectionString) {
return;
}

const client = new Client(connectionString);
await client.connect();
vscode.window.showInformationMessage('Connected to PostgreSQL database');
databaseTreeProvider.refresh();
await client.end();
} catch (err: any) {
const errorMessage = err?.message || 'Unknown error occurred';
vscode.window.showErrorMessage(`Failed to connect: ${errorMessage}`);
}
}
callback: async (item: any) => await cmdConnectDatabase(item, context, databaseTreeProvider)
},
{
command: 'postgres-explorer.disconnect',
Expand Down Expand Up @@ -312,6 +295,19 @@ export async function activate(context: vscode.ExtensionContext) {
{
command: 'postgres-explorer.dropExtension',
callback: async (item: DatabaseTreeItem) => await cmdDropExtension(item, context)
},
// Add connection commands
{
command: 'postgres-explorer.disconnectConnection',
callback: async (item: DatabaseTreeItem) => await cmdDisconnectConnection(item, context, databaseTreeProvider)
},
{
command: 'postgres-explorer.deleteConnection',
callback: async (item: DatabaseTreeItem) => await cmdDisconnectDatabase(item, context, databaseTreeProvider)
},
{
command: 'postgres-explorer.addConnection',
callback: () => ConnectionFormPanel.show(context.extensionUri, context)
}
];

Expand Down
36 changes: 36 additions & 0 deletions src/subscriptions/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,40 @@ export async function cmdDisconnectDatabase(item: DatabaseTreeItem, context: vsc
vscode.window.showErrorMessage(`Failed to delete connection: ${err.message}`);
}
}
}

export async function cmdDisconnectConnection(item: DatabaseTreeItem, context: vscode.ExtensionContext, databaseTreeProvider?: DatabaseTreeProvider) {
try {
if (!item?.connectionId) {
throw new Error('Invalid connection selection');
}

// Refresh the tree view which will collapse all items and close any open connections
databaseTreeProvider?.refresh();
vscode.window.showInformationMessage(`Disconnected from '${item.label}'`);
} catch (err: any) {
vscode.window.showErrorMessage(`Failed to disconnect: ${err.message}`);
}
}

export async function cmdConnectDatabase(item: DatabaseTreeItem, context: vscode.ExtensionContext, databaseTreeProvider?: DatabaseTreeProvider) {
try {
const connectionString = await vscode.window.showInputBox({
prompt: 'Enter PostgreSQL connection string',
placeHolder: 'postgresql://user:password@localhost:5432/dbname'
});

if (!connectionString) {
return;
}

const client = new Client(connectionString);
await client.connect();
vscode.window.showInformationMessage('Connected to PostgreSQL database');
databaseTreeProvider?.refresh();
await client.end();
} catch (err: any) {
const errorMessage = err?.message || 'Unknown error occurred';
vscode.window.showErrorMessage(`Failed to connect: ${errorMessage}`);
}
}
Loading
Loading