Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 77 additions & 16 deletions packages/compass-collection/src/stores/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ type ContextProps = {
connectionString?: string;
};

type ContextWithAppRegistry = ContextProps & {
globalAppRegistry: AppRegistry;
localAppRegistry: AppRegistry;
};

/**
* Setup a scoped store to the collection.
*
Expand Down Expand Up @@ -115,7 +120,7 @@ const setupStore = ({
query,
aggregation,
connectionString,
}: ContextProps) => {
}: ContextWithAppRegistry) => {
const store = role.configureStore({
localAppRegistry,
globalAppRegistry,
Expand All @@ -138,7 +143,7 @@ const setupStore = ({
aggregation,
connectionString,
});
localAppRegistry?.registerStore(role.storeName, store);
localAppRegistry.registerStore(role.storeName, store);

return store;
};
Expand Down Expand Up @@ -176,7 +181,7 @@ const setupPlugin = ({
sourceName,
connectionString,
key,
}: ContextProps) => {
}: ContextWithAppRegistry) => {
const actions = role.configureActions();
const store = setupStore({
role,
Expand Down Expand Up @@ -232,7 +237,7 @@ const setupScopedModals = ({
isFLE,
sourceName,
connectionString,
}: ContextProps) => {
}: ContextWithAppRegistry) => {
const roles = globalAppRegistry?.getRole('Collection.ScopedModal');
if (roles) {
return roles.map((role: any, i: number) => {
Expand All @@ -257,6 +262,71 @@ const setupScopedModals = ({
return [];
};

/**
* Setup the query bar plugins. Need to instantiate the store and actions
* and put them in the app registry for use by all the plugins. This way
* there is only 1 query bar store per collection tab instead of one per
* plugin that uses it.
*/
const setupQueryPlugins = ({
globalAppRegistry,
localAppRegistry,
serverVersion,
state,
namespace,
isReadonly,
isTimeSeries,
isClustered,
isFLE,
query,
aggregation,
}: ContextWithAppRegistry): void => {
const queryBarRole = globalAppRegistry.getRole('Query.QueryBar')?.[0];
if (queryBarRole) {
localAppRegistry.registerRole('Query.QueryBar', queryBarRole);
const queryBarActions = setupActions(queryBarRole, localAppRegistry);
setupStore({
role: queryBarRole,
globalAppRegistry,
localAppRegistry,
dataService: state.dataService,
namespace,
serverVersion,
isReadonly,
isTimeSeries,
isClustered,
isFLE,
actions: queryBarActions,
query,
aggregation,
});
}

const queryHistoryRole = globalAppRegistry.getRole('Query.QueryHistory')?.[0];
if (queryHistoryRole) {
localAppRegistry.registerRole('Query.QueryHistory', queryHistoryRole);
const queryHistoryActions = setupActions(
queryHistoryRole,
localAppRegistry
);
setupStore({
role: queryHistoryRole,
globalAppRegistry,
localAppRegistry,
dataService: state.dataService,
namespace,
serverVersion,
isReadonly,
isTimeSeries,
isClustered,
isFLE,
actions: queryHistoryActions,
query,
aggregation,
});
}
};

