A minimal reference implementation of a Next.js
front-end for the Workflow Orchestrator
framework. It wraps the published
@orchestrator-ui/orchestrator-ui-components library
(Elastic EUI based) and adds a small set of
example pages that demonstrate how to customize navigation, branding,
translations, and authentication.
Most teams adopt this repo by making a copy of it and tailoring it to their own network/service domain, then pointing it at a Workflow Orchestrator backend (REST + GraphQL + optional WebSocket).
- Features
- Architecture
- Prerequisites
- Quick start
- Configuration
- Project layout
- Customization
- npm scripts
- Building & deploying
- Local Keycloak for OAuth testing
- Updating the component library
- Breaking changes
- Contributing
- License
- Minimal reference integration with Workflow Orchestrator, with sensible defaults
- Subscription, workflow, task and metadata management pages
- Built-in pages for search
- OAuth2 / OIDC login via NextAuth with refresh-token rotation
- Internationalization:
en-GB(default) andnl-NL, both extensible - Theme toggle (light / dark) and per-environment banners
- Standalone Next.js production output, ready to containerize
flowchart LR
Browser["Browser<br/>(Elastic EUI)"]
UI["example-orchestrator-ui<br/>Next.js 15 · pages router"]
Backend["Workflow Orchestrator<br/>(REST + GraphQL + WebSocket)"]
OIDC["OIDC Provider<br/>(e.g. Keycloak)"]
Browser <--> UI
UI -->|REST + GraphQL + WS| Backend
UI -->|/api/auth/* · NextAuth| OIDC
The application is intentionally thin: nearly all screens come from
@orchestrator-ui/orchestrator-ui-components. This repo wires those
components into a Next.js app and provides the integration glue
(pages/_app.tsx, configuration/, translations/,
components/AppLogo/).
- Node.js 18+ (the Docker image uses
node:18-alpine) - npm (the lockfile is
package-lock.json) - A running Workflow Orchestrator backend. The simplest option is the
example-orchestratorreference backend (Docker Compose).
git clone git@github.com:workfloworchestrator/example-orchestrator-ui.git
cd example-orchestrator-ui
npm install
cp .env.example .env
# edit .env — at minimum, for local dev you typically want:
# OAUTH2_ACTIVE=false
# ORCHESTRATOR_API_HOST=http://localhost:8080
# ORCHESTRATOR_GRAPHQL_HOST=http://localhost:8080
npm run dev # http://localhost:3000In a separate terminal, start a backend to talk to:
git clone git@github.com:workfloworchestrator/example-orchestrator.git
cd example-orchestrator
docker compose upYou can of course point ORCHESTRATOR_* at any other orchestrator
instance.
All runtime configuration is read from environment variables.
configuration/configuration.ts maps them into the OrchestratorConfig
object that is passed to the component library;
pages/api/auth/[...nextauth].ts reads the OAuth/OIDC variables.
A complete starter set lives in .env.example — copy it to .env (or
.env.local) and adjust.
| Variable | Description |
|---|---|
ORCHESTRATOR_API_HOST |
Base URL of the orchestrator REST API (scheme + host + port). |
ORCHESTRATOR_API_PATH |
Path prefix appended to the API host (e.g. /api). |
ORCHESTRATOR_GRAPHQL_HOST |
Base URL of the GraphQL endpoint. |
ORCHESTRATOR_GRAPHQL_PATH |
Path of the GraphQL endpoint (e.g. /api/graphql). |
ORCHESTRATOR_WEBSOCKET_URL |
WebSocket URL for live updates. |
USE_WEB_SOCKETS |
true to enable WebSocket-driven updates. |
Authentication is handled by NextAuth with
a generic OIDC provider configured from the wellKnown URL. PKCE +
state checks are enabled, and access tokens are refreshed automatically.
| Variable | Description |
|---|---|
OAUTH2_ACTIVE |
Set to false to disable login entirely (handy for local dev). |
OAUTH2_CLIENT_ID |
OAuth2 client ID. |
OAUTH2_CLIENT_SECRET |
Optional. Omit for public/PKCE-only clients. |
OIDC_CONF_FULL_WELL_KNOWN_URL |
Full URL to the OIDC .well-known/openid-configuration document. |
NEXTAUTH_PROVIDER_ID |
Internal NextAuth provider id (e.g. keycloak). |
NEXTAUTH_PROVIDER_NAME |
Human-readable name shown on the sign-in screen. |
NEXTAUTH_AUTHORIZATION_SCOPE_OVERRIDE |
Optional. Override the requested scopes (default: openid profile). |
NEXTAUTH_SECRET |
Standard NextAuth secret for signing session tokens (required in prod). |
NEXTAUTH_URL |
Public base URL of the deployed UI (required by NextAuth in production). |
Heads up: several auth env vars were renamed in commit
edec88c. Seebreaking-changes.mdif you're upgrading from an older version.
| Variable | Description |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------ | ----------- |
| ENVIRONMENT_NAME | Label shown in the top bar (e.g. DEVELOPMENT, STAGING, PRODUCTION). |
| USE_THEME_TOGGLE | true to show the light/dark theme switcher. |
| SHOW_WORKFLOW_INFORMATION_LINK | true to show a "more info" link on workflow pages. |
| WORKFLOW_INFORMATION_LINK_URL | Target URL of that link. |
| ENABLE_SUPPORT_MENU_ITEM | true to add a "Support" menu item. |
| SUPPORT_MENU_ITEM_URL | Target URL for the support menu item. |
| ENABLE_AO_STACK_STATUS | true to show the AO-stack status indicator. |
| AO_STACK_STATUS_URL | Endpoint that the stack-status widget polls. |
| START_WORKFLOW_FILTERS | Pipe-separated list of workflow categories to expose on the start page. Underscores are converted to spaces, e.g. Create | Modify | Terminate. |
.
├── components/AppLogo/ # branding override rendered in the side nav
├── configuration/ # env → OrchestratorConfig mapping
├── pages/ # Next.js routes (pages router)
│ ├── _app.tsx # providers, menu, auth wiring
│ ├── index.tsx # WfoStartPage
│ ├── search.tsx
│ ├── settings.tsx
│ ├── subscriptions/ # list + detail
│ ├── workflows/ # list, detail, "new"
│ ├── tasks/ # list, detail, "new"
│ ├── metadata/ # products, product blocks, resource types, tasks, …
│ └── api/
│ └── auth/[...nextauth].ts # NextAuth + OIDC provider
├── translations/ # en-GB / nl-NL message catalogs + provider
├── font/ # Inter web font
├── public/ # static assets (favicon, etc.)
├── .env.example # template — copy to .env
├── next.config.js # i18n + standalone output + transpiled deps
├── Dockerfile # multi-stage Next.js standalone build
└── docker-compose.yml # Keycloak dev instance for OAuth testing
Most pages are one-liners that delegate to a component from
@orchestrator-ui/orchestrator-ui-components. For example:
// pages/search.tsx
import { WfoSearch } from '@orchestrator-ui/orchestrator-ui-components';
export default function SearchPage() {
return <WfoSearch />;
}This makes it easy to override individual screens by editing one file.
The side navigation is configured in pages/_app.tsx via the
overrideMenuItems prop on <WfoPageTemplate>. The reference
implementation adds an extra entry Search by appending to the default menu items:
const addMenuItems = (defaultMenuItems) => [
...defaultMenuItems,
{ name: 'Search', id: '20', href: '/search' /* … */ },
];Add, remove, or reorder entries here to shape your own navigation.
components/AppLogo/AppLogo.tsx exports getAppLogo(), which is passed
to <WfoPageTemplate getAppLogo={getAppLogo} />. Replace its contents
(or the neighbouring styles.ts) to swap in your own logo / wordmark.
Static assets such as favicon.png live in public/.
translations/ contains the per-locale JSON catalogs that get merged
into the standard messages shipped with the component library. Add or
override keys on a per-key basis; missing keys fall back to the library
defaults.
See translations/README.md for the full
override rules, including how dynamic form-field translations from the
backend translations/${locale} endpoint are merged into
pydanticForms.backendTranslations.
To add a new locale:
- Drop a
<locale>.jsonnext to the existing ones. - Add it to the
localesarray innext.config.js. - Add a matching
caseintranslations/translationsProvider.tsx.
Because this is the Next.js pages router, you add a new route simply
by creating a file under pages/. To make it appear in the nav, add an
entry to addMenuItems in pages/_app.tsx.
| Command | Purpose |
|---|---|
npm run dev |
Start the Next.js dev server on port 3000. |
npm run build |
Production build (emits standalone output). |
npm start |
Serve the production build. |
npm run tsc |
Type-check the project without emitting. |
npm run lint |
Run ESLint. |
npm run prettier |
Check formatting. |
npm run prettier-fix |
Apply Prettier formatting. |
npm test |
Run Jest (passes with no tests). |
A Husky postinstall hook is registered for pre-commit checks.
The included Dockerfile produces a small two-stage image:
docker build -t example-orchestrator-ui .
docker run --rm -p 3000:3000 --env-file .env example-orchestrator-uiInternally it runs next build with output: 'standalone' (see
next.config.js) and copies only the runtime artifacts into the final
image. node server.js is the entry point and the container listens on
port 3000.
For production deployments, remember to set:
NEXTAUTH_URLto the public URL of the UINEXTAUTH_SECRETto a strong random value- the
ORCHESTRATOR_*variables to your real backend OAUTH2_*andOIDC_CONF_FULL_WELL_KNOWN_URLfor your IdP
docker-compose.yml ships a Keycloak
container to test the OAuth2 flow locally:
KEYCLOAK_PORT=8081 \
KEYCLOAK_ADMIN=admin \
KEYCLOAK_ADMIN_PASSWORD=admin \
docker compose upThen create a realm + client in the Keycloak admin UI and point the
OAUTH2_* and OIDC_CONF_FULL_WELL_KNOWN_URL variables at it.
@orchestrator-ui/orchestrator-ui-components is declared with version
* so the Turborepo monorepo build always resolves the freshest version.
When using this repo standalone, you have to refresh the lockfile
manually:
npm update @orchestrator-ui/orchestrator-ui-components
npm update @orchestrator-ui/eslint-config-custom
npm update @orchestrator-ui/jest-config
npm update @orchestrator-ui/tsconfigSee update-instructions.md for the full
note.
Notable version-to-version breakage (env-var renames, prop changes,
etc.) is tracked in breaking-changes.md. Read
it before you upgrade.
Pull requests are welcome. Before sending one:
npm run lint
npm run tsc
npm run prettier
npm testThe Husky pre-commit hook will run formatting/linting on staged files
automatically.
See the upstream Workflow Orchestrator organization for licensing terms.