diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f46eff..1bd9e5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to Simple DB are documented in this file. -## Unreleased +## 0.1.2 - 2026-08-08 ### Added @@ -10,11 +10,17 @@ All notable changes to Simple DB are documented in this file. - Automatic migration of existing 0.1.1 connection profiles to JSON files. - `Open Connection JSON`, `Set Password`, and `Open Connections Folder` actions. - A native `Simple DB` editor context submenu containing the six main database actions. +- A resizable `Simple DB` Results view in the lower VS Code Panel, with a SQL Developer-style data grid and row numbers. ### Changed - Simplified connection creation: choose the engine and name, optionally enter a secure network password, then edit all non-secret connection parameters together in JSON. - Passwords remain in VS Code `SecretStorage` and are explicitly rejected from connection JSON files. +- Query results now open below the SQL editor instead of in a separate editor tab, keeping the SQL document visible while results are inspected. + +### Fixed + +- Fixed the Results webview script error that could leave successful `SELECT` queries stuck on `Loading results…`. ## 0.1.1 - 2026-08-07 diff --git a/README.md b/README.md index 85fc5a3..d759412 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Simple DB -Simple DB `0.1.1` is a Visual Studio Code extension written entirely in JavaScript for working with **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle** through a single interface. +Simple DB `0.1.2` is a Visual Studio Code extension written entirely in JavaScript for working with **SQLite, PostgreSQL, MySQL, SQL Server, and Oracle** through a single interface. The extension opens regular VS Code SQL documents. `F5` launches `src/extension.js` directly: there is no TypeScript, `tsconfig.json`, `dist` folder, or compilation step. @@ -17,11 +17,19 @@ The extension opens regular VS Code SQL documents. `F5` launches `src/extension. - Generate `CREATE`, `ALTER`, and `DROP` scripts from the explorer and inspect object definitions/DDL. - Use explicit per-editor transactions with `BEGIN`, `COMMIT`, and `ROLLBACK`. - Cancel queries and configure query timeouts per connection. -- View results with multiple result sets, types, `NULL`, affected rows, duration, and cell/row/selection copy actions. +- View results below the SQL editor in a resizable SQL Developer-style grid with row numbers, multiple result sets, types, `NULL`, affected rows, duration, and cell/row/selection copy actions. - Preserve 64-bit integers and high-precision `NUMBER` values exactly before displaying or exporting them. - Export already-retrieved results to CSV, JSON, or XLSX without executing the SQL again. - Use configurable local query history with reopen, copy, and rerun actions. +## Quick start + +1. Open **Simple DB** in the Activity Bar and choose **Create Connection**. +2. Select the database engine and enter a connection name. SQLite uses the native file picker; network databases create a JSON profile with the correct default parameters. +3. Edit the generated JSON if needed, press `Ctrl+S`, then use **Test Connection** or **Connect** from the connection menu. Passwords stay outside JSON in VS Code `SecretStorage`. +4. Choose **New Query**, write SQL, and press `Ctrl+Enter` to execute the selection or the statement at the cursor. Use `Ctrl+Shift+Enter` to execute the entire document. +5. Results appear automatically in the resizable **Simple DB — Results** panel below the SQL editor. The same core commands are also available from the editor's **Simple DB** context submenu. + ## Five database engines | Engine | Driver | Notable dialect and explorer support | @@ -32,7 +40,7 @@ The extension opens regular VS Code SQL documents. `F5` launches `src/extension. | SQL Server | `mssql` | databases, schemas, tables, views, procedures/functions, indexes, triggers, sequences, types, synonyms, `GO` | | Oracle | `oracledb` Thin | schemas, tables, views/materialized views, procedures/functions, packages, indexes, triggers, sequences, types, synonyms, PL/SQL | -Oracle uses the default `node-oracledb` Thin mode, so normal connections do not require Oracle Client to be installed. Simple DB `0.1.1` uses SQL authentication with a username and password for SQL Server. +Oracle uses the default `node-oracledb` Thin mode, so normal connections do not require Oracle Client to be installed. Simple DB `0.1.2` uses SQL authentication with a username and password for SQL Server. ## No imposed row limit by default @@ -79,7 +87,9 @@ Each SQL editor has an independent session identifier. A transaction reserves it ## Results, copy, and export -The result panel supports page navigation, switching between multiple result sets, distinguishing `NULL`, selecting a cell or a range with `Shift`, and copying a cell, row, or selection. +Executing SQL automatically reveals the **Simple DB** view in VS Code's lower Panel while keeping the SQL editor visible above it. `SELECT` results are displayed in a spreadsheet-like grid with a sticky header, row numbers, horizontal/vertical scrolling, page navigation, and tabs for multiple result sets. + +The result grid distinguishes `NULL`, shows column types, supports selecting a cell or a range with `Shift`, and can copy a cell, row, or selection. Non-query statements display their execution message and affected-row information in the same lower Results view. CSV, JSON, and XLSX are streamed from the retrieved temporary result pages. The query is not executed again. Very large cell values are bounded for display by `simpleDb.maxCellCharacters`; the UI explicitly indicates when a cell has been truncated for display. @@ -201,7 +211,7 @@ src/ storage/ # profiles, history, and paged results test/ # JavaScript tests ui/ # connection form - views/ # trees and result panel + views/ # trees and lower result grid extension.js # activate/deactivate ``` diff --git a/package-lock.json b/package-lock.json index da3a75f..75d0df6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "simple-db-suzdalenko", - "version": "0.1.1", + "version": "0.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "simple-db-suzdalenko", - "version": "0.1.1", + "version": "0.1.2", "license": "MIT", "dependencies": { "exceljs": "4.4.0", diff --git a/package.json b/package.json index 541fb0e..987114e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "simple-db-suzdalenko", "displayName": "Simple DB - SQL Client for SQLite, MySQL, PostgreSQL, SQL Server & Oracle", "description": "SQL client and database editor for SQLite, MySQL, PostgreSQL, SQL Server (MSSQL) and Oracle. Browse database objects, run queries, manage DDL and export results.", - "version": "0.1.1", + "version": "0.1.2", "publisher": "suzdalenko-dev", "license": "MIT", "icon": "resources/simple-db-marketplace.png", @@ -56,6 +56,7 @@ "activationEvents": [ "onView:simpleDb.connections", "onView:simpleDb.history", + "onView:simpleDb.results", "onLanguage:sql" ], "main": "./src/extension.js", @@ -246,6 +247,13 @@ "title": "Simple DB", "icon": "resources/simple-db.svg" } + ], + "panel": [ + { + "id": "simpleDbResults", + "title": "Simple DB", + "icon": "resources/simple-db.svg" + } ] }, "views": { @@ -260,6 +268,14 @@ "name": "History", "type": "tree" } + ], + "simpleDbResults": [ + { + "id": "simpleDb.results", + "name": "Results", + "type": "webview", + "contextualTitle": "Simple DB Results" + } ] }, "menus": { diff --git a/src/core/valueNormalizer.js b/src/core/valueNormalizer.js index d082194..e9ed77b 100644 --- a/src/core/valueNormalizer.js +++ b/src/core/valueNormalizer.js @@ -6,7 +6,7 @@ function truncateText(value, maxCharacters) { } const removed = value.length - maxCharacters; - return `${value.slice(0, maxCharacters)}… [${removed} caracteres omitidos]`; + return `${value.slice(0, maxCharacters)}… [${removed} characters omitted]`; } function normalizeValue(value, maxCharacters = 10000) { diff --git a/src/extension.js b/src/extension.js index 5557804..8475c2e 100644 --- a/src/extension.js +++ b/src/extension.js @@ -19,7 +19,7 @@ const { ResultStore } = require('./storage/resultStore'); const { promptConnection, promptPassword } = require('./ui/connectionForm'); const { ConnectionsTreeProvider } = require('./views/connectionsTreeProvider'); const { HistoryTreeProvider } = require('./views/historyTreeProvider'); -const { ResultPanel } = require('./views/resultPanel'); +const { RESULT_VIEW_ID, ResultPanel } = require('./views/resultPanel'); const { getDatabaseEngine } = require('./databaseEngines'); let runtime = null; @@ -150,6 +150,11 @@ async function activate(context) { await resultStore.initialize(); const exportService = new ExportService(resultStore, exportConfiguration); const resultPanel = new ResultPanel(resultStore, exportService); + const resultViewRegistration = vscode.window.registerWebviewViewProvider( + RESULT_VIEW_ID, + resultPanel, + { webviewOptions: { retainContextWhenHidden: true } }, + ); const queryRunner = new QueryRunner({ connectionStore, connectionManager, @@ -174,6 +179,7 @@ async function activate(context) { context.subscriptions.push( connectionsView, historyView, + resultViewRegistration, connectionsProvider, historyProvider, editorSessionManager, diff --git a/src/test/resultStore.test.js b/src/test/resultStore.test.js index 807c32f..8ce9d05 100644 --- a/src/test/resultStore.test.js +++ b/src/test/resultStore.test.js @@ -55,6 +55,6 @@ describe('ResultStore', () => { await store.finishSet('exec-2', 0); const metadata = await store.finalizeExecution('exec-2'); expect(metadata.sets[0].pages).toBe(2); - expect((await store.getPage('exec-2', 0, 0))[0][0]).toContain('omitidos'); + expect((await store.getPage('exec-2', 0, 0))[0][0]).toContain('characters omitted'); }); }); diff --git a/src/test/resultViewHtml.test.js b/src/test/resultViewHtml.test.js new file mode 100644 index 0000000..c074702 --- /dev/null +++ b/src/test/resultViewHtml.test.js @@ -0,0 +1,152 @@ +'use strict'; + +const vm = require('node:vm'); +const packageJson = require('../../package.json'); +const { createResultViewHtml } = require('../views/resultViewHtml'); + +describe('lower Results view', () => { + it('generates valid JavaScript for the SQL result grid', () => { + const html = createResultViewHtml('test-nonce'); + const match = html.match( + / - -`; + _disposeViewBindings() { + for (const disposable of this.viewDisposables) disposable.dispose(); + this.viewDisposables = []; } dispose() { - this.messageDisposable?.dispose(); - this.panelDisposable?.dispose(); - this.panel?.dispose(); - this.messageDisposable = null; - this.panelDisposable = null; - this.panel = null; + this._disposeViewBindings(); + this.view = null; + this.executionId = null; } } module.exports = { + RESULT_VIEW_ID, ResultPanel, }; diff --git a/src/views/resultViewHtml.js b/src/views/resultViewHtml.js new file mode 100644 index 0000000..f9df6f7 --- /dev/null +++ b/src/views/resultViewHtml.js @@ -0,0 +1,396 @@ +'use strict'; + +function createResultViewHtml(nonce) { + return ` + + + + + + + + +
Query ResultsRun a query to see results.
+
+ +
Run SELECT or another SQL statement to see its result here.
+ + +`; +} + +module.exports = { + createResultViewHtml, +};