Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bb7bbee
UX: rebrand copy to Process Manager
merefield May 19, 2026
3aa526f
DEV: rename process manager settings
merefield May 19, 2026
23d8ae5
UX: rename process-facing copy
merefield May 19, 2026
22fa16d
DEV: rename process CSS selectors
merefield May 19, 2026
5196d24
DEV: rename process frontend modules
merefield May 19, 2026
6f62d28
DEV: rename process route state
merefield May 19, 2026
43a832f
UX: clarify process wording
merefield May 19, 2026
4678674
DEV: rename process frontend internals
merefield May 19, 2026
aed7023
DEV: rename process Ruby helpers
merefield May 19, 2026
f262d7c
DEV: rename process admin store models
merefield May 19, 2026
bafcf08
DEV: rename process manager namespace
merefield May 19, 2026
cc5ebfe
DEV: rename process routes
merefield May 19, 2026
dab4d86
DEV: rename process payload keys
merefield May 19, 2026
a3977ac
DEV: rename process specs
merefield May 19, 2026
f59f13d
DEV: rename process frontend internals
merefield May 19, 2026
31efe32
DEV: rename process DOM attributes
merefield May 19, 2026
bc914f8
DEV: rename process list and notification identifiers
merefield May 19, 2026
9aca924
DEV: rename process locale namespace
merefield May 20, 2026
9e08170
DEV: rename process manager plugin slug
merefield May 20, 2026
72f02bc
DEV: rename process manager assets
merefield May 20, 2026
2e71f8b
DEV: rename process frontend locals
merefield May 20, 2026
70dbf7c
UX: rename process data explorer defaults
merefield May 20, 2026
7f96828
DEV: rename process fabricators
merefield May 20, 2026
f7c938a
DEV: rename process manager tables
merefield May 20, 2026
b778660
DEV: use process manager schema
merefield May 20, 2026
4d1e458
UX: clarify process AI help
merefield May 20, 2026
1d82d5f
DEV: rename process spec wording
merefield May 20, 2026
d1c757e
DEV: rename process visual test globals
merefield May 20, 2026
dfbbc4e
DEV: rename process visual data helpers
merefield May 20, 2026
593fdc2
DEV: remove workflow locale key
merefield May 20, 2026
2b1328c
DOCS: update process manager README
merefield May 20, 2026
7886acf
CHORE: bump minor version
merefield May 20, 2026
b98322f
DEV: format visual editor
merefield May 20, 2026
102132c
DEV: update process model annotations
merefield May 20, 2026
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
211 changes: 124 additions & 87 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import Textarea from "discourse/components/d-textarea";
import DToggleSwitch from "discourse/components/d-toggle-switch";
import { popupAjaxError } from "discourse/lib/ajax-error";
import I18n, { i18n } from "discourse-i18n";
import WorkflowStepListEditor from "./workflow-step-list-editor";
import WorkflowVisualEditor from "./workflow-visual-editor";
import ProcessStepListEditor from "./process-step-list-editor";
import ProcessVisualEditor from "./process-visual-editor";

