46129 frontend [ templates ] Add FieldSets#205
Conversation
…ets' into frontend/templates/46129__add_fieldsets
…and cloned kickoff test
| for field in self.instance.fields.all(): | ||
| if field.value not in self.NULL_VALUES: | ||
| total += float(field.value) | ||
| if total != float(self.instance.value): |
There was a problem hiding this comment.
🟡 Medium fieldsets/fieldset_rule.py:22
Floating-point comparison total != float(self.instance.value) incorrectly rejects valid field sets due to precision loss. For example, when fields sum to 0.3 via 0.1 + 0.2, the strict equality check fails because 0.1 + 0.2 != 0.3 in IEEE 754 arithmetic. Consider using a tolerance-based comparison like abs(total - float(self.instance.value)) > epsilon.
- if total != float(self.instance.value):
+ if abs(total - float(self.instance.value)) > 1e-9:🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file backend/src/processes/services/workflows/fieldsets/fieldset_rule.py around line 22:
Floating-point comparison `total != float(self.instance.value)` incorrectly rejects valid field sets due to precision loss. For example, when fields sum to `0.3` via `0.1 + 0.2`, the strict equality check fails because `0.1 + 0.2 != 0.3` in IEEE 754 arithmetic. Consider using a tolerance-based comparison like `abs(total - float(self.instance.value)) > epsilon`.
Evidence trail:
backend/src/processes/services/workflows/fieldsets/fieldset_rule.py lines 16-24 at REVIEWED_COMMIT - shows the `_validate_sum_equal` method with `total != float(self.instance.value)` comparison on line 22. IEEE 754 floating-point precision issues are well-documented (e.g., Python docs on floating point: https://docs.python.org/3/tutorial/floatingpoint.html).
| } | ||
| """ | ||
|
|
||
| if data.get('fields'): |
There was a problem hiding this comment.
🟢 Low workflows/kickoff_version.py:180
When data contains {'fields': [], 'fieldsets': []}, the empty fields list is skipped due to truthiness check on line 180, but empty fieldsets is processed via is not None check on line 182. This causes _update_fieldsets to delete all fieldsets while _update_fields leaves orphaned fields intact — inconsistent behavior for empty list inputs. Consider changing line 180 to if data.get('fields') is not None: to match the fieldsets handling.
Also found in 1 other location(s)
backend/src/processes/services/tasks/task_version.py:66
If
field_data.get('selections')returns an empty list[], the condition on line 66 evaluates to falsy, so the method exits without deleting existing selections. This means when a field previously had selections but the new data has'selections': [], the old selections will incorrectly remain in the database instead of being cleared.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file backend/src/processes/services/workflows/kickoff_version.py around line 180:
When `data` contains `{'fields': [], 'fieldsets': []}`, the empty `fields` list is skipped due to truthiness check on line 180, but empty `fieldsets` is processed via `is not None` check on line 182. This causes `_update_fieldsets` to delete all fieldsets while `_update_fields` leaves orphaned fields intact — inconsistent behavior for empty list inputs. Consider changing line 180 to `if data.get('fields') is not None:` to match the fieldsets handling.
Evidence trail:
backend/src/processes/services/workflows/kickoff_version.py lines 180-183 (condition checks), lines 63-77 (_update_fields with delete at line 76-78), lines 136-163 (_update_fieldsets with delete at lines 161-163). Verified at REVIEWED_COMMIT.
Also found in 1 other location(s):
- backend/src/processes/services/tasks/task_version.py:66 -- If `field_data.get('selections')` returns an empty list `[]`, the condition on line 66 evaluates to falsy, so the method exits without deleting existing selections. This means when a field previously had selections but the new data has `'selections': []`, the old selections will incorrectly remain in the database instead of being cleared.
…aticapp/pneumaticworkflow into frontend/templates/46129__add_fieldsets
…off and FieldSetTemplate models
…ntermediate m2m models
…aticapp/pneumaticworkflow into frontend/templates/46129__add_fieldsets
| selection_ids.add(selection.id) | ||
| field.selections.exclude(id__in=selection_ids).delete() | ||
| self._update_field_selections(field, field_data) | ||
| self.instance.output.exclude(id__in=field_ids).delete() |
There was a problem hiding this comment.
🟠 High tasks/task_version.py:94
In _update_fields, the deletion at line 94 removes ALL TaskField objects with task=self.instance, including fields that belong to fieldsets. Since _update_fields runs before _update_fieldsets (lines 531-532), and field_ids only tracks non-fieldset fields, existing fieldset fields are deleted before _update_fieldsets can recreate them. The deletion should filter to only remove fields without a fieldset using self.instance.output.filter(fieldset__isnull=True).exclude(id__in=field_ids).delete().
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file backend/src/processes/services/tasks/task_version.py around line 94:
In `_update_fields`, the deletion at line 94 removes ALL `TaskField` objects with `task=self.instance`, including fields that belong to fieldsets. Since `_update_fields` runs before `_update_fieldsets` (lines 531-532), and `field_ids` only tracks non-fieldset fields, existing fieldset fields are deleted before `_update_fieldsets` can recreate them. The deletion should filter to only remove fields without a fieldset using `self.instance.output.filter(fieldset__isnull=True).exclude(id__in=field_ids).delete()`.
Evidence trail:
backend/src/processes/services/tasks/task_version.py lines 82-94 (_update_fields: field_ids only collects non-fieldset fields, then deletes all output not in field_ids), lines 91 (fieldset=None), line 94 (self.instance.output.exclude(id__in=field_ids).delete()), lines 531-532 (_update_fields called before _update_fieldsets), lines 167-187 (_update_field uses TaskField.objects.update_or_create with fieldset in lookup), lines 231-244 (_update_fieldset_fields), lines 246-276 (_update_fieldsets). backend/src/processes/models/workflows/fields.py lines 47-53 (TaskField.task FK with related_name='output'), lines 60-65 (TaskField.fieldset FK nullable), line 76 (objects = BaseSoftDeleteManager). backend/src/generics/managers.py lines 6-8 (BaseSoftDeleteManager filters is_deleted=False). backend/src/generics/querysets.py lines 59-61 (BaseQuerySet.delete does soft delete via update is_deleted=True).
| service.validate_rules() | ||
| except FieldsetServiceException as ex: | ||
| self.raise_validation_error(message=ex.message) | ||
| for field_template in kickoff.fields.filter(fieldset__isnull=True): |
There was a problem hiding this comment.
🟢 Low workflows/kickoff_value.py:113
When creating fields without a fieldset at lines 113-120, fieldset_id is not passed to TaskFieldService.create(). If the field template has rules, _link_rules accesses kwargs['fieldset_id'] with direct key access and raises KeyError, which escapes the except (TaskFieldException, FieldsetServiceException) block at line 121. Pass fieldset_id=None for fields without a fieldset.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file backend/src/processes/serializers/workflows/kickoff_value.py around line 113:
When creating fields without a fieldset at lines 113-120, `fieldset_id` is not passed to `TaskFieldService.create()`. If the field template has rules, `_link_rules` accesses `kwargs['fieldset_id']` with direct key access and raises `KeyError`, which escapes the `except (TaskFieldException, FieldsetServiceException)` block at line 121. Pass `fieldset_id=None` for fields without a fieldset.
Evidence trail:
backend/src/processes/serializers/workflows/kickoff_value.py lines 113-121 (REVIEWED_COMMIT): `service.create()` called without `fieldset_id`; except block catches only `TaskFieldException, FieldsetServiceException`.
backend/src/generics/base/service.py lines 65-70: `BaseModelService.create(**kwargs)` passes kwargs to `_create_related(**kwargs)`.
backend/src/processes/services/tasks/field.py line 326: `_create_related` calls `_link_rules(instance_template, **kwargs)` if rules exist.
backend/src/processes/services/tasks/field.py line 375: `_link_rules` uses `kwargs['fieldset_id']` (direct key access, raises KeyError if missing).
backend/src/processes/models/templates/fields.py lines 59-68: `FieldTemplate.fieldset` is nullable, and `rules` M2M has no constraint preventing association on fieldset-less fields.
| if field.value not in self.NULL_VALUES: | ||
| total += float(field.value) | ||
| if total != float(self.instance.value): | ||
| raise FieldsetServiceException(MSG_FS_0002(self.instance.value)) |
There was a problem hiding this comment.
Floating-point equality check in sum validation is unreliable
Medium Severity
_validate_sum_equal accumulates field values using float() addition and then compares the total with exact equality (!=). Floating-point arithmetic can produce rounding errors (e.g., 0.1 + 0.2 != 0.3), causing valid inputs to fail validation spuriously. Using Decimal or an epsilon-based comparison would be more reliable.
Reviewed by Cursor Bugbot for commit 5944362. Configure here.
…sorted list across workflow log, task log and kickoff of workflow modal
…ix imports to source module
…in getNormalizedTask
| values_exists = True | ||
| else: | ||
| total += float(field.value) | ||
| values_exists = True |
There was a problem hiding this comment.
Sum rule rejects invalid numbers poorly
Medium Severity
Runtime sum_equal validation in FieldSetRuleService._validate_sum_equal uses float(field.value) with no handling for non-numeric values. Invalid stored or submitted values raise ValueError instead of a fieldset validation error, which can surface as an unhandled server error during kickoff updates or task completion when validate_rules() runs.
Reviewed by Cursor Bugbot for commit 5eb9eb9. Configure here.
…tNormalizedTask to preserve shared field/fieldset ordering
…ts route redirect
| ('is_shared', models.BooleanField(default=True)), | ||
| ('account', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.Account')), | ||
| ('kickoff', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fieldsets', to='processes.Kickoff')), | ||
| ('shared_fieldset', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child_fieldsets', to='processes.FieldsetTemplate')), |
There was a problem hiding this comment.
Shared fieldset FK on_delete mismatch
Medium Severity
Migration 0254 defines shared_fieldset with on_delete=CASCADE, while the model uses on_delete=SET_NULL. Deleting a shared catalog fieldset can cascade-delete template bindings in the database even though application code expects bindings to remain with a null reference.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit a355c08. Configure here.
…aticapp/pneumaticworkflow into frontend/templates/46129__add_fieldsets
| order=fieldset_data['order'], | ||
| title=fieldset_data.get('title'), | ||
| description=fieldset_data.get('description'), | ||
| ) |
There was a problem hiding this comment.
Fieldset update clears title
High Severity
When an existing kickoff or task fieldset binding only needs an order change, create_or_update_fieldsets still calls partial_update_instance with title and description from fieldset_data.get(...). Omitted keys become None, which overwrites stored title/description on the binding even though those fields were not part of the intended update.
Reviewed by Cursor Bugbot for commit 75c2310. Configure here.
| fields=['api_name', 'fieldset'], | ||
| condition=Q(is_deleted=False), | ||
| name='fieldsettemplate_api_name_template_unique', | ||
| ), |
There was a problem hiding this comment.
Duplicate DB constraint name
Medium Severity
FieldsetTemplateRule declares a UniqueConstraint named fieldsettemplate_api_name_template_unique, identical to the constraint on FieldsetTemplate. Migration 0255 creates the rule constraint as fieldsettemplate_rule_api_name_template_unique, so the model Meta no longer matches the database and duplicate names can break future migrations or checks.
Reviewed by Cursor Bugbot for commit 75c2310. Configure here.
…aticapp/pneumaticworkflow into frontend/templates/46129__add_fieldsets
…aticapp/pneumaticworkflow into frontend/templates/46129__add_fieldsets
…pneumaticapp/pneumaticworkflow into frontend/templates/46129__add_fieldsets
…aticapp/pneumaticworkflow into frontend/templates/46129__add_fieldsets
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.
There are 9 total unresolved issues (including 6 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5e73dbe. Configure here.
| del task_fieldsets[i] | ||
| else: | ||
| new_task_fieldsets.append(task_fieldsets[i]) | ||
| task['fieldsets'] = new_kickoff_fieldsets |
There was a problem hiding this comment.
Task drafts get kickoff fieldsets
High Severity
In update_draft_fieldset, task draft updates build new_task_fieldsets but assign task['fieldsets'] from new_kickoff_fieldsets. Task output flows can receive kickoff bindings or the wrong list, and matched task fieldsets are appended to task_fieldsets instead of the new list.
Reviewed by Cursor Bugbot for commit 5e73dbe. Configure here.
| ) | ||
| else: | ||
| print('--- duplicate task fieldset - removed') | ||
| link.delete() |
There was a problem hiding this comment.
Migration skips task fieldset links
High Severity
The migrate_fieldsets handler reuses one updated flag for kickoff M2M links and task M2M links. After the first kickoff link creates a template fieldset, task links are deleted without creating replacements, dropping task fieldset bindings.
Reviewed by Cursor Bugbot for commit 5e73dbe. Configure here.
| f'---|--- new task fieldset: ' | ||
| f'task: "{task["name"]}"', | ||
| ) | ||
| updated = True |
There was a problem hiding this comment.
Draft flag blocks task updates
Medium Severity
update_draft_fieldset uses a single updated flag for kickoff and every task. After kickoff fieldset data is applied, task sections treat later updates as duplicates and skip inserting migrated fieldset payloads into task drafts.
Reviewed by Cursor Bugbot for commit 5e73dbe. Configure here.


1. Release notes
Added support for grouped fields (Fieldsets) in templates and running workflows. Users can now create reusable fieldsets in a catalog, add them to kickoff forms and tasks in the template builder, customize their display order alongside individual fields, fill them out during task execution, and view completed fieldset values in the task execution log, workflow modal, and active task cards. Additionally, a sorting dropdown has been added to the fieldsets catalog page.
2. Description (Problem)
Previously, the concept of fieldsets did not exist in the system as an entity. All fields in templates, kickoff forms, and tasks were configured individually as a flat structure. When a template required identical groups of fields across multiple tasks or kickoff configurations (e.g., billing details, company profile, delivery addresses), administrators had to manually recreate those fields repeatedly. This process was error-prone, caused duplicate configurations, and made template updates/maintenance difficult.
A reusable fields grouping mechanism was required to introduce the new Fieldsets Catalog entity with seamless integration across the template editor, runtime task forms, and workflow execution history.
3. Context
backend/fieldsets/45773__fieldsets)./templates/edit/:idand/templates/new/tasks/:id/workflows/:id/fieldsets4. Solution
/fieldsetslist page with name/date sorting dropdown, and implemented breadcrumb links on the fieldset details view.orderinsidemergeTaskOutputFlow.ts, and extractedMergedOutputRows.tsxcomponent to unify layout rendering.getTaskVariables.tsxto handle nested fieldset properties.fieldsetsRedux slice. AddedisCatalogLoadedand currenttemplateIdchecks to cache catalog items and prevent duplicate API calls during screen swaps.watchWsEvents.ts,routeRealtimeEvent.ts) to handle fieldset structures in notifications, group adjustments, and completed workflow logs.AutosizeInputwith native auto-expanding textareas for Checkbox, Radio, and Attachment components to prevent clipping of long field labels.5. Implementation Details
Before → After
/fieldsetscatalog page with sorting dropdown and breadcrumbs navigation.IExtraFieldmodels.IFieldsetCatalogItem,IFieldsetBindingClient, andIFieldsetRuntimecontracts. Catalog logic is handled via Redux with cache controls.MergedOutputRows.tsx.apiNameBinding.apiNameBindingvalues for each copy, ensuring clone data independence from the original.orderinto a single interleaved stream (Editor, TaskCard, Kickoff, WorkflowLog, Highlights, TuneView).6. What to Test
6.1 Preconditions
6.2 Positive Scenarios / Test Report
2. Add 2 fields and 1 fieldset to Kickoff.
3. Drag the fieldset between the two fields.
4. Save the template and refresh the page.
→ Expected: the custom layout order is fully preserved.
2. Try submitting with the required field empty.
→ Expected: the submit button is disabled, showing a validation warning.
3. Fill the field.
→ Expected: the button becomes active.
2. Open the Workflow Log.
→ Expected: fieldset data is rendered within a distinct grouped container in the correct order.
2. Open the process "Files" tab (attachments-only).
→ Expected: the uploaded file is visible in the process files list.
/fieldsetspage.2. Select name sorting (Name Asc/Desc) and date sorting in the dropdown.
→ Expected: the list order updates immediately.
2. Open the Process Run form on desktop.
→ Expected: the label is rendered to the left of the input field.
3. Resize screen down to mobile viewport.
→ Expected: layout shifts responsively, label moves above the input.
2. Load the task execution form.
→ Expected: the label wraps cleanly using textarea auto-expansion, without clipping.
2. Start a workflow and fill in the fieldset fields in the first task.
→ Expected: the fieldset fields in the second task remain empty (data is isolated per task).
3. Complete both tasks.
→ Expected: Workflow Log displays the correct completed fieldset values for each task independently.
2. Start workflows for both templates concurrently and fill in the fieldset values.
→ Expected: process data is completely isolated.
3. Rename or update the fieldset in the catalog.
→ Expected: when editing templates A and B, the updated fieldset structure is reflected correctly in both editors.
2. Verify rendering sequence across all project display views:
a) Active Task Card (
/tasks/:id) during execution;b) Workflow Log execution history (
/workflows/:id) inside task blocks;c) Workflow Starter (Kickoff form) in dashboard/modal;
d) Highlights feed in logs;
e) Outputs Preview screen in template builder;
f) Tune View modal (field display configuration).
→ Expected: in all views, elements are rendered in the exact order (Field 1 -> Fieldset 1 -> Field 2 -> Fieldset 2).
2. Click the add fieldset button → select a fieldset from the catalog.
→ Expected: the fieldset appears in the Kickoff output flow with the full list of fields and drag handles.
3. Save the template.
→ Expected: on reload, the fieldset is persisted with correct order and all fields intact.
2. Add a fieldset from the catalog to the task's Output flow.
→ Expected: the fieldset is rendered interleaved with regular fields per order.
3. Save and reload.
→ Expected: fieldset is in place with correct order.
→ Expected: the fieldset disappears from the Output flow, regular fields remain, order is recalculated.
2. Save the template.
→ Expected: fieldset is removed; running workflows with this template are unaffected.
2. In a task description, insert a variable from a fieldset field via the variables menu.
3. Save and start a workflow, filling in the field.
→ Expected: the variable in the task description is substituted with the filled value.
→ Expected: the cloned task contains the same fieldset with a unique
apiNameBinding.2. Save the template.
→ Expected: both tasks have independent bindings to the same catalog fieldset.
/tasks/:id).2. Fill in the fieldset fields and complete the task.
→ Expected: the complete button is active only when required fieldset fields are filled. Data is saved.
2. Verify that fieldsets are displayed in the correct order in the modal.
3. Fill in the fields and start the workflow.
→ Expected: workflow is created with all fieldset field values saved.
→ Expected: fieldsets are displayed correctly without auth errors.
2. Fill in and submit the form.
→ Expected: workflow starts with all fieldset values saved.
/fieldsets(name, description, fields).→ Expected: fieldset is created and appears in the list.
2. Open the fieldset detail page, change the name and save.
→ Expected: name is updated.
3. Delete a fieldset not bound to any template.
→ Expected: fieldset is removed from the list.
2. In another tab/browser, complete a task with filled fieldset fields.
→ Expected: the first browser updates in real time showing the completed fieldset block.
2. Use that field in the DueDate configuration of another task.
3. Use a variable from the fieldset in a task Condition.
4. Save and start a workflow.
→ Expected: DueDate is calculated correctly, the condition triggers based on the fieldset value.
2. Remove (unbind) that fieldset from the task.
→ Expected: dangling variables from the removed fieldset are handled gracefully (no render errors). Template saves without errors.
2. Open the workflow page → click "Edit Kickoff" (WorkflowEditPopup).
3. Change fieldset field values and save.
→ Expected: values are updated, changes are reflected in the Workflow Log and active tasks.
2. Use the "Return To" function to send the task back for rework.
→ Expected: task is reverted, previously filled fieldset fields are preserved and available for re-editing.
2. Open the task page → events section (Task Log).
→ Expected: the task completion event displays fieldset fields in the correct order.
2. Open the workflows list page (Workflows Grid).
→ Expected: the page loads without errors, fieldset data is correctly normalized (no crash).
→ Expected: the new template has all fieldset bindings with unique
apiNameBindingvalues.2. Open the cloned template and inspect the task Output flow.
→ Expected: fieldsets are in place, variables reference the clone's fieldset, not the original.
2. Click "Clone" (create a new workflow based on the current one).
→ Expected: the Kickoff form of the new workflow contains fieldsets with values pre-filled from the original.
3. Start the cloned workflow.
→ Expected: workflow is created with correct fieldset data.
2. Click the display settings icon (Tune View).
3. Verify that fieldset fields appear in the modal's field list with correct names and grouping.
→ Expected: fieldset fields are visible, order matches the template configuration.
6.3 Negative Scenarios and Edge Cases
/fieldsets/999999directly.→ Expected: redirects to the templates overview page, and showing an error notification.
2. Attempt to add the same fieldset catalog item twice to the same task.
→ Expected: duplicate addition is disabled or ignored.
→ Expected: access is denied; redirects to safety with an error banner.
6.4 Verification Points
Fieldset: [Name].complete_workflowWS event is processed and the UI updates the fieldset data reactively./v3/fieldsetsincludeordering=nameorordering=-created_at.6.5 Not Tested
en_USandru_RUwere not tested.7. Refactoring
Refactoring was carried out to substitute direct API queries with a cached Redux store (
redux/fieldsets/slice.ts), caching records based ontemplateIdandisCatalogLoaded. Standardized rendering components by migrating all kickoff and task display files to the newMergedOutputRows.tsx, eliminating layout duplication in the Workflow Log, Task Log, and Kickoff Modal.Refactoring Verification
→ Expected: catalog data is loaded from the Redux cache, preventing multiple API requests.
→ Expected: no flashing of stale template A fieldsets occurs.
8. Affected Areas (Dependencies)
→ Expected: the kickoff form correctly displays mixed fields and fieldsets in their configured order.
→ Expected: fieldsets render and submit without authorization issues.
→ Expected: all bound fieldsets are cloned into the new template kickoff configuration.
9. Unit Tests
This branch touches 105 test files, of which 54 are entirely new. Net gain is approximately 390 test cases (
it/test).In addition, mocks and assertions were updated in 51 existing test files to align with the new type contracts (
IFieldsetBindingClient,IFieldsetRuntime,apiNameBinding).10. Related commits
This branch contains 129 commits affecting the frontend part:
Show commit list (129)
75c2310d46129 test(fieldsets): add factories and update tests for fieldset reuse in templatesa355c08b46129 chore(template): remove obsolete isDiscarding state and fieldsets route redirect4099803e46129 fix(fieldsets): remove legacy field order normalization from getNormalizedTask to preserve shared field/fieldset ordering15cff17346129 fix(fieldsets): load fieldsets on new template creation5eb9eb9b46129 fix(fieldsets): normalize Task API fieldsets to runtime format in getNormalizedTaskbf342beb46129 refactor(fieldsets): remove sharedFieldsetId from IFieldsetRuntime4dd4bf2746129 chore: remove legacy ITaskFieldset type, fix stale test mock keysedb20bf046129 refactor(fieldsets): rename IFieldsetData → IFieldsetRuntime, fix imports to source module28909fc646129 feat(fieldsets): replace legacy fieldset mapper with binding pipeline, fix fieldset clone uniquenessff100d7946129 feat(fieldsets): replace apiName with apiNameBinding in IFieldsetData consumers and testsb798332e46129 feat(fieldsets): remove legacy id from IFieldsetData, enforce sharedFieldsetId44fcb9bd46129 feat(fieldsets): remove getFieldsetsCatalogByApiName selector and all consumersad8b152d46129 feat(template-edit): remove fieldsetsByApiName prop from FieldsetIconPicker and OutputFormTaskMerged2d3f43de46129 feat(fieldsets): remove catalog lookups from KickoffRedux, TemplateIntegrations; narrow getNormalizedKickoff signature8917db0346129 feat(fieldsets): remove fieldsetsByApiName from ExtraFieldsInfo, OutputsPreview, MergedOutputRowse6233d9a46129 feat(fieldsets): replace catalog fieldset loading with template-embedded datadc99612d46129 feat(fieldsets): replace catalog API lookup with embedded kickoff fieldsetsd424e11b46129 feat(fieldsets): migrate fieldset types in template editor (part 3) — remove fieldsetsByApiName from template utilities, update cleanTemplateReferences/mapTemplateRequest/collectFieldApiNames signaturesaaecad3046129 feat(fieldsets): unify fieldset removal to use sharedFieldsetId instead of apiName0b3f0d2a46129 fest(fieldsets): migrate fieldset creation and binding flow to IFieldsetBindingClient type with apiNameBindingbd92ea5946129 feat(template) update fieldset catalog loading logic during template fetch05d1ad8a46129 feat(fieldsets): migrate fieldset types in template editor (part 2)323f2f7846129 feat(fieldsets): migrate fieldset types in template editor (part 1)f3ac87c147673 fix(tests): update RichText snapshots3cb70a7d46129 fix(fieldsets): show return link on fieldset detail page instead of tabs91066f70feat(fieldsets): align frontend types and API layer with fieldsets API contract573785a447616 fix(tasks): insert urgent tasks after urgent block44156c0646129 feat(fieldsets): migrate frontend from /templates/:id/fieldsets/:id to /fieldsets/:id601c594147610 chore(tasks): extract workflow rename sync helper7214f56347610 fix(tasks): update workflow names after rename853a445d8830 refactor(ExtraField): remove unused inputClassName from kickoff field in ExtraFieldCreatable and ExtraFieldUser components0acee1d18830 refactor(FieldWithName): remove unused layout effect and related logic734bd84347954 fix(RichText): Enhance image loading error handling in useRichTextContainer7382029d47594 fix(RichText): Improve image loading handling and fix anchor tag closured262e20d47594 feat(RichText): Enhance RichText component with new features and styling improvementsd971733d47593 refactor(WebSocket): streamline WebSocket event handling and connection managementa7d0667247593 (websocket) Enhance WebSocket error handling: log errors for invalid messages and unhandled eventsf44ff8d347589 fix(workflows): apply class name to workflow ended icon4bce466347589 fix(workflows): show workflow complete events as finished with ended iconebf2931846129 feat(fieldsets): migrate POST /templates/:id/fieldsets → POST /fieldsetsb6222a9e46129 feat(fieldsets): migrate fieldsets API from /templates/:id/fieldsets to /fieldsets26403bf847561 refactor(AddGuestsBanner): rename local storage key to reflect groups functionalitya6854bba47561 fix(links): update support article URLs to remove '/en' from pathsb9ae746047561 fix(Groups): reorder PageTitle component to improve layout7ca60b2547328 refactor(WorkflowLog): simplify user ID handling in comments and reactions1f6bcbc247328 fix(WorkflowLog): update comment reaction count to reflect reacted user IDs536fccf847550 fix(interceptor): remove technical JSON payload from InterceptorError message4850685d47328 test(realtime): add unit tests for WebSocket utility functions5712c61747328 fix(ui): resolve watch list rendering and TaskCard invalid markup4f5c760a47328 refactor(realtime): extract WS event routing into dedicated moduledc4f16fc47328 feat(accounts): sync users from WebSocket events6f546bb947328 refactor(groups): migrate groups store to RTK slice80a1c1b947328 fix(realtime): correct WS mappers for notifications and workflow log75b37e6747328 refactor(realtime): consolidate WebSocket payload types into types.ts2b4ac0bd46129 fix(PublicForm): show backend error message instead of generic fallback on submit failure787bf6e346129 feat(fieldsets): add fieldset support to public form kickoffd7aa5e9f46129 test(ExtraFields): add label-left coverage and refactor tests to strict typesed7f046146129 refactor(tests): add central IExtraField/IFieldsetData factories and migrate all 33 test files to use theMe8758c41fix(extra-fields): fix field name overflow in Radio, Checkbox and Attachment by switching from AutosizeInput to native textareab6b39b1346129 resolve conflicts and merge 45773 into 46129ff4c187c46129 Add left label support for date/user/file fields in run mode, fix fieldset date conversion, restrict left labels to desktop only, add responsive toolbar scaling for rich editorfda87f4b46129 feat: add label-left layout support for Checkbox, Radio, and Dropdown fields in Process Run296f48ec46129 feat: support left label positioning for checkbox, radio, attachment and dropdown fields in fieldset editorebc4d07e46129 feat(fieldsets): Add left label position support for fieldset fieldsa02cdf3746129 chore(tests): remove redundant jest reference directives from 74 test files4430015446129 test(conditions): add unit tests for skipped and completed_or_skipped operatorsa290a0a846129 test(fieldsets): add unit tests for task, template, templates, workflows, dashboard and runWorkflowModal redux modules0069b525feat(nginx): read SSL certificate files from the host4e7900d1fix(start.sh) review fixes5fe83cd546129 test(fieldsets): cover API clients, Redux slice/selectors/sagas, mappers and validatorscff7011f46129 test(fieldsets): routing contract for TemplateView, FieldsetsView, TemplateLayout5e2e65aa46129 test(fieldsets): cover fieldsets in WorkflowEditPopup, WorkflowModal, TuneViewModal and logs3e05694446129 test(fieldsets/runtime): cover kickoff edit, task card outputs, highlights and page title99b8bedafeat(docker): Upgrade installation5588c69546129 test(template-edit): add fieldsets coverage for editor (kickoff, task output, runtime, clone)4288682f46129 test(fieldsets): cover task variables, item, fields counter, output form merge64b4dbd346129 test(fieldsets/editor): cover TemplateEdit cleanup, variables sync on catalog change, and TemplateControlls fieldsets flowsccf25a7646129 test(fieldsets): add unit tests for fieldsets in template editor858962e946129 test(fieldsets): add unit tests for Fieldsets, FieldsetCard and FieldsetModal1811ae1846129 fix(fieldset details): reset loading state on template mismatch, show skeleton only during loading, add FieldsetDetails tests15db8dd446129 feat(fieldsets): add fieldset rendering to TuneViewModal48f20a2546129 fix(fieldsets): align getTaskVariables typings with backend and update function to use proper fieldset data for correct task names in task‑filter on workflow and task pages.3429478546129 refactor(template): replace weak param types in collectFieldApiNames with IExtraField/ITaskFieldset and remove redundant null guards53bd469546129 fix(fieldsets): validate URL params on fieldset list and detail pages and redirect when IDs are invalidf19f423646129 feat(conditions): add completed_or_skipped operator and fix operator dropdown menu width8aaf63c646129 refactor(fieldsets): make IFieldsetData.order required, remove non-null assertion in KickoffOutputs and fix test mocks1c6906e246129 fix(run) hide Insert variable button in Run workflow name field and add regression tests784bab8346129 fix(fieldsets): include kickoff fieldset fields in wfNameTemplate validation and extract collectFieldApiNames helper94ad8f2646129 fix(fieldsets): align fieldset preparation with fields logic and fix truncated view rendering09e0f86146129 feat(check if): add skipped operator to task conditions in template editor1aed9e8646129 fix(fieldsets): pass kickoff fieldsets to KickoffOutputs in Highlights feedc753989d46129 fix(fieldsets): validate template ownership on fieldset detail page835ebc3846129 fix(fieldsets): redirect to templates list when template not found (404)097575e646129 fix(fieldsets): wrap createFieldset and deleteFieldset in call() effect0617284b46129 fix(fieldsets): synchronize fieldsets catalog loading before template UI activation, add saga tests7b7910e946129 fix(highlights): show kickoff output fields for WorkflowRun events54551e3e46129 fix(fieldsets): disable Save/Start button when fieldset contains empty required fieldsc7061c7146129 fix(fieldsets): include fieldset file attachments in attachments-only view62011cdd46129 feat(notifications): add complete_workflow notification rendering59fe705046129 fix(fieldsets): persist fieldsets in localStorage via storage factorya7ecb1dc46129 fix(fieldsets): clear fieldsets list on template switch to prevent stale data flashe02b465ctest(fieldsets): add tests for correct fields and fieldsets ordering in workflow run, kickoff edit and task completione17e818646129 fix(fieldsets): correct field/fieldset ordering in KickoffEdit, extract MergedOutputList component2eb16d6246129 fix(fieldsets): use kickoff fieldset order in Run form instead of catalog order0d89feae46129 fix(datasets): enforce strict datasetOptions typing in ExtraField, fix dataset bug on Fieldset page, add prop propagation testa5f79a5c46129 refactor(fieldset): unify Kickoff and Task fieldset rendering via shared MergedOutputRowsb868db2046129 refactor(fieldsets): centralize fieldset catalog in Redux, skip redundant loads by templateId4b52f1b446129 refactor(fieldsets): migrate fieldset catalog from React Context to Redux store2d39393146129 fix(fieldsets): include fieldsets in output guard check for workflow and task log28138592yamaha fix(fildsets): clean up stale fieldset references in cleanTemplateReferences595d5faeyamaha fix(editor): include fieldset fields in cleanTemplateReferences validationc03df84f46129 fix(tests): add missing property in TaskPerformers testda96ea3546129 chore(fieldsets): remove stray word left from refactoring4a1332ef46129 fix(datasets): pass datasetOptions to ExtraFieldIntl in OutputFormTaskMergedf05fee2e46129 fix(fieldsets): fix output display order in workflow log, task log, kickoff modal and fix new field insertion in task editore93cdc1946129 feat(fieldsets): display fields and fieldsets in unified order-sorted list across workflow log, task log and kickoff of workflow modal5944362146129 feat(fieldsets)!: migrate fieldset identification to apiName in editor scopedfae482746129 feat(fieldsets) add sorting SelectMenu to fieldsets list page87dd575446129 feat(fieldsets): add breadcrumb navigation on fieldset detail pagec563064d46129 fix(fieldsets): fix task output fields width narrower than descriptionc0ab52f546129 fix(fieldset): fieldsets link visibility for unsaved templates and cloned kickoff test975d3ee345773 feat(fieldsets): frontend init commit3a3ee10f8830 style: Enhance FieldWithName component and KickoffRedux styles for improved layout and debugging21cfd0218830 style: Add text-small mixin to kickoff-create-field-add-option in Checkbox, Creatable, and Radio componentsde83dda08830 style: Simplify padding and positioning in ExtraFieldCheckbox and KickoffRedux styles9cf596ad8830 style: Consolidate margin-top styles for label elements in KickoffRedux.css648605f38830 style: Update ExtraField styles by adding margin-top to kickoff-create-field-options and removing redundant kickoff-dropdown-field margin065cb5f88830 refactor(TaskForm): Remove title prop from TaskDescriptionEditor and TaskForm components for cleaner codec4c158af8830 refactor: Enhance task view styling: Add text overflow handling for description elements in TemplateEdit.cssNote
High Risk
Large schema and workflow-path changes (kickoff start, task complete, field resolution) plus a one-off data migration command; mistakes could break templates, validation, or existing field data.
Overview
Introduces grouped fields (fieldsets) end-to-end on the backend: new template models (
FieldsetTemplate, rules, shared vs per-template bindings) and workflow models (FieldSet,FieldSetRule), with migrations and amigrate_fieldsetsmanagement command to reshape legacy shared fieldset data.Catalog & template editing:
FieldSetTemplateServicesupports shared CRUD, cloning from shared definitions viashared_fieldset_id, and guards against deleting/editing catalog fieldsets still referenced by templates. Kickoff and task serializers gainfieldsets, withFieldsetMixinsyncing bindings on create/update and draft normalization. New DRF helpers (RelatedApiNameField,RelatedApiNameListField) resolve nested field/rule references byapi_namewithin account/template context.Runtime: Workflows instantiate fieldsets from templates (
FieldSetServiceon task/kickoff start). Kickoff create/update and task completion now read/write values for fields inside fieldsets and runsum_equalrule validation. Template/workflow helpers for output fields include fields attached via fieldsets, not only top-level kickoff/task fields.Supporting changes:
BaseModelServicegains optionalaccount, defaultdelete(), and looser_create_related; dedicatedFieldTemplateServicefor template fields. Versioning schemas and task version updates persist fieldsets. Minor:SystemVariable.TASK_VARSexpanded,TemplateFilterremoved from filters (replaced byFieldSetFilter), locale POT refresh, sample.envlogging default.Reviewed by Cursor Bugbot for commit 5e73dbe. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add FieldSets support to templates, workflows, tasks, and the public UI
FieldsetTemplateandFieldSetDjango models with associated rules, linking fieldsets to templates, kickoffs, and tasks; adds migrations and service layers (FieldSetTemplateService,FieldSetService,FieldSetRuleService) for full CRUD and rule validation./fieldsets/REST API (SharedFieldsetTemplateViewSet) for managing shared fieldset templates, and updates template/kickoff/task serializers to includefieldsetsin all relevant API responses.fieldsetsreducer and saga in the root store.Fieldsets,FieldsetDetails,FieldsetCard,FieldsetModal) behind an admin/owner-gated route at/fieldsets/.KickoffRedux,TaskForm,WorkflowEditPopup,PublicForm,TaskCard,KickoffOutputs, andWorkflowModalto render, edit, validate, and submit fieldset fields alongside regular fields via a sharedMergedOutputListcomponent.TaskUpdateVersionService,KickoffUpdateVersionService) to synchronize fieldset rules and fields during version updates.fieldsetsStorageto localStorage task persistence alongside existingoutputStorage, and clears both on task completion.fieldsetsinto webhook payloads, event serializers, highlights, workflow log, andTuneViewModal.TaskUpdateVersionServiceandKickoffUpdateVersionServicenow delete fieldsets/rules not present in incoming payloads during version updates, which is destructive if callers omit fieldsets unintentionally.Macroscope summarized 5e73dbe.