Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
version: 2
updates:
- package-ecosystem: bun
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 10
groups:
openchart:
patterns:
- '@opendata-ai/openchart-*'
react:
patterns:
- react
- react-dom
- '@types/react'
- '@types/react-dom'
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
actions:
patterns: ['*']
87 changes: 87 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: CI and Pages

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

permissions: {}

jobs:
verify:
name: Check and test production demo
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
pages: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Bun
uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
with:
bun-version: '1.4.2'
- name: Set up Node.js
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
node-version: '24'
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Lint, typecheck and test
run: |
bun run lint
bun run typecheck
bun run test
- name: Install browser dependencies
run: bunx playwright install --with-deps chromium webkit
- name: Build and test the nested deployment in every browser profile
env:
STUDIO_TEST_BASE_PATH: /openstudio/
run: bun run test:e2e
- name: Upload browser evidence
if: failure()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: browser-evidence
path: |
playwright-report/
test-results/
if-no-files-found: ignore
retention-days: 7
- name: Configure Pages
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- name: Upload the tested static artifact
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: dist

deploy:
name: Deploy GitHub Pages
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 5
concurrency:
group: pages
cancel-in-progress: false
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy
id: deployment
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.21.0
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Changelog

## [0.1.0] - 2026-10-14

### Added

- Standalone OpenStudio browser app, extracted from OpenChart and consuming its published public packages.
- CSV/TSV/JSON imports, explicit data preparation, chart/table/map controls, suggestions and diagnostics, responsive preview, local drafts, undo/redo, portable projects and exports.
- GitHub Pages demo deployment after production tests pass at `/openstudio/` in desktop Chromium, throttled phone Chromium, narrow Chromium and WebKit.

### Fixed

- Source replacement, editing and grouping changes require explicit filtering or summarization when observations would otherwise be combined silently.
- Composition controls and suggestions retain transformed fields and the source preparation pipeline across recovery.
- Lollipop composition validates its supported axis orientation and preserves separate series.
- Delimited imports reject malformed quotes and correctly distinguish quoted tabs from TSV delimiters.
- Failed draft recovery preserves downloadable originals before autosave resumes; storage failures cannot overwrite the protected draft.
- Series color picker interactions produce one undoable edit instead of filling history with drag events.
- The deployed notice points to licenses included at the static artifact root.

### Privacy and hosting

- Imported data stays in the browser. Drafts use local storage, and downloaded project files preserve source data and preparation. The demo has no backend, accounts, cloud storage or collaboration service.
14 changes: 14 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
OpenStudio

OpenStudio originates from the OpenChart Studio authoring application in
https://github.com/tryopendata/openchart and uses the public OpenChart packages.
Application source is distributed under the Apache License, Version 2.0.
See LICENSE for the full license and copyright notice.

Inter font
Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter)
The bundled src/assets/InterVariable.woff2 is distributed under the SIL Open
Font License, Version 1.1. See public/Inter-LICENSE.txt. Vite copies that license
to Inter-LICENSE.txt in the deployed static artifact.

Other third-party package licenses remain with their respective packages.
69 changes: 69 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# OpenStudio

