Skip to content

Commit 317e62d

Browse files
github-actions[bot]Adam Tackett
and
Adam Tackett
committed
Traces - Update custom source toast/error/sorting (#2407)
* remove sorting on invalid fields, adjust load more ui Signed-off-by: Adam Tackett <[email protected]> * change Trace ID to Trace Id, fix min size for customdatagrid Signed-off-by: Adam Tackett <[email protected]> * add error state for invalid url traces/services Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * add selected time range callout to service page Signed-off-by: Adam Tackett <[email protected]> * add empty state to services, add cypress test Signed-off-by: Adam Tackett <[email protected]> * update cypress url Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * cypress fix test Signed-off-by: Adam Tackett <[email protected]> * cypress fix test Signed-off-by: Adam Tackett <[email protected]> * remove aggregation from service name validation Signed-off-by: Adam Tackett <[email protected]> --------- Signed-off-by: Adam Tackett <[email protected]> Co-authored-by: Adam Tackett <[email protected]> (cherry picked from commit 7dcfbaa) Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent d5a4f15 commit 317e62d

25 files changed

+512
-253
lines changed

.cypress/integration/app_analytics_test/app_analytics.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ describe('Viewing application', () => {
318318
cy.get('[data-test-subj="spanDetailFlyout"]').should('not.exist');
319319
});
320320

321-
it('Opens trace detail flyout when Trace ID is clicked', () => {
321+
it('Opens trace detail flyout when Trace Id is clicked', () => {
322322
cy.get('[data-test-subj="app-analytics-traceTab"]').click();
323323
cy.get('[data-test-subj="globalLoadingIndicator"]').should('not.exist');
324324
cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click();

.cypress/integration/trace_analytics_test/trace_analytics_services.spec.js

+29-10
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
verify_traces_spans_data_grid_cols_exists,
1414
count_table_row,
1515
AUTH_SERVICE_SPAN_ID,
16+
INVALID_URL,
1617
} from '../../utils/constants';
1718
import { suppressResizeObserverIssue } from '../../utils/constants';
1819

@@ -93,19 +94,37 @@ describe('Testing services table', () => {
9394
});
9495
});
9596

96-
describe('Testing service view empty state', () => {
97-
beforeEach(() => {
98-
cy.visit(`app/observability-traces#/services/${SERVICE_NAME}`, {
97+
describe('Testing service view empty state and invalid url', () => {
98+
it('Renders service view empty state and invalid url', () => {
99+
cy.visit(`app/observability-traces#/services?serviceId=${SERVICE_NAME}`, {
99100
onBeforeLoad: (win) => {
100101
win.sessionStorage.clear();
101102
},
102103
});
103-
});
104-
105-
it('Renders service view empty state', () => {
104+
cy.get('[data-test-subj="globalLoadingIndicator"]').should('not.exist');
106105
cy.contains('frontend-client').should('exist');
107-
cy.get('.euiText').contains('0').should('exist');
108-
cy.get('.euiText').contains('-').should('exist');
106+
cy.contains('No matches').should('exist');
107+
108+
// Renders service view invalid url state
109+
cy.visit(`app/observability-traces#/services?serviceId=${INVALID_URL}`, {
110+
onBeforeLoad: (win) => {
111+
win.sessionStorage.clear();
112+
},
113+
});
114+
cy.get('[data-test-subj="globalLoadingIndicator"]').should('not.exist');
115+
cy.contains(`${INVALID_URL}`).should('exist');
116+
cy.get('.euiCallOut.euiCallOut--danger')
117+
.should('exist')
118+
.within(() => {
119+
cy.get('.euiCallOutHeader__title')
120+
.should('contain.text', `Error loading service: ${INVALID_URL}`);
121+
cy.get('p')
122+
.should(
123+
'contain.text',
124+
'The service name is invalid or could not be found. Please check the URL or try again.'
125+
);
126+
});
127+
cy.contains('No matches').should('exist');
109128
});
110129
});
111130

@@ -410,9 +429,9 @@ describe('Testing traces Spans table and verify columns functionality', () => {
410429
expandServiceView(1);
411430
verify_traces_spans_data_grid_cols_exists();
412431
cy.get('[data-test-subj="service-dep-table"]').should('exist');
413-
cy.get('.euiDataGridHeaderCell__content').contains('Span ID').click();
432+
cy.get('.euiDataGridHeaderCell__content').contains('Span Id').click();
414433
cy.get('.euiListGroupItem__label').contains('Hide column').click();
415-
cy.get('.euiDataGridHeaderCell__content').contains('Trace ID').click();
434+
cy.get('.euiDataGridHeaderCell__content').contains('Trace Id').click();
416435
cy.get('.euiListGroupItem__label').contains('Sort A-Z').click();
417436
cy.get('.euiDataGridHeaderCell__content').contains('Trace group').click();
418437
cy.get('.euiListGroupItem__label').contains('Move left').click();

.cypress/integration/trace_analytics_test/trace_analytics_traces.spec.js

+30-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
/// <reference types="cypress" />
77

8-
import { setTimeFilter, SPAN_ID, TRACE_ID, SPAN_ID_TREE_VIEW } from '../../utils/constants';
8+
import { setTimeFilter, SPAN_ID, TRACE_ID, SPAN_ID_TREE_VIEW, INVALID_URL } from '../../utils/constants';
99

1010
describe('Testing traces table empty state', () => {
1111
beforeEach(() => {
@@ -124,6 +124,32 @@ describe('Testing trace view', () => {
124124
});
125125
});
126126

127+
describe('Testing trace view invalid url', () => {
128+
beforeEach(() => {
129+
cy.visit(`app/observability-traces#/traces?traceId=${INVALID_URL}`, {
130+
onBeforeLoad: (win) => {
131+
win.sessionStorage.clear();
132+
},
133+
});
134+
});
135+
136+
it('Handles a invalid trace url', () => {
137+
cy.get('[data-test-subj="globalLoadingIndicator"]').should('not.exist');
138+
cy.contains(`${INVALID_URL}`).should('exist');
139+
cy.get('.euiCallOut.euiCallOut--danger')
140+
.should('exist')
141+
.within(() => {
142+
cy.get('.euiCallOutHeader__title')
143+
.should('contain.text', `Error loading Trace Id: ${INVALID_URL}`);
144+
cy.get('p')
145+
.should(
146+
'contain.text',
147+
'The Trace Id is invalid or could not be found. Please check the URL or try again.'
148+
);
149+
});
150+
});
151+
});
152+
127153
describe('Testing traces table', () => {
128154
beforeEach(() => {
129155
cy.visit('app/observability-traces#/traces', {
@@ -137,7 +163,7 @@ describe('Testing traces table', () => {
137163
});
138164

139165
it('Renders the traces table and verify Table Column, Pagination and Rows Data ', () => {
140-
cy.get('.euiTableCellContent__text').contains('Trace ID').should('exist');
166+
cy.get('.euiTableCellContent__text').contains('Trace Id').should('exist');
141167
cy.get('.euiTableCellContent__text').contains('Trace group').should('exist');
142168
cy.get('.euiTableCellContent__text').contains('Duration (ms)').should('exist');
143169
cy.get('.euiTableCellContent__text').contains('Percentile in trace group').should('exist');
@@ -287,7 +313,7 @@ describe('Testing switch mode to jaeger', () => {
287313
cy.contains('No').should('exist');
288314
cy.contains('01/24/2023 08:33:35').should('exist');
289315
cy.contains('Latency (ms)').should('exist');
290-
cy.contains('Trace ID').should('exist');
316+
cy.contains('Trace Id').should('exist');
291317
cy.contains('Errors').should('exist');
292318
cy.contains('Last updated').should('exist');
293319
});
@@ -372,7 +398,7 @@ describe('Testing traces Custom source', () => {
372398
cy.get('.euiSelectableListItem').contains('Traces').click();
373399
cy.get('[data-test-subj="globalLoadingIndicator"]').should('not.exist');
374400

375-
cy.get('.euiDataGridHeaderCell__content').contains('Trace ID').should('exist');
401+
cy.get('.euiDataGridHeaderCell__content').contains('Trace Id').should('exist');
376402
cy.get('.euiDataGridHeaderCell__content').contains('Trace group').should('exist');
377403
cy.get('.euiDataGridHeaderCell__content').contains('Duration (ms)').should('exist');
378404
cy.get('.euiDataGridHeaderCell__content').contains('Percentile in trace group').should('exist');

.cypress/utils/constants.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const SPAN_ID_TREE_VIEW = 'fe4076542b41d40b';
2121
export const SERVICE_NAME = 'frontend-client';
2222
export const SERVICE_SPAN_ID = 'e275ac9d21929e9b';
2323
export const AUTH_SERVICE_SPAN_ID = '277a5934acf55dcf';
24+
export const INVALID_URL = 'invalid_url';
2425

2526
export const testDataSet = [
2627
{
@@ -154,8 +155,8 @@ export const suppressResizeObserverIssue = () => {
154155
};
155156

156157
export const verify_traces_spans_data_grid_cols_exists = () => {
157-
cy.get('.euiDataGridHeaderCell__content').contains('Span ID').should('exist');
158-
cy.get('.euiDataGridHeaderCell__content').contains('Trace ID').should('exist');
158+
cy.get('.euiDataGridHeaderCell__content').contains('Span Id').should('exist');
159+
cy.get('.euiDataGridHeaderCell__content').contains('Trace Id').should('exist');
159160
cy.get('.euiDataGridHeaderCell__content').contains('Operation').should('exist');
160161
cy.get('.euiDataGridHeaderCell__content').contains('Duration').should('exist');
161162
cy.get('.euiDataGridHeaderCell__content').contains('Start time').should('exist');

public/components/application_analytics/__tests__/__snapshots__/flyout.test.tsx.snap

+5-5
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ exports[`Trace Detail Render Flyout component render trace detail 1`] = `
2828
/>
2929
</EuiSpacer>
3030
<div
31-
key="list-item-Trace ID"
31+
key="list-item-Trace Id"
3232
>
3333
<EuiDescriptionList
3434
align="center"
3535
compressed={true}
36-
data-test-subj="Trace IDDescriptionList"
36+
data-test-subj="Trace IdDescriptionList"
3737
listItems={
3838
Array [
3939
Object {
@@ -61,7 +61,7 @@ exports[`Trace Detail Render Flyout component render trace detail 1`] = `
6161
}
6262
}
6363
>
64-
Trace ID
64+
Trace Id
6565
</EuiText>,
6666
},
6767
]
@@ -70,7 +70,7 @@ exports[`Trace Detail Render Flyout component render trace detail 1`] = `
7070
>
7171
<dl
7272
className="euiDescriptionList euiDescriptionList--column euiDescriptionList--center euiDescriptionList--compressed"
73-
data-test-subj="Trace IDDescriptionList"
73+
data-test-subj="Trace IdDescriptionList"
7474
>
7575
<EuiDescriptionListTitle
7676
key="title-0"
@@ -104,7 +104,7 @@ exports[`Trace Detail Render Flyout component render trace detail 1`] = `
104104
<div
105105
className="euiTextColor euiTextColor--subdued"
106106
>
107-
Trace ID
107+
Trace Id
108108
</div>
109109
</EuiTextColor>
110110
</div>

public/components/application_analytics/components/flyout_components/trace_detail_render.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export const TraceDetailRender = ({
5151
const renderContent = useMemo(() => {
5252
if (!traceId) return <></>;
5353
const overviewList = [
54-
getListItem('Trace ID', traceId),
54+
getListItem('Trace Id', traceId),
5555
getListItem('Trace group name', fields.trace_group || '-'),
5656
getListItem('Latency', fields.latency),
5757
getListItem('Last updated', fields.last_updated),

public/components/trace_analytics/components/common/__tests__/__snapshots__/search_bar.test.tsx.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ exports[`Search bar components renders search bar 1`] = `
419419
isLoading={false}
420420
onChange={[Function]}
421421
onSearch={[Function]}
422-
placeholder="Trace ID, trace group name, service name"
422+
placeholder="Trace Id, trace group name, service name"
423423
prepend={
424424
<GlobalFilterButton
425425
attributesFilterFields={Array []}
@@ -591,7 +591,7 @@ exports[`Search bar components renders search bar 1`] = `
591591
data-test-subj="search-bar-input-box"
592592
onChange={[Function]}
593593
onKeyUp={[Function]}
594-
placeholder="Trace ID, trace group name, service name"
594+
placeholder="Trace Id, trace group name, service name"
595595
type="search"
596596
value="test"
597597
/>

public/components/trace_analytics/components/common/search_bar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export const SearchBar = forwardRef((props: SearchBarOwnProps, ref) => {
8787
fullWidth
8888
isClearable={false}
8989
placeholder={i18n.translate('traceAnalytics.searchBar.placeholder', {
90-
defaultMessage: 'Trace ID, trace group name, service name',
90+
defaultMessage: 'Trace Id, trace group name, service name',
9191
})}
9292
data-test-subj="search-bar-input-box"
9393
value={query}

public/components/trace_analytics/components/common/shared_components/component_helper_functions.tsx

+24-20
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export const useInjectElementsIntoGrid = (
1111
maxDisplayRows: number,
1212
tracesTableMode: string,
1313
loadMoreHandler?: () => void,
14-
maxTraces?: number
14+
maxTraces?: number,
15+
isLastPage?: boolean
1516
) => {
1617
useEffect(() => {
1718
setTimeout(() => {
@@ -51,34 +52,37 @@ export const useInjectElementsIntoGrid = (
5152
}
5253

5354
const pagination = document.querySelector<HTMLElement>('.euiDataGrid__pagination');
55+
const existingLoadMoreButton = pagination?.querySelector('.trace-table-load-more');
5456

55-
if (tracesTableMode !== 'traces') {
56-
if (pagination) {
57-
const existingLoadMoreButton = pagination.querySelector('.trace-table-load-more');
58-
if (existingLoadMoreButton) {
59-
existingLoadMoreButton.remove();
60-
}
57+
if (tracesTableMode !== 'traces' || !pagination || !loadMoreHandler || !isLastPage) {
58+
if (existingLoadMoreButton) {
59+
existingLoadMoreButton.remove();
6160
}
6261
return;
6362
}
6463

65-
if (pagination && loadMoreHandler) {
66-
pagination.style.display = 'flex';
67-
pagination.style.alignItems = 'center';
68-
pagination.style.justifyContent = 'space-between';
64+
pagination.style.display = 'flex';
65+
pagination.style.alignItems = 'center';
66+
pagination.style.justifyContent = 'space-between';
6967

70-
let loadMoreButton = pagination.querySelector<HTMLElement>('.trace-table-load-more');
71-
if (!loadMoreButton) {
72-
loadMoreButton = document.createElement('button');
73-
loadMoreButton.className = 'trace-table-load-more euiButtonEmpty euiButtonEmpty--text';
74-
loadMoreButton.style.marginLeft = '12px';
75-
loadMoreButton.innerText = 'Load more data';
68+
let loadMoreButton = pagination.querySelector<HTMLElement>('.trace-table-load-more');
69+
if (!loadMoreButton) {
70+
loadMoreButton = document.createElement('button');
71+
loadMoreButton.className = 'trace-table-load-more euiButtonEmpty euiButtonEmpty--text';
72+
loadMoreButton.style.marginLeft = '12px';
73+
loadMoreButton.innerText = '... Load more';
7674

77-
loadMoreButton.onclick = () => loadMoreHandler();
75+
loadMoreButton.onclick = () => loadMoreHandler();
7876

79-
pagination.appendChild(loadMoreButton);
77+
const paginationList = pagination.querySelector('.euiPagination__list');
78+
79+
if (paginationList) {
80+
const listItem = document.createElement('li');
81+
listItem.className = 'euiPagination__item trace-table-load-more';
82+
listItem.appendChild(loadMoreButton);
83+
paginationList.appendChild(listItem);
8084
}
8185
}
8286
}, 100);
83-
}, [rowCount, tracesTableMode, loadMoreHandler, maxTraces, maxDisplayRows]);
87+
}, [rowCount, tracesTableMode, loadMoreHandler, maxTraces, maxDisplayRows, isLastPage]);
8488
};

public/components/trace_analytics/components/common/shared_components/custom_datagrid.tsx

+32-7
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
EuiTextColor,
2323
} from '@elastic/eui';
2424
import { i18n } from '@osd/i18n';
25-
import React, { useMemo, useState } from 'react';
25+
import React, { useEffect, useMemo, useState } from 'react';
2626
import { NoMatchMessage } from '../helper_functions';
2727
import {
2828
TRACE_TABLE_OPTIONS,
@@ -91,8 +91,8 @@ interface RenderCustomDataGridParams {
9191
isTableDataLoading?: boolean;
9292
tracesTableMode?: string;
9393
setTracesTableMode?: (mode: string) => void;
94-
maxTraces: number;
95-
setMaxTraces: (max: number) => void;
94+
maxTraces?: number;
95+
setMaxTraces?: (max: number) => void;
9696
}
9797

9898
export const RenderCustomDataGrid: React.FC<RenderCustomDataGridParams> = ({
@@ -137,14 +137,39 @@ export const RenderCustomDataGrid: React.FC<RenderCustomDataGridParams> = ({
137137
)
138138
: [];
139139

140+
const isLastPage =
141+
tracesTableMode === 'traces' && pagination?.pageSize && maxTraces != null
142+
? (pagination.pageIndex + 1) * pagination.pageSize >= maxTraces &&
143+
rowCount > maxTraces &&
144+
maxTraces < MAX_DISPLAY_ROWS
145+
: false;
146+
147+
// Used for when trace count less than default maxTraces
148+
useEffect(() => {
149+
if (
150+
tracesTableMode === 'traces' &&
151+
rowCount > 0 &&
152+
rowCount < maxTraces &&
153+
maxTraces !== rowCount
154+
) {
155+
setMaxTraces(rowCount);
156+
}
157+
}, [rowCount, maxTraces, tracesTableMode]);
158+
159+
const incrementTraceCount = () => {
160+
const nextIncrement = Math.min(500, rowCount - maxTraces);
161+
if (nextIncrement > 0 && maxTraces < MAX_DISPLAY_ROWS) {
162+
setMaxTraces((prevMax) => Math.min(prevMax + nextIncrement, MAX_DISPLAY_ROWS));
163+
}
164+
};
165+
140166
useInjectElementsIntoGrid(
141167
rowCount,
142168
MAX_DISPLAY_ROWS,
143169
tracesTableMode ?? '',
144-
() => {
145-
setMaxTraces((prevMax: number) => Math.min(prevMax + 500, MAX_DISPLAY_ROWS));
146-
},
147-
maxTraces
170+
incrementTraceCount,
171+
maxTraces,
172+
isLastPage
148173
);
149174

150175
const disableInteractions = useMemo(() => isFullScreen, [isFullScreen]);

0 commit comments

Comments
 (0)