Save view PRD design changes. (#3480)

* refactor: search in dropdown

* refactor: name of the view to i18

* refactor: make the use of useForm from antd

* refactor: moved QuerySearchParamNames into save view module

* refactor: reset to query build when click on explorer link

* refactor: save view prd design changes

* refactor: reverted resetQuery in querybuilder

* refactor: queryParams to query.ts in querybuilder constants

* fix: redirect with saved view is updated

* refactor: removed useffect logic for updating query

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
Rajat Dabade 2023-09-12 11:57:33 +05:30 committed by GitHub
parent 7b4fd55aeb
commit 96adc7f61c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 88 additions and 107 deletions

View File

@ -19,6 +19,7 @@ import {
import axios from 'axios';
import TextToolTip from 'components/TextToolTip';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { QueryParams } from 'constants/query';
import { useGetSearchQueryParam } from 'hooks/queryBuilder/useGetSearchQueryParam';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useDeleteView } from 'hooks/saveViews/useDeleteView';
@ -27,14 +28,10 @@ import { useUpdateView } from 'hooks/saveViews/useUpdateView';
import useErrorNotification from 'hooks/useErrorNotification';
import { useNotifications } from 'hooks/useNotifications';
import { mapCompositeQueryFromQuery } from 'lib/newQueryBuilder/queryBuilderMappers/mapCompositeQueryFromQuery';
import { useEffect, useState } from 'react';
import { useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import {
ExploreHeaderToolTip,
querySearchParams,
SaveButtonText,
} from './constants';
import { ExploreHeaderToolTip, SaveButtonText } from './constants';
import MenuItemGenerator from './MenuItemGenerator';
import SaveViewWithName from './SaveViewWithName';
import {
@ -43,7 +40,7 @@ import {
OffSetCol,
} from './styles';
import { ExplorerCardProps } from './types';
import { deleteViewHandler, isQueryUpdatedInView } from './utils';
import { deleteViewHandler } from './utils';
function ExplorerCard({
sourcepage,
@ -51,7 +48,6 @@ function ExplorerCard({
}: ExplorerCardProps): JSX.Element {
const [isOpen, setIsOpen] = useState<boolean>(false);
const [, setCopyUrl] = useCopyToClipboard();
const [isQueryUpdated, setIsQueryUpdated] = useState<boolean>(false);
const { notifications } = useNotifications();
const onCopyUrlHandler = (): void => {
@ -62,11 +58,11 @@ function ExplorerCard({
};
const {
stagedQuery,
currentQuery,
panelType,
redirectWithQueryBuilderData,
updateAllQueriesOperators,
isStagedQueryUpdated,
} = useQueryBuilder();
const {
@ -83,10 +79,11 @@ function ExplorerCard({
setIsOpen(newOpen);
};
const viewName =
useGetSearchQueryParam(querySearchParams.viewName) || 'Query Builder';
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
const viewKey = useGetSearchQueryParam(querySearchParams.viewKey) || '';
const viewKey = useGetSearchQueryParam(QueryParams.viewKey) || '';
const isQueryUpdated = isStagedQueryUpdated(viewsData?.data?.data, viewKey);
const { mutateAsync: updateViewAsync } = useUpdateView({
compositeQuery: mapCompositeQueryFromQuery(currentQuery, panelType),
@ -128,7 +125,6 @@ function ExplorerCard({
},
{
onSuccess: () => {
setIsQueryUpdated(false);
notifications.success({
message: 'View Updated Successfully',
});
@ -141,24 +137,6 @@ function ExplorerCard({
);
};
useEffect(() => {
setIsQueryUpdated(
isQueryUpdatedInView({
data: viewsData?.data?.data,
stagedQuery,
viewKey,
currentPanelType: panelType,
}),
);
}, [
currentQuery,
viewsData?.data?.data,
stagedQuery,
stagedQuery?.builder.queryData,
viewKey,
panelType,
]);
const moreOptionMenu: MenuProps = {
items: [
{
@ -179,7 +157,7 @@ function ExplorerCard({
<Row align="middle">
<Col span={6}>
<Space>
<Typography>{viewName}</Typography>
<Typography>Query Builder</Typography>
<TextToolTip
url={ExploreHeaderToolTip.url}
text={ExploreHeaderToolTip.text}
@ -197,7 +175,8 @@ function ExplorerCard({
placeholder="Select a view"
dropdownStyle={DropDownOverlay}
dropdownMatchSelectWidth={false}
value={null}
optionLabelProp="value"
value={viewName || undefined}
>
{viewsData?.data.data.map((view) => (
<Select.Option key={view.uuid} value={view.name}>

View File

@ -1,3 +1,5 @@
import { QueryParams } from 'constants/query';
export const ExploreHeaderToolTip = {
url:
'https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=new-query-builder',
@ -9,12 +11,4 @@ export const SaveButtonText = {
SAVE_VIEW: 'Save view',
};
export type QuerySearchParamNames = 'viewName' | 'viewKey';
export const querySearchParams: Record<
QuerySearchParamNames,
QuerySearchParamNames
> = {
viewName: 'viewName',
viewKey: 'viewKey',
};
export type QuerySearchParamNames = QueryParams.viewName | QueryParams.viewKey;

View File

@ -1,12 +1,11 @@
import { NotificationInstance } from 'antd/es/notification/interface';
import axios from 'axios';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
import isEqual from 'lodash-es/isEqual';
import { querySearchParams } from './constants';
import {
DeleteViewHandlerProps,
GetViewDetailsUsingViewKey,
@ -119,9 +118,9 @@ export const saveViewHandler = ({
onSuccess: (data) => {
refetchAllView();
redirectWithQueryBuilderData(mapQueryDataFromApi(compositeQuery), {
[queryParamNamesMap.panelTypes]: panelType,
[querySearchParams.viewName]: viewName,
[querySearchParams.viewKey]: data.data.data,
[QueryParams.panelTypes]: panelType,
[QueryParams.viewName]: viewName,
[QueryParams.viewKey]: data.data.data,
});
notifications.success({
message: 'View Saved Successfully',
@ -159,9 +158,9 @@ export const deleteViewHandler = ({
sourcePage,
),
{
[querySearchParams.viewName]: 'Query Builder',
[queryParamNamesMap.panelTypes]: panelType,
[querySearchParams.viewKey]: '',
[QueryParams.viewName]: '',
[QueryParams.panelTypes]: panelType,
[QueryParams.viewKey]: '',
},
);
}

View File

@ -18,4 +18,12 @@ export enum QueryParams {
q = 'q',
activeLogId = 'activeLogId',
timeRange = 'timeRange',
compositeQuery = 'compositeQuery',
panelTypes = 'panelTypes',
pageSize = 'pageSize',
viewMode = 'viewMode',
selectedFields = 'selectedFields',
linesPerRow = 'linesPerRow',
viewName = 'viewName',
viewKey = 'viewKey',
}

View File

@ -1,16 +0,0 @@
type QueryParamNames =
| 'compositeQuery'
| 'panelTypes'
| 'pageSize'
| 'viewMode'
| 'selectedFields'
| 'linesPerRow';
export const queryParamNamesMap: Record<QueryParamNames, QueryParamNames> = {
compositeQuery: 'compositeQuery',
panelTypes: 'panelTypes',
pageSize: 'pageSize',
viewMode: 'viewMode',
selectedFields: 'selectedFields',
linesPerRow: 'linesPerRow',
};

View File

@ -1,6 +1,6 @@
import { AlertOutlined, AreaChartOutlined } from '@ant-design/icons';
import { Button, Modal, Space } from 'antd';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import history from 'lib/history';
import { useCallback, useState } from 'react';
@ -22,9 +22,9 @@ function ExportPanel({
const onCreateAlertsHandler = useCallback(() => {
history.push(
`${ROUTES.ALERTS_NEW}?${
queryParamNamesMap.compositeQuery
}=${encodeURIComponent(JSON.stringify(query))}`,
`${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent(
JSON.stringify(query),
)}`,
);
}, [query]);

View File

@ -8,7 +8,7 @@ import {
} from '@ant-design/icons';
import { Dropdown, MenuProps, Tooltip, Typography } from 'antd';
import Spinner from 'components/Spinner';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission';
import history from 'lib/history';
@ -73,7 +73,7 @@ function WidgetHeader({
history.push(
`${window.location.pathname}/new?widgetId=${widgetId}&graphType=${
widget.panelTypes
}&${queryParamNamesMap.compositeQuery}=${encodeURIComponent(
}&${QueryParams.compositeQuery}=${encodeURIComponent(
JSON.stringify(widget.query),
)}`,
);
@ -81,9 +81,9 @@ function WidgetHeader({
const onCreateAlertsHandler = useCallback(() => {
history.push(
`${ROUTES.ALERTS_NEW}?${
queryParamNamesMap.compositeQuery
}=${encodeURIComponent(JSON.stringify(widget.query))}`,
`${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent(
JSON.stringify(widget.query),
)}`,
);
}, [widget]);

View File

@ -5,7 +5,7 @@ import { ColumnsType } from 'antd/lib/table';
import saveAlertApi from 'api/alerts/save';
import { ResizeTable } from 'components/ResizeTable';
import TextToolTip from 'components/TextToolTip';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import useComponentPermission from 'hooks/useComponentPermission';
import useInterval from 'hooks/useInterval';
@ -76,7 +76,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
history.push(
`${ROUTES.EDIT_ALERTS}?ruleId=${record.id.toString()}&${
queryParamNamesMap.compositeQuery
QueryParams.compositeQuery
}=${encodeURIComponent(JSON.stringify(compositeQuery))}`,
);
})

View File

@ -1,10 +1,10 @@
import { ArrowLeftOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import { QueryParams } from 'constants/query';
import {
initialQueryBuilderFormValuesMap,
PANEL_TYPES,
} from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import ROUTES from 'constants/routes';
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
@ -38,7 +38,7 @@ function BackButton(): JSX.Element {
const JSONCompositeQuery = encodeURIComponent(JSON.stringify(updatedQuery));
const path = `${ROUTES.LOGS_EXPLORER}?${queryParamNamesMap.compositeQuery}=${JSONCompositeQuery}`;
const path = `${ROUTES.LOGS_EXPLORER}?${QueryParams.compositeQuery}=${JSONCompositeQuery}`;
history.push(path);
}, [history, compositeQuery, updateAllQueriesOperators]);

View File

@ -1,13 +1,13 @@
import { Tabs, TabsProps } from 'antd';
import TabLabel from 'components/TabLabel';
import { AVAILABLE_EXPORT_PANEL_TYPES } from 'constants/panelTypes';
import { QueryParams } from 'constants/query';
import {
initialFilters,
initialQueriesMap,
initialQueryBuilderFormValues,
PANEL_TYPES,
} from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { DEFAULT_PER_PAGE_VALUE } from 'container/Controls/config';
import ExportPanel from 'container/ExportPanel';
import GoToTop from 'container/GoToTop';
@ -50,7 +50,7 @@ function LogsExplorerViews(): JSX.Element {
const { activeLogId, timeRange, onTimeRangeChange } = useCopyLogLink();
const { queryData: pageSize } = useUrlQueryData(
queryParamNamesMap.pageSize,
QueryParams.pageSize,
DEFAULT_PER_PAGE_VALUE,
);

View File

@ -1,9 +1,9 @@
import { PlayCircleFilled } from '@ant-design/icons';
import { QueryParams } from 'constants/query';
import {
initialQueryBuilderFormValuesMap,
PANEL_TYPES,
} from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import ROUTES from 'constants/routes';
import {
@ -63,7 +63,7 @@ function LogsTopNav(): JSX.Element {
const JSONCompositeQuery = encodeURIComponent(JSON.stringify(compositeQuery));
const path = `${ROUTES.LIVE_LOGS}?${queryParamNamesMap.compositeQuery}=${JSONCompositeQuery}`;
const path = `${ROUTES.LIVE_LOGS}?${QueryParams.compositeQuery}=${JSONCompositeQuery}`;
history.push(path, queryHistoryState);
}, [history, panelType, queryClient, stagedQuery]);

View File

@ -1,5 +1,5 @@
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useNotifications } from 'hooks/useNotifications';
import createQueryParams from 'lib/createQueryParams';
@ -49,9 +49,7 @@ function DashboardGraphSlider({ toggleAddWidget }: Props): JSX.Element {
const queryParams = {
graphType: name,
widgetId: emptyLayout.i,
[queryParamNamesMap.compositeQuery]: JSON.stringify(
initialQueriesMap.metrics,
),
[QueryParams.compositeQuery]: JSON.stringify(initialQueriesMap.metrics),
};
history.push(`${pathname}/new?${createQueryParams(queryParams)}`);

View File

@ -1,5 +1,5 @@
import { Col, Row, Select } from 'antd';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { QueryParams } from 'constants/query';
import {
defaultSelectStyle,
ITEMS_PER_PAGE_OPTIONS,
@ -14,7 +14,7 @@ function PageSizeSelect({
isShow,
}: PageSizeSelectProps): JSX.Element | null {
const { redirectWithQuery, queryData: pageSize } = useUrlQueryData<number>(
queryParamNamesMap.pageSize,
QueryParams.pageSize,
ITEMS_PER_PAGE_OPTIONS[0],
);

View File

@ -1,4 +1,4 @@
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { QueryParams } from 'constants/query';
import useUrlQuery from 'hooks/useUrlQuery';
import { useMemo } from 'react';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@ -7,7 +7,7 @@ export const useGetCompositeQueryParam = (): Query | null => {
const urlQuery = useUrlQuery();
return useMemo(() => {
const compositeQuery = urlQuery.get(queryParamNamesMap.compositeQuery);
const compositeQuery = urlQuery.get(QueryParams.compositeQuery);
let parsedCompositeQuery: Query | null = null;
try {

View File

@ -1,5 +1,5 @@
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import useUrlQuery from 'hooks/useUrlQuery';
import { useMemo } from 'react';
@ -9,7 +9,7 @@ export const useGetPanelTypesQueryParam = <T extends PANEL_TYPES | undefined>(
const urlQuery = useUrlQuery();
return useMemo(() => {
const panelTypeQuery = urlQuery.get(queryParamNamesMap.panelTypes);
const panelTypeQuery = urlQuery.get(QueryParams.panelTypes);
return panelTypeQuery ? JSON.parse(panelTypeQuery) : defaultPanelType;
}, [urlQuery, defaultPanelType]);

View File

@ -1,6 +1,5 @@
import { querySearchParams } from 'components/ExplorerCard/constants';
import { QueryParams } from 'constants/query';
import { initialAutocompleteData, PANEL_TYPES } from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { SIGNOZ_VALUE } from 'container/QueryBuilder/filters/OrderByFilter/constants';
import { useCallback } from 'react';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@ -23,9 +22,9 @@ export const useHandleExplorerTabChange = (): {
updateQueriesData,
} = useQueryBuilder();
const viewName = useGetSearchQueryParam(querySearchParams.viewName) || '';
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
const viewKey = useGetSearchQueryParam(querySearchParams.viewKey) || '';
const viewKey = useGetSearchQueryParam(QueryParams.viewKey) || '';
const getUpdateQuery = useCallback(
(newPanelType: PANEL_TYPES): Query => {
@ -60,12 +59,12 @@ export const useHandleExplorerTabChange = (): {
const query = currentQueryData?.query || getUpdateQuery(newPanelType);
redirectWithQueryBuilderData(query, {
[queryParamNamesMap.panelTypes]: newPanelType,
[querySearchParams.viewName]: currentQueryData?.name || viewName,
[querySearchParams.viewKey]: currentQueryData?.uuid || viewKey,
[QueryParams.panelTypes]: newPanelType,
[QueryParams.viewName]: currentQueryData?.name || viewName,
[QueryParams.viewKey]: currentQueryData?.uuid || viewKey,
});
},
[getUpdateQuery, panelType, redirectWithQueryBuilderData, viewKey, viewName],
[panelType, getUpdateQuery, redirectWithQueryBuilderData, viewName, viewKey],
);
return { handleExplorerTabChange };

View File

@ -1,3 +1,5 @@
import { isQueryUpdatedInView } from 'components/ExplorerCard/utils';
import { QueryParams } from 'constants/query';
import {
alphabet,
baseAutoCompleteIdKeysOrder,
@ -13,7 +15,6 @@ import {
MAX_QUERIES,
PANEL_TYPES,
} from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
import useUrlQuery from 'hooks/useUrlQuery';
@ -42,6 +43,7 @@ import {
Query,
QueryState,
} from 'types/api/queryBuilder/queryBuilderData';
import { ViewProps } from 'types/api/saveViews/types';
import { EQueryType } from 'types/common/dashboard';
import {
DataSource,
@ -73,6 +75,7 @@ export const QueryBuilderContext = createContext<QueryBuilderContextType>({
updateQueriesData: () => initialQueriesMap.metrics,
initQueryBuilderData: () => {},
handleOnUnitsChange: () => {},
isStagedQueryUpdated: () => false,
});
export function QueryBuilderProvider({
@ -449,6 +452,17 @@ export function QueryBuilderProvider({
[updateQueryBuilderData],
);
const isStagedQueryUpdated = useCallback(
(viewData: ViewProps[] | undefined, viewKey: string): boolean =>
isQueryUpdatedInView({
currentPanelType: panelType,
data: viewData,
stagedQuery,
viewKey,
}),
[panelType, stagedQuery],
);
const redirectWithQueryBuilderData = useCallback(
(query: Partial<Query>, searchParams?: Record<string, unknown>) => {
const queryType =
@ -481,7 +495,7 @@ export function QueryBuilderProvider({
};
urlQuery.set(
queryParamNamesMap.compositeQuery,
QueryParams.compositeQuery,
encodeURIComponent(JSON.stringify(currentGeneratedQuery)),
);
@ -613,6 +627,7 @@ export function QueryBuilderProvider({
updateQueriesData,
initQueryBuilderData,
handleOnUnitsChange,
isStagedQueryUpdated,
}),
[
query,
@ -635,6 +650,7 @@ export function QueryBuilderProvider({
updateQueriesData,
initQueryBuilderData,
handleOnUnitsChange,
isStagedQueryUpdated,
],
);

View File

@ -1,8 +1,8 @@
import { notification } from 'antd';
import updateDashboardApi from 'api/dashboard/update';
import { AxiosError } from 'axios';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import ROUTES from 'constants/routes';
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
import history from 'lib/history';
@ -88,7 +88,7 @@ export const SaveDashboard = ({
};
const allLayout = getAllLayout();
const params = new URLSearchParams(window.location.search);
const compositeQuery = params.get(queryParamNamesMap.compositeQuery);
const compositeQuery = params.get(QueryParams.compositeQuery);
const { maxTime, minTime } = store.getState().globalTime;
const query = compositeQuery
? updateStepInterval(

View File

@ -8,6 +8,7 @@ import {
Query,
QueryState,
} from 'types/api/queryBuilder/queryBuilderData';
import { ViewProps } from 'types/api/saveViews/types';
import { EQueryType } from './dashboard';
@ -204,6 +205,10 @@ export type QueryBuilderContextType = {
) => QueryBuilderData[T][number],
) => Query;
initQueryBuilderData: (query: Query) => void;
isStagedQueryUpdated: (
viewData: ViewProps[] | undefined,
viewKey: string,
) => boolean;
};
export type QueryAdditionalFilter = {

View File

@ -1,6 +1,5 @@
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { queryParamNamesMap } from 'constants/queryBuilderQueryNames';
import ROUTES from 'constants/routes';
import { generatePath } from 'react-router-dom';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@ -19,5 +18,5 @@ export const generateExportToDashboardLink = ({
`${generatePath(ROUTES.DASHBOARD, {
dashboardId,
})}/new?${QueryParams.graphType}=${panelType}&${QueryParams.widgetId}=empty&${
queryParamNamesMap.compositeQuery
QueryParams.compositeQuery
}=${encodeURIComponent(JSON.stringify(query))}`;