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

SvenO3 pushed a commit to branch 
4466-add-validation-and-naming-warnings-for-property-field-names-in-adapter-schema-configuration
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to 
refs/heads/4466-add-validation-and-naming-warnings-for-property-field-names-in-adapter-schema-configuration
 by this push:
     new d9380d3848 Add errors and warnings for invalid field names
d9380d3848 is described below

commit d9380d384864f3332c23e39dbb512158d1758752
Author: Sven Oehler <[email protected]>
AuthorDate: Thu Jun 25 17:59:55 2026 +0200

    Add errors and warnings for invalid field names
---
 .../configure-schema.component.html                | 46 ++++++++++++
 .../configure-schema/configure-schema.component.ts | 22 +++++-
 .../configure-schema/field-name-validation.ts      | 87 ++++++++++++++++++++++
 3 files changed, 154 insertions(+), 1 deletion(-)

diff --git 
a/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.html
 
b/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.html
index 3b3be24a73..a5ac876f60 100644
--- 
a/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.html
+++ 
b/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.html
@@ -16,6 +16,52 @@
 ~
 -->
 <div fxFlex="100" fxLayout="column">
+    @if (invalidFieldNames().length > 0) {
+        <sp-alert-banner
+            type="error"
+            [title]="'Invalid field names' | translate"
+            [description]="
+                'Field names containing comma (,), double quote (&quot;), or 
semicolon (;) are invalid and must be renamed before continuing.'
+                    | translate
+            "
+            data-cy="configure-schema-invalid-field-names"
+        >
+            <div class="mt-md">
+                @for (fieldName of invalidFieldNames(); track fieldName) {
+                    <div
+                        class="font-bold text-sm"
+                        data-cy="configure-schema-invalid-field-name"
+                    >
+                        {{ fieldName }}
+                    </div>
+                }
+            </div>
+        </sp-alert-banner>
+    }
+
+    @if (warningFieldNames().length > 0) {
+        <sp-alert-banner
+            type="warning"
+            [title]="'Field name recommendation' | translate"
+            [description]="
+                'It is recommended to use a consistent naming convention for 
field names without special characters, except - and _.'
+                    | translate
+            "
+            data-cy="configure-schema-warning-field-names"
+        >
+            <div class="mt-md">
+                @for (fieldName of warningFieldNames(); track fieldName) {
+                    <div
+                        class="font-bold text-sm"
+                        data-cy="configure-schema-warning-field-name"
+                    >
+                        {{ fieldName }}
+                    </div>
+                }
+            </div>
+        </sp-alert-banner>
+    }
+
     <div fxFlex="100" fxLayout="column">
         <sp-adapter-script-editor
             [scriptActive]="scriptActive()"
diff --git 
a/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.ts
 
b/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.ts
index afc0eb52c3..c663040b38 100644
--- 
a/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.ts
+++ 
b/ui/src/app/connect/components/adapter-configuration/configure-schema/configure-schema.component.ts
@@ -38,6 +38,7 @@ import {
     ConfirmDialogComponent,
     DialogService,
     PanelType,
+    SpAlertBannerComponent,
 } from '@streampipes/shared-ui';
 import { CreateAdapterTransformationTemplateDialogComponent } from 
'../../../dialog/create-adapter-transformation-template-dialog/create-adapter-transformation-template-dialog.component';
 import { TranslatePipe, TranslateService } from '@ngx-translate/core';
@@ -57,6 +58,7 @@ import { AdapterSamplePreviewComponent } from 
'./sample-preview/adapter-sample-p
 import { AdapterResultPreviewComponent } from 
'./result-preview/adapter-result-preview.component';
 import { MatButton } from '@angular/material/button';
 import type { editor as MonacoEditor } from 'monaco-editor';