export default class WorkflowEditor extends Component {
export default class ProcessEditor extends Component {
@service adminPluginNavManager;
@service router;
@service store;
Expand Down Expand Up @@ -49,30 +49,30 @@ export default class WorkflowEditor extends Component {

@action
updateModel() {
this.editingModel = this.args.workflow.workingCopy();
this.showDelete = !this.args.workflow.isNew && !this.args.workflow.system;
this.editingModel = this.args.process.workingCopy();
this.showDelete = !this.args.process.isNew && !this.args.process.system;
}

@action
async save() {
this.isSaving = true;

const backupModel = this.args.workflow.workingCopy();
const backupModel = this.args.process.workingCopy();

this.args.workflow.setProperties(this.editingModel);
this.args.process.setProperties(this.editingModel);
try {
await this.args.workflow.save();
this.#sortWorkflows();
await this.args.process.save();
this.#sortProcesses();
this.toasts.success({
data: { message: i18n("admin.discourse_workflow.workflows.saved") },
data: { message: i18n("admin.process_manager.processes.saved") },
duration: 2000,
});
this.router.transitionTo(
"adminPlugins.show.discourse-workflow-workflows",
this.store.findAll("workflow")
"adminPlugins.show.processes",
this.store.findAll("process")
);
} catch (e) {
this.args.workflow.setProperties(backupModel);
this.args.process.setProperties(backupModel);
popupAjaxError(e);
} finally {
later(() => {
Expand All @@ -84,12 +84,12 @@ export default class WorkflowEditor extends Component {
@action
delete() {
return this.dialog.confirm({
message: i18n("admin.discourse_workflow.workflows.confirm_delete"),
message: i18n("admin.process_manager.processes.confirm_delete"),
didConfirm: () => {
return this.args.workflow.destroyRecord().then(() => {
return this.args.process.destroyRecord().then(() => {
this.router.transitionTo(
"adminPlugins.show.discourse-workflow-workflows",
this.store.findAll("workflow")
"adminPlugins.show.processes",
this.store.findAll("process")
);
});
},
Expand All @@ -109,17 +109,17 @@ export default class WorkflowEditor extends Component {
);
}

async toggleField(field, sortWorkflows) {
this.args.workflow.set(field, !this.args.workflow[field]);
this.editingModel.set(field, this.args.workflow[field]);
if (!this.args.workflow.isNew) {
async toggleField(field, sortProcesses) {
this.args.process.set(field, !this.args.process[field]);
this.editingModel.set(field, this.args.process[field]);
if (!this.args.process.isNew) {
try {
const args = {};
args[field] = this.args.workflow[field];
args[field] = this.args.process[field];

await this.args.workflow.update(args);
if (sortWorkflows) {
this.sortWorkflows();
await this.args.process.update(args);
if (sortProcesses) {
this.#sortProcesses();
}
} catch (e) {
popupAjaxError(e);
Expand All @@ -128,15 +128,15 @@ export default class WorkflowEditor extends Component {
}

get showSteps() {
return this.args.workflow.id > 0;
return this.args.process.id > 0;
}

validationWarningMessage(warning) {
const code = warning.code;

if (code === "duplicate_step_positions") {
return i18n(
"admin.discourse_workflow.workflows.validation.duplicate_step_positions",
"admin.process_manager.processes.validation.duplicate_step_positions",
{
positions: (warning.positions || []).join(", "),
}
Expand All @@ -145,7 +145,7 @@ export default class WorkflowEditor extends Component {

if (code === "orphan_target_steps") {
return i18n(
"admin.discourse_workflow.workflows.validation.orphan_target_steps",
"admin.process_manager.processes.validation.orphan_target_steps",
{
count: (warning.option_ids || []).length,
}
Expand All @@ -154,7 +154,7 @@ export default class WorkflowEditor extends Component {

if (code === "missing_option_labels") {
return i18n(
"admin.discourse_workflow.workflows.validation.missing_option_labels",
"admin.process_manager.processes.validation.missing_option_labels",
{
slugs: (warning.slugs || []).join(", "),
}
Expand All @@ -164,181 +164,173 @@ export default class WorkflowEditor extends Component {
return code;
}

#sortWorkflows() {
const sorted = this.args.workflows.toArray().sort((a, b) => {
#sortProcesses() {
const sorted = this.args.processes.toArray().sort((a, b) => {
return a.name.localeCompare(b.name);
});
this.args.workflows.clear();
this.args.workflows.setObjects(sorted);
this.args.processes.clear();
this.args.processes.setObjects(sorted);
}

<template>
<DBreadcrumbsItem
@path="/admin/plugins/{{this.adminPluginNavManager.currentPlugin.name}}/workflows/{{@model.id}}"
@label={{i18n "admin.discourse_workflow.workflows.workflow.short_title"}}
@path="/admin/plugins/{{this.adminPluginNavManager.currentPlugin.name}}/processes/{{@model.id}}"
@label={{i18n "admin.process_manager.processes.process.short_title"}}
/>
<BackButton
@route="adminPlugins.show.discourse-workflow-workflows"
@label="admin.discourse_workflow.workflows.back"
@route="adminPlugins.show.processes"
@label="admin.process_manager.processes.back"
/>
{{#if @workflow.name}}
{{#if @process.name}}
<h2>{{I18n.t
"admin.discourse_workflow.workflows.workflow.editing.title"
workflow_name=@workflow.name
"admin.process_manager.processes.process.editing.title"
process_name=@process.name
}}</h2>
{{else}}
<h2>{{I18n.t
"admin.discourse_workflow.workflows.workflow.new.title"
}}</h2>
<h2>{{I18n.t "admin.process_manager.processes.process.new.title"}}</h2>
{{/if}}
<form
class="form-horizontal workflow-editor"
class="form-horizontal process-editor"
{{didUpdate this.updateModel @model.id}}
{{didInsert this.updateModel @model.id}}
>
{{#if @workflow.validation_warnings.length}}
<div class="control-group workflow-editor__validation-warnings">
{{#if @process.validation_warnings.length}}
<div class="control-group process-editor__validation-warnings">
<label>{{i18n
"admin.discourse_workflow.workflows.validation.title"
"admin.process_manager.processes.validation.title"
}}</label>
<ul>
{{#each @workflow.validation_warnings as |warning|}}
{{#each @process.validation_warnings as |warning|}}
<li>{{this.validationWarningMessage warning}}</li>
{{/each}}
</ul>
</div>
{{/if}}
<div class="control-group">
<DToggleSwitch
class="workflow-editor__enabled"
@state={{@workflow.enabled}}
@label="admin.discourse_workflow.workflows.enabled"
class="process-editor__enabled"
@state={{@process.enabled}}
@label="admin.process_manager.processes.enabled"
{{on "click" this.toggleEnabled}}
/>
</div>
<div class="control-group">
<label>{{I18n.t "admin.discourse_workflow.workflows.name"}}</label>
<label>{{I18n.t "admin.process_manager.processes.name"}}</label>
<Input
class="workflow-editor__name"
class="process-editor__name"
@type="text"
@value={{this.editingModel.name}}
disabled={{this.editingModel.system}}
/>
</div>
<div class="control-group">
<label>{{I18n.t
"admin.discourse_workflow.workflows.description"
}}</label>
<label>{{I18n.t "admin.process_manager.processes.description"}}</label>
<Textarea
class="workflow-editor__description"
class="process-editor__description"
@value={{this.editingModel.description}}
disabled={{this.editingModel.system}}
/>
</div>
<div class="control-group">
<label>{{I18n.t
"admin.discourse_workflow.workflows.overdue_days"
}}</label>
<label>{{I18n.t "admin.process_manager.processes.overdue_days"}}</label>
<Input
class="workflow-editor__overdue-days"
class="process-editor__overdue-days"
@type="number"
min="0"
@value={{this.editingModel.overdue_days}}
disabled={{this.editingModel.system}}
/>
<p>{{i18n "admin.discourse_workflow.workflows.overdue_days_help"}}</p>
<p>{{i18n "admin.process_manager.processes.overdue_days_help"}}</p>
</div>
<div class="control-group">
<DToggleSwitch
class="workflow-editor__show-kanban-tags"
class="process-editor__show-kanban-tags"
@state={{this.editingModel.show_kanban_tags}}
@label="admin.discourse_workflow.workflows.show_kanban_tags"
@label="admin.process_manager.processes.show_kanban_tags"
@disabled={{this.editingModel.system}}
{{on "click" this.toggleShowKanbanTags}}
/>
<p>{{i18n
"admin.discourse_workflow.workflows.show_kanban_tags_help"
}}</p>
<p>{{i18n "admin.process_manager.processes.show_kanban_tags_help"}}</p>
</div>
{{#if @workflow.id}}
{{#if @process.id}}
<div class="control-group">
<label>{{i18n
"admin.discourse_workflow.workflows.kanban_compatibility.label"
"admin.process_manager.processes.kanban_compatibility.label"
}}</label>
<p>
{{#if @workflow.kanban_compatible}}
<span class="workflow-editor__kanban-compatible">
{{#if @process.kanban_compatible}}
<span class="process-editor__kanban-compatible">
{{i18n
"admin.discourse_workflow.workflows.kanban_compatibility.compatible"
"admin.process_manager.processes.kanban_compatibility.compatible"
}}
</span>
{{else}}
<span class="workflow-editor__kanban-incompatible">
<span class="process-editor__kanban-incompatible">
{{i18n
"admin.discourse_workflow.workflows.kanban_compatibility.incompatible"
"admin.process_manager.processes.kanban_compatibility.incompatible"
}}
</span>
{{/if}}
</p>
<p>{{i18n
"admin.discourse_workflow.workflows.kanban_compatibility.help"
"admin.process_manager.processes.kanban_compatibility.help"
}}</p>
</div>
{{/if}}
{{#if this.showSteps}}
<div class="control-group workflow-editor__steps-panel">
<div class="workflow-editor__steps-tabs">
<div class="control-group process-editor__steps-panel">
<div class="process-editor__steps-tabs">
<button
type="button"
class={{if
this.showingStepsList
"btn btn-primary workflow-editor__steps-tab"
"btn btn-default workflow-editor__steps-tab"
"btn btn-primary process-editor__steps-tab"
"btn btn-default process-editor__steps-tab"
}}
{{on "click" this.showStepsList}}
>
{{i18n "admin.discourse_workflow.workflows.steps.tabs.list"}}
{{i18n "admin.process_manager.processes.steps.tabs.list"}}
</button>
<button
type="button"
class={{if
this.showingStepsVisual
"btn btn-primary workflow-editor__steps-tab"
"btn btn-default workflow-editor__steps-tab"
"btn btn-primary process-editor__steps-tab"
"btn btn-default process-editor__steps-tab"
}}
{{on "click" this.showStepsVisual}}
>
{{i18n "admin.discourse_workflow.workflows.steps.tabs.visual"}}
{{i18n "admin.process_manager.processes.steps.tabs.visual"}}
</button>
</div>

{{#if this.showingStepsList}}
<WorkflowStepListEditor
class="workflow-editor__steps"
@workflow={{@workflow}}
<ProcessStepListEditor
class="process-editor__steps"
@process={{@process}}
@disabled={{this.editingModel.system}}
@onChange={{this.stepsChanged}}
/>
{{else}}
<WorkflowVisualEditor
@workflow={{@workflow}}
<ProcessVisualEditor
@process={{@process}}
@disabled={{this.editingModel.system}}
/>
{{/if}}
</div>
{{/if}}
<div class="control-group workflow-editor__action_panel">
<div class="control-group process-editor__action_panel">
<DButton
class="btn-primary workflow-editor__save"
class="btn-primary process-editor__save"
@action={{this.save}}
@disabled={{this.isSaving}}
>{{I18n.t "admin.discourse_workflow.workflows.save"}}</DButton>
>{{I18n.t "admin.process_manager.processes.save"}}</DButton>
{{#if this.showDelete}}
<DButton
@action={{this.delete}}
class="btn-danger workflow-editor__delete"
class="btn-danger process-editor__delete"
>
{{I18n.t "admin.discourse_workflow.workflows.delete"}}
{{I18n.t "admin.process_manager.processes.delete"}}
</DButton>
{{/if}}
</div>
Expand Down
Loading