Merge branch 'develop' into feat--add-react-query-dev-tools-in-dev-env

This commit is contained in:
Shaheer Kochai 2024-07-08 10:53:14 +04:30 committed by GitHub
commit 75815897b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 177 additions and 51 deletions

View File

@ -6,5 +6,6 @@
"share": "Share", "share": "Share",
"save": "Save", "save": "Save",
"edit": "Edit", "edit": "Edit",
"logged_in": "Logged In" "logged_in": "Logged In",
"pending_data_placeholder": "Just a bit of patience, just a little bits enough ⎯ were getting your {{dataSource}}!"
} }

View File

@ -120,11 +120,7 @@ describe('LogsExplorerViews -', () => {
// switch to table view // switch to table view
await userEvent.click(queryByTestId('table-view') as HTMLElement); await userEvent.click(queryByTestId('table-view') as HTMLElement);
expect( expect(queryByText('pending_data_placeholder')).toBeInTheDocument();
queryByText(
'Just a bit of patience, just a little bits enough ⎯ were getting your logs!',
),
).toBeInTheDocument();
}); });
it('check error state', async () => { it('check error state', async () => {

View File

@ -1,8 +1,11 @@
import './LogsLoading.styles.scss'; import './LogsLoading.styles.scss';
import { Typography } from 'antd'; import { Typography } from 'antd';
import { useTranslation } from 'react-i18next';
import { DataSource } from 'types/common/queryBuilder';
export function LogsLoading(): JSX.Element { export function LogsLoading(): JSX.Element {
const { t } = useTranslation('common');
return ( return (
<div className="loading-logs"> <div className="loading-logs">
<div className="loading-logs-content"> <div className="loading-logs-content">
@ -13,8 +16,7 @@ export function LogsLoading(): JSX.Element {
/> />
<Typography> <Typography>
Just a bit of patience, just a little bits enough were getting your {t('pending_data_placeholder', { dataSource: DataSource.LOGS })}
logs!
</Typography> </Typography>
</div> </div>
</div> </div>

View File

@ -39,6 +39,7 @@
font-weight: 500; font-weight: 500;
line-height: 18px; /* 128.571% */ line-height: 18px; /* 128.571% */
letter-spacing: -0.07px; letter-spacing: -0.07px;
cursor: pointer;
} }
} }
} }

View File

@ -6,6 +6,7 @@ import history from 'lib/history';
import { ArrowUpRight } from 'lucide-react'; import { ArrowUpRight } from 'lucide-react';
import { DataSource } from 'types/common/queryBuilder'; import { DataSource } from 'types/common/queryBuilder';
import { isCloudUser } from 'utils/app'; import { isCloudUser } from 'utils/app';
import DOCLINKS from 'utils/docLinks';
export default function NoLogs({ export default function NoLogs({
dataSource, dataSource,
@ -25,8 +26,10 @@ export default function NoLogs({
? ROUTES.GET_STARTED_APPLICATION_MONITORING ? ROUTES.GET_STARTED_APPLICATION_MONITORING
: ROUTES.GET_STARTED_LOGS_MANAGEMENT, : ROUTES.GET_STARTED_LOGS_MANAGEMENT,
); );
} else if (dataSource === 'traces') {
window.open(DOCLINKS.TRACES_EXPLORER_EMPTY_STATE, '_blank');
} else { } else {
window.open(`https://signoz.io/docs/userguide/${dataSource}/`, '_blank'); window.open(`${DOCLINKS.USER_GUIDE}${dataSource}/`, '_blank');
} }
}; };
return ( return (

View File

@ -22,7 +22,7 @@ describe('PipelinePage container test', () => {
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
}); });
it('should handle search', async () => { it.skip('should handle search', async () => {
const setPipelineValue = jest.fn(); const setPipelineValue = jest.fn();
const { getByPlaceholderText, container } = render( const { getByPlaceholderText, container } = render(
<MemoryRouter> <MemoryRouter>

View File

@ -7,6 +7,7 @@ import LogsError from 'container/LogsError/LogsError';
import { LogsLoading } from 'container/LogsLoading/LogsLoading'; import { LogsLoading } from 'container/LogsLoading/LogsLoading';
import NoLogs from 'container/NoLogs/NoLogs'; import NoLogs from 'container/NoLogs/NoLogs';
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config'; import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
import { TracesLoading } from 'container/TracesExplorer/TraceLoading/TraceLoading';
import { useIsDarkMode } from 'hooks/useDarkMode'; import { useIsDarkMode } from 'hooks/useDarkMode';
import useUrlQuery from 'hooks/useUrlQuery'; import useUrlQuery from 'hooks/useUrlQuery';
import GetMinMax from 'lib/getMinMax'; import GetMinMax from 'lib/getMinMax';
@ -146,7 +147,8 @@ function TimeSeriesView({
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
ref={graphRef} ref={graphRef}
> >
{isLoading && <LogsLoading />} {isLoading &&
(dataSource === DataSource.LOGS ? <LogsLoading /> : <TracesLoading />)}
{chartData && {chartData &&
chartData[0] && chartData[0] &&

View File

@ -14,6 +14,7 @@ import { convertDataValueToMs } from './utils';
function TimeSeriesViewContainer({ function TimeSeriesViewContainer({
dataSource = DataSource.TRACES, dataSource = DataSource.TRACES,
isFilterApplied,
}: TimeSeriesViewProps): JSX.Element { }: TimeSeriesViewProps): JSX.Element {
const { stagedQuery, currentQuery, panelType } = useQueryBuilder(); const { stagedQuery, currentQuery, panelType } = useQueryBuilder();
@ -70,8 +71,7 @@ function TimeSeriesViewContainer({
return ( return (
<TimeSeriesView <TimeSeriesView
// TODO handle this when revamping trace explorer isFilterApplied={isFilterApplied}
isFilterApplied={false}
isError={isError} isError={isError}
isLoading={isLoading} isLoading={isLoading}
data={responseData} data={responseData}
@ -83,6 +83,7 @@ function TimeSeriesViewContainer({
interface TimeSeriesViewProps { interface TimeSeriesViewProps {
dataSource?: DataSource; dataSource?: DataSource;
isFilterApplied: boolean;
} }
TimeSeriesViewContainer.defaultProps = { TimeSeriesViewContainer.defaultProps = {

View File

@ -4,6 +4,8 @@ import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query'; import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import EmptyLogsSearch from 'container/EmptyLogsSearch/EmptyLogsSearch';
import NoLogs from 'container/NoLogs/NoLogs';
import { useOptionsMenu } from 'container/OptionsMenu'; import { useOptionsMenu } from 'container/OptionsMenu';
import TraceExplorerControls from 'container/TracesExplorer/Controls'; import TraceExplorerControls from 'container/TracesExplorer/Controls';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
@ -20,11 +22,16 @@ import { AppState } from 'store/reducers';
import { DataSource } from 'types/common/queryBuilder'; import { DataSource } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import { TracesLoading } from '../TraceLoading/TraceLoading';
import { defaultSelectedColumns, PER_PAGE_OPTIONS } from './configs'; import { defaultSelectedColumns, PER_PAGE_OPTIONS } from './configs';
import { Container, ErrorText, tableStyles } from './styles'; import { Container, ErrorText, tableStyles } from './styles';
import { getListColumns, getTraceLink, transformDataWithDate } from './utils'; import { getListColumns, getTraceLink, transformDataWithDate } from './utils';
function ListView(): JSX.Element { interface ListViewProps {
isFilterApplied: boolean;
}
function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
const { stagedQuery, panelType } = useQueryBuilder(); const { stagedQuery, panelType } = useQueryBuilder();
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector< const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
@ -49,7 +56,7 @@ function ListView(): JSX.Element {
QueryParams.pagination, QueryParams.pagination,
); );
const { data, isFetching, isError } = useGetQueryRange( const { data, isFetching, isLoading, isError } = useGetQueryRange(
{ {
query: stagedQuery || initialQueriesMap.traces, query: stagedQuery || initialQueriesMap.traces,
graphType: panelType || PANEL_TYPES.LIST, graphType: panelType || PANEL_TYPES.LIST,
@ -122,18 +129,36 @@ function ListView(): JSX.Element {
[columns, onDragColumns], [columns, onDragColumns],
); );
const isDataPresent =
!isLoading &&
!isFetching &&
!isError &&
transformedQueryTableData.length === 0;
return ( return (
<Container> <Container>
{transformedQueryTableData.length !== 0 && (
<TraceExplorerControls <TraceExplorerControls
isLoading={isFetching} isLoading={isFetching}
totalCount={totalCount} totalCount={totalCount}
config={config} config={config}
perPageOptions={PER_PAGE_OPTIONS} perPageOptions={PER_PAGE_OPTIONS}
/> />
)}
{isError && <ErrorText>{data?.error || 'Something went wrong'}</ErrorText>} {isError && <ErrorText>{data?.error || 'Something went wrong'}</ErrorText>}
{!isError && ( {(isLoading || (isFetching && transformedQueryTableData.length === 0)) && (
<TracesLoading />
)}
{isDataPresent && !isFilterApplied && (
<NoLogs dataSource={DataSource.TRACES} />
)}
{isDataPresent && isFilterApplied && <EmptyLogsSearch />}
{!isError && transformedQueryTableData.length !== 0 && (
<ResizeTable <ResizeTable
tableLayout="fixed" tableLayout="fixed"
pagination={false} pagination={false}

View File

@ -0,0 +1,19 @@
.loading-traces {
padding: 24px 0;
height: 240px;
display: flex;
justify-content: center;
align-items: flex-start;
.loading-traces-content {
display: flex;
align-items: flex-start;
flex-direction: column;
.loading-gif {
height: 72px;
margin-left: -24px;
}
}
}

View File

@ -0,0 +1,24 @@
import './TraceLoading.styles.scss';
import { Typography } from 'antd';
import { useTranslation } from 'react-i18next';
import { DataSource } from 'types/common/queryBuilder';
export function TracesLoading(): JSX.Element {
const { t } = useTranslation('common');
return (
<div className="loading-traces">
<div className="loading-traces-content">
<img
className="loading-gif"
src="/Icons/loading-plane.gif"
alt="wait-icon"
/>
<Typography>
{t('pending_data_placeholder', { dataSource: DataSource.TRACES })}
</Typography>
</div>
</div>
);
}

View File

@ -7,7 +7,6 @@ import { generatePath, Link } from 'react-router-dom';
import { ListItem } from 'types/api/widgets/getQuery'; import { ListItem } from 'types/api/widgets/getQuery';
export const PER_PAGE_OPTIONS: number[] = [10, ...DEFAULT_PER_PAGE_OPTIONS]; export const PER_PAGE_OPTIONS: number[] = [10, ...DEFAULT_PER_PAGE_OPTIONS];
export const TRACES_DETAILS_LINK = 'https://signoz.io/docs/userguide/traces/';
export const columns: ColumnsType<ListItem['data']> = [ export const columns: ColumnsType<ListItem['data']> = [
{ {

View File

@ -4,6 +4,8 @@ import { DEFAULT_ENTITY_VERSION } from 'constants/app';
import { QueryParams } from 'constants/query'; import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import EmptyLogsSearch from 'container/EmptyLogsSearch/EmptyLogsSearch';
import NoLogs from 'container/NoLogs/NoLogs';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { Pagination } from 'hooks/queryPagination'; import { Pagination } from 'hooks/queryPagination';
@ -11,13 +13,20 @@ import useUrlQueryData from 'hooks/useUrlQueryData';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers'; import { AppState } from 'store/reducers';
import { DataSource } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime';
import DOCLINKS from 'utils/docLinks';
import TraceExplorerControls from '../Controls'; import TraceExplorerControls from '../Controls';
import { columns, PER_PAGE_OPTIONS, TRACES_DETAILS_LINK } from './configs'; import { TracesLoading } from '../TraceLoading/TraceLoading';
import { columns, PER_PAGE_OPTIONS } from './configs';
import { ActionsContainer, Container } from './styles'; import { ActionsContainer, Container } from './styles';
function TracesView(): JSX.Element { interface TracesViewProps {
isFilterApplied: boolean;
}
function TracesView({ isFilterApplied }: TracesViewProps): JSX.Element {
const { stagedQuery, panelType } = useQueryBuilder(); const { stagedQuery, panelType } = useQueryBuilder();
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector< const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
@ -29,7 +38,7 @@ function TracesView(): JSX.Element {
QueryParams.pagination, QueryParams.pagination,
); );
const { data, isLoading } = useGetQueryRange( const { data, isLoading, isFetching, isError } = useGetQueryRange(
{ {
query: stagedQuery || initialQueriesMap.traces, query: stagedQuery || initialQueriesMap.traces,
graphType: panelType || PANEL_TYPES.TRACE, graphType: panelType || PANEL_TYPES.TRACE,
@ -65,10 +74,11 @@ function TracesView(): JSX.Element {
return ( return (
<Container> <Container>
{(tableData || []).length !== 0 && (
<ActionsContainer> <ActionsContainer>
<Typography> <Typography>
This tab only shows Root Spans. More details This tab only shows Root Spans. More details
<Typography.Link href={TRACES_DETAILS_LINK} target="_blank"> <Typography.Link href={DOCLINKS.TRACES_DETAILS_LINK} target="_blank">
{' '} {' '}
here here
</Typography.Link> </Typography.Link>
@ -79,6 +89,25 @@ function TracesView(): JSX.Element {
perPageOptions={PER_PAGE_OPTIONS} perPageOptions={PER_PAGE_OPTIONS}
/> />
</ActionsContainer> </ActionsContainer>
)}
{(isLoading || (isFetching && (tableData || []).length === 0)) && (
<TracesLoading />
)}
{!isLoading &&
!isFetching &&
!isError &&
!isFilterApplied &&
(tableData || []).length === 0 && <NoLogs dataSource={DataSource.TRACES} />}
{!isLoading &&
!isFetching &&
(tableData || []).length === 0 &&
!isError &&
isFilterApplied && <EmptyLogsSearch />}
{(tableData || []).length !== 0 && (
<ResizeTable <ResizeTable
loading={isLoading} loading={isLoading}
columns={columns} columns={columns}
@ -87,6 +116,7 @@ function TracesView(): JSX.Element {
scroll={{ x: true }} scroll={{ x: true }}
pagination={false} pagination={false}
/> />
)}
</Container> </Container>
); );
} }

View File

@ -23,7 +23,7 @@ import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange'; import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
import { useNotifications } from 'hooks/useNotifications'; import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history'; import history from 'lib/history';
import { cloneDeep, set } from 'lodash-es'; import { cloneDeep, isEmpty, set } from 'lodash-es';
import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback'; import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { Dashboard } from 'types/api/dashboard/getAll'; import { Dashboard } from 'types/api/dashboard/getAll';
@ -62,6 +62,12 @@ function TracesExplorer(): JSX.Element {
const currentTab = panelType || PANEL_TYPES.LIST; const currentTab = panelType || PANEL_TYPES.LIST;
const listQuery = useMemo(() => {
if (!stagedQuery || stagedQuery.builder.queryData.length < 1) return null;
return stagedQuery.builder.queryData.find((item) => !item.disabled) || null;
}, [stagedQuery]);
const isMultipleQueries = useMemo( const isMultipleQueries = useMemo(
() => () =>
currentQuery.builder.queryData.length > 1 || currentQuery.builder.queryData.length > 1 ||
@ -101,6 +107,7 @@ function TracesExplorer(): JSX.Element {
const tabsItems = getTabsItems({ const tabsItems = getTabsItems({
isListViewDisabled: isMultipleQueries || isGroupByExist, isListViewDisabled: isMultipleQueries || isGroupByExist,
isFilterApplied: !isEmpty(listQuery?.filters.items),
}); });
const exportDefaultQuery = useMemo( const exportDefaultQuery = useMemo(

View File

@ -9,10 +9,12 @@ import { DataSource } from 'types/common/queryBuilder';
interface GetTabsItemsProps { interface GetTabsItemsProps {
isListViewDisabled: boolean; isListViewDisabled: boolean;
isFilterApplied: boolean;
} }
export const getTabsItems = ({ export const getTabsItems = ({
isListViewDisabled, isListViewDisabled,
isFilterApplied,
}: GetTabsItemsProps): TabsProps['items'] => [ }: GetTabsItemsProps): TabsProps['items'] => [
{ {
label: ( label: (
@ -23,7 +25,7 @@ export const getTabsItems = ({
/> />
), ),
key: PANEL_TYPES.LIST, key: PANEL_TYPES.LIST,
children: <ListView />, children: <ListView isFilterApplied={isFilterApplied} />,
disabled: isListViewDisabled, disabled: isListViewDisabled,
}, },
{ {
@ -35,13 +37,18 @@ export const getTabsItems = ({
/> />
), ),
key: PANEL_TYPES.TRACE, key: PANEL_TYPES.TRACE,
children: <TracesView />, children: <TracesView isFilterApplied={isFilterApplied} />,
disabled: isListViewDisabled, disabled: isListViewDisabled,
}, },
{ {
label: <TabLabel label="Time Series" isDisabled={false} />, label: <TabLabel label="Time Series" isDisabled={false} />,
key: PANEL_TYPES.TIME_SERIES, key: PANEL_TYPES.TIME_SERIES,
children: <TimeSeriesView dataSource={DataSource.TRACES} />, children: (
<TimeSeriesView
dataSource={DataSource.TRACES}
isFilterApplied={isFilterApplied}
/>
),
}, },
{ {
label: 'Table View', label: 'Table View',

View File

@ -0,0 +1,9 @@
const DOCLINKS = {
TRACES_EXPLORER_EMPTY_STATE:
'https://signoz.io/docs/instrumentation/overview/?utm_source=product&utm_medium=traces-explorer-empty-state',
USER_GUIDE: 'https://signoz.io/docs/userguide/',
TRACES_DETAILS_LINK:
'https://signoz.io/docs/product-features/trace-explorer/?utm_source=product&utm_medium=traces-explorer-trace-tab#traces-view',
};
export default DOCLINKS;