qp-workflow-react
v1.0.5
Published
React components and hooks for visual workflow design and execution. Pairs with Chd.Workflow .NET backend.
Maintainers
Readme
qp-workflow-react
qp-workflow-react is the React + TypeScript companion package for the Chd.Workflow backend engine. It provides ready-to-use UI pieces for both workflow design and workflow execution.
The package is designed for teams that want to move quickly without rebuilding workflow UI from scratch for every project.
It includes:
- a visual workflow designer,
- a runtime workflow runner,
- a TypeScript API client,
- React hooks for custom experiences,
- localization support,
- external form helpers,
- an admin modal for workflow notification settings.
Although it pairs naturally with Chd.Workflow, the client and components can also work with another backend if the same REST contract is respected.
Table of Contents
- Why this package exists
- Main capabilities
- Installation
- Package exports
- Quick start
- Main components
- Hook usage
- Client API
- TypeScript model overview
- Field system and validation
- External form integration
- Localization
- Backend contract
- Build and publish
- Troubleshooting
- License
Why this package exists
A workflow UI is usually more than just a form.
A real workflow screen often needs to:
- load the current workflow state,
- render fields based on the current node,
- validate inputs,
- show available transitions,
- support confirmation or comment requirements,
- handle guard failures,
- load dropdown options from the backend,
- support external forms,
- support multiple languages,
- give designers a way to edit the workflow visually.
If every project builds this from zero, teams spend a lot of time repeating the same work.
qp-workflow-react solves that by packaging the repeated parts into reusable building blocks.
This lets teams focus on:
- business logic,
- design customization,
- backend actions and rules,
- project-specific workflows.
Main capabilities
Visual workflow design
TreeDesigner provides a visual tree-based editing experience.
Runtime workflow execution
WorkflowRunner renders the active node, fields, and available actions.
Custom workflow UX with hooks
The React hook export lets you build your own UI while reusing state loading and transition logic.
API abstraction
WorkflowClient wraps the REST API in a simple TypeScript class.
External form support
Helpers make it easier to connect non-React or external pages to the same workflow.
Localization
English and Turkish translations are available out of the box.
Notification admin UI
A ready modal exists for notification settings management when the backend exposes those endpoints.
Installation
npm install qp-workflow-reactPeer dependencies:
react >= 18react-dom >= 18
This package builds around a backend that follows the Chd.Workflow REST contract.
Package exports
The package currently exports the following main items:
Core API and types
WorkflowClientWorkflowClientError- all public workflow types from
src/types
React hook export
useWorkflowReact
Designer exports
TreeDesignerWorkflowDesignercreateDefaultWorkflowDefinition
Runtime exports
WorkflowRunner
External form helpers
buildExternalFormUrlparseWorkflowParamsuseWorkflowParamsuseWorkflowExternalForm
Host/admin export
WorkflowHostNotificationSettingsModal
Localization exports
LocaleProvideruseLocalegetLocalelocales- locale-related types
Quick start
A basic end-to-end scenario usually has two parts.
1. Design a workflow
import { TreeDesigner } from 'qp-workflow-react';
<TreeDesigner
apiUrl="http://localhost:5035/api/workflow"
initialDefinitionId="leave-request"
locale="en"
enableFormEditor
onSaved={(definition) => console.log('saved', definition.id)}
/>2. Run a workflow instance
import { WorkflowRunner, WorkflowClient } from 'qp-workflow-react';
const client = new WorkflowClient({
apiUrl: 'http://localhost:5035/api/workflow'
});
const instance = await client.createInstance('leave-request', {
employeeId: '123'
});
<WorkflowRunner
apiUrl="http://localhost:5035/api/workflow"
instanceId={instance.id}
locale="en"
theme="dark"
onCompleted={(result) => console.log('completed', result.id)}
/>Main components
TreeDesigner
TreeDesigner is the main visual workflow editor.
It is useful when you want to:
- create nodes visually,
- manage transitions,
- choose action handlers,
- choose guard handlers,
- set allowed roles/groups,
- edit form fields,
- save definitions through the REST API.
Basic usage
<TreeDesigner
apiUrl="http://localhost:5035/api/workflow"
initialDefinitionId="leave-request"
locale="en"
enableFormEditor
onSaved={(definition) => console.log(definition.id)}
/>Main props
| Prop | Type | Description |
|---|---|---|
| apiUrl | string | Base workflow API URL |
| initialDefinitionId? | string | Definition id to load first |
| onSaved? | (saved) => void | Called after successful save |
| locale? | 'en' \| 'tr' | UI language |
| enableFormEditor? | boolean | Enables field editing UI |
Practical notes
- The component loads action metadata from
/actions. - It loads guard metadata from
/guards. - It loads participant group data from
/admin/participant-groups. - It can create a default definition if the requested definition does not exist.
This makes it suitable for both new workflow design and editing existing definitions.
WorkflowRunner
WorkflowRunner is the runtime execution component.
It is useful when you want a ready-made UI that:
- loads the workflow state,
- renders the current step fields,
- validates values,
- displays available transitions,
- handles comments and confirmations,
- supports dark and light themes,
- refreshes state after transitions.
Basic usage
<WorkflowRunner
apiUrl="http://localhost:5035/api/workflow"
instanceId="instance-abc123"
locale="en"
theme="dark"
onTransition={(action, state) => console.log(action, state)}
onCompleted={(instance) => console.log(instance.id)}
onError={(error) => console.error(error)}
/>Main props
| Prop | Type | Description |
|---|---|---|
| apiUrl | string | Base workflow API URL |
| instanceId | string | Instance to render |
| theme? | 'dark' \| 'light' | Runner theme |
| locale? | 'en' \| 'tr' | UI language |
| debug? | boolean | Shows extra debug data |
| onCompleted? | (instance) => void | Called when the workflow reaches completion |
| onTransition? | (action, newState) => void | Called after successful transition |
| onError? | (error) => void | Called on workflow errors |
| loadingComponent? | ReactNode | Custom loading UI |
| errorComponent? | (error, retry) => ReactNode | Custom error UI |
| completedComponent? | (node, instance) => ReactNode | Custom completion UI |
| className? | string | Custom CSS class |
| style? | CSSProperties | Inline style override |
Built-in behavior
The runner already handles many common tasks:
- loading
GET /instances/{id}/state, - rendering fields by type,
- preserving and updating form values,
- showing validation errors,
- calling transition endpoints,
- handling
requiresConfirmation, - handling
requiresComment, - handling guard failures returned by the backend,
- loading field options when needed.
This is often enough for production usage without writing a custom runtime screen.
WorkflowDesigner
WorkflowDesigner is a more form-oriented design alternative.
Use it if you want a simpler editing style instead of the main tree-first visual layout.
import { WorkflowDesigner } from 'qp-workflow-react';
<WorkflowDesigner
apiUrl="http://localhost:5035/api/workflow"
initialDefinitionId="leave-request"
onSaved={(definition) => console.log(definition.id)}
/>WorkflowHostNotificationSettingsModal
This modal is intended for host/admin screens.
It communicates with:
GET /admin/notification-settingsPUT /admin/notification-settings
It helps manage workflow notification-related settings such as:
- SMTP host,
- SMTP port,
- SMTP user,
- password presence,
- from email,
- SSL usage,
- subject and body templates,
- group member resolution SQL,
- email column name.
Example
import { WorkflowHostNotificationSettingsModal } from 'qp-workflow-react';
<WorkflowHostNotificationSettingsModal
open={open}
onClose={() => setOpen(false)}
apiUrl="http://localhost:5035/api/workflow"
locale="en"
/>A 503 response usually means the backend host has not enabled the required persistence service for this admin area.
Hook usage
The package exports the React hook as useWorkflowReact.
This hook is useful when:
WorkflowRunneris too opinionated for your screen,- you want your own layout,
- you still want to reuse workflow loading and transition logic.
Example
import { useWorkflowReact, WorkflowClient } from 'qp-workflow-react';
const client = new WorkflowClient({ apiUrl: 'http://localhost:5035/api/workflow' });
function CustomRunner({ instanceId }: { instanceId: string }) {
const {
state,
currentNode,
fields,
availableActions,
values,
errors,
isLoading,
error,
setValue,
transition,
reload,
} = useWorkflowReact({ client, instanceId });
if (isLoading) return <p>Loading...</p>;
if (error) return <p>{error.message}</p>;
return (
<div>
<h2>{currentNode?.title ?? currentNode?.name}</h2>
{fields.map(field => (
<div key={field.name}>
<label>{field.label ?? field.name}</label>
<input
value={String(values[field.name] ?? '')}
onChange={e => setValue(field.name, e.target.value)}
/>
{errors[field.name] && <div>{errors[field.name]}</div>}
</div>
))}
{availableActions.map(action => (
<button key={action.id} onClick={() => transition(action.action)}>
{action.label ?? action.action}
</button>
))}
<button onClick={() => reload()}>Reload</button>
</div>
);
}What the hook returns
The hook exposes:
- current workflow state,
- current node,
- fields,
- available actions,
- history,
- breadcrumb,
- form values,
- validation errors,
- loading/error state,
- helpers such as
setValue,setValues,transition,validate,reload,createInstance,cancel.
This is a good option when you need a custom UI but do not want to rebuild the workflow data layer yourself.
Client API
WorkflowClient is a TypeScript wrapper around the workflow REST API.
It is framework-agnostic at the data level and can be used outside the ready React components.
Basic setup
import { WorkflowClient } from 'qp-workflow-react';
const client = new WorkflowClient({
apiUrl: 'http://localhost:5035/api/workflow',
headers: {
'X-Tenant-Id': 'tenant-1'
},
onError: (error) => console.error(error)
});Helpful runtime methods
client.setAuthToken('Bearer token');
client.clearAuthToken();
client.setApiUrl('https://example.com/api/workflow');Main methods
Definitions
getDefinitions(tenantId?)getDefinition(id)createDefinition(definition)updateDefinition(id, definition)deleteDefinition(id)
Instances
getInstance(id)getState(instanceId)createInstance(definitionId, data?, userId?)transition(instanceId, action, data?, userId?, comment?)validate(instanceId, data)getFieldOptions(instanceId, fieldName)cancel(instanceId, request?)
Admin
getNotificationAdminSettings()updateNotificationAdminSettings(body)
Error model
The client throws WorkflowClientError.
Important properties include:
messagestatuserrors?
This is useful when you want to surface backend validation details directly in your UI.
TypeScript model overview
The package exports a broad public type model that mirrors the backend contract.
Important examples include:
Enums and union types
NodeTypeFieldTypeFormTypeWorkflowStatusRuleTypeButtonStyle
Core models
FieldOptionFieldTransitionRuleRuleMappingNodeWorkflowDefinitionWorkflowInstanceHistoryEntryWorkflowState
Metadata models
WorkflowActionInfoWorkflowInputPropertyWorkflowOutputPropertyWorkflowGuardInfoWorkflowRuleInfo
Client models
WorkflowClientOptionsCreateInstanceRequestTransitionRequestCancelRequestValidationResultWorkflowNotificationAdminSettings
This makes the package pleasant to use in TypeScript-heavy projects because both component usage and API usage remain strongly typed.
Field system and validation
The field system supports both backend-aligned field types and frontend-friendly validation behavior.
Supported field types
Current public field type support includes:
TextTextAreaNumberDecimalDateDateTimeTimeCheckboxRadioDropdownMultiSelectFileImageRichTextHiddenEmailPhoneCurrency
Validation behavior
The runtime supports practical validation such as:
- required checks,
- min and max values,
- max length,
- regex validation,
- type-based validation for number/date/email/phone/currency.
Field options
For selectable fields, options can come from:
- static field configuration,
- backend field option endpoints.
Visibility support
The field model also includes support for visibility expressions and guard-related visibility metadata.
This helps advanced forms stay dynamic without requiring every project to write custom visibility logic from zero.
External form integration
External forms are useful when the workflow step should be completed in another page or system.
Examples:
- a legacy MVC/Razor page,
- an older admin form,
- a third-party hosted screen,
- a specialized custom data entry module.
Helper: buildExternalFormUrl
This helper creates a URL with workflow context parameters.
Typical values added include:
workflowInstanceIdworkflowNodeIdworkflowDefinitionIdworkflowActionsworkflowCallback
Helper: parseWorkflowParams
Reads workflow context from query string.
Hook: useWorkflowParams
Convenient React wrapper over parseWorkflowParams().
Hook: useWorkflowExternalForm
A higher-level helper for external form pages.
It helps with:
- reading workflow context,
- calling transition APIs,
- managing loading and error state,
- returning to the callback URL after submission.
Example
import { useWorkflowExternalForm } from 'qp-workflow-react';
function ExternalApprovalPage() {
const workflow = useWorkflowExternalForm({
apiUrl: '/api/workflow'
});
async function submitApprove() {
await workflow.submit('approve', {
note: 'Approved from external page'
});
}
return (
<div>
<button onClick={submitApprove} disabled={workflow.loading}>
Approve
</button>
{workflow.error && <p>{workflow.error}</p>}
{workflow.success && <p>{workflow.success}</p>}
</div>
);
}This is especially useful when not every workflow step should stay inside the main React runner screen.
Localization
The package currently includes English and Turkish locale support.
Basic usage
import { getLocale } from 'qp-workflow-react';
const t = getLocale('en');
console.log(t.common.save);Provider-based usage
import { LocaleProvider } from 'qp-workflow-react';
<LocaleProvider locale="tr">
<App />
</LocaleProvider>Supported locale codes
'en''tr'
Where localization is used
Localization is used in areas such as:
- common labels,
- runner UI,
- designer UI,
- validation messages,
- action labels,
- host notification settings modal.
This makes the package easier to adopt in multilingual internal systems.
Backend contract
This package is designed around the Chd.Workflow backend contract.
Expected endpoints
| Method | Path |
|---|---|
| GET | /definitions |
| GET | /definitions/{id} |
| POST | /definitions |
| PUT | /definitions/{id} |
| DELETE | /definitions/{id} |
| GET | /instances/{id} |
| GET | /instances/{id}/state |
| GET | /instances/{id}/field-options/{fieldName} |
| POST | /instances |
| POST | /instances/{id}/transition |
| POST | /instances/{id}/validate |
| POST | /instances/{id}/cancel |
| GET | /actions |
| GET | /actions/grouped |
| GET | /guards |
| GET | /rules |
| GET | /rules/grouped |
| GET | /rules/{name} |
| GET | /admin/notification-settings |
| PUT | /admin/notification-settings |
| GET | /admin/participant-groups |
JSON style expectations
The package assumes a backend that behaves similarly to the current Chd.Workflow implementation.
In practice, that means:
- camelCase JSON is preferred,
- enum values should be serialized in a compatible way,
- error payloads should include
errorand optionallyerrors.
If you build your own compatible backend, the React package can still be reused.
Build and publish
Important package information from the current project setup:
- package name:
qp-workflow-react - build tool:
tsup - output:
dist - peer dependencies: React 18+
Common commands
npm install
npm run build
npm run dev
npm run typecheckPublish notes
When publishing, keep these fields correct in package.json:
nameversiondescriptionmainmoduletypesrepositorylicensefiles
These details matter because the package is intended to be consumed as a reusable npm library, not only as a local project.
Troubleshooting
Designer cannot load actions or guards
Check that the backend API is running and that:
/actionsworks,/guardsworks,- CORS is configured correctly,
- the API URL is correct.
Participant groups are empty
Check /admin/participant-groups. If the backend does not implement or register participant directory support, the list may be empty.
Transition fails with validation messages
The backend may be returning field-level validation details. Catch WorkflowClientError and inspect error.errors.
Guard failure is returned from the backend
A denied guard usually comes back with code = "GUARD_FAILED". This means the transition was blocked intentionally by workflow logic.
Notification settings modal returns not available
A 503 usually means the backend host has not enabled the notification admin settings service.
External form flow does not return properly
Check:
- query string parameters,
- callback URL value,
- transition call success,
- whether the page is opened in the same window or inside an iframe.
License
MIT License. See LICENSE.
For the backend package details, read Chd.Workflow/README.md.
