From 041613486b228155664f29144fc26d43e454df54 Mon Sep 17 00:00:00 2001 From: Amogh-Bharadwaj Date: Mon, 11 Mar 2024 13:40:16 +0530 Subject: [PATCH] cleanup UI, add missing parts --- ui/app/api/peers/route.ts | 7 + ui/app/dto/PeersDTO.ts | 4 +- ui/app/peers/create/[peerType]/helpers/ka.ts | 30 +++- ui/app/peers/create/[peerType]/page.tsx | 2 +- ui/app/peers/create/[peerType]/schema.ts | 18 ++- ui/components/PeerForms/KafkaConfig.tsx | 159 ++++++++++++------- 6 files changed, 148 insertions(+), 72 deletions(-) diff --git a/ui/app/api/peers/route.ts b/ui/app/api/peers/route.ts index 5d43442bd8..0691212af8 100644 --- a/ui/app/api/peers/route.ts +++ b/ui/app/api/peers/route.ts @@ -10,6 +10,7 @@ import { BigqueryConfig, ClickhouseConfig, DBType, + KafkaConfig, Peer, PostgresConfig, S3Config, @@ -63,6 +64,12 @@ const constructPeer = ( type: DBType.S3, s3Config: config as S3Config, }; + case 'KAFKA': + return { + name, + type: DBType.KAFKA, + kafkaConfig: config as KafkaConfig, + }; default: return; } diff --git a/ui/app/dto/PeersDTO.ts b/ui/app/dto/PeersDTO.ts index a015439d83..6e6a720914 100644 --- a/ui/app/dto/PeersDTO.ts +++ b/ui/app/dto/PeersDTO.ts @@ -1,6 +1,7 @@ import { BigqueryConfig, ClickhouseConfig, + KafkaConfig, PostgresConfig, S3Config, SnowflakeConfig, @@ -43,7 +44,8 @@ export type PeerConfig = | SnowflakeConfig | BigqueryConfig | ClickhouseConfig - | S3Config; + | S3Config + | KafkaConfig; export type CatalogPeer = { id: number; name: string; diff --git a/ui/app/peers/create/[peerType]/helpers/ka.ts b/ui/app/peers/create/[peerType]/helpers/ka.ts index 7aa58e5642..8f542a9f9b 100644 --- a/ui/app/peers/create/[peerType]/helpers/ka.ts +++ b/ui/app/peers/create/[peerType]/helpers/ka.ts @@ -1,30 +1,44 @@ import { KafkaConfig } from '@/grpc_generated/peers'; -import {PeerSetting } from './common'; +import { PeerSetting } from './common'; export const kaSetting: PeerSetting[] = [ { label: 'Servers', - stateHandler: (value, setter) => setter((curr) => ({...cur, servers: value.split(',') })), + stateHandler: (value, setter) => + setter((curr) => ({ ...curr, servers: (value as string).split(',') })), tips: 'Brokers', - helpfulLink: 'https://pkg.go.dev/github.com/twmb/franz-go/pkg/kgo#SeedBrokers', + helpfulLink: + 'https://pkg.go.dev/github.com/twmb/franz-go/pkg/kgo#SeedBrokers', }, { label: 'Username', - stateHandler: (value, setter) => setter((curr) => ({...cur, username: value })), + stateHandler: (value, setter) => + setter((curr) => ({ ...curr, username: value as string })), }, { label: 'Password', type: 'password', - stateHandler: (value, setter) => setter((curr) => ({...cur, password: value })), + stateHandler: (value, setter) => + setter((curr) => ({ ...curr, password: value as string })), }, { label: 'SASL Mechanism', - stateHandler: (value, setter) => setter((curr) => ({...cur, sasl: value })), - helpfulLink: 'https://docs.redpanda.com/current/manage/security/authentication/#scram', + stateHandler: (value, setter) => + setter((curr) => ({ ...curr, sasl: value as string })), + type: 'select', + helpfulLink: + 'https://docs.redpanda.com/current/manage/security/authentication/#scram', + }, + { + label: 'Disable TLS?', + stateHandler: (value, setter) => + setter((curr) => ({ ...curr, disableTls: value as boolean })), + type: 'switch', + tips: 'If you are using a non-TLS connection for Kafka server, check this box.', }, ]; -export const blankKaSetting: S3Config = { +export const blankKaSetting: KafkaConfig = { servers: [], username: '', password: '', diff --git a/ui/app/peers/create/[peerType]/page.tsx b/ui/app/peers/create/[peerType]/page.tsx index 625348264d..1bc714c6b7 100644 --- a/ui/app/peers/create/[peerType]/page.tsx +++ b/ui/app/peers/create/[peerType]/page.tsx @@ -3,7 +3,7 @@ import { PeerConfig } from '@/app/dto/PeersDTO'; import GuideForDestinationSetup from '@/app/mirrors/create/cdc/guide'; import BigqueryForm from '@/components/PeerForms/BigqueryConfig'; import ClickhouseForm from '@/components/PeerForms/ClickhouseConfig'; -import KafkaForm from '@/components/PeerForms/KafkaForm'; +import KafkaForm from '@/components/PeerForms/KafkaConfig'; import PostgresForm from '@/components/PeerForms/PostgresForm'; import S3Form from '@/components/PeerForms/S3Form'; import SnowflakeForm from '@/components/PeerForms/SnowflakeForm'; diff --git a/ui/app/peers/create/[peerType]/schema.ts b/ui/app/peers/create/[peerType]/schema.ts index 447cd2d6fe..440a718cdb 100644 --- a/ui/app/peers/create/[peerType]/schema.ts +++ b/ui/app/peers/create/[peerType]/schema.ts @@ -282,13 +282,21 @@ export const chSchema = z.object({ }); export const kaSchema = z.object({ - servers: z.array(z.string()), - username: z.string(), - password: z.string(), + servers: z.array(z.string()).min(1, { message: 'Atleast 1 server required' }), + username: z + .string({ required_error: 'Username is required' }) + .min(1, { message: 'Username cannot be empty' }), + password: z + .string({ required_error: 'Password is required' }) + .min(1, { message: 'Password cannot be empty' }), sasl: z - .union([z.literal('SCRAM-SHA-256'), z.literal('SCRAM-SHA-512')]) + .union([z.literal('SCRAM-SHA-256'), z.literal('SCRAM-SHA-512')], { + errorMap: () => ({ + message: 'Either SCRAM-SHA-256 or SCRAM-SHA-512 is required.', + }), + }) .optional(), - disableTls: z.boolean(), + disableTls: z.boolean().optional(), }); const urlSchema = z diff --git a/ui/components/PeerForms/KafkaConfig.tsx b/ui/components/PeerForms/KafkaConfig.tsx index f3c580f155..e9acc40337 100644 --- a/ui/components/PeerForms/KafkaConfig.tsx +++ b/ui/components/PeerForms/KafkaConfig.tsx @@ -1,74 +1,119 @@ 'use client'; import { PeerSetter } from '@/app/dto/PeersDTO'; import { kaSetting } from '@/app/peers/create/[peerType]/helpers/ka'; +import SelectTheme from '@/app/styles/select'; import { Label } from '@/lib/Label'; -import { RowWithRadiobutton, RowWithTextField } from '@/lib/Layout'; -import { RadioButton, RadioButtonGroup } from '@/lib/RadioButtonGroup'; +import { RowWithSelect, RowWithSwitch, RowWithTextField } from '@/lib/Layout'; +import { Switch } from '@/lib/Switch/Switch'; import { TextField } from '@/lib/TextField'; import { Tooltip } from '@/lib/Tooltip'; -import { useEffect, useState } from 'react'; +import ReactSelect from 'react-select'; import { InfoPopover } from '../InfoPopover'; - interface KafkaProps { setter: PeerSetter; } + +const saslOptions = [ + { value: 'SCRAM-SHA-256', label: 'SCRAM-SHA-256' }, + { value: 'SCRAM-SHA-512', label: 'SCRAM-SHA-512' }, +]; + const KafkaForm = ({ setter }: KafkaProps) => { return (
- + {kaSetting.map((setting, index) => { - if (displayCondition(setting.label)) - return ( - - {setting.label}{' '} - {!setting.optional && ( - - - - )} - - } - action={ -
- ) => - setting.stateHandler(e.target.value, setter) - } - /> - {setting.tips && ( - - )} -
- } - /> - ); + return setting.type === 'switch' ? ( + + {setting.label}{' '} + {!setting.optional && ( + + + + )} + + } + action={ +
+ + setting.stateHandler(state, setter) + } + /> + {setting.tips && ( + + )} +
+ } + /> + ) : setting.type === 'select' ? ( + SASL Mechanism} + action={ + + val && setting.stateHandler(val.value, setter) + } + options={saslOptions} + theme={SelectTheme} + /> + } + /> + ) : ( + + {setting.label}{' '} + {!setting.optional && ( + + + + )} + + } + action={ +
+ ) => + setting.stateHandler(e.target.value, setter) + } + /> + {setting.tips && ( + + )} +
+ } + /> + ); })}
);