diff --git a/src/hooks/useGetStreamInfo.tsx b/src/hooks/useGetStreamInfo.tsx index 6153553c..76530e3b 100644 --- a/src/hooks/useGetStreamInfo.tsx +++ b/src/hooks/useGetStreamInfo.tsx @@ -1,5 +1,7 @@ import { getLogStreamInfo } from '@/api/logStream'; import { useStreamStore, streamStoreReducers } from '@/pages/Stream/providers/StreamProvider'; +import { notifyError } from '@/utils/notification'; +import { AxiosError, isAxiosError } from 'axios'; import { useQuery } from 'react-query'; const { setStreamInfo } = streamStoreReducers; @@ -17,7 +19,17 @@ export const useGetStreamInfo = (currentStream: string) => { refetchOnWindowFocus: false, refetchOnMount: true, enabled: currentStream !== '', - onSuccess: (data) => setStreamStore((store) => setStreamInfo(store, data)), + onSuccess: (data) => { + setStreamStore((store) => setStreamInfo(store, data)) + }, + onError: (data: AxiosError) => { + if (isAxiosError(data) && data.response) { + const error = data.response?.data as string; + typeof error === 'string' && notifyError({ message: error }); + } else if (data.message && typeof data.message === 'string') { + notifyError({ message: data.message }); + } + }, }); return { diff --git a/src/hooks/useLogStreamStats.tsx b/src/hooks/useLogStreamStats.tsx index ad48da7c..c1bc3d11 100644 --- a/src/hooks/useLogStreamStats.tsx +++ b/src/hooks/useLogStreamStats.tsx @@ -2,6 +2,8 @@ import { useQuery } from 'react-query'; import { getLogStreamStats } from '@/api/logStream'; import { Dayjs } from 'dayjs'; import { useStreamStore, streamStoreReducers } from '@/pages/Stream/providers/StreamProvider'; +import { notifyError } from '@/utils/notification'; +import { AxiosError, isAxiosError } from 'axios'; const { setStats } = streamStoreReducers; @@ -18,6 +20,14 @@ export const useLogStreamStats = (streamName: string, fetchStartTime?: Dayjs) => onSuccess: (data) => { setStreamStore((store) => setStats(store, data)); }, + onError: (data: AxiosError) => { + if (isAxiosError(data) && data.response) { + const error = data.response?.data as string; + typeof error === 'string' && notifyError({ message: error }); + } else if (data.message && typeof data.message === 'string') { + notifyError({ message: data.message }); + } + }, refetchOnWindowFocus: false, }); diff --git a/src/hooks/useRetentionEditor.tsx b/src/hooks/useRetentionEditor.tsx index 37fb9518..ffbd5f1e 100644 --- a/src/hooks/useRetentionEditor.tsx +++ b/src/hooks/useRetentionEditor.tsx @@ -20,6 +20,14 @@ export const useRetentionQuery = (streamName: string) => { const retentionData = _.isArray(data.data) ? data.data[0] || {} : {}; setStreamStore((store) => setRetention(store, retentionData)); }, + onError: (data: AxiosError) => { + if (isAxiosError(data) && data.response) { + const error = data.response?.data as string; + typeof error === 'string' && notifyError({ message: error }); + } else if (data.message && typeof data.message === 'string') { + notifyError({ message: data.message }); + } + }, retry: false, enabled: streamName !== '', refetchOnWindowFocus: false, diff --git a/src/pages/Stream/Views/Manage/Alerts.tsx b/src/pages/Stream/Views/Manage/Alerts.tsx index aca80db4..2a83b14f 100644 --- a/src/pages/Stream/Views/Manage/Alerts.tsx +++ b/src/pages/Stream/Views/Manage/Alerts.tsx @@ -18,6 +18,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { IconEdit, IconInfoCircleFilled, IconPlus, IconTrash } from '@tabler/icons-react'; import { UseFormReturnType, useForm } from '@mantine/form'; import { useStreamStore, streamStoreReducers } from '../../providers/StreamProvider'; +import ErrorView from './ErrorView'; const defaultColumnTypeConfig = { column: '', operator: '=', value: '', repeats: 1, ignoreCase: false }; const defaultColumnTypeRule = { type: 'column' as 'column', config: defaultColumnTypeConfig }; @@ -657,6 +658,7 @@ const AlertList = (props: { const Alerts = (props: { isLoading: boolean; schemaLoading: boolean; + isError: boolean; updateAlerts: ({ config, onSuccess }: { config: any; onSuccess?: () => void }) => void; }) => { const [alertName, setAlertName] = useState(''); @@ -675,7 +677,15 @@ const Alerts = (props: {
- + {props.isError ? ( + + ) : ( + + )} ); }; diff --git a/src/pages/Stream/Views/Manage/ErrorView.tsx b/src/pages/Stream/Views/Manage/ErrorView.tsx new file mode 100644 index 00000000..c9b15db4 --- /dev/null +++ b/src/pages/Stream/Views/Manage/ErrorView.tsx @@ -0,0 +1,15 @@ +import { Stack, Text } from '@mantine/core'; +import { IconAlertTriangle } from '@tabler/icons-react'; +import classes from '../../styles/ErrorView.module.css'; + +const ErrorView = (props: { msg?: string }) => { + const { msg = 'Something went wrong' } = props; + return ( + + + {msg} + + ); +}; + +export default ErrorView; diff --git a/src/pages/Stream/Views/Manage/Info.tsx b/src/pages/Stream/Views/Manage/Info.tsx index 371b38ab..64d20f08 100644 --- a/src/pages/Stream/Views/Manage/Info.tsx +++ b/src/pages/Stream/Views/Manage/Info.tsx @@ -6,6 +6,7 @@ import { useAppStore } from '@/layouts/MainLayout/providers/AppProvider'; import UpdateTimePartitionLimit from './UpdateTimePartitionLimit'; import UpdateCustomPartitionField from './UpdateCustomPartitionField'; import timeRangeUtils from '@/utils/timeRangeUtils'; +import ErrorView from './ErrorView'; const { formatDateWithTimezone } = timeRangeUtils; @@ -92,11 +93,11 @@ const InfoData = (props: { isLoading: boolean }) => { ); }; -const Info = (props: { isLoading: boolean }) => { +const Info = (props: { isLoading: boolean; isError: boolean }) => { return (
- + {props.isError ? : } ); }; diff --git a/src/pages/Stream/Views/Manage/Management.tsx b/src/pages/Stream/Views/Manage/Management.tsx index 0b903031..5f789923 100644 --- a/src/pages/Stream/Views/Manage/Management.tsx +++ b/src/pages/Stream/Views/Manage/Management.tsx @@ -21,19 +21,17 @@ const Management = (props: { schemaLoading: boolean }) => { const hotTierFetch = useHotTier(currentStream || ''); // todo - handle loading and error states separately - const isStatsLoading = getStreamStats.getLogStreamStatsDataIsLoading || getStreamStats.getLogStreamStatsDataIsError; const isAlertsLoading = getStreamAlertsConfig.isError || getStreamAlertsConfig.isLoading; const isRetentionLoading = - getRetentionConfig.getLogRetentionIsLoading || getRetentionConfig.getLogRetentionIsError || instanceConfig === null; - const isStreamInfoLoading = getStreamInfo.getStreamInfoLoading || getStreamInfo.getStreamInfoError; + getRetentionConfig.getLogRetentionIsLoading || instanceConfig === null; const isHotTierLoading = hotTierFetch.getHotTierInfoLoading; return ( - - + + @@ -44,12 +42,14 @@ const Management = (props: { schemaLoading: boolean }) => { deleteHotTierInfo={hotTierFetch.deleteHotTier} isDeleting={hotTierFetch.isDeleting} isUpdating={hotTierFetch.isUpdating} + isRetentionError={getRetentionConfig.getLogRetentionIsError} /> diff --git a/src/pages/Stream/Views/Manage/Settings.tsx b/src/pages/Stream/Views/Manage/Settings.tsx index 4f9d0611..081904e4 100644 --- a/src/pages/Stream/Views/Manage/Settings.tsx +++ b/src/pages/Stream/Views/Manage/Settings.tsx @@ -9,6 +9,7 @@ import { useStreamStore } from '../../providers/StreamProvider'; import { IconCheck, IconTrash, IconX } from '@tabler/icons-react'; import { sanitizeBytes, convertGibToBytes } from '@/utils/formatBytes'; import timeRangeUtils from '@/utils/timeRangeUtils'; +import ErrorView from './ErrorView'; const { formatDateWithTimezone } = timeRangeUtils; @@ -311,6 +312,7 @@ const Settings = (props: { deleteHotTierInfo: ({ onSuccess }: { onSuccess: () => void }) => void; isDeleting: boolean; isUpdating: boolean; + isRetentionError: boolean; }) => { const [isStandAloneMode] = useAppStore((store) => store.isStandAloneMode); return ( @@ -336,7 +338,11 @@ const Settings = (props: { Retention - + {!props.isRetentionError ? ( + + ) : ( + + )} )} diff --git a/src/pages/Stream/Views/Manage/Stats.tsx b/src/pages/Stream/Views/Manage/Stats.tsx index 0f981011..6700850a 100644 --- a/src/pages/Stream/Views/Manage/Stats.tsx +++ b/src/pages/Stream/Views/Manage/Stats.tsx @@ -4,6 +4,7 @@ import { useStreamStore } from '../../providers/StreamProvider'; import _ from 'lodash'; import { calcCompressionRate, sanitizeBytes, sanitizeEventsCount } from '@/utils/formatBytes'; import { IconArrowDown } from '@tabler/icons-react'; +import ErrorView from './ErrorView'; const Header = () => { return ( @@ -188,11 +189,11 @@ const StatsTable = (props: { isLoading: boolean }) => { ); }; -const Stats = (props: { isLoading: boolean }) => { +const Stats = (props: { isLoading: boolean; isError: boolean }) => { return (
- + {!props.isError ? : } ); }; diff --git a/src/pages/Stream/styles/ErrorView.module.css b/src/pages/Stream/styles/ErrorView.module.css new file mode 100644 index 00000000..17c12daa --- /dev/null +++ b/src/pages/Stream/styles/ErrorView.module.css @@ -0,0 +1,8 @@ + +.warningIcon { + color: var(--mantine-color-gray-5); +} + +.errorMsgText { + color: var(--mantine-color-gray-5); +} \ No newline at end of file