Skip to content

Conversation

@tuplle
Copy link
Member

@tuplle tuplle commented Dec 17, 2025

Description

Release 2.1.0 with bug fixes

Dependencies

Third party dependencies

Blocking Pull requests

<Depends on #(PR id)>/

How Has Been This Tested?

  • <Name of a test [test file](link to the test file)>

Test Configuration

<Please describe configuration for tests to run if applicable, like program parameters, host OS, VM configuration etc. You can use >

Name Tested on
OS
Runtime
Dependency Manager
Framework version
Run parameters
Other configuration

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes have been checked, personally or remotely, with @...
  • I have commented my code, particularly in hard-to-understand areas
  • I have resolved all conflicts with the target branch of the PR
  • I have updated and synced my code with the target branch
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes:
    • Lint test
    • Unit tests
    • Integration tests
  • I have checked my contribution with code analysis tools:
  • I have made corresponding changes to the documentation:
    • Developer documentation
    • User Guides

Summary by CodeRabbit

  • New Features

    • Interactive place/arc editing in simulation (marking/data dialogs), task-ref init field with chips, and widespread autocomplete for component/property inputs
    • Loading spinner and app title updated
  • Bug Fixes

    • Stronger numeric validation for token/value inputs; Save disabled when inputs are invalid
  • Documentation

  • Chores

    • Version bumped to 2.1.0-RC.8
    • pnpm lockfile added to .gitignore

✏️ Tip: You can customize this high-level summary in your review settings.

mazarijuraj and others added 30 commits November 13, 2024 09:54
- start development cycle
- remove questionable *ngIf on Placeholder and Description inputs in edit panel
- refactor data detail to allow different init type inputs
- refactor into angular component
- reuse component in form builder
- update monaco petriflow definition, remove regex highlight due to collision with comments
- fix getReferenceValue getting value from original model and not simulated model
[NAB-369] - Boolean field description
[NAB-373] - Place reference value not changed on simulation
[NAB-362] Action editor interpolated string highlight
- add dialog for changing place marking
- add validations to existing data change dialog
- bind arcs and places in simulation mode
- fix typo in place edit dialog
- add missing css for dialog
- fix data dialog opening on arcs with place ref
- refactor dialog call into common functions
- add interface definitions for field list
- add new component definitions
- add default component properties
- change input in data view to autocomplete, prepare for component refactor
- update components in edit panel to autocomplete (WIP)
- reset tool after closing dialog
- clear selected elements collection on reset
[NAB-372] - Element move after dialog save
# Conflicts:
#	src/app/modeler/edit-mode/services/modes/canvas-tool.ts
- fix resetting simulation on dialog close by refactoring dialog open function
[NAB-367] - One-click variable arc change
- increase RC version
- increase version of petri.svg and petriflow.svg libs
- compare init values by transition id if no label is present
mazarijuraj and others added 20 commits April 7, 2025 11:10
- disable tasks that contain taskRef as dataRef
[NAB-359] Task ref with multiple init values
# Conflicts:
#	src/app/modeler/data-mode/data-detail/data-detail.component.ts
… arcs not to load

- arcs which referenced data has non integer value will be displayed/represented with value 0 in edit + simulation mode
- prefill known component properties with default values in form builder (click + drag&drop)
- update fields with placeholder (caseRef/taskRef...) in form builder
- fix i18n text field default properties in form builder
[NAB-368] Component parameters
- Add global flag support for roles and improve role ID form
- Enhanced role model to include a global flag.
- Updated role-detail component to handle global flag changes.
- Updated `@netgrif/petriflow` dependency to 2.2.1.
… arcs not to load

- Improved usage of ImportUtils.isInitValueNumber to replace regex checks for initialization values.
[NAB-375] Variables with no init values referenced in arcs will cause arcs not to load
[NAB-378] Global role support
… arcs not to load

- fix missing init value check
- increase version rc number
- fix init value not set in data detail component
- increase version rc number
- fix duplicate action id bug
- increase version rc number
- Update `@netgrif/petriflow` dependency to 2.2.2.
- fix the problem with columns, add datagroup if there is no one and set it number of cols
@tuplle tuplle requested a review from mazarijuraj December 17, 2025 09:00
@tuplle tuplle self-assigned this Dec 17, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Walkthrough

Adds dialog-based editing for place markings and data in simulation, extensive form-builder autocompletes and typed field metadata, ModelService action ID management, a tokenizer rewrite, UI loading styles, package/config updates, and multiple component/service integrations and refactors.

Changes

