Skip to content

Commit 04fdc9e

Browse files
author
Michael Jonas
committed
Initial commit
0 parents  commit 04fdc9e

52 files changed

Lines changed: 7809 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Git
2+
.git
3+
.gitignore
4+
5+
# Node
6+
node_modules
7+
8+
# Python
9+
__pycache__
10+
*.pyc
11+
*.pyo
12+
.venv
13+
.mypy_cache
14+
.pytest_cache
15+
.ruff_cache
16+
17+
# IDE
18+
.idea
19+
.vscode
20+
*.swp
21+
22+
# Build artifacts (rebuilt in Docker)
23+
src/age_plotter/static/css/styles.css
24+
src/age_plotter/static/vendor/
25+
26+
# Local config
27+
connections.json
28+
*.local.json
29+
30+
# Specs/docs
31+
spec/
32+
*.md

.github/workflows/docker.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Build and Push Docker Image
2+
3+
on:
4+
push:
5+
branches: [main]
6+
tags: ['v*']
7+
pull_request:
8+
branches: [main]
9+
workflow_dispatch: # Manual trigger
10+
11+
env:
12+
REGISTRY: ghcr.io
13+
IMAGE_NAME: ${{ github.repository }}
14+
15+
jobs:
16+
build:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: read
20+
packages: write
21+
22+
steps:
23+
- name: Checkout repository
24+
uses: actions/checkout@v4
25+
26+
- name: Set up QEMU (for multi-platform builds)
27+
uses: docker/setup-qemu-action@v3
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3
31+
32+
- name: Log in to Container Registry
33+
if: github.event_name != 'pull_request'
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ${{ env.REGISTRY }}
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Extract metadata (tags, labels)
41+
id: meta
42+
uses: docker/metadata-action@v5
43+
with:
44+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
45+
tags: |
46+
type=ref,event=branch
47+
type=ref,event=pr
48+
type=semver,pattern={{version}}
49+
type=semver,pattern={{major}}.{{minor}}
50+
type=sha,prefix=
51+
52+
- name: Build and push Docker image
53+
uses: docker/build-push-action@v5
54+
with:
55+
context: .
56+
platforms: linux/amd64,linux/arm64
57+
push: ${{ github.event_name != 'pull_request' }}
58+
tags: ${{ steps.meta.outputs.tags }}
59+
labels: ${{ steps.meta.outputs.labels }}
60+
cache-from: type=gha
61+
cache-to: type=gha,mode=max

