import React from 'react'; import * as NiceModal from '@ebay/nice-modal-react'; import type {SelectOption} from '@gravity-ui/uikit'; import { Alert, Dialog, Disclosure, Divider, Flex, HelpMark, Link, Popover, SegmentedRadioGroup, Select, Switch, Text, TextInput, } from '@gravity-ui/uikit'; import {zodResolver} from '@hookform/resolvers/zod'; import {Controller, useForm} from 'react-hook-form'; import {ResponseError} from '../../../components/Errors/ResponseError'; import {Loader} from '../../../components/Loader'; import {useClusterWithProxy} from '../../../store/reducers/cluster/cluster'; import {selectTopicFormValues, topicApi} from '../../../store/reducers/topic/topic'; import type {TopicFormValues} from '../../../store/reducers/topic/utils'; import {AutoPartitioningStrategy} from '../../../store/reducers/topic/utils'; import {cn} from '../../../utils/cn'; import {BRAND_BUTTON_CLASS} from '../../../utils/constants'; import createToast from '../../../utils/createToast'; import {prepareCommonErrorMessage} from '../../../utils/errors'; import {useTypedSelector} from '../../../utils/hooks'; import i18n from './i18n'; import { TOPIC_FORM_DIALOG, acceptNumber, buildFullTopicPath, formatBandwidthBytes, formatNumberInput, formatWriteQuotaSelectValue, getCreateTopicInitialValues, getUpdateTopicInitialValues, parseNumberInput, } from './utils'; import {getTopicFormValidationSchema} from './validation'; import './TopicFormDialog.scss'; const b = cn('ydb-topic-form-dialog'); type TopicFormMode = 'create' | 'update'; type DialogSuccessHandler = (path: string) => void; interface CommonDialogProps { mode: TopicFormMode; database: string; databaseFullPath: string; parentPath?: string; topicPath?: string; onSuccess?: DialogSuccessHandler; } interface TopicFormDialogNiceModalProps extends CommonDialogProps { onClose?: () => void; } interface TopicFormDialogProps extends Omit { open: boolean; onClose: () => void; onSuccess: DialogSuccessHandler; } interface TopicFormProps { mode: TopicFormMode; database: string; databaseFullPath: string; initialValues: TopicFormValues; onClose: () => void; onSuccess: DialogSuccessHandler; nameInputRef?: React.Ref; } const writeQuotaOptions: SelectOption[] = [128, 512, 1024].map((value) => ({ content: formatBandwidthBytes(value * 1024), value: String(value * 1024), })); function isEditableAutoPartitioningMode(mode?: string) { return mode === AutoPartitioningStrategy.ScaleUp || mode === AutoPartitioningStrategy.Paused; } function MarkdownNote({text}: {text: string}) { const content = React.useMemo(() => { const parts: React.ReactNode[] = []; const linkRegexp = /\[([^\]]+)]\(([^)]+)\)/g; let lastIndex = 0; let match = linkRegexp.exec(text); while (match) { if (match.index > lastIndex) { parts.push(text.slice(lastIndex, match.index)); } parts.push( {match[1]} , ); lastIndex = linkRegexp.lastIndex; match = linkRegexp.exec(text); } if (lastIndex < text.length) { parts.push(text.slice(lastIndex)); } return parts; }, [text]); return ( {content} ); } function FormSection({title, children}: {title?: string; children: React.ReactNode}) { return (
{title ? ( {title} ) : null} {children}
); } function FormRow({ title, note, htmlFor, children, }: { title: string; note?: string; htmlFor?: string; children: React.ReactNode; }) { return (
{htmlFor ? ( ) : ( {title} )} {note ? ( ) : null}
{children}
); } function FixedValue({value}: {value?: string | number}) { return ( {value} ); } function IncompatiblePopover({content, children}: {content: string; children: React.ReactElement}) { return ( {children} ); } function NumericTextInput({ id, value, onChange, errorMessage, invalid, endContent, className, disabled, }: { id?: string; value?: number; onChange: (value: number) => void; errorMessage?: string; invalid?: boolean; endContent?: React.ReactNode; className?: string; disabled?: boolean; }) { const handleUpdate = React.useCallback( (nextValue: string) => { if (acceptNumber(nextValue)) { onChange(parseNumberInput(nextValue)); } }, [onChange], ); return ( ); } function SelectNumberField({ value, onChange, options, errorMessage, formatSelectedValue, }: { value?: number; onChange: (value: number | undefined) => void; options: SelectOption[]; errorMessage?: string; formatSelectedValue?: (value: number) => string; }) { const handleUpdate = React.useCallback( ([nextValue]: string[]) => { onChange(nextValue ? Number(nextValue) : undefined); }, [onChange], ); const renderSelectedOption = React.useCallback( (option: SelectOption) => ( {option.content ?? (formatSelectedValue ? formatSelectedValue(Number(option.value)) : option.value)} ), [formatSelectedValue], ); return (