Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Full width for JSON view rows #433

Merged
merged 7 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/hooks/useHotTier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const useHotTier = (streamName: string, hasSettingsAccess: boolean) => {
return {
getHotTierInfoError,
getHotTierInfoLoading,
refetchHotTierInfo,
updateHotTier,
deleteHotTier,
isDeleting,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Stream/Views/Explore/JSONView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ const JsonView = (props: {
<Box
className={classes.innerContainer}
style={{ display: 'flex', flexDirection: 'row', maxHeight: `calc(100vh - ${primaryHeaderHeight}px )` }}>
<Stack gap={0}>
<Stack gap={0} style={{ width: '100%' }}>
<Stack style={{ overflowY: 'scroll' }}>
<JsonRows isSearching={isSearching} setContextMenu={setContextMenu} />
</Stack>
Expand Down
11 changes: 4 additions & 7 deletions src/pages/Stream/Views/Explore/useLogsFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useEffect } from 'react';
import { useLogsStore, logsStoreReducers } from '../../providers/LogsProvider';
import { useQueryLogs } from '@/hooks/useQueryLogs';
import { useFetchCount } from '@/hooks/useQueryResult';
import { useStreamStore } from '../../providers/StreamProvider';
import useParamsController from '@/pages/Stream/hooks/useParamsController';
import _ from 'lodash';

Expand All @@ -18,8 +17,6 @@ const useLogsFetcher = (props: { schemaLoading: boolean; infoLoading: boolean })
const [{ tableOpts }, setLogsStore] = useLogsStore((store) => store);
const { currentOffset, currentPage, pageData } = tableOpts;
const { getQueryData, loading: logsLoading, queryLogsError } = useQueryLogs();
const [{ info }] = useStreamStore((store) => store);
const firstEventAt = 'first-event-at' in info ? info['first-event-at'] : undefined;

const { refetchCount, countLoading } = useFetchCount();
const hasContentLoaded = schemaLoading === false && logsLoading === false;
Expand All @@ -33,21 +30,21 @@ const useLogsFetcher = (props: { schemaLoading: boolean; infoLoading: boolean })
}, [currentStream]);

useEffect(() => {
if (infoLoading || !firstEventAt) return;
if (infoLoading) return;

if (currentPage === 0) {
getQueryData();
refetchCount();
}
}, [currentPage, currentStream, timeRange, infoLoading, firstEventAt]);
}, [currentPage, currentStream, timeRange, infoLoading]);

useEffect(() => {
if (infoLoading || !firstEventAt) return;
if (infoLoading) return;

if (currentOffset !== 0 && currentPage !== 0) {
getQueryData();
}
}, [currentOffset, infoLoading, firstEventAt]);
}, [currentOffset, infoLoading]);

return {
logsLoading: infoLoading || logsLoading,
Expand Down
52 changes: 32 additions & 20 deletions src/pages/Stream/Views/Manage/Info.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Group, Stack, Text } from '@mantine/core';
import { Group, Loader, Stack, Text } from '@mantine/core';
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';

const { formatDateWithTimezone } = timeRangeUtils;

Expand Down Expand Up @@ -42,7 +43,7 @@ const InfoItem = (props: { title: string; value: string; fullWidth?: boolean })
);
};

