diff --git a/frontend/src/lib/constants.ts b/frontend/src/lib/constants.ts index 3e3925ec9..ceaa1fce0 100644 --- a/frontend/src/lib/constants.ts +++ b/frontend/src/lib/constants.ts @@ -1,4 +1,8 @@ -import { ConfigurationParameters, ConsumerGroupState } from 'generated-sources'; +import { + ApplicationConfigPropertiesKafkaMaskingTypeEnum, + ConfigurationParameters, + ConsumerGroupState, +} from 'generated-sources'; declare global { interface Window { @@ -101,6 +105,20 @@ export const METRICS_OPTIONS = [ { value: 'JMX', label: 'JMX' }, { value: 'PROMETHEUS', label: 'PROMETHEUS' }, ]; +export const MASKING_OPTIONS = [ + { + value: ApplicationConfigPropertiesKafkaMaskingTypeEnum.MASK, + label: 'MASK', + }, + { + value: ApplicationConfigPropertiesKafkaMaskingTypeEnum.REMOVE, + label: 'REMOVE', + }, + { + value: ApplicationConfigPropertiesKafkaMaskingTypeEnum.REPLACE, + label: 'REPLACE', + }, +]; export const CONSUMER_GROUP_STATE_TOOLTIPS: Record = { diff --git a/frontend/src/widgets/ClusterConfigForm/ClusterConfigForm.styled.ts b/frontend/src/widgets/ClusterConfigForm/ClusterConfigForm.styled.ts index 5a3452a93..a99c2f51b 100644 --- a/frontend/src/widgets/ClusterConfigForm/ClusterConfigForm.styled.ts +++ b/frontend/src/widgets/ClusterConfigForm/ClusterConfigForm.styled.ts @@ -41,6 +41,7 @@ export const FlexGrow1 = styled.div` flex-direction: column; display: flex; `; + // KafkaCluster export const BootstrapServer = styled(InputContainer)` grid-template-columns: 3fr 110px 30px; @@ -58,5 +59,23 @@ export const FileUploadInputWrapper = styled.div` display: flex; height: 40px; align-items: center; - color: ${({ theme }) => theme.clusterConfigForm.fileInput.color}}; + color: ${({ theme }) => theme.clusterConfigForm.fileInput.color}; +`; + +// Masking +export const FieldWrapper = styled.div` + display: flex; + gap: 8px; + align-items: center; + flex-wrap: wrap; +`; +export const FieldContainer = styled.div` + display: flex; + flex-direction: row; + gap: 8px; + align-items: center; +`; +export const Error = styled.p` + color: ${({ theme }) => theme.input.error}; + font-size: 12px; `; diff --git a/frontend/src/widgets/ClusterConfigForm/Sections/Masking.tsx b/frontend/src/widgets/ClusterConfigForm/Sections/Masking.tsx new file mode 100644 index 000000000..157932e04 --- /dev/null +++ b/frontend/src/widgets/ClusterConfigForm/Sections/Masking.tsx @@ -0,0 +1,225 @@ +import * as React from 'react'; +import * as S from 'widgets/ClusterConfigForm/ClusterConfigForm.styled'; +import { Button } from 'components/common/Button/Button'; +import Input from 'components/common/Input/Input'; +import { useFieldArray, useFormContext } from 'react-hook-form'; +import PlusIcon from 'components/common/Icons/PlusIcon'; +import IconButtonWrapper from 'components/common/Icons/IconButtonWrapper'; +import CloseCircleIcon from 'components/common/Icons/CloseCircleIcon'; +import { + FieldContainer, + FieldWrapper, + FlexGrow1, + FlexRow, +} from 'widgets/ClusterConfigForm/ClusterConfigForm.styled'; +import SectionHeader from 'widgets/ClusterConfigForm/common/SectionHeader'; +import { MASKING_OPTIONS } from 'lib/constants'; +import ControlledSelect from 'components/common/Select/ControlledSelect'; +import { FormError } from 'components/common/Input/Input.styled'; +import { ErrorMessage } from '@hookform/error-message'; + +const Fields = ({ nestedIdx }: { nestedIdx: number }) => { + const { control } = useFormContext(); + const { fields, append, remove } = useFieldArray({ + control, + name: `masking.${nestedIdx}.fields`, + }); + + const handleAppend = () => append({ value: '' }); + + return ( + + + + {fields.map((item, index) => ( + + + + {fields.length > 1 && ( + remove(index)} + > + + + + + )} + + ))} + + + + + + + + + + ); +}; + +const MaskingCharReplacement = ({ nestedIdx }: { nestedIdx: number }) => { + const { control } = useFormContext(); + const { fields, append, remove } = useFieldArray({ + control, + name: `masking.${nestedIdx}.maskingCharsReplacement`, + }); + + const handleAppend = () => append({ value: '' }); + + return ( + + + + {fields.map((item, index) => ( + + + + {fields.length > 1 && ( + remove(index)} + > + + + + + )} + + ))} + + + + + + + + + + ); +}; + +const Masking = () => { + const { control } = useFormContext(); + const { fields, append, remove } = useFieldArray({ + control, + name: 'masking', + }); + const handleAppend = () => + append({ + type: undefined, + fields: [{ value: '' }], + fieldsNamePattern: '', + maskingCharsReplacement: [{ value: '' }], + replacement: '', + topicKeysPattern: '', + topicValuesPattern: '', + }); + const toggleConfig = () => (fields.length === 0 ? handleAppend() : remove()); + + const hasFields = fields.length > 0; + + return ( + <> + + {hasFields && ( + + {fields.map((item, index) => ( +
+ + + + + + + + + + + remove(index)}> + + + + + + +
+
+ ))} + +
+ )} + + ); +}; +export default Masking; diff --git a/frontend/src/widgets/ClusterConfigForm/index.tsx b/frontend/src/widgets/ClusterConfigForm/index.tsx index cc57cb52c..f2323c8f0 100644 --- a/frontend/src/widgets/ClusterConfigForm/index.tsx +++ b/frontend/src/widgets/ClusterConfigForm/index.tsx @@ -22,6 +22,7 @@ import Metrics from 'widgets/ClusterConfigForm/Sections/Metrics'; import CustomAuthentication from 'widgets/ClusterConfigForm/Sections/CustomAuthentication'; import Authentication from 'widgets/ClusterConfigForm/Sections/Authentication/Authentication'; import KSQL from 'widgets/ClusterConfigForm/Sections/KSQL'; +import Masking from 'widgets/ClusterConfigForm/Sections/Masking'; import { useConfirm } from 'lib/hooks/useConfirm'; interface ClusterConfigFormProps { @@ -145,6 +146,8 @@ const ClusterConfigForm: React.FC = ({

+ +