Skip to content

Commit eb12afb

Browse files
feat(compass-indexes): adds support for hiding and unhiding indexes in Index tab (#4531)
Co-authored-by: Sergey Petushkov <[email protected]>
1 parent 52e3f8d commit eb12afb

28 files changed

+589
-153
lines changed

packages/compass-components/src/components/item-action-controls.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React, { useRef, forwardRef, useCallback, useState } from 'react';
22
import { Button, Icon, IconButton, Menu, MenuItem } from './leafygreen';
3+
import { Tooltip } from './tooltip';
4+
import type { TooltipProps } from './tooltip';
35
import type { ButtonProps } from '@leafygreen-ui/button';
46

57
import { spacing } from '@leafygreen-ui/tokens';
@@ -11,6 +13,11 @@ export type ItemAction<Action> = {
1113
icon: string;
1214
};
1315

16+
export type GroupedItemAction<Action> = ItemAction<Action> & {
17+
tooltip?: string;
18+
tooltipProps?: TooltipProps;
19+
};
20+
1421
export type MenuAction<Action> = {
1522
action: Action;
1623
label: string;
@@ -215,7 +222,7 @@ export function ItemActionGroup<Action extends string>({
215222
isVisible = true,
216223
'data-testid': dataTestId,
217224
}: {
218-
actions: ItemAction<Action>[];
225+
actions: GroupedItemAction<Action>[];
219226
onAction(actionName: Action): void;
220227
className?: string;
221228
iconClassName?: string;
@@ -243,21 +250,39 @@ export function ItemActionGroup<Action extends string>({
243250
className={cx(actionControlsStyle, className)}
244251
data-testid={dataTestId}
245252
>
246-
{actions.map(({ action, icon, label }) => {
247-
return (
253+
{actions.map(({ action, icon, label, tooltip, tooltipProps }) => {
254+
const button = (
248255
<ItemActionButton
249256
key={action}
250257
glyph={icon}
251258
label={label}
252-
title={label}
259+
title={!tooltip ? label : undefined}
253260
size={iconSize}
254261
data-action={action}
255262
data-testid={actionTestId<Action>(dataTestId, action)}
256263
onClick={onClick}
257264
className={cx(actionGroupButtonStyle, iconClassName)}
258265
style={iconStyle}
259-
></ItemActionButton>
266+
/>
260267
);
268+
269+
if (tooltip) {
270+
return (
271+
<Tooltip
272+
{...tooltipProps}
273+
trigger={({ children, ...props }) => (
274+
<div {...props} style={{ display: 'inherit' }}>
275+
{button}
276+
{children}
277+
</div>
278+
)}
279+
>
280+
{tooltip}
281+
</Tooltip>
282+
);
283+
}
284+
285+
return button;
261286
})}
262287
</div>
263288
);

packages/compass-components/src/components/tooltip.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,19 @@ type LeafyGreenTooltipProps = React.ComponentPropsWithoutRef<
2323

2424
type TooltipTrigger = React.FunctionComponent;
2525

26-
const Tooltip: React.FunctionComponent<
27-
TooltipTriggerProps &
28-
Omit<LeafyGreenTooltipProps, 'trigger'> & {
29-
trigger: TooltipTrigger;
30-
}
31-
> = ({ isDisabled, triggerOn, delay, trigger, children, ...rest }) => {
26+
type TooltipProps = TooltipTriggerProps &
27+
Omit<LeafyGreenTooltipProps, 'trigger'> & {
28+
trigger: TooltipTrigger;
29+
};
30+
31+
const Tooltip: React.FunctionComponent<TooltipProps> = ({
32+
isDisabled,
33+
triggerOn,
34+
delay,
35+
trigger,
36+
children,
37+
...rest
38+
}) => {
3239
const ref = useRef<HTMLDivElement | null>(null);
3340
const tooltipState = useTooltipTriggerState({
3441
isDisabled,
@@ -66,4 +73,4 @@ const Tooltip: React.FunctionComponent<
6673
);
6774
};
6875

69-
export { Tooltip };
76+
export { Tooltip, TooltipProps };

packages/compass-components/src/hooks/use-confirmation.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export { ConfirmationModalVariant };
99

1010
type ConfirmationProperties = {
1111
title: string;
12-
description: string;
12+
description: React.ReactNode;
1313
buttonText?: string;
1414
variant?: ConfirmationModalVariant;
1515
};
@@ -129,7 +129,7 @@ export const ConfirmationModalArea: React.FC = ({ children }) => {
129129
<ConfirmationModalContext.Provider value={contextValue}>
130130
{children}
131131
<ConfirmationModal
132-
data-testid="confirmation-modal"
132+
data-testid={'confirmation-modal'}
133133
open={confirmationProps.open}
134134
title={confirmationProps.title ?? 'Are you sure?'}
135135
variant={confirmationProps.variant ?? ConfirmationModalVariant.Default}

packages/compass-components/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import ResizableSidebar, {
4040
} from './components/resizeable-sidebar';
4141
import {
4242
ItemAction,
43+
GroupedItemAction,
4344
MenuAction,
4445
ItemActionControls,
4546
ItemActionGroup,
@@ -96,6 +97,7 @@ export {
9697
WarningSummary,
9798
WorkspaceTabs,
9899
ItemAction,
100+
GroupedItemAction,
99101
MenuAction,
100102
ItemActionControls,
101103
ItemActionGroup,
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import type { CompassBrowser } from '../compass-browser';
2+
import * as Selectors from '../selectors';
3+
4+
type CreateIndexOptions = {
5+
uniqueIndex?: boolean;
6+
indexName?: string;
7+
ttl?: number;
8+
partialFilterExpression?: string;
9+
wildcardProjection?: string;
10+
customCollation?: string;
11+
sparseIndex?: boolean;
12+
};
13+
14+
type IndexType = '1' | '-1' | '2dsphere' | 'text';
15+
16+
const indexTypeToIndexSelectOption: Record<IndexType, string> = {
17+
'1': '1 (asc)',
18+
'-1': '-1 (desc)',
19+
'2dsphere': '2dsphere',
20+
text: 'text',
21+
};
22+
23+
export async function createIndex(
24+
browser: CompassBrowser,
25+
indexDefinition: {
26+
fieldName: string;
27+
indexType: IndexType;
28+
},
29+
extraOptions?: CreateIndexOptions,
30+
screenshotName?: string
31+
): Promise<string> {
32+
const createRowIndex = 0;
33+
const { fieldName, indexType } = indexDefinition;
34+
const indexName = extraOptions?.indexName ?? `${fieldName}_${indexType}`;
35+
36+
// Open the modal
37+
await browser.clickVisible(Selectors.CreateIndexButton);
38+
const createModal = await browser.$(Selectors.CreateIndexModal);
39+
await createModal.waitForDisplayed();
40+
41+
// Select / type field name
42+
await browser.setValueVisible(
43+
Selectors.createIndexModalFieldNameSelectInput(createRowIndex),
44+
fieldName
45+
);
46+
await browser.keys(['Enter']);
47+
48+
// Select field type
49+
const fieldTypeSelect = await browser.$(
50+
Selectors.createIndexModalFieldTypeSelectButton(createRowIndex)
51+
);
52+
await fieldTypeSelect.waitForDisplayed();
53+
await fieldTypeSelect.click();
54+
const fieldTypeSelectMenu = await browser.$(
55+
Selectors.createIndexModalFieldTypeSelectMenu(createRowIndex)
56+
);
57+
await fieldTypeSelectMenu.waitForDisplayed();
58+
await browser.clickVisible(
59+
`li[value="${indexTypeToIndexSelectOption[indexType]}"]`
60+
);
61+
await fieldTypeSelectMenu.waitForDisplayed({ reverse: true });
62+
63+
// Select extra options
64+
if (extraOptions) {
65+
await browser.clickVisible(Selectors.IndexToggleOptions);
66+
const { wildcardProjection } = extraOptions;
67+
68+
if (wildcardProjection) {
69+
await browser.clickVisible(
70+
Selectors.indexToggleOption('wildcardProjection')
71+
);
72+
73+
// set the text in the editor
74+
await browser.setCodemirrorEditorValue(
75+
Selectors.indexOptionInput('wildcardProjection', 'code'),
76+
wildcardProjection
77+
);
78+
}
79+
}
80+
81+
if (screenshotName) {
82+
await browser.screenshot(screenshotName);
83+
}
84+
85+
// Create the index
86+
await browser.clickVisible(Selectors.CreateIndexConfirmButton);
87+
88+
// Assert that modal goes away
89+
await createModal.waitForDisplayed({ reverse: true });
90+
91+
// Assert that index does come in table
92+
const indexComponentSelector = Selectors.indexComponent(indexName);
93+
const indexComponent = await browser.$(indexComponentSelector);
94+
await indexComponent.waitForDisplayed();
95+
96+
return indexName;
97+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { CompassBrowser } from '../compass-browser';
2+
import * as Selectors from '../selectors';
3+
4+
export async function dropIndex(
5+
browser: CompassBrowser,
6+
indexName: string,
7+
screenshotName?: string
8+
) {
9+
const indexComponentSelector = Selectors.indexComponent(indexName);
10+
const indexComponent = await browser.$(indexComponentSelector);
11+
await indexComponent.waitForDisplayed();
12+
13+
await browser.hover(indexComponentSelector);
14+
await browser.clickVisible(
15+
`${indexComponentSelector} ${Selectors.DropIndexButton}`
16+
);
17+
18+
const dropModal = await browser.$(Selectors.DropIndexModal);
19+
await dropModal.waitForDisplayed();
20+
21+
const confirmInput = await browser.$(Selectors.DropIndexModalConfirmName);
22+
await confirmInput.waitForDisplayed();
23+
await confirmInput.setValue(indexName);
24+
25+
if (screenshotName) {
26+
await browser.screenshot(screenshotName);
27+
}
28+
29+
const ConfirmButtonSelector = Selectors.ConfirmationModalConfirmButton(
30+
Selectors.DropIndexModal
31+
);
32+
await browser.clickVisible(ConfirmButtonSelector);
33+
34+
await dropModal.waitForDisplayed({ reverse: true });
35+
36+
await indexComponent.waitForDisplayed({ reverse: true });
37+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { CompassBrowser } from '../compass-browser';
2+
import * as Selectors from '../selectors';
3+
4+
export async function hideIndex(
5+
browser: CompassBrowser,
6+
indexName: string,
7+
screenshotName?: string
8+
) {
9+
const indexComponentSelector = Selectors.indexComponent(indexName);
10+
const indexComponent = await browser.$(indexComponentSelector);
11+
await indexComponent.waitForDisplayed();
12+
13+
await browser.hover(indexComponentSelector);
14+
await browser.clickVisible(
15+
`${indexComponentSelector} ${Selectors.HideIndexButton}`
16+
);
17+
18+
const hideModal = await browser.$(Selectors.ConfirmationModal);
19+
await hideModal.waitForDisplayed();
20+
21+
if (screenshotName) {
22+
await browser.screenshot(screenshotName);
23+
}
24+
25+
await browser.clickVisible(Selectors.ConfirmationModalConfirmButton());
26+
27+
await hideModal.waitForDisplayed({ reverse: true });
28+
29+
const hiddenBadge = await browser.$(Selectors.HiddenIndexBadge(indexName));
30+
await hiddenBadge.waitForDisplayed();
31+
}

packages/compass-e2e-tests/helpers/commands/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,7 @@ export * from './add-wizard';
6060
export * from './set-combo-box-value';
6161
export * from './wait-for-export-to-finish';
6262
export * from './get-connect-form-connection-string';
63+
export * from './create-index';
64+
export * from './drop-index';
65+
export * from './hide-index';
66+
export * from './unhide-index';
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { CompassBrowser } from '../compass-browser';
2+
import * as Selectors from '../selectors';
3+
4+
export async function unhideIndex(
5+
browser: CompassBrowser,
6+
indexName: string,
7+
screenshotName?: string
8+
) {
9+
const indexComponentSelector = Selectors.indexComponent(indexName);
10+
const indexComponent = await browser.$(indexComponentSelector);
11+
await indexComponent.waitForDisplayed();
12+
13+
await browser.hover(indexComponentSelector);
14+
await browser.clickVisible(
15+
`${indexComponentSelector} ${Selectors.UnhideIndexButton}`
16+
);
17+
18+
const unhideModal = await browser.$(Selectors.ConfirmationModal);
19+
await unhideModal.waitForDisplayed();
20+
21+
if (screenshotName) {
22+
await browser.screenshot(screenshotName);
23+
}
24+
25+
await browser.clickVisible(Selectors.ConfirmationModalConfirmButton());
26+
27+
await unhideModal.waitForDisplayed({ reverse: true });
28+
29+
const hiddenBadge = await browser.$(Selectors.HiddenIndexBadge(indexName));
30+
await hiddenBadge.waitForDisplayed({ reverse: true });
31+
}

packages/compass-e2e-tests/helpers/selectors.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -957,11 +957,17 @@ export const CreateIndexConfirmButton = `${CreateIndexModal} [data-testid="creat
957957
export const DropIndexModal = '[data-testid="drop-index-modal"]';
958958
export const DropIndexModalConfirmName =
959959
'[data-testid="confirm-drop-index-name"]';
960-
export const DropIndexModalConfirmButton =
961-
'[data-testid="drop-index-modal"] [role=dialog] > div:nth-child(2) button:first-child';
962-
963960
export const DropIndexButton = '[data-testid="index-actions-delete-action"]';
964961

962+
export const HiddenIndexBadge = (indexName: string) =>
963+
`${indexComponent(indexName)} [data-testid="HIDDEN-badge"]`;
964+
export const HideIndexModal = '[data-testid="hide-index-confirmation-modal"]';
965+
export const HideIndexButton = '[data-testid="index-actions-hide-action"]';
966+
967+
export const UnhideIndexModal =
968+
'[data-testid="unhide-index-confirmation-modal"]';
969+
export const UnhideIndexButton = '[data-testid="index-actions-unhide-action"]';
970+
965971
// Validation tab
966972
export const AddRuleButton = '[data-testid="add-rule-button"]';
967973
export const ValidationEditor = '[data-testid="validation-editor"]';
@@ -1079,7 +1085,9 @@ export const ExportToLanguageQueryOutput =
10791085

10801086
// Confirmation modal
10811087
export const ConfirmationModal = '[data-testid="confirmation-modal"]';
1082-
export const ConfirmationModalConfirmButton = `${ConfirmationModal} [role=dialog] > div:nth-child(2) button:first-child`;
1088+
export const ConfirmationModalConfirmButton = (
1089+
modalSelector = ConfirmationModal
1090+
) => `${modalSelector} [role=dialog] button:nth-of-type(1)`;
10831091

10841092
// New pipeline from text modal
10851093
export const NewPipelineFromTextModal = '[data-testid="import-pipeline-modal"]';

0 commit comments

Comments
 (0)