Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions packages/compass-home/src/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const createDataService = () => ({
configuredKMSProviders() {
return [];
},
currentOp() {},
top() {},
on() {},
off() {},
removeListener() {},
Expand Down
1 change: 1 addition & 0 deletions packages/compass-sidebar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
"eslint": "^7.25.0",
"lodash": "^4.17.21",
"mocha": "^10.2.0",
"mongodb": "^6.3.0",
"mongodb-ns": "^2.4.0",
"nyc": "^15.1.0",
"prettier": "^2.7.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ function renderNavigationItems(
onAction={() => {
/* noop */
}}
showPerformanceItem={false}
showCreateDatabaseAction={true}
isPerformanceTabSupported={true}
onFilterChange={() => {
/* noop */
}}
Expand Down Expand Up @@ -59,4 +59,17 @@ describe('NavigationItems [Component]', function () {
expect(screen.queryByLabelText(createDatabaseText)).to.not.exist;
});
});

describe('when performance tab is not supported', function () {
it('renders disabled "Performance" navigation item', function () {
renderNavigationItems({
isPerformanceTabSupported: false,
});

expect(screen.getByRole('button', { name: 'Performance' })).to.exist;
expect(
screen.getByRole('button', { name: 'Performance' })
).to.have.attribute('aria-disabled', 'true');
});
});
});
152 changes: 102 additions & 50 deletions packages/compass-sidebar/src/components/navigation-items.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React, { useCallback, useMemo } from 'react';
import { connect } from 'react-redux';
import {
useHoverState,
Expand All @@ -14,6 +14,9 @@ import {
PerformanceSignals,
Placeholder,
ContentWithFallback,
palette,
useDarkMode,
Tooltip,
} from '@mongodb-js/compass-components';
import { usePreference, withPreferences } from 'compass-preferences-model';
import type { ItemAction } from '@mongodb-js/compass-components';
Expand Down Expand Up @@ -117,17 +120,31 @@ const navigationItemLabel = css({
marginLeft: spacing[2],
});

const navigationItemDisabledDarkModeStyles = css({
'--item-color': palette.gray.dark1,
'--item-color-active': palette.gray.dark1,
'--item-bg-color-hover': 'var(--item-bg-color)',
});

const navigationItemDisabledLightModeStyles = css({
'--item-color': palette.gray.base,
'--item-color-active': palette.gray.base,
'--item-bg-color-hover': 'var(--item-bg-color)',
});

const navigationItemActionIcons = css({ color: 'inherit' });

export function NavigationItem<Actions extends string>({
isExpanded,
onAction,
onClick,
onClick: onButtonClick,
glyph,
label,
actions,
isActive,
showTooManyCollectionsInsight,
disabled: isButtonDisabled = false,
disabledMessage: buttonDisabledMessage,
}: {
isExpanded?: boolean;
onAction(actionName: Actions, ...rest: any[]): void;
Expand All @@ -137,17 +154,35 @@ export function NavigationItem<Actions extends string>({
actions?: ItemAction<Actions>[];
isActive: boolean;
showTooManyCollectionsInsight?: boolean;
disabled?: boolean;
disabledMessage?: string;
}) {
const darkMode = useDarkMode();
const showInsights = usePreference('showInsights', React);
const onClick = useCallback(() => {
if (isButtonDisabled) {
return;
}
onButtonClick();
}, [isButtonDisabled, onButtonClick]);
const [hoverProps] = useHoverState();
const focusRingProps = useFocusRing();
const defaultActionProps = useDefaultAction(onClick);

const navigationItemProps = mergeProps(
{
className: cx(navigationItem, isActive && activeNavigationItem),
className: cx(
navigationItem,
isActive && activeNavigationItem,
isButtonDisabled &&
(darkMode
? navigationItemDisabledDarkModeStyles
: navigationItemDisabledLightModeStyles)
),
role: 'button',
['aria-label']: label,
['aria-current']: isActive,
['aria-disabled']: isButtonDisabled,
tabIndex: 0,
},
hoverProps,
Expand All @@ -156,37 +191,52 @@ export function NavigationItem<Actions extends string>({
) as React.HTMLProps<HTMLDivElement>;

return (
<div {...navigationItemProps}>
<div className={itemWrapper}>
<div className={itemButtonWrapper}>
<Icon glyph={glyph} size="small"></Icon>
{isExpanded && <span className={navigationItemLabel}>{label}</span>}
</div>
{showInsights && isExpanded && showTooManyCollectionsInsight && (
<div className={signalContainerStyles}>
<SignalPopover
signals={PerformanceSignals.get('too-many-collections')}
></SignalPopover>
<Tooltip
align="right"
spacing={spacing[3]}
isDisabled={!isButtonDisabled || !buttonDisabledMessage}
trigger={({ children: tooltip, ...triggerProps }) => {
const props = mergeProps(triggerProps, navigationItemProps);
return (
<div {...props}>
<div className={itemWrapper}>
<div className={itemButtonWrapper}>
<Icon glyph={glyph} size="small"></Icon>
{isExpanded && (
<span className={navigationItemLabel}>{label}</span>
)}
{tooltip}
</div>
{showInsights && isExpanded && showTooManyCollectionsInsight && (
<div className={signalContainerStyles}>
<SignalPopover
signals={PerformanceSignals.get('too-many-collections')}
></SignalPopover>
</div>
)}
{!isButtonDisabled && isExpanded && actions && (
<ItemActionControls<Actions>
iconSize="small"
onAction={onAction}
data-testid="sidebar-navigation-item-actions"
actions={actions}
// This is what renders the "create database" action,
// the icons here should always be clearly visible,
// so we let the icon to inherit the foreground color of
// the text
isVisible={true}
iconClassName={navigationItemActionIcons}
collapseToMenuThreshold={3}
></ItemActionControls>
)}
<div className={cx('item-background', itemBackground)} />
</div>
</div>
)}
{isExpanded && actions && (
<ItemActionControls<Actions>
iconSize="small"
onAction={onAction}
data-testid="sidebar-navigation-item-actions"
actions={actions}
// This is what renders the "create database" action,
// the icons here should always be clearly visible,
// so we let the icon to inherit the foreground color of
// the text
isVisible={true}
iconClassName={navigationItemActionIcons}
collapseToMenuThreshold={3}
></ItemActionControls>
)}
<div className={cx('item-background', itemBackground)} />
</div>
</div>
);
}}
>
{buttonDisabledMessage}
</Tooltip>
);
}

Expand All @@ -201,8 +251,8 @@ const PlaceholderItem = ({ forLabel }: { forLabel: string }) => {
export function NavigationItems({
isReady,
isExpanded,
showCreateDatabaseAction = false,
showPerformanceItem = false,
showCreateDatabaseAction,
isPerformanceTabSupported,
onFilterChange,
onAction,
currentLocation,
Expand All @@ -211,8 +261,8 @@ export function NavigationItems({
}: {
isReady?: boolean;
isExpanded?: boolean;
showCreateDatabaseAction?: boolean;
showPerformanceItem?: boolean;
showCreateDatabaseAction: boolean;
isPerformanceTabSupported: boolean;
onFilterChange(regex: RegExp | null): void;
onAction(actionName: string, ...rest: any[]): void;
currentLocation: string | null;
Expand Down Expand Up @@ -272,16 +322,16 @@ export function NavigationItems({
label="My Queries"
isActive={currentLocation === 'My Queries'}
/>
{showPerformanceItem && (
<NavigationItem<''>
isExpanded={isExpanded}
onAction={onAction}
onClick={openPerformanceWorkspace}
glyph="Gauge"
label="Performance"
isActive={currentLocation === 'Performance'}
/>
)}
<NavigationItem<''>
isExpanded={isExpanded}
onAction={onAction}
onClick={openPerformanceWorkspace}
glyph="Gauge"
label="Performance"
isActive={currentLocation === 'Performance'}
disabled={!isPerformanceTabSupported}
disabledMessage="Performance metrics are not available for your deployment or to your database user"
/>
<NavigationItem<DatabasesActions>
isExpanded={isExpanded}
onAction={onAction}
Expand Down Expand Up @@ -321,9 +371,10 @@ const mapStateToProps = (
0
);

const isReady = ['ready', 'refreshing'].includes(
state.instance?.status ?? ''
);
const isReady =
['ready', 'refreshing'].includes(state.instance?.status ?? '') &&
state.isPerformanceTabSupported !== null;

const isDataLake = state.instance?.dataLake.isDataLake ?? false;
const isWritable = state.instance?.isWritable ?? false;

Expand All @@ -332,6 +383,7 @@ const mapStateToProps = (
showPerformanceItem: !isDataLake,
showCreateDatabaseAction: !isDataLake && isWritable && !preferencesReadOnly,
showTooManyCollectionsInsight: totalCollectionsCount > 10_000,
isPerformanceTabSupported: !isDataLake && !!state.isPerformanceTabSupported,
};
};

Expand Down
7 changes: 7 additions & 0 deletions packages/compass-sidebar/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { mongoDBInstanceLocator } from '@mongodb-js/compass-app-stores/provider'
import { dataServiceLocator } from 'mongodb-data-service/provider';
import type { DataService } from 'mongodb-data-service';
import type { MongoDBInstance } from 'mongodb-instance-model';
import type { LoggerAndTelemetry } from '@mongodb-js/compass-logging/provider';
import { createLoggerAndTelemetryLocator } from '@mongodb-js/compass-logging/provider';

function activate() {
// noop
Expand All @@ -21,6 +23,7 @@ export const CompassSidebarPlugin = registerHadronPlugin<
{
instance: () => MongoDBInstance;
dataService: () => DataService;
logger: () => LoggerAndTelemetry;
}
>(
{
Expand All @@ -32,10 +35,12 @@ export const CompassSidebarPlugin = registerHadronPlugin<
globalAppRegistry,
instance,
dataService,
logger,
}: {
globalAppRegistry: AppRegistry;
instance: MongoDBInstance;
dataService: DataService;
logger: LoggerAndTelemetry;
},
helpers: ActivateHelpers
) {
Expand All @@ -45,6 +50,7 @@ export const CompassSidebarPlugin = registerHadronPlugin<
instance,
dataService,
connectionInfo: initialConnectionInfo,
logger,
},
helpers
);
Expand All @@ -57,6 +63,7 @@ export const CompassSidebarPlugin = registerHadronPlugin<
{
instance: mongoDBInstanceLocator,
dataService: dataServiceLocator,
logger: createLoggerAndTelemetryLocator('COMPASS-SIDEBAR-UI'),
}
);

Expand Down
10 changes: 9 additions & 1 deletion packages/compass-sidebar/src/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ import isExpanded from './is-expanded';
import type { AppRegistry } from 'hadron-app-registry';
import type { DataServiceAction, DataServiceState } from './data-service';
import dataService from './data-service';
import type {
IsPerformanceTabSupportedState,
SetIsPerformanceTabSupportedAction,
} from './is-performance-tab-supported';
import isPerformanceTabSupported from './is-performance-tab-supported';

export interface RootState {
appRegistry: {
Expand All @@ -44,6 +49,7 @@ export interface RootState {
isDetailsExpanded: IsDetailsExpandedState;
isGenuineMongoDBVisible: IsGenuineMongoDBVisibleState;
isExpanded: IsExpandedState;
isPerformanceTabSupported: IsPerformanceTabSupportedState;
}

export type RootAction =
Expand All @@ -54,7 +60,8 @@ export type RootAction =
| ToggleIsDetailsExpandedAction
| IsGenuineMongoDBVisibleAction
| IsExpandedAction
| DataServiceAction;
| DataServiceAction
| SetIsPerformanceTabSupportedAction;

/**
* The reducer.
Expand All @@ -69,6 +76,7 @@ const reducer = combineReducers<RootState, RootAction>({
isDetailsExpanded,
isGenuineMongoDBVisible,
isExpanded,
isPerformanceTabSupported,
});

export default reducer;
Loading