pglens 1.1.0 → 2.0.1

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 CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.0] - 2026-01-01
9
+
10
+ ### Added
11
+
12
+ - **Server-Side Sorting**: Table sorting is now performed on the database server, ensuring correct ordering across all data pages.
13
+ - **Connection Parameters Mode**: New tabbed interface in connection dialog allowing separate input for Host, Port, User, Password, and Database.
14
+ - **Global Loading Overlay**: Blocks user interaction during data fetching to prevent race conditions.
15
+ - **Dynamic Port Selection**: Server automatically finds an available port if 54321 is busy.
16
+ - **`pglens url` Command**: CLI command to display the currently running server URL.
17
+ - **Database Query Timeout**: Enforced 30-second timeout on all database operations.
18
+
19
+ ### Changed
20
+
21
+ - Connection dialog now defaults to "Parameters" input mode for better usability.
22
+ - Switched to offset-based pagination when a custom sort order is active.
23
+ - Improved connection error handling and validation.
24
+
8
25
  ## [1.1.0] - 2025-11-21
9
26
 
10
27
  ### Added
package/README.md CHANGED
@@ -4,18 +4,23 @@ A simple PostgreSQL database viewer tool. Perfect to quickly view and explore yo
4
4
 
5
5
  ## Features
6
6
 
7
+ - 🔌 **Connection Manager**: Manage multiple database connections from a single UI
8
+ - 🚀 **Background Service**: Runs as a daemon process for persistent access
7
9
  - 🗂️ **Table Browser**: View all tables in your database in a clean, searchable sidebar
8
10
  - 📊 **Data Viewer**: Browse table rows with a modern, easy-to-read interface
11
+ - 📝 **Cell Content Viewer**: Double-click any cell to view full content in a popup
12
+ - 🎨 **JSON/JSONB Formatting**: Auto-formats JSON data with syntax highlighting
13
+ - 🕒 **Timezone Support**: View timestamps in local, UTC, or other timezones
14
+ - 📋 **Clipboard Support**: One-click copy for cell contents
9
15
  - 🪟 **Multiple Tabs**: Open multiple tables simultaneously in separate tabs
10
- - 🔄 **Sorting**: Click column headers to sort data (client-side sorting on current view)
11
- - 📄 **Pagination**: Navigate through large tables with Previous/Next buttons (100 rows per page)
16
+ - 🔄 **Server-Side Sorting**: Click column headers to sort data directly on the database server
17
+ - 📄 **Pagination**: Navigate through large tables with Previous/Next buttons
12
18
  - 🔍 **Table Search**: Quickly find tables by name using the search bar
13
19
  - 👁️ **Column Visibility**: Show or hide columns to focus on what matters
14
20
  - 📏 **Column Resizing**: Resize columns by dragging the column borders
15
21
  - 🎨 **Theme Support**: Choose between light, dark, or system theme
16
- - 🔄 **Refresh Data**: Reload table data with a single click
17
22
  - ⚡ **Optimized Performance**: Uses cursor-based pagination for efficient large table navigation
18
- - 🔒 **SSL Support**: Configurable SSL modes with automatic recommendations on connection errors
23
+ - 🔒 **SSL Support**: Configurable SSL modes (Disable, Require, Prefer, Verify CA/Full)
19
24
  - 🚀 **Easy Setup**: Install globally and run with a single command
20
25
 
21
26
  ## Installation
@@ -32,173 +37,63 @@ npm install pglens
32
37
 
33
38
  ## Usage
34
39
 
35
- Run pglens with your PostgreSQL connection string and optional port:
40
+ ### Start the Server
36
41
 