/**
* Create the context in which a tab is created.
*
Expand Down Expand Up @@ -306,25 +376,16 @@ const createContext = ({
const views: JSX.Element[] = [];
const queryHistoryIndexes: number[] = [];

// Setup the query bar plugin. Need to instantiate the store and actions
// and put them in the app registry for use by all the plugins. This way
// there is only 1 query bar store per collection tab instead of one per
// plugin that uses it.
const queryBarRole = globalAppRegistry.getRole('Query.QueryBar')[0];
localAppRegistry.registerRole('Query.QueryBar', queryBarRole);
const queryBarActions = setupActions(queryBarRole, localAppRegistry);
setupStore({
role: queryBarRole,
setupQueryPlugins({
globalAppRegistry,
localAppRegistry,
dataService: state.dataService,
namespace,
serverVersion,
state,
namespace,
isReadonly,
isTimeSeries,
isClustered,
isFLE,
actions: queryBarActions,
query,
aggregation,
});
Expand Down
1 change: 1 addition & 0 deletions packages/compass-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"@react-stately/tooltip": "^3.0.5",
"@types/lodash": "^4.14.172",
"bson": "^4.6.1",
"focus-trap-react": "^8.4.2",
"hadron-document": "^7.13.0",
"hadron-type-checker": "^6.10.0",
"lodash": "^4.17.21",
Expand Down
141 changes: 141 additions & 0 deletions packages/compass-components/src/components/interactive-popover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React, { useCallback, useEffect, useRef } from 'react';
import { css } from '@leafygreen-ui/emotion';
import FocusTrap from 'focus-trap-react';

import { Popover } from './leafygreen';

const contentContainerStyles = css({
display: 'flex',
height: '100%',
});

type InteractivePopoverProps = {
className: string;
children: (childrenProps: { onClose: () => void }) => React.ReactElement;
trigger: (triggerProps: {
onClick: (event: React.MouseEvent | React.TouchEvent) => void;
ref: React.RefObject<HTMLButtonElement>;
children: React.ReactNode;
}) => React.ReactElement;
open: boolean;
setOpen: (open: boolean) => void;
};

function InteractivePopover({
className,
children,
trigger,
open,
setOpen,
}: InteractivePopoverProps): React.ReactElement {
const triggerRef = useRef<HTMLButtonElement>(null);
const popoverContentContainerRef = useRef<HTMLDivElement>(null);

const onClose = useCallback(() => {
setOpen(false);

// Return focus to the trigger when the popover is hidden.
setTimeout(() => {
triggerRef.current?.focus();
});
}, [setOpen]);

const onClickTrigger = useCallback(() => {
if (open) {
onClose();
return;
}

setOpen(!open);
}, [open, setOpen, onClose]);

// When the popover is open, close it when an item that isn't the popover
// is clicked.
useEffect(() => {
if (!open) {
return;
}

const clickEventListener = (event: MouseEvent | TouchEvent) => {
// Ignore clicks on the popover.
if (
!popoverContentContainerRef.current ||
popoverContentContainerRef.current.contains(event.target as Node)
) {
return;
}
// Ignore clicks on the trigger as it has its own handler.
if (
!triggerRef.current ||
triggerRef.current.contains(event.target as Node)
) {
return;
}

onClose();
};
window.addEventListener('mousedown', clickEventListener);
window.addEventListener('touchstart', clickEventListener);
return () => {
window.removeEventListener('mousedown', clickEventListener);
window.removeEventListener('touchstart', clickEventListener);
};
}, [open, onClose]);

const onPopoverKeyDown = useCallback(
(evt: KeyboardEvent) => {
if (evt.key === 'Escape') {
onClose();
return;
}
},
[onClose]
);

useEffect(() => {
if (!open) {
return;
}
document.addEventListener('keydown', onPopoverKeyDown);

return () => {
document.removeEventListener('keydown', onPopoverKeyDown);
};
}, [onPopoverKeyDown, open]);

return trigger({
onClick: onClickTrigger,
ref: triggerRef,
children: (
<Popover
align="bottom"
justify="start"
active={open}
adjustOnMutation
usePortal
spacing={0}
className={className}
refEl={triggerRef}
>
{open && (
<FocusTrap
focusTrapOptions={{
clickOutsideDeactivates: true,
}}
>
<div
className={contentContainerStyles}
ref={popoverContentContainerRef}
>
{children({
onClose: onClose,
})}
</div>
</FocusTrap>
)}
</Popover>
),
});
}

export { InteractivePopover };
2 changes: 2 additions & 0 deletions packages/compass-components/src/components/leafygreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
default as LeafyGreenModal,
Footer as LeafyGreenModalFooter,
} from '@leafygreen-ui/modal';
import Popover from '@leafygreen-ui/popover';
import { RadioBox, RadioBoxGroup } from '@leafygreen-ui/radio-box-group';
import {
Radio,
Expand Down Expand Up @@ -160,6 +161,7 @@ export {
ModalFooter,
MongoDBLogoMark,
MongoDBLogo,
Popover,
RadioBox,
RadioBoxGroup,
Radio,
Expand Down
3 changes: 1 addition & 2 deletions packages/compass-components/src/components/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { cx, css } from '@leafygreen-ui/emotion';
import { uiColors } from '@leafygreen-ui/palette';

import { withTheme } from '../hooks/use-theme';
import { gray8 } from '../compass-ui-colors';

const toolbarLightThemeStyles = css({
backgroundColor: gray8,
backgroundColor: uiColors.white,
color: uiColors.gray.dark2,
});

Expand Down
Loading