+import { validateFieldNames } from './field-name-validation';
 
 @Component({
     selector: 'sp-configure-schema',
@@ -72,6 +74,7 @@ import type { editor as MonacoEditor } from 'monaco-editor';
         LayoutAlignDirective,
         MatButton,
         TranslatePipe,
+        SpAlertBannerComponent,
     ],
 })
 export class ConfigureSchemaComponent implements OnInit {
@@ -147,6 +150,22 @@ export class ConfigureSchemaComponent implements OnInit {
                 ?.outputs?.[0] || {},
     );
 
+    schemaEvent = computed(() =>
+        this.scriptActive() ? this.output() : this.input(),
+    );
+
+    fieldNameValidation = computed(() =>
+        validateFieldNames(this.schemaEvent()),
+    );
+
+    invalidFieldNames = computed(
+        () => this.fieldNameValidation().invalidFieldNames,
+    );
+
+    warningFieldNames = computed(
+        () => this.fieldNameValidation().warningFieldNames,
+    );
+
     isNextDisabled = computed(() => {
         const state = this.stateService.state();
         const hasInputEvents =
@@ -158,7 +177,8 @@ export class ConfigureSchemaComponent implements OnInit {
             state.isRunningScript ||
             !!state.sampleError ||
             !!state.scriptError ||
-            !hasInputEvents
+            !hasInputEvents ||
+            this.invalidFieldNames().length > 0
         );
     });
 
diff --git 
a/ui/src/app/connect/components/adapter-configuration/configure-schema/field-name-validation.ts
 
b/ui/src/app/connect/components/adapter-configuration/configure-schema/field-name-validation.ts
new file mode 100644
index 0000000000..af4d86b73f
--- /dev/null
+++ 
b/ui/src/app/connect/components/adapter-configuration/configure-schema/field-name-validation.ts
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+export interface FieldNameValidationResult {
+    invalidFieldNames: string[];
+    warningFieldNames: string[];
+}
+
+const INVALID_FIELD_NAME_CHARACTERS_REGEX = /[,";]/;
+const RECOMMENDED_FIELD_NAME_REGEX = /^[A-Za-z0-9_-]+$/;
+
+export function validateFieldNames(event: unknown): FieldNameValidationResult {
+    const invalidFieldNames = new Set<string>();
+    const warningFieldNames = new Set<string>();
+
+    validateFieldNamesRecursively(
+        event,
+        '',
+        invalidFieldNames,
+        warningFieldNames,
+    );
+
+    return {
+        invalidFieldNames: Array.from(invalidFieldNames),
+        warningFieldNames: Array.from(warningFieldNames),
+    };
+}
+
+function validateFieldNamesRecursively(
+    value: unknown,
+    currentPath: string,
+    invalidFieldNames: Set<string>,
+    warningFieldNames: Set<string>,
+): void {
+    if (Array.isArray(value)) {
+        value.forEach(item =>
+            validateFieldNamesRecursively(
+                item,
+                currentPath ? `${currentPath}[]` : '[]',
+                invalidFieldNames,
+                warningFieldNames,
+            ),
+        );
+    } else if (isRecord(value)) {
+        Object.entries(value).forEach(([fieldName, fieldValue]) => {
+            const fieldPath = currentPath
+                ? `${currentPath}.${fieldName}`
+                : fieldName;
+
+            if (INVALID_FIELD_NAME_CHARACTERS_REGEX.test(fieldName)) {
+                invalidFieldNames.add(fieldPath);
+            } else if (!RECOMMENDED_FIELD_NAME_REGEX.test(fieldName)) {
+                warningFieldNames.add(fieldPath);
+            }
+
+            validateFieldNamesRecursively(
+                fieldValue,
+                fieldPath,
+                invalidFieldNames,
+                warningFieldNames,
+            );
+        });
+    }
+}
+
+function isRecord(value: unknown): value is Record<string, unknown> {
+    return (
+        value !== null &&
+        typeof value === 'object' &&
+        Object.prototype.toString.call(value) === '[object Object]'
+    );
+}

Reply via email to