{"id":15012788,"url":"https://github.com/microsoft/taskflow-react","last_synced_at":"2025-10-19T14:31:16.599Z","repository":{"id":40635323,"uuid":"470522109","full_name":"microsoft/taskflow-react","owner":"microsoft","description":"A promise and react based jsx style task flow library","archived":false,"fork":false,"pushed_at":"2022-11-28T19:07:48.000Z","size":441,"stargazers_count":6,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-01-30T10:41:28.632Z","etag":null,"topics":["jsx","promise","react","taskflow","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/microsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2022-03-16T09:52:06.000Z","updated_at":"2024-02-24T09:03:29.000Z","dependencies_parsed_at":"2022-09-26T20:53:36.739Z","dependency_job_id":null,"html_url":"https://github.com/microsoft/taskflow-react","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2Ftaskflow-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2Ftaskflow-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2Ftaskflow-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2Ftaskflow-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/microsoft","download_url":"https://codeload.github.com/microsoft/taskflow-react/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237143800,"owners_count":19262277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jsx","promise","react","taskflow","typescript"],"created_at":"2024-09-24T19:43:13.471Z","updated_at":"2025-10-19T14:31:15.941Z","avatar_url":"https://github.com/microsoft.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React and promise based task flow library\nNow a lot of features are task flow based. You could break features into a seriese of tasks with order and dependency. For example, to start task C, you have to wait for task A / B and then take their outputs for further process. To express and reuse task flow easily and visually, it could help improve development efficiency. In this repo, task flow and workflow are the same.\n\n## Example\n### Simple taskflow expression\nTake the task flow below, there are 4 params for input. The task flow would add all 4 params with 3 add nodes and then double the sum with double node. Then the double node's result would be set as task flow's output.\n\n![SampleTaskFlow](./md/SampleTaskFlow.png)\n\nThe task flow above could be expressed with react jsx style below,\n```typescript\n\u003cWorkflowComponent\u003e\n    \u003cInputNodeComponent params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n    \u003cNodeComponent name=\"add1\" gen={addFunc} deps={[\"num1\", \"num2\"]} /\u003e\n    \u003cNodeComponent name=\"add2\" gen={addFunc} deps={[\"num3\", \"num4\"]} /\u003e\n    \u003cNodeComponent name=\"add3\" gen={addFunc} deps={[\"add1\", \"add2\"]} /\u003e\n    \u003cNodeComponent name=\"double\" gen={doubleFunc} deps={[\"add3\"]} /\u003e\n    \u003cOutputNodeComponent name=\"res\" dep=\"double\" /\u003e\n\u003c/WorkflowComponent\u003e\n```\nIn the jsx code above, there is a container with tag *WorkflowComponent*. Inside the container, there is first a *InputNodeComponent* node with *params* which is a array of name of the input parameters. *NodeComponent* add1 would take num1 and num2 defined within *InputNodeComponent* node to compute the add result with addFunc. After two node add1 and add2 finish work, add3 would take their outputs to run addFunc again with result passed to double node. Finally the result of double node computed by doubleFunc, would be set as task flow's output with alias res. The input parameter and output of a node\n are all refferenced by name.\n\nThe jsx code expression above is simple, clear and visual. You don't have to write code with long and chainning expressions.\n\nFor each *NodeComponent*, you need to specify a function that could genrate *WorkflowExecutionNode* as below,\n```typescript\nexport interface WorkflowExecutionNode {\n    run: (...params: any[]) =\u003e any;\n    cancel?: () =\u003e void;\n}\n```\n\n### Re-usable taskflow expression\nIf you want to define a re-usable task flow, then you could define a function with props to wrap the workflow. For example,\n```typescript\nfunction ComputationWorkflow(props: WorkflowInputProps) {\n    return (\u003cWorkflowComponent {...props}\u003e\n            \u003cInputNodeComponent params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n            \u003cNodeComponent name=\"add1\" gen={addFunc} deps={[\"num1\", \"num2\"]} /\u003e\n            \u003cNodeComponent name=\"add2\" gen={addFunc} deps={[\"num3\", \"num4\"]} /\u003e\n            \u003cNodeComponent name=\"add3\" gen={addFunc} deps={[\"add1\", \"add2\"]} /\u003e\n            \u003cNodeComponent name=\"double\" gen={doubleFunc} deps={[\"add3\"]} /\u003e\n            \u003cOutputNodeComponent name=\"res\" dep=\"double\" /\u003e\n        \u003c/WorkflowComponent\u003e\n    )\n}\n```\nAnd in a new task flow, reuse the task flow by passsing the params. Then chain the current task flow output to parent taks flow's output node.\n```typescript\n\u003cWorkflowComponent\u003e\n    \u003cInputNodeComponent params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n    \u003cComputationWorkflow name=\"comp\" params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n    \u003cOutputNodeComponent name=\"res\" dep=\"comp.res\" /\u003e\n\u003c/WorkflowComponent\u003e\n\n```\n### Taskflow conversion\nThe example above is about taskflow expression. Once you have defined jsx taskflow, you could use buildJsxWorkflow to generate the task flows with ndoes and its depdencies. For example,\n```typescript\nconst jsxWorkflow = \u003cWorkflowComponent\u003e\n    \u003cInputNodeComponent params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n    \u003cComputationWorkflow name=\"comp\" params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n    \u003cOutputNodeComponent name=\"res\" dep=\"comp.res\" /\u003e\n\u003c/WorkflowComponent\u003e\nconst workflow = buildJsxWorkflow(jsxWorkflow)\n```\n### Taskflow execution\n*createWorkflowExecutor* is for create task flow executor by passing the task flow structure. Call the run method, then wait for the outputs of promise and reference the result by alias . For example,\n```typescript\nconst jsxWorkflow = \u003cWorkflowComponent\u003e\n    \u003cInputNodeComponent params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n    \u003cComputationWorkflow name=\"comp\" params={[\"num1\", \"num2\", \"num3\", \"num4\"]} /\u003e\n    \u003cOutputNodeComponent name=\"res\" dep=\"comp.res\" /\u003e\n\u003c/WorkflowComponent\u003e\nconst workflow = buildJsxWorkflow(jsxWorkflow)\nconst executor = createWorkflowExecutor(workflow)\nexecutor.run(1, 2, 3, 4).then((res) =\u003e {\n    console.log(res[\"res\"])\n})\n```\n\nPlease reference *example* and *test* folder for more.\n## Development Setup\nPlease install vscode as IDE\n```ini\n# install\nnpm install\n\n# build\nnpm run build\n\n# test\nnpm run test\n\n# lint\nnpm run lint\n```\nTo debug test case, set sourceMap to be true in tsconfig.json, set configuration to be Jest Current File, open test file and run Start Debugging from vscode menu.\n\n## Usage\n### Api\n****\nbuildJsxWorkflow(expression: React.ReactElement, addNodeName: boolean = false)\n****\nConvert the jsx task flow expression to Workflow with node id to name mapping as optional.\n\n**Parameters**:\n- **expression** - the jsx expression of the task flow\n- **addNodeName** - false by default, if true it would generate id to node name mapping.\n\n**Return**\n\nThe task flow instance\n\n****\ncreateWorkflowExecutor(wf: Workflow)\n****\nCreate task flow executor with task flow instance.\n\n**Parameters**\n\n- **wf** - the task flow instance, not the task flow jsx expression\n\n**Return**\n\nThe task flow executor instance\n\n****\ndumpWorkflow(wf: Workflow)\n****\n\n**Parameters**\n- **wf** - the task flow instance\n\n**Return**\n\nThe code that could generate taks flow instance\n\n\n### Interfaces\nTask flow\n```typescript\nexport interface Workflow {\n    inputs: number[];\n    zeroDepNodes: number[];\n    nodes: WorkflowNode[];\n    outputs: Record\u003cnumber, string\u003e;\n    binding: Record\u003cnumber, number[]\u003e;\n    nodeNames?: Record\u003cnumber, string\u003e;\n}\n```\n\nTask flow executor\n```typescript\nexport interface WorkflowExecutor {\n    cancel() : void;\n    run(...params: any[]) : Promise\u003cany\u003e;\n    setTimeout(timeout: number) : void;\n    reset() : void;\n    state() : ExecutionStatus;\n    inst(inst: boolean) : void;\n    workflow() : Workflow;\n    stats(): NodeExecutionStatus[];\n}\n```\n### Components\nBelow are the basice components. You could create custom task flow components based on theme. Please note that only function components are supported.\n``` typescript\ndeclare function NodeComponent(props: NodeProps): any;\ndeclare function WorkflowComponent(props: WorkflowProps): any;\ndeclare function InputNodeComponent(props: InputNodeProps): any;\ndeclare function OutputNodeComponent(props: OutputNodeProps): any;\n```\n\n## About react\nThe library uses *react* to express task flow. It would add extra bundle size. as 1) *react* is included, 2) the jsx taskflow expression would actually be converted to code to create react elements.\n\nIf you don't want to depends on *react* and minize the bundle size. You could 1) dump the workflow instance code with *dumpWorkflow* method at runtime or test code. And use the generated code to generate task flow instance, 2) use cli and package target to print the genrated code for pure typescript project. Please reference the workflow target in **./example/client**.\n```\n    \"workflow\": \"taskflow-react-cli -w ./src/controller/FreWorkflow.tsx -n workflowDef\"\n```\n\n-w specifies the file path and -n specfies the name of workflow instance exported. Here you need to import unitNodeGenerator from the library, and other node generator functions.\n\n\n## UI application\nThe best scenario for task flow is pure data flow. For task that needs to wait for user's input like clicking button, please keep the resolve function. When user clicks the button, you run the resolve function with input needed.\n\nFor UI specify task flow, it is recommended to define something like bridge to keep state and callback functions to update UI. Please check **./example/client** for reference.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrosoft%2Ftaskflow-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicrosoft%2Ftaskflow-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrosoft%2Ftaskflow-react/lists"}