Skip to content

Commit 5a6c445

Browse files
authored
feat(sidebar): connections filter popover COMPASS-8503 (#6486)
* Refactor ConnectionsNavigation into NavigationItemsFilter * Refactor to a popover * Delete unused icons * Add activated indicator * Blur trigger when closing popover * Fix failing tests * Avoid className prop on NavigationItemsFilter * fixup! Refactor to a popover Pass hideCloseButton instead of using display none * fixup! Blur trigger when closing popover Fix generating unique ids * Remove comments * Revert "Blur trigger when closing popover" This reverts part of commit 6d19bbe. * Control tooltip to avoid it showing when closing popover
1 parent 28bb675 commit 5a6c445

File tree

10 files changed

+301
-240
lines changed

10 files changed

+301
-240
lines changed

packages/compass-components/src/components/icons/connected-plugs.tsx

Lines changed: 0 additions & 46 deletions
This file was deleted.

packages/compass-components/src/components/icons/disconnected-plug.tsx

Lines changed: 0 additions & 27 deletions
This file was deleted.

packages/compass-components/src/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ export { DocumentIcon } from './components/icons/document-icon';
5959
export { FavoriteIcon } from './components/icons/favorite-icon';
6060
export { ServerIcon } from './components/icons/server-icon';
6161
export { NoSavedItemsIcon } from './components/icons/no-saved-items-icon';
62-
export { ConnectedPlugsIcon } from './components/icons/connected-plugs';
63-
export { DisconnectedPlugIcon } from './components/icons/disconnected-plug';
6462
export { GuideCue as LGGuideCue } from '@leafygreen-ui/guide-cue';
6563
export { Variant as BadgeVariant } from '@leafygreen-ui/badge';
6664
export { Variant as BannerVariant } from '@leafygreen-ui/banner';
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import React, { useCallback, useState, type PropsWithChildren } from 'react';
2+
3+
import {
4+
css,
5+
Icon,
6+
IconButton,
7+
InteractivePopover,
8+
Label,
9+
Overline,
10+
palette,
11+
spacing,
12+
Toggle,
13+
Tooltip,
14+
useId,
15+
} from '@mongodb-js/compass-components';
16+
import type { ConnectionsFilter } from './use-filtered-connections';
17+
18+
const containerStyles = css({
19+
display: 'flex',
20+
flexDirection: 'column',
21+
alignItems: 'flex-start',
22+
padding: spacing[300],
23+
minWidth: 270,
24+
});
25+
26+
const activatedIndicatorStyles = css({
27+
position: 'absolute',
28+
top: spacing[50],
29+
right: spacing[50],
30+
});
31+
32+
const groupStyles = css({
33+
display: 'flex',
34+
flexDirection: 'row',
35+
gap: spacing[200],
36+
marginTop: spacing[200],
37+
});
38+
39+
type ConnectionsFilterPopoverProps = PropsWithChildren<{
40+
open: boolean;
41+
setOpen: (open: boolean) => void;
42+
filter: ConnectionsFilter;
43+
onFilterChange(
44+
updater: (filter: ConnectionsFilter) => ConnectionsFilter
45+
): void;
46+
}>;
47+
48+
export default function ConnectionsFilterPopover({
49+
open,
50+
setOpen,
51+
filter,
52+
onFilterChange,
53+
}: ConnectionsFilterPopoverProps) {
54+
const onExcludeInactiveChange = useCallback(
55+
(excludeInactive: boolean) => {
56+
onFilterChange((filter) => ({
57+
...filter,
58+
excludeInactive,
59+
}));
60+
},
61+
[onFilterChange]
62+
);
63+
64+
const excludeInactiveToggleId = useId();
65+
const excludeInactiveLabelId = useId();
66+
67+
// Add future filters to the boolean below
68+
const isActivated = filter.excludeInactive;
69+
70+
// Manually handling the tooltip state instead of supplying a trigger
71+
// we do this to avoid the tooltip from rendering when the popover is open
72+
// and when the IconButton regains focus as the
73+
const [isTooltipOpen, setTooltipOpen] = useState(false);
74+
const handleButtonMouseEnter = useCallback(
75+
() => setTooltipOpen(true),
76+
[setTooltipOpen]
77+
);
78+
const handleButtonMouseLeave = useCallback(
79+
() => setTooltipOpen(false),
80+
[setTooltipOpen]
81+
);
82+
83+
return (
84+
<>
85+
<Tooltip
86+
align="right"
87+
open={isTooltipOpen && !open}
88+
setOpen={setTooltipOpen}
89+
>
90+
Filter connections
91+
</Tooltip>
92+
<InteractivePopover
93+
open={open}
94+
setOpen={setOpen}
95+
containerClassName={containerStyles}
96+
hideCloseButton
97+
trigger={({ onClick, children, ref }) => (
98+
<>
99+
<IconButton
100+
onClick={onClick}
101+
onMouseEnter={handleButtonMouseEnter}
102+
onMouseLeave={handleButtonMouseLeave}
103+
active={open}
104+
aria-label="Filter connections"
105+
ref={ref as React.Ref<unknown>}
106+
>
107+
<Icon glyph="Filter" />
108+
{isActivated && (
109+
<svg
110+
className={activatedIndicatorStyles}
111+
width="6"
112+
height="6"
113+
viewBox="0 0 6 6"
114+
fill="none"
115+
xmlns="http://www.w3.org/2000/svg"
116+
>
117+
<circle cx="3" cy="3" r="3" fill={palette.blue.base} />
118+
</svg>
119+
)}
120+
</IconButton>
121+
{children}
122+
</>
123+
)}
124+
>
125+
<Overline>Filter Options</Overline>
126+
<div className={groupStyles}>
127+
<Toggle
128+
id={excludeInactiveToggleId}
129+
aria-labelledby={excludeInactiveLabelId}
130+
checked={filter.excludeInactive}
131+
onChange={onExcludeInactiveChange}
132+
size="small"
133+
/>
134+
<Label htmlFor={excludeInactiveToggleId} id={excludeInactiveLabelId}>
135+
Show only active connections
136+
</Label>
137+
</div>
138+
</InteractivePopover>
139+
</>
140+
);
141+
}

packages/compass-sidebar/src/components/multiple-connections/connections-navigation.tsx

Lines changed: 15 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import {
1212
Button,
1313
Icon,
1414
ButtonVariant,
15-
IconButton,
16-
ConnectedPlugsIcon,
17-
DisconnectedPlugIcon,
18-
Tooltip,
1915
} from '@mongodb-js/compass-components';
2016
import { ConnectionsNavigationTree } from '@mongodb-js/compass-connections-navigation';
2117
import type { MapDispatchToProps, MapStateToProps } from 'react-redux';
@@ -46,7 +42,10 @@ import {
4642
fetchAllCollections,
4743
type Database,
4844
} from '../../modules/databases';
49-
import { useFilteredConnections } from '../use-filtered-connections';
45+
import {
46+
type ConnectionsFilter,
47+
useFilteredConnections,
48+
} from '../use-filtered-connections';
5049
import NavigationItemsFilter from '../navigation-items-filter';
5150
import {
5251
type ConnectionImportExportAction,
@@ -84,19 +83,6 @@ const connectionCountStyles = css({
8483
marginLeft: spacing[100],
8584
});
8685

87-
const filterContainerStyles = css({
88-
display: 'flex',
89-
flexDirection: 'row',
90-
alignItems: 'center',
91-
gap: spacing[200],
92-
paddingLeft: spacing[400],
93-
paddingRight: spacing[400],
94-
});
95-
96-
const searchFormStyles = css({
97-
flexGrow: 1,
98-
});
99-
10086
const noDeploymentStyles = css({
10187
paddingLeft: spacing[400],
10288
paddingRight: spacing[400],
@@ -123,10 +109,10 @@ type ConnectionListTitleActions =
123109
type ConnectionsNavigationComponentProps = {
124110
connectionsWithStatus: ReturnType<typeof useConnectionsWithStatus>;
125111
activeWorkspace: WorkspaceTab | null;
126-
filterRegex: RegExp | null;
127-
excludeInactive: boolean;
128-
onFilterChange(regex: RegExp | null): void;
129-
onToggleExcludeInactive(): void;
112+
filter: ConnectionsFilter;
113+
onFilterChange(
114+
updater: (filter: ConnectionsFilter) => ConnectionsFilter
115+
): void;
130116
onConnect(info: ConnectionInfo): void;
131117
onNewConnection(): void;
132118
onEditConnection(info: ConnectionInfo): void;
@@ -167,13 +153,11 @@ type ConnectionsNavigationProps = ConnectionsNavigationComponentProps &
167153
const ConnectionsNavigation: React.FC<ConnectionsNavigationProps> = ({
168154
connectionsWithStatus,
169155
activeWorkspace,
170-
filterRegex,
171-
excludeInactive,
156+
filter,
172157
instances,
173158
databases,
174159
isPerformanceTabSupported,
175160
onFilterChange,
176-
onToggleExcludeInactive,
177161
onConnect,
178162
onNewConnection,
179163
onEditConnection,
@@ -270,10 +254,9 @@ const ConnectionsNavigation: React.FC<ConnectionsNavigationProps> = ({
270254
onDatabaseToggle,
271255
} = useFilteredConnections({
272256
connections,
273-
filterRegex,
257+
filter,
274258
fetchAllCollections,
275259
onDatabaseExpand,
276-
excludeInactive,
277260
});
278261

279262
const connectionListTitleActions =
@@ -519,37 +502,11 @@ const ConnectionsNavigation: React.FC<ConnectionsNavigationProps> = ({
519502
</div>
520503
{connections.length > 0 && (
521504
<>
522-
<div className={filterContainerStyles}>
523-
<NavigationItemsFilter
524-
className={searchFormStyles}
525-
placeholder="Search connections"
526-
onFilterChange={onFilterChange}
527-
/>
528-
<Tooltip
529-
justify="middle"
530-
trigger={
531-
<IconButton
532-
onClick={onToggleExcludeInactive}
533-
active={excludeInactive}
534-
aria-label={
535-
excludeInactive
536-
? 'Showing active connections'
537-
: 'Showing all connections'
538-
}
539-
>
540-
{excludeInactive ? (
541-
<ConnectedPlugsIcon />
542-
) : (
543-
<DisconnectedPlugIcon />
544-
)}
545-
</IconButton>
546-
}
547-
>
548-
{excludeInactive
549-
? 'Showing active connections'
550-
: 'Showing all connections'}
551-
</Tooltip>
552-
</div>
505+
<NavigationItemsFilter
506+
placeholder="Search connections"
507+
filter={filter}
508+
onFilterChange={onFilterChange}
509+
/>
553510
<ConnectionsNavigationTree
554511
connections={filtered || connections}
555512
activeWorkspace={activeWorkspace}

packages/compass-sidebar/src/components/multiple-connections/sidebar.spec.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -363,16 +363,13 @@ describe('Multiple Connections Sidebar Component', function () {
363363
const favoriteConnectionId = savedFavoriteConnection.id;
364364
const recentConnectionId = savedRecentConnection.id;
365365

366-
const activeConnectionsToggleButton = screen.getByLabelText(
367-
'Showing all connections'
368-
);
369-
370366
expect(screen.queryByTestId(favoriteConnectionId)).to.be.visible;
371367
expect(screen.queryByTestId(recentConnectionId)).to.be.visible;
372368

373-
userEvent.click(activeConnectionsToggleButton);
374-
expect(activeConnectionsToggleButton.ariaLabel).equals(
375-
'Showing active connections'
369+
userEvent.click(screen.getByLabelText('Filter connections'));
370+
371+
userEvent.click(
372+
screen.getByLabelText('Show only active connections')
376373
);
377374

378375
expect(screen.queryByTestId(favoriteConnectionId)).to.be.null;

0 commit comments

Comments
 (0)