Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
454be57
test stage
Manas-Kenge Jun 2, 2025
c71e137
install-uninstall done
Manas-Kenge Jun 2, 2025
389698f
setup graph
Manas-Kenge Jun 13, 2025
57bbd13
state, transitions backend
Manas-Kenge Jun 23, 2025
fcb7a7f
fix toolbar
Tishasoumya-02 Jun 27, 2025
99c6b2f
remove unused icons
Tishasoumya-02 Jun 27, 2025
662e397
csrf protection, add state functionality
Manas-Kenge Jul 2, 2025
fa5e2f6
Merge branch 'test-1' into fix-toolbar
Manas-Kenge Jul 3, 2025
2914709
Merge pull request #1 from Manas-Kenge/fix-toolbar
Manas-Kenge Jul 3, 2025
596761e
change UI
Manas-Kenge Jul 3, 2025
c211827
sidebar WIP
Manas-Kenge Jul 6, 2025
099a97c
add transitions api
Manas-Kenge Jul 8, 2025
930f39e
Better graph performance
Manas-Kenge Jul 9, 2025
f1fa4b4
add transition actions and minor UI changes
Manas-Kenge Jul 9, 2025
04d39b6
layout api WIP & minor cleanup
Manas-Kenge Jul 18, 2025
28234c6
add update workflow api, modify get workflows api
Manas-Kenge Jul 18, 2025
8aff6c0
add transition reducers
Manas-Kenge Jul 18, 2025
871fe1f
workflow tab WIP
Manas-Kenge Jul 19, 2025
519360b
fix:sidebar,save field description
Tishasoumya-02 Jul 20, 2025
8affd0c
fix
Tishasoumya-02 Jul 20, 2025
7d29072
Merge pull request #2 from Manas-Kenge/workflowStore
Manas-Kenge Jul 21, 2025
c799e4d
Merge pull request #3 from Manas-Kenge/workflowtab
Manas-Kenge Jul 21, 2025
92b2ba3
add properties and transitions in state tab
Manas-Kenge Jul 22, 2025
d1634a8
add sanity check
Manas-Kenge Jul 23, 2025
dc4fbb9
stateTab WIP
Manas-Kenge Jul 24, 2025
f133617
Fix:routes
Tishasoumya-02 Jul 24, 2025
0728ab9
Merge pull request #5 from Manas-Kenge/stateTab
Manas-Kenge Jul 25, 2025
2747eae
migrate from sidebar
Manas-Kenge Jul 25, 2025
3ca4514
transitions tab WIP
Manas-Kenge Jul 26, 2025
07457fb
fix the graph
Tishasoumya-02 Jul 27, 2025
3226bb7
Merge branch 'workflowsettings' of github.com:Manas-Kenge/workflow-ma…
Tishasoumya-02 Jul 27, 2025
59d5d0b
remove sidebar
Manas-Kenge Jul 28, 2025
70802b5
fix workflow form
Manas-Kenge Jul 30, 2025
de06c10
Merge pull request #6 from Manas-Kenge/workflowsettings
Manas-Kenge Jul 30, 2025
93099a0
Merge pull request #4 from Manas-Kenge/sanity-check
Manas-Kenge Jul 30, 2025
9de0973
better graph styling
Manas-Kenge Jul 31, 2025
266a97b
move interfaces, types
Manas-Kenge Jul 31, 2025
cfbe266
add graph types
Manas-Kenge Aug 1, 2025
ca607de
add create transition dialog
Manas-Kenge Aug 2, 2025
664a9e4
Merge branch 'test-1' into migrate-types
Manas-Kenge Aug 5, 2025
bbb1e21
Merge pull request #7 from Manas-Kenge/migrate-types
Manas-Kenge Aug 5, 2025
e003190
fix validation/sanity-check
Manas-Kenge Aug 6, 2025
8a099d8
add transition dialog on connecting the nodes
Manas-Kenge Aug 11, 2025
4c3859f
Merge pull request #9 from Manas-Kenge/transition-dialog
Manas-Kenge Aug 12, 2025
dbea4ea
better data fetching
Manas-Kenge Aug 14, 2025
7a1cbfd
sidebar with tabs added
Manas-Kenge Aug 14, 2025
79bae2c
use BlockDataForm instead of Form
Manas-Kenge Aug 18, 2025
0348bb9
fix styling
Manas-Kenge Aug 18, 2025
6d9394a
Merge pull request #10 from Manas-Kenge/add-sidebar
Manas-Kenge Aug 18, 2025
839778d
fix css actions toolbar
Tishasoumya-02 Aug 18, 2025
981f222
fix classnames
Tishasoumya-02 Aug 18, 2025
b83c4f7
change assign workflow endpoint
Manas-Kenge Aug 19, 2025
cf2c2f6
use react-spectrum styling for sidebar
Manas-Kenge Aug 19, 2025
483ad22
Merge pull request #11 from Manas-Kenge/fix-css-actions-toolbar
Manas-Kenge Aug 19, 2025
1161e60
Merge branch 'test-1' into add-sidebar
Manas-Kenge Aug 19, 2025
650e5e2
move css to separate file
Manas-Kenge Aug 19, 2025
454dd85
add assign dialog
Manas-Kenge Aug 22, 2025
2f804fa
add aria labels
Manas-Kenge Aug 23, 2025
f563410
fix sidebar button
Tishasoumya-02 Aug 26, 2025
090d9ba
merge
Tishasoumya-02 Aug 26, 2025
d2d445c
WIP
Manas-Kenge Aug 26, 2025
c6124ff
Merge pull request #12 from Manas-Kenge/add-sidebar
Manas-Kenge Aug 26, 2025
3a5bc5e
fix margins for sidebar and formatting
Tishasoumya-02 Aug 27, 2025
186a09d
i18n
Tishasoumya-02 Aug 27, 2025
1308cff
remove unused components
Manas-Kenge Aug 27, 2025
dfd65fc
frontend lint
Manas-Kenge Aug 27, 2025
cf66959
Merge pull request #14 from Manas-Kenge/move-settings-to-sidebar
Manas-Kenge Aug 28, 2025
a7c4772
Merge pull request #21 from Manas-Kenge/fix-lint
Manas-Kenge Aug 28, 2025
611ecb7
change icon
Manas-Kenge Aug 28, 2025
b12a568
Merge pull request #13 from Manas-Kenge/assign-dialog
Manas-Kenge Aug 28, 2025
4934326
add sidebar picker border
Manas-Kenge Aug 28, 2025
27a6d18
Added delete buttons for state and transitions
Manas-Kenge Aug 28, 2025
9d4952e
add readme
Manas-Kenge Aug 29, 2025
2b291d0
use widget
Manas-Kenge Aug 29, 2025
492558d
fix: add the delete icon inside the blocksdataform for state and tran…
Tishasoumya-02 Aug 29, 2025
c9e0394
remove widget, change toast
Manas-Kenge Aug 29, 2025
c5c7271
Merge pull request #24 from Manas-Kenge/delete-button-sidebar
Manas-Kenge Aug 30, 2025
b3d633b
Merge pull request #25 from Manas-Kenge/add-readme
Manas-Kenge Aug 30, 2025
31cbd2d
cleanup
Manas-Kenge Aug 30, 2025
538a4b2
add helmet
Manas-Kenge Sep 1, 2025
7a72256
fix edge creation and workflow deletion
Manas-Kenge Sep 1, 2025
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
162 changes: 51 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,149 +1,89 @@
# workflow-manager 🚀
# Volto Workflow Manager

