feat: handle save views

This commit is contained in:
Yunus M 2025-08-06 13:11:55 +05:30
parent 7363cf43b1
commit b3551bf140
10 changed files with 86 additions and 38 deletions

View File

@ -4,6 +4,6 @@ import { AllViewsProps } from 'types/api/saveViews/types';
import { DataSource } from 'types/common/queryBuilder';
export const getAllViews = (
sourcepage: DataSource,
sourcepage: DataSource | 'meter',
): Promise<AxiosResponse<AllViewsProps>> =>
axios.get(`/explorer/views?sourcePage=${sourcepage}`);

View File

@ -111,6 +111,7 @@ function ExplorerOptions({
const isLogsExplorer = sourcepage === DataSource.LOGS;
const isMetricsExplorer = sourcepage === DataSource.METRICS;
const isMeterExplorer = signalSource === 'meter';
const PRESERVED_VIEW_LOCAL_STORAGE_KEY = LOCALSTORAGE.LAST_USED_SAVED_VIEWS;
@ -121,8 +122,11 @@ function ExplorerOptions({
if (isMetricsExplorer) {
return PreservedViewsTypes.METRICS;
}
if (isMeterExplorer) {
return PreservedViewsTypes.METER;
}
return PreservedViewsTypes.TRACES;
}, [isLogsExplorer, isMetricsExplorer]);
}, [isLogsExplorer, isMetricsExplorer, isMeterExplorer]);
const onModalToggle = useCallback((value: boolean) => {
setIsExport(value);
@ -151,6 +155,10 @@ function ExplorerOptions({
[MetricsExplorerEventKeys.OneChartPerQueryEnabled]: isOneChartPerQuery,
panelType,
});
} else if (isMeterExplorer) {
logEvent('Meter Explorer: Save view clicked', {
panelType,
});
}
setIsSaveModalOpen(!isSaveModalOpen);
};
@ -244,7 +252,7 @@ function ExplorerOptions({
error,
isRefetching,
refetch: refetchAllView,
} = useGetAllViews(sourcepage);
} = useGetAllViews(isMeterExplorer ? 'meter' : sourcepage);
const compositeQuery = mapCompositeQueryFromQuery(currentQuery, panelType);
@ -317,7 +325,7 @@ function ExplorerOptions({
compositeQuery,
viewKey,
extraData: updatedExtraData,
sourcePage: sourcepage,
sourcePage: isMeterExplorer ? 'meter' : sourcepage,
viewName,
});
@ -333,7 +341,7 @@ function ExplorerOptions({
compositeQuery: mapCompositeQueryFromQuery(currentQuery, panelType),
viewKey,
extraData: updatedExtraData,
sourcePage: sourcepage,
sourcePage: isMeterExplorer ? 'meter' : sourcepage,
viewName,
},
{
@ -460,6 +468,11 @@ function ExplorerOptions({
panelType,
viewName: option?.value,
});
} else if (isMeterExplorer) {
logEvent('Meter Explorer: Select view', {
panelType,
viewName: option?.value,
});
}
updatePreservedViewInLocalStorage(option);
@ -555,7 +568,7 @@ function ExplorerOptions({
redirectWithQueryBuilderData,
refetchAllView,
saveViewAsync,
sourcePage: sourcepage,
sourcePage: isMeterExplorer ? 'meter' : sourcepage,
viewName: newViewName,
setNewViewName,
});
@ -674,7 +687,7 @@ function ExplorerOptions({
return `Query ${query.builder.queryData[0].queryName}`;
};
const alertButton = useMemo(() => {
const CreateAlertButton = useMemo(() => {
if (isOneChartPerQuery) {
const selectLabel = (
<Button
@ -727,7 +740,7 @@ function ExplorerOptions({
splitedQueries,
]);
const dashboardButton = useMemo(() => {
const AddToDashboardButton = useMemo(() => {
if (isOneChartPerQuery) {
const selectLabel = (
<Button
@ -890,10 +903,13 @@ function ExplorerOptions({
<hr className={isEditDeleteSupported ? '' : 'hidden'} />
<div className={cx('actions', isEditDeleteSupported ? '' : 'hidden')}>
{alertButton}
{dashboardButton}
</div>
{signalSource !== 'meter' && (
<div className={cx('actions', isEditDeleteSupported ? '' : 'hidden')}>
{CreateAlertButton}
{AddToDashboardButton}
</div>
)}
<div className="actions">
{/* Hide the info icon for metrics explorer until we get the docs link */}
{!isMetricsExplorer && (

View File

@ -2,4 +2,5 @@ export enum PreservedViewsTypes {
LOGS = 'logs',
TRACES = 'traces',
METRICS = 'metrics',
METER = 'meter',
}

View File

@ -13,7 +13,7 @@ import { PreservedViewsTypes } from './constants';
export interface SaveNewViewHandlerProps {
viewName: string;
compositeQuery: ICompositeMetricQuery;
sourcePage: DataSource;
sourcePage: DataSource | 'meter';
extraData: SaveViewProps['extraData'];
panelType: PANEL_TYPES | null;
notifications: NotificationInstance;
@ -32,7 +32,8 @@ export interface SaveNewViewHandlerProps {
export type PreservedViewType =
| PreservedViewsTypes.LOGS
| PreservedViewsTypes.TRACES
| PreservedViewsTypes.METRICS;
| PreservedViewsTypes.METRICS
| PreservedViewsTypes.METER;
export type PreservedViewsInLocalStorage = Partial<
Record<PreservedViewType, { key: string; value: string }>

View File

@ -37,7 +37,7 @@ export const saveNewViewHandler = ({
{
viewName,
compositeQuery,
sourcePage,
sourcePage: sourcePage as DataSource,
extraData,
},
{

View File

@ -173,6 +173,22 @@
padding-bottom: 80px;
}
.meter-time-series-container {
display: flex;
flex-direction: column;
gap: 10px;
.builder-units-filter {
padding: 0 8px;
margin-bottom: 0px !important;
.builder-units-filter-label {
margin-bottom: 0px !important;
font-size: 13px;
}
}
}
.lightMode {
.metrics-explorer-explore-container {
.explore-tabs {

View File

@ -2,12 +2,13 @@ import { isAxiosError } from 'axios';
import { ENTITY_VERSION_V5 } from 'constants/app';
import { initialQueryMeterWithType, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { BuilderUnitsFilter } from 'container/QueryBuilder/filters/BuilderUnitsFilter';
import TimeSeriesView from 'container/TimeSeriesView/TimeSeriesView';
import { convertDataValueToMs } from 'container/TimeSeriesView/utils';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
import { useErrorModal } from 'providers/ErrorModalProvider';
import { useMemo } from 'react';
import { useMemo, useState } from 'react';
import { useQueries } from 'react-query';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
@ -25,6 +26,8 @@ function TimeSeries(): JSX.Element {
GlobalReducer
>((state) => state.globalTime);
const [yAxisUnit, setYAxisUnit] = useState<string>('');
const isValidToConvertToMs = useMemo(() => {
const isValid: boolean[] = [];
@ -107,23 +110,31 @@ function TimeSeries(): JSX.Element {
[data, isValidToConvertToMs],
);
const onUnitChangeHandler = (value: string): void => {
setYAxisUnit(value);
};
return (
<div className="time-series-container">
{responseData.map((datapoint, index) => (
<div
className="time-series-view-panel"
// eslint-disable-next-line react/no-array-index-key
key={index}
>
<TimeSeriesView
isFilterApplied={false}
isError={queries[index].isError}
isLoading={queries[index].isLoading}
data={datapoint}
dataSource={DataSource.METRICS}
/>
</div>
))}
<div className="meter-time-series-container">
<BuilderUnitsFilter onChange={onUnitChangeHandler} yAxisUnit={yAxisUnit} />
<div className="time-series-container">
{responseData.map((datapoint, index) => (
<div
className="time-series-view-panel"
// eslint-disable-next-line react/no-array-index-key
key={index}
>
<TimeSeriesView
isFilterApplied={false}
isError={queries[index].isError}
isLoading={queries[index].isLoading}
data={datapoint}
dataSource={DataSource.METRICS}
yAxisUnit={yAxisUnit}
/>
</div>
))}
</div>
</div>
);
}

View File

@ -30,8 +30,10 @@ function BuilderUnitsFilter({
};
return (
<Space>
<DefaultLabel>Y-axis unit</DefaultLabel>
<Space className="builder-units-filter">
<DefaultLabel className="builder-units-filter-label">
Y-axis unit
</DefaultLabel>
<Select
getPopupContainer={popupContainer}
style={selectStyles}

View File

@ -269,8 +269,9 @@ export const defaultMoreMenuItems: SidebarItem[] = [
key: ROUTES.METER_EXPLORER,
label: 'Meter Explorer',
icon: <ChartArea size={16} />,
isNew: true,
isEnabled: true,
isNew: false,
isEnabled: false,
isBeta: true,
itemKey: 'meter-explorer',
},
{

View File

@ -5,9 +5,9 @@ import { AllViewsProps } from 'types/api/saveViews/types';
import { DataSource } from 'types/common/queryBuilder';
export const useGetAllViews = (
sourcepage: DataSource,
sourcepage: DataSource | 'meter',
): UseQueryResult<AxiosResponse<AllViewsProps>, AxiosError> =>
useQuery<AxiosResponse<AllViewsProps>, AxiosError>({
queryKey: [{ sourcepage }],
queryFn: () => getAllViews(sourcepage),
queryFn: () => getAllViews(sourcepage as DataSource),
});