Skip to content

Commit ac54b07

Browse files
authored
feat(crud): add tooltip for N/A count COMPASS-10076 (#7568)
1 parent 1177454 commit ac54b07

File tree

5 files changed

+70
-8
lines changed

5 files changed

+70
-8
lines changed

packages/compass-crud/src/components/crud-toolbar.spec.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
within,
77
userEvent,
88
renderWithConnections,
9+
waitFor,
910
} from '@mongodb-js/testing-library-compass';
1011
import type { PreferencesAccess } from 'compass-preferences-model';
1112
import { createSandboxFromDefaultPreferences } from 'compass-preferences-model';
@@ -37,6 +38,7 @@ describe('CrudToolbar Component', function () {
3738
count={55}
3839
end={20}
3940
getPage={noop}
41+
lastCountRunMaxTimeMS={12345}
4042
insertDataHandler={noop}
4143
loadingCount={false}
4244
isFetching={false}
@@ -499,6 +501,31 @@ describe('CrudToolbar Component', function () {
499501
});
500502
});
501503

504+
describe('when count the count is unavailable', function () {
505+
it('shows N/A with the count maxTimeMS', async function () {
506+
renderCrudToolbar({
507+
count: undefined,
508+
});
509+
expect(screen.getByText('N/A')).to.be.visible;
510+
511+
const naText = screen.getByTestId('crud-document-count-unavailable');
512+
expect(naText).to.be.visible;
513+
userEvent.hover(naText);
514+
515+
await waitFor(
516+
function () {
517+
expect(screen.getByRole('tooltip')).to.exist;
518+
},
519+
{
520+
timeout: 5000,
521+
}
522+
);
523+
524+
const tooltipText = screen.getByRole('tooltip').textContent;
525+
expect(tooltipText).to.include('maxTimeMS of 12345.');
526+
});
527+
});
528+
502529
describe('context menu', function () {
503530
beforeEach(async function () {
504531
await preferences.savePreferences({ enableImportExport: true });
@@ -897,6 +924,7 @@ describe('CrudToolbar Component', function () {
897924
isFetching={false}
898925
docsPerPage={25}
899926
isWritable
927+
lastCountRunMaxTimeMS={1234}
900928
instanceDescription=""
901929
onApplyClicked={noop}
902930
onResetClicked={noop}

packages/compass-crud/src/components/crud-toolbar.tsx

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ import {
2121
useContextMenuGroups,
2222
usePersistedState,
2323
AtlasSkillsBanner,
24+
Tooltip,
2425
} from '@mongodb-js/compass-components';
2526
import type { MenuAction, Signal } from '@mongodb-js/compass-components';
2627
import { ViewSwitcher } from './view-switcher';
27-
import type { DocumentView } from '../stores/crud-store';
28+
import { type DocumentView } from '../stores/crud-store';
2829
import { AddDataMenu } from './add-data-menu';
2930
import { usePreference } from 'compass-preferences-model/provider';
3031
import UpdateMenu from './update-data-menu';
@@ -87,6 +88,12 @@ const loaderContainerStyles = css({
8788
paddingRight: spacing[200],
8889
});
8990

91+
const countUnavailableTextStyles = css({
92+
textDecoration: 'underline',
93+
textDecorationStyle: 'dotted',
94+
textUnderlineOffset: '3px',
95+
});
96+
9097
type ExportDataOption = 'export-query' | 'export-full-collection';
9198
const exportDataActions: MenuAction<ExportDataOption>[] = [
9299
{ action: 'export-query', label: 'Export query results' },
@@ -109,6 +116,9 @@ const ERROR_CODE_OPERATION_TIMED_OUT = 50;
109116
const INCREASE_MAX_TIME_MS_HINT =
110117
'Operation exceeded time limit. Please try increasing the maxTimeMS for the query in the expanded filter options.';
111118

119+
const countUnavailableTooltipText = (maxTimeMS: number) =>
120+
`The count is not available for this query. This can happen when the count operation fails or exceeds the maxTimeMS of ${maxTimeMS}.`;
121+
112122
type ErrorWithPossibleCode = Error & {
113123
code?: {
114124
value: number;
@@ -132,6 +142,7 @@ export type CrudToolbarProps = {
132142
instanceDescription: string;
133143
isWritable: boolean;
134144
isFetching: boolean;
145+
lastCountRunMaxTimeMS: number;
135146
loadingCount: boolean;
136147
onApplyClicked: () => void;
137148
onResetClicked: () => void;
@@ -164,6 +175,7 @@ const CrudToolbar: React.FunctionComponent<CrudToolbarProps> = ({
164175
instanceDescription,
165176
isWritable,
166177
isFetching,
178+
lastCountRunMaxTimeMS,
167179
loadingCount,
168180
onApplyClicked,
169181
onResetClicked,
@@ -198,11 +210,6 @@ const CrudToolbar: React.FunctionComponent<CrudToolbarProps> = ({
198210
SkillsBannerContextEnum.Documents
199211
);
200212

201-
const displayedDocumentCount = useMemo(
202-
() => (loadingCount ? '' : `${count ?? 'N/A'}`),
203-
[loadingCount, count]
204-
);
205-
206213
const onClickRefreshDocuments = useCallback(() => {
207214
track('Query Results Refreshed', {}, connectionInfoRef.current);
208215
refreshDocuments();
@@ -416,7 +423,27 @@ const CrudToolbar: React.FunctionComponent<CrudToolbarProps> = ({
416423
</Select>
417424
<Body data-testid="crud-document-count-display">
418425
{start}{end}{' '}
419-
{displayedDocumentCount && `of ${displayedDocumentCount}`}
426+
{!loadingCount && (
427+
<span>
428+
{'of '}
429+
{count ?? (
430+
<Tooltip
431+
trigger={
432+
<span
433+
data-testid="crud-document-count-unavailable"
434+
className={countUnavailableTextStyles}
435+
>
436+
N/A
437+
</span>
438+
}
439+
>
440+
<Body>
441+
{countUnavailableTooltipText(lastCountRunMaxTimeMS)}
442+
</Body>
443+
</Tooltip>
444+
)}
445+
</span>
446+
)}
420447
</Body>
421448
{loadingCount && (
422449
<div className={loaderContainerStyles}>

packages/compass-crud/src/components/document-list.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export type DocumentListProps = {
121121
CrudToolbarProps,
122122
| 'error'
123123
| 'count'
124+
| 'lastCountRunMaxTimeMS'
124125
| 'loadingCount'
125126
| 'start'
126127
| 'end'
@@ -278,6 +279,7 @@ const DocumentList: React.FunctionComponent<DocumentListProps> = (props) => {
278279
view,
279280
error,
280281
count,
282+
lastCountRunMaxTimeMS,
281283
loadingCount,
282284
start,
283285
end,
@@ -534,6 +536,7 @@ const DocumentList: React.FunctionComponent<DocumentListProps> = (props) => {
534536
error={error}
535537
count={count}
536538
isFetching={isFetching}
539+
lastCountRunMaxTimeMS={lastCountRunMaxTimeMS}
537540
loadingCount={loadingCount}
538541
start={start}
539542
end={end}

packages/compass-crud/src/stores/crud-store.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ describe('store', function () {
316316
status: 'closed',
317317
},
318318
debouncingLoad: false,
319+
lastCountRunMaxTimeMS: 5000,
319320
loadingCount: false,
320321
collection: 'test',
321322
count: null,

packages/compass-crud/src/stores/crud-store.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ const DEFAULT_INITIAL_MAX_TIME_MS = 60000;
253253
* We want to make sure `count` does not hold back the query results for too
254254
* long after docs are returned.
255255
*/
256-
const COUNT_MAX_TIME_MS_CAP = 5000;
256+
export const COUNT_MAX_TIME_MS_CAP = 5000;
257257

258258
/**
259259
* The key we use to persist the user selected maximum documents per page for
@@ -345,6 +345,7 @@ type CrudState = {
345345
isReadonly: boolean;
346346
isTimeSeries: boolean;
347347
status: DOCUMENTS_STATUSES;
348+
lastCountRunMaxTimeMS: number;
348349
debouncingLoad: boolean;
349350
loadingCount: boolean;
350351
shardKeys: null | BSONObject;
@@ -453,6 +454,7 @@ class CrudStoreImpl
453454
status: DOCUMENTS_STATUS_INITIAL,
454455
debouncingLoad: false,
455456
loadingCount: false,
457+
lastCountRunMaxTimeMS: COUNT_MAX_TIME_MS_CAP,
456458
shardKeys: null,
457459
resultId: resultId(),
458460
isWritable: this.instance.isWritable,
@@ -1779,6 +1781,7 @@ class CrudStoreImpl
17791781

17801782
// This is so that the UI can update to show that we're fetching
17811783
this.setState({
1784+
lastCountRunMaxTimeMS: countOptions.maxTimeMS,
17821785
status: DOCUMENTS_STATUS_FETCHING,
17831786
abortController,
17841787
error: null,

0 commit comments

Comments
 (0)