Cohort / File(s) Summary
Configuration & Packaging
\.gitignore, nae.json, package.json
Ignore pnpm-lock.yaml; update services.urls.engine to https://demo.netgrif.cloud/; bump package version to 2.1.0-RC.8 and minor dependency patch bumps.
New Marking Change Dialog
src/app/dialogs/dialog-marking-change/..., src/app/app.module.ts
Add DialogMarkingChangeComponent (TS, HTML, SCSS) with markingCtrl FormControl and validation; declare component in AppModule.
Change Data Dialog
src/app/dialogs/dialog-change-data/*
Add valueCtrl FormControl with required + non-negative-integer validator; numeric constraints, per-field mat-error messages, and Save button disabled when invalid.
Form Builder — Edit Panel & Field List
src/app/form-builder/edit-panel/*, src/app/form-builder/field-list/*, src/app/form-builder/form-builder.*
Add autocompletes for component/property names, new FormControls, copy/clone actions, use FieldListService and typed metadata; expose isPlaceholderField; transfer property metadata on drag/drop; cap right sidenav width.
Field List Service Types & Data
src/app/form-builder/field-list/field-list.service.ts
Introduce PropertyDef, ComponentDef, DataRefDef; type fieldListArray and getComponentMeta; add isPlaceholderField and richer component/property definitions.
Gridster Integration
src/app/form-builder/gridster/gridster.service.ts, src/app/form-builder/gridster/gridster-datafield/*
addDataRef now returns DataRef, applies transferred properties from drag data; template uses fieldListService.isPlaceholderField for placeholder logic; constructor injection updated.
Modeler Module & TaskRef Init
src/app/modeler/modeler.module.ts, src/app/modeler/data-mode/task-ref-init-field/*
Add TaskRefInitFieldComponent (chips + autocomplete), declare/export in ModelerModule; removed FormBuilderModule import.
Data Detail Component
src/app/modeler/data-mode/data-detail/*
Add component/property autocompletes, unified Initial value rendering for many DataTypes, helper methods for typed input handling, FieldListService integration, and new FormControl for component name.
Action Editor / Tokenizer
src/app/modeler/actions-mode/action-editor/*
Make inserted newline conditional in editor helper; replace Java-like tokenizer with a more modular Groovy-oriented tokenizer (tokens.ts) and new token categories.
Action ID Management & Sequence Gen
src/app/modeler/services/model/model.service.ts, src/app/modeler/services/model/sequence-generator.ts
Move action ID generation into ModelService (nextActionId, collectActions); getReferenceValue accepts optional model; SequenceGenerator.reset accepts Action elements and adjusts prefix parsing.
Canvas & Tools
src/app/modeler/edit-mode/domain/canvas-node-element.ts, src/app/modeler/edit-mode/services/modes/*
Add CanvasNodeElement.pretty; remove CanvasTool.openDialog; update CanvasListenerTool.openDialog to optional callback with beforeDialog/afterDialog hooks; SelectTool.reset now clears selection.
Simulation Mode & Tools
src/app/modeler/simulation-mode/*, src/app/modeler/simulation-mode/tool/*
Add right-click suppression in components; new newSvgPlace/newSvgArc helpers; SimulationTool gets onPlaceUp, onArcUp, openMarkingPlaceDialog, openDataDialog, and afterDialog; ChangeDataTool now uses callback-style openDialog and triggers simulation update/render.
UI / Styling / Loading
src/index.html, src/styles.scss
Title capitalization; add loading markup (logo + spinner) and .app-loading animation and related styles.
Role Detail & Place Edit
src/app/modeler/role-mode/role-detail/*, src/app/dialogs/dialog-place-edit/*
Rename control to roleIdForm, adjust error bindings; add Is Global checkbox with changeGlobalFlag handler; update token error wording in place edit dialog.
Miscellaneous Integrations & Minor Edits
src/app/app.module.ts, src/app/form-builder/form-builder.component.ts, various components
Register new components, inject services (e.g., FieldListService, SelectedTransitionService), auto-create a data group in FormBuilderComponent when missing, and other minor template/format changes.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SimulationTool
    participant CanvasPlace
    participant DialogMarkingChangeComponent
    participant ModelService
    participant SimulationModeService

    User->>SimulationTool: click place (onPlaceUp)
    SimulationTool->>CanvasPlace: resolve place id
    SimulationTool->>DialogMarkingChangeComponent: openDialog(placeId, callback)
    DialogMarkingChangeComponent->>ModelService: read place
    ModelService-->>DialogMarkingChangeComponent: place object
    User->>DialogMarkingChangeComponent: submit new marking
    DialogMarkingChangeComponent-->>SimulationTool: callback(updated marking)
    SimulationTool->>ModelService: apply marking
    SimulationTool->>SimulationModeService: renderModel(...)
    SimulationModeService-->>User: updated visualization
Loading
sequenceDiagram
    participant User
    participant SimulationTool
    participant CanvasArc
    participant DialogChangeDataComponent
    participant SimulationModeService
    participant ModelService

    User->>SimulationTool: click arc (onArcUp)
    alt arc references data
        SimulationTool->>DialogChangeDataComponent: openDialog(dataSet, callback)
        User->>DialogChangeDataComponent: edit & save
        DialogChangeDataComponent-->>SimulationTool: callback(updated data)
        SimulationTool->>ModelService: update data model
        SimulationTool->>SimulationModeService: renderModel(...)
    else arc references place
        SimulationTool->>DialogMarkingChangeComponent: openDialog(placeId, callback)
        User->>DialogMarkingChangeComponent: edit & save
        DialogMarkingChangeComponent-->>SimulationTool: callback(updated marking)
        SimulationTool->>ModelService: apply marking
        SimulationTool->>SimulationModeService: renderModel(...)
    end
    SimulationModeService-->>User: updated visualization
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas to focus review on:

  • src/app/form-builder/field-list/field-list.service.ts — new interfaces, expanded field definitions, and isPlaceholder logic.
  • src/app/form-builder/edit-panel/* and src/app/form-builder/field-list/* — many template + logic changes for autocompletes and property cloning.
  • src/app/modeler/data-mode/data-detail/* and task-ref-init-field/* — unified initial value rendering and new component behavior.
  • src/app/modeler/actions-mode/action-editor/definitions/tokens.ts — tokenizer rewrite (language semantics).
  • src/app/modeler/services/model/model.service.ts and sequence-generator.ts — action ID refactor and ID parsing changes.
  • src/app/modeler/simulation-mode/* and simulation tools — dialog callback flow, rendering updates, and new event handlers.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Release 2.1.0' is directly related to the version bump in package.json (2.0.0 -> 2.1.0-RC.8) and aligns with the PR's stated purpose of releasing version 2.1.0.

📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b1962f and 8f31d26.

📒 Files selected for processing (1)
  • package.json (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and test
🔇 Additional comments (1)
package.json (1)

61-63: The @netgrif package versions (1.1.1 for @netgrif/petri.svg and @netgrif/petriflow.svg, 2.2.2 for @netgrif/petriflow) all exist on the npm registry and are not deprecated. No security vulnerabilities detected.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 45

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71a3a66 and 636a552.

📒 Files selected for processing (44)
  • .gitignore (1 hunks)
  • nae.json (1 hunks)
  • package.json (2 hunks)
  • src/app/app.module.ts (2 hunks)
  • src/app/dialogs/dialog-change-data/dialog-change-data.component.html (1 hunks)
  • src/app/dialogs/dialog-change-data/dialog-change-data.component.ts (2 hunks)
  • src/app/dialogs/dialog-marking-change/dialog-marking-change.component.html (1 hunks)
  • src/app/dialogs/dialog-marking-change/dialog-marking-change.component.scss (1 hunks)
  • src/app/dialogs/dialog-marking-change/dialog-marking-change.component.ts (1 hunks)
  • src/app/dialogs/dialog-place-edit/dialog-place-edit.component.html (1 hunks)
  • src/app/form-builder/edit-panel/edit-panel.component.html (7 hunks)
  • src/app/form-builder/edit-panel/edit-panel.component.ts (6 hunks)
  • src/app/form-builder/field-list/field-list.component.ts (4 hunks)
  • src/app/form-builder/field-list/field-list.service.ts (9 hunks)
  • src/app/form-builder/form-builder.component.html (1 hunks)
  • src/app/form-builder/form-builder.module.ts (2 hunks)
  • src/app/form-builder/gridster/gridster-datafield/gridster-data-field.component.html (1 hunks)
  • src/app/form-builder/gridster/gridster-datafield/gridster-data-field.component.ts (2 hunks)
  • src/app/form-builder/gridster/gridster.service.ts (3 hunks)
  • src/app/modeler/actions-mode/action-editor/action-editor-menu/action-editor-menu.component.ts (1 hunks)
  • src/app/modeler/actions-mode/action-editor/action-editor.service.ts (2 hunks)
  • src/app/modeler/actions-mode/action-editor/definitions/tokens.ts (1 hunks)
  • src/app/modeler/data-mode/data-detail/data-detail.component.html (4 hunks)
  • src/app/modeler/data-mode/data-detail/data-detail.component.ts (9 hunks)
  • src/app/modeler/data-mode/task-ref-init-field/task-ref-init-field.component.html (1 hunks)
  • src/app/modeler/data-mode/task-ref-init-field/task-ref-init-field.component.scss (1 hunks)
  • src/app/modeler/data-mode/task-ref-init-field/task-ref-init-field.component.spec.ts (1 hunks)
  • src/app/modeler/data-mode/task-ref-init-field/task-ref-init-field.component.ts (1 hunks)
  • src/app/modeler/edit-mode/domain/canvas-node-element.ts (2 hunks)
  • src/app/modeler/edit-mode/edit-mode.component.ts (2 hunks)
  • src/app/modeler/edit-mode/services/modes/canvas-tool.ts (0 hunks)
  • src/app/modeler/edit-mode/services/modes/select-tool.ts (1 hunks)
  • src/app/modeler/modeler.module.ts (2 hunks)
  • src/app/modeler/role-mode/role-detail/role-detail.component.html (2 hunks)
  • src/app/modeler/role-mode/role-detail/role-detail.component.ts (3 hunks)
  • src/app/modeler/services/canvas/canvas-listener-tool.ts (1 hunks)
  • src/app/modeler/services/model/model.service.ts (13 hunks)
  • src/app/modeler/services/model/sequence-generator.ts (2 hunks)
  • src/app/modeler/simulation-mode/simulation-mode.component.ts (2 hunks)
  • src/app/modeler/simulation-mode/simulation-mode.service.ts (5 hunks)
  • src/app/modeler/simulation-mode/tool/change-data-tool.ts (1 hunks)
  • src/app/modeler/simulation-mode/tool/simulation-tool.ts (4 hunks)
  • src/index.html (1 hunks)
  • src/styles.scss (1 hunks)
💤 Files with no reviewable changes (1)
  • src/app/modeler/edit-mode/services/modes/canvas-tool.ts
🧰 Additional context used
🧬 Code graph analysis (9)
src/app/form-builder/field-list/field-list.component.ts (2)
src/app/form-builder/field-list/field-list.service.ts (1)
  • ComponentDef (11-18)
src/app/form-builder/edit-panel/edit-panel.component.ts (1)
  • dataRef (182-184)
src/app/modeler/simulation-mode/simulation-mode.service.ts (2)
src/app/modeler/services/model/model.service.ts (3)
  • Injectable (33-597)
  • model (73-82)
  • model (84-86)
src/app/modeler/edit-mode/edit-mode.service.ts (1)
  • Injectable (45-367)
src/app/dialogs/dialog-marking-change/dialog-marking-change.component.ts (3)
src/app/dialogs/dialog-change-data/dialog-change-data.component.ts (1)
  • Component (16-46)
src/app/modeler/simulation-mode/simulation-mode.service.ts (2)
  • data (149-151)
  • data (153-155)
src/app/dialogs/dialog-place-edit/dialog-place-edit.component.ts (1)
  • PlaceEditData (7-9)
src/app/modeler/role-mode/role-detail/role-detail.component.ts (1)
src/app/modeler/role-mode/role-detail/changed-role.ts (1)
  • ChangedRole (3-14)
src/app/dialogs/dialog-change-data/dialog-change-data.component.ts (2)
src/app/modeler/simulation-mode/simulation-mode.service.ts (2)
  • data (149-151)
  • data (153-155)
src/app/modeler/edit-mode/domain/canvas-node-element.ts (1)
  • id (7-9)
src/app/modeler/simulation-mode/tool/change-data-tool.ts (2)
src/app/dialogs/dialog-change-data/dialog-change-data.component.ts (2)
  • DataSet (7-9)
  • Data (11-14)
src/app/modeler/simulation-mode/simulation-mode.service.ts (2)
  • data (149-151)
  • data (153-155)
src/app/modeler/data-mode/data-detail/data-detail.component.ts (1)
src/app/form-builder/field-list/field-list.service.ts (3)
  • ComponentDef (11-18)
  • DataRefDef (20-25)
  • PropertyDef (6-9)
src/app/form-builder/gridster/gridster.service.ts (1)
src/app/form-builder/field-list/field-list.service.ts (1)
  • PropertyDef (6-9)
src/app/form-builder/edit-panel/edit-panel.component.ts (1)
src/app/form-builder/field-list/field-list.service.ts (3)
  • ComponentDef (11-18)
  • DataRefDef (20-25)
  • PropertyDef (6-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: task-list-completed
  • GitHub Check: task-list-completed
  • GitHub Check: Build and test
🔇 Additional comments (51)
src/app/modeler/role-mode/role-detail/role-detail.component.html (2)

26-32: LGTM!

The "Is Global" checkbox is properly implemented with correct data binding and change handler. The layout structure is consistent with other form fields in the component.


36-36: LGTM!

Good formatting improvement - adding spaces inside interpolation braces improves readability and follows Angular style guidelines.

src/app/modeler/role-mode/role-detail/role-detail.component.ts (1)

16-16: LGTM!

The addition of trailing commas and the rename from form to roleIdForm are good improvements. The trailing commas follow TypeScript best practices and make future diffs cleaner. The more descriptive form control name improves code readability.

Also applies to: 30-30, 39-42

src/index.html (3)

5-5: LGTM!

The title capitalization improvement enhances the professional appearance of the application.


13-69: LGTM!

The inline spinner styles are appropriate for displaying the loading screen immediately before the main CSS bundle loads. This approach ensures users see visual feedback during application startup.


75-80: LGTM!

The loading layout structure is well-designed, with the logo placeholder and spinner providing clear visual feedback during application initialization. The integration with the styles defined in styles.scss ensures a smooth loading experience.

src/styles.scss (1)

233-259: LGTM!

The loading block and fade-in animation are implemented correctly. The technique of switching display from none to block at 1% of the animation, followed by opacity animation, is a valid workaround for the fact that the display property cannot be smoothly animated. The referenced asset file exists at src/assets/netgrif_logo.svg.

src/app/modeler/data-mode/task-ref-init-field/task-ref-init-field.component.scss (1)

1-3: LGTM!

The utility class is straightforward and follows standard CSS patterns for full-width layouts.

.gitignore (1)

54-54: LGTM!

Adding pnpm-lock.yaml to the ignore list is consistent with the existing pattern of ignoring package-lock.json and is appropriate for this project.

src/app/dialogs/dialog-change-data/dialog-change-data.component.html (1)

1-1: LGTM!

The dynamic plural/singular title based on dataset length improves the user experience.

src/app/modeler/actions-mode/action-editor/action-editor-menu/action-editor-menu.component.ts (1)

39-41: LGTM!

The conditional newline insertion prevents appending unnecessary newlines to falsy values, which improves the text insertion behavior for edge cases.

src/app/modeler/data-mode/task-ref-init-field/task-ref-init-field.component.html (1)

1-26: LGTM!

The template correctly implements a chip-based input with autocomplete functionality. The use of Angular 17+ control flow syntax (@for) and Material components is appropriate. Event handlers are properly bound for adding, selecting, and removing init values.

src/app/dialogs/dialog-marking-change/dialog-marking-change.component.scss (1)

1-8: LGTM!

The dialog styling follows Material Design patterns with appropriate flex layout for content and right-aligned action buttons.

package.json (1)

61-63: All specified @netgrif package versions are published and available.

Verified that @netgrif/petri.svg@1.1.1, @netgrif/petriflow@2.2.2, and @netgrif/petriflow.svg@1.1.1 all exist on npm. No vulnerabilities detected.

src/app/form-builder/form-builder.module.ts (1)

18-18: LGTM! Clean module integration.

The ModelerModule import follows Angular best practices and enables FormBuilderModule to access modeler components.

Also applies to: 43-44

src/app/dialogs/dialog-place-edit/dialog-place-edit.component.html (1)

16-16: LGTM! Corrects misleading validation message.

The error message now accurately reflects that it validates the Tokens field, not the Id field.

src/app/modeler/simulation-mode/simulation-mode.component.ts (1)

1-1: LGTM! Standard context menu suppression.

The right-click handler correctly prevents the default browser context menu, likely to enable custom context menu functionality in simulation mode.

Also applies to: 23-27

src/app/modeler/edit-mode/edit-mode.component.ts (1)

1-1: LGTM! Consistent context menu handling.

The right-click handler implementation is identical to SimulationModeComponent, ensuring consistent UX across mode components.

Also applies to: 31-35

src/app/app.module.ts (1)

47-47: LGTM! Proper component registration.

DialogMarkingChangeComponent is correctly imported and declared in AppModule, following Angular best practices.

Also applies to: 81-81

src/app/form-builder/gridster/gridster-datafield/gridster-data-field.component.ts (1)

9-9: LGTM! Clean service injection.

FieldListService is properly injected as a public property, making it accessible in the component template for placeholder field determination.

Also applies to: 24-26

src/app/dialogs/dialog-marking-change/dialog-marking-change.component.html (1)

7-7: No action needed. The different validator names (validMarking in dialog-place-edit and validMultiplicity in dialog-marking-change) are intentionally named based on their semantic context—validMarking for marking fields and validMultiplicity for count/multiplicity fields. Both implement the same non-negative integer validation logic, but the naming distinction appropriately reflects the field types being validated, which is consistent with best practices.

src/app/modeler/edit-mode/domain/canvas-node-element.ts (1)

23-27: LGTM!

The pretty() helper method provides a clean, consistent way to format node labels for UI display, safely handling cases where label.value is missing.

src/app/modeler/services/model/sequence-generator.ts (2)

18-18: Good fix: Using dynamic prefix length.

The change from a hardcoded substring index to this._prefix.length correctly handles prefixes of any length, fixing a potential bug with non-single-character prefixes.


16-16: LGTM: Action type added to reset() signature.

Extending the collection type to include Action aligns with the broader ID management enhancements and maintains type safety.

src/app/modeler/simulation-mode/simulation-mode.service.ts (3)

62-62: LGTM: Model-aware reference resolution.

Passing this.model to getReferenceValue() ensures the multiplicity calculation uses the correct model context.


90-96: Good improvement: Using ImportUtils for robust parsing.

Replacing direct parsing with ImportUtils.isInitValueNumber() provides more robust handling of initialization values and explicit fallback to 0 for non-numeric values.


125-135: LGTM: Consistent tool binding pattern.

The newSvgPlace() and newSvgArc() methods follow the established pattern from edit-mode (binding created elements to the active tool) and maintain consistency across canvas modes.

src/app/form-builder/field-list/field-list.component.ts (2)

98-100: LGTM: Property metadata serialization.

Serializing meta.properties as JSON enables property metadata to be transferred during drag-and-drop operations, supporting the richer component configuration.


110-117: LGTM: Consistent string coercion and property transfer.

The string coercion for rows and cols ensures consistent data transfer format, and property serialization maintains parity with the new field handler.

src/app/modeler/actions-mode/action-editor/action-editor.service.ts (1)

39-48: Good refactoring: Centralizing ID generation in ModelService.

Delegating action ID generation to ModelService.nextActionId() follows the single responsibility principle and reduces code duplication. Ensure that ModelService.nextActionId() is properly implemented and maintains ID uniqueness across the application.

#!/bin/bash
# Description: Verify ModelService.nextActionId() implementation exists and is used correctly

# Check for nextActionId implementation in ModelService
ast-grep --pattern $'class ModelService {
  $$$
  nextActionId() {
    $$$
  }
  $$$
}'

# Verify all calls to nextActionId go through ModelService
rg -n -C3 --type=ts 'nextActionId'
src/app/modeler/modeler.module.ts (1)

75-75: Remove unused FormBuilderModule import statement.

FormBuilderModule was removed from the @NgModule imports array and is no longer used. Since ModelerModule doesn't depend on FormBuilderComponent and already imports all necessary base modules (GridsterModule, FormsModule, ReactiveFormsModule, etc.), the import statement at line 23 should be removed as cleanup.

src/app/modeler/services/canvas/canvas-listener-tool.ts (1)

342-359: LGTM! Clean dialog lifecycle pattern.

The introduction of beforeDialog() and afterDialog() hooks properly manages keyboard bindings around dialog interactions. The optional afterClose callback provides flexibility while ensuring cleanup always occurs via afterDialog().

src/app/modeler/simulation-mode/tool/change-data-tool.ts (1)

38-54: LGTM! Consistent use of the new openDialog pattern.

The refactored code properly leverages the parent class's openDialog method with the callback pattern, ensuring keyboard bindings are correctly managed during dialog interaction. The null check on data before processing is appropriate.

src/app/modeler/data-mode/data-detail/data-detail.component.html (2)

160-240: LGTM! Comprehensive type-specific initial value editors.

The type-specific editors appropriately handle each data type with suitable UI controls: toggle for boolean, number input for numbers, date/datetime pickers, select for enumerations/multichoice, and a fallback text input. The delegation to nab-task-ref-init-field for TASK_REF maintains good component separation.


119-124: No changes needed—the code correctly handles both event types.

The code at line 120 already uses an instanceof check to distinguish between MatAutocompleteSelectedEvent and regular Event, accessing the appropriate property for each type: $event.option.value for autocomplete selection and $event.target.value for change events. Both event types are handled correctly.

src/app/dialogs/dialog-marking-change/dialog-marking-change.component.ts (1)

14-28: LGTM! Well-structured dialog component.

The component properly injects dialog data and the simulation service, initializes the place reference and form control with appropriate validators. The pattern aligns with similar dialog components in the codebase.

src/app/modeler/simulation-mode/tool/simulation-tool.ts (1)

58-64: LGTM - Dialog interaction handlers are well structured.

The setTimeout(..., 0) pattern for opening dialogs after pointer events is appropriate for avoiding Windows context menu issues as noted in the comment. The arc handler correctly differentiates between data references and place references.

Also applies to: 72-91

src/app/modeler/services/model/model.service.ts (3)

451-484: Comprehensive action collection implementation.

The collectActions method thoroughly traverses all action sources: case events, process events, role events, transition events (including nested dataRef events), and data set events. This ensures the sequence generator is properly initialized with existing action IDs.


525-542: Improved reference value resolution with proper type checking.

The updated getReferenceValue method correctly uses ImportUtils.isInitValueNumber to validate numeric init values and accepts an optional model parameter for flexibility. Returning 0 for non-numeric values is a safe default.


447-449: nextActionId() lacks uniqueness verification by design, not oversight.

Unlike other next*Id() methods, this approach is intentional because actions are distributed across events throughout the model rather than stored in a centralized collection. There is no getAction(id) method to enable efficient uniqueness checks like getPlace(), getTransition(), etc. The _actionIdSequence is instead pre-populated during reset with all existing actions collected from case events, process events, role events, transition events, data reference events, and the dataset, preventing collisions during normal operation.

Likely an incorrect or invalid review comment.

src/app/form-builder/field-list/field-list.service.ts (2)

6-25: Well-defined interfaces for field metadata.

The new PropertyDef, ComponentDef, and DataRefDef interfaces provide clear type definitions for the field configuration system, improving type safety across the form builder.


409-424: Type assertion for stringCollection is valid.

stringCollection is a recognized value in the Petriflow DataType specification and is a legitimate use case. The type assertion is appropriate and does not bypass type checking for invalid data.

Likely an incorrect or invalid review comment.

src/app/form-builder/edit-panel/edit-panel.component.html (2)

154-156: Good refactor using dedicated component for TaskRef initialization.

Replacing the inline TaskRef autocomplete block with the nab-task-ref-init-field component improves maintainability and reusability.


202-220: Autocomplete integration for component/property selection looks good.

The autocomplete functionality for component names and properties provides a better UX with filtered suggestions. The "Copy to DataRef" action button enables convenient property transfer between dataVariable and dataRef.

Also applies to: 242-246

src/app/form-builder/edit-panel/edit-panel.component.ts (4)

38-39: LGTM on imports.

The new imports for FieldListService types and MatAutocompleteSelectedEvent are correctly added to support the autocomplete-driven UI.


418-425: Good enhancement to support both autocomplete and direct input.

The dual handling of MatAutocompleteSelectedEvent and direct input events provides flexibility for both autocomplete selection and manual entry.


455-475: LGTM on setComponent and setDataRefComponent enhancements.

Both methods correctly handle MatAutocompleteSelectedEvent and direct input, with appropriate null checks for creating the component if it doesn't exist.


569-574: Remove unused cloneProperty method or implement error handling for missing clone() methods.

The cloneProperty method is not called anywhere in the codebase and is therefore dead code. Additionally, without access to the @netgrif/petriflow library source, the assumption that all properties on DataRef and DataVariable have a clone() method cannot be verified. Either remove this method if no longer needed, or add type guards and error handling to safely handle properties that may lack a clone() method.

src/app/modeler/data-mode/data-detail/data-detail.component.ts (3)

199-207: LGTM on dynamic-init handling.

The logic correctly initializes item.init with an empty I18nWithDynamic when undefined, and properly creates the inits array when dynamic mode is enabled.


254-277: LGTM on new value setter methods.

The setBooleanValue, setNumberValue, formatDate, and formatDateTime methods provide clean, type-specific handling for different field types.


238-243: Good dual-handling pattern for autocomplete and direct input.

The property_key case correctly distinguishes between MatAutocompleteSelectedEvent and direct input events, consistent with the pattern used in edit-panel.component.ts.

"netgrif": "https://netgrif.com",
"bpmn2pn": "https://bpmn2pn.netgrif.cloud/bpmn2pn/",
"engine": "https://demo.netgrif.com/",
"engine": "https://demo.netgrif.cloud/",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find and examine nae.json file
find . -name "nae.json" -type f

Repository: netgrif/application-builder

Length of output: 81


🏁 Script executed:

# Examine nae.json around line 108
head -120 ./nae.json | tail -30

Repository: netgrif/application-builder

Length of output: 947


🏁 Script executed:

#!/bin/bash
# Check if the new engine URL is accessible

echo "Testing new engine URL..."
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://demo.netgrif.cloud/" --max-time 10)

if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then
    echo "✓ URL is accessible (HTTP $HTTP_CODE)"
else
    echo "✗ URL returned HTTP $HTTP_CODE or is unreachable"
fi

echo ""
echo "Comparing with old URL..."
OLD_HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://demo.netgrif.com/" --max-time 10)
echo "Old URL status: HTTP $OLD_HTTP_CODE"

Repository: netgrif/application-builder

Length of output: 190


Do not merge: New engine URL is unreachable.

The engine URL has been changed from demo.netgrif.com to demo.netgrif.cloud, but the new endpoint is not accessible (HTTP 000). The old URL remains live and functional (HTTP 200). This change will break production deployments. Either revert to the original URL or ensure the new demo.netgrif.cloud endpoint is properly deployed and accessible before merging.

🤖 Prompt for AI Agents
In nae.json at line 108, the engine URL was changed to
"https://demo.netgrif.cloud/" but that endpoint is currently unreachable; revert
the value back to the original reachable URL "https://demo.netgrif.com/" OR
verify and deploy the demo.netgrif.cloud service and only then update this file.
After reverting or fixing the deployment, run a connectivity/HTTP health check
from CI or locally to confirm a 200 response before committing the change.

package.json Outdated
{
"name": "@netgrif/application-builder",
"version": "2.0.0",
"version": "2.1.0-RC.7",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Version mismatch: RC version in release PR.

The PR is titled "Release 2.1.0" targeting the master branch, but the package version is set to "2.1.0-RC.7" (release candidate). Release candidate versions should typically not be merged to master. Ensure the version is updated to "2.1.0" (without the RC suffix) before merging this release.

Apply this diff to use the final release version:

-    "version": "2.1.0-RC.7",
+    "version": "2.1.0",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"version": "2.1.0-RC.7",
"version": "2.1.0",
🤖 Prompt for AI Agents
In package.json around line 3, the version field is set to the RC value
"2.1.0-RC.7" but this PR is a final release; update the version string to
"2.1.0" (remove the "-RC.7" suffix) so the package.json reflects the final
release before merging to master, and ensure no other files or lockfiles
reference the RC tag.

Comment on lines 3 to 8
<mat-form-field fxFlex *ngFor="let data of dataSet">
<mat-label>{{data.id}}</mat-label>
<input type="number" step="1" matInput [(ngModel)]="data.value">
<input type="number" step="1" min="0" matInput [(ngModel)]="data.value" [formControl]="valueCtrl">
<mat-error *ngIf="valueCtrl.errors && valueCtrl.errors.required">Value is required</mat-error>
<mat-error *ngIf="valueCtrl.errors && valueCtrl.errors.validValue">Value can not be a negative number</mat-error>
</mat-form-field>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Shared FormControl breaks multi-field editing.

All input fields in the loop share the same valueCtrl FormControl. This means:

  • All inputs display and update the same value
  • Validation state is shared across all fields
  • Users cannot edit multiple data values independently

Each data item needs its own FormControl or the component should use template-driven forms with separate ngModel bindings without a shared FormControl.

Since the AI summary indicates valueCtrl was introduced in the TypeScript file, you'll need to refactor the component to either:

Option 1: Remove the FormControl and use template-driven validation:

-        <input type="number" step="1" min="0" matInput [(ngModel)]="data.value" [formControl]="valueCtrl">
-        <mat-error *ngIf="valueCtrl.errors && valueCtrl.errors.required">Value is required</mat-error>
-        <mat-error *ngIf="valueCtrl.errors && valueCtrl.errors.validValue">Value can not be a negative number</mat-error>
+        <input type="number" step="1" min="0" matInput [(ngModel)]="data.value" required>
+        <mat-error>Value is required and cannot be negative</mat-error>

And update the save button to check if any data.value is invalid.

Option 2: Use FormArray with individual controls for each data item (requires more changes in the TypeScript file).

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/app/dialogs/dialog-change-data/dialog-change-data.component.html around
lines 3-8, the template currently binds every input to the same FormControl
(valueCtrl) causing shared value and validation across all rows; fix by giving
each datum its own control: either remove the shared FormControl and rely on
template-driven ngModel-only inputs (remove [formControl]="valueCtrl", keep
[(ngModel)]="data.value", add required and min attributes and update the save
routine to validate that no data.value is null/negative), or implement a
reactive FormArray in the component TS that creates one FormControl per data
item and bind each input to formControlName/index accordingly (populate the
FormArray from dataSet, validate per-control, and use the FormArray.valid flag
on save).

Comment on lines +4 to +5
import {CanvasTransition} from '../../modeler/edit-mode/domain/canvas-transition';
import {CanvasNodeElement} from '../../modeler/edit-mode/domain/canvas-node-element';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if CanvasTransition and CanvasNodeElement are used in the component

# First, let's see the full component file to check usage
echo "=== Checking file: src/app/dialogs/dialog-change-data/dialog-change-data.component.ts ==="
wc -l src/app/dialogs/dialog-change-data/dialog-change-data.component.ts

echo -e "\n=== Full file content ==="
cat -n src/app/dialogs/dialog-change-data/dialog-change-data.component.ts

echo -e "\n=== Searching for CanvasTransition or CanvasNodeElement usage ==="
rg -n 'CanvasTransition|CanvasNodeElement' src/app/dialogs/dialog-change-data/dialog-change-data.component.ts

Repository: netgrif/application-builder

Length of output: 2264


Remove unused imports on lines 4-5.

CanvasTransition and CanvasNodeElement are imported but not used in the component. Delete both import statements.

🤖 Prompt for AI Agents
In src/app/dialogs/dialog-change-data/dialog-change-data.component.ts around
lines 4 to 5, the imports for CanvasTransition and CanvasNodeElement are unused;
remove those two import statements to clean up the file and ensure no unused
imports remain (also run/verify TypeScript linting to confirm no other unused
imports).

Comment on lines +37 to 45
private validValue(): ValidatorFn {
return (fc: FormControl): { [key: string]: any } | null => {
const value = Math.floor(fc.value as number);
if (value !== Infinity && value === fc.value as number && value >= 0) {
return null;
}
return ({validMultiplicity: true})
};
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider clarifying validator logic and edge cases.

The validator correctly enforces non-negative integers, but consider these edge cases:

  1. -Infinity: Line 40 checks value !== Infinity but not !isFinite(value), allowing -Infinity to potentially pass if it somehow equals itself after Math.floor.
  2. Validator naming: The error key is validMultiplicity, which suggests this is for multiplicity values. If multiplicity must be strictly positive (>= 1), adjust the condition to value >= 1.

Apply this diff for more robust validation:

 private validValue(): ValidatorFn {
     return (fc: FormControl): { [key: string]: any } | null => {
         const value = Math.floor(fc.value as number);
-        if (value !== Infinity && value === fc.value as number && value >= 0) {
+        if (isFinite(value) && value === fc.value as number && value >= 0) {
             return null;
         }
         return ({validMultiplicity: true})
     };
 }
🤖 Prompt for AI Agents
In src/app/dialogs/dialog-change-data/dialog-change-data.component.ts around
lines 37 to 45, the validator misses non-finite values (e.g., -Infinity) and may
have the wrong threshold for multiplicity; coerce the control value to a Number,
use Number.isFinite to reject infinities/NaN before flooring, compare the
floored number to the numeric original, and enforce the correct lower bound (use
value >= 1 if multiplicity must be strictly positive, otherwise keep value >=
0); if you change the bound, update or rename the error key (validMultiplicity)
to reflect the stricter requirement.

Comment on lines 91 to 97
reset() {
super.reset();
this.restart();
this.selectedElements.clear();
this.clipboardElements.clear();
this.deselectAll();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical ordering bug: Elements will remain visually active after reset.

Calling this.selectedElements.clear() on line 94 before this.deselectAll() on line 96 prevents proper visual deactivation. Here's why:

  • deselectAll() calls clearSelection(), which iterates over selectedElements.getAll() to call removeFromSelection() on each element
  • removeFromSelection() both removes the element from the collection AND calls deactivate() to reset visual styles (cursor, highlighting)
  • If selectedElements.clear() is called first, the collection is empty when deselectAll() runs
  • Result: Elements remain visually activated (highlighted, with 'move' cursor) even though they're no longer selected internally

This creates an inconsistent state where users see highlighted elements they cannot interact with as selected.

Apply this diff to fix the ordering:

 reset() {
     super.reset();
     this.restart();
-    this.selectedElements.clear();
     this.clipboardElements.clear();
     this.deselectAll();
 }

Note: The explicit selectedElements.clear() call is redundant because deselectAll()clearSelection()removeFromSelection() already clears the collection while properly deactivating elements.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reset() {
super.reset();
this.restart();
this.selectedElements.clear();
this.clipboardElements.clear();
this.deselectAll();
}
reset() {
super.reset();
this.restart();
this.clipboardElements.clear();
this.deselectAll();
}
🤖 Prompt for AI Agents
In src/app/modeler/edit-mode/services/modes/select-tool.ts around lines 91 to
97, the reset() method clears selectedElements before calling deselectAll(),
which prevents removeFromSelection() from deactivating elements and leaves them
visually active; fix by removing the explicit this.selectedElements.clear() and
calling this.deselectAll() immediately after this.restart() (so selection
removal/deactivation runs before you clear clipboardElements), e.g. keep
super.reset(); this.restart(); this.deselectAll();
this.clipboardElements.clear();.

Comment on lines +7 to +11
<input matInput [(ngModel)]="role.role.id" (change)="changeId($event)" [formControl]="roleIdForm">
<mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.required">Id is required</mat-error>
<mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.validUnique">
Transition with given id already exists
</mat-error>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix incorrect entity type in error message.

The error message on line 10 references "Transition" but should reference "Role" since this is the role detail component.

Apply this diff to correct the error message:

-            <mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.validUnique">
-                Transition with given id already exists
-            </mat-error>
+            <mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.validUnique">
+                Role with given id already exists
+            </mat-error>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<input matInput [(ngModel)]="role.role.id" (change)="changeId($event)" [formControl]="roleIdForm">
<mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.required">Id is required</mat-error>
<mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.validUnique">
Transition with given id already exists
</mat-error>
<input matInput [(ngModel)]="role.role.id" (change)="changeId($event)" [formControl]="roleIdForm">
<mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.required">Id is required</mat-error>
<mat-error *ngIf="roleIdForm.errors && roleIdForm.errors.validUnique">
Role with given id already exists
</mat-error>
🤖 Prompt for AI Agents
In src/app/modeler/role-mode/role-detail/role-detail.component.html around lines
7 to 11, the mat-error message incorrectly refers to "Transition" instead of
"Role"; update the text inside the mat-error (line 10) to read "Role with given
id already exists" so the error message correctly references the Role entity.

Comment on lines +78 to +81
changeGlobalFlag($event): void {
this.role.role.global = $event.checked;
this.shouldSave = true;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add type annotation to the event parameter.

The changeGlobalFlag method follows the correct pattern, but the $event parameter should be explicitly typed for better type safety and IDE support.

Apply this diff to add the type annotation:

-    changeGlobalFlag($event): void {
+    changeGlobalFlag($event: MatCheckboxChange): void {
         this.role.role.global = $event.checked;
         this.shouldSave = true;
     }

Also add the import at the top of the file:

import {MatCheckboxChange} from '@angular/material/checkbox';

Note: The same type annotation improvement could be applied to changeId and changeTitle methods (they should receive typed event objects), but that's outside the scope of this change.

🤖 Prompt for AI Agents
In src/app/modeler/role-mode/role-detail/role-detail.component.ts around lines
78 to 81, the changeGlobalFlag method's $event parameter lacks a type
annotation; add an explicit type MatCheckboxChange to the $event parameter and
mark the method signature accordingly, and add the import "MatCheckboxChange"
from "@angular/material/checkbox" at the top of the file so the type resolves;
keep the method body unchanged and ensure TypeScript compiles with the new
import and typed parameter.

Comment on lines +109 to +124
openDataDialog(id: string, value: number): void {
const dataSet = new Map<string, number>([[id, value]]);
this.openDialog(DialogChangeDataComponent, {
width: '50%',
panelClass: "dialog-width-50",
data: {
dataSet: dataSet
} as DataSet
}, (data: Array<Data>) => {
if (data) {
this.simulationModeService.data.set(data[0].id, data[0].value);
this.simulation.updateData(this.simulationModeService.data);
this.simulationModeService.renderModel(this.simulation.simulationModel);
}
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing bounds check before accessing data[0].

The callback checks if (data) but doesn't verify the array has elements before accessing data[0]. If the dialog returns an empty array, this will cause a runtime error.

 openDataDialog(id: string, value: number): void {
     const dataSet = new Map<string, number>([[id, value]]);
     this.openDialog(DialogChangeDataComponent, {
         width: '50%',
         panelClass: "dialog-width-50",
         data: {
             dataSet: dataSet
         } as DataSet
     }, (data: Array<Data>) => {
-        if (data) {
+        if (data && data.length > 0) {
             this.simulationModeService.data.set(data[0].id, data[0].value);
             this.simulation.updateData(this.simulationModeService.data);
             this.simulationModeService.renderModel(this.simulation.simulationModel);
         }
     });
 }
🤖 Prompt for AI Agents
In src/app/modeler/simulation-mode/tool/simulation-tool.ts around lines 109 to
124, the callback checks only that `data` is truthy but then accesses `data[0]`
without ensuring the array has elements; add a bounds check (e.g., `if (data &&
data.length > 0)`) before accessing `data[0]`, and optionally validate
`data[0].id` and `data[0].value` are defined before using them to update
simulation state and render the model.

<nab-root></nab-root>
<nab-root>

<!-- loading layout replaced by app after startupp -->
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix the typo in the comment.

The comment contains a typo: "startupp" should be "startup".

Apply this diff to fix the typo:

-    <!-- loading layout replaced by app after startupp -->
+    <!-- loading layout replaced by app after startup -->
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<!-- loading layout replaced by app after startupp -->
<!-- loading layout replaced by app after startup -->
🤖 Prompt for AI Agents
In src/index.html around line 74, the HTML comment contains a typo ("startupp");
update the comment text to read "startup" so it becomes: <!-- loading layout
replaced by app after startup -->.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review continued from previous batch...

Comment on lines +539 to +545
filteredComponents(component: PetriflowComponent): Array<ComponentDef> {
const componentDefs: DataRefDef = this._fieldListService.fieldListArray.find(type => type.type === this.dataVariable.type);
if (!componentDefs) {
return [];
}
return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(component.name));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential null reference when component.name is undefined.

The filter at line 544 calls component.name directly without a null check. If component.name is undefined, includes(undefined) will coerce it to the string "undefined" and may produce unexpected matches.

     filteredComponents(component: PetriflowComponent): Array<ComponentDef> {
         const componentDefs: DataRefDef =  this._fieldListService.fieldListArray.find(type => type.type === this.dataVariable.type);
         if (!componentDefs) {
             return [];
         }
-        return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(component.name));
+        return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(component.name?.toLowerCase() ?? ''));
     }

This also normalizes the case for consistent filtering.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
filteredComponents(component: PetriflowComponent): Array<ComponentDef> {
const componentDefs: DataRefDef = this._fieldListService.fieldListArray.find(type => type.type === this.dataVariable.type);
if (!componentDefs) {
return [];
}
return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(component.name));
}
filteredComponents(component: PetriflowComponent): Array<ComponentDef> {
const componentDefs: DataRefDef = this._fieldListService.fieldListArray.find(type => type.type === this.dataVariable.type);
if (!componentDefs) {
return [];
}
return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(component.name?.toLowerCase() ?? ''));
}
🤖 Prompt for AI Agents
In src/app/form-builder/edit-panel/edit-panel.component.ts around lines 539 to
545, the filter uses component.name directly which can be undefined and causes
includes(undefined) to behave incorrectly; update the filter to normalize both
sides and guard against undefined by deriving a safeLowerName = (component.name
|| '').toLowerCase() and only calling includes on that, and ensure def.title is
present (e.g., (def.title || '').toLowerCase().includes(safeLowerName)) so
filtering is consistent and null-safe.

Comment on lines +562 to +567
public setPropertyDefaultValue($event: MatAutocompleteSelectedEvent, index: number, component: PetriflowComponent): void {
component.properties[index].value = this._fieldListService.fieldListArray
.find(type => type.type === this.dataVariable.type)?.components
.find(compDef => (!component.name && !compDef.name) || (!!component.name && !!compDef.name && component.name === compDef.name))?.properties
.find(propDef => propDef.name === $event.option.value).defaultValue;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing null check before accessing defaultValue can cause runtime error.

The chained find() calls may return undefined, but .defaultValue is accessed unconditionally on line 566. If no matching property definition is found, this will throw a TypeError.

     public setPropertyDefaultValue($event: MatAutocompleteSelectedEvent, index: number, component: PetriflowComponent): void {
-        component.properties[index].value = this._fieldListService.fieldListArray
+        const defaultValue = this._fieldListService.fieldListArray
                                             .find(type => type.type === this.dataVariable.type)?.components
                                             .find(compDef => (!component.name && !compDef.name) || (!!component.name && !!compDef.name && component.name === compDef.name))?.properties
-                                            .find(propDef => propDef.name === $event.option.value).defaultValue;
+                                            ?.find(propDef => propDef.name === $event.option.value)?.defaultValue;
+        if (defaultValue !== undefined) {
+            component.properties[index].value = defaultValue;
+        }
     }
🤖 Prompt for AI Agents
In src/app/form-builder/edit-panel/edit-panel.component.ts around lines 562 to
567, the chained find() calls may return undefined and the code accesses
.defaultValue unconditionally which can throw; update the logic to safely handle
missing results by resolving each find into a temporary variable (or use
optional chaining) and only read .defaultValue if the property definition
exists, otherwise assign a sensible fallback (e.g., undefined or empty string)
to component.properties[index].value; ensure you don’t assume intermediate
objects exist before accessing their properties.

Comment on lines +28 to +35
import {
ComponentDef,
DataRefDef,
FieldListService,
PropertyDef
} from '../../../form-builder/field-list/field-list.service';
import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete';
import {MatChipInputEvent} from '@angular/material/chips';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for MatChipInputEvent usage in the component file and template
rg -n "MatChipInputEvent" src/app/modeler/data-mode/data-detail/ --type ts

Repository: netgrif/application-builder

Length of output: 195


🏁 Script executed:

#!/bin/bash
# Search more broadly for any use of MatChipInputEvent (method params, variable declarations, etc.)
# Also check if there's a template file that might use it
rg "MatChipInputEvent" src/app/modeler/data-mode/data-detail/ -A 2 -B 2

echo "---"
echo "Checking for template file:"
find src/app/modeler/data-mode/data-detail/ -name "*.html"

Repository: netgrif/application-builder

Length of output: 710


🏁 Script executed:

#!/bin/bash
# Check the template file for any chip-related content
cat src/app/modeler/data-mode/data-detail/data-detail.component.html | grep -i "chip\|matChip" || echo "No chip-related content found in template"

Repository: netgrif/application-builder

Length of output: 112


Remove unused import: MatChipInputEvent.

MatChipInputEvent is imported on line 35 but is not used anywhere in the component (no method parameters, variable declarations) or template. Remove this import.

🤖 Prompt for AI Agents
In src/app/modeler/data-mode/data-detail/data-detail.component.ts around lines
28 to 35, the import MatChipInputEvent is unused; remove MatChipInputEvent from
the import list (delete it from the line importing from
'@angular/material/chips') so the file only imports symbols that are actually
used, then run a quick build/TS lint to confirm no unused-import errors remain.

Comment on lines +413 to +419
get filteredComponents(): Array<ComponentDef> {
const componentDefs: DataRefDef = this._fieldListService.fieldListArray.find(type => type.type === this.item.type);
if (!componentDefs) {
return [];
}
return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(this.item.component.name));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential null reference and case-sensitivity issue in filteredComponents.

Similar to edit-panel.component.ts, line 418 uses this.item.component.name directly in includes() without null-checking or case normalization. If component.name is undefined, it will be coerced to "undefined".

     get filteredComponents(): Array<ComponentDef> {
         const componentDefs: DataRefDef =  this._fieldListService.fieldListArray.find(type => type.type === this.item.type);
         if (!componentDefs) {
             return [];
         }
-        return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(this.item.component.name));
+        return componentDefs.components.filter(def => def.name !== undefined && def.title.toLowerCase().includes(this.item.component?.name?.toLowerCase() ?? ''));
     }
🤖 Prompt for AI Agents
In src/app/modeler/data-mode/data-detail/data-detail.component.ts around lines
413 to 419, the getter uses this.item.component.name directly in includes()
which can be undefined and is not case-normalized; update the code to (1) guard
against a missing component/name by using safe access or a default empty string
(e.g., const query = (this.item?.component?.name || '').toLowerCase()), and (2)
compare using lowercased strings (e.g.,
def.title?.toLowerCase().includes(query)), ensuring you also null-check
def.title before calling toLowerCase so no null reference errors occur.

Comment on lines +436 to +441
public setPropertyDefaultValue($event: MatAutocompleteSelectedEvent, index: number, dataVariable: DataVariable): void {
dataVariable.component.properties[index].value = this._fieldListService.fieldListArray
.find(type => type.type === dataVariable.type)?.components
.find(compDef => (!dataVariable.component.name && !compDef.name) || (!!dataVariable.component.name && !!compDef.name && dataVariable.component.name === compDef.name))?.properties
.find(propDef => propDef.name === $event.option.value).defaultValue;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing null check before accessing defaultValue can cause runtime error.

Same issue as in edit-panel.component.ts: the chained find() on line 440 may return undefined, causing a TypeError when accessing .defaultValue.

     public setPropertyDefaultValue($event: MatAutocompleteSelectedEvent, index: number, dataVariable: DataVariable): void {
-        dataVariable.component.properties[index].value = this._fieldListService.fieldListArray
+        const defaultValue = this._fieldListService.fieldListArray
             .find(type => type.type === dataVariable.type)?.components
             .find(compDef => (!dataVariable.component.name && !compDef.name) || (!!dataVariable.component.name && !!compDef.name && dataVariable.component.name === compDef.name))?.properties
-            .find(propDef => propDef.name === $event.option.value).defaultValue;
+            ?.find(propDef => propDef.name === $event.option.value)?.defaultValue;
+        if (defaultValue !== undefined) {
+            dataVariable.component.properties[index].value = defaultValue;
+        }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public setPropertyDefaultValue($event: MatAutocompleteSelectedEvent, index: number, dataVariable: DataVariable): void {
dataVariable.component.properties[index].value = this._fieldListService.fieldListArray
.find(type => type.type === dataVariable.type)?.components
.find(compDef => (!dataVariable.component.name && !compDef.name) || (!!dataVariable.component.name && !!compDef.name && dataVariable.component.name === compDef.name))?.properties
.find(propDef => propDef.name === $event.option.value).defaultValue;
}
public setPropertyDefaultValue($event: MatAutocompleteSelectedEvent, index: number, dataVariable: DataVariable): void {
const defaultValue = this._fieldListService.fieldListArray
.find(type => type.type === dataVariable.type)?.components
.find(compDef => (!dataVariable.component.name && !compDef.name) || (!!dataVariable.component.name && !!compDef.name && dataVariable.component.name === compDef.name))?.properties
?.find(propDef => propDef.name === $event.option.value)?.defaultValue;
if (defaultValue !== undefined) {
dataVariable.component.properties[index].value = defaultValue;
}
}
🤖 Prompt for AI Agents
In src/app/modeler/data-mode/data-detail/data-detail.component.ts around lines
436 to 441, the chained find() calls may return undefined and the code accesses
.defaultValue without checking, causing a runtime TypeError; fix by resolving
each step into guarded intermediate variables (typeDef, compDef, propDef) or use
safe optional checks so you only read .defaultValue when propDef is non-null,
and assign a sensible fallback (e.g., null or empty string) if any lookup fails.

Kovy95 and others added 2 commits December 17, 2025 10:58
[NAB-389] Cannot change the number of columns in form editor
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
src/app/form-builder/gridster/gridster.service.ts (3)

244-244: JSON.parse may throw on empty or invalid string.

event.dataTransfer.getData('properties') can return an empty string, and JSON.parse('') throws a SyntaxError. This was previously flagged but remains unaddressed.

Wrap the parse in a try-catch or validate the string first:

-        const properties: Array<PropertyDef> = JSON.parse(event.dataTransfer.getData('properties'));
+        let properties: Array<PropertyDef> = null;
+        try {
+            const propertiesData = event.dataTransfer.getData('properties');
+            if (propertiesData) {
+                properties = JSON.parse(propertiesData);
+            }
+        } catch (e) {
+            // Invalid properties data, skip
+        }

244-249: Potential null reference when accessing newDataRef.component.properties.

If ref_component from drag data is empty/falsy, addDataRef (lines 220-222) won't create a Component, leaving newDataRef.component as undefined. However, line 247 unconditionally accesses newDataRef.component.properties, which will throw a TypeError. This was previously flagged but remains unaddressed.

Add a null check or ensure component exists before pushing properties:

         const properties: Array<PropertyDef> = JSON.parse(event.dataTransfer.getData('properties'));
-        if (!!properties) {
+        if (properties && newDataRef.component) {
             for (const property of properties) {
                 newDataRef.component.properties.push(new Property(property.name, property.defaultValue));
             }
         }

Alternatively, ensure a component is always created in addDataRef when properties will be added, or initialize one in addNewDataRef if missing:

if (!newDataRef.component) {
    newDataRef.component = new Component('');
    newDataRef.component.properties = [];
}

245-245: Redundant double negation !!properties.

The !! is unnecessary here; if (properties) achieves the same result.

-        if (!!properties) {
+        if (properties) {
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 636a552 and 5b1962f.

📒 Files selected for processing (2)
  • src/app/form-builder/form-builder.component.ts (2 hunks)
  • src/app/form-builder/gridster/gridster.service.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/app/form-builder/form-builder.component.ts (2)
src/app/modeler/services/canvas/canvas-listener-tool.ts (2)
  • router (424-426)
  • transitionService (428-430)
src/app/modeler/modeler-config.ts (1)
  • ModelerConfig (3-40)
src/app/form-builder/gridster/gridster.service.ts (1)
src/app/form-builder/field-list/field-list.service.ts (1)
  • PropertyDef (6-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and test
🔇 Additional comments (4)
src/app/form-builder/gridster/gridster.service.ts (2)

21-21: LGTM: Import additions support property handling.

The new imports for Property and PropertyDef are necessary for the enhanced property-handling logic in addNewDataRef.

Also applies to: 29-29


199-199: LGTM: Return type change improves composability.

Changing addDataRef to return DataRef allows the caller to capture and further process the created reference, which is leveraged in addNewDataRef.

Also applies to: 234-234

src/app/form-builder/form-builder.component.ts (2)

5-7: LGTM! Import statements are correctly added.

The new imports support the default data group initialization logic and are consistent with the codebase patterns shown in the relevant code snippets.


18-18: Constructor signature updated correctly.

The injection of SelectedTransitionService follows standard Angular patterns. However, note that the constructor now contains initialization logic that mutates the model (see next comment).

Comment on lines +22 to +27
if (this.modelService.model.getTransition(this.transitionService.id)?.dataGroups?.length === 0) {
const dataGroup = new DataGroup(`${this.transitionService.id}_0`);
dataGroup.layout = LayoutType.GRID;
dataGroup.cols = ModelerConfig.LAYOUT_DEFAULT_COLS;
this.modelService.model.getTransition(this.transitionService.id).dataGroups.push(dataGroup);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Null-pointer risk and constructor side effects.

This code has several issues:

  1. Null-pointer exception risk (Line 26): The second call to getTransition doesn't use optional chaining (?.), which will throw if it returns null or undefined. While Line 22 uses ?., Line 26 directly accesses .dataGroups.push(...) without null safety.

  2. Inconsistent null handling: The condition ?.length === 0 only triggers for an empty array, not for null or undefined dataGroups. If dataGroups is null/undefined, the condition evaluates to false, but then Line 26 would still fail when trying to push.

  3. Duplicate calls: this.modelService.model.getTransition(this.transitionService.id) is called twice—once with optional chaining and once without. This is inefficient and error-prone.

  4. Constructor side effects: Constructors should be lightweight and avoid model mutations. This initialization logic should be moved to ngOnInit lifecycle hook.

Apply this diff to fix the null safety issues, eliminate duplicate calls, and move logic to ngOnInit:

-export class FormBuilderComponent implements AfterViewInit {
+export class FormBuilderComponent implements OnInit, AfterViewInit {
     title = 'form-builder';
     width: number;
 
     constructor(private router: Router, private modelService: ModelService, private transitionService: SelectedTransitionService) {
         if (!this.modelService.model) {
             this.router.navigate(['/modeler']);
         }
-        if (this.modelService.model.getTransition(this.transitionService.id)?.dataGroups?.length === 0) {
-            const dataGroup = new DataGroup(`${this.transitionService.id}_0`);
-            dataGroup.layout = LayoutType.GRID;
-            dataGroup.cols = ModelerConfig.LAYOUT_DEFAULT_COLS;
-            this.modelService.model.getTransition(this.transitionService.id).dataGroups.push(dataGroup);
-        }
     }
 
+    ngOnInit(): void {
+        const transition = this.modelService.model?.getTransition(this.transitionService.id);
+        if (transition && (!transition.dataGroups || transition.dataGroups.length === 0)) {
+            const dataGroup = new DataGroup(`${this.transitionService.id}_0`);
+            dataGroup.layout = LayoutType.GRID;
+            dataGroup.cols = ModelerConfig.LAYOUT_DEFAULT_COLS;
+            if (!transition.dataGroups) {
+                transition.dataGroups = [];
+            }
+            transition.dataGroups.push(dataGroup);
+        }
+    }
+
     ngAfterViewInit(): void {

Additionally, update the class declaration on Line 1 to include OnInit:

-import {AfterViewInit, Component, OnDestroy, OnInit} from '@angular/core';
+import {AfterViewInit, Component, OnInit} from '@angular/core';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (this.modelService.model.getTransition(this.transitionService.id)?.dataGroups?.length === 0) {
const dataGroup = new DataGroup(`${this.transitionService.id}_0`);
dataGroup.layout = LayoutType.GRID;
dataGroup.cols = ModelerConfig.LAYOUT_DEFAULT_COLS;
this.modelService.model.getTransition(this.transitionService.id).dataGroups.push(dataGroup);
}
export class FormBuilderComponent implements OnInit, AfterViewInit {
title = 'form-builder';
width: number;
constructor(private router: Router, private modelService: ModelService, private transitionService: SelectedTransitionService) {
if (!this.modelService.model) {
this.router.navigate(['/modeler']);
}
}
ngOnInit(): void {
const transition = this.modelService.model?.getTransition(this.transitionService.id);
if (transition && (!transition.dataGroups || transition.dataGroups.length === 0)) {
const dataGroup = new DataGroup(`${this.transitionService.id}_0`);
dataGroup.layout = LayoutType.GRID;
dataGroup.cols = ModelerConfig.LAYOUT_DEFAULT_COLS;
if (!transition.dataGroups) {
transition.dataGroups = [];
}
transition.dataGroups.push(dataGroup);
}
}
ngAfterViewInit(): void {
// ... existing code ...
}
}

newDataRef.component.properties.push(new Property(property.name, property.defaultValue));
}
}
this.options.api.optionsChanged();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider optional chaining for defensive coding.

While this.options.api should be available when this method is called (since it's only invoked after gridster initialization), using optional chaining would be more defensive and consistent with line 113.

-        this.options.api.optionsChanged();
+        this.options.api?.optionsChanged();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this.options.api.optionsChanged();
this.options.api?.optionsChanged();
🤖 Prompt for AI Agents
In src/app/form-builder/gridster/gridster.service.ts around line 250, the direct
call this.options.api.optionsChanged() is fragile; update it to use optional
chaining on the api reference (this.options.api?.optionsChanged()) to guard
against undefined API objects, matching the defensive pattern used at line 113
and avoiding runtime errors if the method is invoked before full initialization.

@tuplle tuplle requested a review from machacjozef December 17, 2025 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants