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

marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git

commit 19e66247b244e6e717a30c2ba8eacd8f0c6efd93
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Tue Nov 26 20:18:15 2024 -0500

    Sensitive fields validator
---
 .../webui/src/designer/property/DslProperties.css  |  9 +++++
 .../webui/src/designer/property/DslProperties.tsx  | 41 ++++++++++++++++------
 .../src/designer/property/PropertiesHeader.tsx     |  2 +-
 .../webui/src/designer/property/PropertyStore.ts   |  6 ++++
 .../property/property/ComponentPropertyField.tsx   | 26 +++++++++++---
 .../property/property/DslPropertyField.tsx         | 38 ++++++++++++++++++--
 .../property/property/KameletPropertyField.tsx     | 37 ++++++++++++++-----
 .../src/designer/property/DslProperties.css        |  9 +++++
 .../src/designer/property/DslProperties.tsx        | 41 ++++++++++++++++------
 .../src/designer/property/PropertiesHeader.tsx     |  2 +-
 .../src/designer/property/PropertyStore.ts         |  6 ++++
 .../property/property/ComponentPropertyField.tsx   | 26 +++++++++++---
 .../property/property/DslPropertyField.tsx         | 38 ++++++++++++++++++--
 .../property/property/KameletPropertyField.tsx     | 37 ++++++++++++++-----
 .../src/designer/property/DslProperties.css        |  9 +++++
 .../src/designer/property/DslProperties.tsx        | 41 ++++++++++++++++------
 .../src/designer/property/PropertiesHeader.tsx     |  2 +-
 .../src/designer/property/PropertyStore.ts         |  6 ++++
 .../property/property/ComponentPropertyField.tsx   | 26 +++++++++++---
 .../property/property/DslPropertyField.tsx         | 38 ++++++++++++++++++--
 .../property/property/KameletPropertyField.tsx     | 37 ++++++++++++++-----
 21 files changed, 402 insertions(+), 75 deletions(-)

diff --git a/karavan-app/src/main/webui/src/designer/property/DslProperties.css 
b/karavan-app/src/main/webui/src/designer/property/DslProperties.css
index e2401cf3..6e867105 100644
--- a/karavan-app/src/main/webui/src/designer/property/DslProperties.css
+++ b/karavan-app/src/main/webui/src/designer/property/DslProperties.css
@@ -276,3 +276,12 @@
     background-color: yellow;
 }
 
+.karavan .properties .value-sensitive-invalid {
+    background-color: red;
+}
+
+.karavan .properties .property-selector .pf-v5-c-toggle-group__button {
+    padding-left: 6px;
+    padding-right: 6px;
+}
+
diff --git a/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx 
b/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx
index 9511b1f8..dd2376ee 100644
--- a/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx
+++ b/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx
@@ -14,15 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, {useState} from 'react';
+import React, {useEffect, useState} from 'react';
 import {
+    Button,
+    ExpandableSection,
     Form,
     Text,
-    Title,
+    TextInputGroup,
+    TextInputGroupMain,
+    TextInputGroupUtilities,
     TextVariants,
-    ExpandableSection,
-    Button,
-    Tooltip, ToggleGroupItem, ToggleGroup, TextInputGroup, TextInputGroupMain, 
TextInputGroupUtilities,
+    Title,
+    ToggleGroup,
+    ToggleGroupItem,
+    Tooltip,
 } from '@patternfly/react-core';
 import '../karavan.css';
 import './DslProperties.css';
@@ -63,11 +68,18 @@ export function DslProperties(props: Props) {
     const [selectedStep, dark]
         = useDesignerStore((s) => [s.selectedStep, s.dark], shallow)
 
-    const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, 
setPropertyFilter, setRequiredOnly]
-        = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, 
s.requiredOnly, s.setChangedOnly, s.setPropertyFilter, s.setRequiredOnly], 
shallow)
+    const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, 
sensitiveOnly, setSensitiveOnly, setPropertyFilter, setRequiredOnly]
+        = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, 
s.requiredOnly, s.setChangedOnly, s.sensitiveOnly, s.setSensitiveOnly, 
s.setPropertyFilter, s.setRequiredOnly], shallow)
 
     const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
 
+    useEffect(() => {
+        setRequiredOnly(false);
+        setChangedOnly(false);
+        setSensitiveOnly(false);
+        setPropertyFilter('');
+    }, [selectedStep?.uuid])
+
     function getClonableElementHeader(): React.JSX.Element {
         const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep);
         const description = selectedStep?.dslName ? 
CamelMetadataApi.getCamelModelMetadataByClassName(selectedStep?.dslName)?.description
 : title;
@@ -130,7 +142,10 @@ export function DslProperties(props: Props) {
             propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| p.required);
         }
         if (changedOnly) {
-            propertyMetas = propertyMetas.filter(p =>p.name === 'parameters' 
|| PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+            propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+        }
+        if (sensitiveOnly) {
+            propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| p.secret);
         }
         return propertyMetas
     }
@@ -144,7 +159,7 @@ export function DslProperties(props: Props) {
     function getPropertySelector() {
         return (
             <div style={{display: 'flex', flexDirection: 'row', alignItems: 
'center', gap: '3px', pointerEvents: 'initial', opacity: '1'}}>
-                <ToggleGroup aria-label="properties selctor">
+                <ToggleGroup className='property-selector' 
aria-label="properties selctor">
                     <ToggleGroupItem
                         text="Required"
                         buttonId="requiredOnly"
@@ -157,6 +172,12 @@ export function DslProperties(props: Props) {
                         isSelected={changedOnly}
                         onChange={(_, selected) => setChangedOnly(selected)}
                     />
+                    <ToggleGroupItem
+                        text="Sensitive"
+                        buttonId="sensitiveOnly"
+                        isSelected={sensitiveOnly}
+                        onChange={(_, selected) => setSensitiveOnly(selected)}
+                    />
                 </ToggleGroup>
                 <TextInputGroup>
                     <TextInputGroupMain
@@ -179,7 +200,7 @@ export function DslProperties(props: Props) {
     }
 
     function getPropertySelectorChanged(): boolean {
-        return requiredOnly || changedOnly || propertyFilter?.trim().length > 
0;
+        return requiredOnly || changedOnly || sensitiveOnly || 
propertyFilter?.trim().length > 0;
     }
 
     function getShowExpanded(): boolean {
diff --git 
a/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx 
b/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx
index 00a3e1ee..ac7a3b3d 100644
--- a/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx
+++ b/karavan-app/src/main/webui/src/designer/property/PropertiesHeader.tsx
@@ -25,7 +25,7 @@ import {
     MenuToggle,
     DropdownList,
     DropdownItem, Flex, Popover, FlexItem, Badge, ClipboardCopy,
-    Switch, Radio, Tooltip,
+    Switch, Tooltip,
 } from '@patternfly/react-core';
 import '../karavan.css';
 import './DslProperties.css';
diff --git a/karavan-app/src/main/webui/src/designer/property/PropertyStore.ts 
b/karavan-app/src/main/webui/src/designer/property/PropertyStore.ts
index b9d0e511..3515ec0a 100644
--- a/karavan-app/src/main/webui/src/designer/property/PropertyStore.ts
+++ b/karavan-app/src/main/webui/src/designer/property/PropertyStore.ts
@@ -24,11 +24,14 @@ interface PropertiesState {
     setRequiredOnly: (requiredOnly: boolean) => void
     changedOnly: boolean;
     setChangedOnly: (changedOnly: boolean) => void
+    sensitiveOnly: boolean;
+    setSensitiveOnly: (sensitiveOnly: boolean) => void
 }
 
 export const usePropertiesStore = createWithEqualityFn<PropertiesState>((set, 
get) => ({
     requiredOnly: false,
     changedOnly: false,
+    sensitiveOnly: false,
     propertyFilter: '',
     setPropertyFilter: (propertyFilter: string) => {
         set({propertyFilter: propertyFilter});
@@ -39,4 +42,7 @@ export const usePropertiesStore = 
createWithEqualityFn<PropertiesState>((set, ge
     setChangedOnly: (changedOnly: boolean) => {
         set({changedOnly: changedOnly});
     },
+    setSensitiveOnly: (sensitiveOnly: boolean) => {
+        set({sensitiveOnly: sensitiveOnly});
+    },
 }), shallow)
diff --git 
a/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
 
b/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
index 57ff7d4c..f6227cc1 100644
--- 
a/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
+++ 
b/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
@@ -27,7 +27,7 @@ import {
     InputGroupItem,
     TextInputGroup,
     TextVariants,
-    Text
+    Text, ValidatedOptions, FormHelperText, HelperText, HelperTextItem
 } from '@patternfly/react-core';
 import {
     Select,
@@ -45,8 +45,6 @@ import {ToDefinition} from 
"karavan-core/lib/model/CamelDefinition";
 import {InfrastructureSelector} from "./InfrastructureSelector";
 import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
-import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
-import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {usePropertiesHook} from "../usePropertiesHook";
 import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
@@ -57,6 +55,8 @@ import {ExpressionModalEditor} from 
"../../../expression/ExpressionModalEditor";
 import {PropertyPlaceholderDropdown} from "./PropertyPlaceholderDropdown";
 import {INTERNAL_COMPONENTS} from "karavan-core/lib/api/ComponentApi";
 import {PropertyUtil} from "./PropertyUtil";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import ExclamationCircleIcon from 
"@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
 
 const prefix = "parameters";
 const beanPrefix = "#bean:";
@@ -101,7 +101,6 @@ export function ComponentPropertyField(props: Props) {
     }, [checkChanges, textValue])
 
     function parametersChanged(parameter: string, value: string | number | 
boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) {
-        console.log("parametersChange", parameter, value);
         setCheckChanges(false);
         onParametersChange(parameter, value, pathParameter, newRoute);
         setSelectStatus(new Map<string, boolean>([[parameter, false]]))
@@ -266,6 +265,7 @@ export function ComponentPropertyField(props: Props) {
             {(!showEditor || property.secret) &&
                 <TextInput className="text-field" isRequired ref={ref}
                            type="text"
+                           validated={validated}
                            autoComplete="off"
                            id={id} name={id}
                            value={(textValue !== undefined ? textValue : 
property.defaultValue) || ''}
@@ -315,6 +315,7 @@ export function ComponentPropertyField(props: Props) {
                     <TextInput
                         className="text-field" isRequired
                         type="text"
+                        validated={validated}
                         autoComplete="off"
                         id={id} name={id}
                         value={(textValue !== undefined ? textValue : 
property.defaultValue) || ''}
@@ -387,6 +388,7 @@ export function ComponentPropertyField(props: Props) {
                         id={property.name + "-placeholder"}
                         name={property.name + "-placeholder"}
                         type="text"
+                        validated={validated}
                         aria-label="placeholder"
                         value={!isValueBoolean ? textValue?.toString() : ''}
                         onBlur={_ => onParametersChange(property.name, 
textValue)}
@@ -417,8 +419,23 @@ export function ComponentPropertyField(props: Props) {
         )
     }
 
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
+
     const property: ComponentProperty = props.property;
     const value = props.value;
+    const validated = (property.secret && !isSensitiveFieldValid(value)) ? 
ValidatedOptions.error : ValidatedOptions.default;
     return (
         <FormGroup
             key={id}
@@ -453,6 +470,7 @@ export function ComponentPropertyField(props: Props) {
             {property.type === 'boolean'
                 && getSwitch(property)}
             {getInfrastructureSelectorModal()}
+            {getValidationHelper()}
         </FormGroup>
     )
 }
diff --git 
a/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
 
b/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
index 5331f8fb..18090154 100644
--- 
a/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
+++ 
b/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
@@ -33,7 +33,15 @@ import {
     Card,
     InputGroup,
     SelectOptionProps,
-    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem
+    capitalize,
+    InputGroupItem,
+    TextVariants,
+    ToggleGroup,
+    ToggleGroupItem,
+    ValidatedOptions,
+    FormHelperText,
+    HelperText,
+    HelperTextItem
 } from '@patternfly/react-core';
 import {
     Select,
@@ -83,6 +91,8 @@ import {SelectField} from "./SelectField";
 import {PropertyUtil} from "./PropertyUtil";
 import {usePropertiesStore} from "../PropertyStore";
 import {Property} from "karavan-core/lib/model/KameletModels";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import ExclamationCircleIcon from 
"@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
 
 const beanPrefix = "#bean:";
 const classPrefix = "#class:";
@@ -103,7 +113,8 @@ export function DslPropertyField(props: Props) {
 
     const [integration, setIntegration, addVariable, files] = 
useIntegrationStore((s) => [s.integration, s.setIntegration, s.addVariable, 
s.files], shallow)
     const [dark, setSelectedStep, beans] = useDesignerStore((s) => [s.dark, 
s.setSelectedStep, s.beans], shallow)
-    const [propertyFilter, changedOnly, requiredOnly] = usePropertiesStore((s) 
=> [s.propertyFilter, s.changedOnly, s.requiredOnly], shallow)
+    const [propertyFilter, changedOnly, requiredOnly, sensitiveOnly] = 
usePropertiesStore((s) =>
+        [s.propertyFilter, s.changedOnly, s.requiredOnly, s.sensitiveOnly], 
shallow)
 
     const [isShowAdvanced, setIsShowAdvanced] = useState<string[]>([]);
     const [arrayValues, setArrayValues] = useState<Map<string, string>>(new 
Map<string, string>());
@@ -638,6 +649,7 @@ export function DslPropertyField(props: Props) {
                         id={property.name + "-placeholder"}
                         name={property.name + "-placeholder"}
                         type="text"
+                        validated={validated}
                         aria-label="placeholder"
                         value={!isValueBoolean ? textValue?.toString() : ''}
                         onBlur={_ => propertyChanged(property.name, textValue)}
@@ -918,6 +930,9 @@ export function DslPropertyField(props: Props) {
         if (changedOnly) {
             properties = properties.filter(p => 
PropertyUtil.hasKameletPropertyValueChanged(p, getKameletPropertyValue(p)));
         }
+        if (sensitiveOnly) {
+            properties = properties.filter(p => p.format == "password");
+        }
         return properties;
     }
 
@@ -1038,6 +1053,9 @@ export function DslPropertyField(props: Props) {
         if (changedOnly) {
             componentProperties = componentProperties.filter(p => 
PropertyUtil.hasComponentPropertyValueChanged(p, getComponentPropertyValue(p)));
         }
+        if (sensitiveOnly) {
+            componentProperties = componentProperties.filter(p => p.secret);
+        }
         return componentProperties
     }
 
@@ -1082,11 +1100,26 @@ export function DslPropertyField(props: Props) {
         return false;
     }
 
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
+
     const element = props.element;
     const isKamelet = CamelUtil.isKameletComponent(element);
     const isRouteTemplate = element?.dslName === 'RouteTemplateDefinition';
     const property: PropertyMeta = props.property;
     const value = props.value;
+    const validated = (property.secret && !isSensitiveFieldValid(value)) ? 
ValidatedOptions.error : ValidatedOptions.default;
     const isVariable = getIsVariable();
     const beanConstructors = element?.dslName === 'BeanFactoryDefinition' && 
property.name === 'constructors'
     const beanProperties = element?.dslName === 'BeanFactoryDefinition' && 
property.name === 'properties'
@@ -1143,6 +1176,7 @@ export function DslPropertyField(props: Props) {
                 {!isKamelet && property.name === 'parameters' && 
getComponentParameters(property)}
                 {beanConstructors && getBeanProperties('constructors')}
                 {beanProperties && getBeanProperties('properties')}
+                {getValidationHelper()}
             </FormGroup>
             {getInfrastructureSelectorModal()}
         </>
diff --git 
a/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
 
b/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
index d70582b5..b91289c1 100644
--- 
a/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
+++ 
b/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
@@ -16,19 +16,22 @@
  */
 import React, {useEffect, useRef, useState} from 'react';
 import {
-    FormGroup,
-    TextInput,
-    Popover,
-    Switch, InputGroup, Button, Tooltip, capitalize, Text, TextVariants, 
InputGroupItem
+    InputGroup,
+    Button,
+    Tooltip,
+    capitalize,
+    Text,
+    TextVariants,
+    InputGroupItem,
+    ValidatedOptions,
+    FormHelperText, HelperText, HelperTextItem, TextInput, FormGroup, Popover, 
Switch
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
-import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
+import ExclamationCircleIcon from 
'@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
 import {Property} from "karavan-core/lib/model/KameletModels";
 import {InfrastructureSelector} from "./InfrastructureSelector";
 import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
-import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
-import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 import {usePropertiesHook} from "../usePropertiesHook";
 import {Select, SelectDirection, SelectOption, SelectVariant} from 
"@patternfly/react-core/deprecated";
@@ -38,6 +41,8 @@ import EditorIcon from 
"@patternfly/react-icons/dist/js/icons/code-icon";
 import {ExpressionModalEditor} from 
"../../../expression/ExpressionModalEditor";
 import {useDesignerStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 
 interface Props {
     property: Property,
@@ -171,9 +176,10 @@ export function KameletPropertyField(props: Props) {
                     ref={ref}
                     className="text-field" isRequired
                     type='text'
+                    validated={validated}
                     autoComplete="off"
                     id={id} name={id}
-                    value={textValue}
+                    value={textValue || ''}
                     onBlur={_ => {
                         if (isNumeric((textValue))) {
                             parametersChanged(property.id, Number(textValue))
@@ -240,9 +246,23 @@ export function KameletPropertyField(props: Props) {
             </div>
         )
     }
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
 
     const property =  props.property;
     const value =  props.value;
+    const validated = (property.format === 'password' && 
!isSensitiveFieldValid(value)) ? ValidatedOptions.error : 
ValidatedOptions.default;
     const prefix = "parameters";
     const id = prefix + "-" + property.id;
     return (
@@ -279,6 +299,7 @@ export function KameletPropertyField(props: Props) {
                     isChecked={Boolean(value) === true}
                     onChange={e => parametersChanged(property.id, 
!Boolean(value))}/>
                 }
+                {getValidationHelper()}
             </FormGroup>
             {getInfrastructureSelectorModal()}
         </div>
diff --git a/karavan-designer/src/designer/property/DslProperties.css 
b/karavan-designer/src/designer/property/DslProperties.css
index e2401cf3..6e867105 100644
--- a/karavan-designer/src/designer/property/DslProperties.css
+++ b/karavan-designer/src/designer/property/DslProperties.css
@@ -276,3 +276,12 @@
     background-color: yellow;
 }
 
+.karavan .properties .value-sensitive-invalid {
+    background-color: red;
+}
+
+.karavan .properties .property-selector .pf-v5-c-toggle-group__button {
+    padding-left: 6px;
+    padding-right: 6px;
+}
+
diff --git a/karavan-designer/src/designer/property/DslProperties.tsx 
b/karavan-designer/src/designer/property/DslProperties.tsx
index 9511b1f8..dd2376ee 100644
--- a/karavan-designer/src/designer/property/DslProperties.tsx
+++ b/karavan-designer/src/designer/property/DslProperties.tsx
@@ -14,15 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, {useState} from 'react';
+import React, {useEffect, useState} from 'react';
 import {
+    Button,
+    ExpandableSection,
     Form,
     Text,
-    Title,
+    TextInputGroup,
+    TextInputGroupMain,
+    TextInputGroupUtilities,
     TextVariants,
-    ExpandableSection,
-    Button,
-    Tooltip, ToggleGroupItem, ToggleGroup, TextInputGroup, TextInputGroupMain, 
TextInputGroupUtilities,
+    Title,
+    ToggleGroup,
+    ToggleGroupItem,
+    Tooltip,
 } from '@patternfly/react-core';
 import '../karavan.css';
 import './DslProperties.css';
@@ -63,11 +68,18 @@ export function DslProperties(props: Props) {
     const [selectedStep, dark]
         = useDesignerStore((s) => [s.selectedStep, s.dark], shallow)
 
-    const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, 
setPropertyFilter, setRequiredOnly]
-        = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, 
s.requiredOnly, s.setChangedOnly, s.setPropertyFilter, s.setRequiredOnly], 
shallow)
+    const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, 
sensitiveOnly, setSensitiveOnly, setPropertyFilter, setRequiredOnly]
+        = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, 
s.requiredOnly, s.setChangedOnly, s.sensitiveOnly, s.setSensitiveOnly, 
s.setPropertyFilter, s.setRequiredOnly], shallow)
 
     const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
 
+    useEffect(() => {
+        setRequiredOnly(false);
+        setChangedOnly(false);
+        setSensitiveOnly(false);
+        setPropertyFilter('');
+    }, [selectedStep?.uuid])
+
     function getClonableElementHeader(): React.JSX.Element {
         const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep);
         const description = selectedStep?.dslName ? 
CamelMetadataApi.getCamelModelMetadataByClassName(selectedStep?.dslName)?.description
 : title;
@@ -130,7 +142,10 @@ export function DslProperties(props: Props) {
             propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| p.required);
         }
         if (changedOnly) {
-            propertyMetas = propertyMetas.filter(p =>p.name === 'parameters' 
|| PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+            propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+        }
+        if (sensitiveOnly) {
+            propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| p.secret);
         }
         return propertyMetas
     }
@@ -144,7 +159,7 @@ export function DslProperties(props: Props) {
     function getPropertySelector() {
         return (
             <div style={{display: 'flex', flexDirection: 'row', alignItems: 
'center', gap: '3px', pointerEvents: 'initial', opacity: '1'}}>
-                <ToggleGroup aria-label="properties selctor">
+                <ToggleGroup className='property-selector' 
aria-label="properties selctor">
                     <ToggleGroupItem
                         text="Required"
                         buttonId="requiredOnly"
@@ -157,6 +172,12 @@ export function DslProperties(props: Props) {
                         isSelected={changedOnly}
                         onChange={(_, selected) => setChangedOnly(selected)}
                     />
+                    <ToggleGroupItem
+                        text="Sensitive"
+                        buttonId="sensitiveOnly"
+                        isSelected={sensitiveOnly}
+                        onChange={(_, selected) => setSensitiveOnly(selected)}
+                    />
                 </ToggleGroup>
                 <TextInputGroup>
                     <TextInputGroupMain
@@ -179,7 +200,7 @@ export function DslProperties(props: Props) {
     }
 
     function getPropertySelectorChanged(): boolean {
-        return requiredOnly || changedOnly || propertyFilter?.trim().length > 
0;
+        return requiredOnly || changedOnly || sensitiveOnly || 
propertyFilter?.trim().length > 0;
     }
 
     function getShowExpanded(): boolean {
diff --git a/karavan-designer/src/designer/property/PropertiesHeader.tsx 
b/karavan-designer/src/designer/property/PropertiesHeader.tsx
index 00a3e1ee..ac7a3b3d 100644
--- a/karavan-designer/src/designer/property/PropertiesHeader.tsx
+++ b/karavan-designer/src/designer/property/PropertiesHeader.tsx
@@ -25,7 +25,7 @@ import {
     MenuToggle,
     DropdownList,
     DropdownItem, Flex, Popover, FlexItem, Badge, ClipboardCopy,
-    Switch, Radio, Tooltip,
+    Switch, Tooltip,
 } from '@patternfly/react-core';
 import '../karavan.css';
 import './DslProperties.css';
diff --git a/karavan-designer/src/designer/property/PropertyStore.ts 
b/karavan-designer/src/designer/property/PropertyStore.ts
index b9d0e511..3515ec0a 100644
--- a/karavan-designer/src/designer/property/PropertyStore.ts
+++ b/karavan-designer/src/designer/property/PropertyStore.ts
@@ -24,11 +24,14 @@ interface PropertiesState {
     setRequiredOnly: (requiredOnly: boolean) => void
     changedOnly: boolean;
     setChangedOnly: (changedOnly: boolean) => void
+    sensitiveOnly: boolean;
+    setSensitiveOnly: (sensitiveOnly: boolean) => void
 }
 
 export const usePropertiesStore = createWithEqualityFn<PropertiesState>((set, 
get) => ({
     requiredOnly: false,
     changedOnly: false,
+    sensitiveOnly: false,
     propertyFilter: '',
     setPropertyFilter: (propertyFilter: string) => {
         set({propertyFilter: propertyFilter});
@@ -39,4 +42,7 @@ export const usePropertiesStore = 
createWithEqualityFn<PropertiesState>((set, ge
     setChangedOnly: (changedOnly: boolean) => {
         set({changedOnly: changedOnly});
     },
+    setSensitiveOnly: (sensitiveOnly: boolean) => {
+        set({sensitiveOnly: sensitiveOnly});
+    },
 }), shallow)
diff --git 
a/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx 
b/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx
index 57ff7d4c..f6227cc1 100644
--- a/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx
+++ b/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx
@@ -27,7 +27,7 @@ import {
     InputGroupItem,
     TextInputGroup,
     TextVariants,
-    Text
+    Text, ValidatedOptions, FormHelperText, HelperText, HelperTextItem
 } from '@patternfly/react-core';
 import {
     Select,
@@ -45,8 +45,6 @@ import {ToDefinition} from 
"karavan-core/lib/model/CamelDefinition";
 import {InfrastructureSelector} from "./InfrastructureSelector";
 import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
-import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
-import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {usePropertiesHook} from "../usePropertiesHook";
 import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
@@ -57,6 +55,8 @@ import {ExpressionModalEditor} from 
"../../../expression/ExpressionModalEditor";
 import {PropertyPlaceholderDropdown} from "./PropertyPlaceholderDropdown";
 import {INTERNAL_COMPONENTS} from "karavan-core/lib/api/ComponentApi";
 import {PropertyUtil} from "./PropertyUtil";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import ExclamationCircleIcon from 
"@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
 
 const prefix = "parameters";
 const beanPrefix = "#bean:";
@@ -101,7 +101,6 @@ export function ComponentPropertyField(props: Props) {
     }, [checkChanges, textValue])
 
     function parametersChanged(parameter: string, value: string | number | 
boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) {
-        console.log("parametersChange", parameter, value);
         setCheckChanges(false);
         onParametersChange(parameter, value, pathParameter, newRoute);
         setSelectStatus(new Map<string, boolean>([[parameter, false]]))
@@ -266,6 +265,7 @@ export function ComponentPropertyField(props: Props) {
             {(!showEditor || property.secret) &&
                 <TextInput className="text-field" isRequired ref={ref}
                            type="text"
+                           validated={validated}
                            autoComplete="off"
                            id={id} name={id}
                            value={(textValue !== undefined ? textValue : 
property.defaultValue) || ''}
@@ -315,6 +315,7 @@ export function ComponentPropertyField(props: Props) {
                     <TextInput
                         className="text-field" isRequired
                         type="text"
+                        validated={validated}
                         autoComplete="off"
                         id={id} name={id}
                         value={(textValue !== undefined ? textValue : 
property.defaultValue) || ''}
@@ -387,6 +388,7 @@ export function ComponentPropertyField(props: Props) {
                         id={property.name + "-placeholder"}
                         name={property.name + "-placeholder"}
                         type="text"
+                        validated={validated}
                         aria-label="placeholder"
                         value={!isValueBoolean ? textValue?.toString() : ''}
                         onBlur={_ => onParametersChange(property.name, 
textValue)}
@@ -417,8 +419,23 @@ export function ComponentPropertyField(props: Props) {
         )
     }
 
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
+
     const property: ComponentProperty = props.property;
     const value = props.value;
+    const validated = (property.secret && !isSensitiveFieldValid(value)) ? 
ValidatedOptions.error : ValidatedOptions.default;
     return (
         <FormGroup
             key={id}
@@ -453,6 +470,7 @@ export function ComponentPropertyField(props: Props) {
             {property.type === 'boolean'
                 && getSwitch(property)}
             {getInfrastructureSelectorModal()}
+            {getValidationHelper()}
         </FormGroup>
     )
 }
diff --git 
a/karavan-designer/src/designer/property/property/DslPropertyField.tsx 
b/karavan-designer/src/designer/property/property/DslPropertyField.tsx
index 5331f8fb..18090154 100644
--- a/karavan-designer/src/designer/property/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/property/property/DslPropertyField.tsx
@@ -33,7 +33,15 @@ import {
     Card,
     InputGroup,
     SelectOptionProps,
-    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem
+    capitalize,
+    InputGroupItem,
+    TextVariants,
+    ToggleGroup,
+    ToggleGroupItem,
+    ValidatedOptions,
+    FormHelperText,
+    HelperText,
+    HelperTextItem
 } from '@patternfly/react-core';
 import {
     Select,
@@ -83,6 +91,8 @@ import {SelectField} from "./SelectField";
 import {PropertyUtil} from "./PropertyUtil";
 import {usePropertiesStore} from "../PropertyStore";
 import {Property} from "karavan-core/lib/model/KameletModels";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import ExclamationCircleIcon from 
"@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
 
 const beanPrefix = "#bean:";
 const classPrefix = "#class:";
@@ -103,7 +113,8 @@ export function DslPropertyField(props: Props) {
 
     const [integration, setIntegration, addVariable, files] = 
useIntegrationStore((s) => [s.integration, s.setIntegration, s.addVariable, 
s.files], shallow)
     const [dark, setSelectedStep, beans] = useDesignerStore((s) => [s.dark, 
s.setSelectedStep, s.beans], shallow)
-    const [propertyFilter, changedOnly, requiredOnly] = usePropertiesStore((s) 
=> [s.propertyFilter, s.changedOnly, s.requiredOnly], shallow)
+    const [propertyFilter, changedOnly, requiredOnly, sensitiveOnly] = 
usePropertiesStore((s) =>
+        [s.propertyFilter, s.changedOnly, s.requiredOnly, s.sensitiveOnly], 
shallow)
 
     const [isShowAdvanced, setIsShowAdvanced] = useState<string[]>([]);
     const [arrayValues, setArrayValues] = useState<Map<string, string>>(new 
Map<string, string>());
@@ -638,6 +649,7 @@ export function DslPropertyField(props: Props) {
                         id={property.name + "-placeholder"}
                         name={property.name + "-placeholder"}
                         type="text"
+                        validated={validated}
                         aria-label="placeholder"
                         value={!isValueBoolean ? textValue?.toString() : ''}
                         onBlur={_ => propertyChanged(property.name, textValue)}
@@ -918,6 +930,9 @@ export function DslPropertyField(props: Props) {
         if (changedOnly) {
             properties = properties.filter(p => 
PropertyUtil.hasKameletPropertyValueChanged(p, getKameletPropertyValue(p)));
         }
+        if (sensitiveOnly) {
+            properties = properties.filter(p => p.format == "password");
+        }
         return properties;
     }
 
@@ -1038,6 +1053,9 @@ export function DslPropertyField(props: Props) {
         if (changedOnly) {
             componentProperties = componentProperties.filter(p => 
PropertyUtil.hasComponentPropertyValueChanged(p, getComponentPropertyValue(p)));
         }
+        if (sensitiveOnly) {
+            componentProperties = componentProperties.filter(p => p.secret);
+        }
         return componentProperties
     }
 
@@ -1082,11 +1100,26 @@ export function DslPropertyField(props: Props) {
         return false;
     }
 
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
+
     const element = props.element;
     const isKamelet = CamelUtil.isKameletComponent(element);
     const isRouteTemplate = element?.dslName === 'RouteTemplateDefinition';
     const property: PropertyMeta = props.property;
     const value = props.value;
+    const validated = (property.secret && !isSensitiveFieldValid(value)) ? 
ValidatedOptions.error : ValidatedOptions.default;
     const isVariable = getIsVariable();
     const beanConstructors = element?.dslName === 'BeanFactoryDefinition' && 
property.name === 'constructors'
     const beanProperties = element?.dslName === 'BeanFactoryDefinition' && 
property.name === 'properties'
@@ -1143,6 +1176,7 @@ export function DslPropertyField(props: Props) {
                 {!isKamelet && property.name === 'parameters' && 
getComponentParameters(property)}
                 {beanConstructors && getBeanProperties('constructors')}
                 {beanProperties && getBeanProperties('properties')}
+                {getValidationHelper()}
             </FormGroup>
             {getInfrastructureSelectorModal()}
         </>
diff --git 
a/karavan-designer/src/designer/property/property/KameletPropertyField.tsx 
b/karavan-designer/src/designer/property/property/KameletPropertyField.tsx
index d70582b5..b91289c1 100644
--- a/karavan-designer/src/designer/property/property/KameletPropertyField.tsx
+++ b/karavan-designer/src/designer/property/property/KameletPropertyField.tsx
@@ -16,19 +16,22 @@
  */
 import React, {useEffect, useRef, useState} from 'react';
 import {
-    FormGroup,
-    TextInput,
-    Popover,
-    Switch, InputGroup, Button, Tooltip, capitalize, Text, TextVariants, 
InputGroupItem
+    InputGroup,
+    Button,
+    Tooltip,
+    capitalize,
+    Text,
+    TextVariants,
+    InputGroupItem,
+    ValidatedOptions,
+    FormHelperText, HelperText, HelperTextItem, TextInput, FormGroup, Popover, 
Switch
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
-import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
+import ExclamationCircleIcon from 
'@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
 import {Property} from "karavan-core/lib/model/KameletModels";
 import {InfrastructureSelector} from "./InfrastructureSelector";
 import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
-import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
-import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 import {usePropertiesHook} from "../usePropertiesHook";
 import {Select, SelectDirection, SelectOption, SelectVariant} from 
"@patternfly/react-core/deprecated";
@@ -38,6 +41,8 @@ import EditorIcon from 
"@patternfly/react-icons/dist/js/icons/code-icon";
 import {ExpressionModalEditor} from 
"../../../expression/ExpressionModalEditor";
 import {useDesignerStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 
 interface Props {
     property: Property,
@@ -171,9 +176,10 @@ export function KameletPropertyField(props: Props) {
                     ref={ref}
                     className="text-field" isRequired
                     type='text'
+                    validated={validated}
                     autoComplete="off"
                     id={id} name={id}
-                    value={textValue}
+                    value={textValue || ''}
                     onBlur={_ => {
                         if (isNumeric((textValue))) {
                             parametersChanged(property.id, Number(textValue))
@@ -240,9 +246,23 @@ export function KameletPropertyField(props: Props) {
             </div>
         )
     }
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
 
     const property =  props.property;
     const value =  props.value;
+    const validated = (property.format === 'password' && 
!isSensitiveFieldValid(value)) ? ValidatedOptions.error : 
ValidatedOptions.default;
     const prefix = "parameters";
     const id = prefix + "-" + property.id;
     return (
@@ -279,6 +299,7 @@ export function KameletPropertyField(props: Props) {
                     isChecked={Boolean(value) === true}
                     onChange={e => parametersChanged(property.id, 
!Boolean(value))}/>
                 }
+                {getValidationHelper()}
             </FormGroup>
             {getInfrastructureSelectorModal()}
         </div>
diff --git a/karavan-space/src/designer/property/DslProperties.css 
b/karavan-space/src/designer/property/DslProperties.css
index e2401cf3..6e867105 100644
--- a/karavan-space/src/designer/property/DslProperties.css
+++ b/karavan-space/src/designer/property/DslProperties.css
@@ -276,3 +276,12 @@
     background-color: yellow;
 }
 
+.karavan .properties .value-sensitive-invalid {
+    background-color: red;
+}
+
+.karavan .properties .property-selector .pf-v5-c-toggle-group__button {
+    padding-left: 6px;
+    padding-right: 6px;
+}
+
diff --git a/karavan-space/src/designer/property/DslProperties.tsx 
b/karavan-space/src/designer/property/DslProperties.tsx
index 9511b1f8..dd2376ee 100644
--- a/karavan-space/src/designer/property/DslProperties.tsx
+++ b/karavan-space/src/designer/property/DslProperties.tsx
@@ -14,15 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, {useState} from 'react';
+import React, {useEffect, useState} from 'react';
 import {
+    Button,
+    ExpandableSection,
     Form,
     Text,
-    Title,
+    TextInputGroup,
+    TextInputGroupMain,
+    TextInputGroupUtilities,
     TextVariants,
-    ExpandableSection,
-    Button,
-    Tooltip, ToggleGroupItem, ToggleGroup, TextInputGroup, TextInputGroupMain, 
TextInputGroupUtilities,
+    Title,
+    ToggleGroup,
+    ToggleGroupItem,
+    Tooltip,
 } from '@patternfly/react-core';
 import '../karavan.css';
 import './DslProperties.css';
@@ -63,11 +68,18 @@ export function DslProperties(props: Props) {
     const [selectedStep, dark]
         = useDesignerStore((s) => [s.selectedStep, s.dark], shallow)
 
-    const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, 
setPropertyFilter, setRequiredOnly]
-        = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, 
s.requiredOnly, s.setChangedOnly, s.setPropertyFilter, s.setRequiredOnly], 
shallow)
+    const [propertyFilter, changedOnly, requiredOnly, setChangedOnly, 
sensitiveOnly, setSensitiveOnly, setPropertyFilter, setRequiredOnly]
+        = usePropertiesStore((s) => [s.propertyFilter, s.changedOnly, 
s.requiredOnly, s.setChangedOnly, s.sensitiveOnly, s.setSensitiveOnly, 
s.setPropertyFilter, s.setRequiredOnly], shallow)
 
     const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
 
+    useEffect(() => {
+        setRequiredOnly(false);
+        setChangedOnly(false);
+        setSensitiveOnly(false);
+        setPropertyFilter('');
+    }, [selectedStep?.uuid])
+
     function getClonableElementHeader(): React.JSX.Element {
         const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep);
         const description = selectedStep?.dslName ? 
CamelMetadataApi.getCamelModelMetadataByClassName(selectedStep?.dslName)?.description
 : title;
@@ -130,7 +142,10 @@ export function DslProperties(props: Props) {
             propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| p.required);
         }
         if (changedOnly) {
-            propertyMetas = propertyMetas.filter(p =>p.name === 'parameters' 
|| PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+            propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| PropertyUtil.hasDslPropertyValueChanged(p, getPropertyValue(p)));
+        }
+        if (sensitiveOnly) {
+            propertyMetas = propertyMetas.filter(p => p.name === 'parameters' 
|| p.secret);
         }
         return propertyMetas
     }
@@ -144,7 +159,7 @@ export function DslProperties(props: Props) {
     function getPropertySelector() {
         return (
             <div style={{display: 'flex', flexDirection: 'row', alignItems: 
'center', gap: '3px', pointerEvents: 'initial', opacity: '1'}}>
-                <ToggleGroup aria-label="properties selctor">
+                <ToggleGroup className='property-selector' 
aria-label="properties selctor">
                     <ToggleGroupItem
                         text="Required"
                         buttonId="requiredOnly"
@@ -157,6 +172,12 @@ export function DslProperties(props: Props) {
                         isSelected={changedOnly}
                         onChange={(_, selected) => setChangedOnly(selected)}
                     />
+                    <ToggleGroupItem
+                        text="Sensitive"
+                        buttonId="sensitiveOnly"
+                        isSelected={sensitiveOnly}
+                        onChange={(_, selected) => setSensitiveOnly(selected)}
+                    />
                 </ToggleGroup>
                 <TextInputGroup>
                     <TextInputGroupMain
@@ -179,7 +200,7 @@ export function DslProperties(props: Props) {
     }
 
     function getPropertySelectorChanged(): boolean {
-        return requiredOnly || changedOnly || propertyFilter?.trim().length > 
0;
+        return requiredOnly || changedOnly || sensitiveOnly || 
propertyFilter?.trim().length > 0;
     }
 
     function getShowExpanded(): boolean {
diff --git a/karavan-space/src/designer/property/PropertiesHeader.tsx 
b/karavan-space/src/designer/property/PropertiesHeader.tsx
index 00a3e1ee..ac7a3b3d 100644
--- a/karavan-space/src/designer/property/PropertiesHeader.tsx
+++ b/karavan-space/src/designer/property/PropertiesHeader.tsx
@@ -25,7 +25,7 @@ import {
     MenuToggle,
     DropdownList,
     DropdownItem, Flex, Popover, FlexItem, Badge, ClipboardCopy,
-    Switch, Radio, Tooltip,
+    Switch, Tooltip,
 } from '@patternfly/react-core';
 import '../karavan.css';
 import './DslProperties.css';
diff --git a/karavan-space/src/designer/property/PropertyStore.ts 
b/karavan-space/src/designer/property/PropertyStore.ts
index b9d0e511..3515ec0a 100644
--- a/karavan-space/src/designer/property/PropertyStore.ts
+++ b/karavan-space/src/designer/property/PropertyStore.ts
@@ -24,11 +24,14 @@ interface PropertiesState {
     setRequiredOnly: (requiredOnly: boolean) => void
     changedOnly: boolean;
     setChangedOnly: (changedOnly: boolean) => void
+    sensitiveOnly: boolean;
+    setSensitiveOnly: (sensitiveOnly: boolean) => void
 }
 
 export const usePropertiesStore = createWithEqualityFn<PropertiesState>((set, 
get) => ({
     requiredOnly: false,
     changedOnly: false,
+    sensitiveOnly: false,
     propertyFilter: '',
     setPropertyFilter: (propertyFilter: string) => {
         set({propertyFilter: propertyFilter});
@@ -39,4 +42,7 @@ export const usePropertiesStore = 
createWithEqualityFn<PropertiesState>((set, ge
     setChangedOnly: (changedOnly: boolean) => {
         set({changedOnly: changedOnly});
     },
+    setSensitiveOnly: (sensitiveOnly: boolean) => {
+        set({sensitiveOnly: sensitiveOnly});
+    },
 }), shallow)
diff --git 
a/karavan-space/src/designer/property/property/ComponentPropertyField.tsx 
b/karavan-space/src/designer/property/property/ComponentPropertyField.tsx
index 57ff7d4c..f6227cc1 100644
--- a/karavan-space/src/designer/property/property/ComponentPropertyField.tsx
+++ b/karavan-space/src/designer/property/property/ComponentPropertyField.tsx
@@ -27,7 +27,7 @@ import {
     InputGroupItem,
     TextInputGroup,
     TextVariants,
-    Text
+    Text, ValidatedOptions, FormHelperText, HelperText, HelperTextItem
 } from '@patternfly/react-core';
 import {
     Select,
@@ -45,8 +45,6 @@ import {ToDefinition} from 
"karavan-core/lib/model/CamelDefinition";
 import {InfrastructureSelector} from "./InfrastructureSelector";
 import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
-import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
-import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {usePropertiesHook} from "../usePropertiesHook";
 import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
@@ -57,6 +55,8 @@ import {ExpressionModalEditor} from 
"../../../expression/ExpressionModalEditor";
 import {PropertyPlaceholderDropdown} from "./PropertyPlaceholderDropdown";
 import {INTERNAL_COMPONENTS} from "karavan-core/lib/api/ComponentApi";
 import {PropertyUtil} from "./PropertyUtil";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import ExclamationCircleIcon from 
"@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
 
 const prefix = "parameters";
 const beanPrefix = "#bean:";
@@ -101,7 +101,6 @@ export function ComponentPropertyField(props: Props) {
     }, [checkChanges, textValue])
 
     function parametersChanged(parameter: string, value: string | number | 
boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) {
-        console.log("parametersChange", parameter, value);
         setCheckChanges(false);
         onParametersChange(parameter, value, pathParameter, newRoute);
         setSelectStatus(new Map<string, boolean>([[parameter, false]]))
@@ -266,6 +265,7 @@ export function ComponentPropertyField(props: Props) {
             {(!showEditor || property.secret) &&
                 <TextInput className="text-field" isRequired ref={ref}
                            type="text"
+                           validated={validated}
                            autoComplete="off"
                            id={id} name={id}
                            value={(textValue !== undefined ? textValue : 
property.defaultValue) || ''}
@@ -315,6 +315,7 @@ export function ComponentPropertyField(props: Props) {
                     <TextInput
                         className="text-field" isRequired
                         type="text"
+                        validated={validated}
                         autoComplete="off"
                         id={id} name={id}
                         value={(textValue !== undefined ? textValue : 
property.defaultValue) || ''}
@@ -387,6 +388,7 @@ export function ComponentPropertyField(props: Props) {
                         id={property.name + "-placeholder"}
                         name={property.name + "-placeholder"}
                         type="text"
+                        validated={validated}
                         aria-label="placeholder"
                         value={!isValueBoolean ? textValue?.toString() : ''}
                         onBlur={_ => onParametersChange(property.name, 
textValue)}
@@ -417,8 +419,23 @@ export function ComponentPropertyField(props: Props) {
         )
     }
 
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
+
     const property: ComponentProperty = props.property;
     const value = props.value;
+    const validated = (property.secret && !isSensitiveFieldValid(value)) ? 
ValidatedOptions.error : ValidatedOptions.default;
     return (
         <FormGroup
             key={id}
@@ -453,6 +470,7 @@ export function ComponentPropertyField(props: Props) {
             {property.type === 'boolean'
                 && getSwitch(property)}
             {getInfrastructureSelectorModal()}
+            {getValidationHelper()}
         </FormGroup>
     )
 }
diff --git a/karavan-space/src/designer/property/property/DslPropertyField.tsx 
b/karavan-space/src/designer/property/property/DslPropertyField.tsx
index 5331f8fb..18090154 100644
--- a/karavan-space/src/designer/property/property/DslPropertyField.tsx
+++ b/karavan-space/src/designer/property/property/DslPropertyField.tsx
@@ -33,7 +33,15 @@ import {
     Card,
     InputGroup,
     SelectOptionProps,
-    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem
+    capitalize,
+    InputGroupItem,
+    TextVariants,
+    ToggleGroup,
+    ToggleGroupItem,
+    ValidatedOptions,
+    FormHelperText,
+    HelperText,
+    HelperTextItem
 } from '@patternfly/react-core';
 import {
     Select,
@@ -83,6 +91,8 @@ import {SelectField} from "./SelectField";
 import {PropertyUtil} from "./PropertyUtil";
 import {usePropertiesStore} from "../PropertyStore";
 import {Property} from "karavan-core/lib/model/KameletModels";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import ExclamationCircleIcon from 
"@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
 
 const beanPrefix = "#bean:";
 const classPrefix = "#class:";
@@ -103,7 +113,8 @@ export function DslPropertyField(props: Props) {
 
     const [integration, setIntegration, addVariable, files] = 
useIntegrationStore((s) => [s.integration, s.setIntegration, s.addVariable, 
s.files], shallow)
     const [dark, setSelectedStep, beans] = useDesignerStore((s) => [s.dark, 
s.setSelectedStep, s.beans], shallow)
-    const [propertyFilter, changedOnly, requiredOnly] = usePropertiesStore((s) 
=> [s.propertyFilter, s.changedOnly, s.requiredOnly], shallow)
+    const [propertyFilter, changedOnly, requiredOnly, sensitiveOnly] = 
usePropertiesStore((s) =>
+        [s.propertyFilter, s.changedOnly, s.requiredOnly, s.sensitiveOnly], 
shallow)
 
     const [isShowAdvanced, setIsShowAdvanced] = useState<string[]>([]);
     const [arrayValues, setArrayValues] = useState<Map<string, string>>(new 
Map<string, string>());
@@ -638,6 +649,7 @@ export function DslPropertyField(props: Props) {
                         id={property.name + "-placeholder"}
                         name={property.name + "-placeholder"}
                         type="text"
+                        validated={validated}
                         aria-label="placeholder"
                         value={!isValueBoolean ? textValue?.toString() : ''}
                         onBlur={_ => propertyChanged(property.name, textValue)}
@@ -918,6 +930,9 @@ export function DslPropertyField(props: Props) {
         if (changedOnly) {
             properties = properties.filter(p => 
PropertyUtil.hasKameletPropertyValueChanged(p, getKameletPropertyValue(p)));
         }
+        if (sensitiveOnly) {
+            properties = properties.filter(p => p.format == "password");
+        }
         return properties;
     }
 
@@ -1038,6 +1053,9 @@ export function DslPropertyField(props: Props) {
         if (changedOnly) {
             componentProperties = componentProperties.filter(p => 
PropertyUtil.hasComponentPropertyValueChanged(p, getComponentPropertyValue(p)));
         }
+        if (sensitiveOnly) {
+            componentProperties = componentProperties.filter(p => p.secret);
+        }
         return componentProperties
     }
 
@@ -1082,11 +1100,26 @@ export function DslPropertyField(props: Props) {
         return false;
     }
 
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
+
     const element = props.element;
     const isKamelet = CamelUtil.isKameletComponent(element);
     const isRouteTemplate = element?.dslName === 'RouteTemplateDefinition';
     const property: PropertyMeta = props.property;
     const value = props.value;
+    const validated = (property.secret && !isSensitiveFieldValid(value)) ? 
ValidatedOptions.error : ValidatedOptions.default;
     const isVariable = getIsVariable();
     const beanConstructors = element?.dslName === 'BeanFactoryDefinition' && 
property.name === 'constructors'
     const beanProperties = element?.dslName === 'BeanFactoryDefinition' && 
property.name === 'properties'
@@ -1143,6 +1176,7 @@ export function DslPropertyField(props: Props) {
                 {!isKamelet && property.name === 'parameters' && 
getComponentParameters(property)}
                 {beanConstructors && getBeanProperties('constructors')}
                 {beanProperties && getBeanProperties('properties')}
+                {getValidationHelper()}
             </FormGroup>
             {getInfrastructureSelectorModal()}
         </>
diff --git 
a/karavan-space/src/designer/property/property/KameletPropertyField.tsx 
b/karavan-space/src/designer/property/property/KameletPropertyField.tsx
index d70582b5..b91289c1 100644
--- a/karavan-space/src/designer/property/property/KameletPropertyField.tsx
+++ b/karavan-space/src/designer/property/property/KameletPropertyField.tsx
@@ -16,19 +16,22 @@
  */
 import React, {useEffect, useRef, useState} from 'react';
 import {
-    FormGroup,
-    TextInput,
-    Popover,
-    Switch, InputGroup, Button, Tooltip, capitalize, Text, TextVariants, 
InputGroupItem
+    InputGroup,
+    Button,
+    Tooltip,
+    capitalize,
+    Text,
+    TextVariants,
+    InputGroupItem,
+    ValidatedOptions,
+    FormHelperText, HelperText, HelperTextItem, TextInput, FormGroup, Popover, 
Switch
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
-import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
+import ExclamationCircleIcon from 
'@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon';
 import {Property} from "karavan-core/lib/model/KameletModels";
 import {InfrastructureSelector} from "./InfrastructureSelector";
 import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
-import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
-import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 import {usePropertiesHook} from "../usePropertiesHook";
 import {Select, SelectDirection, SelectOption, SelectVariant} from 
"@patternfly/react-core/deprecated";
@@ -38,6 +41,8 @@ import EditorIcon from 
"@patternfly/react-icons/dist/js/icons/code-icon";
 import {ExpressionModalEditor} from 
"../../../expression/ExpressionModalEditor";
 import {useDesignerStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
+import {isSensitiveFieldValid} from "../../utils/ValidatorUtils";
+import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 
 interface Props {
     property: Property,
@@ -171,9 +176,10 @@ export function KameletPropertyField(props: Props) {
                     ref={ref}
                     className="text-field" isRequired
                     type='text'
+                    validated={validated}
                     autoComplete="off"
                     id={id} name={id}
-                    value={textValue}
+                    value={textValue || ''}
                     onBlur={_ => {
                         if (isNumeric((textValue))) {
                             parametersChanged(property.id, Number(textValue))
@@ -240,9 +246,23 @@ export function KameletPropertyField(props: Props) {
             </div>
         )
     }
+    function getValidationHelper() {
+        return (
+            validated !== ValidatedOptions.default
+                ? <FormHelperText>
+                    <HelperText>
+                        <HelperTextItem icon={<ExclamationCircleIcon />} 
variant={validated}>
+                            {'Must be a placeholder {{ }} or secret 
{{secret:name/key}}'}
+                        </HelperTextItem>
+                    </HelperText>
+                </FormHelperText>
+                : <></>
+        )
+    }
 
     const property =  props.property;
     const value =  props.value;
+    const validated = (property.format === 'password' && 
!isSensitiveFieldValid(value)) ? ValidatedOptions.error : 
ValidatedOptions.default;
     const prefix = "parameters";
     const id = prefix + "-" + property.id;
     return (
@@ -279,6 +299,7 @@ export function KameletPropertyField(props: Props) {
                     isChecked={Boolean(value) === true}
                     onChange={e => parametersChanged(property.id, 
!Boolean(value))}/>
                 }
+                {getValidationHelper()}
             </FormGroup>
             {getInfrastructureSelectorModal()}
         </div>

Reply via email to