const InfoData = () => {
const InfoData = (props: { isLoading: boolean }) => {
const [info] = useStreamStore((store) => store.info);
const [currentStream] = useAppStore((store) => store.currentStream);

Expand All @@ -59,33 +60,44 @@ const InfoData = () => {

return (
<Stack style={{ flex: 1 }}>
<Stack style={{ flex: 1, padding: '1.5rem', justifyContent: 'space-between' }}>
<Stack gap={0} style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<InfoItem title="Name" value={currentStream || ''} />
<InfoItem title="Created At" value={createdAtWithTz} />
<InfoItem title="First Event At" value={firstEventAtWithTz} />
{props.isLoading ? (
<Stack style={{ flex: 1, width: '100%', alignItems: 'center', justifyContent: 'center' }}>
<Stack style={{ alignItems: 'center' }}>
<Loader />
</Stack>
</Stack>
<Stack gap={0} style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<InfoItem title="Schema Type" value={staticSchemaFlag} />
<InfoItem title="Time Partition Field" value={timePartition} />
<UpdateTimePartitionLimit timePartition={timePartition} currentStream={currentStream ? currentStream : ''} />
) : (
<Stack style={{ flex: 1, padding: '1.5rem', justifyContent: 'space-between' }}>
<Stack gap={0} style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<InfoItem title="Name" value={currentStream || ''} />
<InfoItem title="Created At" value={createdAtWithTz} />
<InfoItem title="First Event At" value={firstEventAtWithTz} />
</Stack>
<Stack gap={0} style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<InfoItem title="Schema Type" value={staticSchemaFlag} />
<InfoItem title="Time Partition Field" value={timePartition} />
<UpdateTimePartitionLimit
timePartition={timePartition}
currentStream={currentStream ? currentStream : ''}
/>
</Stack>
<Stack gap={0} style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<UpdateCustomPartitionField
currentStream={currentStream ? currentStream : ''}
timePartition={timePartition}
/>
</Stack>
</Stack>
<Stack gap={0} style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<UpdateCustomPartitionField
currentStream={currentStream ? currentStream : ''}
timePartition={timePartition}
/>
</Stack>
</Stack>
)}
</Stack>
);
};

const Info = () => {
const Info = (props: { isLoading: boolean; isError: boolean }) => {
return (
<Stack className={classes.sectionContainer} gap={0}>
<Header />
<InfoData />
{props.isError ? <ErrorView /> : <InfoData isLoading={props.isLoading} />}
</Stack>
);
};
Expand Down
5 changes: 4 additions & 1 deletion src/pages/Stream/Views/Manage/Management.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Stats from './Stats';
import { useLogStreamStats } from '@/hooks/useLogStreamStats';
import Info from './Info';
import DeleteStreamModal from '../../components/DeleteStreamModal';
import { useGetStreamInfo } from '@/hooks/useGetStreamInfo';
import { useRetentionQuery } from '@/hooks/useRetentionEditor';
import { useHotTier } from '@/hooks/useHotTier';

Expand All @@ -19,6 +20,7 @@ const Management = (props: { schemaLoading: boolean }) => {
const getStreamAlertsConfig = useAlertsQuery(currentStream || '', hasAlertsAccess, isStandAloneMode);
const getStreamStats = useLogStreamStats(currentStream || '');
const getRetentionConfig = useRetentionQuery(currentStream || '', hasSettingsAccess);
const getStreamInfo = useGetStreamInfo(currentStream || '', currentStream !== null);
const hotTierFetch = useHotTier(currentStream || '', hasSettingsAccess);

// todo - handle loading and error states separately
Expand All @@ -34,14 +36,15 @@ const Management = (props: { schemaLoading: boolean }) => {
isLoading={getStreamStats.getLogStreamStatsDataIsLoading}
isError={getStreamStats.getLogStreamStatsDataIsError}
/>
<Info />
<Info isLoading={getStreamInfo.getStreamInfoLoading} isError={getStreamInfo.getStreamInfoError} />
</Stack>
<Stack style={{ flexDirection: 'row', height: '57%' }} gap={24}>
<Stack w="49.4%">
<Settings
isLoading={isHotTierLoading || isRetentionLoading}
updateRetentionConfig={getRetentionConfig.updateLogStreamRetention}
updateHotTierInfo={hotTierFetch.updateHotTier}
refetchHotTierInfo={hotTierFetch.refetchHotTierInfo}
deleteHotTierInfo={hotTierFetch.deleteHotTier}
isDeleting={hotTierFetch.isDeleting}
isUpdating={hotTierFetch.isUpdating}
Expand Down
57 changes: 43 additions & 14 deletions src/pages/Stream/Views/Manage/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { Box, Button, Divider, Loader, Modal, NumberInput, Stack, TextInput } from '@mantine/core';
import { Box, Button, Divider, Group, Loader, Modal, NumberInput, px, Stack, TextInput } from '@mantine/core';
import classes from '../../styles/Management.module.css';
import { Text } from '@mantine/core';
import { useAppStore } from '@/layouts/MainLayout/providers/AppProvider';
import { useForm } from '@mantine/form';
import _ from 'lodash';
import { useCallback, useEffect, useState } from 'react';
import { useStreamStore } from '../../providers/StreamProvider';
import { IconCheck, IconTrash, IconX } from '@tabler/icons-react';
import { IconCheck, IconX, IconReload } from '@tabler/icons-react';
import { sanitizeBytes, convertGibToBytes } from '@/utils/formatBytes';
import timeRangeUtils from '@/utils/timeRangeUtils';
import ErrorView from './ErrorView';
import RestrictedView from '@/components/Misc/RestrictedView';
import IconButton from '@/components/Button/IconButton';

const { formatDateWithTimezone } = timeRangeUtils;

const renderRefreshIcon = () => <IconReload size={px('1rem')} stroke={1.5} />;

const Header = () => {
return (
<Stack className={classes.headerContainer} style={{ minHeight: '3rem', maxHeight: '3rem' }}>
Expand Down Expand Up @@ -168,6 +171,7 @@ const DeleteHotTierModal = (props: {

const HotTierConfig = (props: {
updateHotTierInfo: ({ size }: { size: string }) => void;
refetchHotTierInfo: () => void;
deleteHotTierInfo: ({ onSuccess }: { onSuccess: () => void }) => void;
isDeleting: boolean;
isUpdating: boolean;
Expand Down Expand Up @@ -228,21 +232,23 @@ const HotTierConfig = (props: {
/>
<Stack style={{ flexDirection: 'row', justifyContent: 'space-between' }} gap={8}>
<Text className={classes.fieldTitle}>Hot Tier Storage Size</Text>
{!hotTierNotSet && streamType === 'UserDefined' ? (
<IconTrash onClick={openDeleteModal} stroke={1.2} size="1.2rem" className={classes.deleteIcon} />
{!hotTierNotSet ? (
<Group style={{ justifyContent: 'end' }}>
<IconButton
size={38}
renderIcon={renderRefreshIcon}
onClick={props.refetchHotTierInfo}
tooltipLabel="Refresh now"
/>
</Group>
) : null}
</Stack>
<Stack style={{ flexDirection: 'row', justifyContent: 'space-between', height: '3.8rem' }}>
<Stack gap={4} style={{ ...(hotTierNotSet ? { display: 'none' } : {}) }}>
<Text className={classes.fieldDescription}>Oldest Record:</Text>
<Text className={classes.fieldDescription}>
{_.isEmpty(oldestEntry) ? 'No Entries Stored' : formatDateWithTimezone(oldestEntry)}
</Text>
</Stack>
<Stack style={{ flexDirection: 'row', height: '6.8rem' }}>
<Stack style={{ width: hotTierNotSet ? '100%' : '50%' }} gap={isDirty || hotTierNotSet ? 16 : 4}>
<Stack style={{}} gap={12}>
<Stack gap={12}>
{streamType === 'UserDefined' ? (
<NumberInput
w={hotTierNotSet ? '100%' : '50%'}
classNames={{ label: classes.fieldDescription }}
placeholder="Size in GiB"
key="size"
Expand All @@ -257,15 +263,15 @@ const HotTierConfig = (props: {
) : null}
<Text
className={classes.fieldDescription}
ta="end"
ta="start"
style={{ ...(isDirty || hotTierNotSet ? { display: 'none' } : {}) }}>
{humanizedUsedSize} used | {humanizedAvailableSize} available
</Text>
</Stack>
<Stack
style={{
flexDirection: 'row',
justifyContent: 'flex-end',
justifyContent: 'flex-start',
...(!isDirty || hotTierNotSet ? { display: 'none' } : {}),
}}
gap={12}>
Expand All @@ -289,6 +295,18 @@ const HotTierConfig = (props: {
</Stack>
{props.isUpdating && <Loader size="sm" />}
</Stack>

{!hotTierNotSet && streamType === 'UserDefined' ? (
<Stack
style={{ alignItems: 'flex-start', paddingTop: '0.8rem', ...(hotTierNotSet ? { display: 'none' } : {}) }}>
<Box>
<Button variant="outline" onClick={openDeleteModal}>
Delete
</Button>
</Box>
</Stack>
) : null}

<Stack style={{ alignItems: 'flex-end', ...(!hotTierNotSet ? { display: 'none' } : {}) }}>
<Box>
<Button onClick={onUpdate} disabled={localSizeValue <= 0} loading={props.isUpdating}>
Expand All @@ -297,6 +315,15 @@ const HotTierConfig = (props: {
</Box>
</Stack>
</Stack>
<Divider orientation="vertical" size={2} style={{ ...(hotTierNotSet ? { display: 'none' } : {}) }} />
<Stack
gap={4}
style={{ ...(hotTierNotSet ? { display: 'none' } : { display: 'flex', justifyContent: 'flex-start' }) }}>
<Text style={{ fontSize: '11.2px' }}>Oldest Record:</Text>
<Text className={classes.fieldDescription}>
{_.isEmpty(oldestEntry) ? 'No Entries Stored' : formatDateWithTimezone(oldestEntry)}
</Text>
</Stack>
</Stack>
</Stack>
);
Expand All @@ -310,6 +337,7 @@ const Settings = (props: {
isLoading: boolean;
updateRetentionConfig: ({ config }: { config: any }) => void;
updateHotTierInfo: ({ size }: { size: string }) => void;
refetchHotTierInfo: () => void;
deleteHotTierInfo: ({ onSuccess }: { onSuccess: () => void }) => void;
isDeleting: boolean;
isUpdating: boolean;
Expand All @@ -333,6 +361,7 @@ const Settings = (props: {
) : (
<>
<HotTierConfig
refetchHotTierInfo={props.refetchHotTierInfo}
updateHotTierInfo={props.updateHotTierInfo}
deleteHotTierInfo={props.deleteHotTierInfo}
isDeleting={props.isDeleting}
Expand Down
9 changes: 2 additions & 7 deletions src/pages/Stream/components/EventTimeLineGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { appStoreReducers, useAppStore } from '@/layouts/MainLayout/providers/Ap
import { LogsResponseWithHeaders } from '@/@types/parseable/api/query';
import _ from 'lodash';
import timeRangeUtils from '@/utils/timeRangeUtils';
import { useStreamStore } from '../providers/StreamProvider';

const { setTimeRange } = appStoreReducers;
const { makeTimeRangeLabel } = timeRangeUtils;
Expand Down Expand Up @@ -163,15 +162,13 @@ const EventTimeLineGraph = () => {
const [{ custSearchQuery }, setLogStore] = useLogsStore((store) => store.custQuerySearchState);
const [{ interval, startTime, endTime }] = useAppStore((store) => store.timeRange);
const [localStream, setLocalStream] = useState<string | null>('');
const [{ info }] = useStreamStore((store) => store);
const firstEventAt = 'first-event-at' in info ? info['first-event-at'] : undefined;

useEffect(() => {
setLocalStream(currentStream);
}, [currentStream]);

useEffect(() => {
if (!localStream || localStream.length === 0 || !firstEventAt) return;
if (!localStream || localStream.length === 0) return;

const totalMinutes = interval / (1000 * 60);
const numBins = Math.trunc(totalMinutes < 10 ? totalMinutes : totalMinutes < 60 ? 10 : 60);
Expand All @@ -189,15 +186,13 @@ const EventTimeLineGraph = () => {
dayjs(startTime).startOf('minute').toISOString(),
dayjs(endTime).startOf('minute').toISOString(),
custSearchQuery,
firstEventAt,
]);

const isLoading = fetchGraphDataMutation.isLoading;
const avgEventCount = useMemo(() => calcAverage(fetchGraphDataMutation?.data), [fetchGraphDataMutation?.data]);
const graphData = useMemo(() => {
if (!firstEventAt) return null;
return parseGraphData(fetchGraphDataMutation?.data, avgEventCount, interval);
}, [fetchGraphDataMutation?.data, interval, firstEventAt]);
}, [fetchGraphDataMutation?.data, interval]);
const hasData = Array.isArray(graphData) && graphData.length !== 0;
const [, setAppStore] = useAppStore((_store) => null);
const setTimeRangeFromGraph = useCallback((barValue: any) => {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Stream/components/Querier/FilterQueryBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const RuleView = (props: RuleViewType) => {
const getUniqueColValues = useMemo(() => {
if (!rule.field) return [];
return Array.from(
new Set(pageData.filter((item) => item[rule.field] !== null).map((item) => String(item[rule.field]))),
new Set(pageData.filter((item) => item[rule.field] != null).map((item) => String(item[rule.field]))),
);
}, [pageData, rule.field]);

Expand Down
14 changes: 14 additions & 0 deletions src/pages/Stream/components/Querier/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,20 @@ const QuerierModal = (props: {
}
}, [showQueryBuilder]);

useEffect(() => {
const handleKeyPress = (event: { key: string }) => {
if (event.key === 'Escape') {
onClose();
}
};

window.addEventListener('keydown', handleKeyPress);

return () => {
window.removeEventListener('keydown', handleKeyPress);
};
}, []);

return (
<Modal
opened={showQueryBuilder}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Stream/hooks/useParamsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ const useParamsController = () => {
setLogsStore((store) => setPerPage(store, _.toNumber(presentParams.rows)));
}

if (storeAsParams.fields !== presentParams.fields) {
if (storeAsParams.fields !== presentParams.fields && !_.isEmpty(presentParams.fields)) {
setLogsStore((store) => setTargetColumns(store, joinOrSplit(presentParams.fields) as string[]));
}

Expand Down
Loading
Loading