From bb7bbee01a3672d65e313a8bc558fafa7bc605be Mon Sep 17 00:00:00 2001 From: merefield Date: Tue, 19 May 2026 15:56:54 +0100 Subject: [PATCH 01/34] UX: rebrand copy to Process Manager --- README.md | 135 ++++++++++++++++++----------------- config/locales/client.en.yml | 109 ++++++++++++++-------------- config/locales/server.en.yml | 14 ++-- plugin.rb | 2 +- 4 files changed, 133 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index 2f0b1fb..98fbcda 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ -# discourse-workflow +# Process Manager -A workflow tool for Discourse! +`discourse-workflow` provides a process management plugin for Discourse. Discuss the plugin here: https://meta.discourse.org/t/discourse-workflow/347110?u=merefield ## Introduction -A plugin which provides a secure workflow framework for Topics which are passed along a customizable set of steps until the workflow is complete. Some branching and looping is supported. +Process Manager provides a secure process-management framework for Discourse topics. Each process is made of configurable workflow steps and options, and topics move through those steps until completion. Some branching and looping is supported. + +Using topics as work items gives each process a flexible, native Discourse foundation: each item can have a detailed description, attachments, discussion, notifications, tags, categories, permissions, and a full history out of the box. If you are new to the terminology, see: @@ -15,27 +17,28 @@ If you are new to the terminology, see: ## Features -- Workflow definitions made from steps mapped to Categories (or Sub-categories) -- Workflow instances represented as Topics that transition across Categories +- Process-management workflows using Discourse topics as work items +- Admin-defined processes made from steps mapped to Categories (or Sub-categories) +- Visual workflow editor for arranging steps, swim lanes, and transition connectors - Transition actions presented as buttons per step option - Permission model aligned to native Discourse category permissions -- Workflow discovery list (`/workflow`) with quick filters -- Workflow view selector in discovery (`List`, `Kanban`, `Chart`) when applicable -- Kanban view for compatible single-workflow lists +- Process discovery list (`/workflow`) with quick filters +- Process view selector in discovery (`List`, `Kanban`, `Chart`) when applicable +- Kanban view for compatible single-process lists - Drag/drop transitions in Kanban with legal/illegal drop-zone highlighting - Keyboard Kanban transitions on focused cards (`ArrowLeft` / `ArrowRight`) when legal -- Workflow-level Kanban tags toggle (`show_kanban_tags`, default `true`) -- Workflow burn down chart view (`/workflow/charts` and chart mode in `/workflow`) for single-workflow context +- Process-level Kanban tags toggle (`show_kanban_tags`, default `true`) +- Built-in process burn-down chart view (`/workflow/charts` and chart mode in `/workflow`) for single-process context - Chart period selector (`1` to `12` weeks), complete-week windows (Sunday to Saturday), per-step colored series - Overdue behavior with hierarchy: - global default (`workflow_overdue_days_default`) - workflow override - step override - `0` disables overdue behavior at that scope -- Workflow overdue indicator column in the workflow topic list +- Overdue indicator column in the process topic list - Stale state transition handling with explicit user-facing error and automatic refresh - Transition audit trail via small action posts -- Workflow visualization modal from topic and list links +- Process visualization modal from topic and list links - Data Explorer audit query support - Data Explorer workflow stats query support for chart-oriented time series - Optional AI-assisted step handling with prompt + option guardrails @@ -43,51 +46,51 @@ If you are new to the terminology, see: ## Quickstart 1. Enable the plugin in Site Settings (`workflow_enabled`). -2. Go to `Admin -> Plugins -> Discourse Workflow`, create a Workflow, then save it. -3. Add Workflow Steps (Categories in journey order), then add Step Options (actions/transitions). -4. Create a Topic in the first step Category and transition it through actions from the topic banner. +2. Go to `Admin -> Plugins -> Process Manager`, create a process, then save it. +3. Add workflow steps (Categories in journey order), then add step options (actions/transitions). +4. Create a topic in the first step Category and transition it through actions from the topic banner. 5. Use `/workflow` to view queue state, apply quick filters, and switch between `List` / `Kanban` / `Chart` views when available. 6. In Kanban, click a card to open the topic, drag cards to legal target steps, or use keyboard arrows on focused cards. -7. Use `/workflow/charts` (or `Chart` view in `/workflow`) to see step counts over time for the currently scoped single workflow. +7. Use `/workflow/charts` (or `Chart` view in `/workflow`) to see step counts over time for the currently scoped single process. ## Setup ### Core plugin settings -- `workflow_enabled`: enables/disables workflow behavior. +- `workflow_enabled`: enables/disables Process Manager behavior. - `workflow_overdue_days_default`: default overdue threshold in days; `0` disables overdue by default. - `workflow_openai_api_key`: API key for AI actions. - `workflow_ai_model`: model used for AI actions. - `workflow_ai_prompt_system`: system prompt support for AI transitions. -- `workflow_charts_allowed_groups`: non-admin groups allowed to view workflow charts. +- `workflow_charts_allowed_groups`: non-admin groups allowed to view process charts. -### Workflow definition setup +### Process definition setup -The workflow plugin is not bundled with a workflow; you create your own definitions. +Process Manager is not bundled with a process; you create your own definitions. -The screens to create one are in `Admin -> Plugins -> Discourse Workflow`. +The screens to create one are in `Admin -> Plugins -> Process Manager`. -First create a new Workflow by hitting the button, save it, then populate it with Steps by editing the workflow. Each Step, once created, can be edited to add Options, taken from a list of pre-defined Options. +First create a new process by hitting the button, save it, then populate it with steps by editing the process. Each step, once created, can be edited to add options, taken from a list of pre-defined options. You can change the label of an Option in `Admin -> Customize -> Text`. A good range of Options is seeded by default, but you can customize the text as needed. -Workflow-level Kanban controls: +Process-level Kanban controls: - `show_kanban_tags`: controls whether tags render on Kanban cards below the title. Default is enabled. ### Overdue setup hierarchy - Global default: `workflow_overdue_days_default` -- Optional workflow-level override: `Workflow.overdue_days` +- Optional process-level override: `Workflow.overdue_days` - Optional step-level override: `WorkflowStep.overdue_days` Resolution order is `step -> workflow -> global`. A value of `0` means overdue behavior is disabled at that level. ### Kanban compatibility and behavior -Kanban view is shown when the current `/workflow` list is scoped to a single compatible workflow. +Kanban view is shown when the current `/workflow` list is scoped to a single compatible process. Compatibility requires: @@ -102,21 +105,21 @@ For each directed edge, Kanban drag/keyboard transitions are option-agnostic and ### Chart view behavior and access model -Chart view is shown when the current workflow discovery context resolves to a single workflow. +Chart view is shown when the current process discovery context resolves to a single process. - Route support: `/workflow/charts` and chart mode in `/workflow` via `workflow_view=chart` -- View selector behavior: `Chart` is only shown when the user can view charts and the current discovery context is a single workflow +- View selector behavior: `Chart` is only shown when the user can view charts and the current discovery context is a single process - Period selection: `1` to `12` weeks - Time windows: complete weeks (Sunday through Saturday) - Series: one line per step, color derived from step category color (or parent category color fallback) -- Response scope: chart payload includes selected workflow metadata (`selected_workflow_id`, `selected_workflow_name`) plus series data for that selected workflow context +- Response scope: chart payload includes selected process metadata (`selected_workflow_id`, `selected_workflow_name`) plus series data for that selected process context Access model for charts is intentionally separate from topic-level category access: - Admins can always view charts - Users in `workflow_charts_allowed_groups` can view charts -- Chart access is aggregate and workflow-level; it is intentionally not constrained to per-topic visibility rules -- This allows operational/reporting audiences to monitor workflow throughput without granting direct access to every underlying topic +- Chart access is aggregate and process-level; it is intentionally not constrained to per-topic visibility rules +- This allows operational/reporting audiences to monitor process throughput without granting direct access to every underlying topic If you want stricter chart data visibility, keep `workflow_charts_allowed_groups` empty and rely on admin-only access. @@ -124,10 +127,10 @@ If you want stricter chart data visibility, keep `workflow_charts_allowed_groups The plugin schedules and runs the following jobs: -- `Jobs::DiscourseWorkflow::DailyStats`: records daily workflow step counts +- `Jobs::DiscourseWorkflow::DailyStats`: records daily process step counts - `Jobs::DiscourseWorkflow::AiTransitions`: runs AI-enabled transitions -- `Jobs::DiscourseWorkflow::DataExplorerQueriesCompleteness`: ensures default workflow Data Explorer queries exist -- `Jobs::DiscourseWorkflow::TopicArrivalNotifier`: sends first-post arrival notifications on workflow transitions +- `Jobs::DiscourseWorkflow::DataExplorerQueriesCompleteness`: ensures default Process Manager Data Explorer queries exist +- `Jobs::DiscourseWorkflow::TopicArrivalNotifier`: sends first-post arrival notifications on process transitions ### AI actions @@ -143,60 +146,60 @@ To leverage the Discourse platform as-is as much as possible, this plugin uses m ## Swim Lanes -Each Workflow swim-lane is a Category (or Sub-Category). +Each process swim lane is a Category (or Sub-Category). -As an instance of a workflow continues along its journey it moves between Categories in a customizable but pre-defined journey. +As a process instance continues along its journey, it moves between Categories in a customizable but pre-defined journey. -## Workflow Instances +## Process Instances -A single instance of a workflow (e.g. a ticket) is a Topic. You can add tags to a Topic to highlight priority or other metadata. You cannot amend its Category once it has begun its journey other than by taking workflow actions upon the Topic. +A single process instance (for example, a ticket) is a Topic. You can add tags to a Topic to highlight priority or other metadata. You cannot amend its Category once it has begun its journey other than by taking process actions upon the Topic. ## Actors Any Group which has Topic creation access to a Category can act upon the topics in that Category. -Those that have Reply access can comment on the Workflow item just as they can for a normal Topic. +Those that have Reply access can comment on the process item just as they can for a normal Topic. You can hide Topics within a Category from specific groups in the normal way. ## Actions via Options -These are defined for each step when setting up the Workflow. Actors can choose to take any available action as each Option is presented as a button on the Topic. +These are defined for each step when setting up the process. Actors can choose to take any available action as each Option is presented as a button on the Topic. Actions on a Topic are captured in a Small Action Post to help users understand the journey of the Topic. ## Dashboard -A Topic Discovery filter `Workflow` gives a list of workflow instances (special workflow topics), with three presentation modes when available: +A Topic Discovery filter `Processes` gives a list of process instances, with three presentation modes when available: -- `List`: sortable workflow topic list with workflow columns and quick filters -- `Kanban`: actionable card board for compatible single-workflow views -- `Chart`: step count trends over time for a single workflow +- `List`: sortable process topic list with process columns and quick filters +- `Kanban`: actionable card board for compatible single-process views +- `Chart`: step count trends over time for a single process -You should keep Workflow Categories and ideally tags distinct, so you can also use those to filter for all workflow instances that are at a particular stage, or have a specific tag. +You should keep process Categories and ideally tags distinct, so you can also use those to filter for all process instances that are at a particular stage, or have a specific tag. ## Audit trail -A bundled Data Explorer query provides a basic audit report of a workflow instance journey. +A bundled Data Explorer query provides a basic audit report of a process instance journey. Because Data Explorer queries can be exposed beyond Admin, you can choose who to show them to. ## Visualisation -There is a button on each workflow Topic that allows you to bring up a visualization of where the Topic is in its workflow. +There is a button on each process Topic that allows you to bring up a visualization of where the Topic is in its process. -This is also accessible from the workflow fields on the Workflow Discovery Dashboard. +This is also accessible from the process fields on the Processes discovery view. ## Major Differences In Behavior To Stock -- you can't create a new Topic in a Category that's beyond the first step of a workflow -- you can't change the Category of a Topic that is within a workflow -- only "Creators" can act upon a Topic in a Workflow. +- you can't create a new Topic in a Category that's beyond the first step of a process +- you can't change the Category of a Topic that is within a process +- only "Creators" can act upon a Topic in a process. ## Tips -- Consider making all workflow steps for a particular workflow a Subcategory within a single Category. Whilst this isn't necessary it will allow you to simply filter for that Category using existing Discourse Category drop-down in the Discovery list to see all workflow instances for that specific workflow. -- In the new Workflow Discovery list you can click on Workflow Name, Position or Step to visualise where that instance is along its path. +- Consider making all steps for a particular process a Subcategory within a single Category. Whilst this isn't necessary it will allow you to simply filter for that Category using existing Discourse Category drop-down in the Discovery list to see all process instances for that specific process. +- In the new Processes discovery list you can click on Process, Position or Step to visualise where that instance is along its path. ## Roadmap Themes @@ -210,14 +213,14 @@ Status legend: Permissioning principle: - The plugin intentionally reuses core Discourse category permissions as the default and preferred model. -- Finer-grained step/action permission controls are lower priority so the workflow system stays simple to operate, easy for admins to reason about, and close to standard Discourse behavior. +- Finer-grained step/action permission controls are lower priority so Process Manager stays simple to operate, easy for admins to reason about, and close to standard Discourse behavior. | Area | Capability | Status | Notes | | ----------- | ------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------- | -| Definition | Workflow definitions (steps/options mapped to categories) | Implemented | Core admin CRUD plus workflow-level display controls (for example `show_kanban_tags`) | +| Definition | Process definitions (steps/options mapped to categories) | Implemented | Core admin CRUD plus process-level display controls (for example `show_kanban_tags`) | | Runtime | Topic transitions with audit posts | Implemented | Transition actions are logged in-topic | -| Discovery | Workflow list with quick filters, list/kanban toggle, and step filtering | Implemented | `/workflow` supports SPA quick filters plus list/kanban switching | -| Discovery | Real-time workflow state-change notifier with refresh CTA | Planned | Wire MessageBus updates into `/workflow` with a core-style “press to refresh” flow | +| Discovery | Process list with quick filters, list/kanban toggle, and step filtering | Implemented | `/workflow` supports SPA quick filters plus list/kanban switching | +| Discovery | Real-time process state-change notifier with refresh CTA | Planned | Wire MessageBus updates into `/workflow` with a core-style “press to refresh” flow | | Kanban | Card transitions (drag/drop and keyboard arrows) | Implemented | Legal transitions only; deterministic directed edge mapping | | SLA | Overdue thresholds (step -> workflow -> global, `0` disables) | Implemented | Includes overdue list indicator | | Permissions | Native Discourse category permissions for acting/commenting | Implemented | Transition authority still aligns with category create access | @@ -225,22 +228,22 @@ Permissioning principle: | Validation | Transition preconditions (required tags/fields/checks) | Planned | Intended as optional guardrails before transitions | | SLA | Escalation/reminder notifications | Partial | Overdue visibility exists; automated escalation is next | | Ownership | Discourse Assign integration | Planned | Target is step-entry assignment and auditable ownership changes | -| Operations | Bulk workflow transitions from list views | Missing | High-volume queue operation not yet first-class | -| Performance | Admin/list/chart/transition query-path N+1 and over-fetch hardening | Implemented | Admin serializers preloaded, workflow quick filters now SQL-scoped, chart loading scoped to selected workflow, transition lookup round-trips reduced, and workflow-state staleness indexing added | -| Performance | Bulk workflow arrival notification fan-out | Planned | Use bulk insert (`insert_all`) for category watcher notifications to reduce per-user insert overhead at high watcher counts | -| Performance | Cache workflow chart payloads | Planned | Add short-lived caching keyed by workflow and period to reduce repeated chart aggregation for frequent refreshes | -| Performance | Cache workflow visualisation payloads | Planned | Cache graph payloads keyed by topic/workflow-state version to avoid rebuilding identical visualisations | -| Performance | Production query-plan validation for workflow filters | Partial | Query shape is now SQL-driven; continue with `EXPLAIN`/index tuning against large production-like datasets | -| Reporting | Built-in workflow analytics dashboards | Partial | Data Explorer support exists; admin-native reporting is next | -| Lifecycle | Import/export/version workflow definitions | Missing | Useful for staging->production promotion and rollback | +| Operations | Bulk process transitions from list views | Missing | High-volume queue operation not yet first-class | +| Performance | Admin/list/chart/transition query-path N+1 and over-fetch hardening | Implemented | Admin serializers preloaded, process quick filters now SQL-scoped, chart loading scoped to selected process, transition lookup round-trips reduced, and workflow-state staleness indexing added | +| Performance | Bulk process arrival notification fan-out | Planned | Use bulk insert (`insert_all`) for category watcher notifications to reduce per-user insert overhead at high watcher counts | +| Performance | Cache process chart payloads | Planned | Add short-lived caching keyed by process and period to reduce repeated chart aggregation for frequent refreshes | +| Performance | Cache process visualisation payloads | Planned | Cache graph payloads keyed by topic/workflow-state version to avoid rebuilding identical visualisations | +| Performance | Production query-plan validation for process filters | Partial | Query shape is now SQL-driven; continue with `EXPLAIN`/index tuning against large production-like datasets | +| Reporting | Built-in process analytics dashboards | Partial | Data Explorer support exists; admin-native reporting is next | +| Lifecycle | Import/export/version process definitions | Missing | Useful for staging->production promotion and rollback | | Integration | Event hooks / webhooks / automation integration | Planned | Transition and step events are good integration points | | AI | Guardrailed AI-assisted transitions | Partial | Present but should tighten confidence/fallback/audit behavior | ### Priority Roadmap -1. Add MessageBus-driven workflow state-change notifications with a core-style refresh CTA in `/workflow`. +1. Add MessageBus-driven process state-change notifications with a core-style refresh CTA in `/workflow`. 2. Add transition preconditions and clearer per-action validation feedback. 3. Add escalation automation (reminders/alerts) on top of existing overdue thresholds. -4. Add first-class reporting and assignment integration for operational workflows. +4. Add first-class reporting and assignment integration for operational processes. 5. Add definition lifecycle tooling (import/export/versioning) for safe environment promotion. 6. Keep advanced step/action permission granularity as a lower-priority enhancement to avoid unnecessary complexity versus native Discourse permissioning. diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ed2e585..908d06c 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1,42 +1,42 @@ en: js: user_menu: - no_workflow_notifications_title: "You don’t have any workflow notifications yet" + no_workflow_notifications_title: "You don’t have any process notifications yet" no_workflow_notifications_body: > - You will be notified in this panel when a Topic enters a workflow state for which you are Watching the First Post of the Category. Notifications will also be sent to your email when you haven’t logged in for a while. + You will be notified in this panel when a topic enters a process step for which you are Watching the First Post of the category. Notifications will also be sent to your email when you haven’t logged in for a while.

