Skip to content

Commit 09befe1

Browse files
Electron desktop app (#10)
* add electron desktop app * fixes and icons * fix tests * fix tests * fix tests
1 parent 5194d60 commit 09befe1

22 files changed

Lines changed: 4682 additions & 211 deletions

.github/workflows/release.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Version (e.g. v0.1.0)'
8+
required: true
9+
type: string
10+
11+
jobs:
12+
build:
13+
strategy:
14+
matrix:
15+
include:
16+
- os: ubuntu-latest
17+
platform: linux
18+
- os: macos-latest
19+
platform: mac
20+
- os: windows-latest
21+
platform: win
22+
23+
runs-on: ${{ matrix.os }}
24+
25+
steps:
26+
- uses: actions/checkout@v4
27+
28+
- name: Setup Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: '22'
32+
cache: 'npm'
33+
34+
- name: Install dependencies
35+
run: npm ci
36+
37+
- name: Build web + Electron
38+
run: npx vite build
39+
env:
40+
ELECTRON: 'true'
41+
42+
- name: Package desktop app
43+
run: npx electron-builder --${{ matrix.platform }}
44+
env:
45+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46+
47+
- name: Upload artifacts
48+
uses: actions/upload-artifact@v4
49+
with:
50+
name: desktop-${{ matrix.platform }}
51+
path: |
52+
release/*.exe
53+
release/*.dmg
54+
release/*.AppImage
55+
release/*.deb
56+
if-no-files-found: ignore
57+
58+
github_release:
59+
runs-on: ubuntu-latest
60+
needs: [build]
61+
name: Create GitHub release
62+
permissions:
63+
contents: write
64+
steps:
65+
- name: Download all artifacts
66+
uses: actions/download-artifact@v4
67+
with:
68+
path: artifacts
69+
merge-multiple: true
70+
71+
- name: Create Release
72+
uses: ncipollo/release-action@v1
73+
with:
74+
artifacts: "artifacts/*"
75+
tag: ${{ inputs.version }}
76+
commit: ${{ github.sha }}
77+
generateReleaseNotes: true
78+
draft: false
79+
prerelease: false

.github/workflows/test.yml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,20 @@ jobs:
2525
- name: Run tests
2626
run: npm test
2727

28-
- name: Build
28+
- name: Build (web)
2929
run: npm run build
30+
31+
- name: Build (Electron)
32+
run: ELECTRON=true npx vite build
33+
34+
- name: Install Playwright browsers
35+
run: npx playwright install --with-deps chromium
36+
37+
- name: Electron e2e tests
38+
run: xvfb-run --auto-servernum npx playwright test
39+
40+
- uses: actions/upload-artifact@v4
41+
if: failure()
42+
with:
43+
name: playwright-traces
44+
path: test-results/

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ node_modules/
33

44
# Build output
55
dist/
6+
dist-electron/
7+
release/
8+
9+
# Local config (template is config.default.json)
10+
config.json
611

712
# Vite
813
*.local

CLAUDE.md

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# CLAUDE.md - RowBinary Visualizer
1+
# CLAUDE.md - ClickHouse Format Explorer
22

33
## Project Overview
44

5-
A web-based tool for visualizing ClickHouse RowBinary wire format data. Features an interactive hex viewer with AST-based type visualization, similar to ImHex. The tool queries a local ClickHouse database and presents the raw binary data alongside a decoded AST tree with bidirectional highlighting.
5+
A tool for visualizing ClickHouse RowBinary and Native wire format data. Features an interactive hex viewer with AST-based type visualization, similar to ImHex. Available as a web app (Docker) or an Electron desktop app that connects to your existing ClickHouse server.
66

77
**Current scope**: RowBinaryWithNamesAndTypes and Native formats.
88

@@ -11,16 +11,22 @@ A web-based tool for visualizing ClickHouse RowBinary wire format data. Features
1111
- **Frontend**: React 18 + TypeScript + Vite
1212
- **State**: Zustand
1313
- **UI**: react-window (virtualized hex viewer), react-resizable-panels (split panes)
14-
- **Testing**: Vitest + testcontainers (ClickHouse integration tests)
15-
- **Deployment**: Docker (bundles ClickHouse + nginx + built frontend)
14+
- **Desktop**: Electron (optional, connects to user's ClickHouse)
15+
- **Testing**: Vitest + testcontainers (integration), Playwright (Electron e2e)
16+
- **Deployment**: Docker (bundles ClickHouse + nginx) or Electron desktop app
1617

1718
## Commands
1819

1920
```bash
20-
npm run dev # Start dev server (requires ClickHouse at localhost:8123)
21-
npm run build # Build for production
22-
npm run test # Run integration tests (uses testcontainers)
23-
npm run lint # ESLint check
21+
npm run dev # Start web dev server (requires ClickHouse at localhost:8123)
22+
npm run build # Build web app for production
23+
npm run test # Run integration tests (uses testcontainers)
24+
npm run lint # ESLint check
25+
npm run test:e2e # Build Electron + run Playwright e2e tests
26+
27+
# Electron desktop app
28+
npm run electron:dev # Dev mode with hot reload
29+
npm run electron:build # Package desktop installer for current platform
2430

2531
# Docker (self-contained with bundled ClickHouse)
2632
docker build -t rowbinary-explorer .
@@ -33,7 +39,7 @@ docker run -d -p 8080:80 rowbinary-explorer
3339
src/
3440
├── components/ # React components
3541
│ ├── App.tsx # Main layout with resizable panels
36-
│ ├── QueryInput.tsx # SQL query input + run button
42+
│ ├── QueryInput.tsx # SQL query input + run button + connection settings
3743
│ ├── HexViewer/ # Virtualized hex viewer with highlighting
3844
│ └── AstTree/ # Collapsible AST tree view
3945
├── core/
@@ -52,10 +58,15 @@ src/
5258
│ │ ├── type-lexer.ts # Tokenizer for type strings
5359
│ │ └── type-parser.ts # Parser: string -> ClickHouseType
5460
│ └── clickhouse/
55-
│ └── client.ts # HTTP client for ClickHouse queries
61+
│ └── client.ts # HTTP client (fetch for web, IPC for Electron)
5662
├── store/
5763
│ └── store.ts # Zustand store (query, parsed data, UI state)
5864
└── styles/ # CSS files
65+
electron/
66+
├── main.ts # Electron main process (window, IPC handlers)
67+
└── preload.ts # Preload script (contextBridge → electronAPI)
68+
e2e/
69+
└── electron.spec.ts # Playwright Electron e2e tests
5970
docs/
6071
├── rowbinaryspec.md # RowBinary wire format specification
6172
├── nativespec.md # Native wire format specification
@@ -94,14 +105,34 @@ A discriminated union representing all ClickHouse types (`src/core/types/clickho
94105

95106
### Decoding Flow
96107
1. User enters SQL query, clicks "Run Query"
97-
2. `ClickHouseClient` (`src/core/clickhouse/client.ts`) POSTs query with selected format
108+
2. `ClickHouseClient` (`src/core/clickhouse/client.ts`) sends query:
109+
- **Web mode**: `fetch()` via Vite proxy or nginx
110+
- **Electron mode**: IPC to main process → `fetch()` to ClickHouse (no CORS)
98111
3. Decoder parses the binary response:
99112
- **RowBinary** (`rowbinary-decoder.ts`): Row-oriented, header + rows
100113
- **Native** (`native-decoder.ts`): Column-oriented with blocks
101114
4. Type strings parsed via `parseType()` into `ClickHouseType`
102115
5. Each decoded value returns an `AstNode` with byte tracking
103116
6. UI renders hex view (left) and AST tree (right)
104117

118+
### Electron Architecture
119+
```
120+
Renderer (React) Main Process (Node.js)
121+
│ │
122+
├─ window.electronAPI │
123+
│ .executeQuery(opts) ────────►├─ fetch(clickhouseUrl + query)
124+
│ │ → ArrayBuffer
125+
│◄── IPC response ──────────────┤
126+
│ │
127+
├─ Uint8Array → decoders │
128+
└─ render hex view + AST tree │
129+
```
130+
131+
- Runtime detection: `window.electronAPI` exists → IPC path, otherwise → `fetch()`
132+
- `vite-plugin-electron` activates only when `ELECTRON=true` env var is set
133+
- Connection config in `config.json` (project root in dev, next to executable in prod)
134+
- Experimental ClickHouse settings (Variant, Dynamic, JSON, etc.) sent as query params
135+
105136
### Interactive Highlighting
106137
- Click a node in AST tree → highlights corresponding bytes in hex view
107138
- Click a byte in hex view → selects the deepest AST node containing that byte
@@ -133,12 +164,13 @@ A discriminated union representing all ClickHouse types (`src/core/types/clickho
133164

134165
## Testing
135166

136-
Integration tests use testcontainers to spin up a real ClickHouse instance:
167+
### Integration Tests (Vitest + testcontainers)
168+
169+
Tests use testcontainers to spin up a real ClickHouse instance:
137170
```bash
138171
npm run test # Runs all integration tests
139172
```
140173

141-
### Test Structure
142174
Tests are organized into three categories with shared test case definitions:
143175

144176
1. **Smoke Tests** (`smoke.integration.test.ts`)
@@ -155,6 +187,18 @@ Tests are organized into three categories with shared test case definitions:
155187
- Analyze byte coverage of AST leaf nodes
156188
- Report uncovered byte ranges
157189

190+
### Electron e2e Tests (Playwright)
191+
192+
```bash
193+
npm run test:e2e # Builds Electron app + runs Playwright tests
194+
```
195+
196+
Tests in `e2e/electron.spec.ts` launch the actual Electron app and verify:
197+
- App window opens and UI renders
198+
- Host input is visible (Electron mode) and Share button is hidden
199+
- Connection settings can be edited
200+
- Upload button is present and functional
201+
158202
### Test Case Interface
159203
```typescript
160204
interface ValidationTestCase {

README.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ClickHouse Format Explorer
22

3-
A web-based tool for visualizing ClickHouse RowBinary and Native format data. Features an interactive hex viewer with AST-based type visualization.
3+
A tool for visualizing ClickHouse RowBinary and Native format data. Features an interactive hex viewer with AST-based type visualization. Available as a web app or Electron desktop app.
44

55
![Screenshot](.static/screenshot.png)
66

@@ -11,6 +11,7 @@ A web-based tool for visualizing ClickHouse RowBinary and Native format data. Fe
1111
- **AST Tree**: Collapsible tree view showing decoded structure
1212
- **Interactive Highlighting**: Selecting a node in the tree highlights corresponding bytes in the hex view (and vice versa)
1313
- **Full Type Support**: All ClickHouse types including Variant, Dynamic, JSON, Geo types, Nested, etc.
14+
- **Desktop App**: Electron app that connects to your existing ClickHouse server (no bundled DB)
1415

1516
## Quick Start (Docker)
1617

@@ -23,9 +24,39 @@ docker run -d -p 8080:80 rowbinary-explorer
2324

2425
Open http://localhost:8080
2526

26-
## Development Setup
27+
## Desktop App
2728

28-
For local development (requires ClickHouse at `localhost:8123`):
29+
For developers who already run ClickHouse locally. Download the latest release for your platform from the [Releases](../../releases) page:
30+
31+
| Platform | Format |
32+
|----------|--------|
33+
| Windows | `.exe` (NSIS installer) |
34+
| macOS | `.dmg` |
35+
| Linux | `.AppImage` / `.deb` |
36+
37+
### Configuration
38+
39+
The app looks for a `config.json` file next to the executable:
40+
41+
```json
42+
{
43+
"host": "http://localhost:8123"
44+
}
45+
```
46+
47+
You can also change the host from the **Host** field in the toolbar. Changes are saved back to `config.json`.
48+
49+
### Building from source
50+
51+
```bash
52+
npm install
53+
npm run electron:dev # Dev mode with hot reload
54+
npm run electron:build # Package installer for current platform
55+
```
56+
57+
## Web Development Setup
58+
59+
For local web development (requires ClickHouse at `localhost:8123`):
2960

3061
```bash
3162
npm install
@@ -37,7 +68,7 @@ Open http://localhost:5173
3768
## Usage
3869

3970
1. Enter a SQL query in the input box
40-
2. Click "Run Query" to fetch data from ClickHouse (expects local instance at `localhost:8123`)
71+
2. Click "Execute" to fetch data from ClickHouse
4172
3. Explore the parsed data:
4273
- Click nodes in the AST tree to highlight bytes
4374
- Click bytes in the hex viewer to select the corresponding node
@@ -66,3 +97,5 @@ SELECT '{"user": {"id": 123}}'::JSON(`user.id` UInt32)
6697
- Zustand (state management)
6798
- react-window (virtualized hex viewer)
6899
- react-resizable-panels (split pane layout)
100+
- Electron (desktop app, optional)
101+
- Playwright (e2e testing)

build/icon.icns

88.4 KB
Binary file not shown.

build/icon.ico

8.16 KB
Binary file not shown.

build/icon.png

18.9 KB
Loading

config.default.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"host": "http://localhost:8123"
3+
}

0 commit comments

Comments
 (0)