From 40eddb110a6309b172b83ceaf3a94fc4f4bfd661 Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Mon, 3 Jun 2024 15:01:42 +0530 Subject: [PATCH 1/4] feat: base setup for individual column type units --- .../src/container/GridTableComponent/index.tsx | 2 ++ .../RightContainer/YAxisUnitSelector.tsx | 3 ++- .../NewWidget/RightContainer/constants.ts | 15 ++++++++++++++- .../NewWidget/RightContainer/index.tsx | 18 +++++++++++++++++- frontend/src/container/NewWidget/index.tsx | 12 +++++++++++- frontend/src/types/api/dashboard/getAll.ts | 4 ++++ 6 files changed, 50 insertions(+), 4 deletions(-) diff --git a/frontend/src/container/GridTableComponent/index.tsx b/frontend/src/container/GridTableComponent/index.tsx index 9dbccc1fd6d..d2caab44c5e 100644 --- a/frontend/src/container/GridTableComponent/index.tsx +++ b/frontend/src/container/GridTableComponent/index.tsx @@ -52,6 +52,8 @@ function GridTableComponent({ [columns], ); + console.log(columns, dataSource); + useEffect(() => { if (tableProcessedDataRef) { // eslint-disable-next-line no-param-reassign diff --git a/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx b/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx index 999fd7b42b5..31169a548e2 100644 --- a/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx +++ b/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx @@ -13,13 +13,14 @@ const findCategoryByName = ( ): Record | undefined => find(flattenedCategories, (option) => option.name === searchValue); +type OnSelectType = Dispatch> | ((val: string) => void); function YAxisUnitSelector({ defaultValue, onSelect, fieldLabel, }: { defaultValue: string; - onSelect: Dispatch>; + onSelect: OnSelectType; fieldLabel: string; }): JSX.Element { const onSelectHandler = (selectedValue: string): void => { diff --git a/frontend/src/container/NewWidget/RightContainer/constants.ts b/frontend/src/container/NewWidget/RightContainer/constants.ts index 0a4b250e70f..d68d20ece09 100644 --- a/frontend/src/container/NewWidget/RightContainer/constants.ts +++ b/frontend/src/container/NewWidget/RightContainer/constants.ts @@ -68,7 +68,7 @@ export const panelTypeVsFillSpan: { [key in PANEL_TYPES]: boolean } = { export const panelTypeVsYAxisUnit: { [key in PANEL_TYPES]: boolean } = { [PANEL_TYPES.TIME_SERIES]: true, [PANEL_TYPES.VALUE]: true, - [PANEL_TYPES.TABLE]: true, + [PANEL_TYPES.TABLE]: false, [PANEL_TYPES.LIST]: false, [PANEL_TYPES.PIE]: false, [PANEL_TYPES.BAR]: true, @@ -99,3 +99,16 @@ export const panelTypeVsPanelTimePreferences: { [PANEL_TYPES.TRACE]: false, [PANEL_TYPES.EMPTY_WIDGET]: false, } as const; + +export const panelTypeVsColumnUnitPreferences: { + [key in PANEL_TYPES]: boolean; +} = { + [PANEL_TYPES.TIME_SERIES]: false, + [PANEL_TYPES.VALUE]: false, + [PANEL_TYPES.TABLE]: true, + [PANEL_TYPES.LIST]: false, + [PANEL_TYPES.PIE]: false, + [PANEL_TYPES.BAR]: false, + [PANEL_TYPES.TRACE]: false, + [PANEL_TYPES.EMPTY_WIDGET]: false, +} as const; diff --git a/frontend/src/container/NewWidget/RightContainer/index.tsx b/frontend/src/container/NewWidget/RightContainer/index.tsx index e6e176b3df7..f4b873df59c 100644 --- a/frontend/src/container/NewWidget/RightContainer/index.tsx +++ b/frontend/src/container/NewWidget/RightContainer/index.tsx @@ -18,10 +18,12 @@ import { useEffect, useState, } from 'react'; -import { Widgets } from 'types/api/dashboard/getAll'; +import { ColumnUnit, Widgets } from 'types/api/dashboard/getAll'; import { DataSource } from 'types/common/queryBuilder'; +import { ColumnUnitSelector } from './ColumnUnitSelector/ColumnUnitSelector'; import { + panelTypeVsColumnUnitPreferences, panelTypeVsCreateAlert, panelTypeVsFillSpan, panelTypeVsPanelTimePreferences, @@ -57,6 +59,8 @@ function RightContainer({ softMin, setSoftMax, setSoftMin, + columnUnits, + setColumnUnits, }: RightContainerProps): JSX.Element { const onChangeHandler = useCallback( (setFunc: Dispatch>, value: string) => { @@ -78,6 +82,9 @@ function RightContainer({ const allowPanelTimePreference = panelTypeVsPanelTimePreferences[selectedGraph]; + const allowPanelColumnPreference = + panelTypeVsColumnUnitPreferences[selectedGraph]; + const { currentQuery } = useQueryBuilder(); const [graphTypes, setGraphTypes] = useState(GraphTypes); @@ -179,6 +186,13 @@ function RightContainer({ )} + {allowPanelColumnPreference && ( + + )} + {allowYAxisUnit && ( >; softMin: number | null; softMax: number | null; + columnUnits: ColumnUnit; + setColumnUnits: Dispatch>; setSoftMin: Dispatch>; setSoftMax: Dispatch>; } diff --git a/frontend/src/container/NewWidget/index.tsx b/frontend/src/container/NewWidget/index.tsx index e8ea2b5f043..0140c6c5a67 100644 --- a/frontend/src/container/NewWidget/index.tsx +++ b/frontend/src/container/NewWidget/index.tsx @@ -30,7 +30,7 @@ import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { generatePath, useParams } from 'react-router-dom'; import { AppState } from 'store/reducers'; -import { Dashboard, Widgets } from 'types/api/dashboard/getAll'; +import { ColumnUnit, Dashboard, Widgets } from 'types/api/dashboard/getAll'; import { IField } from 'types/api/logs/fields'; import { EQueryType } from 'types/common/dashboard'; import { DataSource } from 'types/common/queryBuilder'; @@ -156,6 +156,10 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element { : selectedWidget?.softMax || 0, ); + const [columnUnits, setColumnUnits] = useState( + selectedWidget?.columnUnits || {}, + ); + useEffect(() => { setSelectedWidget((prev) => { if (!prev) { @@ -174,11 +178,13 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element { softMin, softMax, fillSpans: isFillSpans, + columnUnits, selectedLogFields, selectedTracesFields, }; }); }, [ + columnUnits, currentQuery, description, isFillSpans, @@ -284,6 +290,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element { panelTypes: graphType, query: currentQuery, thresholds: selectedWidget?.thresholds, + columnUnits: selectedWidget?.columnUnits, softMin: selectedWidget?.softMin || 0, softMax: selectedWidget?.softMax || 0, fillSpans: selectedWidget?.fillSpans, @@ -305,6 +312,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element { panelTypes: graphType, query: currentQuery, thresholds: selectedWidget?.thresholds, + columnUnits: selectedWidget?.columnUnits, softMin: selectedWidget?.softMin || 0, softMax: selectedWidget?.softMax || 0, fillSpans: selectedWidget?.fillSpans, @@ -483,6 +491,8 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element { setStacked={setStacked} opacity={opacity} yAxisUnit={yAxisUnit} + columnUnits={columnUnits} + setColumnUnits={setColumnUnits} setOpacity={setOpacity} selectedNullZeroValue={selectedNullZeroValue} setSelectedNullZeroValue={setSelectedNullZeroValue} diff --git a/frontend/src/types/api/dashboard/getAll.ts b/frontend/src/types/api/dashboard/getAll.ts index d2f90317076..0fa9f4caf7c 100644 --- a/frontend/src/types/api/dashboard/getAll.ts +++ b/frontend/src/types/api/dashboard/getAll.ts @@ -83,6 +83,9 @@ export interface WidgetRow { description: string; } +export interface ColumnUnit { + [key: string]: string; +} export interface IBaseWidget { isStacked: boolean; id: string; @@ -98,6 +101,7 @@ export interface IBaseWidget { softMin: number | null; softMax: number | null; fillSpans?: boolean; + columnUnits?: ColumnUnit; selectedLogFields: IField[] | null; selectedTracesFields: BaseAutocompleteData[] | null; } From e4cfa871b6a5285f26efc7b0c203a5a3eb10d2b8 Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Mon, 3 Jun 2024 16:14:19 +0530 Subject: [PATCH 2/4] feat: added logic for y axis unit selection --- .../container/GridTableComponent/index.tsx | 36 ++++++++++++-- .../src/container/GridTableComponent/types.ts | 2 + .../ColumnUnitSelector.styles.scss | 19 +++++++ .../ColumnUnitSelector/ColumnUnitSelector.tsx | 49 +++++++++++++++++++ .../RightContainer/YAxisUnitSelector.tsx | 10 +++- .../PanelWrapper/TablePanelWrapper.tsx | 1 + 6 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss create mode 100644 frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.tsx diff --git a/frontend/src/container/GridTableComponent/index.tsx b/frontend/src/container/GridTableComponent/index.tsx index d2caab44c5e..6a4e5a551c4 100644 --- a/frontend/src/container/GridTableComponent/index.tsx +++ b/frontend/src/container/GridTableComponent/index.tsx @@ -1,12 +1,13 @@ import { ExclamationCircleFilled } from '@ant-design/icons'; import { Space, Tooltip } from 'antd'; +import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig'; import { Events } from 'constants/events'; import { QueryTable } from 'container/QueryTable'; import { createTableColumnsFromQuery, RowData, } from 'lib/query/createTableColumnsFromQuery'; -import { get, set } from 'lodash-es'; +import { get, isEmpty, set } from 'lodash-es'; import { memo, ReactNode, useCallback, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { eventEmitter } from 'utils/getEventEmitter'; @@ -19,11 +20,12 @@ function GridTableComponent({ data, query, thresholds, + columnUnits, tableProcessedDataRef, ...props }: GridTableComponentProps): JSX.Element { const { t } = useTranslation(['valueGraph']); - const { columns, dataSource } = useMemo( + const { columns, dataSource: originalDataSource } = useMemo( () => createTableColumnsFromQuery({ query, @@ -31,7 +33,6 @@ function GridTableComponent({ }), [data, query], ); - const createDataInCorrectFormat = useCallback( (dataSource: RowData[]): RowData[] => dataSource.map((d) => { @@ -52,7 +53,34 @@ function GridTableComponent({ [columns], ); - console.log(columns, dataSource); + const applyColumnUnits = useCallback( + (dataSource: RowData[]): RowData[] => { + let mutateDataSource = dataSource; + if (isEmpty(columnUnits)) { + return mutateDataSource; + } + + mutateDataSource = mutateDataSource.map( + (val): RowData => { + const newValue = val; + Object.keys(val).forEach((k) => { + if (columnUnits[k]) { + newValue[k] = getYAxisFormattedValue(String(val[k]), columnUnits[k]); + } + }); + return newValue; + }, + ); + + return mutateDataSource; + }, + [columnUnits], + ); + + const dataSource = useMemo(() => applyColumnUnits(originalDataSource), [ + applyColumnUnits, + originalDataSource, + ]); useEffect(() => { if (tableProcessedDataRef) { diff --git a/frontend/src/container/GridTableComponent/types.ts b/frontend/src/container/GridTableComponent/types.ts index 8a482158846..25ca647933a 100644 --- a/frontend/src/container/GridTableComponent/types.ts +++ b/frontend/src/container/GridTableComponent/types.ts @@ -5,11 +5,13 @@ import { ThresholdProps, } from 'container/NewWidget/RightContainer/Threshold/types'; import { RowData } from 'lib/query/createTableColumnsFromQuery'; +import { ColumnUnit } from 'types/api/dashboard/getAll'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; export type GridTableComponentProps = { query: Query; thresholds?: ThresholdProps[]; + columnUnits?: ColumnUnit; tableProcessedDataRef?: React.MutableRefObject; } & Pick & Omit, 'columns' | 'dataSource'>; diff --git a/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss b/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss new file mode 100644 index 00000000000..bdf3dffb058 --- /dev/null +++ b/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss @@ -0,0 +1,19 @@ +.column-unit-selector { + margin-top: 16px; + + .heading { + color: var(--bg-vanilla-400); + font-family: 'Space Mono'; + font-size: 13px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 138.462% */ + letter-spacing: 0.52px; + text-transform: uppercase; + } + + .y-axis-unit-selector { + flex-direction: row !important; + align-items: center; + } +} diff --git a/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.tsx b/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.tsx new file mode 100644 index 00000000000..6eff73fdf6f --- /dev/null +++ b/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.tsx @@ -0,0 +1,49 @@ +import './ColumnUnitSelector.styles.scss'; + +import { Typography } from 'antd'; +import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import { Dispatch, SetStateAction } from 'react'; +import { ColumnUnit } from 'types/api/dashboard/getAll'; + +import YAxisUnitSelector from '../YAxisUnitSelector'; + +interface ColumnUnitSelectorProps { + columnUnits: ColumnUnit; + setColumnUnits: Dispatch>; +} + +export function ColumnUnitSelector( + props: ColumnUnitSelectorProps, +): JSX.Element { + const { currentQuery } = useQueryBuilder(); + + function getAggregateColumnsNamesAndLabels(): string[] { + return currentQuery.builder.queryData.map((q) => q.queryName); + } + + const { columnUnits, setColumnUnits } = props; + const aggregationQueries = getAggregateColumnsNamesAndLabels(); + + function handleColumnUnitSelect(queryName: string, value: string): void { + setColumnUnits((prev) => ({ + ...prev, + [queryName]: value, + })); + } + return ( +
+ Column Units + {aggregationQueries.map((query) => ( + handleColumnUnitSelect(query, value)} + fieldLabel={query} + key={query} + handleClear={(): void => { + handleColumnUnitSelect(query, ''); + }} + /> + ))} +
+ ); +} diff --git a/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx b/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx index 31169a548e2..00ba8a572ee 100644 --- a/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx +++ b/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx @@ -18,10 +18,12 @@ function YAxisUnitSelector({ defaultValue, onSelect, fieldLabel, + handleClear, }: { defaultValue: string; onSelect: OnSelectType; fieldLabel: string; + handleClear?: () => void; }): JSX.Element { const onSelectHandler = (selectedValue: string): void => { onSelect(findCategoryByName(selectedValue)?.id || ''); @@ -36,7 +38,9 @@ function YAxisUnitSelector({ style={{ width: '100%' }} rootClassName="y-axis-root-popover" options={options} + allowClear defaultValue={findCategoryById(defaultValue)?.name} + onClear={handleClear} onSelect={onSelectHandler} filterOption={(inputValue, option): boolean => { if (option) { @@ -47,10 +51,14 @@ function YAxisUnitSelector({ return false; }} > - + ); } export default YAxisUnitSelector; + +YAxisUnitSelector.defaultProps = { + handleClear: (): void => {}, +}; diff --git a/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx b/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx index 5a440f4fdc8..d05b74fe4e1 100644 --- a/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx +++ b/frontend/src/container/PanelWrapper/TablePanelWrapper.tsx @@ -16,6 +16,7 @@ function TablePanelWrapper({ data={panelData} query={widget.query} thresholds={thresholds} + columnUnits={widget.columnUnits} tableProcessedDataRef={tableProcessedDataRef} // eslint-disable-next-line react/jsx-props-no-spreading {...GRID_TABLE_CONFIG} From 7538e51185c21b6fcb4cad73dc903da04d007021 Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Mon, 3 Jun 2024 16:26:08 +0530 Subject: [PATCH 3/4] fix: light mode design --- .../ColumnUnitSelector/ColumnUnitSelector.styles.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss b/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss index bdf3dffb058..5426d866723 100644 --- a/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss +++ b/frontend/src/container/NewWidget/RightContainer/ColumnUnitSelector/ColumnUnitSelector.styles.scss @@ -17,3 +17,11 @@ align-items: center; } } + +.lightMode { + .column-unit-selector { + .heading { + color: var(--bg-ink-400); + } + } +} From a1ae4495a3fd9b1cf88b4e84a4326d46ff50fcbb Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Mon, 3 Jun 2024 23:28:07 +0530 Subject: [PATCH 4/4] feat: fix the mutation of original datasource array --- frontend/src/container/GridTableComponent/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/container/GridTableComponent/index.tsx b/frontend/src/container/GridTableComponent/index.tsx index 6a4e5a551c4..26bdda1a49a 100644 --- a/frontend/src/container/GridTableComponent/index.tsx +++ b/frontend/src/container/GridTableComponent/index.tsx @@ -7,7 +7,7 @@ import { createTableColumnsFromQuery, RowData, } from 'lib/query/createTableColumnsFromQuery'; -import { get, isEmpty, set } from 'lodash-es'; +import { cloneDeep, get, isEmpty, set } from 'lodash-es'; import { memo, ReactNode, useCallback, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { eventEmitter } from 'utils/getEventEmitter'; @@ -55,7 +55,7 @@ function GridTableComponent({ const applyColumnUnits = useCallback( (dataSource: RowData[]): RowData[] => { - let mutateDataSource = dataSource; + let mutateDataSource = cloneDeep(dataSource); if (isEmpty(columnUnits)) { return mutateDataSource; }