For more, see your notification preferences. tabs: - workflow_notifications: "Workflow notifications" + workflow_notifications: "Process notifications" workflow_notifications_with_unread: - one: "Workflow notifications - %{count} unread notification" - other: "Workflow notifications - %{count} unread notifications" + one: "Process notifications - %{count} unread notification" + other: "Process notifications - %{count} unread notifications" notifications: workflow_topic_arrival_label: "Arrival in: %{workflow_name}" workflow_topic_arrival_description: "Author: %{username}, step: %{workflow_step_name}" titles: - workflow_topic_arrival: "A topic titled %{topic_title} has arrived in step: %{workflow_step_name} of the workflow: %{workflow_name}, authored by %{username}" + workflow_topic_arrival: "A topic titled %{topic_title} has arrived in step: %{workflow_step_name} of the process: %{workflow_name}, authored by %{username}" action_codes: - workflow_transition: "acted upon topic in a workflow %{when}" + workflow_transition: "acted upon topic in a process %{when}" topics: bottom: - workflow: Currently, there are no more viewable Workflow topics. + workflow: Currently, there are no more viewable process topics. none: - workflow: Currently, there are no viewable Workflow topics. - workflow-name: "Workflow" - workflow-step-name: "Step Name" + workflow: Currently, there are no viewable process topics. + workflow-name: "Process" + workflow-step-name: "Step name" workflow-step-position: "Step" workflow-overdue: "Overdue" filters: workflow: - title: "Workflow" - help: "topics involved in a workflow" + title: "Processes" + help: "topics involved in a managed process" discourse_workflow: workflow_link: "%{workflow_name}: %{workflow_step_name}" topic_banner: - title: "Discourse Workflow" + title: "Process manager" step_title: "Step:" - workflow_title: "Workflow:" + workflow_title: "Process:" step: "%{workflow_step_position}. %{workflow_step_name}" step_age_less_than_day: "In this step for less than a day" step_age_days: @@ -46,10 +46,10 @@ en: transition_target: "-> %{target_step_name}" blocked_reason_create_permission: "You can reply in this step, but only users with topic creation permission in this category can transition it." visualisation_button: "Visualise" - visualisation_title: "Workflow: %{workflow_name}" + visualisation_title: "Process: %{workflow_name}" quick_filters: - view_label: "Workflow View" - my_categories: "My Categories" + view_label: "Process view" + my_categories: "My categories" overdue: "Overdue" step_placeholder: "Step #" apply_step: "Step = X" @@ -58,18 +58,18 @@ en: chart_view: "Chart" clear: "Clear" charts: - title: "Workflow Burn Down" + title: "Process burn-down" weeks_label: "Weeks" weeks_value: one: "%{count} week" other: "%{count} weeks" - workflow_label: "Workflow" - workflow_name: "Workflow: %{workflow_name}" + workflow_label: "Process" + workflow_name: "Process: %{workflow_name}" loading: "Loading chart data..." y_axis_count: "Topics in step" kanban: - title: "Workflow Kanban" - workflow_name: "Workflow: %{workflow_name}" + title: "Process Kanban" + workflow_name: "Process: %{workflow_name}" empty_step: "No topics in this step" topic_count: one: "%{count} topic" @@ -81,7 +81,7 @@ en: confirmation: "Are you sure you want to submit this topic?" start: button_label: "Start" - confirmation: "Are you sure you want to start this workflow?" + confirmation: "Are you sure you want to start this process?" accept: button_label: "Accept" confirmation: "Are you sure you want to accept this topic?" @@ -114,46 +114,49 @@ en: confirmation: "Are you sure you want to move this Topic back to the previous step?" finish: button_label: "Finish" - confirmation: "Are you sure you want to finish this workflow?" + confirmation: "Are you sure you want to finish this process?" close: button_label: "Close" - confirmation: "Are you sure you want to close this workflow?" + confirmation: "Are you sure you want to close this process?" reopen: button_label: "Reopen" - confirmation: "Are you sure you want to reopen this workflow?" + confirmation: "Are you sure you want to reopen this process?" admin_js: admin: + site_settings: + categories: + discourse_workflow: "Process Manager" discourse_workflow: - title: "Discourse Workflow" + title: "Process Manager" workflows: - title: "Workflows" - short_title: "Workflows" - instructions: "Create a workflow by adding a series of steps. Each step can have a different user or group assigned to it. When a topic is created in a category with a workflow, it will be assigned to the first step. The user or group assigned to that step will be notified. When the user or group completes the step, the topic will be assigned to the next step." - none: "No workflows have been created yet." - new: "Create a New Workflow" + title: "Processes" + short_title: "Processes" + instructions: "Create a process by adding a series of workflow steps. When a topic is created in the first step category, it enters the process. Users with the right category permissions can then act on the topic and move it to the next configured step." + none: "No processes have been created yet." + new: "Create a new process" enabled: "Enabled" name: "Name" description: "Description" - overdue_days: "Overdue Days Override" - overdue_days_help: "Blank uses the global default. 0 disables overdue behavior for this workflow." - show_kanban_tags: "Show Tags In Kanban" + overdue_days: "Overdue days override" + overdue_days_help: "Blank uses the global default. 0 disables overdue behavior for this process." + show_kanban_tags: "Show tags in Kanban" show_kanban_tags_help: "When enabled, Kanban cards display topic tags below the title." kanban_compatibility: - label: "Kanban Compatibility" + label: "Kanban compatibility" compatible: "Compatible" incompatible: "Not compatible" help: "Kanban view requires one start step, unique positions, valid step targets, reachability from the start step, and a unique directed transition mapping per step pair. Backward/cyclic paths are supported." workflow: - short_title: "Workflow" + short_title: "Process" editing: - title: "Editing Existing Workflow: %{workflow_name}" + title: "Editing process: %{workflow_name}" new: - title: "Create a New Workflow" + title: "Create a new process" step: editing: - title: "Editing Workflow Step: %{workflow_step_name}" + title: "Editing step: %{workflow_step_name}" new: - title: "Add a New Workflow Step" + title: "Add a new step" option: new: title: "Add a New Option" @@ -162,22 +165,22 @@ en: steps: position: "ID" category: "Category" - ai_enabled: "AI Enabled" - ai_prompt: "AI Prompt" + ai_enabled: "AI enabled" + ai_prompt: "AI prompt" tabs: list: "List" visual: "Visual" overdue_days: "Step Overdue Days Override" - overdue_days_help: "Blank uses workflow/global defaults. 0 disables overdue behavior for this step." + overdue_days_help: "Blank uses process/global defaults. 0 disables overdue behavior for this step." title: "Steps" new: "Add a New Step" none: "No steps have been added yet." name: "Name" description: "Description" no_steps: "No steps have been added yet." - saved: "Workflow Step saved!" - confirm_delete: "Are you sure you want to delete this workflow step?" - deleted: "Workflow Step deleted!" + saved: "Step saved!" + confirm_delete: "Are you sure you want to delete this step?" + deleted: "Step deleted!" options: title: "Options" new: "Add a New Option" @@ -206,7 +209,7 @@ en: reopen: "Reopen" visual: add_step: "Add step" - add_step_title: "Create a workflow step using the selected name and category" + add_step_title: "Create a process step using the selected name and category" add_step_to_lane: "Add step to this swimlane" change_connector_option: "Change the action used by this connector" confirm_delete_connector: "Are you sure you want to permanently delete this connector?" @@ -219,17 +222,17 @@ en: default_step_name: "New step" delete_connector: "Delete connector" delete_step: "Delete step" - loading: "Loading workflow visual..." + loading: "Loading process visual..." new_step_name: "New step name" unknown_category: "Unknown category" back: "Back" save: "Save" - saved: "Workflow saved!" + saved: "Process saved!" edit: "Edit" delete: "Delete" - confirm_delete: "Are you sure you want to delete this workflow?" + confirm_delete: "Are you sure you want to delete this process?" validation: - title: "Validation Warnings" + title: "Validation warnings" duplicate_step_positions: "Duplicate step positions detected: %{positions}" orphan_target_steps: "Some step options target missing steps (%{count} option entries affected)" missing_option_labels: "Missing option button labels for slugs: %{slugs}" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 5380a53..6f47c12 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1,14 +1,14 @@ en: site_settings: - workflow_enabled: "Enable the workflow plugin" - workflow_overdue_days_default: "Default overdue threshold in days for workflow topics. Use 0 to disable overdue behavior by default." - workflow_charts_allowed_groups: "Groups allowed to view workflow burn down charts in addition to admins." + workflow_enabled: "Enable Process Manager" + workflow_overdue_days_default: "Default overdue threshold in days for process topics. Use 0 to disable overdue behavior by default." + workflow_charts_allowed_groups: "Groups allowed to view process burn-down charts in addition to admins." discourse_workflow: topic_transition_action_description: 'Moved from "%{starting_step_name}" to "%{ending_step_name}" with action: "%{step_option_name}" by @%{username}' errors: - no_midway_error: "You cannot create a Topic midway through a workflow and this Category is part of a workflow." + no_midway_error: "You cannot create a topic midway through a process and this category is part of a process." transition_failed_stale_state_refreshing: "Transition Failed: probably due to stale UI state - please try again after refresh - refreshing!" - charts_access_denied: "You are not allowed to view workflow charts." + charts_access_denied: "You are not allowed to view process charts." options: start: "Start" ready: "Ready" @@ -18,10 +18,10 @@ en: workflow: attributes: name: - blank: "A workflow must have a name" + blank: "A process must have a name" workflow_step: attributes: name: - blank: "A workflow step must have a name" + blank: "A process step must have a name" category_id: blank: "You must select a Category" diff --git a/plugin.rb b/plugin.rb index 8178ca4..464294f 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true # name: discourse-workflow -# about: A topic-based workflow engine for Discourse +# about: A process management plugin for Discourse # version: 0.5.0 # authors: Robert Barrow # contact_emails: robert@pavilion.tech From 3aa526f84631f9803e6f3a5c335dccc077035aa5 Mon Sep 17 00:00:00 2001 From: merefield Date: Tue, 19 May 2026 16:10:32 +0100 Subject: [PATCH 02/34] DEV: rename process manager settings --- README.md | 24 ++++---- .../workflow_charts_controller.rb | 6 +- config/locales/server.en.yml | 6 +- config/settings.yml | 12 ++-- lib/discourse_workflow/ai_actions.rb | 27 +++----- lib/discourse_workflow/charts_permissions.rb | 2 +- .../list_controller_extension.rb | 4 +- .../not_midway_validator.rb | 14 +++-- lib/discourse_workflow/stats.rb | 2 +- plugin.rb | 8 +-- .../discourse_workflow/daily_stats_spec.rb | 61 ++++++++++++++++--- spec/lib/stats_spec.rb | 4 +- spec/lib/workflow_topic_lifecycle_spec.rb | 2 +- .../workflow_action_controller_spec.rb | 2 +- .../workflow_charts_controller_spec.rb | 4 +- spec/requests/workflow_list_filters_spec.rb | 2 +- .../workflow_overdue_thresholds_spec.rb | 38 ++++++------ spec/requests/workflow_topic_view_spec.rb | 2 +- spec/system/workflow_charts_spec.rb | 4 +- spec/system/workflow_quick_filters_spec.rb | 2 +- spec/system/workflow_topic_banner_spec.rb | 2 +- 21 files changed, 132 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 98fbcda..abe42f4 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ If you are new to the terminology, see: - Built-in process burn-down chart view (`/workflow/charts` and chart mode in `/workflow`) for single-process context - Chart period selector (`1` to `12` weeks), complete-week windows (Sunday to Saturday), per-step colored series - Overdue behavior with hierarchy: - - global default (`workflow_overdue_days_default`) + - global default (`process_manager_overdue_days_default`) - workflow override - step override - `0` disables overdue behavior at that scope @@ -45,7 +45,7 @@ If you are new to the terminology, see: ## Quickstart -1. Enable the plugin in Site Settings (`workflow_enabled`). +1. Enable the plugin in Site Settings (`process_manager_enabled`). 2. Go to `Admin -> Plugins -> Process Manager`, create a process, then save it. 3. Add workflow steps (Categories in journey order), then add step options (actions/transitions). 4. Create a topic in the first step Category and transition it through actions from the topic banner. @@ -57,12 +57,12 @@ If you are new to the terminology, see: ### Core plugin settings -- `workflow_enabled`: enables/disables Process Manager behavior. -- `workflow_overdue_days_default`: default overdue threshold in days; `0` disables overdue by default. -- `workflow_openai_api_key`: API key for AI actions. -- `workflow_ai_model`: model used for AI actions. -- `workflow_ai_prompt_system`: system prompt support for AI transitions. -- `workflow_charts_allowed_groups`: non-admin groups allowed to view process charts. +- `process_manager_enabled`: enables/disables Process Manager behavior. +- `process_manager_overdue_days_default`: default overdue threshold in days; `0` disables overdue by default. +- `process_manager_openai_api_key`: API key for AI actions. +- `process_manager_ai_model`: model used for AI actions. +- `process_manager_ai_prompt_system`: system prompt support for AI transitions. +- `process_manager_charts_allowed_groups`: non-admin groups allowed to view process charts. ### Process definition setup @@ -82,7 +82,7 @@ Process-level Kanban controls: ### Overdue setup hierarchy -- Global default: `workflow_overdue_days_default` +- Global default: `process_manager_overdue_days_default` - Optional process-level override: `Workflow.overdue_days` - Optional step-level override: `WorkflowStep.overdue_days` @@ -117,11 +117,11 @@ Chart view is shown when the current process discovery context resolves to a sin Access model for charts is intentionally separate from topic-level category access: - Admins can always view charts -- Users in `workflow_charts_allowed_groups` can view charts +- Users in `process_manager_charts_allowed_groups` can view charts - Chart access is aggregate and process-level; it is intentionally not constrained to per-topic visibility rules - This allows operational/reporting audiences to monitor process throughput without granting direct access to every underlying topic -If you want stricter chart data visibility, keep `workflow_charts_allowed_groups` empty and rely on admin-only access. +If you want stricter chart data visibility, keep `process_manager_charts_allowed_groups` empty and rely on admin-only access. ### Background jobs @@ -134,7 +134,7 @@ The plugin schedules and runs the following jobs: ### AI actions -You can leverage AI to handle a step. You need `workflow_openai_api_key`, AI enabled on the step, and a prompt including both `{{options}}` and `{{topic}}`. You can also tune behavior with `workflow_ai_model` and `workflow_ai_prompt_system`. +You can leverage AI to handle a step. You need `process_manager_openai_api_key`, AI enabled on the step, and a prompt including both `{{options}}` and `{{topic}}`. You can also tune behavior with `process_manager_ai_model` and `process_manager_ai_prompt_system`. Example prompt: diff --git a/app/controllers/discourse_workflow/workflow_charts_controller.rb b/app/controllers/discourse_workflow/workflow_charts_controller.rb index d21d59e..6050902 100644 --- a/app/controllers/discourse_workflow/workflow_charts_controller.rb +++ b/app/controllers/discourse_workflow/workflow_charts_controller.rb @@ -5,7 +5,7 @@ class WorkflowChartsController < ApplicationController requires_plugin ::DiscourseWorkflow::PLUGIN_NAME before_action :ensure_logged_in - before_action :ensure_workflow_enabled + before_action :ensure_process_manager_enabled before_action :ensure_can_view_charts def index @@ -28,8 +28,8 @@ def index private - def ensure_workflow_enabled - raise Discourse::NotFound if !SiteSetting.workflow_enabled + def ensure_process_manager_enabled + raise Discourse::NotFound if !SiteSetting.process_manager_enabled end def ensure_can_view_charts diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 6f47c12..1876731 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1,8 +1,8 @@ en: site_settings: - workflow_enabled: "Enable Process Manager" - workflow_overdue_days_default: "Default overdue threshold in days for process topics. Use 0 to disable overdue behavior by default." - workflow_charts_allowed_groups: "Groups allowed to view process burn-down charts in addition to admins." + process_manager_enabled: "Enable Process Manager" + process_manager_overdue_days_default: "Default overdue threshold in days for process topics. Use 0 to disable overdue behavior by default." + process_manager_charts_allowed_groups: "Groups allowed to view process burn-down charts in addition to admins." discourse_workflow: topic_transition_action_description: 'Moved from "%{starting_step_name}" to "%{ending_step_name}" with action: "%{step_option_name}" by @%{username}' errors: diff --git a/config/settings.yml b/config/settings.yml index 4747fab..cab399b 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -1,20 +1,20 @@ plugins: - workflow_enabled: + process_manager_enabled: client: true default: true - workflow_openai_api_key: + process_manager_openai_api_key: client: false default: '' - workflow_overdue_days_default: + process_manager_overdue_days_default: client: true type: integer default: 3 min: 0 - workflow_ai_prompt_system: + process_manager_ai_prompt_system: client: false default: "" type: string - workflow_ai_model: + process_manager_ai_model: client: false type: enum default: gpt-4o-mini @@ -24,7 +24,7 @@ plugins: - gpt-4o-mini - gpt-4-turbo - gpt-4 - workflow_charts_allowed_groups: + process_manager_charts_allowed_groups: client: false type: group_list default: "" diff --git a/lib/discourse_workflow/ai_actions.rb b/lib/discourse_workflow/ai_actions.rb index 417d7eb..6e14b8a 100644 --- a/lib/discourse_workflow/ai_actions.rb +++ b/lib/discourse_workflow/ai_actions.rb @@ -4,12 +4,7 @@ module DiscourseWorkflow class AiActions def transition_all DiscourseWorkflow::WorkflowState - .includes( - topic: :first_post, - workflow_step: { - workflow_step_options: :workflow_option - } - ) + .includes(topic: :first_post, workflow_step: { workflow_step_options: :workflow_option }) .find_each do |workflow_state| step = workflow_state.workflow_step next unless step @@ -27,17 +22,15 @@ def ai_transition(workflow_state) topic = workflow_state.topic return unless step && topic - client = - OpenAI::Client.new(access_token: SiteSetting.workflow_openai_api_key) - model_name = SiteSetting.workflow_ai_model - system_prompt = SiteSetting.workflow_ai_prompt_system + client = OpenAI::Client.new(access_token: SiteSetting.process_manager_openai_api_key) + model_name = SiteSetting.process_manager_ai_model + system_prompt = SiteSetting.process_manager_ai_prompt_system base_user_prompt = step.ai_prompt return if base_user_prompt.blank? # get option slugs for this step - options = - step.workflow_step_options.map { |o| o.workflow_option&.slug }.compact + options = step.workflow_step_options.map { |o| o.workflow_option&.slug }.compact return if options.empty? @@ -46,7 +39,7 @@ def ai_transition(workflow_state) messages = [ { role: "system", content: system_prompt }, - { role: "user", content: user_prompt } + { role: "user", content: user_prompt }, ] response = @@ -55,8 +48,8 @@ def ai_transition(workflow_state) model: model_name, messages: messages, max_tokens: 8, - temperature: 0.1 - } + temperature: 0.1, + }, ) if response["error"] @@ -71,9 +64,7 @@ def ai_transition(workflow_state) result = response.dig("choices", 0, "message", "content") result = result.strip.chomp(".").downcase if result.present? - if result.present? && options.include?(result) - Transition.new.transition(nil, topic, result) - end + Transition.new.transition(nil, topic, result) if result.present? && options.include?(result) end end end diff --git a/lib/discourse_workflow/charts_permissions.rb b/lib/discourse_workflow/charts_permissions.rb index ca2298f..05b2bb3 100644 --- a/lib/discourse_workflow/charts_permissions.rb +++ b/lib/discourse_workflow/charts_permissions.rb @@ -6,7 +6,7 @@ def self.can_view?(user) return false if user.blank? return true if user.admin? - allowed_group_ids = SiteSetting.workflow_charts_allowed_groups_map + allowed_group_ids = SiteSetting.process_manager_charts_allowed_groups_map allowed_group_ids.present? && user.in_any_groups?(allowed_group_ids) end end diff --git a/lib/discourse_workflow/list_controller_extension.rb b/lib/discourse_workflow/list_controller_extension.rb index 15ef504..2cecee1 100644 --- a/lib/discourse_workflow/list_controller_extension.rb +++ b/lib/discourse_workflow/list_controller_extension.rb @@ -27,7 +27,7 @@ def workflow end if params[:overdue] == "1" - default_overdue_days = SiteSetting.workflow_overdue_days_default.to_i + default_overdue_days = SiteSetting.process_manager_overdue_days_default.to_i workflow_topic_ids_scope = workflow_topic_ids_scope .joins(:workflow_step, :workflow) @@ -89,7 +89,7 @@ def workflow_list_user end def ensure_discourse_workflow - raise Discourse::NotFound if !SiteSetting.workflow_enabled + raise Discourse::NotFound if !SiteSetting.process_manager_enabled end end end diff --git a/lib/discourse_workflow/not_midway_validator.rb b/lib/discourse_workflow/not_midway_validator.rb index d5c585b..1a8ee5f 100644 --- a/lib/discourse_workflow/not_midway_validator.rb +++ b/lib/discourse_workflow/not_midway_validator.rb @@ -3,20 +3,22 @@ module DiscourseWorkflow class NotMidwayValidator < ActiveModel::Validator def validate(record) - return unless SiteSetting.workflow_enabled? + return unless SiteSetting.process_manager_enabled? return if record.private_message? active_steps = - WorkflowStep - .joins(:workflow) - .where(category_id: record.category_id, workflows: { enabled: true }) + WorkflowStep.joins(:workflow).where( + category_id: record.category_id, + workflows: { + enabled: true, + }, + ) return if !active_steps.exists? return if active_steps.where(position: 1).exists? # return if record.user.staff? - workflow_in_progress = - active_steps.where("workflow_steps.position > 1").exists? + workflow_in_progress = active_steps.where("workflow_steps.position > 1").exists? if workflow_in_progress record.errors.add(:base, message: I18n.t("discourse_workflow.errors.no_midway_error")) end diff --git a/lib/discourse_workflow/stats.rb b/lib/discourse_workflow/stats.rb index c7b144c..0ff7f32 100644 --- a/lib/discourse_workflow/stats.rb +++ b/lib/discourse_workflow/stats.rb @@ -2,7 +2,7 @@ module DiscourseWorkflow class Stats def calculate_daily_stats - return unless SiteSetting.workflow_enabled + return unless SiteSetting.process_manager_enabled current_date = Date.current now = Time.zone.now diff --git a/plugin.rb b/plugin.rb index 464294f..4d2d2dc 100644 --- a/plugin.rb +++ b/plugin.rb @@ -9,7 +9,7 @@ gem "event_stream_parser", "1.0.0", { require: false } gem "ruby-openai", "8.1.0", { require: false } -enabled_site_setting :workflow_enabled +enabled_site_setting :process_manager_enabled register_asset "stylesheets/common/workflow_common.scss" register_asset "stylesheets/desktop/workflow_desktop.scss", :desktop @@ -32,7 +32,7 @@ module ::DiscourseWorkflow end register_topic_preloader_associations({ workflow_state: %i[workflow workflow_step] }) do - SiteSetting.workflow_enabled + SiteSetting.process_manager_enabled end Discourse::Application.routes.prepend { get "/workflow/charts" => "list#workflow_charts" } @@ -138,7 +138,7 @@ module ::DiscourseWorkflow elsif !workflow_overdue_days.nil? workflow_overdue_days.to_i else - SiteSetting.workflow_overdue_days_default.to_i + SiteSetting.process_manager_overdue_days_default.to_i end end @@ -397,7 +397,7 @@ module ::DiscourseWorkflow on(:topic_created) do |*params| topic, opts = params - if SiteSetting.workflow_enabled + if SiteSetting.process_manager_enabled workflow_step = DiscourseWorkflow::WorkflowStep.joins(:workflow).find_by( category_id: topic.category_id, diff --git a/spec/jobs/scheduled/discourse_workflow/daily_stats_spec.rb b/spec/jobs/scheduled/discourse_workflow/daily_stats_spec.rb index d6ead5e..99631f7 100644 --- a/spec/jobs/scheduled/discourse_workflow/daily_stats_spec.rb +++ b/spec/jobs/scheduled/discourse_workflow/daily_stats_spec.rb @@ -82,23 +82,64 @@ before do freeze_time Time.zone.parse("2026-02-23 10:30:00 UTC") - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true - create_states_for(workflow: workflow_a, step: step_a1, count: 3, topic_category_id: category_a1.id) - create_states_for(workflow: workflow_a, step: step_a2, count: 2, topic_category_id: category_a1.id) - create_states_for(workflow: workflow_a, step: step_a3, count: 1, topic_category_id: category_a1.id) - create_states_for(workflow: workflow_a, step: step_a4, count: 4, topic_category_id: category_a1.id) + create_states_for( + workflow: workflow_a, + step: step_a1, + count: 3, + topic_category_id: category_a1.id, + ) + create_states_for( + workflow: workflow_a, + step: step_a2, + count: 2, + topic_category_id: category_a1.id, + ) + create_states_for( + workflow: workflow_a, + step: step_a3, + count: 1, + topic_category_id: category_a1.id, + ) + create_states_for( + workflow: workflow_a, + step: step_a4, + count: 4, + topic_category_id: category_a1.id, + ) - create_states_for(workflow: workflow_b, step: step_b1, count: 2, topic_category_id: category_b1.id) - create_states_for(workflow: workflow_b, step: step_b2, count: 1, topic_category_id: category_b1.id) - create_states_for(workflow: workflow_b, step: step_b3, count: 2, topic_category_id: category_b1.id) + create_states_for( + workflow: workflow_b, + step: step_b1, + count: 2, + topic_category_id: category_b1.id, + ) + create_states_for( + workflow: workflow_b, + step: step_b2, + count: 1, + topic_category_id: category_b1.id, + ) + create_states_for( + workflow: workflow_b, + step: step_b3, + count: 2, + topic_category_id: category_b1.id, + ) # Unstarted topics should not be counted until they have a workflow_state. Fabricate(:topic, category: category_a1) Fabricate(:topic, category: category_b1) # Existing same-day stats are replaced by the scheduled run. - Fabricate(:workflow_stat, cob_date: Date.current, workflow: workflow_a, workflow_step: step_a1, count: 99) + Fabricate( + :workflow_stat, + cob_date: Date.current, + workflow: workflow_a, + workflow_step: step_a1, + count: 99, + ) # Historical days are left untouched. Fabricate( :workflow_stat, @@ -128,7 +169,7 @@ end it "does not write stats when workflow is disabled" do - SiteSetting.workflow_enabled = false + SiteSetting.process_manager_enabled = false expect { job.execute({}) }.not_to change { DiscourseWorkflow::WorkflowStat.count } end diff --git a/spec/lib/stats_spec.rb b/spec/lib/stats_spec.rb index d3990e1..16a3192 100644 --- a/spec/lib/stats_spec.rb +++ b/spec/lib/stats_spec.rb @@ -32,7 +32,7 @@ end it "calculates daily counts per workflow step from workflow states" do - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true expect do described_class.new.calculate_daily_stats end.to change { DiscourseWorkflow::WorkflowStat.count @@ -40,7 +40,7 @@ end it "ignores corrupted states with null workflow_id or workflow_step_id" do - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true state_1.update_columns(workflow_id: nil) state_2.update_columns(workflow_step_id: nil) diff --git a/spec/lib/workflow_topic_lifecycle_spec.rb b/spec/lib/workflow_topic_lifecycle_spec.rb index a49bb13..01e4723 100644 --- a/spec/lib/workflow_topic_lifecycle_spec.rb +++ b/spec/lib/workflow_topic_lifecycle_spec.rb @@ -26,7 +26,7 @@ end it "does not initialize workflow_state for topics when workflow is disabled" do - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true topic = Fabricate(:topic, category: start_category) DiscourseWorkflow::WorkflowState.where(topic_id: topic.id).delete_all diff --git a/spec/requests/workflow_action_controller_spec.rb b/spec/requests/workflow_action_controller_spec.rb index f4f1290..a6ea356 100644 --- a/spec/requests/workflow_action_controller_spec.rb +++ b/spec/requests/workflow_action_controller_spec.rb @@ -56,7 +56,7 @@ end before do - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true category_1.set_permissions(everyone: :full, staff: :full) category_2.set_permissions(everyone: :full, staff: :full) category_1.save! diff --git a/spec/requests/workflow_charts_controller_spec.rb b/spec/requests/workflow_charts_controller_spec.rb index 442fdd0..cc028e6 100644 --- a/spec/requests/workflow_charts_controller_spec.rb +++ b/spec/requests/workflow_charts_controller_spec.rb @@ -64,8 +64,8 @@ end before do - SiteSetting.workflow_enabled = true - SiteSetting.workflow_charts_allowed_groups = allowed_group.id.to_s + SiteSetting.process_manager_enabled = true + SiteSetting.process_manager_charts_allowed_groups = allowed_group.id.to_s GroupUser.create!(group: allowed_group, user: allowed_user) category_1.update_columns(color: "112233") diff --git a/spec/requests/workflow_list_filters_spec.rb b/spec/requests/workflow_list_filters_spec.rb index 2b99b20..86aa5a7 100644 --- a/spec/requests/workflow_list_filters_spec.rb +++ b/spec/requests/workflow_list_filters_spec.rb @@ -41,7 +41,7 @@ ) end before do - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true sign_in(user) category_a.set_permissions(everyone: :full, staff: :full) diff --git a/spec/requests/workflow_overdue_thresholds_spec.rb b/spec/requests/workflow_overdue_thresholds_spec.rb index 1ce9d85..30cd37d 100644 --- a/spec/requests/workflow_overdue_thresholds_spec.rb +++ b/spec/requests/workflow_overdue_thresholds_spec.rb @@ -8,15 +8,9 @@ fab!(:workflow_global_default) do Fabricate(:workflow, name: "Global Default Workflow", overdue_days: nil) end - fab!(:workflow_override) do - Fabricate(:workflow, name: "Workflow Override", overdue_days: 5) - end - fab!(:workflow_step_override) do - Fabricate(:workflow, name: "Step Override", overdue_days: 10) - end - fab!(:workflow_disabled) do - Fabricate(:workflow, name: "Disabled Overdue", overdue_days: 0) - end + fab!(:workflow_override) { Fabricate(:workflow, name: "Workflow Override", overdue_days: 5) } + fab!(:workflow_step_override) { Fabricate(:workflow, name: "Step Override", overdue_days: 10) } + fab!(:workflow_disabled) { Fabricate(:workflow, name: "Disabled Overdue", overdue_days: 0) } fab!(:category_global_default, :category) fab!(:category_workflow_override, :category) @@ -60,9 +54,15 @@ ) end - fab!(:topic_global_default) { Fabricate(:topic_with_op, category: category_global_default, user: user) } - fab!(:topic_workflow_override) { Fabricate(:topic_with_op, category: category_workflow_override, user: user) } - fab!(:topic_step_override) { Fabricate(:topic_with_op, category: category_step_override, user: user) } + fab!(:topic_global_default) do + Fabricate(:topic_with_op, category: category_global_default, user: user) + end + fab!(:topic_workflow_override) do + Fabricate(:topic_with_op, category: category_workflow_override, user: user) + end + fab!(:topic_step_override) do + Fabricate(:topic_with_op, category: category_step_override, user: user) + end fab!(:topic_disabled) { Fabricate(:topic_with_op, category: category_disabled, user: user) } fab!(:state_global_default) do @@ -99,14 +99,16 @@ end before do - SiteSetting.workflow_enabled = true - SiteSetting.workflow_overdue_days_default = 3 + SiteSetting.process_manager_enabled = true + SiteSetting.process_manager_overdue_days_default = 3 sign_in(user) - [category_global_default, - category_workflow_override, - category_step_override, - category_disabled].each do |category| + [ + category_global_default, + category_workflow_override, + category_step_override, + category_disabled, + ].each do |category| category.set_permissions(everyone: :full, staff: :full) category.save! end diff --git a/spec/requests/workflow_topic_view_spec.rb b/spec/requests/workflow_topic_view_spec.rb index f1c8f5e..0570197 100644 --- a/spec/requests/workflow_topic_view_spec.rb +++ b/spec/requests/workflow_topic_view_spec.rb @@ -35,7 +35,7 @@ end before do - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true category.set_permissions(everyone: :full, staff: :full) category.save! sign_in(user) diff --git a/spec/system/workflow_charts_spec.rb b/spec/system/workflow_charts_spec.rb index 36392df..fd10fa2 100644 --- a/spec/system/workflow_charts_spec.rb +++ b/spec/system/workflow_charts_spec.rb @@ -62,8 +62,8 @@ before do enable_current_plugin - SiteSetting.workflow_enabled = true - SiteSetting.workflow_charts_allowed_groups = allowed_group.id.to_s + SiteSetting.process_manager_enabled = true + SiteSetting.process_manager_charts_allowed_groups = allowed_group.id.to_s 10.times do topic = Fabricate(:topic, category: category_1) diff --git a/spec/system/workflow_quick_filters_spec.rb b/spec/system/workflow_quick_filters_spec.rb index e343e58..b593147 100644 --- a/spec/system/workflow_quick_filters_spec.rb +++ b/spec/system/workflow_quick_filters_spec.rb @@ -56,7 +56,7 @@ before do enable_current_plugin - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true SiteSetting.tagging_enabled = true category_1.set_permissions(everyone: :full, staff: :full) category_2.set_permissions(everyone: :readonly, staff: :full) diff --git a/spec/system/workflow_topic_banner_spec.rb b/spec/system/workflow_topic_banner_spec.rb index cb580a6..1c55c3c 100644 --- a/spec/system/workflow_topic_banner_spec.rb +++ b/spec/system/workflow_topic_banner_spec.rb @@ -49,7 +49,7 @@ before do enable_current_plugin - SiteSetting.workflow_enabled = true + SiteSetting.process_manager_enabled = true GroupUser.create!(group_id: actor_group.id, user_id: actor.id) start_category.set_permissions(everyone: :readonly, actor_group.id => :full, staff: :full) From 23d8ae5a7e8d80591f7158a5a8f3968d9e19011c Mon Sep 17 00:00:00 2001 From: merefield Date: Tue, 19 May 2026 16:23:10 +0100 Subject: [PATCH 03/34] UX: rename process-facing copy --- README.md | 20 ++++++++++---------- config/locales/client.en.yml | 16 ++++++++-------- spec/system/workflow_charts_spec.rb | 7 ++----- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index abe42f4..b33b3ae 100644 --- a/README.md +++ b/README.md @@ -6,20 +6,20 @@ Discuss the plugin here: https://meta.discourse.org/t/discourse-workflow/347110? ## Introduction -Process Manager provides a secure process-management framework for Discourse topics. Each process is made of configurable workflow steps and options, and topics move through those steps until completion. Some branching and looping is supported. +Process Manager provides a secure process-management framework for Discourse topics. Each process is made of configurable steps and options, and topics move through those steps until completion. Some branching and looping is supported. Using topics as work items gives each process a flexible, native Discourse foundation: each item can have a detailed description, attachments, discussion, notifications, tags, categories, permissions, and a full history out of the box. If you are new to the terminology, see: -- Workflow: https://en.wikipedia.org/wiki/Workflow +- Workflow terminology: https://en.wikipedia.org/wiki/Workflow - Business process: https://en.wikipedia.org/wiki/Business_process ## Features -- Process-management workflows using Discourse topics as work items +- Process management using Discourse topics as work items - Admin-defined processes made from steps mapped to Categories (or Sub-categories) -- Visual workflow editor for arranging steps, swim lanes, and transition connectors +- Visual process editor for arranging steps, swim lanes, and transition connectors - Transition actions presented as buttons per step option - Permission model aligned to native Discourse category permissions - Process discovery list (`/workflow`) with quick filters @@ -32,7 +32,7 @@ If you are new to the terminology, see: - Chart period selector (`1` to `12` weeks), complete-week windows (Sunday to Saturday), per-step colored series - Overdue behavior with hierarchy: - global default (`process_manager_overdue_days_default`) - - workflow override + - process override - step override - `0` disables overdue behavior at that scope - Overdue indicator column in the process topic list @@ -40,14 +40,14 @@ If you are new to the terminology, see: - Transition audit trail via small action posts - Process visualization modal from topic and list links - Data Explorer audit query support -- Data Explorer workflow stats query support for chart-oriented time series +- Data Explorer process stats query support for chart-oriented time series - Optional AI-assisted step handling with prompt + option guardrails ## Quickstart 1. Enable the plugin in Site Settings (`process_manager_enabled`). 2. Go to `Admin -> Plugins -> Process Manager`, create a process, then save it. -3. Add workflow steps (Categories in journey order), then add step options (actions/transitions). +3. Add process steps (Categories in journey order), then add step options (actions/transitions). 4. Create a topic in the first step Category and transition it through actions from the topic banner. 5. Use `/workflow` to view queue state, apply quick filters, and switch between `List` / `Kanban` / `Chart` views when available. 6. In Kanban, click a card to open the topic, drag cards to legal target steps, or use keyboard arrows on focused cards. @@ -86,7 +86,7 @@ Process-level Kanban controls: - Optional process-level override: `Workflow.overdue_days` - Optional step-level override: `WorkflowStep.overdue_days` -Resolution order is `step -> workflow -> global`. A value of `0` means overdue behavior is disabled at that level. +Resolution order is `step -> process -> global`. A value of `0` means overdue behavior is disabled at that level. ### Kanban compatibility and behavior @@ -222,14 +222,14 @@ Permissioning principle: | Discovery | Process list with quick filters, list/kanban toggle, and step filtering | Implemented | `/workflow` supports SPA quick filters plus list/kanban switching | | Discovery | Real-time process state-change notifier with refresh CTA | Planned | Wire MessageBus updates into `/workflow` with a core-style “press to refresh” flow | | Kanban | Card transitions (drag/drop and keyboard arrows) | Implemented | Legal transitions only; deterministic directed edge mapping | -| SLA | Overdue thresholds (step -> workflow -> global, `0` disables) | Implemented | Includes overdue list indicator | +| SLA | Overdue thresholds (step -> process -> global, `0` disables) | Implemented | Includes overdue list indicator | | Permissions | Native Discourse category permissions for acting/commenting | Implemented | Transition authority still aligns with category create access | | Permissions | Step/action-level transition permissions | Partial | Deliberately lower priority to preserve simple, core-aligned permissioning | | Validation | Transition preconditions (required tags/fields/checks) | Planned | Intended as optional guardrails before transitions | | SLA | Escalation/reminder notifications | Partial | Overdue visibility exists; automated escalation is next | | Ownership | Discourse Assign integration | Planned | Target is step-entry assignment and auditable ownership changes | | Operations | Bulk process transitions from list views | Missing | High-volume queue operation not yet first-class | -| Performance | Admin/list/chart/transition query-path N+1 and over-fetch hardening | Implemented | Admin serializers preloaded, process quick filters now SQL-scoped, chart loading scoped to selected process, transition lookup round-trips reduced, and workflow-state staleness indexing added | +| Performance | Admin/list/chart/transition query-path N+1 and over-fetch hardening | Implemented | Admin serializers preloaded, process quick filters now SQL-scoped, chart loading scoped to selected process, transition lookup round-trips reduced, and process-state staleness indexing added | | Performance | Bulk process arrival notification fan-out | Planned | Use bulk insert (`insert_all`) for category watcher notifications to reduce per-user insert overhead at high watcher counts | | Performance | Cache process chart payloads | Planned | Add short-lived caching keyed by process and period to reduce repeated chart aggregation for frequent refreshes | | Performance | Cache process visualisation payloads | Planned | Cache graph payloads keyed by topic/workflow-state version to avoid rebuilding identical visualisations | diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 908d06c..d6c3a92 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -131,7 +131,7 @@ en: workflows: title: "Processes" short_title: "Processes" - instructions: "Create a process by adding a series of workflow steps. When a topic is created in the first step category, it enters the process. Users with the right category permissions can then act on the topic and move it to the next configured step." + instructions: "Create a process by adding a series of process steps. When a topic is created in the first step category, it enters the process. Users with the right category permissions can then act on the topic and move it to the next configured step." none: "No processes have been created yet." new: "Create a new process" enabled: "Enabled" @@ -159,9 +159,9 @@ en: title: "Add a new step" option: new: - title: "Add a New Option" + title: "Add a new option" editing: - title: "Editing Option at position: %{position}" + title: "Editing option at position: %{position}" steps: position: "ID" category: "Category" @@ -170,10 +170,10 @@ en: tabs: list: "List" visual: "Visual" - overdue_days: "Step Overdue Days Override" + overdue_days: "Step overdue days override" overdue_days_help: "Blank uses process/global defaults. 0 disables overdue behavior for this step." title: "Steps" - new: "Add a New Step" + new: "Add a new step" none: "No steps have been added yet." name: "Name" description: "Description" @@ -183,13 +183,13 @@ en: deleted: "Step deleted!" options: title: "Options" - new: "Add a New Option" - target_step: "Target Step" + new: "Add a new option" + target_step: "Target step" no_target_step: "No target step selected" select_an_option: "Select an option" position: "Position" name: "Name" - target_position: "Target Position" + target_position: "Target position" actions: submit: "Submit" start: "Start" diff --git a/spec/system/workflow_charts_spec.rb b/spec/system/workflow_charts_spec.rb index fd10fa2..a0992cb 100644 --- a/spec/system/workflow_charts_spec.rb +++ b/spec/system/workflow_charts_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe "Workflow charts", type: :system do +RSpec.describe "Workflow charts" do fab!(:workflow_discovery_page) { PageObjects::Pages::WorkflowDiscovery.new } fab!(:admin, :admin) fab!(:allowed_group, :group) @@ -87,10 +87,7 @@ expect(page).to have_current_path("/workflow/charts", url: false) expect(workflow_discovery_page).to have_workflow_burndown_chart expect(workflow_discovery_page).to have_workflow_burndown_chart_canvas - expect(page).to have_css( - ".workflow-burndown__workflow-name", - text: "Workflow: #{workflow.name}", - ) + expect(page).to have_css(".workflow-burndown__workflow-name", text: "Process: #{workflow.name}") expect(workflow_discovery_page).to have_workflow_view_option("Chart") expect(workflow_discovery_page).to have_workflow_chart_weeks_selector expect(workflow_discovery_page).to have_no_workflow_view_option("Kanban") From 22fa16de5613ad3652642425c417a05ea4be454c Mon Sep 17 00:00:00 2001 From: merefield Date: Tue, 19 May 2026 16:29:16 +0100 Subject: [PATCH 04/34] DEV: rename process CSS selectors --- .../discourse/components/workflow-editor.gjs | 38 ++-- .../components/workflow-list-editor.gjs | 14 +- .../components/workflow-step-editor.gjs | 20 +- .../components/workflow-step-list-editor.gjs | 10 +- .../workflow-step-option-editor.gjs | 8 +- .../workflow-step-option-list-editor.gjs | 18 +- .../components/workflow-visual-editor.gjs | 66 +++--- .../discourse-workflow-workflows/index.gjs | 2 +- .../discourse/components/workflow-buttons.gjs | 8 +- .../components/workflow-name-link.gjs | 2 +- .../components/workflow-topic-banner.gjs | 32 +-- .../workflow-quick-filters.gjs | 80 +++---- .../z-workflow-burndown-chart.gjs | 18 +- .../discourse/initializers/init-workflow.gjs | 22 +- .../stylesheets/common/workflow_common.scss | 204 +++++++++--------- .../stylesheets/desktop/workflow_desktop.scss | 4 +- .../stylesheets/mobile/workflow_mobile.scss | 2 +- .../pages/workflow_admin_visual.rb | 119 +++++----- .../page_objects/pages/workflow_discovery.rb | 84 ++++---- .../page_objects/pages/workflow_topic.rb | 8 +- spec/system/workflow_admin_visual_spec.rb | 8 +- spec/system/workflow_charts_spec.rb | 2 +- spec/system/workflow_quick_filters_spec.rb | 26 +-- 23 files changed, 396 insertions(+), 399 deletions(-) diff --git a/admin/assets/javascripts/discourse/components/workflow-editor.gjs b/admin/assets/javascripts/discourse/components/workflow-editor.gjs index ee0d679..89eee35 100644 --- a/admin/assets/javascripts/discourse/components/workflow-editor.gjs +++ b/admin/assets/javascripts/discourse/components/workflow-editor.gjs @@ -192,12 +192,12 @@ export default class WorkflowEditor extends Component { }} {{/if}}
{{#if @workflow.validation_warnings.length}} -
+
@@ -210,7 +210,7 @@ export default class WorkflowEditor extends Component { {{/if}}