Skip to content

Commit

Permalink
feat(sidebar): connections filter popover COMPASS-8503 (#6486)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
kraenhansen authored Nov 14, 2024
1 parent 28bb675 commit 5a6c445
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 240 deletions.

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions packages/compass-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ export { DocumentIcon } from './components/icons/document-icon';
export { FavoriteIcon } from './components/icons/favorite-icon';
export { ServerIcon } from './components/icons/server-icon';
export { NoSavedItemsIcon } from './components/icons/no-saved-items-icon';
export { ConnectedPlugsIcon } from './components/icons/connected-plugs';
export { DisconnectedPlugIcon } from './components/icons/disconnected-plug';
export { GuideCue as LGGuideCue } from '@leafygreen-ui/guide-cue';
export { Variant as BadgeVariant } from '@leafygreen-ui/badge';
export { Variant as BannerVariant } from '@leafygreen-ui/banner';
Expand Down
141 changes: 141 additions & 0 deletions packages/compass-sidebar/src/components/connections-filter-popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React, { useCallback, useState, type PropsWithChildren } from 'react';

import {
css,
Icon,
IconButton,
InteractivePopover,
Label,
Overline,
palette,
spacing,
Toggle,
Tooltip,
useId,
} from '@mongodb-js/compass-components';
import type { ConnectionsFilter } from './use-filtered-connections';

const containerStyles = css({
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
padding: spacing[300],
minWidth: 270,
});

const activatedIndicatorStyles = css({
position: 'absolute',
top: spacing[50],
right: spacing[50],
});

const groupStyles = css({
display: 'flex',
flexDirection: 'row',
gap: spacing[200],
marginTop: spacing[200],
});

type ConnectionsFilterPopoverProps = PropsWithChildren<{
open: boolean;
setOpen: (open: boolean) => void;
filter: ConnectionsFilter;
onFilterChange(
updater: (filter: ConnectionsFilter) => ConnectionsFilter
): void;
}>;

export default function ConnectionsFilterPopover({
open,
setOpen,
filter,
onFilterChange,
}: ConnectionsFilterPopoverProps) {
const onExcludeInactiveChange = useCallback(
(excludeInactive: boolean) => {
onFilterChange((filter) => ({
...filter,
excludeInactive,
}));
},
[onFilterChange]
);

const excludeInactiveToggleId = useId();
const excludeInactiveLabelId = useId();

// Add future filters to the boolean below
const isActivated = filter.excludeInactive;

// Manually handling the tooltip state instead of supplying a trigger
// we do this to avoid the tooltip from rendering when the popover is open
// and when the IconButton regains focus as the
const [isTooltipOpen, setTooltipOpen] = useState(false);
const handleButtonMouseEnter = useCallback(
() => setTooltipOpen(true),
[setTooltipOpen]
);
const handleButtonMouseLeave = useCallback(
() => setTooltipOpen(false),
[setTooltipOpen]
);

return (
<>
<Tooltip
align="right"
open={isTooltipOpen && !open}
setOpen={setTooltipOpen}
>
Filter connections
</Tooltip>
<InteractivePopover
open={open}
setOpen={setOpen}
containerClassName={containerStyles}
hideCloseButton
trigger={({ onClick, children, ref }) => (
<>
<IconButton
onClick={onClick}
onMouseEnter={handleButtonMouseEnter}
onMouseLeave={handleButtonMouseLeave}
active={open}
aria-label="Filter connections"
ref={ref as React.Ref<unknown>}
>
<Icon glyph="Filter" />
{isActivated && (
<svg
className={activatedIndicatorStyles}
width="6"
height="6"
viewBox="0 0 6 6"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="3" cy="3" r="3" fill={palette.blue.base} />
</svg>
)}
</IconButton>
{children}
</>
)}
>
<Overline>Filter Options</Overline>
<div className={groupStyles}>
<Toggle
id={excludeInactiveToggleId}
aria-labelledby={excludeInactiveLabelId}
checked={filter.excludeInactive}
onChange={onExcludeInactiveChange}
size="small"
/>
<Label htmlFor={excludeInactiveToggleId} id={excludeInactiveLabelId}>
Show only active connections
</Label>
</div>
</InteractivePopover>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ import {
Button,
Icon,
ButtonVariant,
IconButton,
ConnectedPlugsIcon,
DisconnectedPlugIcon,
Tooltip,
} from '@mongodb-js/compass-components';
import { ConnectionsNavigationTree } from '@mongodb-js/compass-connections-navigation';
import type { MapDispatchToProps, MapStateToProps } from 'react-redux';
Expand Down Expand Up @@ -46,7 +42,10 @@ import {
fetchAllCollections,
type Database,
} from '../../modules/databases';
import { useFilteredConnections } from '../use-filtered-connections';
import {
type ConnectionsFilter,
useFilteredConnections,
} from '../use-filtered-connections';
import NavigationItemsFilter from '../navigation-items-filter';
import {
type ConnectionImportExportAction,
Expand Down Expand Up @@ -84,19 +83,6 @@ const connectionCountStyles = css({
marginLeft: spacing[100],
});

const filterContainerStyles = css({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
gap: spacing[200],
paddingLeft: spacing[400],
paddingRight: spacing[400],
});

const searchFormStyles = css({
flexGrow: 1,
});

const noDeploymentStyles = css({
paddingLeft: spacing[400],
paddingRight: spacing[400],
Expand All @@ -123,10 +109,10 @@ type ConnectionListTitleActions =
type ConnectionsNavigationComponentProps = {
connectionsWithStatus: ReturnType<typeof useConnectionsWithStatus>;
activeWorkspace: WorkspaceTab | null;
filterRegex: RegExp | null;
excludeInactive: boolean;
onFilterChange(regex: RegExp | null): void;
onToggleExcludeInactive(): void;
filter: ConnectionsFilter;
onFilterChange(
updater: (filter: ConnectionsFilter) => ConnectionsFilter
): void;
onConnect(info: ConnectionInfo): void;
onNewConnection(): void;
onEditConnection(info: ConnectionInfo): void;
Expand Down Expand Up @@ -167,13 +153,11 @@ type ConnectionsNavigationProps = ConnectionsNavigationComponentProps &
const ConnectionsNavigation: React.FC<ConnectionsNavigationProps> = ({
connectionsWithStatus,
activeWorkspace,
filterRegex,
excludeInactive,
filter,
instances,
databases,
isPerformanceTabSupported,
onFilterChange,
onToggleExcludeInactive,
onConnect,
onNewConnection,
onEditConnection,
Expand Down Expand Up @@ -270,10 +254,9 @@ const ConnectionsNavigation: React.FC<ConnectionsNavigationProps> = ({
onDatabaseToggle,
} = useFilteredConnections({
connections,
filterRegex,
filter,
fetchAllCollections,
onDatabaseExpand,
excludeInactive,
});

const connectionListTitleActions =
Expand Down Expand Up @@ -519,37 +502,11 @@ const ConnectionsNavigation: React.FC<ConnectionsNavigationProps> = ({
</div>
{connections.length > 0 && (
<>
<div className={filterContainerStyles}>
<NavigationItemsFilter
className={searchFormStyles}
placeholder="Search connections"
onFilterChange={onFilterChange}
/>
<Tooltip
justify="middle"
trigger={
<IconButton
onClick={onToggleExcludeInactive}
active={excludeInactive}
aria-label={
excludeInactive
? 'Showing active connections'
: 'Showing all connections'
}
>
{excludeInactive ? (
<ConnectedPlugsIcon />
) : (
<DisconnectedPlugIcon />
)}
</IconButton>
}
>
{excludeInactive
? 'Showing active connections'
: 'Showing all connections'}
</Tooltip>
</div>
<NavigationItemsFilter
placeholder="Search connections"
filter={filter}
onFilterChange={onFilterChange}
/>
<ConnectionsNavigationTree
connections={filtered || connections}
activeWorkspace={activeWorkspace}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,16 +363,13 @@ describe('Multiple Connections Sidebar Component', function () {
const favoriteConnectionId = savedFavoriteConnection.id;
const recentConnectionId = savedRecentConnection.id;

const activeConnectionsToggleButton = screen.getByLabelText(
'Showing all connections'
);

expect(screen.queryByTestId(favoriteConnectionId)).to.be.visible;
expect(screen.queryByTestId(recentConnectionId)).to.be.visible;

userEvent.click(activeConnectionsToggleButton);
expect(activeConnectionsToggleButton.ariaLabel).equals(
'Showing active connections'
userEvent.click(screen.getByLabelText('Filter connections'));

userEvent.click(
screen.getByLabelText('Show only active connections')
);

expect(screen.queryByTestId(favoriteConnectionId)).to.be.null;
Expand Down
Loading

0 comments on commit 5a6c445

Please sign in to comment.