.gitignore

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
.Python
7+
build/
8+
develop-eggs/
9+
dist/
10+
downloads/
11+
eggs/
12+
.eggs/
13+
lib/
14+
lib64/
15+
parts/
16+
sdist/
17+
var/
18+
wheels/
19+
*.egg-info/
20+
.installed.cfg
21+
*.egg
22+
23+
# Virtual environments
24+
.venv/
25+
venv/
26+
ENV/
27+
28+
# IDE
29+
.idea/
30+
.vscode/
31+
*.swp
32+
*.swo
33+
34+
# Testing
35+
.pytest_cache/
36+
.coverage
37+
htmlcov/
38+
39+
# mypy
40+
.mypy_cache/
41+
42+
# ruff
43+
.ruff_cache/
44+
45+
# Claude
46+
.claude/
47+
48+
# Node.js
49+
node_modules/
50+
51+
# Built frontend assets (generated by npm run build)
52+
src/age_plotter/static/vendor/
53+
src/age_plotter/static/css/styles.css
54+
55+
# Local connections config (contains credentials)
56+
connections.json

Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Build frontend assets
2+
FROM node:20-slim AS frontend
3+
4+
WORKDIR /app
5+
COPY package*.json ./
6+
RUN npm ci
7+
8+
COPY scripts/ ./scripts/
9+
COPY tailwind.config.js ./
10+
COPY src/age_plotter/static/ ./src/age_plotter/static/
11+
COPY src/age_plotter/templates/ ./src/age_plotter/templates/
12+
13+
RUN npm run build
14+
15+
16+
# Python runtime
17+
FROM python:3.12-slim
18+
19+
WORKDIR /app
20+
21+
# Install uv for fast dependency management
22+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
23+
24+
# Copy project files
25+
COPY pyproject.toml ./
26+
COPY src/ ./src/
27+
28+
# Copy built frontend assets
29+
COPY --from=frontend /app/src/age_plotter/static/css/ ./src/age_plotter/static/css/
30+
COPY --from=frontend /app/src/age_plotter/static/vendor/ ./src/age_plotter/static/vendor/
31+
32+
# Install Python dependencies
33+
RUN uv pip install --system --no-cache .
34+
35+
# Default environment
36+
ENV AGE_PLOTTER_HOST=0.0.0.0
37+
ENV AGE_PLOTTER_PORT=8100
38+
39+
EXPOSE 8100
40+
41+
# Run without reload in production
42+
CMD ["python", "-c", "import uvicorn; uvicorn.run('age_plotter.main:app', host='0.0.0.0', port=int(__import__('os').environ.get('AGE_PLOTTER_PORT', '8100')))"]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 wedgemaster
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Age Plotter
2+
3+
A modern web UI for querying Neo4j and PostgreSQL AGE graph databases. Built as a lightweight alternative to Neo4j Browser and AGViewer.
4+
5+
![Age Plotter Screenshot](docs/screenshot.png)
6+
7+
## Features
8+
9+
- **Monaco Editor** - VS Code's editor with Cypher syntax highlighting
10+
- **Schema-aware completions** - autocomplete for node labels, relationship types, and properties
11+
- **Graph visualization** - interactive Cytoscape.js graphs with multiple layout options
12+
- **Dual view modes** - switch between table and graph views
13+
- **Query history** - with favorites and draft auto-save
14+
- **Multi-database support** - Neo4j (Bolt) and PostgreSQL AGE
15+
- **Session isolation** - each browser session has independent connections
16+
17+
## Requirements
18+
19+
- Python 3.11+
20+
- Node.js 18+
21+
- [uv](https://github.com/astral-sh/uv) (recommended) or pip
22+
23+
## Quick Start
24+
25+
```bash
26+
# Install dependencies
27+
npm install
28+
npm run build
29+
uv sync
30+
31+
# Run
32+
uv run python -m age_plotter
33+
```
34+
35+
Open http://localhost:8100
36+
37+
## Docker
38+
39+
```bash
40+
# Copy and edit connection config
41+
cp connections.example.json connections.json
42+
43+
# Run with docker-compose
44+
docker-compose up
45+
```
46+
47+
## Configuration
48+
49+
Environment variables:
50+
51+
| Variable | Default | Description |
52+
|----------|---------|-------------|
53+
| `AGE_PLOTTER_HOST` | `127.0.0.1` | Host to bind |
54+
| `AGE_PLOTTER_PORT` | `8100` | Port to bind |
55+
| `AGE_PLOTTER_CONNECTIONS` | - | Path to JSON file with preconfigured connections |
56+
57+
### Preconfigured Connections
58+
59+
Create a `connections.json` file (see `connections.example.json`):
60+
61+
```json
62+
[
63+
{
64+
"name": "Local Neo4j",
65+
"type": "neo4j",
66+
"uri": "bolt://localhost:7687",
67+
"username": "neo4j",
68+
"password": "password",
69+
"database": "neo4j"
70+
},
71+
{
72+
"name": "Local AGE",
73+
"type": "age",
74+
"host": "localhost",
75+
"port": 5432,
76+
"database": "mydb",
77+
"username": "postgres",
78+
"password": "password",
79+
"graph_name": "my_graph"
80+
}
81+
]
82+
```
83+
84+
Then:
85+
86+
```bash
87+
export AGE_PLOTTER_CONNECTIONS=/path/to/connections.json
88+
uv run python -m age_plotter
89+
```
90+
91+
## Development
92+
93+
```bash
94+
# Watch mode for frontend assets
95+
npm run watch:css
96+
npm run watch:js
97+
98+
# Run with auto-reload
99+
uv run python -m age_plotter --reload
100+
```
101+
102+
## License
103+
104+
MIT

connections.example.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"connections": [
3+
{
4+
"name": "Local Neo4j",
5+
"type": "neo4j",
6+
"uri": "bolt://localhost:7687",
7+
"username": "neo4j",
8+
"password": "your-password-here",
9+
"database": "neo4j"
10+
},
11+
{
12+
"name": "Local AGE",
13+
"type": "age",
14+
"host": "localhost",
15+
"port": 5432,
16+
"database": "your-age-db",
17+
"username": "your-age-user-name",
18+
"password": "your-password-here",
19+
"graph_name": "your-age-graph"
20+
}
21+
]
22+
}

docker-compose.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
services:
2+
age-plotter:
3+
image: ghcr.io/wedgemaster/age-plotter:main
4+
ports:
5+
- "${AGE_PLOTTER_PORT:-8100}:${AGE_PLOTTER_PORT:-8100}"
6+
environment:
7+
- AGE_PLOTTER_PORT=${AGE_PLOTTER_PORT:-8100}
8+
- AGE_PLOTTER_HOST=0.0.0.0
9+
- AGE_PLOTTER_CONNECTIONS=/app/connections.json
10+
volumes:
11+
# Mount connections file (create from connections.example.json)
12+
- ./connections.json:/app/connections.json:ro
13+
restart: unless-stopped

0 commit comments

Comments
 (0)