This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 2cb63ad525 fix: Properly handle optional static properties (#4212)
2cb63ad525 is described below

commit 2cb63ad525e4254186e1b3deea7f62f00abcfd1c
Author: Dominik Riemer <[email protected]>
AuthorDate: Mon Mar 2 10:53:11 2026 +0100

    fix: Properly handle optional static properties (#4212)
---
 .../base/abstract-validated-static-property.ts     |  1 +
 .../static-color-picker.component.ts               | 35 +++++++++++++++++-----
 .../static-file-input.component.ts                 |  4 ++-
 .../static-free-input.component.ts                 |  7 +++--
 .../static-mapping-unary.component.ts              | 32 +++++++++++++++++---
 .../static-property-util.service.ts                |  1 +
 .../static-property.component.html                 |  1 +
 .../static-runtime-resolvable-group.component.html | 15 ----------
 .../static-secret-input.component.html             |  2 +-
 .../static-secret-input.component.ts               | 31 ++++++++++++++-----
 .../static-slide-toggle.component.ts               |  4 +--
 11 files changed, 92 insertions(+), 41 deletions(-)

diff --git 
a/ui/src/app/core-ui/static-properties/base/abstract-validated-static-property.ts
 
b/ui/src/app/core-ui/static-properties/base/abstract-validated-static-property.ts
index d26d033746..898ab74350 100644
--- 
a/ui/src/app/core-ui/static-properties/base/abstract-validated-static-property.ts
+++ 
b/ui/src/app/core-ui/static-properties/base/abstract-validated-static-property.ts
@@ -38,6 +38,7 @@ export abstract class AbstractValidatedStaticPropertyRenderer<
     }
 
     enableValidators() {
+        this.fieldValid = this.parentForm.controls[this.fieldName].valid;
         this.parentForm.controls[this.fieldName].valueChanges.subscribe(
             value => {
                 this.onValueChange(value);
diff --git 
a/ui/src/app/core-ui/static-properties/static-color-picker/static-color-picker.component.ts
 
b/ui/src/app/core-ui/static-properties/static-color-picker/static-color-picker.component.ts
index c21ca8bcba..3b46e52881 100644
--- 
a/ui/src/app/core-ui/static-properties/static-color-picker/static-color-picker.component.ts
+++ 
b/ui/src/app/core-ui/static-properties/static-color-picker/static-color-picker.component.ts
@@ -18,7 +18,12 @@
 
 import { Component, OnInit } from '@angular/core';
 import { StaticPropertyUtilService } from '../static-property-util.service';
-import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
+import {
+    FormsModule,
+    ReactiveFormsModule,
+    ValidatorFn,
+    Validators,
+} from '@angular/forms';
 import { ColorPickerStaticProperty } from '@streampipes/platform-services';
 import { AbstractValidatedStaticPropertyRenderer } from 
'../base/abstract-validated-static-property';
 import { FlexDirective, LayoutDirective } from '@ngbracket/ngx-layout/flex';
@@ -59,23 +64,37 @@ export class StaticColorPickerComponent
     ngOnInit() {
         this.addValidator(
             this.staticProperty.selectedColor,
-            Validators.required,
+            this.collectValidators(),
         );
         this.enableValidators();
+        this.checkCompleted();
+    }
+
+    private collectValidators(): ValidatorFn[] {
+        const validators: ValidatorFn[] = [];
+        if (!this.staticProperty.optional) {
+            validators.push(Validators.required);
+        }
+
+        return validators;
     }
 
     checkCompleted() {
         this.applyCompletedConfiguration(
-            this.staticPropertyUtil.asColorPickerStaticProperty(
-                this.staticProperty,
-            ).selectedColor &&
-                this.staticPropertyUtil.asColorPickerStaticProperty(
+            this.staticProperty.optional ||
+                (this.staticPropertyUtil.asColorPickerStaticProperty(
                     this.staticProperty,
-                ).selectedColor !== '',
+                ).selectedColor &&
+                    this.staticPropertyUtil.asColorPickerStaticProperty(
+                        this.staticProperty,
+                    ).selectedColor !== ''),
         );
     }
 
     onStatusChange(status: any) {}
 
-    onValueChange(value: any) {}
+    onValueChange(value: any) {
+        this.staticProperty.selectedColor = value;
+        this.checkCompleted();
+    }
 }
diff --git 
a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
 
b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
index 90c60615ad..86f8754f69 100644
--- 
a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
+++ 
b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
@@ -126,7 +126,9 @@ export class StaticFileInputComponent
 
     collectValidators() {
         const validators: ValidatorFn[] = [];
-        validators.push(Validators.required);
+        if (!this.staticProperty.optional) {
+            validators.push(Validators.required);
+        }
 
         return validators;
     }
diff --git 
a/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
 
b/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
index 5748c6b942..97d02656fb 100644
--- 
a/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
+++ 
b/ui/src/app/core-ui/static-properties/static-free-input/static-free-input.component.ts
@@ -128,9 +128,10 @@ export class StaticFreeInputComponent
 
     emitUpdate() {
         const valid =
-            this.staticProperty.value !== undefined &&
-            this.staticProperty.value !== '' &&
-            this.staticProperty.value !== null;
+            this.staticProperty.optional ||
+            (this.staticProperty.value !== undefined &&
+                this.staticProperty.value !== '' &&
+                this.staticProperty.value !== null);
         this.applyCompletedConfiguration(valid);
     }
 
diff --git 
a/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts
 
b/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts
index 5b7e8fe923..8e325377a1 100644
--- 
a/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts
+++ 
b/ui/src/app/core-ui/static-properties/static-mapping-unary/static-mapping-unary.component.ts
@@ -17,7 +17,12 @@
  */
 
 import { Component, OnInit } from '@angular/core';
-import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
+import {
+    FormsModule,
+    ReactiveFormsModule,
+    ValidatorFn,
+    Validators,
+} from '@angular/forms';
 import { StaticMappingComponent } from '../static-mapping/static-mapping';
 import { MappingPropertyUnary } from '@streampipes/platform-services';
 import { FlexDirective, LayoutDirective } from '@ngbracket/ngx-layout/flex';
@@ -50,22 +55,41 @@ export class StaticMappingUnaryComponent
 
     ngOnInit() {
         this.extractPossibleSelections();
-        if (!this.staticProperty.selectedProperty) {
+        if (
+            !this.staticProperty.selectedProperty &&
+            !this.staticProperty.optional
+        ) {
             this.staticProperty.selectedProperty =
                 this.availableProperties[0].propertySelector;
             this.applyCompletedConfiguration(true);
         }
         this.addValidator(
             this.staticProperty.selectedProperty,
-            Validators.required,
+            this.collectValidators(),
         );
         this.enableValidators();
+        this.applyCompletedConfiguration(
+            this.staticProperty.optional ||
+                !!this.staticProperty.selectedProperty,
+        );
+    }
+
+    private collectValidators(): ValidatorFn[] {
+        const validators: ValidatorFn[] = [];
+        if (!this.staticProperty.optional) {
+            validators.push(Validators.required);
+        }
+
+        return validators;
     }
 
     onStatusChange(status: any) {}
 
     onValueChange(value: any) {
         this.staticProperty.selectedProperty = value;
-        this.applyCompletedConfiguration(true);
+        this.applyCompletedConfiguration(
+            this.staticProperty.optional ||
+                !!this.staticProperty.selectedProperty,
+        );
     }
 }
diff --git 
a/ui/src/app/core-ui/static-properties/static-property-util.service.ts 
b/ui/src/app/core-ui/static-properties/static-property-util.service.ts
index f1e6989f87..314d20d915 100644
--- a/ui/src/app/core-ui/static-properties/static-property-util.service.ts
+++ b/ui/src/app/core-ui/static-properties/static-property-util.service.ts
@@ -191,6 +191,7 @@ export class StaticPropertyUtilService {
         dst.label = src.label;
         dst.description = src.description;
         dst.internalName = src.internalName;
+        dst.optional = src.optional;
         return dst;
     }
 
diff --git 
a/ui/src/app/core-ui/static-properties/static-property.component.html 
b/ui/src/app/core-ui/static-properties/static-property.component.html
index b071831fd9..0ebed3e66b 100644
--- a/ui/src/app/core-ui/static-properties/static-property.component.html
+++ b/ui/src/app/core-ui/static-properties/static-property.component.html
@@ -241,6 +241,7 @@
                     [eventSchemas]="eventSchemas"
                     [parentForm]="parentForm"
                     [fieldName]="fieldName"
+                    [pipelineElement]="pipelineElement"
                     [staticProperties]="staticProperties"
                     [renderStaticProperty]="groupStaticPropertyTpl"
                     [staticProperty]="staticProperty"
diff --git 
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-group/static-runtime-resolvable-group.component.html
 
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-group/static-runtime-resolvable-group.component.html
index 11069a4bb1..aeb36061e0 100644
--- 
a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-group/static-runtime-resolvable-group.component.html
+++ 
b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-group/static-runtime-resolvable-group.component.html
@@ -47,21 +47,6 @@
                 [ngTemplateOutlet]="renderStaticProperty"
                 [ngTemplateOutletContext]="ctxFor(property, i)"
             />
-            <!--                <sp-app-static-property-->
-            <!--                    [adapterId]="adapterId"-->
-            <!--                    [parentForm]="parentForm"-->
-            <!--                    [staticProperties]="staticProperties"-->
-            <!--                    [fieldName]="-->
-            <!--                        fieldName + '-' + 
property.internalName + '-' + i-->
-            <!--                    "-->
-            <!--                    [showBorder]="false"-->
-            <!--                    [eventSchemas]="eventSchemas"-->
-            <!--                    [staticProperty]="property"-->
-            <!--                    
[displayRecommended]="displayRecommended"-->
-            <!--                    
(updateEmitter)="handleConfigurationUpdate($event)"-->
-            <!--                    class="test fullWidth"-->
-            <!--                >-->
-            <!--                </sp-app-static-property>-->
         }
     </div>
 </div>
diff --git 
a/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html
 
b/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html
index 1e7a0430d0..03a3fc3c50 100644
--- 
a/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html
+++ 
b/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.html
@@ -25,7 +25,7 @@
                 formControlName="{{ fieldName }}"
                 matInput
                 [placeholder]="staticProperty.label"
-                required
+                [required]="!staticProperty.optional"
                 [attr.data-cy]="fieldName"
                 (blur)="emitUpdate()"
             />
diff --git 
a/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.ts
 
b/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.ts
index bc9251ff62..68d442ba98 100644
--- 
a/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.ts
+++ 
b/ui/src/app/core-ui/static-properties/static-secret-input/static-secret-input.component.ts
@@ -17,7 +17,12 @@
  */
 
 import { Component, OnInit } from '@angular/core';
-import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
+import {
+    FormsModule,
+    ReactiveFormsModule,
+    ValidatorFn,
+    Validators,
+} from '@angular/forms';
 import { StaticPropertyUtilService } from '../static-property-util.service';
 import { SecretStaticProperty } from '@streampipes/platform-services';
 import { AbstractValidatedStaticPropertyRenderer } from 
'../base/abstract-validated-static-property';
@@ -48,18 +53,29 @@ export class StaticSecretInputComponent
     }
 
     ngOnInit() {
-        this.addValidator(this.staticProperty.value, Validators.required);
+        this.addValidator(this.staticProperty.value, this.collectValidators());
         this.enableValidators();
+        this.emitUpdate();
+    }
+
+    private collectValidators(): ValidatorFn[] {
+        const validators: ValidatorFn[] = [];
+        if (!this.staticProperty.optional) {
+            validators.push(Validators.required);
+        }
+
+        return validators;
     }
 
     emitUpdate() {
         this.applyCompletedConfiguration(
-            this.staticPropertyUtil.asFreeTextStaticProperty(
-                this.staticProperty,
-            ).value &&
-                this.staticPropertyUtil.asFreeTextStaticProperty(
+            this.staticProperty.optional ||
+                (this.staticPropertyUtil.asFreeTextStaticProperty(
                     this.staticProperty,
-                ).value !== '',
+                ).value &&
+                    this.staticPropertyUtil.asFreeTextStaticProperty(
+                        this.staticProperty,
+                    ).value !== ''),
         );
     }
 
@@ -68,5 +84,6 @@ export class StaticSecretInputComponent
     onValueChange(value: any) {
         this.staticProperty.value = value;
         this.staticProperty.encrypted = false;
+        this.emitUpdate();
     }
 }
diff --git 
a/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts
 
b/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts
index a52e5294bb..dfc2220921 100644
--- 
a/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts
+++ 
b/ui/src/app/core-ui/static-properties/static-slide-toggle/static-slide-toggle.component.ts
@@ -19,7 +19,7 @@
 import { Component, OnInit } from '@angular/core';
 import { SlideToggleStaticProperty } from '@streampipes/platform-services';
 import { AbstractValidatedStaticPropertyRenderer } from 
'../base/abstract-validated-static-property';
-import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { FlexDirective, LayoutDirective } from '@ngbracket/ngx-layout/flex';
 import { MatSlideToggle } from '@angular/material/slide-toggle';
 
@@ -39,7 +39,7 @@ export class StaticSlideToggleComponent
     implements OnInit
 {
     ngOnInit(): void {
-        this.addValidator(this.staticProperty.selected, Validators.required);
+        this.addValidator(this.staticProperty.selected, []);
         this.enableValidators();
         this.emitUpdate();
     }

Reply via email to