From f10f7a806f102d53d4f66e88542afd98707c1f2d Mon Sep 17 00:00:00 2001 From: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com> Date: Fri, 16 May 2025 16:35:11 +0530 Subject: [PATCH] feat: suggest and allow variables in panel title (#7898) * feat: suggest and allow variables in panel title * feat: refined the logic for suggestion and addition with $ * feat: added logic for panel title resolved string and added test cases * feat: added support to full view --- .../GridCard/WidgetGraphComponent.tsx | 14 +- .../GridCardLayout/WidgetHeader/index.tsx | 22 ++- .../RightContainer/RightContainer.styles.scss | 1 - .../NewWidget/RightContainer/index.tsx | 109 +++++++++++- .../__test__/useGetResolvedText.test.tsx | 133 +++++++++++++++ .../hooks/dashboard/useGetResolvedText.tsx | 156 ++++++++++++++++++ 6 files changed, 419 insertions(+), 16 deletions(-) create mode 100644 frontend/src/hooks/dashboard/__test__/useGetResolvedText.test.tsx create mode 100644 frontend/src/hooks/dashboard/useGetResolvedText.tsx diff --git a/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx b/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx index 99f8d1f237..d39fe0c080 100644 --- a/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx +++ b/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx @@ -1,6 +1,6 @@ import '../GridCardLayout.styles.scss'; -import { Skeleton, Typography } from 'antd'; +import { Skeleton, Tooltip, Typography } from 'antd'; import cx from 'classnames'; import { useNavigateToExplorer } from 'components/CeleryTask/useNavigateToExplorer'; import { ToggleGraphProps } from 'components/Graph/types'; @@ -9,6 +9,7 @@ import { QueryParams } from 'constants/query'; import { PANEL_TYPES } from 'constants/queryBuilder'; import { placeWidgetAtBottom } from 'container/NewWidget/utils'; import PanelWrapper from 'container/PanelWrapper/PanelWrapper'; +import useGetResolvedText from 'hooks/dashboard/useGetResolvedText'; import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard'; import { useNotifications } from 'hooks/useNotifications'; import { useSafeNavigate } from 'hooks/useSafeNavigate'; @@ -293,6 +294,11 @@ function WidgetGraphComponent({ }); }; + const { truncatedText, fullText } = useGetResolvedText({ + text: widget.title as string, + maxLength: 100, + }); + return (
+ {truncatedText || fullText || 'View'} + + } footer={[]} centered open={isFullViewOpen} diff --git a/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx b/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx index 9956ebc160..2d69a737f7 100644 --- a/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx +++ b/frontend/src/container/GridCardLayout/WidgetHeader/index.tsx @@ -16,6 +16,7 @@ import { Dropdown, Input, MenuProps, Tooltip, Typography } from 'antd'; import Spinner from 'components/Spinner'; import { QueryParams } from 'constants/query'; import { PANEL_TYPES } from 'constants/queryBuilder'; +import useGetResolvedText from 'hooks/dashboard/useGetResolvedText'; import useCreateAlerts from 'hooks/queryBuilder/useCreateAlerts'; import useComponentPermission from 'hooks/useComponentPermission'; import { useSafeNavigate } from 'hooks/useSafeNavigate'; @@ -205,6 +206,11 @@ function WidgetHeader({ [updatedMenuList, onMenuItemSelectHandler], ); + const { truncatedText, fullText } = useGetResolvedText({ + text: widget.title as string, + maxLength: 100, + }); + if (widget.id === PANEL_TYPES.EMPTY_WIDGET) { return null; } @@ -237,13 +243,15 @@ function WidgetHeader({ ) : ( <>
- - {title} - + + + {truncatedText} + + {widget.description && ( (null); + const onChangeHandler = useCallback( (setFunc: Dispatch>, value: string) => { setFunc(value); @@ -112,6 +136,66 @@ function RightContainer({ const [graphTypes, setGraphTypes] = useState(GraphTypes); + // Get dashboard variables + const dashboardVariables = useMemo(() => { + if (!selectedDashboard?.data?.variables) return []; + return Object.entries(selectedDashboard.data.variables).map(([, value]) => ({ + value: value.name || '', + label: value.name || '', + })); + }, [selectedDashboard?.data?.variables]); + + const updateCursorAndDropdown = (value: string, pos: number): void => { + setCursorPos(pos); + const lastDollar = value.lastIndexOf('$', pos - 1); + setAutoCompleteOpen(lastDollar !== -1 && pos >= lastDollar + 1); + }; + + const onInputChange = (value: string): void => { + setInputValue(value); + onChangeHandler(setTitle, value); + setTimeout(() => { + const pos = inputRef.current?.input?.selectionStart ?? 0; + updateCursorAndDropdown(value, pos); + }, 0); + }; + + const handleInputCursor = (): void => { + const pos = inputRef.current?.input?.selectionStart ?? 0; + updateCursorAndDropdown(inputValue, pos); + }; + + const onSelect = (selectedValue: string): void => { + const pos = cursorPos; + const value = inputValue; + const lastDollar = value.lastIndexOf('$', pos - 1); + const textBeforeDollar = value.substring(0, lastDollar); + const textAfterDollar = value.substring(lastDollar + 1); + const match = textAfterDollar.match(/^([a-zA-Z0-9_.]*)/); + const rest = textAfterDollar.substring(match ? match[1].length : 0); + const newValue = `${textBeforeDollar}$${selectedValue}${rest}`; + setInputValue(newValue); + onChangeHandler(setTitle, newValue); + setAutoCompleteOpen(false); + setTimeout(() => { + const newCursor = `${textBeforeDollar}$${selectedValue}`.length; + inputRef.current?.input?.setSelectionRange(newCursor, newCursor); + setCursorPos(newCursor); + }, 0); + }; + + const filterOption = ( + inputValue: string, + option?: VariableOption, + ): boolean => { + const pos = cursorPos; + const value = inputValue; + const lastDollar = value.lastIndexOf('$', pos - 1); + if (lastDollar === -1) return false; + const afterDollar = value.substring(lastDollar + 1, pos).toLowerCase(); + return option?.value.toLowerCase().startsWith(afterDollar) || false; + }; + useEffect(() => { const queryContainsMetricsDataSource = currentQuery.builder.queryData.some( (query) => query.dataSource === DataSource.METRICS, @@ -148,12 +232,25 @@ function RightContainer({
Name - onChangeHandler(setTitle, event.target.value)} - value={title} - rootClassName="name-input" - /> + open={autoCompleteOpen} + > + setAutoCompleteOpen(false)} + /> + Description