37
- ```bash
38
- pglens --url postgresql://user:password@localhost:5432/dbname --port 54321
39
- ```
40
-
41
- ### Arguments
42
-
43
- - `--url` (required): PostgreSQL connection string
44
- - Format: `postgresql://user:password@host:port/database`
45
- - Example: `postgresql://postgres:mypassword@localhost:5432/mydb`
46
- - `--port` (optional): Port to run the web server on (default: 54321)
47
- - `--sslmode` (optional): SSL mode for database connection (default: `prefer`)
48
- - `disable`: Disable SSL encryption
49
- - `require`: Require SSL, but don't verify certificate
50
- - `prefer`: Prefer SSL, but allow non-SSL fallback (default)
51
- - `verify-ca`: Require SSL and verify certificate authority
52
- - `verify-full`: Require SSL and verify certificate and hostname
53
-
54
- ### SSL Mode Examples
55
-
56
- ```bash
57
- # Use default SSL mode (prefer)
58
- pglens --url postgresql://postgres:secret@localhost:5432/myapp
59
-
60
- # Require SSL without certificate verification (for self-signed certs)
61
- pglens --url postgresql://postgres:secret@localhost:5432/myapp --sslmode require
62
-
63
- # Disable SSL (for local development)
64
- pglens --url postgresql://postgres:secret@localhost:5432/myapp --sslmode disable
65
-
66
- # Full certificate verification (for production)
67
- pglens --url postgresql://postgres:secret@localhost:5432/myapp --sslmode verify-full
68
- ```
69
-
70
- ### Connection Troubleshooting
71
-
72
- If you encounter connection errors, pglens will automatically analyze the error and suggest an appropriate SSL mode:
73
-
74
- ```
75
- ✗ Failed to connect to PostgreSQL database: self signed certificate
76
-
77
- 💡 SSL Mode Recommendation: Try using --sslmode require
78
- Current SSL mode: verify-full
79
- Suggested command: Add --sslmode require to your command
80
- ```
81
-
82
- ### Basic Example
83
-
84
- ```bash
85
- pglens --url postgresql://postgres:secret@localhost:5432/myapp --port 54321
86
- ```
87
-
88
- Then open your browser to `http://localhost:54321` to view your database.
89
-
90
- ## Running with PM2 (Server Deployment)
91
-
92
- For production use on a server, you can run pglens as a persistent process using [PM2](https://pm2.keymetrics.io/), a process manager for Node.js applications.
93
-
94
- ### Install PM2
42
+ Start pglens as a background service:
95
43
 
96
44
  ```bash
97
- npm install -g pm2
45
+ pglens start
98
46
  ```
99
47
 
100
- ### Start pglens with PM2
48
+ This will start the server on `http://localhost:54321` (or the next available port if 54321 is busy).
49
+ The URL will be printed to the console. You can also check the running URL at any time with:
101
50
 
102
51
  ```bash
103
- pm2 start pglens -- --url postgresql://user:password@localhost:5432/dbname --port 54321
52
+ pglens url
104
53
  ```
105
54
 
106
- Or with SSL mode:
55
+ ### Connect to a Database
107
56
 
108
- ```bash
109
- pm2 start pglens -- --url postgresql://user:password@localhost:5432/dbname --port 54321 --sslmode require
110
- ```
57
+ 1. Open `http://localhost:54321`
58
+ 2. Click the **+** icon in the sidebar
59
+ 3. Enter your connection details using one of the tabs:
60
+ - **Parameters** (Default): Enter Host, Port, Database, User, and Password separately.
61
+ - **Connection URL**: Paste a standard PostgreSQL connection string (e.g., `postgresql://user:pass@localhost:5432/db`).
62
+ 4. Select the **SSL Mode** appropriate for your server.
63
+ 5. Click **Connect**.
111
64
 
112
- Or use PM2's ecosystem file for better configuration:
113
-
114
- **ecosystem.config.js:**
115
-
116
- ```javascript
117
- module.exports = {
118
- apps: [
119
- {
120
- name: "pglens",
121
- script: "pglens",
122
- args: "--url postgresql://user:password@localhost:5432/dbname --port 54321 --sslmode require",
123
- instances: 1,
124
- autorestart: true,
125
- watch: false,
126
- max_memory_restart: "300M",
127
- env: {
128
- NODE_ENV: "production",
129
- },
130
- },
131
- ],
132
- };
133
- ```
65
+ ### Stop the Server
134
66
 
135
- Then start with:
67
+ To stop the background service:
136
68
 
137
69
  ```bash
138
- pm2 start ecosystem.config.js
70
+ pglens stop
139
71
  ```
140
72
 
141
- ### Useful PM2 Commands
142
-
143
- ```bash
144
- # View running processes
145
- pm2 list
146
-
147
- # View logs
148
- pm2 logs pglens
149
-
150
- # Stop pglens
151
- pm2 stop pglens
152
-
153
- # Restart pglens
154
- pm2 restart pglens
155
-
156
- # Delete pglens from PM2
157
- pm2 delete pglens
158
-
159
- # Save PM2 process list (for auto-restart on reboot)
160
- pm2 save
161
-
162
- # Setup PM2 to start on system boot
163
- pm2 startup
164
- ```
165
-
166
- ### Important Security Reminder
167
-
168
- ⚠️ **Warning**: When running pglens on a server, ensure you:
169
-
170
- - Use a reverse proxy (nginx, Apache) with authentication
171
- - Restrict access via firewall rules
172
- - Use HTTPS/TLS encryption
173
- - Consider adding authentication middleware
174
- - Never expose it directly to the internet without proper security measures
175
-
176
73
  ## How It Works
177
74
 
178
- 1. **Start the server**: Run the `pglens` command with your database URL
179
- 2. **View tables**: The left sidebar shows all tables in your database
180
- 3. **Search tables**: Use the search bar to quickly filter tables by name
181
- 4. **Select a table**: Click on any table to view its data in a new tab
182
- 5. **Multiple tabs**: Open multiple tables at once - each opens in its own tab
183
- 6. **Sort data**: Click on column headers to sort the current view
184
- 7. **Customize columns**: Use the "Columns" button to show/hide columns or resize them by dragging borders
185
- 8. **Navigate pages**: Use Previous/Next buttons to load more rows (100 rows per page)
186
- 9. **Refresh data**: Click the refresh button (↻) to reload the current table
187
- 10. **Change theme**: Click the theme button (🌓) to switch between light, dark, or system theme
75
+ 1. **Start**: Run `pglens start` to launch the background service
76
+ 2. **Connect**: Add one or more database connections via the Web UI
77
+ 3. **Explore**:
78
+ - Use the sidebar to browse tables across different connections
79
+ - Double-click cells to view detailed content
80
+ - Use the "Columns" menu to toggle visibility
81
+ - Switch themes for comfortable viewing
188
82
 
189
83
  ## Development
190
84
 
191
85
  To develop or modify pglens:
192
86
 
193
87
  ```bash
194
- # Clone or navigate to the project directory
88
+ # Clone the repository
89
+ git clone https://github.com/tsvillain/pglens.git
195
90
  cd pglens
196
91
 
197
92
  # Install dependencies
198
93
  npm install
199
94
 
200
- # Run locally
201
- node bin/pglens --url your-connection-string --port 54321
95
+ # Run locally (starts server in foreground for logs)
96
+ node bin/pglens serve
202
97
  ```
203
98
 
204
99
  ## Contributing
@@ -210,11 +105,9 @@ Contributions are welcome! Please read our [Contributing Guidelines](CONTRIBUTIN
210
105
  - Pull request process
211
106
  - Issue reporting
212
107
 
213
- We appreciate all contributions, whether it's bug fixes, new features, documentation improvements, or feedback.
214
-
215
108
  ## Security Note
216
109
 
217
- This tool is designed for local development use only. It has no authentication and should **never** be exposed to the internet or untrusted networks. Always use it on localhost or within a trusted network environment.
110
+ This tool is designed for local development use. While it supports SSL for database connections, the web interface itself runs on HTTP (localhost) and has no user authentication. **Do not expose the pglens port (54321) directly to the internet.**
218
111
 
219
112
  ## License
220
113
 
package/bin/pglens CHANGED
@@ -2,17 +2,153 @@
2
2
 
3
3
  const { program } = require('commander');
4
4
  const { startServer } = require('../src/server');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+ const { spawn } = require('child_process');
9
+
10
+ const PID_FILE = path.join(os.homedir(), '.pglens.pid');
11
+ const PORT_FILE = path.join(os.homedir(), '.pglens.port');
5
12
 
6
13
  program
7
14
  .name('pglens')
8
15
  .description('A simple PostgreSQL database viewer tool')
9
- .version('1.0.0')
10
- .requiredOption('--url <url>', 'PostgreSQL connection string (e.g., postgresql://user:pass@localhost:5432/dbname)')
11
- .option('--port <port>', 'Port to run the web server on', '54321')
12
- .option('--sslmode <mode>', 'SSL mode: disable, require, prefer, verify-ca, verify-full', 'prefer')
13
- .parse(process.argv);
16
+ .version('2.0.1');
17
+
18
+ function getRunningPort() {
19
+ if (fs.existsSync(PORT_FILE)) {
20
+ try {
21
+ return parseInt(fs.readFileSync(PORT_FILE, 'utf8'));
22
+ } catch (e) {
23
+ return null;
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+
29
+ program
30
+ .command('start')
31
+ .description('Start the pglens server in background')
32
+ .action(async () => {
33
+ // Check if already running
34
+ if (fs.existsSync(PID_FILE)) {
35
+ try {
36
+ const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
37
+ process.kill(pid, 0); // Check if process exists
38
+ console.log(`pglens is already running (PID: ${pid})`);
39
+
40
+ const port = getRunningPort();
41
+ if (port) {
42
+ console.log(`✓ Server running on http://localhost:${port}`);
43
+ } else {
44
+ console.log(' Server URL unknown (check logs)');
45
+ }
46
+ return;
47
+ } catch (e) {
48
+ // Stale PID file, remove it
49
+ fs.unlinkSync(PID_FILE);
50
+ if (fs.existsSync(PORT_FILE)) fs.unlinkSync(PORT_FILE);
51
+ }
52
+ }
53
+
54
+ // Spawn detached child process
55
+ const child = spawn(process.execPath, [__filename, 'serve'], {
56
+ detached: true,
57
+ stdio: 'ignore'
58
+ });
59
+
60
+ // Save PID
61
+ fs.writeFileSync(PID_FILE, child.pid.toString());
62
+
63
+ // Unref to allow parent to exit
64
+ child.unref();
65
+
66
+ console.log(` Background process started (PID: ${child.pid})`);
67
+
68
+ // Wait for server to start and acquire port
69
+ let attempts = 0;
70
+ const maxAttempts = 20;
71
+ const checkInterval = 100;
72
+
73
+ process.stdout.write(' Waiting for server...');
74
+
75
+ const interval = setInterval(() => {
76
+ const port = getRunningPort();
77
+ if (port) {
78
+ clearInterval(interval);
79
+ process.stdout.write('\r\x1b[K'); // Clear line
80
+ console.log(`✓ Server running on http://localhost:${port}`);
81
+ process.exit(0);
82
+ }
83
+
84
+ attempts++;
85
+ if (attempts >= maxAttempts) {
86
+ clearInterval(interval);
87
+ process.stdout.write('\r\x1b[K'); // Clear line
88
+ console.log('✓ Server started (could not determine port, check logs)');
89
+ process.exit(0);
90
+ }
91
+ }, checkInterval);
92
+ });
93
+
94
+ // Hidden command that actually runs the server
95
+ program
96
+ .command('serve', { hidden: true })
97
+ .action(() => {
98
+ startServer();
99
+ });
100
+
101
+ program
102
+ .command('stop')
103
+ .description('Stop the pglens server')
104
+ .action(() => {
105
+ if (!fs.existsSync(PID_FILE)) {
106
+ console.log('pglens is not running');
107
+ return;
108
+ }
109
+
110
+ try {
111
+ const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
112
+ process.kill(pid, 'SIGTERM');
113
+ fs.unlinkSync(PID_FILE);
114
+ if (fs.existsSync(PORT_FILE)) fs.unlinkSync(PORT_FILE);
115
+ console.log('pglens stopped');
116
+ } catch (e) {
117
+ console.error(`Error stopping pglens: ${e.message}`);
118
+ // Clean up if process not found
119
+ if (e.code === 'ESRCH') {
120
+ fs.unlinkSync(PID_FILE);
121
+ if (fs.existsSync(PORT_FILE)) fs.unlinkSync(PORT_FILE);
122
+ }
123
+ }
124
+ });
125
+
126
+ program
127
+ .command('url')
128
+ .description('Show the URL where pglens is running')
129
+ .action(() => {
130
+ if (!fs.existsSync(PID_FILE)) {
131
+ console.log('pglens is not running');
132
+ return;
133
+ }
14
134
 
15
- const options = program.opts();
135
+ // Verify process is actually running
136
+ try {
137
+ const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
138
+ process.kill(pid, 0);
139
+ } catch (e) {
140
+ console.log('pglens is not running (stale PID file)');
141
+ fs.unlinkSync(PID_FILE);
142
+ if (fs.existsSync(PORT_FILE)) fs.unlinkSync(PORT_FILE);
143
+ return;
144
+ }
16
145
 
17
- startServer(options.url, parseInt(options.port, 10), options.sslmode);
146
+ const port = getRunningPort();
147
+ if (port) {
148
+ console.log(`http://localhost:${port}`);
149
+ } else {
150
+ console.log('Could not determine server URL.');
151
+ }
152
+ });
18
153
 
154
+ program.parse(process.argv);