-
Notifications
You must be signed in to change notification settings - Fork 189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(sidebar): connections filter popover COMPASS-8503 #6486
Changes from all commits
754ab49
4fd49fc
b0aea1a
464e79d
6d19bbe
5e901dd
207bbc1
efc191c
d02f274
03f93b8
b8f783f
65beec5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Already merged, but your comment ends mid-sentence :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks: #6502 |
||
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 |
---|---|---|
|
@@ -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'; | ||
|
@@ -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, | ||
|
@@ -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], | ||
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've combined the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. I believe that's the plan with the popover. |
||
onFilterChange( | ||
updater: (filter: ConnectionsFilter) => ConnectionsFilter | ||
): void; | ||
onConnect(info: ConnectionInfo): void; | ||
onNewConnection(): void; | ||
onEditConnection(info: ConnectionInfo): void; | ||
|
@@ -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, | ||
|
@@ -270,10 +254,9 @@ const ConnectionsNavigation: React.FC<ConnectionsNavigationProps> = ({ | |
onDatabaseToggle, | ||
} = useFilteredConnections({ | ||
connections, | ||
filterRegex, | ||
filter, | ||
fetchAllCollections, | ||
onDatabaseExpand, | ||
excludeInactive, | ||
}); | ||
|
||
const connectionListTitleActions = | ||
|
@@ -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} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️