diff --git a/src/pages/Stream/Views/Manage/Info.tsx b/src/pages/Stream/Views/Manage/Info.tsx index 64d20f08..d2fec7f4 100644 --- a/src/pages/Stream/Views/Manage/Info.tsx +++ b/src/pages/Stream/Views/Manage/Info.tsx @@ -3,10 +3,9 @@ import classes from '../../styles/Management.module.css'; import { useStreamStore } from '../../providers/StreamProvider'; import _ from 'lodash'; import { useAppStore } from '@/layouts/MainLayout/providers/AppProvider'; -import UpdateTimePartitionLimit from './UpdateTimePartitionLimit'; -import UpdateCustomPartitionField from './UpdateCustomPartitionField'; import timeRangeUtils from '@/utils/timeRangeUtils'; import ErrorView from './ErrorView'; +import UpdateStreamInfo from './UpdateStreamInfo'; const { formatDateWithTimezone } = timeRangeUtils; @@ -76,16 +75,10 @@ const InfoData = (props: { isLoading: boolean }) => { - + - + )} diff --git a/src/pages/Stream/Views/Manage/UpdateCustomPartitionField.tsx b/src/pages/Stream/Views/Manage/UpdateCustomPartitionField.tsx deleted file mode 100644 index 2eba0307..00000000 --- a/src/pages/Stream/Views/Manage/UpdateCustomPartitionField.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { Box, Group, Loader, Stack, TagsInput, Tooltip, Text } from '@mantine/core'; -import classes from '../../styles/Management.module.css'; -import { IconCheck, IconX, IconEdit } from '@tabler/icons-react'; -import { useStreamStore } from '../../providers/StreamProvider'; -import _ from 'lodash'; -import { useCallback, useEffect, useState } from 'react'; -import { useLogStream } from '@/hooks/useLogStream'; -import { useGetStreamInfo } from '@/hooks/useGetStreamInfo'; - -const UpdateFieldButtons = (props: { onClose: () => void; onUpdateClick: () => void; isUpdating: boolean }) => { - return ( - - {!props.isUpdating ? ( - - - props.onUpdateClick()} stroke={1.6} size={16} /> - - - - props.onClose()} /> - - - ) : ( - - )} - - ); -}; - -export default function UpdateCustomPartitionField(props: { timePartition: string; currentStream: string }) { - const [info] = useStreamStore((store) => store.info); - const isStaticSchema = _.get(info, 'static_schema_flag', false); - const existingCustomPartition = _.get(info, 'custom_partition', '-').split(','); - const [partitionFields] = useStreamStore((store) => store.fieldNames); - const [value, setValue] = useState([]); - const [updating, setUpdating] = useState(false); - const [showEditField, setShowEditField] = useState(false); - const [error, setError] = useState(null); - const { updateLogStreamMutation } = useLogStream(); - const { getStreamInfoRefetch } = useGetStreamInfo(props.currentStream, props.currentStream !== null); - - useEffect(() => { - const customPartition: string = _.get(info, 'custom_partition', 'EMPTY_VALUE'); - setValue(customPartition !== 'EMPTY_VALUE' ? customPartition.split(',') : []); - }, [props.currentStream, info]); - - const onChangeValue = useCallback( - (value: string[]) => { - setValue(value); - - if (isStaticSchema) { - value?.forEach((el) => { - if (!partitionFields.includes(el)) { - setError('Unknown Field Included'); - } else { - setError(null); - } - }); - } - if (Array.isArray(value) && value.length === 0) { - setError(null); - } - }, - [setValue], - ); - - const updateLogStreamSuccess = useCallback(() => { - getStreamInfoRefetch().then(() => { - setUpdating(false); - setShowEditField(false); - }); - }, [getStreamInfoRefetch]); - - const updateLogStream = useCallback( - (updatedValue: string) => { - updateLogStreamMutation({ - streamName: props.currentStream, - header: { 'x-p-custom-partition': updatedValue }, - onSuccess: updateLogStreamSuccess, - onError: () => { - setUpdating(false), setValue(existingCustomPartition); - }, - }); - }, - [props.currentStream, updateLogStreamMutation], - ); - - const updateCustomPartition = useCallback(() => { - const valuesFlattened = value?.join(','); - - if (valuesFlattened === undefined) return; - if (error !== null) return; - - setUpdating(true); - updateLogStream(valuesFlattened); - }, [value, updateLogStream]); - - return ( - - - - Custom Partition Field - - - - setShowEditField((prev) => !prev)} - /> - - - {showEditField ? ( - - onChangeValue(value)} - maxTags={3} - value={value?.length === 1 && value?.[0] === '' ? undefined : value} - error={error} - /> - setShowEditField(false)} - isUpdating={updating} - /> - - ) : ( - - {existingCustomPartition.join(',')} - - )} - - ); -} diff --git a/src/pages/Stream/Views/Manage/UpdateStreamInfo.tsx b/src/pages/Stream/Views/Manage/UpdateStreamInfo.tsx new file mode 100644 index 00000000..11c0f9cd --- /dev/null +++ b/src/pages/Stream/Views/Manage/UpdateStreamInfo.tsx @@ -0,0 +1,216 @@ +import { Box, Group, Loader, Stack, TagsInput, Tooltip, Text, TextInput } from '@mantine/core'; +import classes from '../../styles/Management.module.css'; +import { IconCheck, IconX, IconEdit } from '@tabler/icons-react'; +import { useStreamStore } from '../../providers/StreamProvider'; +import _ from 'lodash'; +import { ChangeEvent, FC, useCallback, useEffect, useState } from 'react'; +import { useLogStream } from '@/hooks/useLogStream'; +import { useGetStreamInfo } from '@/hooks/useGetStreamInfo'; + +interface UpdateFieldButtonsProps { + onClose: () => void; + onUpdateClick: () => void; + isUpdating: boolean; +} + +interface PartitionLimitProps { + timePartition: string; + currentStream: string; +} + +type PartitionValue = string[] | number | undefined; + +const UpdateFieldButtons: FC = ({ onClose, onUpdateClick, isUpdating }) => { + return ( + + {!isUpdating ? ( + + + onUpdateClick()} stroke={1.6} size={16} /> + + + + onClose()} /> + + + ) : ( + + )} + + ); +}; + +const UpdateStreamInfo: FC = ({ timePartition, currentStream }) => { + const [info] = useStreamStore((store) => store.info); + const [partitionFields] = useStreamStore((store) => store.fieldNames); + + const isStaticSchema = _.get(info, 'static_schema_flag', false); + const initialPartitionValue = isStaticSchema + ? _.get(info, 'custom_partition', '-').split(',') + : _.get(info, 'time_partition_limit'); + + const [value, setValue] = useState(initialPartitionValue); + const [updating, setUpdating] = useState(false); + const [error, setError] = useState(null); + const [showEditField, setShowEditField] = useState(false); + + const { updateLogStreamMutation } = useLogStream(); + const { getStreamInfoRefetch } = useGetStreamInfo(currentStream, currentStream !== null); + + useEffect(() => { + setValue(initialPartitionValue); + }, [currentStream, info, initialPartitionValue]); + + const handleCustomPartitionChange = useCallback( + (value: string[]) => { + setValue(value); + + if (isStaticSchema) { + value?.forEach((el) => { + if (!partitionFields.includes(el)) { + setError('Unknown Field Included'); + } else { + setError(null); + } + }); + } + if (Array.isArray(value) && value.length === 0) { + setError(null); + } + }, + [setValue], + ); + + const handleTimePartitionChange = useCallback( + (e: ChangeEvent) => { + const inputTime = e.target.value; + const numberRegex = /^\d*$/; + if (numberRegex.test(inputTime)) { + const parsedValue = parseInt(inputTime); + if (parsedValue > 0) { + setValue(parsedValue); + setError(null); + } else { + setValue(0); + setError('Number should be higher than zero'); + } + } + }, + [setValue], + ); + + const updateLogStreamSuccess = useCallback(() => { + getStreamInfoRefetch().then(() => { + setUpdating(false); + setShowEditField(false); + }); + }, [getStreamInfoRefetch]); + + const updateLogStream = useCallback( + (updatedValue: string | number) => { + updateLogStreamMutation({ + streamName: currentStream, + header: isStaticSchema + ? { 'x-p-custom-partition': String(updatedValue) } + : { 'x-p-time-partition-limit': `${updatedValue}d` }, + onSuccess: updateLogStreamSuccess, + onError: () => setUpdating(false), + }); + }, + [updateLogStreamMutation, currentStream, isStaticSchema], + ); + + const updatePartitionLimit = useCallback(() => { + if (error) return; + if (isStaticSchema) { + if (!Array.isArray(value) || value.length === 0) return; + setUpdating(true); + updateLogStream(value.join(',')); + } else { + if (typeof value !== 'number') return; + setUpdating(true); + updateLogStream(value); + } + }, [value, updateLogStream]); + + return ( + + + + {isStaticSchema ? 'Custom Partition Field' : 'Max Historical Difference'} + + + {timePartition !== '-' && !isStaticSchema && ( + + setShowEditField((prev) => !prev)} + /> + + )} + {isStaticSchema && !showEditField && ( + + setShowEditField((prev) => !prev)} + /> + + )} + + + {showEditField ? ( + + {isStaticSchema ? ( + + ) : ( + + )} + + setShowEditField(false)} + isUpdating={updating} + /> + + ) : ( + + {isStaticSchema + ? Array.isArray(value) + ? value.join(',') + : '-' + : typeof value === 'number' + ? `${value} day(s)` + : '-'} + + )} + + ); +}; + +export default UpdateStreamInfo; diff --git a/src/pages/Stream/Views/Manage/UpdateTimePartitionLimit.tsx b/src/pages/Stream/Views/Manage/UpdateTimePartitionLimit.tsx deleted file mode 100644 index ed868125..00000000 --- a/src/pages/Stream/Views/Manage/UpdateTimePartitionLimit.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import _ from 'lodash'; -import { useStreamStore } from '../../providers/StreamProvider'; -import { ChangeEvent, useCallback, useState, useEffect } from 'react'; -import { useLogStream } from '@/hooks/useLogStream'; -import { useGetStreamInfo } from '@/hooks/useGetStreamInfo'; -import { Box, Loader, Stack, TextInput, Tooltip, Text, Group } from '@mantine/core'; -import { IconCheck, IconX, IconEdit } from '@tabler/icons-react'; -import classes from '../../styles/Management.module.css'; - -const UpdateFieldButtons = (props: { onClose: () => void; onUpdateClick: () => void; isUpdating: boolean }) => { - return ( - - {!props.isUpdating ? ( - - - props.onUpdateClick()} stroke={1.6} size={16} /> - - - - props.onClose()} /> - - - ) : ( - - )} - - ); -}; - -function UpdateTimePartitionLimit(props: { timePartition: string; currentStream: string }) { - const [info] = useStreamStore((store) => store.info); - const timePartitonLimit = _.get(info, 'time_partition_limit'); - const [value, setValue] = useState(timePartitonLimit); - const [updating, setUpdating] = useState(false); - const [error, setError] = useState(null); - const [showEditField, setShowEditField] = useState(false); - const { updateLogStreamMutation } = useLogStream(); - const { getStreamInfoRefetch } = useGetStreamInfo(props.currentStream, props.currentStream !== null); - - useEffect(() => { - setValue(timePartitonLimit); - }, [props.currentStream, info]); - - const onChange = useCallback( - (e: ChangeEvent) => { - const inputTime = e.target.value; - const numberRegex = /^\d*$/; - if (numberRegex.test(inputTime)) { - if (parseInt(inputTime) > 0) { - setValue(parseInt(inputTime)); - setError(null); - } else { - setValue(0); - setError('Number should be higher than zero'); - } - } - }, - [setValue], - ); - - const updateLogStreamSuccess = useCallback(() => { - getStreamInfoRefetch().then(() => { - setUpdating(false); - setShowEditField(false); - }); - }, [getStreamInfoRefetch]); - - const updateLogStream = useCallback( - (updatedValue: number) => { - updateLogStreamMutation({ - streamName: props.currentStream, - header: { 'x-p-time-partition-limit': `${updatedValue}d` }, - onSuccess: updateLogStreamSuccess, - onError: () => setUpdating(false), - }); - }, - [updateLogStreamMutation, props.currentStream], - ); - - const updateTimePartitionLimit = useCallback(() => { - if (value === undefined) return; - if (error !== null) return; - - setUpdating(true); - updateLogStream(value); - }, [value, updateLogStream]); - - return ( - - - - Max Historical Difference - - - {props.timePartition !== '-' && ( - - setShowEditField((prev) => !prev)} - /> - - )} - - {showEditField ? ( - - onChange(e)} - error={error} - /> - setShowEditField(false)} - isUpdating={updating} - /> - - ) : ( - - {timePartitonLimit !== undefined ? `${timePartitonLimit} day(s)` : '-'} - - )} - - ); -} - -export default UpdateTimePartitionLimit;