Skip to content

Commit f935286

Browse files
prmoore77claude
andcommitted
Add Homebrew install instructions, auto-select cell, and TLS icons
- Add Homebrew installation to README.md Quick Start section - Auto-select cell after query execution so right pane updates automatically - Add TLS status icons next to server names in explorer: - Green lock: TLS enabled with certificate verification - Yellow lock: TLS enabled but skip-verify - Red unlock: No TLS (insecure connection) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 63108d4 commit f935286

File tree

5 files changed

+55
-6
lines changed

5 files changed

+55
-6
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,16 @@ A web-based SQL interface for GizmoSQL servers. GizmoSQL UI provides a modern, r
1111

1212
## Quick Start
1313

14+
### macOS (Homebrew)
15+
16+
```bash
17+
brew install gizmodata/tap/gizmosql-ui
18+
gizmosql-ui
19+
```
20+
1421
### Using Pre-built Executable
1522

16-
Download the appropriate executable for your platform from the releases page, then run:
23+
Download the appropriate executable for your platform from the [releases page](https://github.com/gizmodata/gizmosql-ui/releases), then run:
1724

1825
```bash
1926
./gizmosql-ui

src/frontend/src/App.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useCallback } from 'react';
1+
import { useState, useCallback, useMemo } from 'react';
22
import { AppProvider, useApp } from './context/AppContext';
33
import { NotebookExplorer } from './components/NotebookExplorer';
44
import { ServerExplorer } from './components/ServerExplorer';
@@ -20,13 +20,20 @@ interface SelectedTable {
2020
function AppContent() {
2121
const { state, toggleTheme, updateCellServer, executeCell } = useApp();
2222
const [showAddServer, setShowAddServer] = useState(false);
23-
const [selectedCell, setSelectedCell] = useState<Cell | null>(null);
23+
const [selectedCellId, setSelectedCellId] = useState<string | null>(null);
2424
const [selectedTable, setSelectedTable] = useState<SelectedTable | null>(null);
2525
const [leftSidebarWidth, setLeftSidebarWidth] = useState(260);
2626
const [rightSidebarWidth, setRightSidebarWidth] = useState(280);
2727
const [tableDetailsHeight, setTableDetailsHeight] = useState(280);
2828
const [pendingExecuteCellId, setPendingExecuteCellId] = useState<string | null>(null);
2929

30+
// Derive selected cell from state so it updates when cell result changes
31+
const selectedCell = useMemo(() => {
32+
if (!selectedCellId) return null;
33+
const activeNotebook = state.notebooks.find(n => n.id === state.activeNotebookId);
34+
return activeNotebook?.cells.find(c => c.id === selectedCellId) || null;
35+
}, [selectedCellId, state.notebooks, state.activeNotebookId]);
36+
3037
const handleTableSelect = useCallback((serverId: string, catalog: string, schema: string, tableName: string) => {
3138
console.log('Table selected:', serverId, catalog, schema, tableName);
3239
setSelectedTable({ serverId, catalog, schema, tableName });
@@ -183,7 +190,7 @@ function AppContent() {
183190

184191
{/* Main area */}
185192
<main className="main-content">
186-
<NotebookView onCellSelect={setSelectedCell} onRequestConnection={handleRequestConnection} />
193+
<NotebookView onCellSelect={(cell) => setSelectedCellId(cell?.id || null)} onRequestConnection={handleRequestConnection} />
187194
</main>
188195

189196
{/* Right sidebar */}

src/frontend/src/components/Cell.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export function Cell({ notebookId, cell, isActive, onActivate, onAddCellBelow, o
2626
const executeRef = useRef<() => void>(() => {});
2727

2828
const handleExecute = useCallback(() => {
29+
// Auto-activate this cell when executing so right pane updates
30+
onActivate();
31+
2932
console.log('Executing cell:', cell.id, 'serverId:', cell.serverId, 'servers:', state.servers.length);
3033
console.log('onRequestConnection available:', !!onRequestConnection);
3134

@@ -70,7 +73,7 @@ export function Cell({ notebookId, cell, isActive, onActivate, onAddCellBelow, o
7073
}
7174

7275
executeCell(notebookId, cell.id);
73-
}, [executeCell, notebookId, cell.id, cell.serverId, state.servers, updateCellServer, onRequestConnection]);
76+
}, [executeCell, notebookId, cell.id, cell.serverId, state.servers, updateCellServer, onRequestConnection, onActivate]);
7477

7578
const handleServerSelect = (serverId: string) => {
7679
updateCellServer(notebookId, cell.id, serverId);

src/frontend/src/components/ServerExplorer.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,24 @@
155155
color: var(--primary-color);
156156
}
157157

158+
/* TLS status icons */
159+
.tls-icon {
160+
flex-shrink: 0;
161+
margin-left: -2px;
162+
}
163+
164+
.tls-secure {
165+
color: #22c55e; /* green */
166+
}
167+
168+
.tls-warning {
169+
color: #eab308; /* yellow */
170+
}
171+
172+
.tls-insecure {
173+
color: #ef4444; /* red */
174+
}
175+
158176
.icon-catalog {
159177
color: #f59e0b;
160178
}

src/frontend/src/components/ServerExplorer.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState, useCallback } from 'react';
22
import { useApp } from '../context/AppContext';
33
import { ServerConnection } from '../types';
44
import { VscFolder, VscTable, VscEye } from 'react-icons/vsc';
5-
import { Database, Server } from 'lucide-react';
5+
import { Database, Server, Lock, LockOpen } from 'lucide-react';
66
import './ServerExplorer.css';
77

88
interface TreeNode {
@@ -271,6 +271,20 @@ export function ServerExplorer({ onAddServer, onTableSelect }: ServerExplorerPro
271271
{isLoading ? <span className="loading-spinner"></span> : '▶'}
272272
</span>
273273
<Server className="node-icon-svg icon-server" size={16} />
274+
{/* TLS status icon */}
275+
{server.useTls ? (
276+
<Lock
277+
className={`tls-icon ${server.skipTlsVerify ? 'tls-warning' : 'tls-secure'}`}
278+
size={12}
279+
title={server.skipTlsVerify ? 'TLS enabled (certificate not verified)' : 'TLS enabled (certificate verified)'}
280+
/>
281+
) : (
282+
<LockOpen
283+
className="tls-icon tls-insecure"
284+
size={12}
285+
title="Connection is not encrypted (insecure)"
286+
/>
287+
)}
274288
<span className="server-status-dot" data-status={server.status}></span>
275289
<span className="server-name">{server.name}</span>
276290
<button

0 commit comments

Comments
 (0)