A browser-based visualization editor and interactive demo of [OpenChart](https://github.com/tryopendata/openchart). Import your data, prepare it, design a chart, table or map, and download the result. The GitHub Pages demo runs the complete editor locally in your browser, with no account or backend.

**[Open the demo](https://tryopendata.github.io/openstudio/)** · [Authoring guide](docs/authoring.md) · [Changelog](CHANGELOG.md) · [OpenChart library](https://github.com/tryopendata/openchart)

## What you can do

- Explore eight sample documents or import CSV, TSV, OpenChart JSON and Studio project backups.
- Edit values and field types, filter rows, calculate explicit grouped summaries, and replace a dataset while retaining its design.
- Compose bars, lines, areas, scatterplots, lollipops, intervals, histograms and tables; edit axes, colors, labels, facets and annotations.
- Configure table columns, inline visuals, search and phone layouts; inspect map joins, palettes and zoom.
- Inspect exact observations, compare values, preview phone/article/wide layouts, and use suggestions and design diagnostics.
- Undo and redo edits, recover a local draft, download project backups and JSON, and export chart/map SVG or PNG and data CSV.

See the [authoring guide](docs/authoring.md) for the supported controls and the limits of each workflow. Sample datasets are examples, not live data feeds.

## Your data

Local CSV, TSV and JSON files are parsed in the browser. OpenStudio does not send imported datasets to a server. One working draft is stored in browser local storage, scoped to the current browser profile and origin. Different paths on the same origin share that storage; private browsing, clearing site data or switching browsers/hosts can remove or separate drafts.

Use **Download Studio project** to keep the source data, preparation and visualization together. Plain JSON preserves the visualization document; CSV and image exports are not lossless project backups. Browser storage can be smaller than an accepted import, so a successful import does not guarantee the draft can be saved. The editor reports storage failures. If a draft cannot be reopened, OpenStudio preserves its original text before saving new edits. Use **Download recovery draft** to keep that original. If it cannot be preserved, autosave stays disabled so the saved original is not overwritten; download your current Studio project as well.

Plain CSV/TSV/JSON imports accept up to **5 MB and 20,000 rows**. Studio project backups accept **20 MB**. There are no cloud projects, accounts, collaborative sessions, public share links or publishing APIs. You can publish downloaded artifacts through your own tools.

## Develop

Install Bun 1.4.2 and Node.js 24, then run:

```sh
bun install --frozen-lockfile
bun run dev # http://127.0.0.1:6007/
```

OpenStudio consumes pinned public OpenChart packages. It builds independently; an OpenChart checkout or library build is not required.

```sh
bun run lint
bun run typecheck
bun run test
bun run build # dist/
bun run preview # http://127.0.0.1:6008/
```

For the production browser suite:

```sh
bunx playwright install chromium webkit
STUDIO_TEST_BASE_PATH=/openstudio/ bun run test:e2e
```

On Linux CI, install browsers with `bunx playwright install --with-deps chromium webkit`. The suite builds the static artifact and serves it beneath `/openstudio/` in desktop Chromium, throttled phone Chromium, narrow Chromium and phone WebKit. Port 6008 must be free. Browser reports and traces are written to ignored `playwright-report/` and `test-results/` directories.

## GitHub Pages deployment

The repository's [CI and Pages workflow](.github/workflows/ci.yml) checks pull requests and pushes to `main`. It deploys the tested `dist/` artifact after all checks pass on `main`.

1. In repository **Settings → Pages → Build and deployment**, select **GitHub Actions** as the source.
2. Allow the `github-pages` environment to deploy from `main`; retain any desired reviewer protection.
3. Push or merge to `main`, or manually run **CI and Pages** on `main` from the Actions tab.
4. Open the URL shown by the deployment job: [tryopendata.github.io/openstudio/](https://tryopendata.github.io/openstudio/).

The deploy job uses GitHub's built-in token and OIDC. No application secrets, API credentials or backend deployment are needed. See [GitHub's custom workflow documentation](https://docs.github.com/en/pages/getting-started-with-github-pages/using-custom-workflows-with-github-pages) for repository and environment setup.

Vite keeps `base: './'`: scripts, styles and the bundled font use relative URLs. Preserve the trailing slash for nested deployments. To use another static host, serve the whole `dist/` directory over HTTPS, cache hashed assets immutably and revalidate HTML. Development, preview and QA servers are local tools. To roll back the demo, revert the affected commit on `main` and let the workflow rebuild and deploy it.

## License

Application code is licensed under [Apache-2.0](LICENSE). The bundled Inter font is licensed under the [SIL Open Font License 1.1](public/Inter-LICENSE.txt); that license is also included in the deployed site. See [NOTICE](NOTICE) for attribution.
46 changes: 46 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
"files": {
"includes": [
"src/**"
]
},
"formatter": {
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"css": {
"formatter": {
"enabled": true
},
"linter": {
"enabled": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "all",
"semicolons": "always"
}
},
"linter": {
"rules": {
"recommended": true,
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": "error",
"useExhaustiveDependencies": "warn"
},
"style": {
"noNonNullAssertion": "off",
"useImportType": "error"
},
"suspicious": {
"noExplicitAny": "on",
"noAssignInExpressions": "off"
}
}
}
}
Loading
Loading