[![Built with Cookieplone](https://img.shields.io/badge/built%20with-Cookieplone-0083be.svg?logo=cookiecutter)](https://github.com/plone/cookieplone-templates/)
[![Black code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Backend Tests](https://github.com/collective/workflow-manager/actions/workflows/backend.yml/badge.svg)](https://github.com/collective/workflow-manager/actions/workflows/backend.yml)
[![Frontend Tests](https://github.com/collective/workflow-manager/actions/workflows/frontend.yml/badge.svg)](https://github.com/collective/workflow-manager/actions/workflows/frontend.yml)
Volto Workflow Manager is a visual workflow editor for Plone.
It lets you create, manage, and edit workflows inside the Volto UI using a simple graph-based interface.

A new project using Plone 6.
---

## Quick Start 🏁
## Installation

### Prerequisites ✅
This package is a Volto add-on. To install it in your Volto project:

- An [operating system](https://6.docs.plone.org/install/create-project-cookieplone.html#prerequisites-for-installation) that runs all the requirements mentioned.
- [uv](https://6.docs.plone.org/install/create-project-cookieplone.html#uv)
- [nvm](https://6.docs.plone.org/install/create-project-cookieplone.html#nvm)
- [Node.js and pnpm](https://6.docs.plone.org/install/create-project.html#node-js) 22
- [Make](https://6.docs.plone.org/install/create-project-cookieplone.html#make)
- [Git](https://6.docs.plone.org/install/create-project-cookieplone.html#git)
- [Docker](https://docs.docker.com/get-started/get-docker/) (optional)
1. Add `workflow-manager` to your project's `package.json`:


### Installation 🔧

1. Clone this repository, then change your working directory.

```shell
git clone git@github.com:collective/workflow-manager.git
cd workflow-manager
```json
{
"addons": ["workflow-manager"]
}
```

2. Install this code base.
2. Install dependencies:

```shell
make install
```bash
pnpm install
```

3. Start the Volto development server:

### Fire Up the Servers 🔥

1. Create a new Plone site on your first run.

```shell
make backend-create-site
```bash
pnpm start
```

2. Start the backend at http://localhost:8080/.
---

```shell
make backend-start
```
## How to Use

3. In a new shell session, start the frontend at http://localhost:3000/.
1. Open the **Control Panel** and select **Workflow Manager**.
2. Create a new workflow if one does not exist.
3. Add states and transitions using the graph interface.
4. Edit state and transition details from the sidebar.
5. Assign permissions and roles as needed.
6. Save changes using the Volto toolbar.

```shell
make frontend-start
```

Voila! Your Plone site should be live and kicking! 🎉

### Local Stack Deployment 📦
---

Deploy a local `Docker Compose` environment that includes:
## Development Setup

- Docker images for Backend and Frontend 🖼️
- A stack with a Traefik router and a Postgres database 🗃️
- Accessible at [http://workflow-manager.localhost](http://workflow-manager.localhost) 🌐
If you want to contribute or customize the add-on locally:

Execute the following:

```shell
make stack-start
make stack-create-site
```
## Requirements

And... you're all set! Your Plone site is up and running locally! 🚀
- [Node.js 22](https://6.docs.plone.org/install/create-project.html#node-js)
- [pnpm](https://pnpm.io/)
- [UV](https://6.docs.plone.org/install/create-project-cookieplone.html#uv)

## Project Structure 🏗️
### Installation

This monorepo consists of the following distinct sections:
1. Clone the repository:

- **backend**: Houses the API and Plone installation, utilizing pip instead of buildout, and includes a policy package named workflow.manager.
- **frontend**: Contains the React (Volto) package.
- **devops**: Encompasses Docker Stack, Ansible playbooks, and Cache settings.
- **docs**: Scaffold for writing documentation for your project.

### Why This Structure? 🤔

- All necessary codebases to run the site are contained within the repo (excluding existing addons for Plone and React).
- Specific GitHub Workflows are triggered based on changes in each codebase (refer to .github/workflows).
- Simplifies the creation of Docker images for each codebase.
- Demonstrates Plone installation/setup without buildout.

## Code Quality Assurance 🧐

To automatically format your code and ensure it adheres to quality standards, execute:

```shell
make check
```sh
git clone https://github.com/Manas-Kenge/workflow-manager.git
cd workflow-manager
```

### Format the codebase
2. Install dependencies for both Backend and Frontend:

To format the codebase, it is possible to run `format`:

```shell
make format
```sh
make install
```

| Section | Tool | Description | Configuration |
| --- | --- | --- | --- |
| backend | Ruff | Python code formatting, imports sorting | [`backend/pyproject.toml`](./backend/pyproject.toml) |
| backend | `zpretty` | XML and ZCML formatting | -- |
| frontend | ESLint | Fixes most common frontend issues | [`frontend/.eslintrc.js`](.frontend/.eslintrc.js) |
| frontend | prettier | Format JS and Typescript code | [`frontend/.prettierrc`](.frontend/.prettierrc) |
| frontend | Stylelint | Format Styles (css, less, sass) | [`frontend/.stylelintrc`](.frontend/.stylelintrc) |

Formatters can also be run within the `backend` or `frontend` folders.
### Start the Servers

### Linting the codebase
or `lint`:
1. Start the **Backend** (Plone) at [http://localhost:8080/](http://localhost:8080/):

```shell
make lint
```sh
make backend-start
```

| Section | Tool | Description | Configuration |
| --- | --- | --- | --- |
| backend | Ruff | Checks code formatting, imports sorting | [`backend/pyproject.toml`](./backend/pyproject.toml) |
| backend | Pyroma | Checks Python package metadata | -- |
| backend | check-python-versions | Checks Python version information | -- |
| backend | `zpretty` | Checks XML and ZCML formatting | -- |
| frontend | ESLint | Checks JS / Typescript lint | [`frontend/.eslintrc.js`](.frontend/.eslintrc.js) |
| frontend | prettier | Check JS / Typescript formatting | [`frontend/.prettierrc`](.frontend/.prettierrc) |
| frontend | Stylelint | Check Styles (css, less, sass) formatting | [`frontend/.stylelintrc`](.frontend/.stylelintrc) |

Linters can be run individually within the `backend` or `frontend` folders.
2. In a new terminal, start the **Frontend** (Volto) at [http://localhost:3000/](http://localhost:3000/):

## Internationalization 🌐
```sh
make frontend-start
```

Generate translation files for Plone and Volto with ease:
Your Plone development environment is now live!

```shell
make i18n
```

## Credits and Acknowledgements 🙏
# License

Generated using [Cookieplone (0.9.7)](https://github.com/plone/cookieplone) and [cookieplone-templates (684d5c7)](https://github.com/plone/cookieplone-templates/commit/684d5c7f43a6ebc3184e2a0106b0160820a96e66) on 2025-05-22 13:24:17.198737. A special thanks to all contributors and supporters!
This project is licensed under the MIT License.
115 changes: 115 additions & 0 deletions backend/src/workflow/manager/actionmanager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from zope.component import queryUtility

from plone.memoize.instance import memoize
from plone.contentrules.engine.interfaces import IRuleStorage, IRuleAssignmentManager
from plone.app.contentrules.conditions.wftransition import WorkflowTransitionCondition
from plone.contentrules.engine import utils
from plone.app.contentrules.rule import Rule, get_assignments
from plone.contentrules.engine.assignments import RuleAssignment
from Products.CMFCore.interfaces._events import IActionSucceededEvent
from Products.CMFCore.utils import getToolByName
from workflow.manager.utils import generateRuleName, generateRuleNameOld

from zope.i18nmessageid import MessageFactory
_ = MessageFactory("plone")


class RuleAdapter:
"""Adapter for managing content rules with workflow transitions."""

def __init__(self, rule, transition):
self.rule = rule
self.transition = transition

@property
@memoize
def portal(self):
return getToolByName(self.transition, 'portal_url').getPortalObject()

def activate(self):
"""
1) make sure condition is enabled for transition
2) enable at root and bubble to item below
"""
c = WorkflowTransitionCondition()
c.wf_transitions = [self.transition.id]
self.rule.conditions = [c]
self.rule.event = IActionSucceededEvent

assignable = IRuleAssignmentManager(self.portal)
path = '/'.join(self.portal.getPhysicalPath())
assignable[self.rule.__name__] = RuleAssignment(
self.rule.id,
enabled=True,
bubbles=True
)
assignments = get_assignments(self.rule)
if path not in assignments:
assignments.insert(path)

@property
def id(self):
return self.rule.id

def get_action(self, index):
return self.rule.actions[index]

def action_index(self, action):
return self.rule.actions.index(action)

def action_url(self, action):
return f'{self.portal.absolute_url()}/{self.rule.id}/++action++{self.action_index(action)}/edit'

def delete_action(self, index):
self.rule.actions.remove(self.rule.actions[index])

@property
def actions(self):
return self.rule.actions


class ActionManager:
"""Manager for workflow transition content rules and actions."""

def get_rule(self, transition):
rulename = generateRuleName(transition)
rulename_old = generateRuleNameOld(transition)
if self.storage is not None:
for rule in self.storage.values():
if rule.__name__ in (rulename, rulename_old):
return RuleAdapter(rule, transition)
return None

def create(self, transition):
rule = self.get_rule(transition)
if rule is None:
rule_id = generateRuleName(transition)
r = Rule()
r.title = _("%s transition content rule") % transition.id
r.description = _(
"This content rule was automatically created by "
"the workflow manager to create actions on "
"workflow events. If you want the behavior to "
"work as expected, do not modify this out of "
"the workflow manager."
)
self.storage[rule_id] = r
rule = RuleAdapter(r, transition)
rule.activate()

return rule

@property
@memoize
def storage(self):
return queryUtility(IRuleStorage)

@property
@memoize
def available_actions(self):
return utils.allAvailableActions(IActionSucceededEvent)

def delete_rule_for(self, transition):
rule = self.get_rule(transition)
if rule is not None:
del self.storage[rule.rule.__name__]
Empty file.
12 changes: 12 additions & 0 deletions backend/src/workflow/manager/api/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:plone="http://namespaces.plone.org/plone"
i18n_domain="workflow.manager">

<!-- -*- extra stuff goes here -*- -->

<include package=".services" />


</configure>
Empty file.
12 changes: 12 additions & 0 deletions backend/src/workflow/manager/api/services/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:plone="http://namespaces.plone.org/plone"
i18n_domain="workflow.manager">

<!-- -*- extra stuff goes here -*- -->
<include package=".workflow" />



</configure>
Empty file.
Loading
Loading