ODE Desktop is the Open Data Ensemble desktop application (Tauri + React + Rust). It provides two modes:
| Mode | Purpose |
|---|---|
| Data management | Pull, inspect, correct, and sync observations; import/export; conflicts and local workspace state. |
| Forms / app workbench | Develop and test app bundles, embedded formplayer, and custom apps — aligned with Formulus and the shared WebView contract. |
The internal Rust crate may still be named custodian; user-facing strings use ODE Desktop.
- Field and data staff managing observations and sync (Data management).
- Form and app authors testing bundles and custom apps against Synkronus before mobile deploy (Workbench).
Relationship to other ODE components: Synkronus (API), Formulus + formplayer (runtime parity), Portal and CLI (same public API — no privileged desktop channel). Long-form prose here is intended to be copy-friendly for opendataensemble.org documentation; keep user-facing sections free of repo-only trivia (put contributor notes under Development).
Official builds are produced with pnpm tauri build (artifacts vary by OS: .msi, .dmg, .app, AppImage, .deb, etc.). When releases are published, attach those bundles to GitHub Releases and link them from project docs.
Prerequisites
- Windows: WebView2 (usually present on current Windows 10/11).
- Linux: WebKitGTK and related packages as required by Tauri prerequisites.
- macOS: Xcode command-line tools for development builds.
A placeholder curl-style installer script is at scripts/install-ode-desktop.sh (to be wired to real release asset URLs). For early testing, run from source (below).
cd desktop
pnpm install
pnpm tauri devpnpm tauri dev starts the Vite dev server and opens the Tauri desktop window (required for the Rust backend). Do not open http://localhost:1420 in a regular browser — IPC commands such as invoke are only available inside the Tauri shell.
| Script | Purpose |
|---|---|
pnpm dev |
Vite dev server (frontend). |
pnpm build |
Typecheck + Vite production build. |
pnpm build:formplayer |
Build ../formulus-formplayer and copy output into public/formplayer_dist/. |
pnpm build:tauri |
Prepare Formplayer assets (build:formplayer) and then run the desktop frontend build. |
pnpm tauri build |
Full desktop bundle; automatically runs pnpm build:tauri first, so the packaged app includes formplayer_dist. |
pnpm lint / pnpm lint:fix |
ESLint. |
pnpm format / pnpm format:check |
Prettier. |
pnpm test |
Vitest (unit / component tests). |
pnpm typecheck |
tsc --noEmit. |
pnpm codegen:synk-client |
Regenerate TypeScript client from Synkronus OpenAPI. |
pnpm copy:formplayer |
Copy ../formulus-formplayer/build/ → public/formplayer_dist/. Prefer from formulus-formplayer/: pnpm run build:copy (build + Formulus + desktop copy). |
cd src-tauri
cargo test
cargo fmt
cargo clippyConfiguration is in openapi.client.config.json (paths relative to desktop/):
- Default spec:
../synkronus/openapi/synkronus.yaml - Output:
src/generated/synkronus-client
Override at generation time:
OPENAPI_SPEC_RELATIVE_PATHOPENAPI_OUTPUT_RELATIVE_PATH
CI regenerates the client and fails if the repo does not match (ode-desktop workflow).
For custom app authors testing locally before publishing a bundle:
- Workbench → Bundles → turn Developer mode On and pick a folder that contains
index.html(e.g. yourdist/output). - Optional: add
forms/next toindex.htmlwith the usual{formType}/schema.json+ui.jsonlayout for Form preview. - Use Refresh app after each build (also available from the orange Workbench banner while mode is on).
Mirrored files live under bundles/dev-local/app/ and bundles/dev-local/forms/ in the active profile workspace. Synk downloads stay in bundles/active/ — use Refresh from server on Bundles to update those.
User guide: ODE Desktop developer mode. Agent reference: AGENTS.md.
- Bridge contract:
formulus/src/webview/FormulusInterfaceDefinition.ts— source of truth forformulusAPI/ postMessage. After changes, runsync-interfaceinformulus-formplayerand mirror behavior in the desktop WebView host. - Dev mirror paths:
bundles/dev-local/app/,bundles/dev-local/forms/when developer mode is on;bundles/active/otherwise (see AGENTS.md). - Form preview host (Workbench → Form preview):
public/formulus-injection.js+ iframe shim; parent handlespostMessageinsrc/lib/formPreviewBridge.ts(explicit matrix perFormulusInjectionScriptrequesttype; device APIs including camera, audio, and video are stubbed in preview; observations + URIs use Tauri where applicable). Nested sub-observation flows (openFormplayer+options.subObservationMode) open a stacked Form preview iframe and resolve the parent promise withFormCompletionResultwithout persisting the child as a top-level observation. - Bundle extensions: merge rules for
forms/ext.jsonandforms/{form}/ext.jsonfollow FormulusExtensionService; seesrc/lib/bundleResolution.ts. - Embedded formplayer: production build copied into
public/formplayer_dist/; load in a WebView with the sameFormInitDataexpectations as mobile (seesrc/lib/formplayerHost.tsfor placeholder types).
Bundled icons live under src-tauri/icons/ and are referenced from src-tauri/tauri.conf.json bundle.icon. Misplaced iOS-style asset folders are not used for Tauri Linux bundles and have been removed to avoid confusion. For deb/AppImage installs, verify the packaged .desktop file Icon= entry resolves on Ubuntu/GNOME (dash, dock, Alt+Tab).
Conventional Commits; run pnpm lint, pnpm format:check, and pnpm test before pushing. PRs touching desktop/** trigger the ODE Desktop GitHub Actions workflow (see .github/CICD.md).